mcdev 7.5.0 → 7.6.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 (34) hide show
  1. package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
  2. package/@types/lib/index.d.ts +12 -8
  3. package/@types/lib/index.d.ts.map +1 -1
  4. package/@types/lib/metadataTypes/AttributeSet.d.ts.map +1 -1
  5. package/@types/lib/metadataTypes/DataExtension.d.ts +3 -1
  6. package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
  7. package/@types/lib/metadataTypes/Event.d.ts +2 -2
  8. package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
  9. package/@types/lib/metadataTypes/Journey.d.ts +16 -0
  10. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
  11. package/@types/lib/metadataTypes/MetadataType.d.ts +4 -2
  12. package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
  13. package/@types/lib/metadataTypes/TransactionalEmail.d.ts +1 -0
  14. package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
  15. package/@types/lib/metadataTypes/TriggeredSend.d.ts +0 -8
  16. package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -1
  17. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +1 -0
  18. package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts +1 -0
  19. package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -1
  20. package/@types/lib/util/util.d.ts.map +1 -1
  21. package/@types/types/mcdev.d.d.ts +15 -7
  22. package/@types/types/mcdev.d.d.ts.map +1 -1
  23. package/lib/cli.js +13 -2
  24. package/lib/index.js +46 -42
  25. package/lib/metadataTypes/Event.js +4 -1
  26. package/lib/metadataTypes/Journey.js +456 -90
  27. package/lib/metadataTypes/MetadataType.js +8 -4
  28. package/lib/metadataTypes/TriggeredSend.js +21 -12
  29. package/lib/metadataTypes/definitions/Journey.definition.js +1 -0
  30. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +1 -0
  31. package/package.json +15 -15
  32. package/test/mockRoot/.mcdevrc.json +1 -1
  33. package/test/resources/9999999/interaction/v1/interactions/dsfdsafdsa-922c-4568-85a5-e5cc77efc3be/delete-response.txt +1 -0
  34. package/test/type.journey.test.js +6 -5
@@ -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 singleKey = '';
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
- singleKey = key.slice(3);
220
- if (singleKey.startsWith('%23')) {
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
- singleKey = singleKey.slice(3);
226
+ id = id.slice(3);
224
227
  }
