mcdev 7.5.0 → 7.6.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/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/@types/lib/index.d.ts +12 -8
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/AttributeSet.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Automation.d.ts +14 -0
- package/@types/lib/metadataTypes/Automation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtension.d.ts +3 -1
- package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Event.d.ts +2 -2
- package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts +17 -0
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts +8 -4
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Query.d.ts +7 -0
- package/@types/lib/metadataTypes/Query.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TransactionalEmail.d.ts +1 -0
- package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TriggeredSend.d.ts +0 -8
- package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -1
- package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts +1 -0
- package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -1
- package/@types/lib/util/util.d.ts.map +1 -1
- package/@types/types/mcdev.d.d.ts +20 -8
- package/@types/types/mcdev.d.d.ts.map +1 -1
- package/lib/cli.js +13 -2
- package/lib/index.js +46 -45
- package/lib/metadataTypes/Automation.js +28 -0
- package/lib/metadataTypes/Event.js +4 -1
- package/lib/metadataTypes/Journey.js +472 -94
- package/lib/metadataTypes/MetadataType.js +12 -6
- package/lib/metadataTypes/TriggeredSend.js +46 -15
- package/lib/metadataTypes/definitions/Automation.definition.js +1 -0
- package/lib/metadataTypes/definitions/Journey.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +1 -0
- package/package.json +15 -15
- package/test/general.test.js +5 -5
- package/test/mockRoot/.mcdevrc.json +1 -1
- package/test/resources/9999999/dataFolder/retrieve-ContentTypeINcontextual_suppression_list,hidden,list,mysubs,publication,suppression_list,triggered_send,triggered_send_journeybuilder-response.xml +385 -0
- package/test/resources/9999999/interaction/v1/interactions/0175b971-71a3-4d8e-98ac-48121f3fbf4f/get-response.json +461 -0
- package/test/resources/9999999/interaction/v1/interactions/dsfdsafdsa-922c-4568-85a5-e5cc77efc3be/delete-response.txt +1 -0
- package/test/resources/9999999/interaction/v1/interactions/transactional/pause/post-response.json +3 -0
- package/test/resources/9999999/interaction/v1/interactions/transactional/resume/post-response.json +3 -0
- package/test/resources/9999999/triggeredSendDefinition/retrieve-CustomerKey=testExisting_triggeredSend-response.xml +72 -0
- package/test/resources/9999999/triggeredSendDefinition/retrieve-CustomerKey=testExisting_triggeredSend_rcb-response.xml +72 -0
- package/test/resources/9999999/triggeredSendDefinition/retrieve-TriggeredSendStatusINNew,Active,Inactive,Moved,Canceled-response.xml +1 -1
- package/test/resources/9999999/triggeredSendDefinition/retrieve-TriggeredSendStatusINdummy,Active-response.xml +118 -0
- package/test/type.automation.test.js +13 -13
- package/test/type.journey.test.js +79 -5
- package/test/type.query.test.js +2 -2
- package/test/type.triggeredSend.test.js +68 -1
- package/types/mcdev.d.js +2 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import MetadataType from './MetadataType.js';
|
|
4
4
|
import TransactionalEmail from './TransactionalEmail.js';
|
|
5
|
+
import TriggeredSend from './TriggeredSend.js';
|
|
5
6
|
import Event from './Event.js';
|
|
6
7
|
import { Util } from '../util/util.js';
|
|
7
8
|
import cache from '../util/cache.js';
|
|
@@ -187,7 +188,8 @@ class Journey extends MetadataType {
|
|
|
187
188
|
[
|
|
188
189
|
'Interaction matching key not found.',
|
|
189
190
|
'Must provide a valid ID or Key parameter',
|
|
190
|
-
].includes(ex.message)
|
|
191
|
+
].includes(ex.message) ||
|
|
192
|
+
(key && ex.code === 'ERR_BAD_REQUEST')
|
|
191
193
|
) {
|
|
192
194
|
Util.logger.info(
|
|
193
195
|
`Downloaded: ${this.definition.type} (0)${Util.getKeysString(
|
|
@@ -209,22 +211,32 @@ class Journey extends MetadataType {
|
|
|
209
211
|
*/
|
|
210
212
|
static async deleteByKey(key) {
|
|
211
213
|
let version;
|
|
212
|
-
let
|
|
214
|
+
let id;
|
|
215
|
+
let cachedJourney;
|
|
213
216
|
|
|
214
217
|
if (key.startsWith('id:') || key.startsWith('%23')) {
|
|
215
218
|
// ! allow selecting journeys by ID because that's what users see in the URL
|
|
216
219
|
// if the key started with %23 assume an ID was copied from the URL but the user forgot to prefix it with id:
|
|
217
220
|
|
|
218
221
|
// remove id: or %23
|
|
219
|
-
|
|
220
|
-
if (
|
|
222
|
+
id = key.slice(3);
|
|
223
|
+
if (id.startsWith('%23')) {
|
|
221
224
|
// in the journey URL the Id is prefixed with an HTML-encoded "#" which could accidentally be copied by users
|
|
222
225
|
// despite the slicing above, this still needs testing here because users might have prefixed the ID with id: but did not know to remove the #23
|
|
223
|
-
|
|
226
|
+
id = id.slice(3);
|
|
224
227
|
}
|
|
225
|
-
if (
|
|
228
|
+
if (id.includes('/')) {
|
|
226
229
|
// in the journey URL the version is appended after the ID, separated by a forward-slash.
|
|
227
|
-
[
|
|
230
|
+
[id, version] = id.split('/');
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
const response = await this.client.rest.get(
|
|
234
|
+
`/interaction/v1/interactions/${encodeURIComponent(id)}?extras=activities`
|
|
235
|
+
);
|
|
236
|
+
const results = this.parseResponseBody(response, key);
|
|
237
|
+
cachedJourney = results[key];
|
|
238
|
+
} catch {
|
|
239
|
+
// handle below
|
|
228
240
|
}
|
|
229
241
|
} else {
|
|
230
242
|
if (key.includes('/')) {
|
|
@@ -233,40 +245,75 @@ class Journey extends MetadataType {
|
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
// delete by key with specified version does not work, therefore we need to get the ID first
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const results = this.parseResponseBody(response, key);
|
|
240
|
-
singleKey = results[key].id;
|
|
241
|
-
if (version && version !== '*' && version > results[key].version) {
|
|
242
|
-
Util.logger.error(
|
|
243
|
-
`The chosen version (${version}) is higher than the latest known version (${results[key].version}). Please choose a lower version.`
|
|
248
|
+
try {
|
|
249
|
+
const response = await this.client.rest.get(
|
|
250
|
+
`/interaction/v1/interactions/key:${encodeURIComponent(key)}?extras=activities`
|
|
244
251
|
);
|
|
245
|
-
|
|
252
|
+
const results = this.parseResponseBody(response, key);
|
|
253
|
+
cachedJourney = results[key];
|
|
254
|
+
id = cachedJourney?.id;
|
|
255
|
+
} catch {
|
|
256
|
+
// handle below
|
|
246
257
|
}
|
|
247
|
-
Util.logger.debug(`Deleting interaction ${key} via its ID ${singleKey}`);
|
|
248
258
|
}
|
|
249
|
-
if (
|
|
250
|
-
if (!/^\d+$/.test(version)) {
|
|
251
|
-
Util.logger.error(
|
|
252
|
-
'Version is required for deleting interactions to avoid accidental deletion of the wrong item. Please append it at the end of the key or id, separated by forward-slash. Example for deleting version 4: ' +
|
|
253
|
-
key +
|
|
254
|
-
'/4'
|
|
255
|
-
);
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
259
|
+
if (!cachedJourney?.key) {
|
|
258
260
|
Util.logger.warn(
|
|
259
|
-
`
|
|
261
|
+
` ☇ skipping deletion of ${this.definition.type} ${key}: not found on server`
|
|
260
262
|
);
|
|
263
|
+
return false;
|
|
261
264
|
}
|
|
265
|
+
switch (cachedJourney.definitionType) {
|
|
266
|
+
case 'Multistep': {
|
|
267
|
+
if (version && version !== '*' && version > cachedJourney.version) {
|
|
268
|
+
Util.logger.error(
|
|
269
|
+
`The chosen version (${version}) is higher than the latest known version (${cachedJourney.version}). Please choose a lower version.`
|
|
270
|
+
);
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
if (version !== '*') {
|
|
274
|
+
if (!/^\d+$/.test(version)) {
|
|
275
|
+
Util.logger.error(
|
|
276
|
+
'Version is required for deleting interactions to avoid accidental deletion of the wrong item. Please append it at the end of the key or id, separated by forward-slash. Example for deleting version 4: ' +
|
|
277
|
+
key +
|
|
278
|
+
'/4'
|
|
279
|
+
);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
Util.logger.warn(
|
|
283
|
+
`Deleting Journeys via this command breaks following retrieve-by-key/id requests until you've deployed/created a new draft version! You can get still get the latest available version of your journey by retrieving all interactions on this BU.`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
262
286
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
287
|
+
return super.deleteByKeyREST(
|
|
288
|
+
'/interaction/v1/interactions/' +
|
|
289
|
+
id +
|
|
290
|
+
(version === '*' ? '' : `?versionNumber=${version}`),
|
|
291
|
+
key,
|
|
292
|
+
false
|
|
293
|
+
);
|
|
294
|
+
// break;
|
|
295
|
+
}
|
|
296
|
+
default: {
|
|
297
|
+
// Quicksend, Transactional dont have versions
|
|
298
|
+
const response = await super.deleteByKeyREST(
|
|
299
|
+
'/interaction/v1/interactions/' + id,
|
|
300
|
+
key,
|
|
301
|
+
false
|
|
302
|
+
);
|
|
303
|
+
if (response && cachedJourney.definitionType === 'Transactional') {
|
|
304
|
+
const msg = [];
|
|
305
|
+
if (cachedJourney.activities[0]?.configurationArguments?.triggeredSendKey) {
|
|
306
|
+
msg.push(
|
|
307
|
+
`transactionalEmail "${cachedJourney.activities[0].configurationArguments.triggeredSendKey}"`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
if (msg.length) {
|
|
311
|
+
Util.logger.info(` - Remember to also delete linked ${msg.join(' and ')}`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return response;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
270
317
|
}
|
|
271
318
|
|
|
272
319
|
/**
|
|
@@ -1607,7 +1654,11 @@ class Journey extends MetadataType {
|
|
|
1607
1654
|
);
|
|
1608
1655
|
const cachedVersion = cache.getByKey(this.definition.type, normalizedKey);
|
|
1609
1656
|
if (cachedVersion) {
|
|
1610
|
-
if (
|
|
1657
|
+
if (
|
|
1658
|
+
cachedVersion.status === 'Draft' ||
|
|
1659
|
+
cachedVersion.definitionType !== 'Multistep'
|
|
1660
|
+
) {
|
|
1661
|
+
// we can update journeys either if there is a draft version or if the type is not multistep. transactional and quicksend journeys do not have versions.
|
|
1611
1662
|
// add version to ensure we update the correct one
|
|
1612
1663
|
metadataMap[metadataKey].version = cachedVersion.version;
|
|
1613
1664
|
// update modifiedDate field to bypass API-error "Another user recently modified this journey. Refresh to edit the latest version."
|
|
@@ -2335,121 +2386,406 @@ class Journey extends MetadataType {
|
|
|
2335
2386
|
let version;
|
|
2336
2387
|
const endpoint = '/interaction/v1/interactions/stop/';
|
|
2337
2388
|
const stoppedKeyArr = [];
|
|
2389
|
+
const pauseTransactionalKeyArr = [];
|
|
2338
2390
|
const apiLimit = pLimit(20);
|
|
2339
2391
|
const journeyCache = await this.retrieveForCache();
|
|
2340
2392
|
|
|
2393
|
+
const stoppableJourneyStatus = ['Paused', 'Published', 'Finishing'];
|
|
2394
|
+
|
|
2341
2395
|
await Promise.allSettled(
|
|
2342
2396
|
keyArr.map((key) =>
|
|
2343
2397
|
apiLimit(async () => {
|
|
2344
2398
|
[key, version] = key.split('/');
|
|
2345
2399
|
if (journeyCache.metadata[key]) {
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2400
|
+
switch (journeyCache.metadata[key].definitionType) {
|
|
2401
|
+
case 'Transactional': {
|
|
2402
|
+
// transactional send journeys cannot be "stopped" but only "paused"
|
|
2403
|
+
pauseTransactionalKeyArr.push(key);
|
|
2404
|
+
break;
|
|
2405
|
+
}
|
|
2406
|
+
case 'Multistep': {
|
|
2407
|
+
const toBeStoppedVersions = [];
|
|
2408
|
+
if (version === '*') {
|
|
2409
|
+
const responseAllVersions = await this.client.rest.getBulk(
|
|
2410
|
+
'/interaction/v1/interactions/?id=' +
|
|
2411
|
+
journeyCache.metadata[key].id +
|
|
2412
|
+
'&mostRecentVersionOnly=false',
|
|
2413
|
+
this.definition.restPageSize || 500
|
|
2414
|
+
);
|
|
2415
|
+
if (responseAllVersions?.items?.length) {
|
|
2416
|
+
// find all active versions
|
|
2417
|
+
const allActiveVersions = responseAllVersions.items
|
|
2418
|
+
.filter((item) =>
|
|
2419
|
+
stoppableJourneyStatus.includes(item.status)
|
|
2420
|
+
)
|
|
2421
|
+
.map((item) => item.version);
|
|
2422
|
+
if (allActiveVersions.length) {
|
|
2423
|
+
toBeStoppedVersions.push(...allActiveVersions);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
if (!toBeStoppedVersions.length) {
|
|
2427
|
+
Util.logger.warn(
|
|
2428
|
+
` ☇ skipping stop of ${this.definition.type} ${key}: no active versions found`
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
} else {
|
|
2432
|
+
if (!version) {
|
|
2433
|
+
version = journeyCache.metadata[key].version;
|
|
2434
|
+
Util.logger.info(
|
|
2435
|
+
Util.getGrayMsg(
|
|
2436
|
+
` - ${this.definition.type} ${key}: no version provided. Will try to stop latest version: Version ${version}. To stop all versions, append /* after the key.`
|
|
2437
|
+
)
|
|
2438
|
+
);
|
|
2439
|
+
if (
|
|
2440
|
+
!stoppableJourneyStatus.includes(
|
|
2441
|
+
journeyCache.metadata[key].status
|
|
2442
|
+
)
|
|
2443
|
+
) {
|
|
2444
|
+
Util.logger.warn(
|
|
2445
|
+
` ☇ skipping stop of ${this.definition.type} ${key}: version ${version} has status "${journeyCache.metadata[key].status}" which cannot be stopped. To stop all versions, append /* after the key.`
|
|
2446
|
+
);
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
toBeStoppedVersions.push(version);
|
|
2450
|
+
}
|
|
2451
|
+
const rateLimitActivities = pLimit(2);
|
|
2452
|
+
const stoppedVersions = (
|
|
2453
|
+
await Promise.all(
|
|
2454
|
+
toBeStoppedVersions.map((version) =>
|
|
2455
|
+
rateLimitActivities(async () => {
|
|
2456
|
+
try {
|
|
2457
|
+
await this.client.rest.post(
|
|
2458
|
+
endpoint +
|
|
2459
|
+
journeyCache.metadata[key].id +
|
|
2460
|
+
`?versionNumber=${version}`,
|
|
2461
|
+
{}
|
|
2462
|
+
);
|
|
2463
|
+
Util.logger.info(
|
|
2464
|
+
` - Stopped ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} - Version ${version}`
|
|
2465
|
+
);
|
|
2466
|
+
return version;
|
|
2467
|
+
} catch (ex) {
|
|
2468
|
+
Util.logger.error(
|
|
2469
|
+
` - Stopping ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} - Version ${version} failed: ${ex.message}`
|
|
2470
|
+
);
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
})
|
|
2474
|
+
)
|
|
2475
|
+
)
|
|
2476
|
+
).filter(Boolean);
|
|
2477
|
+
if (stoppedVersions.length === toBeStoppedVersions.length) {
|
|
2478
|
+
stoppedKeyArr.push(key);
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
break;
|
|
2482
|
+
}
|
|
2483
|
+
default: {
|
|
2484
|
+
Util.logger.error(
|
|
2485
|
+
` - Stopping ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2368
2488
|
}
|
|
2489
|
+
} else {
|
|
2490
|
+
Util.logger.error(
|
|
2491
|
+
` ☇ skipping stop of ${this.definition.type} ${key}: not found on server`
|
|
2492
|
+
);
|
|
2369
2493
|
}
|
|
2370
2494
|
})
|
|
2371
2495
|
)
|
|
2372
2496
|
);
|
|
2497
|
+
stoppedKeyArr.push(...(await this.pause(pauseTransactionalKeyArr)));
|
|
2373
2498
|
|
|
2374
2499
|
return stoppedKeyArr;
|
|
2375
2500
|
}
|
|
2501
|
+
|
|
2376
2502
|
/**
|
|
2377
2503
|
* pauses selected journey versions
|
|
2378
2504
|
*
|
|
2379
2505
|
* @param {string[]} keyArr customerkey of the metadata
|
|
2506
|
+
* @param {MetadataTypeMapObj} [journeyCache] metadata cache used by refresh to avoid recaching
|
|
2380
2507
|
* @returns {Promise.<string[]>} Returns list of keys that were paused
|
|
2381
2508
|
*/
|
|
2382
|
-
static async pause(keyArr) {
|
|
2509
|
+
static async pause(keyArr, journeyCache) {
|
|
2383
2510
|
let version;
|
|
2384
|
-
const
|
|
2385
|
-
const stoppedKeyArr = [];
|
|
2511
|
+
const pausedKeyArr = [];
|
|
2386
2512
|
const apiLimit = pLimit(20);
|
|
2387
|
-
|
|
2513
|
+
journeyCache ||= await this.retrieveForCache();
|
|
2388
2514
|
|
|
2389
2515
|
await Promise.allSettled(
|
|
2390
2516
|
keyArr.map((key) =>
|
|
2391
2517
|
apiLimit(async () => {
|
|
2392
2518
|
[key, version] = key.split('/');
|
|
2393
2519
|
if (journeyCache.metadata[key]) {
|
|
2394
|
-
|
|
2395
|
-
try {
|
|
2396
|
-
await this.client.rest.post(
|
|
2397
|
-
endpoint +
|
|
2398
|
-
journeyCache.metadata[key].id +
|
|
2399
|
-
(version === '*'
|
|
2400
|
-
? '?allVersions=true'
|
|
2401
|
-
: `?versionNumber=${version}`),
|
|
2402
|
-
{}
|
|
2403
|
-
);
|
|
2404
|
-
Util.logger.info(` - Paused ${this.definition.type} ${key}/${version}`);
|
|
2405
|
-
stoppedKeyArr.push(key);
|
|
2406
|
-
} catch (ex) {
|
|
2520
|
+
if (journeyCache.metadata[key].status !== 'Published') {
|
|
2407
2521
|
Util.logger.error(
|
|
2408
|
-
` - Pausing ${this.definition.type} ${key} failed: ${
|
|
2522
|
+
` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Cannot pause a journey in status ${journeyCache.metadata[key].status}`
|
|
2409
2523
|
);
|
|
2524
|
+
return;
|
|
2410
2525
|
}
|
|
2526
|
+
switch (journeyCache.metadata[key].definitionType) {
|
|
2527
|
+
case 'Transactional': {
|
|
2528
|
+
try {
|
|
2529
|
+
const response = await this.client.rest.post(
|
|
2530
|
+
'/interaction/v1/interactions/transactional/pause',
|
|
2531
|
+
{ definitionId: journeyCache.metadata[key].id }
|
|
2532
|
+
);
|
|
2533
|
+
if (response.errors?.length) {
|
|
2534
|
+
throw new Error(JSON.stringify(response));
|
|
2535
|
+
} else {
|
|
2536
|
+
Util.logger.info(
|
|
2537
|
+
` - 🛑 paused ${this.definition.type} ${key} / ${journeyCache.metadata[key].name}`
|
|
2538
|
+
);
|
|
2539
|
+
pausedKeyArr.push(key);
|
|
2540
|
+
}
|
|
2541
|
+
} catch (ex) {
|
|
2542
|
+
Util.logger.error(
|
|
2543
|
+
` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
break;
|
|
2547
|
+
}
|
|
2548
|
+
case 'Multistep': {
|
|
2549
|
+
version ||= journeyCache.metadata[key].version;
|
|
2550
|
+
try {
|
|
2551
|
+
await this.client.rest.post(
|
|
2552
|
+
'/interaction/v1/interactions/pause/' +
|
|
2553
|
+
journeyCache.metadata[key].id +
|
|
2554
|
+
(version === '*'
|
|
2555
|
+
? '?allVersions=true'
|
|
2556
|
+
: `?versionNumber=${version}`),
|
|
2557
|
+
{}
|
|
2558
|
+
);
|
|
2559
|
+
Util.logger.info(
|
|
2560
|
+
` -- 🛑 paused ${this.definition.type} ${key}/${version} / ${journeyCache.metadata[key].name}`
|
|
2561
|
+
);
|
|
2562
|
+
pausedKeyArr.push(key);
|
|
2563
|
+
} catch (ex) {
|
|
2564
|
+
Util.logger.error(
|
|
2565
|
+
` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
2568
|
+
break;
|
|
2569
|
+
}
|
|
2570
|
+
default: {
|
|
2571
|
+
Util.logger.error(
|
|
2572
|
+
` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
} else {
|
|
2577
|
+
Util.logger.error(
|
|
2578
|
+
` ☇ skipping pause of ${this.definition.type} ${key}: not found on server`
|
|
2579
|
+
);
|
|
2411
2580
|
}
|
|
2412
2581
|
})
|
|
2413
2582
|
)
|
|
2414
2583
|
);
|
|
2415
2584
|
|
|
2416
|
-
return
|
|
2585
|
+
return pausedKeyArr;
|
|
2417
2586
|
}
|
|
2418
2587
|
/**
|
|
2419
2588
|
* resumes selected journey versions
|
|
2420
2589
|
*
|
|
2421
2590
|
* @param {string[]} keyArr customerkey of the metadata
|
|
2422
|
-
* @
|
|
2591
|
+
* @param {MetadataTypeMapObj} [journeyCache] metadata cache used by refresh to avoid recaching
|
|
2592
|
+
* @returns {Promise.<string[]>} Returns list of keys that were resumed
|
|
2423
2593
|
*/
|
|
2424
|
-
static async execute(keyArr) {
|
|
2594
|
+
static async execute(keyArr, journeyCache) {
|
|
2425
2595
|
let version;
|
|
2426
2596
|
const endpoint = '/interaction/v1/interactions/resume/';
|
|
2427
2597
|
const resumedKeyArr = [];
|
|
2428
2598
|
const apiLimit = pLimit(20);
|
|
2429
|
-
|
|
2599
|
+
journeyCache ||= await this.retrieveForCache();
|
|
2430
2600
|
|
|
2431
2601
|
await Promise.allSettled(
|
|
2432
2602
|
keyArr.map((key) =>
|
|
2433
2603
|
apiLimit(async () => {
|
|
2434
2604
|
[key, version] = key.split('/');
|
|
2435
2605
|
if (journeyCache.metadata[key]) {
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
endpoint +
|
|
2440
|
-
journeyCache.metadata[key].id +
|
|
2441
|
-
(version === '*'
|
|
2442
|
-
? '?allVersions=true'
|
|
2443
|
-
: `?versionNumber=${version}`),
|
|
2444
|
-
{}
|
|
2606
|
+
if (journeyCache.metadata[key].status !== 'Paused') {
|
|
2607
|
+
Util.logger.error(
|
|
2608
|
+
` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Cannot pause a journey in status ${journeyCache.metadata[key].status}`
|
|
2445
2609
|
);
|
|
2446
|
-
|
|
2447
|
-
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
switch (journeyCache.metadata[key].definitionType) {
|
|
2613
|
+
case 'Transactional': {
|
|
2614
|
+
try {
|
|
2615
|
+
const response = await this.client.rest.post(
|
|
2616
|
+
'/interaction/v1/interactions/transactional/resume',
|
|
2617
|
+
{ definitionId: journeyCache.metadata[key].id }
|
|
2618
|
+
);
|
|
2619
|
+
if (response.errors?.length) {
|
|
2620
|
+
throw new Error(JSON.stringify(response));
|
|
2621
|
+
} else {
|
|
2622
|
+
Util.logger.info(
|
|
2623
|
+
` - ✅ resumed ${this.definition.type} ${key} / ${journeyCache.metadata[key].name}`
|
|
2624
|
+
);
|
|
2625
|
+
resumedKeyArr.push(key);
|
|
2626
|
+
}
|
|
2627
|
+
} catch (ex) {
|
|
2628
|
+
Util.logger.error(
|
|
2629
|
+
` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
break;
|
|
2633
|
+
}
|
|
2634
|
+
case 'Multistep': {
|
|
2635
|
+
version ||= journeyCache.metadata[key].version;
|
|
2636
|
+
try {
|
|
2637
|
+
await this.client.rest.post(
|
|
2638
|
+
endpoint +
|
|
2639
|
+
journeyCache.metadata[key].id +
|
|
2640
|
+
(version === '*'
|
|
2641
|
+
? '?allVersions=true'
|
|
2642
|
+
: `?versionNumber=${version}`),
|
|
2643
|
+
{}
|
|
2644
|
+
);
|
|
2645
|
+
Util.logger.info(
|
|
2646
|
+
` - ✅ resumed ${this.definition.type} ${key}/${version}`
|
|
2647
|
+
);
|
|
2648
|
+
resumedKeyArr.push(key);
|
|
2649
|
+
} catch (ex) {
|
|
2650
|
+
Util.logger.error(
|
|
2651
|
+
` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
|
|
2652
|
+
);
|
|
2653
|
+
}
|
|
2654
|
+
break;
|
|
2655
|
+
}
|
|
2656
|
+
default: {
|
|
2657
|
+
Util.logger.error(
|
|
2658
|
+
` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
} else {
|
|
2663
|
+
Util.logger.error(
|
|
2664
|
+
` ☇ skipping resume of ${this.definition.type} ${key}: not found on server`
|
|
2665
|
+
);
|
|
2666
|
+
}
|
|
2667
|
+
})
|
|
2668
|
+
)
|
|
2669
|
+
);
|
|
2670
|
+
|
|
2671
|
+
return resumedKeyArr;
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
/**
|
|
2675
|
+
* TSD-specific refresh method that finds active TSDs and refreshes them
|
|
2676
|
+
*
|
|
2677
|
+
* @param {string[]} keyArr metadata keys
|
|
2678
|
+
* @param {boolean} [checkKey] whether to check if the key is valid
|
|
2679
|
+
* @returns {Promise.<string[]>} Returns list of keys that were refreshed
|
|
2680
|
+
*/
|
|
2681
|
+
static async refresh(keyArr, checkKey = true) {
|
|
2682
|
+
console.time('Time'); // eslint-disable-line no-console
|
|
2683
|
+
if (!keyArr) {
|
|
2684
|
+
Util.logger.error('No refresh-keys provided');
|
|
2685
|
+
return [];
|
|
2686
|
+
// keyArr = await this.getKeysForValidTSDs((await this.findRefreshableItems()).metadata);
|
|
2687
|
+
// checkKey = false;
|
|
2688
|
+
}
|
|
2689
|
+
let journeyCache;
|
|
2690
|
+
if (checkKey) {
|
|
2691
|
+
journeyCache = await this.retrieveForCache();
|
|
2692
|
+
}
|
|
2693
|
+
// then executes pause, publish, start on them.
|
|
2694
|
+
Util.logger.info(`Refreshing ${keyArr.length} ${this.definition.typeName}...`);
|
|
2695
|
+
Util.logger.debug(`Refreshing keys: ${keyArr.join(', ')}`);
|
|
2696
|
+
const refreshedKeyArr = [];
|
|
2697
|
+
const tsKeys = [];
|
|
2698
|
+
const rateLimit = pLimit(10);
|
|
2699
|
+
await Promise.all(
|
|
2700
|
+
keyArr.map((key) =>
|
|
2701
|
+
rateLimit(async () => {
|
|
2702
|
+
if (checkKey && !journeyCache.metadata[key]) {
|
|
2703
|
+
Util.logger.error(
|
|
2704
|
+
` ☇ skipping refresh of ${this.definition.type} ${key}: not found on server`
|
|
2705
|
+
);
|
|
2706
|
+
return;
|
|
2707
|
+
}
|
|
2708
|
+
switch (journeyCache.metadata[key].definitionType) {
|
|
2709
|
+
case 'Transactional': {
|
|
2710
|
+
if (checkKey && journeyCache.metadata[key]?.status !== 'Published') {
|
|
2711
|
+
Util.logger.error(
|
|
2712
|
+
` ☇ skipping refresh of ${this.definition.type} ${key}: Can only refresh journeys with status 'Published'. Found status: ${journeyCache.metadata[key]?.status}`
|
|
2713
|
+
);
|
|
2714
|
+
} else {
|
|
2715
|
+
const result = await this._refreshItem(key, journeyCache);
|
|
2716
|
+
if (result) {
|
|
2717
|
+
refreshedKeyArr.push(key);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
break;
|
|
2721
|
+
}
|
|
2722
|
+
case 'Multistep': {
|
|
2723
|
+
// find all published & paused versions
|
|
2724
|
+
const responseAllVersions = await this.client.rest.getBulk(
|
|
2725
|
+
'/interaction/v1/interactions/?id=' +
|
|
2726
|
+
journeyCache.metadata[key].id +
|
|
2727
|
+
'&mostRecentVersionOnly=false',
|
|
2728
|
+
this.definition.restPageSize || 500
|
|
2448
2729
|
);
|
|
2449
|
-
|
|
2450
|
-
|
|
2730
|
+
if (responseAllVersions?.items?.length) {
|
|
2731
|
+
const allActiveVersions = responseAllVersions.items
|
|
2732
|
+
.filter(
|
|
2733
|
+
(item) =>
|
|
2734
|
+
item.status === 'Paused' || item.status === 'Published'
|
|
2735
|
+
)
|
|
2736
|
+
.map((item) => item.version);
|
|
2737
|
+
if (allActiveVersions.length) {
|
|
2738
|
+
Util.logger.info(
|
|
2739
|
+
Util.getGrayMsg(
|
|
2740
|
+
` - journey ${key} / ${journeyCache.metadata[key].name} Paused/Published version numbers: ` +
|
|
2741
|
+
allActiveVersions.join(', ')
|
|
2742
|
+
)
|
|
2743
|
+
);
|
|
2744
|
+
// get TS keys from email activities of paused/published versions
|
|
2745
|
+
const rateLimitActivities = pLimit(2);
|
|
2746
|
+
tsKeys.push(
|
|
2747
|
+
...(
|
|
2748
|
+
await Promise.all(
|
|
2749
|
+
allActiveVersions.map((version) =>
|
|
2750
|
+
rateLimitActivities(async () => {
|
|
2751
|
+
const journey = await this.client.rest.get(
|
|
2752
|
+
'/interaction/v1/interactions/' +
|
|
2753
|
+
journeyCache.metadata[key]?.id +
|
|
2754
|
+
'?extras=activities&versionNumber=' +
|
|
2755
|
+
version
|
|
2756
|
+
);
|
|
2757
|
+
// return all triggeredSends
|
|
2758
|
+
// ! if somebody changed the key of the triggeredSend then the journey would have wrong info in triggeredSendKey. There is the alternative field triggeredSendId but that would be too costly to use here because we would need to retrieve all TSs to find the correct one. Also, changing TS keys is not a common practice.
|
|
2759
|
+
return journey.activities
|
|
2760
|
+
.filter(
|
|
2761
|
+
(activity) =>
|
|
2762
|
+
activity.type === 'EMAILV2' &&
|
|
2763
|
+
activity.configurationArguments
|
|
2764
|
+
?.triggeredSendKey
|
|
2765
|
+
)
|
|
2766
|
+
.map(
|
|
2767
|
+
(activity) =>
|
|
2768
|
+
activity.configurationArguments
|
|
2769
|
+
?.triggeredSendKey
|
|
2770
|
+
);
|
|
2771
|
+
})
|
|
2772
|
+
)
|
|
2773
|
+
)
|
|
2774
|
+
).flat()
|
|
2775
|
+
);
|
|
2776
|
+
|
|
2777
|
+
refreshedKeyArr.push(key);
|
|
2778
|
+
} else {
|
|
2779
|
+
Util.logger.error(
|
|
2780
|
+
` ☇ skipping refresh of ${this.definition.type} ${key}: no published/paused versions found`
|
|
2781
|
+
);
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
break;
|
|
2785
|
+
}
|
|
2786
|
+
default: {
|
|
2451
2787
|
Util.logger.error(
|
|
2452
|
-
` -
|
|
2788
|
+
` - Refreshing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
|
|
2453
2789
|
);
|
|
2454
2790
|
}
|
|
2455
2791
|
}
|
|
@@ -2457,7 +2793,49 @@ class Journey extends MetadataType {
|
|
|
2457
2793
|
)
|
|
2458
2794
|
);
|
|
2459
2795
|
|
|
2460
|
-
|
|
2796
|
+
if (tsKeys.length) {
|
|
2797
|
+
// refresh TriggeredSends
|
|
2798
|
+
TriggeredSend.buObject = this.buObject;
|
|
2799
|
+
TriggeredSend.client = this.client;
|
|
2800
|
+
TriggeredSend.properties = this.properties;
|
|
2801
|
+
// hard-refresh all triggeredSends even if the TS was paused (inactive) before
|
|
2802
|
+
await TriggeredSend.refresh(tsKeys, false);
|
|
2803
|
+
} else {
|
|
2804
|
+
Util.logger.info(Util.getGrayMsg('No triggeredSends found to refresh'));
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
Util.logger.info(
|
|
2808
|
+
`Refreshed ${refreshedKeyArr.length} of ${keyArr.length} ${this.definition.type}`
|
|
2809
|
+
);
|
|
2810
|
+
console.timeEnd('Time'); // eslint-disable-line no-console
|
|
2811
|
+
return refreshedKeyArr;
|
|
2812
|
+
}
|
|
2813
|
+
/**
|
|
2814
|
+
* helper for {@link Journey.refresh} that pauses, publishes and starts a triggered send
|
|
2815
|
+
*
|
|
2816
|
+
* @param {string} key external key of triggered send item
|
|
2817
|
+
* @param {MetadataTypeMapObj} journeyCache metadata cache
|
|
2818
|
+
* @returns {Promise.<boolean>} true if refresh was successful
|
|
2819
|
+
*/
|
|
2820
|
+
static async _refreshItem(key, journeyCache) {
|
|
2821
|
+
// pause
|
|
2822
|
+
const pausedKeys = await this.pause([key], journeyCache);
|
|
2823
|
+
if (!pausedKeys?.length || pausedKeys[0] !== key) {
|
|
2824
|
+
Util.logger.error(` - failed to pause ${this.definition.typeName}: ${key}`);
|
|
2825
|
+
return false;
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
// update cache or else resume (execute) will fail
|
|
2829
|
+
journeyCache.metadata[key].status = 'Paused';
|
|
2830
|
+
|
|
2831
|
+
// resume
|
|
2832
|
+
const resumedKeys = await this.execute([key], journeyCache);
|
|
2833
|
+
if (!resumedKeys?.length || resumedKeys[0] !== key) {
|
|
2834
|
+
Util.logger.error(` - failed to resume ${this.definition.typeName}: ${key}`);
|
|
2835
|
+
return false;
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
return true;
|
|
2461
2839
|
}
|
|
2462
2840
|
}
|
|
2463
2841
|
|