mcdev 4.2.1 → 4.3.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.
Files changed (98) hide show
  1. package/.github/ISSUE_TEMPLATE/bug.yml +3 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +1 -2
  3. package/.github/pr-labeler.yml +3 -0
  4. package/.github/workflows/close_issues_on_merge.yml +18 -0
  5. package/.github/workflows/pr-labeler.yml +19 -0
  6. package/LICENSE +1 -1
  7. package/README.md +1 -1
  8. package/docs/dist/documentation.md +702 -284
  9. package/lib/Deployer.js +21 -15
  10. package/lib/Retriever.js +41 -34
  11. package/lib/cli.js +36 -6
  12. package/lib/index.js +56 -10
  13. package/lib/metadataTypes/AccountUser.js +17 -23
  14. package/lib/metadataTypes/Asset.js +36 -48
  15. package/lib/metadataTypes/AttributeGroup.js +1 -2
  16. package/lib/metadataTypes/Automation.js +75 -37
  17. package/lib/metadataTypes/Campaign.js +4 -3
  18. package/lib/metadataTypes/ContentArea.js +2 -3
  19. package/lib/metadataTypes/DataExtension.js +56 -47
  20. package/lib/metadataTypes/DataExtensionField.js +9 -12
  21. package/lib/metadataTypes/DataExtensionTemplate.js +2 -3
  22. package/lib/metadataTypes/DataExtract.js +1 -2
  23. package/lib/metadataTypes/DataExtractType.js +1 -2
  24. package/lib/metadataTypes/Discovery.js +3 -4
  25. package/lib/metadataTypes/Email.js +20 -6
  26. package/lib/metadataTypes/EmailSendDefinition.js +40 -39
  27. package/lib/metadataTypes/EventDefinition.js +29 -2
  28. package/lib/metadataTypes/FileTransfer.js +1 -2
  29. package/lib/metadataTypes/Filter.js +1 -2
  30. package/lib/metadataTypes/Folder.js +12 -14
  31. package/lib/metadataTypes/FtpLocation.js +1 -2
  32. package/lib/metadataTypes/ImportFile.js +1 -2
  33. package/lib/metadataTypes/Interaction.js +743 -12
  34. package/lib/metadataTypes/List.js +36 -33
  35. package/lib/metadataTypes/MetadataType.js +170 -124
  36. package/lib/metadataTypes/MobileCode.js +1 -2
  37. package/lib/metadataTypes/MobileKeyword.js +1 -2
  38. package/lib/metadataTypes/Query.js +15 -6
  39. package/lib/metadataTypes/Role.js +10 -11
  40. package/lib/metadataTypes/Script.js +2 -5
  41. package/lib/metadataTypes/SetDefinition.js +1 -2
  42. package/lib/metadataTypes/TransactionalMessage.js +25 -32
  43. package/lib/metadataTypes/TransactionalSMS.js +3 -4
  44. package/lib/metadataTypes/TriggeredSendDefinition.js +232 -56
  45. package/lib/metadataTypes/definitions/Asset.definition.js +1 -1
  46. package/lib/metadataTypes/definitions/Automation.definition.js +1 -1
  47. package/lib/metadataTypes/definitions/DataExtension.definition.js +10 -1
  48. package/lib/metadataTypes/definitions/Email.definition.js +1 -1
  49. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +1 -1
  50. package/lib/metadataTypes/definitions/EventDefinition.definition.js +40 -1
  51. package/lib/metadataTypes/definitions/Folder.definition.js +31 -0
  52. package/lib/metadataTypes/definitions/ImportFile.definition.js +1 -1
  53. package/lib/metadataTypes/definitions/Interaction.definition.js +47 -26
  54. package/lib/metadataTypes/definitions/List.definition.js +1 -1
  55. package/lib/metadataTypes/definitions/Query.definition.js +1 -1
  56. package/lib/metadataTypes/definitions/Script.definition.js +1 -1
  57. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +4 -3
  58. package/lib/metadataTypes/definitions/TransactionalPush.definition.js +4 -3
  59. package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +4 -3
  60. package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +10 -2
  61. package/lib/util/auth.js +15 -2
  62. package/lib/util/cli.js +4 -1
  63. package/lib/util/file.js +7 -3
  64. package/lib/util/init.js +62 -0
  65. package/lib/util/util.js +173 -11
  66. package/package.json +23 -9
  67. package/test/dataExtension.test.js +10 -10
  68. package/test/interaction.test.js +123 -0
  69. package/test/mockRoot/.mcdevrc.json +1 -1
  70. package/test/mockRoot/deploy/testInstance/testBU/interaction/testExisting_interaction.interaction-meta.json +266 -0
  71. package/test/mockRoot/deploy/testInstance/testBU/interaction/testNew_interaction.interaction-meta.json +266 -0
  72. package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +0 -3
  73. package/test/query.test.js +8 -8
  74. package/test/resourceFactory.js +30 -14
  75. package/test/resources/1111111/dataExtension/retrieve-response.xml +26 -0
  76. package/test/resources/9999999/data/v1/customobjectdata/key/childBU_dataextension_test/rowset/get-response.json +13 -0
  77. package/test/resources/9999999/dataFolder/retrieve-response.xml +22 -0
  78. package/test/resources/9999999/eventDefinition/get-expected.json +34 -0
  79. package/test/resources/9999999/interaction/build-expected.json +260 -0
  80. package/test/resources/9999999/interaction/get-expected.json +264 -0
  81. package/test/resources/9999999/interaction/post-expected.json +264 -0
  82. package/test/resources/9999999/interaction/put-expected.json +264 -0
  83. package/test/resources/9999999/interaction/template-expected.json +260 -0
  84. package/test/resources/9999999/interaction/v1/EventDefinitions/get-response.json +43 -0
  85. package/test/resources/9999999/interaction/v1/interactions/get-response.json +222 -3
  86. package/test/resources/9999999/interaction/v1/interactions/key_0b76dccf-594c-b6dc-1acf-10c4493dcb84/get-response.json +219 -0
  87. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +280 -0
  88. package/test/resources/9999999/interaction/v1/interactions/post-response.json +280 -0
  89. package/test/resources/9999999/interaction/v1/interactions/put-response.json +280 -0
  90. package/test/resources/9999999/messaging/v1/email/definitions/post-response.json +1 -1
  91. package/test/resources/9999999/query/post-expected.sql +1 -1
  92. package/test/resources/9999999/transactionalEmail/post-expected.json +1 -1
  93. package/test/resources/9999999/triggeredSendDefinition/retrieve-response.xml +68 -0
  94. package/test/transactionalEmail.test.js +7 -7
  95. package/test/transactionalPush.test.js +7 -7
  96. package/test/transactionalSMS.test.js +7 -7
  97. package/test/utils.js +50 -0
  98. package/types/mcdev.d.js +1 -0
