@pipedream/salesforce_rest_api 1.6.0 → 1.7.0

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 (23) hide show
  1. package/actions/create-attachment/create-attachment.mjs +1 -1
  2. package/actions/get-case/get-case.mjs +36 -0
  3. package/actions/get-user/get-user.mjs +34 -0
  4. package/actions/list-case-comments/list-case-comments.mjs +32 -0
  5. package/actions/list-email-messages/list-email-messages.mjs +38 -0
  6. package/actions/list-email-templates/list-email-templates.mjs +23 -0
  7. package/actions/list-knowledge-articles/list-knowledge-articles.mjs +23 -0
  8. package/actions/send-email/send-email.mjs +60 -0
  9. package/actions/update-email-template/update-email-template.mjs +81 -0
  10. package/package.json +1 -1
  11. package/sources/case-updated-instant/case-updated-instant.mjs +43 -0
  12. package/sources/common/common-new-record.mjs +157 -0
  13. package/sources/common/common-updated-record.mjs +198 -0
  14. package/sources/{common.mjs → common/common.mjs} +2 -2
  15. package/sources/email-template-updated-instant/email-template-updated-instant.mjs +43 -0
  16. package/sources/knowledge-article-updated-instant/knowledge-article-updated-instant.mjs +43 -0
  17. package/sources/new-case-instant/new-case-instant.mjs +43 -0
  18. package/sources/new-email-template-instant/new-email-template-instant.mjs +43 -0
  19. package/sources/new-knowledge-article-instant/new-knowledge-article-instant.mjs +43 -0
  20. package/sources/new-record-instant/new-record-instant.mjs +4 -118
  21. package/sources/record-deleted-instant/record-deleted-instant.mjs +2 -2
  22. package/sources/record-updated-instant/record-updated-instant.mjs +4 -138
  23. /package/sources/{common-webhook-methods.mjs → common/common-webhook-methods.mjs} +0 -0
