@pipedream/salesforce_rest_api 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/actions/add-contact-to-campaign/add-contact-to-campaign.mjs +1 -1
  2. package/actions/add-lead-to-campaign/add-lead-to-campaign.mjs +1 -1
  3. package/actions/convert-soap-xml-to-json/convert-soap-xml-to-json.mjs +1 -1
  4. package/actions/create-account/create-account.mjs +1 -1
  5. package/actions/create-attachment/create-attachment.mjs +1 -1
  6. package/actions/create-campaign/create-campaign.mjs +1 -1
  7. package/actions/create-case/create-case.mjs +1 -1
  8. package/actions/create-casecomment/create-casecomment.mjs +1 -1
  9. package/actions/create-contact/create-contact.mjs +1 -1
  10. package/actions/create-event/create-event.mjs +1 -1
  11. package/actions/create-lead/create-lead.mjs +1 -1
  12. package/actions/create-note/create-note.mjs +1 -1
  13. package/actions/create-opportunity/create-opportunity.mjs +1 -1
  14. package/actions/create-record/create-record.mjs +1 -1
  15. package/actions/create-task/create-task.mjs +1 -1
  16. package/actions/delete-opportunity/delete-opportunity.mjs +1 -1
  17. package/actions/delete-record/delete-record.mjs +1 -1
  18. package/actions/find-create-record/find-create-record.mjs +1 -1
  19. package/actions/find-records/find-records.mjs +1 -1
  20. package/actions/get-sobject-fields-values/get-sobject-fields-values.mjs +1 -1
  21. package/actions/insert-blob-data/insert-blob-data.mjs +1 -1
  22. package/actions/post-feed-to-chatter/post-feed-to-chatter.mjs +1 -1
  23. package/actions/soql-search/soql-search.mjs +1 -1
  24. package/actions/sosl-search/sosl-search.mjs +1 -1
  25. package/actions/update-account/update-account.mjs +1 -1
  26. package/actions/update-contact/update-contact.mjs +1 -1
  27. package/actions/update-opportunity/update-opportunity.mjs +1 -1
  28. package/actions/update-record/update-record.mjs +1 -1
  29. package/common/constants.mjs +4 -0
  30. package/package.json +1 -1
  31. package/salesforce_rest_api.app.mjs +15 -32
  32. package/sources/common-instant.mjs +29 -13
  33. package/sources/common.mjs +57 -57
  34. package/sources/new-outbound-message/new-outbound-message.mjs +1 -1
  35. package/sources/new-record/new-record.mjs +44 -37
  36. package/sources/new-record-instant/new-record-instant.mjs +1 -1
  37. package/sources/object-updated/object-updated.mjs +48 -26
  38. package/sources/object-updated-instant/object-updated-instant.mjs +1 -1
  39. package/sources/record-deleted/record-deleted.mjs +1 -1
  40. package/sources/record-deleted-instant/record-deleted-instant.mjs +1 -1
  41. package/sources/updated-field-on-record/updated-field-on-record.mjs +78 -111
  42. package/sources/updated-field-on-record-instant/updated-field-on-record-instant.mjs +1 -1
@@ -12,7 +12,7 @@ export default {
12
12
  See [Event SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_campaignmember.htm)
13
13
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
14
14
  `),
15
- version: "0.0.4",
15
+ version: "0.0.5",
16
16
  type: "action",
17
17
  props: {
18
18
  salesForceRestApi,
@@ -12,7 +12,7 @@ export default {
12
12
  See [Event SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_campaignmember.htm)
13
13
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
14
14
  `),
15
- version: "0.0.4",
15
+ version: "0.0.5",
16
16
  type: "action",