@@ -19,34 +19,25 @@ class Asset extends MetadataType {
19
19
  *
20
20
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
21
21
  * @param {void} _ -
22
- * @param {void} __ -
23
- * @param {TYPE.AssetSubType} [selectedSubType] optionally limit to a single subtype
22
+ * @param {TYPE.AssetSubType[]} [subTypeArr] optionally limit to a single subtype
24
23
  * @param {string} [key] customer key
25
24
  * @returns {Promise.<{metadata: TYPE.AssetMap, type: string}>} Promise
26
25
  */
27
- static async retrieve(retrieveDir, _, __, selectedSubType, key) {
26
+ static async retrieve(retrieveDir, _, subTypeArr, key) {
28
27
  const items = [];
29
- const subTypes = selectedSubType ? [selectedSubType] : this._getSubTypes();
28
+ subTypeArr = subTypeArr || this._getSubTypes();
30
29
  await File.initPrettier();
31
30
  // loop through subtypes and return results of each subType for caching (saving is handled per subtype)
32
- for (const subType of subTypes) {
31
+ for (const subType of subTypeArr) {
33
32
  // each subtype contains multiple different specific types (images contains jpg and png for example)
34
33
  // we use await here to limit the risk of too many concurrent api requests at time
35
- items.push(
36
- ...(await this.requestSubType(
37
- subType,
38
- this.definition.extendedSubTypes[subType],
39
- retrieveDir,
40
- null,
41
- null,
42
- key
43
- ))
44
- );
34
+ items.push(...(await this.requestSubType(subType, retrieveDir, null, null, key)));
45
35
  }
46
36
  const metadata = this.parseResponseBody({ items: items });
47
37
  if (retrieveDir) {
48
38
  Util.logger.info(
49
- `Downloaded: ${this.definition.type} (${Object.keys(metadata).length})`
39
+ `Downloaded: ${this.definition.type} (${Object.keys(metadata).length})` +
40
+ Util.getKeysString(key)
50
41
  );
51
42
  }
52
43
  return { metadata: metadata, type: this.definition.type };
@@ -55,12 +46,12 @@ class Asset extends MetadataType {
55
46
  /**
56
47
  * Retrieves asset metadata for caching
57
48
  *
58
- * @param {void} _ -
59
- * @param {string} [selectedSubType] optionally limit to a single subtype
49
+ * @param {void} _ unused
50
+ * @param {string[]} [subTypeArr] optionally limit to a single subtype
60
51
  * @returns {Promise.<{metadata: TYPE.AssetMap, type: string}>} Promise
61
52
  */
62
- static retrieveForCache(_, selectedSubType) {
63
- return this.retrieve(null, null, null, selectedSubType);
53
+ static retrieveForCache(_, subTypeArr) {
54
+ return this.retrieve(null, null, subTypeArr);
64
55
  }
65
56
 
66
57
  /**
@@ -81,13 +72,7 @@ class Asset extends MetadataType {
81
72
  // each subtype contains multiple different specific types (images contains jpg and png for example)
82
73
  // we use await here to limit the risk of too many concurrent api requests at time
83
74
  items.push(
84
- ...(await this.requestSubType(
85
- subType,
86
- this.definition.extendedSubTypes[subType],
87
- templateDir,
88
- name,
89
- templateVariables
90
- ))
75
+ ...(await this.requestSubType(subType, templateDir, name, templateVariables))
91
76
  );
92
77
  }
93
78
  const metadata = this.parseResponseBody({ items: items });
@@ -146,27 +131,21 @@ class Asset extends MetadataType {
146
131
  * Retrieves Metadata of a specific asset type
147
132
  *
148
133
  * @param {TYPE.AssetSubType} subType group of similar assets to put in a folder (ie. images)
149
- * @param {TYPE.AssetSubType[]} subTypeArray list of all asset types within this subtype
150
134
  * @param {string} [retrieveDir] target directory for saving assets
151
135
  * @param {string} [templateName] name of the metadata file
152
136
  * @param {TYPE.TemplateMap} [templateVariables] variables to be replaced in the metadata
153
137
  * @param {string} key customer key to filter by
154
138
  * @returns {Promise} Promise
155
139
  */
156
- static async requestSubType(
157
- subType,
158
- subTypeArray,
159
- retrieveDir,
160
- templateName,
161
- templateVariables,
162
- key
163
- ) {
140
+ static async requestSubType(subType, retrieveDir, templateName, templateVariables, key) {
164
141
  if (retrieveDir) {
165
142
  Util.logger.info(`- Retrieving Subtype: ${subType}`);
166
143
  } else {
167
144
  Util.logger.info(` - Caching Subtype: ${subType}`);
168
145
  }
169
- const subtypeIds = subTypeArray?.map(
146
+ /** @type {TYPE.AssetSubType[]} */
147
+ const extendedSubTypeArr = this.definition.extendedSubTypes[subType];
148
+ const subtypeIds = extendedSubTypeArr?.map(
170
149
  (subTypeItemName) => Asset.definition.typeMapping[subTypeItemName]
171
150
  );
172
151
  const uri = '/asset/v1/content/assets/query';
@@ -507,10 +486,9 @@ class Asset extends MetadataType {
507
486
  *
508
487
  * @param {TYPE.AssetItem} metadata a single asset
509
488
  * @param {string} deployDir directory of deploy files
510
- * @param {TYPE.BuObject} buObject buObject properties for auth
511
489
  * @returns {Promise.<TYPE.AssetItem>} Promise
512
490
  */
513
- static async preDeployTasks(metadata, deployDir, buObject) {
491
+ static async preDeployTasks(metadata, deployDir) {
514
492
  // additonalattributes fail where the value is "" so we need to remove them from deploy
515
493
  if (metadata?.data?.email?.attributes?.length > 0) {
516
494
  metadata.data.email.attributes = metadata.data.email.attributes.filter(
@@ -519,10 +497,7 @@ class Asset extends MetadataType {
519
497
  }
520
498
 
521
499
  // folder
522
- metadata.category = {
523
- id: cache.searchForField('folder', metadata.r__folder_Path, 'Path', 'ID'),
524
- };
525
- delete metadata.r__folder_Path;
500
+ this.setFolderId(metadata);
526
501
 
527
502
  // restore asset type id which is needed for deploy
528
503
  metadata.assetType.id = this.definition.typeMapping[metadata.assetType.name];
@@ -538,13 +513,13 @@ class Asset extends MetadataType {
538
513
 
539
514
  // only execute #3 if we are deploying / copying from one BU to another, not while using mcdev as a developer tool
540
515
  if (
541
- buObject.mid &&
542
- metadata.memberId !== buObject.mid &&
543
- !metadata[this.definition.keyField].endsWith(buObject.mid)
516
+ this.buObject.mid &&
517
+ metadata.memberId !== this.buObject.mid &&
518
+ !metadata[this.definition.keyField].endsWith(this.buObject.mid)
544
519
  ) {
545
520
  // #3 make sure customer key is unique by suffixing it with target MID (unless we are deploying to the same MID)
546
521
  // check if this suffixed with the source MID
547
- const suffix = '-' + buObject.mid;
522
+ const suffix = '-' + this.buObject.mid;
548
523
  // for customer key max is 36 chars
549
524
  metadata[this.definition.keyField] =
550
525
  metadata[this.definition.keyField].slice(0, Math.max(0, 36 - suffix.length)) +
@@ -610,7 +585,7 @@ class Asset extends MetadataType {
610
585
  *
611
586
  * @private
612
587
  * @param {TYPE.AssetItem} metadata a single asset
613
- * @returns {TYPE.AssetSubType} subtype
588
+ * @returns {TYPE.AssetSubType | void} subtype
614
589
  */
615
590
  static _getSubtype(metadata) {
616
591
  for (const sub in this.definition.extendedSubTypes) {
@@ -790,6 +765,17 @@ class Asset extends MetadataType {
790
765
  );
791
766
  }
792
767
  }
768
+ /**
769
+ * Asset-specific script that retrieves the folder ID from cache and updates the given metadata with it before deploy
770
+ *
771
+ * @param {TYPE.MetadataTypeItem} metadata a single item
772
+ */
773
+ static setFolderId(metadata) {
774
+ metadata.category = {
775
+ id: cache.searchForField('folder', metadata.r__folder_Path, 'Path', 'ID'),
776
+ };
777
+ delete metadata.r__folder_Path;
778
+ }
793
779
 
794
780
  /**
795
781
  * helper for {@link preDeployTasks} that loads extracted code content back into JSON
@@ -970,6 +956,7 @@ class Asset extends MetadataType {
970
956
 
971
957
  break;
972
958
  }
959
+ case 'template': // template-template
973
960
  case 'buttonblock': // block - Button Block
974
961
  case 'freeformblock': // block
975
962
  case 'htmlblock': // block
@@ -1191,6 +1178,7 @@ class Asset extends MetadataType {
1191
1178
  subFolder: [customerKey],
1192
1179
  };
1193
1180
  }
1181
+ case 'template': // template-template
1194
1182
  case 'buttonblock': // block - Button Block
1195
1183
  case 'freeformblock': // block
1196
1184
  case 'htmlblock': // block
@@ -15,11 +15,10 @@ class AttributeGroup extends MetadataType {
15
15
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
16
16
  * @param {void} [_] unused parameter
17
17
  * @param {void} [__] unused parameter
18
- * @param {void} [___] unused parameter
19
18
  * @param {string} [key] customer key of single item to retrieve
20
19
  * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
21
20
  */
22
- static retrieve(retrieveDir, _, __, ___, key) {
21
+ static retrieve(retrieveDir, _, __, key) {
23
22
  return super.retrieveREST(
24
23
  retrieveDir,
25
24
  '/hub/v1/contacts/schema/attributeGroups',
@@ -19,11 +19,10 @@ class Automation extends MetadataType {
19
19
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
20
20
  * @param {void} [_] unused parameter
21
21
  * @param {void} [__] unused parameter
22
- * @param {void} [___] unused parameter
23
22
  * @param {string} [key] customer key of single item to retrieve
24
23
  * @returns {Promise.<TYPE.AutomationMapObj>} Promise of metadata
25
24
  */
26
- static async retrieve(retrieveDir, _, __, ___, key) {
25
+ static async retrieve(retrieveDir, _, __, key) {
27
26
  /** @type {TYPE.SoapRequestParams} */
28
27
  let requestParams = null;
29
28
  if (key) {
@@ -36,12 +35,39 @@ class Automation extends MetadataType {
36
35
  };
37
36
  }
38
37
  const results = await this.client.soap.retrieveBulk('Program', ['ObjectID'], requestParams);
39
-
38
+ if (results.Results?.length) {
39
+ // empty results will come back without "Results" defined
40
+ Util.logger.info(
41
+ Util.getGrayMsg(
42
+ ` - ${results.Results?.length} Automations found. Retrieving details...`
43
+ )
44
+ );
45
+ }
40
46
  const details = results.Results
41
47
  ? await Promise.all(
42
- results.Results.map((a) =>
43
- this.client.rest.get('/automation/v1/automations/' + a.ObjectID)
44
- )
48
+ results.Results.map(async (a) => {
49
+ try {
50
+ return await this.client.rest.get(
51
+ '/automation/v1/automations/' + a.ObjectID
52
+ );
53
+ } catch (ex) {
54
+ try {
55
+ if (ex.message == 'socket hang up') {
56
+ // one more retry; it's a rare case but retrying again should solve the issue gracefully
57
+ return await this.client.rest.get(
58
+ '/automation/v1/automations/' + a.ObjectID
59
+ );
60
+ }
61
+ } catch {
62
+ // no extra action needed, handled below
63
+ }
64
+ // if we do get here, we should log the error and continue instead of failing to download all automations
65
+ Util.logger.error(
66
+ ` ☇ skipping Automation ${a.ObjectID}: ${ex.message} ${ex.code}`
67
+ );
68
+ return null;
69
+ }
70
+ })
45
71
  )
46
72
  : [];
47
73
  const parsed = this.parseResponseBody({ items: details });
@@ -49,10 +75,11 @@ class Automation extends MetadataType {
49
75
  // * retrieveDir is mandatory in this method as it is not used for caching (there is a seperate method for that)
50
76
  const savedMetadata = await this.saveResults(parsed, retrieveDir, null, null);
51
77
  Util.logger.info(
52
- `Downloaded: ${this.definition.type} (${Object.keys(savedMetadata).length})`
78
+ `Downloaded: ${this.definition.type} (${Object.keys(savedMetadata).length})` +
79
+ Util.getKeysString(key)
53
80
  );
54
81
  if (this.properties.metaDataTypes.documentOnRetrieve.includes(this.definition.type)) {
55
- await this.document(this.buObject, savedMetadata);
82
+ await this.document(savedMetadata);
56
83
  }
57
84
  return { metadata: savedMetadata, type: this.definition.type };
58
85
  }
@@ -245,28 +272,9 @@ class Automation extends MetadataType {
245
272
  */
246
273
  static async preDeployTasks(metadata) {
247
274
  if (this.validateDeployMetadata(metadata)) {
248
- try {
249
- metadata.categoryId = cache.searchForField(
250
- 'folder',
251
- metadata.r__folder_Path,
252
- 'Path',
253
- 'ID'
254
- );
255
- if (metadata.r__folder_Path !== 'my automations') {
256
- Util.logger.warn(
257
- ` - Automation '${
258
- metadata[this.definition.nameField]
259
- }' is located in subfolder ${
260
- metadata.r__folder_Path
261
- }. Please note that creating automation folders is not supported via API and hence you will have to create it manually in the GUI if you choose to deploy this automation.`
262
- );
263
- }
264
- delete metadata.r__folder_Path;
265
- } catch {
266
- throw new Error(
267
- `Folder '${metadata.r__folder_Path}' was not found on the server. Please create this manually in the GUI. Automation-folders cannot be deployed automatically.`
268
- );
269
- }
275
+ // folder
276
+ this.setFolderId(metadata);
277
+
270
278
  if (metadata.type === 'scheduled' && metadata?.schedule?.startDate) {
271
279
  // Starting Source == 'Schedule'
272
280
 
@@ -493,13 +501,44 @@ class Automation extends MetadataType {
493
501
  }
494
502
  }
495
503
 
504
+ /**
505
+ * automation-specific script that retrieves the folder ID from cache and updates the given metadata with it before deploy
506
+ *
507
+ * @param {TYPE.MetadataTypeItem} metadata a single item
508
+ */
509
+ static setFolderId(metadata) {
510
+ try {
511
+ metadata.categoryId = cache.searchForField(
512
+ 'folder',
513
+ metadata.r__folder_Path,
514
+ 'Path',
515
+ 'ID'
516
+ );
517
+ if (metadata.r__folder_Path !== 'my automations') {
518
+ Util.logger.warn(
519
+ ` - Automation '${
520
+ metadata[this.definition.nameField]
521
+ }' is located in subfolder ${
522
+ metadata.r__folder_Path
523
+ }. Please note that creating automation folders is not supported via API and hence you will have to create it manually in the GUI if you choose to deploy this automation.`
524
+ );
525
+ }
526
+ delete metadata.r__folder_Path;
527
+ } catch {
528
+ throw new Error(
529
+ `Folder '${metadata.r__folder_Path}' was not found on the server. Please create this manually in the GUI. Automation-folders cannot be deployed automatically.`
530
+ );
531
+ }
532
+ }
533
+
496
534
  /**
497
535
  * parses retrieved Metadata before saving
498
536
  *
499
537
  * @param {TYPE.AutomationItem} metadata a single automation definition
500
- * @returns {TYPE.AutomationItem} parsed item
538
+ * @returns {TYPE.AutomationItem | void} parsed item
501
539
  */
502
540
  static parseMetadata(metadata) {
541
+ // folder
503
542
  this.setFolderPath(metadata);
504
543
  // automations are often skipped due to lack of support.
505
544
  try {
@@ -895,26 +934,25 @@ class Automation extends MetadataType {
895
934
  /**
896
935
  * Parses metadata into a readable Markdown/HTML format then saves it
897
936
  *
898
- * @param {TYPE.BuObject} buObject properties for auth
899
937
  * @param {TYPE.AutomationMap} [metadata] a list of dataExtension definitions
900
938
  * @returns {Promise.<void>} -
901
939
  */
902
- static async document(buObject, metadata) {
940
+ static async document(metadata) {
903
941
  if (['md', 'both'].includes(this.properties.options.documentType)) {
904
942
  if (!metadata) {
905
943
  metadata = this.readBUMetadataForType(
906
944
  File.normalizePath([
907
945
  this.properties.directories.retrieve,
908
- buObject.credential,
909
- buObject.businessUnit,
946
+ this.buObject.credential,
947
+ this.buObject.businessUnit,
910
948
  ]),
911
949
  true
912
950
  ).automation;
913
951
  }
914
952
  const docPath = File.normalizePath([
915
953
  this.properties.directories.retrieve,
916
- buObject.credential,
917
- buObject.businessUnit,
954
+ this.buObject.credential,
955
+ this.buObject.businessUnit,
918
956
  this.definition.type,
919
957
  ]);
920
958
  if (!metadata || !Object.keys(metadata).length) {
@@ -17,11 +17,10 @@ class Campaign extends MetadataType {
17
17
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
18
18
  * @param {void} [_] unused parameter
19
19
  * @param {void} [__] unused parameter
20
- * @param {void} [___] unused parameter
21
20
  * @param {string} [key] customer key of single item to retrieve
22
21
  * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
23
22
  */
24
- static async retrieve(retrieveDir, _, __, ___, key) {
23
+ static async retrieve(retrieveDir, _, __, key) {
25
24
  const res = await super.retrieveREST(retrieveDir, '/hub/v1/campaigns', null, null, key);
26
25
  // get assignments
27
26
 
@@ -30,7 +29,9 @@ class Campaign extends MetadataType {
30
29
  this.getAssetTags(retrieveDir, res.metadata[key].id, key)
31
30
  )
32
31
  );
33
- Util.logger.info(`Downloaded: campaignAssets (${campaignAssets.flat().length})`);
32
+ Util.logger.info(
33
+ `Downloaded: campaignAssets (${campaignAssets.flat().length})` + Util.getKeysString(key)
34
+ );
34
35
 
35
36
  return res;
36
37
  }
@@ -17,11 +17,10 @@ class ContentArea extends MetadataType {
17
17
  * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
18
18
  * @param {void} [_] unused parameter
19
19
  * @param {void} [__] unused parameter
20
- * @param {void} [___] unused parameter
21
20
  * @param {string} [key] customer key of single item to retrieve
22
21
  * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
23
22
  */
24
- static retrieve(retrieveDir, _, __, ___, key) {
23
+ static retrieve(retrieveDir, _, __, key) {
25
24
  Util.logger.warn(
26
25
  ' - Classic Content Areas are deprecated and will be discontinued by SFMC in the near future. Ensure that you migrate any existing Content Areas to Content Builder as soon as possible.'
27
26
  );
@@ -37,7 +36,7 @@ class ContentArea extends MetadataType {
37
36
  };
38
37
  }
39
38
  // !dont activate `await File.initPrettier('html');` as we only want to retrieve for migration and formatting might mess with the outcome
40
- return super.retrieveSOAP(retrieveDir, null, requestParams);
39
+ return super.retrieveSOAP(retrieveDir, requestParams);
41
40
  }
42
41
  /**
43
42
  * manages post retrieve steps