225
- if (singleKey.includes('/')) {
228
+ if (id.includes('/')) {
226
229
  // in the journey URL the version is appended after the ID, separated by a forward-slash.
227
- [singleKey, version] = singleKey.split('/');
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
- const response = await this.client.rest.get(
237
- `/interaction/v1/interactions/key:${encodeURIComponent(key)}?extras=`
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
- return false;
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 (version !== '*') {
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
- `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.`
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
- return super.deleteByKeyREST(
264
- '/interaction/v1/interactions/' +
265
- singleKey +
266
- (version === '*' ? '' : `?versionNumber=${version}`),
267
- key,
268
- false
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 (cachedVersion.status === 'Draft') {
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,41 +2386,115 @@ 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
- version ||= journeyCache.metadata[key].version;
2347
- if (version === '*') {
2348
- Util.logger.warn(
2349
- ` ☇ skipping ${this.definition.type} ${key}: Cannot stop all versions at once. The highest version is ${journeyCache.metadata[key].version}`
2350
- );
2351
- return;
2352
- }
2353
- try {
2354
- await this.client.rest.post(
2355
- endpoint +
2356
- journeyCache.metadata[key].id +
2357
- `?versionNumber=${version}`,
2358
- {}
2359
- );
2360
- Util.logger.info(
2361
- ` - Stopped ${this.definition.type} ${key}/${version}`
2362
- );
2363
- stoppedKeyArr.push(key);
2364
- } catch (ex) {
2365
- Util.logger.error(
2366
- ` - Stopping ${this.definition.type} ${key} failed: ${ex.message}`
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
  }
@@ -2381,8 +2506,7 @@ class Journey extends MetadataType {
2381
2506
  */
2382
2507
  static async pause(keyArr) {
2383
2508
  let version;
2384
- const endpoint = '/interaction/v1/interactions/pause/';
2385
- const stoppedKeyArr = [];
2509
+ const pausedKeyArr = [];
2386
2510
  const apiLimit = pLimit(20);
2387
2511
  const journeyCache = await this.retrieveForCache();
2388
2512
 
@@ -2391,35 +2515,78 @@ class Journey extends MetadataType {
2391
2515
  apiLimit(async () => {
2392
2516
  [key, version] = key.split('/');
2393
2517
  if (journeyCache.metadata[key]) {
2394
- version ||= journeyCache.metadata[key].version;
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) {
2518
+ if (journeyCache.metadata[key].status !== 'Published') {
2407
2519
  Util.logger.error(
2408
- ` - Pausing ${this.definition.type} ${key} failed: ${ex.message}`
2520
+ ` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Cannot pause a journey in status ${journeyCache.metadata[key].status}`
2409
2521
  );
2522
+ return;
2410
2523
  }
2524
+ switch (journeyCache.metadata[key].definitionType) {
2525
+ case 'Transactional': {
2526
+ try {
2527
+ const response = await this.client.rest.post(
2528
+ '/interaction/v1/interactions/transactional/pause',
2529
+ { definitionId: journeyCache.metadata[key].id }
2530
+ );
2531
+ if (response.errors?.length) {
2532
+ throw new Error(JSON.stringify(response));
2533
+ } else {
2534
+ Util.logger.info(
2535
+ ` - 🛑 paused ${this.definition.type} ${key} / ${journeyCache.metadata[key].name}`
2536
+ );
2537
+ pausedKeyArr.push(key);
2538
+ }
2539
+ } catch (ex) {
2540
+ Util.logger.error(
2541
+ ` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
2542
+ );
2543
+ }
2544
+ break;
2545
+ }
2546
+ case 'Multistep': {
2547
+ version ||= journeyCache.metadata[key].version;
2548
+ try {
2549
+ await this.client.rest.post(
2550
+ '/interaction/v1/interactions/pause/' +
2551
+ journeyCache.metadata[key].id +
2552
+ (version === '*'
2553
+ ? '?allVersions=true'
2554
+ : `?versionNumber=${version}`),
2555
+ {}
2556
+ );
2557
+ Util.logger.info(
2558
+ ` -- 🛑 paused ${this.definition.type} ${key}/${version} / ${journeyCache.metadata[key].name}`
2559
+ );
2560
+ pausedKeyArr.push(key);
2561
+ } catch (ex) {
2562
+ Util.logger.error(
2563
+ ` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
2564
+ );
2565
+ }
2566
+ break;
2567
+ }
2568
+ default: {
2569
+ Util.logger.error(
2570
+ ` - Pausing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
2571
+ );
2572
+ }
2573
+ }
2574
+ } else {
2575
+ Util.logger.error(
2576
+ ` ☇ skipping pause of ${this.definition.type} ${key}: not found on server`
2577
+ );
2411
2578
  }
2412
2579
  })
2413
2580
  )
2414
2581
  );
2415
2582
 
2416
- return stoppedKeyArr;
2583
+ return pausedKeyArr;
2417
2584
  }
2418
2585
  /**
2419
2586
  * resumes selected journey versions
2420
2587
  *
2421
2588
  * @param {string[]} keyArr customerkey of the metadata
2422
- * @returns {Promise.<string[]>} Returns list of keys that were paused
2589
+ * @returns {Promise.<string[]>} Returns list of keys that were resumed
2423
2590
  */
2424
2591
  static async execute(keyArr) {
2425
2592
  let version;
@@ -2433,23 +2600,188 @@ class Journey extends MetadataType {
2433
2600
  apiLimit(async () => {
2434
2601
  [key, version] = key.split('/');
2435
2602
  if (journeyCache.metadata[key]) {
2436
- version ||= journeyCache.metadata[key].version;
2437
- try {
2438
- await this.client.rest.post(
2439
- endpoint +
2440
- journeyCache.metadata[key].id +
2441
- (version === '*'
2442
- ? '?allVersions=true'
2443
- : `?versionNumber=${version}`),
2444
- {}
2603
+ if (journeyCache.metadata[key].status !== 'Paused') {
2604
+ Util.logger.error(
2605
+ ` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Cannot pause a journey in status ${journeyCache.metadata[key].status}`
2445
2606
  );
2446
- Util.logger.info(
2447
- ` - Resumed ${this.definition.type} ${key}/${version}`
2607
+ return;
2608
+ }
2609
+ switch (journeyCache.metadata[key].definitionType) {
2610
+ case 'Transactional': {
2611
+ try {
2612
+ const response = await this.client.rest.post(
2613
+ '/interaction/v1/interactions/transactional/resume',
2614
+ { definitionId: journeyCache.metadata[key].id }
2615
+ );
2616
+ if (response.errors?.length) {
2617
+ throw new Error(JSON.stringify(response));
2618
+ } else {
2619
+ Util.logger.info(
2620
+ ` - ✅ resumed ${this.definition.type} ${key} / ${journeyCache.metadata[key].name}`
2621
+ );
2622
+ resumedKeyArr.push(key);
2623
+ }
2624
+ } catch (ex) {
2625
+ Util.logger.error(
2626
+ ` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
2627
+ );
2628
+ }
2629
+ break;
2630
+ }
2631
+ case 'Multistep': {
2632
+ version ||= journeyCache.metadata[key].version;
2633
+ try {
2634
+ await this.client.rest.post(
2635
+ endpoint +
2636
+ journeyCache.metadata[key].id +
2637
+ (version === '*'
2638
+ ? '?allVersions=true'
2639
+ : `?versionNumber=${version}`),
2640
+ {}
2641
+ );
2642
+ Util.logger.info(
2643
+ ` - ✅ resumed ${this.definition.type} ${key}/${version}`
2644
+ );
2645
+ resumedKeyArr.push(key);
2646
+ } catch (ex) {
2647
+ Util.logger.error(
2648
+ ` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: ${ex.message}`
2649
+ );
2650
+ }
2651
+ break;
2652
+ }
2653
+ default: {
2654
+ Util.logger.error(
2655
+ ` - Resuming ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
2656
+ );
2657
+ }
2658
+ }
2659
+ } else {
2660
+ Util.logger.error(
2661
+ ` ☇ skipping resume of ${this.definition.type} ${key}: not found on server`
2662
+ );
2663
+ }
2664
+ })
2665
+ )
2666
+ );
2667
+
2668
+ return resumedKeyArr;
2669
+ }
2670
+
2671
+ /**
2672
+ * TSD-specific refresh method that finds active TSDs and refreshes them
2673
+ *
2674
+ * @param {string[]} keyArr metadata keys
2675
+ * @param {boolean} [checkKey] whether to check if the key is valid
2676
+ * @returns {Promise.<string[]>} Returns list of keys that were refreshed
2677
+ */
2678
+ static async refresh(keyArr, checkKey = true) {
2679
+ console.time('Time'); // eslint-disable-line no-console
2680
+ if (!keyArr) {
2681
+ Util.logger.error('No refresh-keys provided');
2682
+ return [];
2683
+ // keyArr = await this.getKeysForValidTSDs((await this.findRefreshableItems()).metadata);
2684
+ // checkKey = false;
2685
+ }
2686
+ let journeyCache;
2687
+ if (checkKey) {
2688
+ journeyCache = await this.retrieveForCache();
2689
+ }
2690
+ // then executes pause, publish, start on them.
2691
+ Util.logger.info(`Refreshing ${keyArr.length} ${this.definition.typeName}...`);
2692
+ Util.logger.debug(`Refreshing keys: ${keyArr.join(', ')}`);
2693
+ const refreshedKeyArr = [];
2694
+ const tsKeys = [];
2695
+ const rateLimit = pLimit(10);
2696
+ await Promise.all(
2697
+ keyArr.map((key) =>
2698
+ rateLimit(async () => {
2699
+ if (checkKey && !journeyCache.metadata[key]) {
2700
+ Util.logger.error(
2701
+ ` ☇ skipping refresh of ${this.definition.type} ${key}: not found on server`
2702
+ );
2703
+ return;
2704
+ }
2705
+ switch (journeyCache.metadata[key].definitionType) {
2706
+ case 'Transactional': {
2707
+ if (checkKey && journeyCache.metadata[key]?.status !== 'Published') {
2708
+ Util.logger.error(
2709
+ ` ☇ skipping refresh of ${this.definition.type} ${key}: Can only refresh journeys with status 'Published'. Found status: ${journeyCache.metadata[key]?.status}`
2710
+ );
2711
+ } else {
2712
+ const result = await this._refreshItem(key);
2713
+ if (result) {
2714
+ refreshedKeyArr.push(key);
2715
+ }
2716
+ }
2717
+ break;
2718
+ }
2719
+ case 'Multistep': {
2720
+ // find all published & paused versions
2721
+ const responseAllVersions = await this.client.rest.getBulk(
2722
+ '/interaction/v1/interactions/?id=' +
2723
+ journeyCache.metadata[key].id +
2724
+ '&mostRecentVersionOnly=false',
2725
+ this.definition.restPageSize || 500
2448
2726
  );
2449
- resumedKeyArr.push(key);
2450
- } catch (ex) {
2727
+ if (responseAllVersions?.items?.length) {
2728
+ const allActiveVersions = responseAllVersions.items
2729
+ .filter(
2730
+ (item) =>
2731
+ item.status === 'Paused' || item.status === 'Published'
2732
+ )
2733
+ .map((item) => item.version);
2734
+ if (allActiveVersions.length) {
2735
+ Util.logger.info(
2736
+ Util.getGrayMsg(
2737
+ ` - journey ${key} / ${journeyCache.metadata[key].name} Paused/Published version numbers: ` +
2738
+ allActiveVersions.join(', ')
2739
+ )
2740
+ );
2741
+ // get TS keys from email activities of paused/published versions
2742
+ const rateLimitActivities = pLimit(2);
2743
+ tsKeys.push(
2744
+ ...(
2745
+ await Promise.all(
2746
+ allActiveVersions.map((version) =>
2747
+ rateLimitActivities(async () => {
2748
+ const journey = await this.client.rest.get(
2749
+ '/interaction/v1/interactions/' +
2750
+ journeyCache.metadata[key]?.id +
2751
+ '?extras=activities&versionNumber=' +
2752
+ version
2753
+ );
2754
+ // return all triggeredSends
2755
+ return journey.activities
2756
+ .filter(
2757
+ (activity) =>
2758
+ activity.type === 'EMAILV2' &&
2759
+ activity.configurationArguments
2760
+ ?.triggeredSendKey
2761
+ )
2762
+ .map(
2763
+ (activity) =>
2764
+ activity.configurationArguments
2765
+ ?.triggeredSendKey
2766
+ );
2767
+ })
2768
+ )
2769
+ )
2770
+ ).flat()
2771
+ );
2772
+
2773
+ refreshedKeyArr.push(key);
2774
+ } else {
2775
+ Util.logger.error(
2776
+ ` ☇ skipping refresh of ${this.definition.type} ${key}: no published/paused versions found`
2777
+ );
2778
+ }
2779
+ }
2780
+ break;
2781
+ }
2782
+ default: {
2451
2783
  Util.logger.error(
2452
- ` - Resuming ${this.definition.type} ${key} failed: ${ex.message}`
2784
+ ` - Refreshing ${this.definition.type} ${key} / ${journeyCache.metadata[key].name} failed: Unsupported definitionType '${journeyCache.metadata[key].definitionType}'`
2453
2785
  );
2454
2786
  }
2455
2787
  }
@@ -2457,7 +2789,41 @@ class Journey extends MetadataType {
2457
2789
  )
2458
2790
  );
2459
2791
 
2460
- return resumedKeyArr;
2792
+ // refresh TriggeredSends
2793
+ TriggeredSend.buObject = this.buObject;
2794
+ TriggeredSend.client = this.client;
2795
+ TriggeredSend.properties = this.properties;
2796
+ // hard-refresh all triggeredSends even if the TS was paused (inactive) before
2797
+ await TriggeredSend.refresh(tsKeys, false);
2798
+
2799
+ Util.logger.info(
2800
+ `Refreshed ${refreshedKeyArr.length} of ${keyArr.length} ${this.definition.type}`
2801
+ );
2802
+ console.timeEnd('Time'); // eslint-disable-line no-console
2803
+ return refreshedKeyArr;
2804
+ }
2805
+ /**
2806
+ * helper for {@link Journey.refresh} that pauses, publishes and starts a triggered send
2807
+ *
2808
+ * @param {string} key external key of triggered send item
2809
+ * @returns {Promise.<boolean>} true if refresh was successful
2810
+ */
2811
+ static async _refreshItem(key) {
2812
+ // pause
2813
+ const pausedKeys = await this.pause([key]);
2814
+ if (!pausedKeys?.length || pausedKeys[0] !== key) {
2815
+ Util.logger.error(` - failed to pause ${this.definition.typeName}: ${key}`);
2816
+ return false;
2817
+ }
2818
+
2819
+ // resume
2820
+ const resumedKeys = await this.execute([key]);
2821
+ if (!resumedKeys?.length || resumedKeys[0] !== key) {
2822
+ Util.logger.error(` - failed to resume ${this.definition.typeName}: ${key}`);
2823
+ return false;
2824
+ }
2825
+
2826
+ return true;
2461
2827
  }
2462
2828
  }
2463
2829