mcdev 7.6.3 → 7.7.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 (147) hide show
  1. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  2. package/.github/ISSUE_TEMPLATE/task.md +1 -1
  3. package/.github/workflows/coverage-base-update.yml +2 -2
  4. package/.github/workflows/coverage-develop-branch.yml +3 -1
  5. package/.github/workflows/coverage-main-branch.yml +3 -1
  6. package/.github/workflows/coverage.yml +5 -3
  7. package/.mcdev-validations.js +0 -0
  8. package/@types/lib/Builder.d.ts +14 -0
  9. package/@types/lib/Builder.d.ts.map +1 -1
  10. package/@types/lib/MetadataTypeDefinitions.d.ts +2 -0
  11. package/@types/lib/MetadataTypeDefinitions.d.ts.map +1 -1
  12. package/@types/lib/MetadataTypeInfo.d.ts +2 -0
  13. package/@types/lib/MetadataTypeInfo.d.ts.map +1 -1
  14. package/@types/lib/index.d.ts +17 -8
  15. package/@types/lib/index.d.ts.map +1 -1
  16. package/@types/lib/metadataTypes/Asset.d.ts +11 -3
  17. package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
  18. package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
  19. package/@types/lib/metadataTypes/DomainVerification.d.ts +180 -0
  20. package/@types/lib/metadataTypes/DomainVerification.d.ts.map +1 -0
  21. package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
  22. package/@types/lib/metadataTypes/Journey.d.ts +7 -4
  23. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
  24. package/@types/lib/metadataTypes/MetadataType.d.ts +15 -7
  25. package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
  26. package/@types/lib/metadataTypes/MobileKeyword.d.ts +2 -10
  27. package/@types/lib/metadataTypes/MobileKeyword.d.ts.map +1 -1
  28. package/@types/lib/metadataTypes/MobileMessage.d.ts +2 -10
  29. package/@types/lib/metadataTypes/MobileMessage.d.ts.map +1 -1
  30. package/@types/lib/metadataTypes/SendClassification.d.ts.map +1 -1
  31. package/@types/lib/metadataTypes/SenderProfile.d.ts +7 -0
  32. package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -1
  33. package/@types/lib/metadataTypes/TransactionalEmail.d.ts +2 -2
  34. package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
  35. package/@types/lib/metadataTypes/TriggeredSend.d.ts +8 -0
  36. package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -1
  37. package/@types/lib/metadataTypes/Verification.d.ts +0 -9
  38. package/@types/lib/metadataTypes/Verification.d.ts.map +1 -1
  39. package/@types/lib/metadataTypes/definitions/DomainVerification.definition.d.ts +100 -0
  40. package/@types/lib/metadataTypes/definitions/DomainVerification.definition.d.ts.map +1 -0
  41. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +1 -1
  42. package/@types/lib/util/devops.d.ts.map +1 -1
  43. package/@types/lib/util/replaceContentBlockReference.d.ts +2 -1
  44. package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -1
  45. package/@types/lib/util/util.d.ts +42 -1
  46. package/@types/lib/util/util.d.ts.map +1 -1
  47. package/@types/lib/util/validations.d.ts.map +1 -1
  48. package/@types/types/mcdev.d.d.ts +34 -0
  49. package/@types/types/mcdev.d.d.ts.map +1 -1
  50. package/boilerplate/config.json +11 -0
  51. package/boilerplate/files/eslint.config.js +98 -3
  52. package/boilerplate/forcedUpdates.json +4 -0
  53. package/boilerplate/gitignore-template +1 -1
  54. package/boilerplate/npm-dependencies.json +1 -0
  55. package/eslint.config.js +4 -3
  56. package/lib/Builder.js +114 -54
  57. package/lib/Deployer.js +2 -2
  58. package/lib/MetadataTypeDefinitions.js +2 -0
  59. package/lib/MetadataTypeInfo.js +2 -0
  60. package/lib/cli.js +127 -3
  61. package/lib/index.js +217 -164
  62. package/lib/metadataTypes/Asset.js +76 -22
  63. package/lib/metadataTypes/DataExtension.js +10 -2
  64. package/lib/metadataTypes/DomainVerification.js +246 -0
  65. package/lib/metadataTypes/Event.js +21 -9
  66. package/lib/metadataTypes/Journey.js +339 -223
  67. package/lib/metadataTypes/MetadataType.js +153 -106
  68. package/lib/metadataTypes/MobileKeyword.js +5 -2
  69. package/lib/metadataTypes/MobileMessage.js +5 -2
  70. package/lib/metadataTypes/SendClassification.js +5 -0
  71. package/lib/metadataTypes/SenderProfile.js +102 -3
  72. package/lib/metadataTypes/TransactionalEmail.js +3 -1
  73. package/lib/metadataTypes/Verification.js +3 -1
  74. package/lib/metadataTypes/definitions/DomainVerification.definition.js +71 -0
  75. package/lib/metadataTypes/definitions/Journey.definition.js +7 -1
  76. package/lib/metadataTypes/definitions/SendClassification.definition.js +2 -2
  77. package/lib/metadataTypes/definitions/SenderProfile.definition.js +1 -1
  78. package/lib/util/config.js +6 -0
  79. package/lib/util/devops.js +130 -154
  80. package/lib/util/file.js +3 -3
  81. package/lib/util/replaceContentBlockReference.js +10 -3
  82. package/lib/util/util.js +96 -14
  83. package/lib/util/validations.js +34 -14
  84. package/package.json +10 -10
  85. package/test/general.test.js +339 -96
  86. package/test/mockRoot/.mcdev-validations.js +66 -0
  87. package/test/mockRoot/.mcdevrc.json +30 -2
  88. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_htmlblock.asset-block-meta.html +1 -0
  89. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_htmlblock.asset-block-meta.json +39 -0
  90. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_notexisting.asset-block-meta.html +4 -0
  91. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_notexisting.asset-block-meta.json +39 -0
  92. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_preexisting.asset-block-meta.html +4 -0
  93. package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_preexisting.asset-block-meta.json +39 -0
  94. package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_assetMessage/testNew_assetMessage.asset-message-meta.json +435 -0
  95. package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_assetMessage/views.html.content.asset-message-meta.html +150 -0
  96. package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_asset_templatebasedemail/testNew_asset_templatebasedemail.asset-message-meta.json +305 -0
  97. package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_asset_templatebasedemail/views.html.content.asset-message-meta.html +150 -0
  98. package/test/mockRoot/deploy/testInstance/testBU/asset/template/testNew_asset_template/content.asset-template-meta.html +150 -0
  99. package/test/mockRoot/deploy/testInstance/testBU/asset/template/testNew_asset_template/testNew_asset_template.asset-template-meta.json +116 -0
  100. package/test/mockRoot/deploy/testInstance/testBU/domainVerification/joern.berkefeld.New@accenture.com.domainVerification-meta.json +6 -0
  101. package/test/mockRoot/deploy/testInstance/testBU/domainVerification/joern.berkefeld@accenture.com.domainVerification-meta.json +6 -0
  102. package/test/mockRoot/deploy/testInstance/testBU/domainVerification/mcdev.accenture.com.domainVerification-meta.json +6 -0
  103. package/test/mockRoot/deploy/testInstance/testBU/journey/testNew_temail_notPublished.journey-meta.json +213 -0
  104. package/test/mockRoot/deploy/testInstance/testBU/senderProfile/testExisting_senderProfile.senderProfile-meta.json +1 -0
  105. package/test/mockRoot/deploy/testInstance/testBU/senderProfile/testNew_senderProfile.senderProfile-meta.json +1 -0
  106. package/test/resourceFactory.js +7 -24
  107. package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_assetMessage.json +441 -0
  108. package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_htmlblock.json +59 -0
  109. package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_template.json +147 -0
  110. package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_templatebasedemail.json +322 -0
  111. package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_withCBBK_notexisting.json +59 -0
  112. package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_withCBBK_preexisting.json +59 -0
  113. package/test/resources/9999999/asset-deploy2/block/testBlacklist_asset_htmlblock.asset-block-meta.html +1 -0
  114. package/test/resources/9999999/asset-deploy2/block/testBlacklist_asset_htmlblock.asset-block-meta.json +39 -0
  115. package/test/resources/9999999/automation/clone-expected.json +61 -0
  116. package/test/resources/9999999/dataExtension/retrieve-CustomerKey=testExisting_dataExtension-response.xml +52 -0
  117. package/test/resources/9999999/dataExtension-deploy/testBlacklist_dataExtension.dataExtension-meta.json +20 -0
  118. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-shared,dataextension,hidden,salesforcedataextension,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml +137 -0
  119. package/test/resources/9999999/domainVerification/create-expected.json +3 -0
  120. package/test/resources/9999999/domainVerification/get-sap-expected.json +6 -0
  121. package/test/resources/9999999/domainVerification/update-expected.json +6 -0
  122. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_temail/put-response-paused.json +219 -0
  123. package/test/resources/9999999/interaction/v1/interactions/key_testNew_temail_notPublished/get-response.json +218 -0
  124. package/test/resources/9999999/interaction/v1/interactions/post-response.json +216 -0
  125. package/test/resources/9999999/journey/create-transactionaEmail-publish-expected.json +217 -0
  126. package/test/resources/9999999/messaging/v1/domainverification/delete/post-response.txt +1 -0
  127. package/test/resources/9999999/messaging/v1/domainverification/get-response.json +43 -0
  128. package/test/resources/9999999/messaging/v1/domainverification/post-response.txt +1 -0
  129. package/test/resources/9999999/messaging/v1/domainverification/update/post-response.txt +1 -0
  130. package/test/resources/9999999/messaging/v1/email/definitions/get-response.json +7 -0
  131. package/test/resources/9999999/messaging/v1/email/definitions/testNew_temail_notPublished/get-response.json +26 -0
  132. package/test/resources/9999999/query/clone-expected.json +8 -0
  133. package/test/resources/9999999/query/clone-expected.sql +7 -0
  134. package/test/resources/9999999/senderProfile/create-response.xml +1 -1
  135. package/test/resources/9999999/senderProfile/post-expected.json +1 -1
  136. package/test/resources/9999999/transactionalEmail/create-publish-expected.json +20 -0
  137. package/test/type.asset.test.js +216 -9
  138. package/test/type.automation.test.js +1 -1
  139. package/test/type.domainVerification.test.js +169 -0
  140. package/test/type.journey.test.js +107 -21
  141. package/test/type.script.test.js +1 -1
  142. package/test/type.sendClassification.test.js +3 -3
  143. package/test/type.senderProfile.test.js +26 -6
  144. package/test/type.transactionalEmail.test.js +5 -5
  145. package/test/type.triggeredSend.test.js +1 -1
  146. package/test/utils.js +8 -0
  147. package/types/mcdev.d.js +12 -0
