Salesforce Connector

reshuffle-salesforce-connector

Code | npm | Code sample

npm install reshuffle-salesforce-connector

Reshuffle Salesforce Connector

This package contains a Reshuffle connector to Salesforce.

The following example tracks changes to account names:

const { Reshuffle } = require('reshuffle')
const { SalesforceConnector } = require('reshuffle-salesforce-connector')

;(async () => {
  const app = new Reshuffle()
  const sf = new SalesforceConnector(app, {
    clientId: process.env.SALESFORCE_CLIENT_ID,
    clientSecret: process.env.SALESFORCE_CLIENT_SECRET,
    baseURL: process.env.RESHUFFLE_RUNTIME_BASE_URL,
    encryptionKey: process.env.RESHUFFLE_ENCRYPTION_KEY,
  })

  app.start(8000)  // Listen to HTTP for authentication

  console.log('Authenticate with Salesforce')
  await sf.authenticate()
  console.log('Authenticated')

  sf.on({ query: 'SELECT Id,Name FROM Account' }, async (event, app) => {
    console.log(event)
  })

  console.log('Edit an account name to trigger an event...')

})().catch(console.error)

Table of Contents

Configuration Configuration options

Connector events:

query Query result changed

Connector actions:

authenticate Authenticate against Salsforce

isAuthenticated Is authenticated with Salsforce

query Query Salesforce data

map Process a collection of Salesforce objects

sobject Access a Salesforce object type

SDK:

sdk Get direct JSForce SDK access

Configuration options

The first step to access Salesforce is to create a new Connected App. You can do this by accessing the settings on your Salesforce platform. See this guide for details.

The app should have OAuth access enabled with the following scopes:

  • Full access (full)
  • Perform requests on your behalf at any time (refresh_token, offline_access)

You can limit the app to only support certain operations, by replacing "Full access" with more specific scopes.

Once the app is created, copy the clientId (Consumer Key) and clientSecret (Consumer Secret). We recommend configuring them in the environment variables like so:

const app = new Reshuffle()
const salesforceConnector = new SalesforceConnector(app, {
  clientId: process.env.SALESFORCE_CLIENT_ID,
  clientSecret: process.env.SALESFORCE_CLIENT_SECRET,
  baseURL: process.env.RESHUFFLE_RUNTIME_BASE_URL,
  encryptionKey: process.env.RESHUFFLE_ENCRYPTION_KEY,
})

The configuration also uses RESHUFFLE_RUNTIME_BASE_URL to point to the base URL of the server hosting the Reshuffle runtime, and RESHUFFLE_ENCRYPTION_KEY which is a 64 digit hex string (32 bytes) which is used to encrypt the access tokens received from Salesforce during the authentication process.

During the authentication process, Salesforce sends back credentials including an access token, a refresh token and an instance URL. If you already have these access credentials, you can skip the authentication flow and pass them when initializing the connector like so:

const salesforceConnector = new SalesforceConnector(app, {
  clientId: process.env.SALESFORCE_CLIENT_ID,
  clientSecret: process.env.SALESFORCE_CLIENT_SECRET,
  baseURL: process.env.RESHUFFLE_RUNTIME_BASE_URL,
  encryptionKey: process.env.RESHUFFLE_ENCRYPTION_KEY,
  accessToken: process.env.SALESFORCE_ACCESS_TOKEN, /* credentials */
  refreshToken: process.env.SALESFORCE_REFRESH_TOKEN, /* credentials */
  instanceUrl: process.env.SALESFORCE_INSTANCE_URL, /* credentials */
})

Connector events

Query event

Example:

async (event, app) => {
  console.log('Salesforce event:', event)
})

This event is fired when the result of a query changes. This could be when a new object is added, and existing object removed, or one of the queried fields changes.

For example, the following event will trigger when a new Account object is created, when an Account object is removed or when an account name changes:

salesforceConnector.on(
  { query: 'SELECT Id,Name FROM Account' },
  async (event, app) => {
    console.log(event)
  },
)

Note that the event will not trigger if other fields, like the account owner, are changed. You can exapnd the query to SELECT other fields as well. In this case these fields will also trigger the event and will be returned in the event object.

Connector actions

Authenticate action

Definition:

() => void

Usage:

await salesforceConnector.authenticate()

Authenticate against the Salesforce API. This action return immediately if a connection is already authenticated or if it finds valid access tokens in the datastore and is able to connect with Salesforce.

If it does not have valid access token, the action attempts to open a browser to allow the user to authenticate through a standard OAuth flow.

Note that in order to complete the OAuth flow, Reshuffle must be accessible from the Internet, with its base URL provided to the connector config (typically through the RESHUFFLE_RUNTIME_BASE_URL environment variable). If Reshuffle is running on your dev machine, we recommend using ngrok to expose a local port to the world (see example in the scripts section of package.json).

When Reshuffle is running on a server, you can use the authenticator utility provided with this connector to start the authentication process from your (or your user's) machine.

This action throws an error if the connector already has Salesforce access credentials. This can happen if credentials were passed upon initialization, read from persistent store or if the action is called more than once.

Is Authenticated action

Definition:

() => boolean

Usage:

const isAuthenticated = salesforceConnector.isAuthenticated()

Checks whether the connector is authenticated with Salesforce. Auth credentials (access token, refresh token and instance URL) may be passed upon connector initialization, read from data store or obtained from Salesforce through the OAuth flow (see authenticate above).

Query action

Definition:

(
  query: string,
) => object

Usage:

const res = await salesforceConnector.query('SELECT Id, Name FROM Account')
console.log('Salesforce accounts:')
for (const account of res.records) {
  console.log(' ', account.Id, account.Name)
}

Query Salesforce for data.

Map action

Definition:

(
  type: string,
  func: object => void,
) => object

Usage:

const res = await salesforceConnector.map('Account', async (account) => {
  if (account.Name.startsWith('A')) {
    console.log(account)
  }
})

Apply a JavaScript function to process a collection of Salesforce objects of the specified type.

Sobject action

Definition:

(
  type: string,
) => object

Usage:

const account = await salesforceConnector.sobject('Account')
const res = account.find({ Name: 'Acme' }, '*')
})

Get an accessor to a Salesforce object type. The accessor provides methods for finding objects of this type and provide CRUD operations on this type of object.

SDK

SDK action

Definition:

() => object

Usage:

const conn = await salesforceConnector.sdk()

The connector uses JSForce to connect with Salesforce. This action returns the underlying JSForce connection so you can directly access its methods.