@@ -18,7 +18,7 @@ export default {
18
18
  key: "salesforce_rest_api-create-attachment",
19
19
  name: "Create Attachment",
20
20
  description: `Creates an Attachment on a parent object. [See the documentation](${docsLink})`,
21
- version: "0.5.0",
21
+ version: "0.5.1",
22
22
  type: "action",
23
23
  props,
24
24
  async run({ $ }) {
@@ -0,0 +1,36 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-get-case",
5
+ name: "Get Case",
6
+ description: "Retrieves a case by its ID. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_get_field_values.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ caseId: {
12
+ propDefinition: [
13
+ salesforce,
14
+ "recordId",
15
+ () => ({
16
+ objType: "Case",
17
+ }),
18
+ ],
19
+ label: "Case ID",
20
+ description: "The case ID to retrieve",
21
+ },
22
+ },
23
+ async run({ $ }) {
24
+ const fields = (await this.salesforce.getFieldsForObjectType("Case")).map(({ name }) => name);
25
+
26
+ let query = `SELECT ${fields.join(", ")} FROM Case WHERE Id = '${this.caseId}'`;
27
+
28
+ const { records } = await this.salesforce.query({
29
+ $,
30
+ query,
31
+ });
32
+
33
+ $.export("$summary", `Successfully retrieved case with ID ${this.caseId}`);
34
+ return records[0];
35
+ },
36
+ };
@@ -0,0 +1,34 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-get-user",
5
+ name: "Get User",
6
+ description: "Retrieves a user by their ID. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_get_field_values.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ userId: {
12
+ propDefinition: [
13
+ salesforce,
14
+ "recordId",
15
+ () => ({
16
+ objType: "User",
17
+ }),
18
+ ],
19
+ },
20
+ },
21
+ async run({ $ }) {
22
+ const fields = (await this.salesforce.getFieldsForObjectType("User")).map(({ name }) => name);
23
+
24
+ let query = `SELECT ${fields.join(", ")} FROM User WHERE Id = '${this.userId}'`;
25
+
26
+ const { records } = await this.salesforce.query({
27
+ $,
28
+ query,
29
+ });
30
+
31
+ $.export("$summary", `Sucessfully retrieved user with ID ${this.userId}`);
32
+ return records[0];
33
+ },
34
+ };
@@ -0,0 +1,32 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-list-case-comments",
5
+ name: "List Case Comments",
6
+ description: "Lists all comments for a case. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_get_field_values.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ caseId: {
12
+ propDefinition: [
13
+ salesforce,
14
+ "recordId",
15
+ () => ({
16
+ objType: "Case",
17
+ }),
18
+ ],
19
+ },
20
+ },
21
+ async run({ $ }) {
22
+ const fields = (await this.salesforce.getFieldsForObjectType("CaseComment")).map(({ name }) => name);
23
+ let query = `SELECT ${fields.join(", ")} FROM CaseComment WHERE ParentId = '${this.caseId}'`;
24
+
25
+ const { records } = await this.salesforce.query({
26
+ $,
27
+ query,
28
+ });
29
+ $.export("$summary", `Sucessfully retrieved ${records.length} comments for case with ID ${this.caseId}`);
30
+ return records;
31
+ },
32
+ };
@@ -0,0 +1,38 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-list-email-messages",
5
+ name: "List Email Messages",
6
+ description: "Lists all email messages for a case. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_get_field_values.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ caseId: {
12
+ propDefinition: [
13
+ salesforce,
14
+ "recordId",
15
+ () => ({
16
+ objType: "Case",
17
+ }),
18
+ ],
19
+ label: "Case ID",
20
+ description: "The ID of the case to retrieve email messages for",
21
+ optional: true,
22
+ },
23
+ },
24
+ async run({ $ }) {
25
+ const fields = (await this.salesforce.getFieldsForObjectType("EmailMessage")).map(({ name }) => name);
26
+ let query = `SELECT ${fields.join(", ")} FROM EmailMessage`;
27
+ if (this.caseId) {
28
+ query += ` WHERE RelatedToId = '${this.caseId}'`;
29
+ }
30
+
31
+ const { records } = await this.salesforce.query({
32
+ $,
33
+ query,
34
+ });
35
+ $.export("$summary", `Sucessfully retrieved ${records.length} email messages for case with ID ${this.caseId}`);
36
+ return records;
37
+ },
38
+ };
@@ -0,0 +1,23 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-list-email-templates",
5
+ name: "List Email Templates",
6
+ description: "Lists all email templates. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_emailtemplate.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ },
12
+ async run({ $ }) {
13
+ const fields = (await this.salesforce.getFieldsForObjectType("EmailTemplate")).map(({ name }) => name);
14
+ const query = `SELECT ${fields.join(", ")} FROM EmailTemplate`;
15
+
16
+ const { records } = await this.salesforce.query({
17
+ $,
18
+ query,
19
+ });
20
+ $.export("$summary", `Sucessfully retrieved ${records.length} email templates`);
21
+ return records;
22
+ },
23
+ };
@@ -0,0 +1,23 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-list-knowledge-articles",
5
+ name: "List Knowledge Articles",
6
+ description: "Lists all knowledge articles. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_knowledgearticle.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ },
12
+ async run({ $ }) {
13
+ const fields = (await this.salesforce.getFieldsForObjectType("KnowledgeArticle")).map(({ name }) => name);
14
+ const query = `SELECT ${fields.join(", ")} FROM KnowledgeArticle`;
15
+
16
+ const { records } = await this.salesforce.query({
17
+ $,
18
+ query,
19
+ });
20
+ $.export("$summary", `Sucessfully retrieved ${records.length} knowledge articles`);
21
+ return records;
22
+ },
23
+ };
@@ -0,0 +1,60 @@
1
+ import salesforce from "../../salesforce_rest_api.app.mjs";
2
+
3
+ export default {
4
+ key: "salesforce_rest_api-send-email",
5
+ name: "Send Email",
6
+ description: "Sends an email. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_action.meta/api_action/actions_obj_email_simple.htm)",
7
+ version: "0.0.1",
8
+ type: "action",
9
+ props: {
10
+ salesforce,
11
+ emailAddress: {
12
+ type: "string",
13
+ label: "Email Address",
14
+ description: "The email address to send the email to",
15
+ },
16
+ emailSubject: {
17
+ type: "string",
18
+ label: "Subject",
19
+ description: "The subject of the email",
20
+ },
21
+ emailBody: {
22
+ type: "string",
23
+ label: "Body",
24
+ description: "The body of the email",
25
+ },
26
+ logEmailOnSend: {
27
+ type: "boolean",
28
+ label: "Log Email on Send",
29
+ description: "Indicates whether to log the email on the specified records’ activity time lines",
30
+ optional: true,
31
+ },
32
+ },
33
+ methods: {
34
+ sendEmail(opts = {}) {
35
+ return this.salesforce._makeRequest({
36
+ url: `${this.salesforce._baseApiVersionUrl()}/actions/standard/emailSimple`,
37
+ method: "POST",
38
+ ...opts,
39
+ });
40
+ },
41
+ },
42
+ async run({ $ }) {
43
+ const response = await this.sendEmail({
44
+ $,
45
+ data: {
46
+ inputs: [
47
+ {
48
+ emailAddresses: this.emailAddress,
49
+ emailSubject: this.emailSubject,
50
+ emailBody: this.emailBody,
51
+ senderType: "CurrentUser",
52
+ logEmailOnSend: this.logEmailOnSend,
53
+ },
54
+ ],
55
+ },
56
+ });
57
+ $.export("$summary", `Email sent to ${this.emailAddress}`);
58
+ return response;
59
+ },
60
+ };
@@ -0,0 +1,81 @@
1
+ import {
2
+ convertFieldsToProps, getAdditionalFields,
3
+ } from "../../common/props-utils.mjs";
4
+ import salesforce from "../../salesforce_rest_api.app.mjs";
5
+ import { additionalFields } from "../common/base-create-update.mjs";
6
+
7
+ export default {
8
+ key: "salesforce_rest_api-update-email-template",
9
+ name: "Update Email Template",
10
+ description: "Updates an email template. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_update_fields.htm)",
11
+ version: "0.0.1",
12
+ type: "action",
13
+ props: {
14
+ salesforce,
15
+ recordId: {
16
+ propDefinition: [
17
+ salesforce,
18
+ "recordId",
19
+ () => ({
20
+ objType: "EmailTemplate",
21
+ }),
22
+ ],
23
+ description: "The email template to update.",
24
+ },
25
+ fieldsToUpdate: {
26
+ propDefinition: [
27
+ salesforce,
28
+ "fieldsToUpdate",
29
+ () => ({
30
+ objType: "EmailTemplate",
31
+ }),
32
+ ],
33
+ reloadProps: true,
34
+ },
35
+ },
36
+ methods: {
37
+ getAdditionalFields,
38
+ convertFieldsToProps,
39
+ },
40
+ async additionalProps() {
41
+ const { fieldsToUpdate } = this;
42
+ const fields = await this.salesforce.getFieldsForObjectType("EmailTemplate");
43
+
44
+ const selectedFields = fields.filter(({ name }) => fieldsToUpdate.includes(name));
45
+ const selectedFieldProps = this.convertFieldsToProps(selectedFields);
46
+
47
+ return {
48
+ docsInfo: {
49
+ type: "alert",
50
+ alertType: "info",
51
+ content: "[See the documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_emailtemplate.htm) for information on all available fields.",
52
+ },
53
+ ...selectedFieldProps,
54
+ additionalFields,
55
+ };
56
+ },
57
+ async run({ $ }) {
58
+ /* eslint-disable no-unused-vars */
59
+ const {
60
+ salesforce,
61
+ recordId,
62
+ fieldsToUpdate,
63
+ getAdditionalFields: getData,
64
+ convertFieldsToProps,
65
+ docsInfo,
66
+ additionalFields,
67
+ ...data
68
+ } = this;
69
+ /* eslint-enable no-unused-vars */
70
+ const response = await this.salesforce.updateRecord("EmailTemplate", {
71
+ $,
72
+ id: recordId,
73
+ data: {
74
+ ...data,
75
+ ...getData(),
76
+ },
77
+ });
78
+ $.export("$summary", `Successfully updated Email Template record (ID: ${recordId})`);
79
+ return response;
80
+ },
81
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/salesforce_rest_api",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Pipedream Salesforce (REST API) Components",
5
5
  "main": "salesforce_rest_api.app.mjs",
6
6
  "keywords": [
@@ -0,0 +1,43 @@
1
+ import common from "../common/common-updated-record.mjs";
2
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
3
+
4
+ export default {
5
+ ...common,
6
+ type: "source",
7
+ name: "Case Updated (Instant, of Selectable Type)",
8
+ key: "salesforce_rest_api-case-updated-instant",
9
+ description: "Emit new event when a case is updated. [See the documentation](https://sforce.co/3yPSJZy)",
10
+ version: "0.0.1",
11
+ props: {
12
+ salesforce: common.props.salesforce,
13
+ db: "$.service.db",
14
+ http: {
15
+ type: "$.interface.http",
16
+ customResponse: true,
17
+ },
18
+ timer: {
19
+ type: "$.interface.timer",
20
+ description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
21
+ default: {
22
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
23
+ },
24
+ },
25
+ fieldsToObtain: {
26
+ propDefinition: [
27
+ common.props.salesforce,
28
+ "fieldsToObtain",
29
+ () => ({
30
+ objType: "Case",
31
+ }),
32
+ ],
33
+ optional: true,
34
+ description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
35
+ },
36
+ },
37
+ methods: {
38
+ ...common.methods,
39
+ getObjectType() {
40
+ return "Case";
41
+ },
42
+ },
43
+ };
@@ -0,0 +1,157 @@
1
+ import startCase from "lodash/startCase.js";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import common from "../common/common.mjs";
4
+
5
+ export default {
6
+ ...common,
7
+ hooks: {
8
+ ...common.hooks,
9
+ async deploy() {
10
+ const objectType = this.getObjectType();
11
+ const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
12
+ this.setNameField(nameField);
13
+
14
+ // emit historical events
15
+ const { recentItems } = await this.salesforce.listSObjectTypeIds(objectType);
16
+ const ids = recentItems.map((item) => item.Id);
17
+ for (const id of ids.slice(-25)) {
18
+ const object = await this.salesforce.getSObject(objectType, id);
19
+ const event = {
20
+ body: {
21
+ "New": object,
22
+ "UserId": id,
23
+ },
24
+ };
25
+ this.processWebhookEvent(event);
26
+ }
27
+ },
28
+ async activate() {
29
+ // Attempt to create the webhook
30
+ const secretToken = uuidv4();
31
+ let webhookData;
32
+ const objectType = this.getObjectType();
33
+ try {
34
+ webhookData = await this.createWebhook({
35
+ endpointUrl: this.http.endpoint,
36
+ sObjectType: objectType,
37
+ event: this.getEventType(),
38
+ secretToken,
39
+ fieldsToCheck: this.getFieldsToCheck(),
40
+ fieldsToCheckMode: this.getFieldsToCheckMode(),
41
+ skipValidation: true, // neccessary for custom objects
42
+ });
43
+ console.log("Webhook created successfully");
44
+ } catch (err) {
45
+ console.log("Error creating webhook:", err);
46
+ console.log("The source will operate on the polling schedule instead.");
47
+
48
+ const latestDateCovered = this.getLatestDateCovered();
49
+ if (!latestDateCovered) {
50
+ const now = new Date().toISOString();
51
+ this.setLatestDateCovered(now);
52
+ }
53
+
54
+ await this.timerActivateHook?.();
55
+ }
56
+ this._setSecretToken(secretToken);
57
+ this._setWebhookData(webhookData);
58
+
59
+ const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
60
+ this.setNameField(nameField);
61
+ },
62
+ },
63
+ methods: {
64
+ ...common.methods,
65
+ generateTimerMeta(item, fieldName) {
66
+ const { objectType } = this;
67
+ const {
68
+ CreatedDate: createdDate,
69
+ [fieldName]: name,
70
+ Id: id,
71
+ } = item;
72
+ const entityType = startCase(objectType);
73
+ const summary = `New ${entityType} created: ${name ?? id}`;
74
+ const ts = Date.parse(createdDate);
75
+ return {
76
+ id,
77
+ summary,
78
+ ts,
79
+ };
80
+ },
81
+ generateWebhookMeta(data) {
82
+ const nameField = this.getNameField();
83
+ const { New: newObject } = data.body;
84
+ const {
85
+ CreatedDate: createdDate,
86
+ Id: id,
87
+ [nameField]: name,
88
+ } = newObject;
89
+ const summary = `New ${this.getObjectType()} created: ${name ?? id}`;
90
+ const ts = Date.parse(createdDate);
91
+ return {
92
+ id,
93
+ summary,
94
+ ts,
95
+ };
96
+ },
97
+ getEventType() {
98
+ return "new";
99
+ },
100
+ async processTimerEvent(eventData) {
101
+ const {
102
+ paginate,
103
+ setLatestDateCovered,
104
+ getObjectTypeColumns,
105
+ getNameField,
106
+ generateTimerMeta,
107
+ $emit: emit,
108
+ } = this;
109
+
110
+ const {
111
+ startTimestamp,
112
+ endTimestamp,
113
+ } = eventData;
114
+
115
+ const fieldName = getNameField();
116
+ const columns = getObjectTypeColumns();
117
+
118
+ const events = await paginate({
119
+ objectType: this.getObjectType(),
120
+ startTimestamp,
121
+ endTimestamp,
122
+ columns,
123
+ });
124
+
125
+ const [
126
+ latestEvent,
127
+ ] = events;
128
+
129
+ if (latestEvent?.CreatedDate) {
130
+ const latestDateCovered = new Date(latestEvent.CreatedDate);
131
+ latestDateCovered.setSeconds(0);
132
+ setLatestDateCovered(latestDateCovered.toISOString());
133
+ }
134
+
135
+ Array.from(events)
136
+ .reverse()
137
+ .forEach((item) => {
138
+ const meta = generateTimerMeta(item, fieldName);
139
+ emit(item, meta);
140
+ });
141
+ },
142
+ async timerActivateHook() {
143
+ const {
144
+ getObjectTypeDescription,
145
+ setObjectTypeColumns,
146
+ } = this;
147
+
148
+ let columns = this.fieldsToObtain;
149
+ if (!columns?.length) {
150
+ const { fields } = await getObjectTypeDescription(this.getObjectType());
151
+ columns = fields.map(({ name }) => name);
152
+ }
153
+
154
+ setObjectTypeColumns(columns);
155
+ },
156
+ },
157
+ };
@@ -0,0 +1,198 @@
1
+ import startCase from "lodash/startCase.js";
2
+ import common from "../common/common.mjs";
3
+ import constants from "../../common/constants.mjs";
4
+ import { v4 as uuidv4 } from "uuid";
5
+
6
+ export default {
7
+ ...common,
8
+ hooks: {
9
+ ...common.hooks,
10
+ async deploy() {
11
+ const objectType = this.getObjectType();
12
+ const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
13
+ this.setNameField(nameField);
14
+
15
+ // emit historical events
16
+ const { recentItems } = await this.salesforce.listSObjectTypeIds(objectType);
17
+ const ids = recentItems.map((item) => item.Id);
18
+ for (const id of ids.slice(-25)) {
19
+ const object = await this.salesforce.getSObject(objectType, id);
20
+ const event = {
21
+ body: {
22
+ "New": object,
23
+ "UserId": id,
24
+ },
25
+ };
26
+ const meta = this.generateWebhookMeta(event);
27
+ this.$emit(event.body, meta);
28
+ }
29
+ },
30
+ async activate() {
31
+ // Attempt to create the webhook
32
+ const secretToken = uuidv4();
33
+ let webhookData;
34
+ const objectType = this.getObjectType();
35
+ try {
36
+ webhookData = await this.createWebhook({
37
+ endpointUrl: this.http.endpoint,
38
+ sObjectType: objectType,
39
+ event: this.getEventType(),
40
+ secretToken,
41
+ fieldsToCheck: this.getFieldsToCheck(),
42
+ fieldsToCheckMode: this.getFieldsToCheckMode(),
43
+ skipValidation: true, // neccessary for custom objects
44
+ });
45
+ console.log("Webhook created successfully");
46
+ } catch (err) {
47
+ console.log("Error creating webhook:", err);
48
+ console.log("The source will operate on the polling schedule instead.");
49
+
50
+ const latestDateCovered = this.getLatestDateCovered();
51
+ if (!latestDateCovered) {
52
+ const now = new Date().toISOString();
53
+ this.setLatestDateCovered(now);
54
+ }
55
+
56
+ await this.timerActivateHook?.();
57
+ }
58
+ this._setSecretToken(secretToken);
59
+ this._setWebhookData(webhookData);
60
+
61
+ const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
62
+ this.setNameField(nameField);
63
+ },
64
+ },
65
+ methods: {
66
+ ...common.methods,
67
+ generateWebhookMeta(data) {
68
+ const nameField = this.getNameField();
69
+ const { New: newObject } = data.body;
70
+ const {
71
+ LastModifiedDate: lastModifiedDate,
72
+ Id: id,
73
+ [nameField]: name,
74
+ } = newObject;
75
+ const summary = `${this.getObjectType()} updated: ${name}`;
76
+ const ts = Date.parse(lastModifiedDate);
77
+ const compositeId = `${id}-${ts}`;
78
+ return {
79
+ id: compositeId,
80
+ summary,
81
+ ts,
82
+ };
83
+ },
84
+ generateTimerMeta(item, fieldName) {
85
+ const {
86
+ LastModifiedDate: lastModifiedDate,
87
+ [fieldName]: name,
88
+ Id: id,
89
+ } = item;
90
+
91
+ const entityType = startCase(this.getObjectType());
92
+ const summary = `${entityType} updated: ${name}`;
93
+ const ts = Date.parse(lastModifiedDate);
94
+ return {
95
+ id: `${id}-${ts}`,
96
+ summary,
97
+ ts,
98
+ };
99
+ },
100
+ getEventType() {
101
+ return "updated";
102
+ },
103
+ isEventRelevant(changedFields) {
104
+ const { fields } = this;
105
+ return fields?.length
106
+ ? Object.keys(changedFields).some((key) => fields.includes(key))
107
+ : true;
108
+ },
109
+ getChangedFields(body) {
110
+ return Object.entries(body.New).filter(([
111
+ key,
112
+ value,
113
+ ]) => {
114
+ const oldValue = body.Old[key];
115
+ return (
116
+ value !== undefined
117
+ && oldValue !== undefined
118
+ && JSON.stringify(value) !== JSON.stringify(oldValue)
119
+ );
120
+ })
121
+ .reduce((obj, [
122
+ key,
123
+ value,
124
+ ]) => {
125
+ obj[key] = {
126
+ old: body.Old[key],
127
+ new: value,
128
+ };
129
+ return obj;
130
+ }, {});
131
+ },
132
+ processWebhookEvent(event) {
133
+ const { body } = event;
134
+ const changedFields = this.getChangedFields(body);
135
+ if (this.isEventRelevant(changedFields)) {
136
+ const meta = this.generateWebhookMeta(event);
137
+ this.$emit({
138
+ ...body,
139
+ changedFields,
140
+ }, meta);
141
+ }
142
+ },
143
+ async processTimerEvent(eventData) {
144
+ const {
145
+ getNameField,
146
+ getObjectTypeColumns,
147
+ paginate,
148
+ setLatestDateCovered,
149
+ generateTimerMeta,
150
+ $emit: emit,
151
+ } = this;
152
+
153
+ const {
154
+ startTimestamp,
155
+ endTimestamp,
156
+ } = eventData;
157
+
158
+ const fieldName = getNameField();
159
+ const columns = getObjectTypeColumns();
160
+
161
+ const events = await paginate({
162
+ objectType: this.getObjectType(),
163
+ startTimestamp,
164
+ endTimestamp,
165
+ columns,
166
+ dateFieldName: constants.FIELD_NAME.LAST_MODIFIED_DATE,
167
+ });
168
+
169
+ const [
170
+ latestEvent,
171
+ ] = events;
172
+
173
+ if (latestEvent?.LastModifiedDate) {
174
+ const latestDateCovered = new Date(latestEvent.LastModifiedDate);
175
+ latestDateCovered.setSeconds(0);
176
+ setLatestDateCovered(latestDateCovered.toISOString());
177
+ }
178
+
179
+ Array.from(events)
180
+ .reverse()
181
+ .forEach((item) => {
182
+ const meta = generateTimerMeta(item, fieldName);
183
+ emit(item, meta);
184
+ });
185
+ },
186
+ async timerActivateHook() {
187
+ const {
188
+ getObjectTypeDescription,
189
+ setObjectTypeColumns,
190
+ } = this;
191
+
192
+ const { fields } = await getObjectTypeDescription(this.getObjectType());
193
+ const columns = fields.map(({ name }) => name);
194
+
195
+ setObjectTypeColumns(columns);
196
+ },
197
+ },
198
+ };
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
2
- import salesforce from "../salesforce_rest_api.app.mjs";
3
- import constants from "../common/constants.mjs";
2
+ import salesforce from "../../salesforce_rest_api.app.mjs";
3
+ import constants from "../../common/constants.mjs";
4
4
  import { v4 as uuidv4 } from "uuid";
5
5
  import commonWebhookMethods from "./common-webhook-methods.mjs";
6
6
 
@@ -0,0 +1,43 @@
1
+ import common from "../common/common-updated-record.mjs";
2
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
3
+
4
+ export default {
5
+ ...common,
6
+ type: "source",
7
+ name: "Email Template Updated (Instant, of Selectable Type)",
8
+ key: "salesforce_rest_api-email-template-updated-instant",
9
+ description: "Emit new event when an email template is updated. [See the documentation](https://sforce.co/3yPSJZy)",
10
+ version: "0.0.1",
11
+ props: {
12
+ salesforce: common.props.salesforce,
13
+ db: "$.service.db",
14
+ http: {
15
+ type: "$.interface.http",
16
+ customResponse: true,
17
+ },
18
+ timer: {
19
+ type: "$.interface.timer",
20
+ description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
21
+ default: {
22
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
23
+ },
24
+ },
25
+ fieldsToObtain: {
26
+ propDefinition: [
27
+ common.props.salesforce,
28
+ "fieldsToObtain",
29
+ () => ({
30
+ objType: "EmailTemplate",
31
+ }),
32
+ ],
33
+ optional: true,
34
+ description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
35
+ },
36
+ },
37
+ methods: {
38
+ ...common.methods,
39
+ getObjectType() {
40
+ return "EmailTemplate";
41
+ },
42
+ },
43
+ };
@@ -0,0 +1,43 @@
1
+ import common from "../common/common-updated-record.mjs";
2
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
3
+
4
+ export default {
5
+ ...common,
6
+ type: "source",
7
+ name: "Knowledge Article Updated (Instant, of Selectable Type)",
8
+ key: "salesforce_rest_api-knowledge-article-updated-instant",
9
+ description: "Emit new event when a knowledge article is updated. [See the documentation](https://sforce.co/3yPSJZy)",
10
+ version: "0.0.1",
11
+ props: {
12
+ salesforce: common.props.salesforce,
13
+ db: "$.service.db",
14
+ http: {
15
+ type: "$.interface.http",
16
+ customResponse: true,
17
+ },
18
+ timer: {
19
+ type: "$.interface.timer",
20
+ description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
21
+ default: {
22
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
23
+ },
24
+ },
25
+ fieldsToObtain: {
26
+ propDefinition: [
27
+ common.props.salesforce,
28
+ "fieldsToObtain",
29
+ () => ({
30
+ objType: "KnowledgeArticle",
31
+ }),
32
+ ],
33
+ optional: true,
34
+ description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
35
+ },
36
+ },
37
+ methods: {
38
+ ...common.methods,
39
+ getObjectType() {
40
+ return "KnowledgeArticle";
41
+ },
42
+ },
43
+ };
@@ -0,0 +1,43 @@
1
+ import common from "../common/common-new-record.mjs";
2
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
3
+
4
+ export default {
5
+ ...common,
6
+ type: "source",
7
+ name: "New Case (Instant, of Selectable Type)",
8
+ key: "salesforce_rest_api-new-case-instant",
9
+ description: "Emit new event when a case is created. [See the documentation](https://sforce.co/3yPSJZy)",
10
+ version: "0.0.1",
11
+ props: {
12
+ salesforce: common.props.salesforce,
13
+ db: "$.service.db",
14
+ http: {
15
+ type: "$.interface.http",
16
+ customResponse: true,
17
+ },
18
+ timer: {
19
+ type: "$.interface.timer",
20
+ description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
21
+ default: {
22
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
23
+ },
24
+ },
25
+ fieldsToObtain: {
26
+ propDefinition: [
27
+ common.props.salesforce,
28
+ "fieldsToObtain",
29
+ () => ({
30
+ objType: "Case",
31
+ }),
32
+ ],
33
+ optional: true,
34
+ description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
35
+ },
36
+ },
37
+ methods: {
38
+ ...common.methods,
39
+ getObjectType() {
40
+ return "Case";
41
+ },
42
+ },
43
+ };
@@ -0,0 +1,43 @@
1
+ import common from "../common/common-new-record.mjs";
2
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
3
+
4
+ export default {
5
+ ...common,
6
+ type: "source",
7
+ name: "New Email Template (Instant, of Selectable Type)",
8
+ key: "salesforce_rest_api-new-email-template-instant",
9
+ description: "Emit new event when an email template is created. [See the documentation](https://sforce.co/3yPSJZy)",
10
+ version: "0.0.1",
11
+ props: {
12
+ salesforce: common.props.salesforce,
13
+ db: "$.service.db",
14
+ http: {
15
+ type: "$.interface.http",
16
+ customResponse: true,
17
+ },
18
+ timer: {
19
+ type: "$.interface.timer",
20
+ description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
21
+ default: {
22
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
23
+ },
24
+ },
25
+ fieldsToObtain: {
26
+ propDefinition: [
27
+ common.props.salesforce,
28
+ "fieldsToObtain",
29
+ () => ({
30
+ objType: "EmailTemplate",
31
+ }),
32
+ ],
33
+ optional: true,
34
+ description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
35
+ },
36
+ },
37
+ methods: {
38
+ ...common.methods,
39
+ getObjectType() {
40
+ return "EmailTemplate";
41
+ },
42
+ },
43
+ };
@@ -0,0 +1,43 @@
1
+ import common from "../common/common-new-record.mjs";
2
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
3
+
4
+ export default {
5
+ ...common,
6
+ type: "source",
7
+ name: "New Knowledge Article (Instant, of Selectable Type)",
8
+ key: "salesforce_rest_api-new-knowledge-article-instant",
9
+ description: "Emit new event when a knowledge article is created. [See the documentation](https://sforce.co/3yPSJZy)",
10
+ version: "0.0.1",
11
+ props: {
12
+ salesforce: common.props.salesforce,
13
+ db: "$.service.db",
14
+ http: {
15
+ type: "$.interface.http",
16
+ customResponse: true,
17
+ },
18
+ timer: {
19
+ type: "$.interface.timer",
20
+ description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
21
+ default: {
22
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
23
+ },
24
+ },
25
+ fieldsToObtain: {
26
+ propDefinition: [
27
+ common.props.salesforce,
28
+ "fieldsToObtain",
29
+ () => ({
30
+ objType: "KnowledgeArticle",
31
+ }),
32
+ ],
33
+ optional: true,
34
+ description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
35
+ },
36
+ },
37
+ methods: {
38
+ ...common.methods,
39
+ getObjectType() {
40
+ return "KnowledgeArticle";
41
+ },
42
+ },
43
+ };
@@ -1,5 +1,4 @@
1
- import startCase from "lodash/startCase.js";
2
- import common from "../common.mjs";
1
+ import common from "../common/common-new-record.mjs";
3
2
 
4
3
  export default {
5
4
  ...common,
@@ -7,7 +6,7 @@ export default {
7
6
  name: "New Record (Instant, of Selectable Type)",
8
7
  key: "salesforce_rest_api-new-record-instant",
9
8
  description: "Emit new event when a record of the selected object type is created. [See the documentation](https://sforce.co/3yPSJZy)",
10
- version: "0.2.0",
9
+ version: "0.2.1",
11
10
  props: {
12
11
  ...common.props,
13
12
  fieldsToObtain: {
@@ -22,123 +21,10 @@ export default {
22
21
  description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
23
22
  },
24
23
  },
25
- hooks: {
26
- ...common.hooks,
27
- async deploy() {
28
- const objectType = this.objectType;
29
- const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
30
- this.setNameField(nameField);
31
-
32
- // emit historical events
33
- const { recentItems } = await this.salesforce.listSObjectTypeIds(objectType);
34
- const ids = recentItems.map((item) => item.Id);
35
- for (const id of ids.slice(-25)) {
36
- const object = await this.salesforce.getSObject(objectType, id);
37
- const event = {
38
- body: {
39
- "New": object,
40
- "UserId": id,
41
- },
42
- };
43
- this.processWebhookEvent(event);
44
- }
45
- },
46
- },
47
24
  methods: {
48
25
  ...common.methods,
49
- generateTimerMeta(item, fieldName) {
50
- const { objectType } = this;
51
- const {
52
- CreatedDate: createdDate,
53
- [fieldName]: name,
54
- Id: id,
55
- } = item;
56
- const entityType = startCase(objectType);
57
- const summary = `New ${entityType} created: ${name ?? id}`;
58
- const ts = Date.parse(createdDate);
59
- return {
60
- id,
61
- summary,
62
- ts,
63
- };
64
- },
65
- generateWebhookMeta(data) {
66
- const nameField = this.getNameField();
67
- const { New: newObject } = data.body;
68
- const {
69
- CreatedDate: createdDate,
70
- Id: id,
71
- [nameField]: name,
72
- } = newObject;
73
- const entityType = startCase(this.objectType).toLowerCase();
74
- const summary = `New ${entityType} created: ${name ?? id}`;
75
- const ts = Date.parse(createdDate);
76
- return {
77
- id,
78
- summary,
79
- ts,
80
- };
81
- },
82
- getEventType() {
83
- return "new";
84
- },
85
- async processTimerEvent(eventData) {
86
- const {
87
- paginate,
88
- objectType,
89
- setLatestDateCovered,
90
- getObjectTypeColumns,
91
- getNameField,
92
- generateTimerMeta,
93
- $emit: emit,
94
- } = this;
95
-
96
- const {
97
- startTimestamp,
98
- endTimestamp,
99
- } = eventData;
100
-
101
- const fieldName = getNameField();
102
- const columns = getObjectTypeColumns();
103
-
104
- const events = await paginate({
105
- objectType,
106
- startTimestamp,
107
- endTimestamp,
108
- columns,
109
- });
110
-
111
- const [
112
- latestEvent,
113
- ] = events;
114
-
115
- if (latestEvent?.CreatedDate) {
116
- const latestDateCovered = new Date(latestEvent.CreatedDate);
117
- latestDateCovered.setSeconds(0);
118
- setLatestDateCovered(latestDateCovered.toISOString());
119
- }
120
-
121
- Array.from(events)
122
- .reverse()
123
- .forEach((item) => {
124
- const meta = generateTimerMeta(item, fieldName);
125
- emit(item, meta);
126
- });
127
- },
128
- async timerActivateHook() {
129
- const {
130
- objectType,
131
- getObjectTypeDescription,
132
- setObjectTypeColumns,
133
- } = this;
134
-
135
- let columns = this.fieldsToObtain;
136
- if (!columns?.length) {
137
- const { fields } = await getObjectTypeDescription(objectType);
138
- columns = fields.map(({ name }) => name);
139
- }
140
-
141
- setObjectTypeColumns(columns);
26
+ getObjectType() {
27
+ return this.objectType;
142
28
  },
143
29
  },
144
30
  };
@@ -1,5 +1,5 @@
1
1
  import startCase from "lodash/startCase.js";
2
- import common from "../common.mjs";
2
+ import common from "../common/common.mjs";
3
3
 
4
4
  export default {
5
5
  ...common,
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Deleted Record (Instant, of Selectable Type)",
8
8
  key: "salesforce_rest_api-record-deleted-instant",
9
9
  description: "Emit new event when a record of the selected object type is deleted. [See the documentation](https://sforce.co/3msDDEE)",
10
- version: "0.1.0",
10
+ version: "0.1.1",
11
11
  methods: {
12
12
  ...common.methods,
13
13
  generateWebhookMeta(data) {
@@ -1,6 +1,4 @@
1
- import startCase from "lodash/startCase.js";
2
- import common from "../common.mjs";
3
- import constants from "../../common/constants.mjs";
1
+ import common from "../common/common-updated-record.mjs";
4
2
  const { salesforce } = common.props;
5
3
 
6
4
  export default {
@@ -9,7 +7,7 @@ export default {
9
7
  name: "New Updated Record (Instant, of Selectable Type)",
10
8
  key: "salesforce_rest_api-record-updated-instant",
11
9
  description: "Emit new event when a record of the selected type is updated. [See the documentation](https://sforce.co/3yPSJZy)",
12
- version: "0.2.0",
10
+ version: "0.2.1",
13
11
  props: {
14
12
  ...common.props,
15
13
  fields: {
@@ -29,140 +27,8 @@ export default {
29
27
  },
30
28
  methods: {
31
29
  ...common.methods,
32
- generateWebhookMeta(data) {
33
- const nameField = this.getNameField();
34
- const { New: newObject } = data.body;
35
- const {
36
- LastModifiedDate: lastModifiedDate,
37
- Id: id,
38
- [nameField]: name,
39
- } = newObject;
40
- const entityType = startCase(this.objectType);
41
- const summary = `${entityType} updated: ${name}`;
42
- const ts = Date.parse(lastModifiedDate);
43
- const compositeId = `${id}-${ts}`;
44
- return {
45
- id: compositeId,
46
- summary,
47
- ts,
48
- };
49
- },
50
- generateTimerMeta(item, fieldName) {
51
- const { objectType } = this;
52
-
53
- const {
54
- LastModifiedDate: lastModifiedDate,
55
- [fieldName]: name,
56
- Id: id,
57
- } = item;
58
-
59
- const entityType = startCase(objectType);
60
- const summary = `${entityType} updated: ${name}`;
61
- const ts = Date.parse(lastModifiedDate);
62
- return {
63
- id: `${id}-${ts}`,
64
- summary,
65
- ts,
66
- };
67
- },
68
- getEventType() {
69
- return "updated";
70
- },
71
- isEventRelevant(changedFields) {
72
- const { fields } = this;
73
- return fields?.length
74
- ? Object.keys(changedFields).some((key) => fields.includes(key))
75
- : true;
76
- },
77
- getChangedFields(body) {
78
- return Object.entries(body.New).filter(([
79
- key,
80
- value,
81
- ]) => {
82
- const oldValue = body.Old[key];
83
- return (
84
- value !== undefined
85
- && oldValue !== undefined
86
- && JSON.stringify(value) !== JSON.stringify(oldValue)
87
- );
88
- })
89
- .reduce((obj, [
90
- key,
91
- value,
92
- ]) => {
93
- obj[key] = {
94
- old: body.Old[key],
95
- new: value,
96
- };
97
- return obj;
98
- }, {});
99
- },
100
- processWebhookEvent(event) {
101
- const { body } = event;
102
- const changedFields = this.getChangedFields(body);
103
- if (this.isEventRelevant(changedFields)) {
104
- const meta = this.generateWebhookMeta(event);
105
- this.$emit({
106
- ...body,
107
- changedFields,
108
- }, meta);
109
- }
110
- },
111
- async processTimerEvent(eventData) {
112
- const {
113
- getNameField,
114
- getObjectTypeColumns,
115
- paginate,
116
- objectType,
117
- setLatestDateCovered,
118
- generateTimerMeta,
119
- $emit: emit,
120
- } = this;
121
-
122
- const {
123
- startTimestamp,
124
- endTimestamp,
125
- } = eventData;
126
-
127
- const fieldName = getNameField();
128
- const columns = getObjectTypeColumns();
129
-
130
- const events = await paginate({
131
- objectType,
132
- startTimestamp,
133
- endTimestamp,
134
- columns,
135
- dateFieldName: constants.FIELD_NAME.LAST_MODIFIED_DATE,
136
- });
137
-
138
- const [
139
- latestEvent,
140
- ] = events;
141
-
142
- if (latestEvent?.LastModifiedDate) {
143
- const latestDateCovered = new Date(latestEvent.LastModifiedDate);
144
- latestDateCovered.setSeconds(0);
145
- setLatestDateCovered(latestDateCovered.toISOString());
146
- }
147
-
148
- Array.from(events)
149
- .reverse()
150
- .forEach((item) => {
151
- const meta = generateTimerMeta(item, fieldName);
152
- emit(item, meta);
153
- });
154
- },
155
- async timerActivateHook() {
156
- const {
157
- objectType,
158
- getObjectTypeDescription,
159
- setObjectTypeColumns,
160
- } = this;
161
-
162
- const { fields } = await getObjectTypeDescription(objectType);
163
- const columns = fields.map(({ name }) => name);
164
-
165
- setObjectTypeColumns(columns);
30
+ getObjectType() {
31
+ return this.objectType;
166
32
  },
167
33
  },
168
34
  };