@@ -188,13 +188,13 @@ class Asset extends MetadataType {
188
188
  }
189
189
 
190
190
  /**
191
- * Returns Order in which metadata needs to be retrieved/deployed
191
+ * Returns Order in which metadata needs to be retrieved/deployed and skips components with missing components
192
192
  *
193
- * @param {AssetMap} metadataMap metadata mapped by their keyField
193
+ * @param {AssetMap} metadataMap metadata thats about to be deployed
194
194
  * @param {string} deployDir directory where deploy metadata are saved
195
195
  * @returns {Promise.<AssetMap>} keyField => metadata map but sorted to ensure dependencies are deployed in correct order
196
196
  */
197
- static async _getUpsertOrder(metadataMap, deployDir) {
197
+ static async _getUpsertOrderAndSkipMissing(metadataMap, deployDir) {
198
198
  /**
199
199
  * one entry for each dependency with the first item being the key thats required by the second item
200
200
  *
@@ -207,29 +207,44 @@ class Asset extends MetadataType {
207
207
  Util.OPTIONS.referenceTo = 'key';
208
208
  // loop through all metadata types which are being retrieved/deployed
209
209
  for (const key in metadataMap) {
210
+ const errors = [];
210
211
  const findAssetKeys = new Set();
212
+ // find asset references in metadata
213
+ const findAssetKeyMeta = Util.findLeafVals(metadataMap[key], 'r__asset_key');
214
+ for (const metaKey of findAssetKeyMeta) {
215
+ if (metadataMap[key] || cache.getByKey(this.definition.type, metaKey)) {
216
+ findAssetKeys.add(metaKey);
217
+ } else {
218
+ errors.push(
219
+ `content block ${metaKey} that is referenced via r__asset_key was not found on BU nor in deployment package`
220
+ );
221
+ }
222
+ }
211
223
  try {
212
224
  // find asset references in code
213
225
  await this.replaceCbReference(metadataMap[key], deployDir, findAssetKeys);
214
- // find asset references in metadata
215
- const findAssetKeyMeta = Util.findLeafVals(metadataMap[key], 'r__asset_key');
216
- for (const metaKey of findAssetKeyMeta) {
217
- findAssetKeys.add(metaKey);
226
+ } catch (ex) {
227
+ if (ex.code === 200) {
228
+ // no dependent keys found
229
+ // good from this perspective
230
+ } else {
231
+ errors.push(
232
+ `content block ${ex.message} that is referenced via ContentBlockByX was not found on BU nor in deployment package`
233
+ );
218
234
  }
219
-
235
+ }
236
+ if (errors.length) {
237
+ Util.logger.error(
238
+ ` ☇ skipping ${this.definition.type} ${key}:${errors.length > 1 ? '\n ·' : ''} ${errors.join('\n · ')}`
239
+ );
240
+ } else {
220
241
  const dependentKeys = [...findAssetKeys];
221
242
  if (dependentKeys.length > 0) {
222
243
  dependencies.push(...dependentKeys.map((depKey) => [depKey, key]));
223
244
  } else {
224
- Util.logger.debug('Asset._getUpsertOrder: this case should not happen');
245
+ Util.logger.debug('Asset._getUpsertOrder: no dependent keys found for ' + key);
225
246
  dependencies.push([undefined, key]);
226
247
  }
227
- } catch (ex) {
228
- if (ex.code !== 200) {
229
- Util.logger.errorStack(ex, 'Cannot find related code blocks for ' + key);
230
- }
231
- // no dependent keys found
232
- dependencies.push([undefined, key]);
233
248
  }
234
249
  }
235
250
 
@@ -240,7 +255,9 @@ class Asset extends MetadataType {
240
255
  const metadataTypeMapSorted = {};
241
256
  // group subtypes per type
242
257
  for (const key of flatList) {
243
- metadataTypeMapSorted[key] = metadataMap[key];
258
+ if (metadataMap[key]) {
259
+ metadataTypeMapSorted[key] = metadataMap[key];
260
+ }
244
261
  }
245
262
  return metadataTypeMapSorted;
246
263
  }
@@ -253,12 +270,13 @@ class Asset extends MetadataType {
253
270
  * @returns {Promise.<AssetMap>} keyField => metadata map
254
271
  */
255
272
  static async upsert(metadataMap, deployDir) {
256
- if (Object.keys(metadataMap).length > 1) {
257
- // fill the cache map with our deployment package to ensure we can find
258
- ReplaceCbReference.createCacheForMap(metadataMap);
259
- // assets can link to other assets (via template, content block reference and SSJS/AMPscript) and deployment would fail if we did not sort this here
260
- metadataMap = await this._getUpsertOrder(metadataMap, deployDir);
261
- }
273
+ // add already existing, cached items to our cache map to ensure we can find them
274
+ ReplaceCbReference.createCacheForMap(cache.getCache().asset);
275
+ // await ReplaceCbReference.createCache(this.properties, this.buObject, true);
276
+ // fill the cache map with our deployment package to ensure we can find
277
+ ReplaceCbReference.createCacheForMap(metadataMap);
278
+ // assets can link to other assets (via template, content block reference and SSJS/AMPscript) and deployment would fail if we did not sort this here
279
+ metadataMap = await this._getUpsertOrderAndSkipMissing(metadataMap, deployDir);
262
280
  return super.upsert(metadataMap, deployDir, true);
263
281
  }
264
282
 
@@ -274,6 +292,32 @@ class Asset extends MetadataType {
274
292
  return super.createREST(metadata, uri);
275
293
  }
276
294
 
295
+ /**
296
+ * helper for {@link MetadataType.createREST}
297
+ *
298
+ * @param {MetadataTypeItem} metadataEntry a single metadata Entry
299
+ * @param {object} apiResponse varies depending on the API call
300
+ * @returns {Promise.<object>} apiResponse, potentially modified
301
+ */
302
+ static async postCreateTasks(metadataEntry, apiResponse) {
303
+ if (apiResponse[this.definition.idField]) {
304
+ // this also happens inside of MetadataType.upsert but we need it for createCacheMap()
305
+ // ensure we have the ID in the cache
306
+ metadataEntry[this.definition.idField] = apiResponse[this.definition.idField];
307
+ }
308
+ if (apiResponse.objectID) {
309
+ // ensure we have the asset objectId in the cache
310
+ metadataEntry.objectID = apiResponse.objectID;
311
+ }
312
+
313
+ // make this newly created item available in cache for other itmes that might reference it
314
+ /** @type {MetadataTypeMap} */
315
+ const newObject = {};
316
+ newObject[metadataEntry[this.definition.keyField]] = metadataEntry;
317
+ ReplaceCbReference.createCacheForMap(newObject);
318
+ return apiResponse;
319
+ }
320
+
277
321
  /**
278
322
  * Updates a single asset
279
323
  *
@@ -799,6 +843,16 @@ class Asset extends MetadataType {
799
843
  // folder
800
844
  this.setFolderId(metadata);
801
845
 
846
+ if (
847
+ metadata.assetType.name === 'webpage' &&
848
+ !cache.getByKey(this.definition.type, metadata[this.definition.keyField])
849
+ ) {
850
+ // we are attempting to CREATE a cloudpage asset which needs to be prevented.
851
+ throw new Error(
852
+ 'CloudPages cannot be created via mcdev. Please create it via the UI first, then change its key to the value required by you, and finally, re-run this deployment.'
853
+ );
854
+ }
855
+
802
856
  // template-based emails
803
857
  if (
804
858
  metadata.assetType.name === 'templatebasedemail' &&
@@ -53,7 +53,15 @@ class DataExtension extends MetadataType {
53
53
  let filteredByPreDeploy = 0;
54
54
  for (const metadataKey in metadataMap) {
55
55
  try {
56
- await this.validation('deploy', metadataMap[metadataKey], deployDir);
56
+ metadataMap[metadataKey] = await this.validation(
57
+ 'deploy',
58
+ metadataMap[metadataKey],
59
+ deployDir
60
+ );
61
+ if (!metadataMap[metadataKey]) {
62
+ filteredByPreDeploy++;
63
+ continue;
64
+ }
57
65
  metadataMap[metadataKey] = await this.preDeployTasks(metadataMap[metadataKey]);
58
66
 
59
67
  await this.createOrUpdate(
@@ -394,7 +402,7 @@ class DataExtension extends MetadataType {
394
402
  }
395
403
 
396
404
  // find all shared data extensions
397
- if (!this.deployedSharedKeys.length) {
405
+ if (!this.deployedSharedKeys?.length) {
398
406
  Util.logger.debug(
399
407
  `Skipping fixShared logic because no Shared Data Extensions were updated`
400
408
  );
@@ -0,0 +1,246 @@
1
+ 'use strict';
2
+
3
+ import MetadataType from './MetadataType.js';
4
+ import { Util } from '../util/util.js';
5
+ import cache from '../util/cache.js';
6
+
7
+ /**
8
+ * @typedef {import('../../types/mcdev.d.js').BuObject} BuObject
9
+ * @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract
10
+ * @typedef {import('../../types/mcdev.d.js').CodeExtractItem} CodeExtractItem
11
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeItem} MetadataTypeItem
12
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemDiff} MetadataTypeItemDiff
13
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemObj} MetadataTypeItemObj
14
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap
15
+ * @typedef {import('../../types/mcdev.d.js').MetadataTypeMapObj} MetadataTypeMapObj
16
+ * @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams
17
+ * @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap
18
+ * @typedef {import('../../types/mcdev.d.js').DomainVerificationItem} DomainVerificationItem
19
+ */
20
+
21
+ /**
22
+ * DomainVerification MetadataType
23
+ *
24
+ * @augments MetadataType
25
+ */
26
+ class DomainVerification extends MetadataType {
27
+ /**
28
+ * Retrieves Metadata ofDomainVerification.
29
+ * Endpoint /automation/v1/dataextracts/ returns all items
30
+ *
31
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
32
+ * @param {void | string[]} [_] unused parameter
33
+ * @param {void | string[]} [__] unused parameter
34
+ * @param {string} [key] customer key of single item to retrieve
35
+ * @returns {Promise.<MetadataTypeMapObj>} Promise of metadata
36
+ */
37
+ static async retrieve(retrieveDir, _, __, key) {
38
+ return super.retrieveREST(retrieveDir, '/messaging/v1/domainverification/', null, key);
39
+ }
40
+
41
+ /**
42
+ * Retrieves Metadata of DomainVerification for caching
43
+ *
44
+ * @returns {Promise.<MetadataTypeMapObj>} Promise of metadata
45
+ */
46
+ static async retrieveForCache() {
47
+ return super.retrieveREST(null, '/messaging/v1/domainverification/');
48
+ }
49
+
50
+ /**
51
+ * Creates a single item
52
+ *
53
+ * @param {DomainVerificationItem} metadataItem a single item
54
+ * @returns {Promise} Promise
55
+ */
56
+ static create(metadataItem) {
57
+ return super.createREST(metadataItem, '/messaging/v1/domainverification/');
58
+ }
59
+
60
+ /**
61
+ * helper for {@link MetadataType.createREST}
62
+ *
63
+ * @param {DomainVerificationItem} metadataEntry a single metadata Entry
64
+ * @param {object} apiResponse varies depending on the API call
65
+ * @returns {Promise.<DomainVerificationItem>} apiResponse
66
+ */
67
+ static async postCreateTasks(metadataEntry, apiResponse) {
68
+ if (apiResponse && apiResponse === `${metadataEntry.domain} successfully added.`) {
69
+ return metadataEntry;
70
+ } else {
71
+ throw new Error(apiResponse);
72
+ }
73
+ }
74
+
75
+ /**
76
+ * helper for {@link update}
77
+ *
78
+ * @param {DomainVerificationItem} metadataEntry a single metadata Entry
79
+ * @param {object} apiResponse varies depending on the API call
80
+ * @returns {Promise.<DomainVerificationItem>} apiResponse, potentially modified
81
+ */
82
+ static async postUpdateTasks(metadataEntry, apiResponse) {
83
+ if (apiResponse && apiResponse === `1 records successfully updated!`) {
84
+ metadataEntry.domain = metadataEntry.emailAddress;
85
+ return metadataEntry;
86
+ } else {
87
+ throw new Error(apiResponse);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Updates a single item; replaces super.updateREST because we need to send metadataItem as an array for some reason and also get an array back
93
+ *
94
+ * @param {DomainVerificationItem} metadataItem a single item
95
+ * @returns {Promise.<DomainVerificationItem>} Promise
96
+ */
97
+ static async update(metadataItem) {
98
+ const uri = '/messaging/v1/domainverification/update';
99
+
100
+ this.removeNotUpdateableFields(metadataItem);
101
+ try {
102
+ // set to empty object in case API returned nothing to be able to update it in helper classes
103
+ let response = (await this.client.rest.post(uri, [metadataItem])) || {};
104
+ this.getErrorsREST(response);
105
+ response = await this.postUpdateTasks(metadataItem, response);
106
+ // some times, e.g. automation dont return a key in their update response and hence we need to fall back to name
107
+ Util.logger.info(` - updated ${Util.getTypeKeyName(this.definition, metadataItem)}`);
108
+ return metadataItem;
109
+ } catch (ex) {
110
+ const parsedErrors = this.getErrorsREST(ex);
111
+ Util.logger.error(
112
+ ` ☇ error updating ${Util.getTypeKeyName(this.definition, metadataItem)}:`
113
+ );
114
+ for (const msg of parsedErrors) {
115
+ Util.logger.error(' • ' + msg);
116
+ }
117
+ return null;
118
+ }
119
+ }
120
+ /**
121
+ * manages post retrieve steps
122
+ *
123
+ * @param {DomainVerificationItem} metadataItem a single item
124
+ * @returns {DomainVerificationItem} metadata
125
+ */
126
+ static postRetrieveTasks(metadataItem) {
127
+ if (metadataItem.status !== 'Verified') {
128
+ Util.logger.warn(
129
+ Util.getMsgPrefix(this.definition, metadataItem) +
130
+ ` is not verified. Current status: ${metadataItem.status}`
131
+ );
132
+ }
133
+ if (!metadataItem.isSendable) {
134
+ Util.logger.warn(
135
+ Util.getMsgPrefix(this.definition, metadataItem) + ` is not sendable.`
136
+ );
137
+ }
138
+ return metadataItem;
139
+ }
140
+
141
+ /**
142
+ * Gets executed after deployment of metadata type
143
+ *
144
+ * @param {MetadataTypeMap} upsertResults metadata mapped by their keyField as returned by update/create
145
+ * @returns {Promise.<void>} -
146
+ */
147
+ static async postDeployTasks(upsertResults) {
148
+ // re-retrieve all upserted items to ensure we have all fields (createdDate and modifiedDate are otherwise not present)
149
+ Util.logger.debug(
150
+ `Caching all ${this.definition.type} post-deploy to ensure we have all fields`
151
+ );
152
+ const typeCache = await this.retrieveForCache();
153
+ // update values in upsertResults with retrieved values before saving to disk
154
+ for (const key of Object.keys(upsertResults)) {
155
+ if (typeCache.metadata[key]) {
156
+ upsertResults[key] = typeCache.metadata[key];
157
+ }
158
+ }
159
+ }
160
+
161
+ /**
162
+ * prepares a single item for deployment
163
+ *
164
+ * @param {DomainVerificationItem} metadata a single item
165
+ * @returns {Promise.<DomainVerificationItem>} Promise
166
+ */
167
+ static async preDeployTasks(metadata) {
168
+ if (metadata.domainType && metadata.domainType !== 'UserDomain') {
169
+ throw new Error(
170
+ `Can only delete entries of type 'UserDomain'. Found: ${metadata.domainType}`
171
+ );
172
+ }
173
+ // prep for update which uses emailAddress instead of domain
174
+ metadata.emailAddress = metadata.domain;
175
+
176
+ return metadata;
177
+ }
178
+
179
+ /**
180
+ * Gets executed before deleting a list of keys for the current type
181
+ *
182
+ * @returns {Promise.<void>} -
183
+ */
184
+ static async preDeleteTasks() {
185
+ if (!cache.getCache()) {
186
+ cache.initCache(this.buObject);
187
+ }
188
+ if (!cache.getCache()?.[this.definition.type]) {
189
+ const cached = await this.retrieveForCache();
190
+ if (cached) {
191
+ cache.setMetadata(this.definition.type, cached?.metadata);
192
+ }
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Delete a metadata item from the specified business unit
198
+ *
199
+ * @param {string} key Identifier of data extension
200
+ * @returns {Promise.<boolean>} deletion success flag
201
+ */
202
+ static async deleteByKey(key) {
203
+ const metadataItem = cache.getByKey(this.definition.type, key);
204
+ if (!metadataItem) {
205
+ Util.logger.error(` - ${this.definition.type} ${key} not found`);
206
+ return false;
207
+ }
208
+ if (metadataItem.domainType !== 'UserDomain') {
209
+ Util.logger.error(
210
+ ` - ${this.definition.type} ${key}: Can only delete entries of type UserDomain. Found: ${metadataItem.domainType}`
211
+ );
212
+ return false;
213
+ }
214
+ try {
215
+ const response = await this.client.rest.post(
216
+ '/messaging/v1/domainverification/delete',
217
+ [
218
+ {
219
+ emailAddress: metadataItem.domain,
220
+ domainType: metadataItem.domainType,
221
+ },
222
+ ]
223
+ );
224
+ if (response === '1 records successfully updated!') {
225
+ Util.logger.info(` - deleted ${this.definition.type}: ${key}`);
226
+ this.postDeleteTasks(key);
227
+ return true;
228
+ } else {
229
+ Util.logger.error(
230
+ ` - Deleting ${this.definition.type} '${key}' failed: ` + response
231
+ );
232
+ return false;
233
+ }
234
+ } catch (ex) {
235
+ Util.logger.errorStack(ex, ` - Deleting ${this.definition.type} '${key}' failed`);
236
+
237
+ return false;
238
+ }
239
+ }
240
+ }
241
+
242
+ // Assign definition to static attributes
243
+ import MetadataTypeDefinitions from '../MetadataTypeDefinitions.js';
244
+ DomainVerification.definition = MetadataTypeDefinitions.domainVerification;
245
+
246
+ export default DomainVerification;
@@ -46,7 +46,6 @@ class Event extends MetadataType {
46
46
  * @returns {Promise.<MetadataTypeMapObj>} Promise of metadata
47
47
  */
48
48
  static async retrieve(retrieveDir, _, __, key) {
49
- Util.logBeta(this.definition.type);
50
49
  try {
51
50
  return await super.retrieveREST(
52
51
  retrieveDir,
@@ -87,7 +86,6 @@ class Event extends MetadataType {
87
86
  * @returns {Promise.<MetadataTypeItemObj>} Promise of metadata
88
87
  */
89
88
  static async retrieveAsTemplate(templateDir, name, templateVariables) {
90
- Util.logBeta(this.definition.type);
91
89
  const res = await this.client.rest.get(
92
90
  '/interaction/v1/eventDefinitions?name=' + encodeURIComponent(name)
93
91
  );
@@ -141,13 +139,27 @@ class Event extends MetadataType {
141
139
  * @param {string} key Identifier of item
142
140
  * @returns {Promise.<boolean>} deletion success status
143
141
  */
144
- static deleteByKey(key) {
145
- Util.logBeta(this.definition.type);
146
- return super.deleteByKeyREST(
147
- '/interaction/v1/eventDefinitions/key:' + encodeURIComponent(key),
148
- key,
149
- false
150
- );
142
+ static async deleteByKey(key) {
143
+ let response = false;
144
+ try {
145
+ response = await super.deleteByKeyREST(
146
+ '/interaction/v1/eventDefinitions/key:' + encodeURIComponent(key),
147
+ key,
148
+ true
149
+ );
150
+ Util.logger.info(` - deleted ${this.definition.type}: ${key}`);
151
+ } catch (ex) {
152
+ if (ex.code === 30000) {
153
+ Util.logger.warn(
154
+ ` ☇ skipping deletion of ${this.definition.type} ${key}: not found on server`
155
+ );
156
+ } else {
157
+ Util.logger.errorStack(ex, ` - Deleting ${this.definition.type} '${key}' failed`);
158
+ }
159
+
160
+ return false;
161
+ }
162
+ return response;
151
163
  }
152
164
 
153
165
  /**