sfmc-sdk 1.0.0 → 2.0.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.
- package/.github/workflows/codeql-analysis.yml +1 -1
- package/.github/workflows/prvalidation.yml +4 -4
- package/.github/workflows/release.yml +4 -4
- package/lib/auth.js +7 -6
- package/lib/index.js +10 -8
- package/lib/rest.js +40 -29
- package/lib/soap.js +8 -22
- package/lib/util.js +18 -14
- package/package.json +14 -13
- package/test/auth.test.js +6 -10
- package/test/resources/auth.js +32 -0
- package/test/resources/rest.js +416 -0
- package/test/resources/soap.js +649 -0
- package/test/rest.test.js +22 -12
- package/test/soap.test.js +27 -10
- package/test/utils.js +6 -5
- package/test/resources/auth.json +0 -32
- package/test/resources/rest.json +0 -378
- package/test/resources/soap.json +0 -640
|
@@ -7,7 +7,7 @@ jobs:
|
|
|
7
7
|
pr-labeler:
|
|
8
8
|
runs-on: ubuntu-latest
|
|
9
9
|
steps:
|
|
10
|
-
- uses: TimonVS/pr-labeler-action@
|
|
10
|
+
- uses: TimonVS/pr-labeler-action@v4
|
|
11
11
|
with:
|
|
12
12
|
configuration-path: .github/pr-labeler.yml # optional, .github/pr-labeler.yml is the default value
|
|
13
13
|
env:
|
|
@@ -16,10 +16,10 @@ jobs:
|
|
|
16
16
|
runs-on: ubuntu-latest
|
|
17
17
|
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
20
|
-
- uses: actions/setup-node@
|
|
19
|
+
- uses: actions/checkout@v3
|
|
20
|
+
- uses: actions/setup-node@v3
|
|
21
21
|
with:
|
|
22
|
-
node-version:
|
|
22
|
+
node-version: 18
|
|
23
23
|
registry-url: https://registry.npmjs.org/
|
|
24
24
|
- run: npm install
|
|
25
25
|
- run: npm run lint
|
|
@@ -15,12 +15,12 @@ jobs:
|
|
|
15
15
|
id: create_release
|
|
16
16
|
env:
|
|
17
17
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
18
|
-
- uses: actions/checkout@
|
|
19
|
-
- uses: actions/setup-node@
|
|
18
|
+
- uses: actions/checkout@v3
|
|
19
|
+
- uses: actions/setup-node@v3
|
|
20
20
|
with:
|
|
21
|
-
node-version:
|
|
21
|
+
node-version: 18
|
|
22
22
|
registry-url: https://registry.npmjs.org/
|
|
23
|
-
- uses: HarmvZ/set-package-json-version-action@v0.
|
|
23
|
+
- uses: HarmvZ/set-package-json-version-action@v0.2.5
|
|
24
24
|
with:
|
|
25
25
|
version: ${{ steps.create_release.outputs.tag_name }}
|
|
26
26
|
- run: npm i
|
package/lib/auth.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
const { isConnectionError, RestError } = require('./util');
|
|
2
|
+
import { isConnectionError, RestError, axiosInstance as axios } from './util.js';
|
|
4
3
|
const AVAIALABLE_SCOPES = [
|
|
5
4
|
'accounts_read',
|
|
6
5
|
'accounts_write',
|
|
@@ -89,10 +88,12 @@ const AVAIALABLE_SCOPES = [
|
|
|
89
88
|
'workflows_write',
|
|
90
89
|
];
|
|
91
90
|
|
|
92
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Class which handles authentication logic
|
|
93
|
+
*/
|
|
94
|
+
export default class Auth {
|
|
93
95
|
/**
|
|
94
96
|
* Creates an instance of Auth.
|
|
95
|
-
*
|
|
96
97
|
* @param {object} authObject Auth Payload
|
|
97
98
|
* @param {string} authObject.client_id Client Id from SFMC config
|
|
98
99
|
* @param {string} authObject.client_secret Client Secret from SFMC config
|
|
@@ -179,13 +180,13 @@ module.exports = class Auth {
|
|
|
179
180
|
|
|
180
181
|
/**
|
|
181
182
|
* Helper to get back list of scopes supported by SDK
|
|
182
|
-
*
|
|
183
183
|
* @returns {Array[String]} array of potential scopes
|
|
184
184
|
*/
|
|
185
185
|
getSupportedScopes() {
|
|
186
186
|
return AVAIALABLE_SCOPES;
|
|
187
187
|
}
|
|
188
|
-
}
|
|
188
|
+
}
|
|
189
|
+
|
|
189
190
|
/**
|
|
190
191
|
* @param {object} authObject Auth object
|
|
191
192
|
* @returns {boolean} true if token is expired
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import Auth from './auth.js';
|
|
3
|
+
import Rest from './rest.js';
|
|
4
|
+
import Soap from './soap.js';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Class main handler for the SDK
|
|
8
|
+
*/
|
|
9
|
+
export default class SDK {
|
|
7
10
|
/**
|
|
8
11
|
* Creates an instance of SDK.
|
|
9
|
-
*
|
|
10
12
|
* @param {object} authObject Auth Object for making requests
|
|
11
13
|
* @param {object} options options for the SDK as a whole, for example collection of handler functions, or retry settings
|
|
12
|
-
* @param {number} [options.requestAttempts
|
|
13
|
-
* @param {boolean} [options.retryOnConnectionError
|
|
14
|
+
* @param {number} [options.requestAttempts] number of retries which should be done, defaulted to 1
|
|
15
|
+
* @param {boolean} [options.retryOnConnectionError] should request be retried in case of connection issues
|
|
14
16
|
* @param {object} [options.eventHandlers] collection of functions which are executed on certain events
|
|
15
17
|
*/
|
|
16
18
|
constructor(authObject, options) {
|
|
@@ -27,4 +29,4 @@ module.exports = class SDK {
|
|
|
27
29
|
this.rest = new Rest(this.auth, options);
|
|
28
30
|
this.soap = new Soap(this.auth, options);
|
|
29
31
|
}
|
|
30
|
-
}
|
|
32
|
+
}
|
package/lib/rest.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import {
|
|
3
|
+
isObject,
|
|
4
|
+
isPayload,
|
|
5
|
+
isConnectionError,
|
|
6
|
+
RestError,
|
|
7
|
+
axiosInstance as axios,
|
|
8
|
+
} from './util.js';
|
|
9
|
+
import pLimit from 'p-limit';
|
|
5
10
|
|
|
6
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Class which handles rest endpoints
|
|
13
|
+
*/
|
|
14
|
+
export default class Rest {
|
|
7
15
|
/**
|
|
8
16
|
* Constuctor of Rest object
|
|
9
|
-
*
|
|
10
17
|
* @function Object() { [native code] }
|
|
11
18
|
* @param {object} authObject Auth object used for initializing
|
|
12
19
|
* @param {object} options options for the SDK as a whole, for example collection of handler functions, or retry settings
|
|
@@ -23,7 +30,6 @@ module.exports = class Rest {
|
|
|
23
30
|
|
|
24
31
|
/**
|
|
25
32
|
* Method that makes the GET API request
|
|
26
|
-
*
|
|
27
33
|
* @param {string} url of the resource to retrieve
|
|
28
34
|
* @returns {Promise.<object>} API response
|
|
29
35
|
*/
|
|
@@ -37,8 +43,7 @@ module.exports = class Rest {
|
|
|
37
43
|
);
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
40
|
-
* helper for {@link getBulk} to determine if the url is a transactional message API
|
|
41
|
-
*
|
|
46
|
+
* helper for {@link this.getBulk} to determine if the url is a transactional message API
|
|
42
47
|
* @private
|
|
43
48
|
* @param {string} url url without query params
|
|
44
49
|
* @returns {boolean} true if the url is a transactional message API
|
|
@@ -47,8 +52,7 @@ module.exports = class Rest {
|
|
|
47
52
|
return url && this.transactionalApis.some((api) => url.includes(api));
|
|
48
53
|
}
|
|
49
54
|
/**
|
|
50
|
-
* helper for {@link getBulk} to determine if the url is a legacy API
|
|
51
|
-
*
|
|
55
|
+
* helper for {@link this.getBulk} to determine if the url is a legacy API
|
|
52
56
|
* @private
|
|
53
57
|
* @param {string} url url without query params
|
|
54
58
|
* @returns {boolean} true if the url is a legacy API
|
|
@@ -58,7 +62,6 @@ module.exports = class Rest {
|
|
|
58
62
|
}
|
|
59
63
|
/**
|
|
60
64
|
* Method that makes paginated GET API Requests using $pageSize and $page parameters
|
|
61
|
-
*
|
|
62
65
|
* @param {string} url of the resource to retrieve
|
|
63
66
|
* @param {number} [pageSize] of the response, defaults to 50
|
|
64
67
|
* @param {string} [iteratorField] attribute of the response to iterate over (only required if it's not 'items'|'definitions'|'entry')
|
|
@@ -95,6 +98,8 @@ module.exports = class Rest {
|
|
|
95
98
|
},
|
|
96
99
|
this.options.requestAttempts
|
|
97
100
|
);
|
|
101
|
+
|
|
102
|
+
// determine iterator field if not provided
|
|
98
103
|
if (iteratorField && Array.isArray(responseBatch[iteratorField])) {
|
|
99
104
|
// if the iteratorField is set, use it
|
|
100
105
|
} else if (Array.isArray(responseBatch.items)) {
|
|
@@ -106,26 +111,38 @@ module.exports = class Rest {
|
|
|
106
111
|
} else {
|
|
107
112
|
throw new TypeError('Could not find an array to iterate over');
|
|
108
113
|
}
|
|
114
|
+
|
|
115
|
+
// merge results with existing
|
|
109
116
|
if (collector && Array.isArray(responseBatch[iteratorField])) {
|
|
110
117
|
collector[iteratorField].push(...responseBatch[iteratorField]);
|
|
111
118
|
} else if (!collector) {
|
|
112
119
|
collector = responseBatch;
|
|
113
120
|
}
|
|
121
|
+
// ! the transactional message API returns a value for "count" that represents the currently returned number of records, instead of the total amount. checking for count != pageSize is a workaround for this
|
|
122
|
+
// * opened Support Case #43988240 for this issue
|
|
114
123
|
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
(!isTransactionalMessageApi ||
|
|
118
|
-
(isTransactionalMessageApi &&
|
|
119
|
-
responseBatch[countKey] != responseBatch[pageSizeKey]))
|
|
124
|
+
isTransactionalMessageApi &&
|
|
125
|
+
responseBatch[countKey] != responseBatch[pageSizeKey]
|
|
120
126
|
) {
|
|
121
|
-
// ! the transactional message API returns a value for "count" that represents the currently returned number of records, instead of the total amount. checking for count != pageSize is a workaround for this
|
|
122
|
-
// * opened Support Case #43988240 for this issue
|
|
123
127
|
shouldPaginate = false;
|
|
124
|
-
}
|
|
128
|
+
}
|
|
129
|
+
// if results are less than size, no more requested needed
|
|
130
|
+
else if (responseBatch[iteratorField].length < pageSize) {
|
|
131
|
+
shouldPaginate = false;
|
|
132
|
+
}
|
|
133
|
+
// stop if total amount is same as the current amount (all have been retrieved)
|
|
134
|
+
else if (collector[iteratorField].length >= responseBatch[countKey]) {
|
|
135
|
+
shouldPaginate = false;
|
|
136
|
+
}
|
|
137
|
+
// stop if response contains no results (for whatever reason) - this is a known issue on legacy API
|
|
138
|
+
else if (responseBatch[iteratorField].length === 0) {
|
|
139
|
+
shouldPaginate = false;
|
|
140
|
+
}
|
|
141
|
+
// otherwise loop
|
|
142
|
+
else {
|
|
125
143
|
page++;
|
|
126
144
|
shouldPaginate = true;
|
|
127
145
|
if (this.options?.eventHandlers?.onLoop) {
|
|
128
|
-
// TODO in v1 change to undefined to ensure breaking changes considered
|
|
129
146
|
// eslint-disable-next-line unicorn/no-null
|
|
130
147
|
this.options.eventHandlers.onLoop(null, collector?.[iteratorField]);
|
|
131
148
|
}
|
|
@@ -135,9 +152,8 @@ module.exports = class Rest {
|
|
|
135
152
|
}
|
|
136
153
|
/**
|
|
137
154
|
* Method that makes a GET API request for each URL (including rate limiting)
|
|
138
|
-
*
|
|
139
155
|
* @param {string[]} urlArray of the resource to retrieve
|
|
140
|
-
* @param {number} [concurrentLimit
|
|
156
|
+
* @param {number} [concurrentLimit] number of requests to execute at once
|
|
141
157
|
* @returns {Promise.<Array>} API response
|
|
142
158
|
*/
|
|
143
159
|
async getCollection(urlArray, concurrentLimit) {
|
|
@@ -160,7 +176,6 @@ module.exports = class Rest {
|
|
|
160
176
|
}
|
|
161
177
|
/**
|
|
162
178
|
* Method that makes the POST api request
|
|
163
|
-
*
|
|
164
179
|
* @param {string} url of the resource to create
|
|
165
180
|
* @param {object} payload for the POST request body
|
|
166
181
|
* @returns {Promise.<object>} API response
|
|
@@ -176,7 +191,6 @@ module.exports = class Rest {
|
|
|
176
191
|
}
|
|
177
192
|
/**
|
|
178
193
|
* Method that makes the PUT api request
|
|
179
|
-
*
|
|
180
194
|
* @param {string} url of the resource to replace
|
|
181
195
|
* @param {object} payload for the PUT request body
|
|
182
196
|
* @returns {Promise.<object>} API response
|
|
@@ -192,7 +206,6 @@ module.exports = class Rest {
|
|
|
192
206
|
}
|
|
193
207
|
/**
|
|
194
208
|
* Method that makes the PATCH api request
|
|
195
|
-
*
|
|
196
209
|
* @param {string} url of the resource to update
|
|
197
210
|
* @param {object} payload for the PATCH request body
|
|
198
211
|
* @returns {Promise.<object>} API response
|
|
@@ -208,7 +221,6 @@ module.exports = class Rest {
|
|
|
208
221
|
}
|
|
209
222
|
/**
|
|
210
223
|
* Method that makes the DELETE api request
|
|
211
|
-
*
|
|
212
224
|
* @param {string} url of the resource to delete
|
|
213
225
|
* @returns {Promise.<object>} API response
|
|
214
226
|
*/
|
|
@@ -224,7 +236,6 @@ module.exports = class Rest {
|
|
|
224
236
|
}
|
|
225
237
|
/**
|
|
226
238
|
* Method that makes the api request
|
|
227
|
-
*
|
|
228
239
|
* @param {object} requestOptions configuration for the request including body
|
|
229
240
|
* @param {number} remainingAttempts number of times this request should be reattempted in case of error
|
|
230
241
|
* @returns {Promise.<object>} Results from the Rest request in Object format
|
|
@@ -278,10 +289,10 @@ module.exports = class Rest {
|
|
|
278
289
|
}
|
|
279
290
|
}
|
|
280
291
|
}
|
|
281
|
-
}
|
|
292
|
+
}
|
|
293
|
+
|
|
282
294
|
/**
|
|
283
295
|
* method to check if the payload is plausible and throw error if not
|
|
284
|
-
*
|
|
285
296
|
* @param {object} options API request opptions
|
|
286
297
|
*/
|
|
287
298
|
function _checkPayload(options) {
|
package/lib/soap.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { XMLBuilder, XMLParser } from 'fast-xml-parser';
|
|
3
|
+
import { isObject, isConnectionError, axiosInstance as axios, SOAPError } from './util.js';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Class which handles SOAP endpoints
|
|
7
|
+
*/
|
|
8
|
+
export default class Soap {
|
|
8
9
|
/**
|
|
9
10
|
* Constuctor of Soap object
|
|
10
|
-
*
|
|
11
11
|
* @function Object() { [native code] }
|
|
12
12
|
* @param {object} auth Auth object used for initializing
|
|
13
13
|
* @param {object} options options for the SDK as a whole, for example collection of handler functions, or retry settings
|
|
@@ -19,7 +19,6 @@ module.exports = class Soap {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Method used to retrieve data via SOAP API
|
|
22
|
-
*
|
|
23
22
|
* @param {string} type - SOAP Object type
|
|
24
23
|
* @param {string[]} properties - Properties which should be retrieved
|
|
25
24
|
* @param {object} [requestParameters] - additional RetrieveRequest parameters, for example filter or options
|
|
@@ -80,7 +79,6 @@ module.exports = class Soap {
|
|
|
80
79
|
}
|
|
81
80
|
/**
|
|
82
81
|
* Method used to retrieve all data via SOAP API
|
|
83
|
-
*
|
|
84
82
|
* @param {string} type - SOAP Object type
|
|
85
83
|
* @param {string[]} properties - Properties which should be retrieved
|
|
86
84
|
* @param {object} [requestParameters] - additional RetrieveRequest parameters, for example filter or options
|
|
@@ -111,7 +109,6 @@ module.exports = class Soap {
|
|
|
111
109
|
}
|
|
112
110
|
/**
|
|
113
111
|
* Method used to create data via SOAP API
|
|
114
|
-
*
|
|
115
112
|
* @param {string} type - SOAP Object type
|
|
116
113
|
* @param {string[]} properties - Properties which should be created
|
|
117
114
|
* @param {object} [requestParameters] - additional RetrieveRequest parameters, for example filter or options
|
|
@@ -144,7 +141,6 @@ module.exports = class Soap {
|
|
|
144
141
|
}
|
|
145
142
|
/**
|
|
146
143
|
* Method used to update data via SOAP API
|
|
147
|
-
*
|
|
148
144
|
* @param {string} type - SOAP Object type
|
|
149
145
|
* @param {string[]} properties - Properties which should be updated
|
|
150
146
|
* @param {object} [requestParameters] - additional RetrieveRequest parameters, for example filter or options
|
|
@@ -178,7 +174,6 @@ module.exports = class Soap {
|
|
|
178
174
|
}
|
|
179
175
|
/**
|
|
180
176
|
* Method used to delete data via SOAP API
|
|
181
|
-
*
|
|
182
177
|
* @param {string} type - SOAP Object type
|
|
183
178
|
* @param {string[]} properties - Properties which should be retrieved
|
|
184
179
|
* @param {object} [requestParameters] - additional RetrieveRequest parameters, for example filter or options
|
|
@@ -211,7 +206,6 @@ module.exports = class Soap {
|
|
|
211
206
|
}
|
|
212
207
|
/**
|
|
213
208
|
* Method used to schedule data via SOAP API
|
|
214
|
-
*
|
|
215
209
|
* @param {string} type - SOAP Object type
|
|
216
210
|
* @param {object} schedule - object for what the schedule should be
|
|
217
211
|
* @param {Array | object} interactions - Object or array of interactions
|
|
@@ -253,7 +247,6 @@ module.exports = class Soap {
|
|
|
253
247
|
}
|
|
254
248
|
/**
|
|
255
249
|
* Method used to describe metadata via SOAP API
|
|
256
|
-
*
|
|
257
250
|
* @param {string} type - SOAP Object type
|
|
258
251
|
* @returns {Promise.<object>} SOAP object converted from XML
|
|
259
252
|
*/
|
|
@@ -281,7 +274,6 @@ module.exports = class Soap {
|
|
|
281
274
|
}
|
|
282
275
|
/**
|
|
283
276
|
* Method used to execute data via SOAP API
|
|
284
|
-
*
|
|
285
277
|
* @param {string} type - SOAP Object type
|
|
286
278
|
* @param {string[]} properties - Properties which should be retrieved
|
|
287
279
|
* @returns {Promise.<object>} SOAP object converted from XML
|
|
@@ -309,7 +301,6 @@ module.exports = class Soap {
|
|
|
309
301
|
}
|
|
310
302
|
/**
|
|
311
303
|
* Method used to execute data via SOAP API
|
|
312
|
-
*
|
|
313
304
|
* @param {string} type - SOAP Object type
|
|
314
305
|
* @param {string} action - type of action, for example 'Start'
|
|
315
306
|
* @param {object} payload - relevant payload to perform, for example query Definition
|
|
@@ -349,7 +340,6 @@ module.exports = class Soap {
|
|
|
349
340
|
}
|
|
350
341
|
/**
|
|
351
342
|
* Method used to configure data via SOAP API
|
|
352
|
-
*
|
|
353
343
|
* @private
|
|
354
344
|
* @param {string} type - SOAP Object type
|
|
355
345
|
* @param {object[]} configArray - Properties which should be updated
|
|
@@ -385,7 +375,6 @@ module.exports = class Soap {
|
|
|
385
375
|
|
|
386
376
|
/**
|
|
387
377
|
* Method that makes the api request
|
|
388
|
-
*
|
|
389
378
|
* @param {object} options configuration for the request including body
|
|
390
379
|
* @param {number} remainingAttempts number of times this request should be reattempted in case of error
|
|
391
380
|
* @returns {Promise.<object>} Results from the SOAP request in Object format
|
|
@@ -459,10 +448,10 @@ module.exports = class Soap {
|
|
|
459
448
|
}
|
|
460
449
|
}
|
|
461
450
|
}
|
|
462
|
-
}
|
|
451
|
+
}
|
|
452
|
+
|
|
463
453
|
/**
|
|
464
454
|
* Method to build the payload then conver to XML
|
|
465
|
-
*
|
|
466
455
|
* @param {object} request Object form of the payload
|
|
467
456
|
* @param {string} token access token for authentication
|
|
468
457
|
* @returns {string} XML string payload
|
|
@@ -486,7 +475,6 @@ function _buildEnvelope(request, token) {
|
|
|
486
475
|
|
|
487
476
|
/**
|
|
488
477
|
* Method to filter requests in SOAP
|
|
489
|
-
*
|
|
490
478
|
* @param {object} filter Polymorphic filter object
|
|
491
479
|
* @returns {object} formatted filter object
|
|
492
480
|
*/
|
|
@@ -519,7 +507,6 @@ function _parseFilter(filter) {
|
|
|
519
507
|
}
|
|
520
508
|
/**
|
|
521
509
|
* Method to parse the XML response
|
|
522
|
-
*
|
|
523
510
|
* @param {string} response payload including whole SOAP response
|
|
524
511
|
* @param {string} key key of the expected response body
|
|
525
512
|
* @returns {Promise.<object | Error>} Result of request in Object format
|
|
@@ -547,7 +534,6 @@ async function _parseResponse(response, key) {
|
|
|
547
534
|
}
|
|
548
535
|
/**
|
|
549
536
|
* Method checks options object for validity
|
|
550
|
-
*
|
|
551
537
|
* @param {object} options configuration for the request including body
|
|
552
538
|
* @param {string[]} additional - additional keys which are acceptable
|
|
553
539
|
*/
|
package/lib/util.js
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
3
|
* Method to check if Object passed is a simple object
|
|
4
|
-
*
|
|
5
4
|
* @param {object} object Object to check
|
|
6
5
|
* @returns {boolean} true if is simple Object
|
|
7
6
|
*/
|
|
8
|
-
|
|
7
|
+
export function isObject(object) {
|
|
8
|
+
return Object.prototype.toString.call(object) === '[object Object]';
|
|
9
|
+
}
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Method to check if Object passed is a valid payload for API calls
|
|
12
|
-
*
|
|
13
13
|
* @param {object} object Object to check
|
|
14
14
|
* @returns {boolean} true if is a valid payload
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
Object.prototype.toString.call(object) === '[object Object]' || Array.isArray(object);
|
|
16
|
+
export function isPayload(object) {
|
|
17
|
+
return Object.prototype.toString.call(object) === '[object Object]' || Array.isArray(object);
|
|
18
|
+
}
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Method to check if it is a connection error
|
|
21
|
-
*
|
|
22
22
|
* @param {string} code returned code from exception
|
|
23
23
|
* @returns {boolean} true if a connection error
|
|
24
24
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
export function isConnectionError(code) {
|
|
26
|
+
return (
|
|
27
|
+
code &&
|
|
28
|
+
['ETIMEDOUT', 'EHOSTUNREACH', 'ENOTFOUND', 'ECONNRESET', 'ECONNABORTED'].includes(code)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* CustomError type for handling REST (including Auth) based errors
|
|
30
|
-
*
|
|
31
34
|
* @class RestError
|
|
32
35
|
* @augments {Error}
|
|
33
36
|
*/
|
|
34
|
-
|
|
37
|
+
export class RestError extends Error {
|
|
35
38
|
/**
|
|
36
39
|
*
|
|
37
40
|
* @param {Error} ex Error object
|
|
@@ -59,15 +62,14 @@ module.exports.RestError = class RestError extends Error {
|
|
|
59
62
|
Error.captureStackTrace(this, RestError);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
|
-
}
|
|
65
|
+
}
|
|
63
66
|
|
|
64
67
|
/**
|
|
65
68
|
* CustomError type for handling SOAP based errors
|
|
66
|
-
*
|
|
67
69
|
* @class SOAPError
|
|
68
70
|
* @augments {Error}
|
|
69
71
|
*/
|
|
70
|
-
|
|
72
|
+
export class SOAPError extends Error {
|
|
71
73
|
/**
|
|
72
74
|
*
|
|
73
75
|
* @param {Error} ex Error object
|
|
@@ -113,4 +115,6 @@ module.exports.SOAPError = class SOAPError extends Error {
|
|
|
113
115
|
Error.captureStackTrace(this, SOAPError);
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
|
-
}
|
|
118
|
+
}
|
|
119
|
+
import axios from 'axios';
|
|
120
|
+
export const axiosInstance = axios.create();
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sfmc-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Libarary to simplify SFMC requests with updated dependencies and less overhead",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "nyc --reporter=text mocha",
|
|
8
|
-
"lint": "eslint ./lib
|
|
9
|
-
"lint:fix": "eslint ./lib
|
|
8
|
+
"lint": "eslint ./lib ./test",
|
|
9
|
+
"lint:fix": "eslint ./lib ./test --fix",
|
|
10
10
|
"prepare": "husky install"
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"author": "Doug Midgley <douglasmidgley@gmail.com>",
|
|
17
17
|
"license": "BSD-3-Clause",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"axios": "^1.
|
|
20
|
-
"fast-xml-parser": "4.2.
|
|
21
|
-
"p-limit": "
|
|
19
|
+
"axios": "^1.4.0",
|
|
20
|
+
"fast-xml-parser": "4.2.2",
|
|
21
|
+
"p-limit": "4.0.0"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"fuel",
|
|
@@ -35,20 +35,21 @@
|
|
|
35
35
|
"assert": "2.0.0",
|
|
36
36
|
"axios-mock-adapter": "1.21.4",
|
|
37
37
|
"chai": "4.3.7",
|
|
38
|
-
"eslint": "8.
|
|
38
|
+
"eslint": "8.42.0",
|
|
39
39
|
"eslint-config-prettier": "8.8.0",
|
|
40
|
-
"eslint-plugin-jsdoc": "
|
|
40
|
+
"eslint-plugin-jsdoc": "46.2.0",
|
|
41
41
|
"eslint-plugin-mocha": "10.1.0",
|
|
42
42
|
"eslint-plugin-prettier": "4.2.1",
|
|
43
|
-
"eslint-plugin-unicorn": "
|
|
43
|
+
"eslint-plugin-unicorn": "47.0.0",
|
|
44
44
|
"husky": "8.0.3",
|
|
45
45
|
"mocha": "10.2.0",
|
|
46
46
|
"nyc": "15.1.0",
|
|
47
47
|
"prettier-eslint": "15.0.1",
|
|
48
|
-
"sinon": "15.0
|
|
48
|
+
"sinon": "15.1.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
|
-
"npm": ">=
|
|
52
|
-
"node": ">=
|
|
53
|
-
}
|
|
51
|
+
"npm": ">=9.5.1",
|
|
52
|
+
"node": ">=18.16.0"
|
|
53
|
+
},
|
|
54
|
+
"type": "module"
|
|
54
55
|
}
|
package/test/auth.test.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { assert } from 'chai';
|
|
2
|
+
import SDK from '../lib/index.js';
|
|
3
|
+
import { defaultSdk, mock } from './utils.js';
|
|
4
|
+
import { success, unauthorized } from './resources/auth.js';
|
|
5
|
+
import { isConnectionError } from '../lib/util.js';
|
|
6
6
|
|
|
7
7
|
describe('auth', function () {
|
|
8
8
|
afterEach(function () {
|
|
@@ -10,7 +10,6 @@ describe('auth', function () {
|
|
|
10
10
|
});
|
|
11
11
|
it('should return an auth payload with token', async function () {
|
|
12
12
|
//given
|
|
13
|
-
const { success } = resources;
|
|
14
13
|
|
|
15
14
|
//when
|
|
16
15
|
mock.onPost(success.url).reply(success.status, success.response);
|
|
@@ -22,7 +21,7 @@ describe('auth', function () {
|
|
|
22
21
|
});
|
|
23
22
|
it('should return an auth payload with previous token and one request', async function () {
|
|
24
23
|
//given
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
mock.onPost(success.url).reply(success.status, success.response);
|
|
27
26
|
// when
|
|
28
27
|
const sdk = defaultSdk();
|
|
@@ -35,7 +34,6 @@ describe('auth', function () {
|
|
|
35
34
|
});
|
|
36
35
|
it('should return an unauthorized error', async function () {
|
|
37
36
|
//given
|
|
38
|
-
const { unauthorized } = resources;
|
|
39
37
|
mock.onPost(unauthorized.url).reply(unauthorized.status, unauthorized.response);
|
|
40
38
|
// when
|
|
41
39
|
const auth = defaultSdk().auth.getAccessToken();
|
|
@@ -156,7 +154,6 @@ describe('auth', function () {
|
|
|
156
154
|
|
|
157
155
|
it('RETRY: should return an success, after a connection issues', async function () {
|
|
158
156
|
//given
|
|
159
|
-
const { success } = resources;
|
|
160
157
|
|
|
161
158
|
//when
|
|
162
159
|
mock.onPost(success.url)
|
|
@@ -171,7 +168,6 @@ describe('auth', function () {
|
|
|
171
168
|
});
|
|
172
169
|
it('FAILED RETRY: should return an error, after multiple connection issues', async function () {
|
|
173
170
|
//given
|
|
174
|
-
const { success } = resources;
|
|
175
171
|
|
|
176
172
|
//when
|
|
177
173
|
mock.onPost(success.url).timeout();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const success = {
|
|
2
|
+
url: 'https://mct0l7nxfq2r988t1kxfy8sc47ma.auth.marketingcloudapis.com/v2/token',
|
|
3
|
+
response: {
|
|
4
|
+
access_token: 'TESTTOKEN',
|
|
5
|
+
token_type: 'Bearer',
|
|
6
|
+
expires_in: 1079,
|
|
7
|
+
scope: 'offline documents_and_images_read documents_and_images_write saved_content_read saved_content_write automations_execute automations_read automations_write journeys_execute journeys_read journeys_write email_read email_send email_write push_read push_send push_write sms_read sms_send sms_write social_post social_publish social_read social_write web_publish web_read web_write audiences_read audiences_write list_and_subscribers_read list_and_subscribers_write data_extensions_read data_extensions_write file_locations_read file_locations_write tracking_events_read calendar_read calendar_write campaign_read campaign_write accounts_read accounts_write users_read users_write webhooks_read webhooks_write workflows_write approvals_write tags_write approvals_read tags_read workflows_read ott_chat_messaging_read ott_chat_messaging_send ott_channels_read ott_channels_write marketing_cloud_connect_read marketing_cloud_connect_write marketing_cloud_connect_send event_notification_callback_create event_notification_callback_read event_notification_callback_update event_notification_callback_delete event_notification_subscription_create event_notification_subscription_read event_notification_subscription_update event_notification_subscription_delete tracking_events_write key_manage_view key_manage_rotate key_manage_revoke dfu_configure journeys_aspr journeys_delete package_manager_package package_manager_deploy deep_linking_asset_read deep_linking_asset_write deep_linking_asset_delete deep_linking_settings_read deep_linking_settings_write',
|
|
8
|
+
soap_instance_url: 'https://mct0l7nxfq2r988t1kxfy8sc47ma.soap.marketingcloudapis.com/',
|
|
9
|
+
rest_instance_url: 'https://mct0l7nxfq2r988t1kxfy8sc47ma.rest.marketingcloudapis.com/',
|
|
10
|
+
},
|
|
11
|
+
status: 200,
|
|
12
|
+
};
|
|
13
|
+
export const unauthorized = {
|
|
14
|
+
url: 'https://mct0l7nxfq2r988t1kxfy8sc47ma.auth.marketingcloudapis.com/v2/token',
|
|
15
|
+
response: {
|
|
16
|
+
error: 'invalid_client',
|
|
17
|
+
error_description:
|
|
18
|
+
'Client authentication failed. Make sure that the client ID and client secret are valid and that the package is installed and enabled.',
|
|
19
|
+
error_uri: 'https://developer.salesforce.com/docs',
|
|
20
|
+
},
|
|
21
|
+
status: 401,
|
|
22
|
+
};
|
|
23
|
+
export const expired = {
|
|
24
|
+
url: 'https://mct0l7nxfq2r988t1kxfy8sc47ma.auth.marketingcloudapis.com/v2/token',
|
|
25
|
+
response: {
|
|
26
|
+
documentation:
|
|
27
|
+
'https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/error-handling.htm',
|
|
28
|
+
errorcode: 0,
|
|
29
|
+
message: 'Not Authorized',
|
|
30
|
+
},
|
|
31
|
+
status: 401,
|
|
32
|
+
};
|