@pipedream/salesforce_rest_api 2.0.1 → 3.0.1
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.
- package/actions/add-contact-to-campaign/add-contact-to-campaign.mjs +2 -2
- package/actions/add-lead-to-campaign/add-lead-to-campaign.mjs +2 -2
- package/actions/convert-soap-xml-to-json/convert-soap-xml-to-json.mjs +2 -2
- package/actions/create-account/create-account.mjs +2 -2
- package/actions/create-accounts-batch/create-accounts-batch.mjs +2 -2
- package/actions/create-attachment/create-attachment.mjs +2 -2
- package/actions/create-campaign/create-campaign.mjs +2 -2
- package/actions/create-case/create-case.mjs +2 -2
- package/actions/create-casecomment/create-casecomment.mjs +2 -2
- package/actions/create-contact/create-contact.mjs +2 -2
- package/actions/create-content-note/create-content-note.mjs +2 -2
- package/actions/create-crm-record/create-crm-record.mjs +2 -2
- package/actions/create-event/create-event.mjs +2 -2
- package/actions/create-lead/create-lead.mjs +2 -2
- package/actions/create-note/create-note.mjs +2 -2
- package/actions/create-opportunities-batch/create-opportunities-batch.mjs +2 -2
- package/actions/create-opportunity/create-opportunity.mjs +2 -2
- package/actions/create-record/create-record.mjs +2 -2
- package/actions/create-task/create-task.mjs +2 -2
- package/actions/create-user/create-user.mjs +2 -2
- package/actions/delete-crm-record/delete-crm-record.mjs +2 -2
- package/actions/delete-note/delete-note.mjs +2 -2
- package/actions/delete-opportunity/delete-opportunity.mjs +2 -2
- package/actions/delete-record/delete-record.mjs +2 -2
- package/actions/describe-object/describe-object.mjs +2 -2
- package/actions/find-records/find-records.mjs +2 -2
- package/actions/get-case/get-case.mjs +2 -2
- package/actions/get-current-user/get-current-user.mjs +2 -2
- package/actions/get-knowledge-articles/get-knowledge-articles.mjs +2 -2
- package/actions/get-knowledge-data-category-groups/get-knowledge-data-category-groups.mjs +2 -2
- package/actions/get-record-by-id/get-record-by-id.mjs +2 -2
- package/actions/get-related-records/get-related-records.mjs +2 -2
- package/actions/get-user/get-user.mjs +2 -2
- package/actions/get-user-info/get-user-info.mjs +2 -2
- package/actions/insert-blob-data/insert-blob-data.mjs +2 -2
- package/actions/list-case-comments/list-case-comments.mjs +2 -2
- package/actions/list-case-feed-items/list-case-feed-items.mjs +2 -2
- package/actions/list-cases/list-cases.mjs +2 -2
- package/actions/list-email-messages/list-email-messages.mjs +2 -2
- package/actions/list-email-templates/list-email-templates.mjs +2 -2
- package/actions/list-knowledge-articles/list-knowledge-articles.mjs +2 -2
- package/actions/list-object-fields/list-object-fields.mjs +2 -2
- package/actions/list-objects/list-objects.mjs +2 -2
- package/actions/post-feed-to-chatter/post-feed-to-chatter.mjs +2 -2
- package/actions/search-string/search-string.mjs +2 -2
- package/actions/send-email/send-email.mjs +2 -2
- package/actions/soql-query/soql-query.mjs +2 -2
- package/actions/soql-search/soql-search.mjs +2 -2
- package/actions/sosl-search/sosl-search.mjs +2 -2
- package/actions/text-search/text-search.mjs +2 -2
- package/actions/update-account/update-account.mjs +2 -2
- package/actions/update-accounts-batch/update-accounts-batch.mjs +2 -2
- package/actions/update-contact/update-contact.mjs +2 -2
- package/actions/update-content-note/update-content-note.mjs +2 -2
- package/actions/update-crm-record/update-crm-record.mjs +2 -2
- package/actions/update-email-template/update-email-template.mjs +2 -2
- package/actions/update-note/update-note.mjs +2 -2
- package/actions/update-opportunities-batch/update-opportunities-batch.mjs +2 -2
- package/actions/update-opportunity/update-opportunity.mjs +2 -2
- package/actions/update-record/update-record.mjs +2 -2
- package/actions/upsert-record/upsert-record.mjs +2 -2
- package/common/constants.mjs +5 -0
- package/package.json +1 -1
- package/sources/case-updated-instant/case-updated-instant.mjs +1 -1
- package/sources/email-template-updated-instant/email-template-updated-instant.mjs +1 -1
- package/sources/knowledge-article-updated-instant/knowledge-article-updated-instant.mjs +1 -1
- package/sources/new-case-instant/new-case-instant.mjs +1 -1
- package/sources/new-email-template-instant/new-email-template-instant.mjs +1 -1
- package/sources/new-feed-comment/new-feed-comment.mjs +1 -1
- package/sources/new-feed-item/new-feed-item.mjs +1 -1
- package/sources/new-knowledge-article-instant/new-knowledge-article-instant.mjs +1 -1
- package/sources/new-outbound-message/new-outbound-message.mjs +97 -18
- package/sources/new-record-instant/new-record-instant.mjs +1 -1
- package/sources/record-deleted-instant/record-deleted-instant.mjs +1 -1
- package/sources/record-updated-instant/record-updated-instant.mjs +1 -1
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
name: "New Email Template (Instant, of Selectable Type)",
|
|
8
8
|
key: "salesforce_rest_api-new-email-template-instant",
|
|
9
9
|
description: "Emit new event when an email template is created. [See the documentation](https://sforce.co/3yPSJZy)",
|
|
10
|
-
version: "0.0.
|
|
10
|
+
version: "0.0.13",
|
|
11
11
|
props: {
|
|
12
12
|
salesforce: common.props.salesforce,
|
|
13
13
|
db: "$.service.db",
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
name: "New Chatter Feed Comment (Instant or Polling)",
|
|
13
13
|
key: "salesforce_rest_api-new-feed-comment",
|
|
14
14
|
description: "Emit new events for each Chatter FeedComment (reply) created in Salesforce, polling `FeedComment` via SOQL on `CreatedDate`. Use this to react to comments on Chatter posts, since Chatter activity does not update the parent record's `LastModifiedDate`. The payload includes both `ParentId` (a polymorphic reference to the feed's parent - either a record feed, e.g. a Case ID starting with `500`, or a User feed) and `FeedItemId` (the ID of the FeedItem the comment belongs to) - these are distinct fields; do not confuse them. Set `parentObjectType` to a parent object API name (e.g. `Case`) to only emit comments whose parent record is of that type. Set `excludeSelf` to `true` to drop comments authored by the connected integration user. Note: querying FeedComment without a parent filter requires the `View All Data` permission on the connected user. Attempts instant delivery via webhook and falls back to timer polling automatically. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_feedcomment.htm)",
|
|
15
|
-
version: "0.0.
|
|
15
|
+
version: "0.0.6",
|
|
16
16
|
props: {
|
|
17
17
|
...common.props,
|
|
18
18
|
parentObjectType: {
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
name: "New Chatter Feed Item (Instant or Polling)",
|
|
13
13
|
key: "salesforce_rest_api-new-feed-item",
|
|
14
14
|
description: "Emit new events for each Chatter FeedItem (post) created in Salesforce, polling `FeedItem` via SOQL on `CreatedDate`. Use this to react to Chatter posts on Cases and other records, since Chatter activity does not update the parent record's `LastModifiedDate` (so **New Record (Instant, of Selectable Type)** and **New Case (Instant, of Selectable Type)** never emit for it). Set `parentObjectType` to the parent object's API name (e.g. `Case`, `Opportunity`) to only emit posts whose parent record is of that type. Set `excludeSelf` to `true` to drop posts authored by the connected integration user. Note: `Body` is null for system-generated post types (e.g. `TrackedChange`). Attempts instant delivery via webhook and falls back to timer polling automatically when the Streaming API does not support this object. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_feeditem.htm)",
|
|
15
|
-
version: "0.0.
|
|
15
|
+
version: "0.0.6",
|
|
16
16
|
props: {
|
|
17
17
|
...common.props,
|
|
18
18
|
parentObjectType: {
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
name: "New Knowledge Article (Instant, of Selectable Type)",
|
|
8
8
|
key: "salesforce_rest_api-new-knowledge-article-instant",
|
|
9
9
|
description: "Emit new event when a knowledge article is created. [See the documentation](https://sforce.co/3yPSJZy)",
|
|
10
|
-
version: "0.0.
|
|
10
|
+
version: "0.0.13",
|
|
11
11
|
props: {
|
|
12
12
|
salesforce: common.props.salesforce,
|
|
13
13
|
db: "$.service.db",
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { XMLParser } from "fast-xml-parser";
|
|
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
|
type: "source",
|
|
6
7
|
name: "New Outbound Message (Instant)",
|
|
7
8
|
key: "salesforce_rest_api-new-outbound-message",
|
|
8
|
-
description: "Emit new event when a new outbound message is received in Salesforce.",
|
|
9
|
-
version: "0.
|
|
9
|
+
description: "Emit new event when a new outbound message is received in Salesforce. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_om_outboundmessaging_notifications.htm)",
|
|
10
|
+
version: "1.0.0",
|
|
10
11
|
dedupe: "unique",
|
|
11
12
|
props: {
|
|
12
13
|
db: "$.service.db",
|
|
@@ -15,6 +16,13 @@ export default {
|
|
|
15
16
|
customResponse: true,
|
|
16
17
|
},
|
|
17
18
|
salesforce,
|
|
19
|
+
validateSessionId: {
|
|
20
|
+
type: "boolean",
|
|
21
|
+
label: "Validate Session ID",
|
|
22
|
+
description: "Additionally verify the `SessionId` of each outbound message against the Salesforce API. Requires the outbound message's `Send Session ID` option to be enabled. Leave this disabled unless you need it: sessions that are IP-locked, or that belong to a user without API access, cannot be verified and their messages are rejected.",
|
|
23
|
+
optional: true,
|
|
24
|
+
default: false,
|
|
25
|
+
},
|
|
18
26
|
infoBox: {
|
|
19
27
|
type: "alert",
|
|
20
28
|
alertType: "info",
|
|
@@ -22,13 +30,33 @@ export default {
|
|
|
22
30
|
\\
|
|
23
31
|
Set the Outbound Message's \`Endpoint URL\` to the endpoint of this source, which you can view after it is created.
|
|
24
32
|
\\
|
|
25
|
-
The \`Send Session ID\` option
|
|
33
|
+
The outbound message must be sent from the same Salesforce org as the connected account above. Each message is verified against that org's \`Organization Id\`, so the \`Send Session ID\` option is no longer required.`,
|
|
26
34
|
},
|
|
27
35
|
},
|
|
28
36
|
methods: {
|
|
37
|
+
_getOrganizationId() {
|
|
38
|
+
return this.db.get("organizationId");
|
|
39
|
+
},
|
|
40
|
+
_setOrganizationId(organizationId) {
|
|
41
|
+
this.db.set("organizationId", organizationId);
|
|
42
|
+
},
|
|
43
|
+
_getOrganizationCheckedAt() {
|
|
44
|
+
return this.db.get("organizationCheckedAt") || 0;
|
|
45
|
+
},
|
|
46
|
+
_setOrganizationCheckedAt(timestamp) {
|
|
47
|
+
this.db.set("organizationCheckedAt", timestamp);
|
|
48
|
+
},
|
|
29
49
|
_unwrapMessage(message) {
|
|
30
50
|
const parser = new XMLParser({
|
|
31
51
|
removeNSPrefix: true,
|
|
52
|
+
// Salesforce sends identifiers such as CaseNumber, postal codes and
|
|
53
|
+
// external IDs as digit strings. Parsing those as numbers strips
|
|
54
|
+
// leading zeros and rewrites E-notation and hex-like values.
|
|
55
|
+
numberParseOptions: {
|
|
56
|
+
leadingZeros: false,
|
|
57
|
+
eNotation: false,
|
|
58
|
+
hex: false,
|
|
59
|
+
},
|
|
32
60
|
});
|
|
33
61
|
const obj = parser.parse(message);
|
|
34
62
|
const notifications = obj["Envelope"]["Body"].notifications;
|
|
@@ -55,22 +83,69 @@ The \`Send Session ID\` option must be enabled in Salesforce for validating outb
|
|
|
55
83
|
},
|
|
56
84
|
});
|
|
57
85
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
86
|
+
// Compare on the leading 15 characters so that a 15 character ID and its 18
|
|
87
|
+
// character form match. Both values come from Salesforce in canonical case,
|
|
88
|
+
// so the comparison stays case-sensitive.
|
|
89
|
+
_toShortId(id) {
|
|
90
|
+
return `${id}`.slice(0, constants.ID_SHORT_LENGTH);
|
|
91
|
+
},
|
|
92
|
+
async _fetchOrganizationId() {
|
|
93
|
+
const { organization_id: organizationId } =
|
|
94
|
+
await this.salesforce.getUserInfo(this.salesforce._authToken());
|
|
95
|
+
return organizationId;
|
|
96
|
+
},
|
|
97
|
+
// The cached ID belongs to whichever account was connected when it was
|
|
98
|
+
// stored, and Salesforce exposes no stable connection identity to key it
|
|
99
|
+
// on. So re-resolve from the connected account whenever the incoming ID
|
|
100
|
+
// does not match: pointing the source at a different org then heals itself
|
|
101
|
+
// on the next message instead of rejecting every message from then on.
|
|
102
|
+
async _matchesConnectedOrganization(organizationId) {
|
|
103
|
+
const cachedOrganizationId = this._getOrganizationId();
|
|
104
|
+
if (cachedOrganizationId
|
|
105
|
+
&& this._toShortId(organizationId) === this._toShortId(cachedOrganizationId)) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Re-resolve on a mismatch, but at most once per cooldown, so a stream of
|
|
110
|
+
// rejected messages cannot amplify into a stream of Salesforce API calls.
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
if (now - this._getOrganizationCheckedAt() < constants.ORGANIZATION_REFRESH_COOLDOWN_MS) {
|
|
64
113
|
return false;
|
|
65
114
|
}
|
|
115
|
+
|
|
116
|
+
// Stamp before the request so a failing or concurrent refresh still
|
|
117
|
+
// consumes the cooldown rather than retrying on every delivery.
|
|
118
|
+
this._setOrganizationCheckedAt(now);
|
|
119
|
+
const currentOrganizationId = await this._fetchOrganizationId();
|
|
120
|
+
this._setOrganizationId(currentOrganizationId);
|
|
121
|
+
return this._toShortId(organizationId) === this._toShortId(currentOrganizationId);
|
|
122
|
+
},
|
|
123
|
+
// Errors are intentionally not caught: a session that cannot be verified
|
|
124
|
+
// must surface as a failed execution rather than a discarded message.
|
|
125
|
+
async _isValidSessionId(sessionId) {
|
|
126
|
+
const data = await this.salesforce.getUserInfo(sessionId);
|
|
127
|
+
return Boolean(data);
|
|
66
128
|
},
|
|
67
129
|
async _isValidSource(data) {
|
|
68
|
-
const {
|
|
69
|
-
|
|
70
|
-
|
|
130
|
+
const {
|
|
131
|
+
OrganizationId: organizationId,
|
|
132
|
+
SessionId: sessionId,
|
|
133
|
+
} = data;
|
|
134
|
+
if (!organizationId) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!(await this._matchesConnectedOrganization(organizationId))) {
|
|
139
|
+
return false;
|
|
71
140
|
}
|
|
72
141
|
|
|
73
|
-
|
|
142
|
+
if (!this.validateSessionId) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return sessionId
|
|
147
|
+
? this._isValidSessionId(sessionId)
|
|
148
|
+
: false;
|
|
74
149
|
},
|
|
75
150
|
generateMeta(data) {
|
|
76
151
|
const {
|
|
@@ -78,7 +153,7 @@ The \`Send Session ID\` option must be enabled in Salesforce for validating outb
|
|
|
78
153
|
Notification: { Id: eventId },
|
|
79
154
|
} = data;
|
|
80
155
|
const id = `${eventId}-${actionId}`;
|
|
81
|
-
const summary =
|
|
156
|
+
const summary = `New outbound message with ID ${eventId}`;
|
|
82
157
|
const ts = Date.now();
|
|
83
158
|
return {
|
|
84
159
|
id,
|
|
@@ -89,13 +164,17 @@ The \`Send Session ID\` option must be enabled in Salesforce for validating outb
|
|
|
89
164
|
},
|
|
90
165
|
async run(event) {
|
|
91
166
|
const { bodyRaw } = event;
|
|
92
|
-
this._sendHttpResponse(true);
|
|
93
167
|
const data = this._unwrapMessage(bodyRaw);
|
|
168
|
+
|
|
94
169
|
if (!(await this._isValidSource(data))) {
|
|
95
|
-
|
|
96
|
-
|
|
170
|
+
// Acknowledge `false` so Salesforce keeps the message queued and retries
|
|
171
|
+
// for up to 24 hours, rather than dropping it as delivered.
|
|
172
|
+
this._sendHttpResponse(false);
|
|
173
|
+
throw new Error(`Rejected an outbound message from Salesforce organization \`${data.OrganizationId}\` (connected organization: \`${this._getOrganizationId() || "unknown"}\`). Check that this source is connected to the organization that sends the outbound message, and, if \`Validate Session ID\` is enabled, that the message includes a valid Session ID.`);
|
|
97
174
|
}
|
|
98
175
|
|
|
176
|
+
this._sendHttpResponse(true);
|
|
177
|
+
|
|
99
178
|
let notifications = data.Notification;
|
|
100
179
|
if (!Array.isArray(notifications)) {
|
|
101
180
|
notifications = [
|
|
@@ -104,7 +183,7 @@ The \`Send Session ID\` option must be enabled in Salesforce for validating outb
|
|
|
104
183
|
}
|
|
105
184
|
|
|
106
185
|
notifications.forEach((n) => {
|
|
107
|
-
const notification = Object.assign(data, {
|
|
186
|
+
const notification = Object.assign({}, data, {
|
|
108
187
|
Notification: n,
|
|
109
188
|
});
|
|
110
189
|
this.$emit(notification, this.generateMeta(notification));
|
|
@@ -6,7 +6,7 @@ export default {
|
|
|
6
6
|
name: "New Record (Instant, of Selectable Type)",
|
|
7
7
|
key: "salesforce_rest_api-new-record-instant",
|
|
8
8
|
description: "Emit new event when a record of the selected object type is created. [See the documentation](https://sforce.co/3yPSJZy)",
|
|
9
|
-
version: "0.2.
|
|
9
|
+
version: "0.2.13",
|
|
10
10
|
props: {
|
|
11
11
|
...common.props,
|
|
12
12
|
fieldsToObtain: {
|
|
@@ -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.
|
|
10
|
+
version: "0.1.12",
|
|
11
11
|
methods: {
|
|
12
12
|
...common.methods,
|
|
13
13
|
generateWebhookMeta(data) {
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
name: "New Updated Record (Instant, of Selectable Type)",
|
|
8
8
|
key: "salesforce_rest_api-record-updated-instant",
|
|
9
9
|
description: "Emit new event when a record of the selected type is updated. [See the documentation](https://sforce.co/3yPSJZy)",
|
|
10
|
-
version: "0.2.
|
|
10
|
+
version: "0.2.13",
|
|
11
11
|
props: {
|
|
12
12
|
...common.props,
|
|
13
13
|
fields: {
|