sfdx-node

Utility to wrap the Salesforce CLI for use in NodeJS

Usage no npm install needed!

<script type="module">
  import sfdxNode from 'https://cdn.skypack.dev/sfdx-node';
</script>

README

SFDX-Node

Wrapper for the Salesforce CLI to use in Node.js

Installation

npm install sfdx-node

Usage

The Salesforce CLI is based on OCLIF and is a combination of different OCLIF plugins. This module includes all the commands in force, auth and config namespaces. To use Salesforce CLI commands within Node.js programs, we wrap the namespace, topics, and camelcase the commands. For example:

  • sfdx force:org:list becomes sfdx.force.org.list()
  • sfdx force:package:version:create becomes sfdx.force.package.versionCreate()
  • sfdx auth:web:login becomes sfdx.auth.web.login()
  • sfdx config:set becomes sfdx.config.set()

sfdx NAMESPACE:TOPIC:COMMAND:SUB -> sfdx.namespace.topic.commandSub();

Command parameters can be passed in as an object to the command using the flag names. So sfdx force:org:create --setalias myorg --setdefaultusername can be executed as below:

const sfdx = require('sfdx-node');

// Create a new scratch org with alias myorg and set it as default org
sfdx.force.org.create({
  setalias: 'myorg',
  setdefaultusername: true
});

Similarly, the special command arguments can be passing in as an array named args inside an object, as the second method argument. So, sfdx alias:set myorg1=test-user1@example.com myorg2=test-user2@example.com can be executed as below:

const sfdx = require('sfdx-node');

// Set/overwrite aliases for already authorized orgs
sfdx.alias.set({},{
  args: ['myorg1=test-user1@example.com', 'myorg2=test-user2@example.com']
});

Commands all return a JS Promise.

const sfdx = require('sfdx-node');

//authorize a dev hub
sfdx.auth.web.login({
  setdefaultdevhubusername: true,
  setalias: 'HubOrg'
})
  .then(() => sfdx.force.source.push()) //push source
  .then(() => {
    // Display confirmation of source push
    console.log('Source pushed to scratch org');
  });

Using _quiet for showing/hiding command output

It is possible to control the visibility of the output (success or failure) generated by a Salesforce CLI command, executed through this module. Output can be made visible by passing in the flag _quiet as false. Default value for flag _quiet is true, which means that the default behavior of this module is to hide the output of a Salesforce CLI command.

const sfdx = require('sfdx-node');

// Fetch all the aliases, but do not show how the Salesforce CLI command output
sfdx.alias.list()
  .then((listResult) => {
    // Do something with the fetched list of all aliases
    console.log('Alias list:', listResult);
  });

// Fetch all the aliases, and show the Salesforce CLI command output
sfdx.alias.list({
  _quiet: false
})
  .then((listResult) => {
    // Do something else with the fetched list of all aliases
  });

Using _rejectOnError for promise rejection (in case of a command failure)

Majority of the Salesforce CLI commands, when executed through node, do not reject the promise when an error occurs. They rather resolve with undefined. Promise rejection can be forced by passing in the flag _rejectOnError as true. A few Salesforce CLI commands reject the promise as their out-of-the-box behavior, without using this _rejectOnError flag.

const sfdx = require('sfdx-node');

// Pull the remote changes from the scratch org
sfdx.force.source.pull({
  _rejectOnError: true
})
  .then((pullResult) => {
    // Successfully pulled from scratch org
    console.log('Changes pulled from scratch org:', pullResult);
  })
  .catch((pullError) => {
    // Promise rejected in case of conflicts or some other issue while pulling from scratch org
    console.log('Errors occurred during pull operation:', pullError);
  });

Rejecting promises is not the default bahavior of this module, unless the promise is rejected by Salesforce CLI command itself. This _rejectOnError flag needs to be passed in as true for every command that is expected to reject the promise in case of an error.

Promise rejection overlapping for parallel calls

When multiple CLI commands are executed in parallel using this module, while also making use of _rejectOnError, more than one or even all the commands may end up rejecting the promises. This can happen because the errors are shared among all the parallel executions.

To avoid this, make use of sfdx-node/parallel module. It works in the same way as the main module, except for the fact that each command is executed in it's own child process. This ensures that each command execution has it's own context and it doesn't share errors with other commands executing in parallel.

const sfdx = require('sfdx-node/parallel');

// Get source status for first scratch org
sfdx.force.source.status({
  targetusername: 'test-user1@example.com',
  _rejectOnError: true
})
  .then((statusResult) => {
    // Source status for first scratch org
    console.log('First org source status:', statusResult);
  })
  .catch((statusError) => {
    // Error occurred during source status check for first scratch org
    console.log('First org error:', statusError);
  });

// Get source status for second scratch org
sfdx.force.source.status({
  targetusername: 'test-user2@example.com',
  _rejectOnError: true
})
  .then((statusResult) => {
    // Source status for second scratch org
    console.log('Second org source status:', statusResult);
  })
  .catch((statusError) => {
    // Error occurred during source status check for second scratch org
    console.log('Second org error:', statusError);
  });