17
17
  props: {
18
18
  salesForceRestApi,
@@ -5,7 +5,7 @@ export default {
5
5
  key: "salesforce_rest_api-convert-soap-xml-to-json",
6
6
  name: "Convert SOAP XML Object to JSON",
7
7
  description: "Converts a SOAP XML Object received from Salesforce to JSON",
8
- version: "0.0.3",
8
+ version: "0.0.4",
9
9
  type: "action",
10
10
  props: {
11
11
  salesforce_rest_api,
@@ -17,7 +17,7 @@ export default {
17
17
  See [Account SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_account.htm)
18
18
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
19
19
  `),
20
- version: "0.2.5",
20
+ version: "0.2.6",
21
21
  type: "action",
22
22
  props: {
23
23
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Attachment SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_attachment.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.3.5",
19
+ version: "0.3.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Campaign SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_campaign.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Case SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_case.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [CaseComment SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_casecomment.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Contact SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_contact.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -11,7 +11,7 @@ export default {
11
11
  See [Event SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_event.htm)
12
12
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
13
13
  `),
14
- version: "0.2.5",
14
+ version: "0.2.6",
15
15
  type: "action",
16
16
  props: {
17
17
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Lead SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_lead.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Note SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_note.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Opportunity SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_opportunity.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -8,7 +8,7 @@ export default {
8
8
  Create new records of a given resource.
9
9
  See [docs](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_create.htm)
10
10
  `),
11
- version: "0.2.5",
11
+ version: "0.2.6",
12
12
  type: "action",
13
13
  props: {
14
14
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Task SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_task.htm)
17
17
  and [Create Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_create.htm)
18
18
  `),
19
- version: "0.3.5",
19
+ version: "0.3.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -9,7 +9,7 @@ export default {
9
9
  See [Opportunity SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_opportunity.htm)
10
10
  and [Delete Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_delete_record.htm)
11
11
  `),
12
- version: "0.2.5",
12
+ version: "0.2.6",
13
13
  type: "action",
14
14
  props: {
15
15
  salesforce,
@@ -5,7 +5,7 @@ export default {
5
5
  name: "Delete a Record in an Object",
6
6
  description:
7
7
  "Deletes an existing record in an object. [API Doc](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query.htm)",
8
- version: "0.1.3",
8
+ version: "0.1.4",
9
9
  type: "action",
10
10
  props: {
11
11
  salesForceRestApi,
@@ -6,7 +6,7 @@ export default {
6
6
  name: "Get Field Values from Object Record and optionally create one is none is found. ",
7
7
  description:
8
8
  "Finds a specified Salesforce record by a field. Optionally, create one if none is found. [API Docs](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_get_field_values.htm)",
9
- version: "0.1.3",
9
+ version: "0.1.4",
10
10
  type: "action",
11
11
  props: {
12
12
  salesForceRestApi,
@@ -5,7 +5,7 @@ export default {
5
5
  name: "Get Object Records",
6
6
  description:
7
7
  "Retrieves all records in an object or a record in an object by the given ID or criteria. [API Doc](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_get_field_values.htm)",
8
- version: "0.1.3",
8
+ version: "0.1.4",
9
9
  type: "action",
10
10
  props: {
11
11
  salesForceRestApi,
@@ -8,7 +8,7 @@ export default {
8
8
  Retrieve field values from a record. You can specify the fields you want to retrieve.
9
9
  See [docs](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_get_field_values.htm)
10
10
  `),
11
- version: "0.2.5",
11
+ version: "0.2.6",
12
12
  type: "action",
13
13
  props: {
14
14
  salesforce,
@@ -8,7 +8,7 @@ export default {
8
8
  Inserts blob data in Salesforce standard objects.
9
9
  See [docs](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm)
10
10
  `),
11
- version: "0.2.5",
11
+ version: "0.2.6",
12
12
  type: "action",
13
13
  props: {
14
14
  salesforce,
@@ -8,7 +8,7 @@ export default {
8
8
  Posts a message to the Chatter Feed.
9
9
  [See doc](https://developer.salesforce.com/docs/atlas.en-us.chatterapi.meta/chatterapi/quickreference_post_feed_item.htm)
10
10
  `),
11
- version: "0.0.4",
11
+ version: "0.0.5",
12
12
  type: "action",
13
13
  props: {
14
14
  salesForceRestApi,
@@ -8,7 +8,7 @@ export default {
8
8
  Executes a SOQL query.
9
9
  See [docs](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm)
10
10
  `),
11
- version: "0.2.6",
11
+ version: "0.2.7",
12
12
  type: "action",
13
13
  props: {
14
14
  salesforce,
@@ -8,7 +8,7 @@ export default {
8
8
  Executes the specified SOSL search.
9
9
  See [docs](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl.htm)
10
10
  `),
11
- version: "0.2.5",
11
+ version: "0.2.6",
12
12
  type: "action",
13
13
  props: {
14
14
  salesforce,
@@ -17,7 +17,7 @@ export default {
17
17
  See [Account SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_account.htm)
18
18
  and [Update Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_update_fields.htm)
19
19
  `),
20
- version: "0.2.5",
20
+ version: "0.2.6",
21
21
  type: "action",
22
22
  props: {
23
23
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Contact SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_contact.htm)
17
17
  and [Update Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_update_fields.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -16,7 +16,7 @@ export default {
16
16
  See [Opportunity SObject](https://developer.salesforce.com/docs/atlas.en-us.228.0.object_reference.meta/object_reference/sforce_api_objects_opportunity.htm)
17
17
  and [Update Record](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_update_fields.htm)
18
18
  `),
19
- version: "0.2.5",
19
+ version: "0.2.6",
20
20
  type: "action",
21
21
  props: {
22
22
  salesforce,
@@ -8,7 +8,7 @@ export default {
8
8
  Updates a record of a given resource.
9
9
  [See docs here](https://developer.salesforce.com/docs/atlas.en-us.228.0.api_rest.meta/api_rest/dome_update_fields.htm)
10
10
  `),
11
- version: "0.2.5",
11
+ version: "0.2.6",
12
12
  type: "action",
13
13
  props: {
14
14
  salesforce,
@@ -33,4 +33,8 @@ export default {
33
33
  CAMPAIGN_MEMBER: "CampaignMember",
34
34
  LEAD: "Lead",
35
35
  },
36
+ FIELD_NAME: {
37
+ CREATED_DATE: "CreatedDate",
38
+ LAST_MODIFIED_DATE: "LastModifiedDate",
39
+ },
36
40
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/salesforce_rest_api",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Pipedream Salesforce (REST API) Components",
5
5
  "main": "salesforce_rest_api.app.mjs",
6
6
  "keywords": [
@@ -1,6 +1,4 @@
1
1
  import { axios } from "@pipedream/platform";
2
- import salesforceWebhooks from "salesforce-webhooks";
3
- const { SalesforceClient } = salesforceWebhooks;
4
2
 
5
3
  export default {
6
4
  type: "app",
@@ -23,14 +21,21 @@ export default {
23
21
  type: "string",
24
22
  label: "SObject Type",
25
23
  description: "Standard object type of the record to get field values from",
26
- async options() {
24
+ async options({
25
+ page,
26
+ filter = this.isValidSObject,
27
+ mapper = ({
28
+ label, name: value,
29
+ }) => ({
30
+ label,
31
+ value,
32
+ }),
33
+ }) {
34
+ if (page !== 0) {
35
+ return [];
36
+ }
27
37
  const { sobjects } = await this.listSObjectTypes();
28
- return sobjects
29
- .filter(this.isValidSObject)
30
- .map((sobject) => ({
31
- label: sobject.label,
32
- value: sobject.name,
33
- }));
38
+ return sobjects.filter(filter).map(mapper);
34
39
  },
35
40
  },
36
41
  field: {
@@ -175,14 +180,6 @@ export default {
175
180
  // Remove milliseconds from date ISO string
176
181
  return dateString.replace(/\.[0-9]{3}/, "");
177
182
  },
178
- _getSalesforceClient() {
179
- const clientOpts = {
180
- apiVersion: this._apiVersion(),
181
- authToken: this._authToken(),
182
- instance: this._subdomain(),
183
- };
184
- return new SalesforceClient(clientOpts);
185
- },
186
183
  isValidSObject(sobject) {
187
184
  // Only the activity of those SObject types that have the `replicateable`
188
185
  // flag set is published via the `getUpdated` API.
@@ -196,21 +193,6 @@ export default {
196
193
  sobject.name.includes("History")
197
194
  );
198
195
  },
199
- async createWebhook(endpointUrl, sObjectType, event, secretToken, opts) {
200
- const client = this._getSalesforceClient();
201
- const webhookOpts = {
202
- endpointUrl,
203
- sObjectType,
204
- event,
205
- secretToken,
206
- ...opts,
207
- };
208
- return client.createWebhook(webhookOpts);
209
- },
210
- async deleteWebhook(webhookData) {
211
- const client = this._getSalesforceClient();
212
- return client.deleteWebhook(webhookData);
213
- },
214
196
  async listSObjectTypes() {
215
197
  const url = this._sObjectsApiUrl();
216
198
  return this._makeRequest({
@@ -226,6 +208,7 @@ export default {
226
208
  async getNameFieldForObjectType(objectType) {
227
209
  const url = this._sObjectTypeDescriptionApiUrl(objectType);
228
210
  const data = await this._makeRequest({
211
+ debug: true,
229
212
  url,
230
213
  });
231
214
  const nameField = data.fields.find((f) => f.nameField);
@@ -1,6 +1,8 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
-
3
2
  import salesforce from "../salesforce_rest_api.app.mjs";
3
+ import salesforceWebhooks from "salesforce-webhooks";
4
+
5
+ const { SalesforceClient } = salesforceWebhooks;
4
6
 
5
7
  export default {
6
8
  dedupe: "unique",
@@ -31,19 +33,17 @@ export default {
31
33
  const secretToken = uuidv4();
32
34
  let webhookData;
33
35
  try {
34
- webhookData = await this.salesforce.createWebhook(
35
- this.http.endpoint,
36
- this.objectType,
37
- this.getEventType(),
36
+ webhookData = await this.createWebhook({
37
+ endpointUrl: this.http.endpoint,
38
+ sObjectType: this.objectType,
39
+ event: this.getEventType(),
38
40
  secretToken,
39
- {
40
- fieldsToCheck: this.getFieldsToCheck(),
41
- fieldsToCheckMode: this.getFieldsToCheckMode(),
42
- skipValidation: true, // neccessary for custom objects
43
- },
44
- );
41
+ fieldsToCheck: this.getFieldsToCheck(),
42
+ fieldsToCheckMode: this.getFieldsToCheckMode(),
43
+ skipValidation: true, // neccessary for custom objects
44
+ });
45
45
  } catch (err) {
46
- console.log("Create webhook error:", err.response?.data ?? err);
46
+ console.log("Create webhook error:", err);
47
47
  throw err;
48
48
  }
49
49
  this._setSecretToken(secretToken);
@@ -52,10 +52,26 @@ export default {
52
52
  async deactivate() {
53
53
  // Create the webhook from the Salesforce platform
54
54
  const webhookData = this._getWebhookData();
55
- await this.salesforce.deleteWebhook(webhookData);
55
+ await this.deleteWebhook(webhookData);
56
56
  },
57
57
  },
58
58
  methods: {
59
+ getClient() {
60
+ const { salesforce } = this;
61
+ return new SalesforceClient({
62
+ apiVersion: salesforce._apiVersion(),
63
+ authToken: salesforce._authToken(),
64
+ instance: salesforce._subdomain(),
65
+ });
66
+ },
67
+ createWebhook(args = {}) {
68
+ const client = this.getClient();
69
+ return client.createWebhook(args);
70
+ },
71
+ deleteWebhook(args = {}) {
72
+ const client = this.getClient();
73
+ return client.deleteWebhook(args);
74
+ },
59
75
  _getSecretToken() {
60
76
  return this.db.get("secretToken");
61
77
  },
@@ -1,5 +1,6 @@
1
1
  import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
2
2
  import salesforce from "../salesforce_rest_api.app.mjs";
3
+ import constants from "../common/constants.mjs";
3
4
 
4
5
  export default {
5
6
  dedupe: "unique",
@@ -36,6 +37,12 @@ export default {
36
37
  },
37
38
  },
38
39
  methods: {
40
+ getObjectTypeColumns() {
41
+ return this.db.get("columns") ?? [];
42
+ },
43
+ setObjectTypeColumns(columns) {
44
+ this.db.set("columns", columns);
45
+ },
39
46
  getLatestDateCovered() {
40
47
  return this.db.get("latestDateCovered");
41
48
  },
@@ -51,72 +58,65 @@ export default {
51
58
  processEvent() {
52
59
  throw new Error("processEvent is not implemented");
53
60
  },
54
- chunkArray(array, chunkSize = 25) {
55
- return array.reduce((chunks, item, index) => {
56
- const chunkIndex = Math.floor(index / chunkSize);
57
-
58
- if (!chunks[chunkIndex]) {
59
- chunks[chunkIndex] = [];
60
- }
61
-
62
- chunks[chunkIndex].push(item);
63
-
64
- return chunks;
65
- }, []);
66
- },
67
- getRelativeObjectUrl(id, historyObjectType) {
68
- const {
69
- salesforce,
70
- objectType,
71
- } = this;
72
- return `/services/data/v${salesforce._apiVersion()}/sobjects/${historyObjectType || objectType}/${id}`;
73
- },
74
- getBatchRequests(ids, historyObjectType) {
75
- return ids.map((id) => ({
76
- method: "GET",
77
- url: this.getRelativeObjectUrl(id, historyObjectType),
78
- }));
79
- },
80
- batchRequest(args = {}) {
61
+ getObjectTypeDescription(objectType) {
81
62
  const { salesforce } = this;
82
63
  return salesforce._makeRequest({
83
64
  debug: true,
84
- method: "POST",
85
- url: `${salesforce._baseApiVersionUrl()}/composite/batch`,
86
- ...args,
65
+ url: salesforce._sObjectTypeDescriptionApiUrl(objectType),
87
66
  });
88
67
  },
89
- makeChunkBatchRequests({
90
- ids, objectType, ...args
68
+ query({
69
+ query, ...args
91
70
  } = {}) {
92
- const {
93
- batchRequest,
94
- chunkArray,
95
- } = this;
96
-
97
- const chunks = chunkArray(ids);
98
- const promises = chunks.map((ids) => batchRequest({
99
- data: {
100
- batchRequests: this.getBatchRequests(ids, objectType),
101
- ...args?.data,
102
- },
71
+ const { salesforce } = this;
72
+ const baseUrl = salesforce._baseApiVersionUrl();
73
+ return salesforce._makeRequest({
74
+ url: `${baseUrl}/query/?q=${encodeURIComponent(query)}`,
103
75
  ...args,
104
- }));
105
- return Promise.all(promises);
76
+ });
106
77
  },
107
- getChunkBatchResults(responses) {
108
- return responses.reduce((acc, { results }) => [
109
- ...acc,
110
- ...results,
111
- ], []);
78
+ queryObjects({
79
+ objectType, columns,
80
+ startTimestamp, endTimestamp,
81
+ dateFieldName = constants.FIELD_NAME.CREATED_DATE,
82
+ limit = 100, offset = 0, ...args
83
+ } = {}) {
84
+ return this.query({
85
+ debug: true,
86
+ query: `
87
+ SELECT ${columns.join(", ")}
88
+ FROM ${objectType}
89
+ WHERE ${dateFieldName} > ${startTimestamp} AND ${dateFieldName} <= ${endTimestamp}
90
+ ORDER BY ${dateFieldName} DESC
91
+ LIMIT ${limit} OFFSET ${offset}
92
+ `,
93
+ ...args,
94
+ });
112
95
  },
113
- async makeChunkBatchRequestsAndGetResults(args) {
114
- const {
115
- makeChunkBatchRequests,
116
- getChunkBatchResults,
117
- } = this;
118
- const responses = await makeChunkBatchRequests(args);
119
- return getChunkBatchResults(responses);
96
+ async paginate({
97
+ fn = this.queryObjects, limit = 100, offset = 0, maxRecords = 4000, ...args
98
+ } = {}) {
99
+ let records = [];
100
+ let nextRecords = [];
101
+
102
+ do {
103
+ ({ records: nextRecords } =
104
+ await fn({
105
+ ...args,
106
+ offset,
107
+ limit,
108
+ }));
109
+
110
+ records = [
111
+ ...records,
112
+ ...nextRecords,
113
+ ];
114
+
115
+ offset += limit;
116
+
117
+ } while (records.length < maxRecords && nextRecords.length === limit);
118
+
119
+ return records;
120
120
  },
121
121
  },
122
122
  async run(event) {
@@ -6,7 +6,7 @@ export default {
6
6
  name: "New Outbound Message (Instant)",
7
7
  key: "salesforce_rest_api-new-outbound-message",
8
8
  description: "Emit new event when a new outbound message is received in Salesforce. See Salesforce's guide on setting up [Outbound Messaging](https://sforce.co/3JbZJom). Set the Outbound Message's Endpoint URL to the endpoint of the created source. The \"Send Session ID\" option must be enabled for validating outbound messages from Salesforce.",
9
- version: "0.1.4",
9
+ version: "0.1.5",
10
10
  dedupe: "unique",
11
11
  props: {
12
12
  db: "$.service.db",
@@ -8,26 +8,34 @@ export default {
8
8
  name: "New Record (of Selectable Type)",
9
9
  key: "salesforce_rest_api-new-record",
10
10
  description: "Emit new event (at regular intervals) when a record of arbitrary object type (selected as an input parameter by the user) is created. See [the docs](https://sforce.co/3yPSJZy) for more information.",
11
- version: "0.0.3",
11
+ version: "0.0.5",
12
+ hooks: {
13
+ ...common.hooks,
14
+ async activate() {
15
+ const {
16
+ objectType,
17
+ getObjectTypeDescription,
18
+ setObjectTypeColumns,
19
+ } = this;
20
+
21
+ await common.hooks.activate.call(this);
22
+
23
+ const { fields } = await getObjectTypeDescription(objectType);
24
+ const columns = fields.map(({ name }) => name);
25
+
26
+ setObjectTypeColumns(columns);
27
+ },
28
+ },
12
29
  methods: {
13
30
  ...common.methods,
14
- isItemRelevant(item, startTimestamp, endTimestamp) {
15
- if (!item) {
16
- return false;
17
- }
18
- const startDate = Date.parse(startTimestamp);
19
- const endDate = Date.parse(endTimestamp);
20
- const createdDate = Date.parse(item.CreatedDate);
21
- return startDate <= createdDate && endDate >= createdDate;
22
- },
23
- generateMeta(item) {
24
- const nameField = this.getNameField();
31
+ generateMeta(item, fieldName) {
32
+ const { objectType } = this;
25
33
  const {
26
34
  CreatedDate: createdDate,
35
+ [fieldName]: name,
27
36
  Id: id,
28
- [nameField]: name,
29
37
  } = item;
30
- const entityType = startCase(this.objectType);
38
+ const entityType = startCase(objectType);
31
39
  const summary = `New ${entityType} created: ${name}`;
32
40
  const ts = Date.parse(createdDate);
33
41
  return {
@@ -38,11 +46,11 @@ export default {
38
46
  },
39
47
  async processEvent(eventData) {
40
48
  const {
41
- salesforce,
49
+ paginate,
42
50
  objectType,
43
51
  setLatestDateCovered,
44
- makeChunkBatchRequestsAndGetResults,
45
- isItemRelevant,
52
+ getObjectTypeColumns,
53
+ getNameField,
46
54
  generateMeta,
47
55
  $emit: emit,
48
56
  } = this;
@@ -51,32 +59,31 @@ export default {
51
59
  startTimestamp,
52
60
  endTimestamp,
53
61
  } = eventData;
54
- const {
55
- ids,
56
- latestDateCovered,
57
- } = await salesforce.getUpdatedForObjectType(
62
+
63
+ const fieldName = getNameField();
64
+ const columns = getObjectTypeColumns();
65
+
66
+ const events = await paginate({
58
67
  objectType,
59
68
  startTimestamp,
60
69
  endTimestamp,
61
- );
62
- setLatestDateCovered(latestDateCovered);
70
+ columns,
71
+ });
63
72
 
64
- if (!ids?.length) {
65
- return console.log("No batch requests to send");
66
- }
73
+ const [
74
+ latestEvent,
75
+ ] = events;
67
76
 
68
- const results = await makeChunkBatchRequestsAndGetResults({
69
- ids,
70
- });
77
+ if (latestEvent?.CreatedDate) {
78
+ const latestDateCovered = new Date(latestEvent.CreatedDate);
79
+ latestDateCovered.setSeconds(0);
80
+ setLatestDateCovered(latestDateCovered.toISOString());
81
+ }
71
82
 
72
- results
73
- .filter(({
74
- statusCode, result: item,
75
- }) =>
76
- statusCode === 200
77
- && isItemRelevant(item, startTimestamp, endTimestamp))
78
- .forEach(({ result: item }) => {
79
- const meta = generateMeta(item);
83
+ Array.from(events)
84
+ .reverse()
85
+ .forEach((item) => {
86
+ const meta = generateMeta(item, fieldName);
80
87
  emit(item, meta);
81
88
  });
82
89
  },
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Record (Instant, of Selectable Type)",
8
8
  key: "salesforce_rest_api-new-record-instant",
9
9
  description: "Emit new event immediately after a record of arbitrary object type (selected as an input parameter by the user) is created",
10
- version: "0.0.2",
10
+ version: "0.0.3",
11
11
  hooks: {
12
12
  ...common.hooks,
13
13
  async deploy() {
@@ -1,6 +1,6 @@
1
1
  import startCase from "lodash/startCase.js";
2
-
3
2
  import common from "../common.mjs";
3
+ import constants from "../../common/constants.mjs";
4
4
 
5
5
  export default {
6
6
  ...common,
@@ -8,32 +8,51 @@ export default {
8
8
  name: "New Updated Object (of Selectable Type)",
9
9
  key: "salesforce_rest_api-object-updated",
10
10
  description: "Emit new event (at regular intervals) when an object of arbitrary type (selected as an input parameter by the user) is updated. [See the docs](https://sforce.co/3yPSJZy) for more information.",
11
- version: "0.1.8",
11
+ version: "0.1.10",
12
+ hooks: {
13
+ ...common.hooks,
14
+ async activate() {
15
+ const {
16
+ objectType,
17
+ getObjectTypeDescription,
18
+ setObjectTypeColumns,
19
+ } = this;
20
+
21
+ await common.hooks.activate.call(this);
22
+
23
+ const { fields } = await getObjectTypeDescription(objectType);
24
+ const columns = fields.map(({ name }) => name);
25
+
26
+ setObjectTypeColumns(columns);
27
+ },
28
+ },
12
29
  methods: {
13
30
  ...common.methods,
14
- generateMeta(item) {
15
- const nameField = this.getNameField();
31
+ generateMeta(item, fieldName) {
32
+ const { objectType } = this;
33
+
16
34
  const {
17
35
  LastModifiedDate: lastModifiedDate,
36
+ [fieldName]: name,
18
37
  Id: id,
19
- [nameField]: name,
20
38
  } = item;
21
- const entityType = startCase(this.objectType);
39
+
40
+ const entityType = startCase(objectType);
22
41
  const summary = `${entityType} updated: ${name}`;
23
42
  const ts = Date.parse(lastModifiedDate);
24
- const compositeId = `${id}-${ts}`;
25
43
  return {
26
- id: compositeId,
44
+ id: `${id}-${ts}`,
27
45
  summary,
28
46
  ts,
29
47
  };
30
48
  },
31
49
  async processEvent(eventData) {
32
50
  const {
33
- salesforce,
51
+ getNameField,
52
+ getObjectTypeColumns,
53
+ paginate,
34
54
  objectType,
35
55
  setLatestDateCovered,
36
- makeChunkBatchRequestsAndGetResults,
37
56
  generateMeta,
38
57
  $emit: emit,
39
58
  } = this;
@@ -43,28 +62,31 @@ export default {
43
62
  endTimestamp,
44
63
  } = eventData;
45
64
 
46
- const {
47
- ids,
48
- latestDateCovered,
49
- } = await salesforce.getUpdatedForObjectType(
65
+ const fieldName = getNameField();
66
+ const columns = getObjectTypeColumns();
67
+
68
+ const events = await paginate({
50
69
  objectType,
51
70
  startTimestamp,
52
71
  endTimestamp,
53
- );
54
- setLatestDateCovered(latestDateCovered);
72
+ columns,
73
+ dateFieldName: constants.FIELD_NAME.LAST_MODIFIED_DATE,
74
+ });
55
75
 
56
- if (!ids?.length) {
57
- return console.log("No batch requests to send");
58
- }
76
+ const [
77
+ latestEvent,
78
+ ] = events;
59
79
 
60
- const results = await makeChunkBatchRequestsAndGetResults({
61
- ids,
62
- });
80
+ if (latestEvent?.LastModifiedDate) {
81
+ const latestDateCovered = new Date(latestEvent.LastModifiedDate);
82
+ latestDateCovered.setSeconds(0);
83
+ setLatestDateCovered(latestDateCovered.toISOString());
84
+ }
63
85
 
64
- results
65
- .filter(({ statusCode }) => statusCode === 200)
66
- .forEach(({ result: item }) => {
67
- const meta = generateMeta(item);
86
+ Array.from(events)
87
+ .reverse()
88
+ .forEach((item) => {
89
+ const meta = generateMeta(item, fieldName);
68
90
  emit(item, meta);
69
91
  });
70
92
  },
@@ -8,7 +8,7 @@ export default {
8
8
  name: "New Updated Object (Instant, of Selectable Type)",
9
9
  key: "salesforce_rest_api-object-updated-instant",
10
10
  description: "Emit new event immediately after an object of arbitrary type (selected as an input parameter by the user) is updated",
11
- version: "0.1.4",
11
+ version: "0.1.5",
12
12
  methods: {
13
13
  ...common.methods,
14
14
  generateMeta(data) {
@@ -8,7 +8,7 @@ export default {
8
8
  name: "New Deleted Record (of Selectable Type)",
9
9
  key: "salesforce_rest_api-record-deleted",
10
10
  description: "Emit new event (at regular intervals) when a record of arbitrary object type (selected as an input parameter by the user) is deleted. [See the docs](https://sforce.co/3msDDEE) for more information.",
11
- version: "0.0.2",
11
+ version: "0.0.3",
12
12
  methods: {
13
13
  ...common.methods,
14
14
  generateMeta(item) {
@@ -8,7 +8,7 @@ export default {
8
8
  name: "New Deleted Record (Instant, of Selectable Type)",
9
9
  key: "salesforce_rest_api-record-deleted-instant",
10
10
  description: "Emit new event immediately after a record of arbitrary object type (selected as an input parameter by the user) is deleted",
11
- version: "0.0.2",
11
+ version: "0.0.3",
12
12
  methods: {
13
13
  ...common.methods,
14
14
  generateMeta(data) {
@@ -1,6 +1,6 @@
1
- import startCase from "lodash/startCase.js";
2
-
1
+ import words from "lodash/words.js";
3
2
  import common from "../common.mjs";
3
+
4
4
  const { salesforce } = common.props;
5
5
 
6
6
  /**
@@ -11,38 +11,29 @@ const { salesforce } = common.props;
11
11
  */
12
12
  export default {
13
13
  ...common,
14
+ dedupe: "greatest",
14
15
  type: "source",
15
16
  name: "New Updated Field on Record (of Selectable Type)",
16
17
  key: "salesforce_rest_api-updated-field-on-record",
17
18
  description: "Emit new event (at regular intervals) when a field of your choosing is updated on any record of a specified Salesforce object. Field history tracking must be enabled for the chosen field. See the docs on [field history tracking](https://sforce.co/3mtj0rF) and [history objects](https://sforce.co/3Fn4lWB) for more information.",
18
- version: "0.1.8",
19
+ version: "0.1.10",
19
20
  props: {
20
21
  ...common.props,
21
22
  objectType: {
22
23
  type: common.props.objectType.type,
23
24
  label: common.props.objectType.label,
24
25
  description: common.props.objectType.description,
25
- async options(context) {
26
- const { page } = context;
27
- if (page !== 0) {
28
- return {
29
- options: [],
30
- };
31
- }
32
-
33
- const { sobjects } = await this.salesforce.listSObjectTypes();
34
- // Filter options to include only sObjects with associated
35
- // [history](https://sforce.co/3Fn4lWB) objects
36
- const options = sobjects
37
- .filter(this.isValidSObject)
38
- .map((sobject) => ({
39
- label: sobjects.find((o) => o.name === sobject.associateParentEntity).label,
40
- value: sobject.associateParentEntity,
41
- }));
42
- return {
43
- options,
44
- };
45
- },
26
+ propDefinition: [
27
+ salesforce,
28
+ "objectType",
29
+ () => ({
30
+ filter: ({
31
+ replicateable,
32
+ associateEntityType,
33
+ }) => replicateable && associateEntityType === "History",
34
+ mapper: ({ associateParentEntity: value }) => words(value).join(" "),
35
+ }),
36
+ ],
46
37
  },
47
38
  field: {
48
39
  propDefinition: [
@@ -64,62 +55,64 @@ export default {
64
55
  hooks: {
65
56
  ...common.hooks,
66
57
  async activate() {
58
+ const {
59
+ objectType,
60
+ getObjectTypeDescription,
61
+ setHistoryObjectType,
62
+ setObjectTypeColumns,
63
+ } = this;
64
+
67
65
  await common.hooks.activate.call(this);
68
- const historyObject = await this.salesforce.getHistorySObjectForObjectType(this.objectType);
69
- if (!historyObject) {
70
- throw new Error(`History object not found for "${this.objectType}"`);
71
- }
72
- this._setHistoryObjectType(historyObject.name);
66
+
67
+ const historyObjectType = `${objectType}History`;
68
+
69
+ const { fields } = await getObjectTypeDescription(historyObjectType);
70
+ const columns = fields.map(({ name }) => name);
71
+
72
+ setHistoryObjectType(historyObjectType);
73
+ setObjectTypeColumns(columns);
73
74
  },
74
75
  },
75
76
  methods: {
76
77
  ...common.methods,
77
- _getHistoryObjectType() {
78
+ getHistoryObjectType() {
78
79
  return this.db.get("historyObjectType");
79
80
  },
80
- _setHistoryObjectType(historyObjectType) {
81
+ setHistoryObjectType(historyObjectType) {
81
82
  this.db.set("historyObjectType", historyObjectType);
82
83
  },
83
- _getParentId(item) {
84
- const parentIdKey = `${this.objectType}Id`;
85
- return item[parentIdKey] ?? item["ParentId"];
86
- },
87
- getUniqueParentIds(items) {
88
- // To fetch associated sObject records only once, create a set of the "parent IDs" of the
89
- // history object records
90
- const parentIdSet = new Set(items.map(this._getParentId).filter((id) => id));
91
- return Array.from(parentIdSet);
92
- },
93
- isValidSObject(sobject) {
94
- // Only the activity of those SObject types that have the `replicateable`
95
- // flag set is published via the `getUpdated` API.
96
- //
97
- // See the API docs here: https://sforce.co/3gDy3uP
98
- return sobject.replicateable && this.salesforce.isHistorySObject(sobject);
99
- },
100
84
  isRelevant(item) {
101
- const isFieldRelevant = item.Field === this.field;
102
- const isFieldValueRelevant = !this.fieldUpdatedTo || item.NewValue === this.fieldUpdatedTo;
85
+ const {
86
+ field,
87
+ fieldUpdatedTo,
88
+ } = this;
89
+
90
+ const isFieldRelevant =
91
+ item.Field === field
92
+ || item.Field === `${item.DataType}${field}`;
93
+
94
+ const isFieldValueRelevant =
95
+ !fieldUpdatedTo
96
+ || item.NewValue === fieldUpdatedTo;
97
+
103
98
  return isFieldRelevant && isFieldValueRelevant;
104
99
  },
105
100
  generateMeta(event) {
106
- const nameField = this.getNameField();
107
101
  const {
108
- record: item = {},
109
- update,
110
- } = event;
111
- const { [nameField]: name } = item;
102
+ objectType,
103
+ field,
104
+ } = this;
105
+
112
106
  const {
113
- Id: id,
114
107
  CreatedDate: createdDate,
115
- } = update;
116
- const entityType = startCase(this.objectType);
117
- const summary = `${this.field} on ${entityType}: ${name}`;
108
+ Id: id,
109
+ [`${objectType}Id`]: objectId,
110
+ } = event;
111
+
118
112
  const ts = Date.parse(createdDate);
119
- const compositeId = `${id}-${ts}`;
120
113
  return {
121
- id: compositeId,
122
- summary,
114
+ id: `${id}-${ts}`,
115
+ summary: `${field} on ${objectType}: ${objectId}`,
123
116
  ts,
124
117
  };
125
118
  },
@@ -127,68 +120,42 @@ export default {
127
120
  startTimestamp, endTimestamp,
128
121
  }) {
129
122
  const {
130
- salesforce,
131
- _getHistoryObjectType,
123
+ getHistoryObjectType,
124
+ getObjectTypeColumns,
132
125
  setLatestDateCovered,
133
- makeChunkBatchRequestsAndGetResults,
134
126
  isRelevant,
135
- getUniqueParentIds,
136
- _getParentId,
127
+ paginate,
137
128
  generateMeta,
138
129
  $emit: emit,
139
130
  } = this;
140
131
 
141
- let historyItemRetrievals = [];
142
- let itemRetrievals = [];
143
- const historyObjectType = _getHistoryObjectType();
144
- const {
145
- ids,
146
- latestDateCovered,
147
- } = await salesforce.getUpdatedForObjectType(
148
- historyObjectType,
132
+ const objectType = getHistoryObjectType();
133
+ const columns = getObjectTypeColumns();
134
+
135
+ const events = await paginate({
136
+ objectType,
149
137
  startTimestamp,
150
138
  endTimestamp,
151
- );
139
+ columns,
140
+ });
152
141
 
153
- setLatestDateCovered((new Date(latestDateCovered)).toISOString());
142
+ const [
143
+ latestEvent,
144
+ ] = events;
154
145
 
155
- if (ids?.length) {
156
- historyItemRetrievals = await makeChunkBatchRequestsAndGetResults({
157
- ids,
158
- objectType: historyObjectType,
159
- });
146
+ if (latestEvent?.CreatedDate) {
147
+ const latestDateCovered = new Date(latestEvent.CreatedDate);
148
+ latestDateCovered.setSeconds(0);
149
+ setLatestDateCovered(latestDateCovered.toISOString());
160
150
  }
161
151
 
162
- const historyItems = historyItemRetrievals
163
- .filter(({
164
- statusCode, result: item,
165
- }) => statusCode === 200 && isRelevant(item))
166
- .map(({ result: item }) => item);
167
-
168
- const parentIds = getUniqueParentIds(historyItems);
169
-
170
- if (parentIds.length) {
171
- itemRetrievals = await makeChunkBatchRequestsAndGetResults({
172
- ids: parentIds,
152
+ Array.from(events)
153
+ .reverse()
154
+ .filter(isRelevant)
155
+ .forEach((event) => {
156
+ const meta = generateMeta(event);
157
+ emit(event, meta);
173
158
  });
174
- }
175
-
176
- const itemsById = itemRetrievals
177
- .filter(({ statusCode }) => statusCode === 200)
178
- .reduce((acc, { result: item }) => ({
179
- ...acc,
180
- [item.Id]: item,
181
- }), {});
182
-
183
- const events = historyItems.map((item) => ({
184
- update: item,
185
- record: itemsById[_getParentId(item)],
186
- }));
187
-
188
- events.forEach((event) => {
189
- const meta = generateMeta(event);
190
- emit(event, meta);
191
- });
192
159
  },
193
160
  },
194
161
  };
@@ -9,7 +9,7 @@ export default {
9
9
  name: "New Updated Field on Record (Instant, of Selectable Type)",
10
10
  key: "salesforce_rest_api-updated-field-on-record-instant",
11
11
  description: "Emit new event immediately after a field of your choosing is updated on any record of a specified Salesforce object",
12
- version: "0.1.4",
12
+ version: "0.1.5",
13
13
  props: {
14
14
  ...common.props,
15
15
  field: {