mcdev 4.3.0 → 4.3.2

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 (29) hide show
  1. package/.fork/custom-commands.json +14 -0
  2. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  3. package/boilerplate/gitignore-template +1 -0
  4. package/docs/dist/documentation.md +2 -40
  5. package/lib/Retriever.js +22 -19
  6. package/lib/metadataTypes/AccountUser.js +42 -13
  7. package/lib/metadataTypes/Asset.js +37 -42
  8. package/lib/metadataTypes/Automation.js +1 -1
  9. package/lib/metadataTypes/DataExtensionField.js +5 -3
  10. package/lib/metadataTypes/EmailSendDefinition.js +84 -44
  11. package/lib/metadataTypes/Interaction.js +74 -9
  12. package/lib/metadataTypes/List.js +17 -15
  13. package/lib/metadataTypes/MetadataType.js +1 -1
  14. package/lib/metadataTypes/TriggeredSendDefinition.js +6 -5
  15. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +52 -31
  16. package/lib/metadataTypes/definitions/Interaction.definition.js +1 -1
  17. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +2 -2
  18. package/lib/metadataTypes/definitions/TransactionalPush.definition.js +2 -2
  19. package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +2 -2
  20. package/lib/util/auth.js +8 -3
  21. package/lib/util/devops.js +8 -4
  22. package/lib/util/util.js +51 -9
  23. package/package.json +2 -1
  24. package/test/interaction.test.js +2 -2
  25. package/test/mockRoot/.mcdevrc.json +1 -1
  26. package/test/resourceFactory.js +20 -9
  27. package/test/resources/9999999/interaction/v1/interactions/key_0b76dccf-594c-b6dc-1acf-10c4493dcb84/get-response.json +219 -0
  28. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +280 -0
  29. package/test/resources/9999999/triggeredSendDefinition/retrieve-response.xml +68 -0
@@ -41,8 +41,8 @@ module.exports = {
41
41
  template: false,
42
42
  },
43
43
  definitionId: {
44
- isCreateable: true,
45
- isUpdateable: true,
44
+ isCreateable: false,
45
+ isUpdateable: false,
46
46
  retrieving: false,
47
47
  template: false,
48
48
  },
package/lib/util/auth.js CHANGED
@@ -101,7 +101,7 @@ function setupSDK(sessionKey, authObject) {
101
101
  credentialStore.set(sessionKey, authObject);
102
102
  },
103
103
  onConnectionError: (ex, remainingAttempts) => {
104
- Util.logger.warn(
104
+ Util.logger.info(
105
105
  ` - Connection problem (Code: ${ex.code}). Retrying ${remainingAttempts} time${
106
106
  remainingAttempts > 1 ? 's' : ''
107
107
  }${
@@ -114,8 +114,13 @@ function setupSDK(sessionKey, authObject) {
114
114
  );
115
115
  Util.logger.errorStack(ex);
116
116
  },
117
- // logRequest: (req) => console.log('request', req), // uncomment to log requests
118
- // logResponse: (res) => console.log('response:', res), // uncomment to log responses
117
+ // logRequest: (req) =>
118
+ // console.log(`${Util.color.fgMagenta}request${Util.color.reset}`, req), // uncomment to log requests
119
+ // logResponse: (res) =>
120
+ // console.log(
121
+ // `${Util.color.bgMagenta}response${Util.color.reset}:`,
122
+ // typeof res.data == 'string' && res.data.length > 10000 ? res.data : res
123
+ // ), // uncomment to log responses
119
124
  },
120
125
  requestAttempts: 4,
121
126
  retryOnConnectionError: true,
@@ -111,6 +111,8 @@ const DevOps = {
111
111
  // Filter to only handle files that start with at least one of the passed filterPaths.
112
112
  // ! Filter happens after initial parse, because if file was moved its new path has to be calculated
113
113
  .filter((file) => filterPaths.some((path) => file.file.startsWith(path)))
114
+ .filter((file) => !file.file.endsWith('.error.log'))
115
+ .filter((file) => !file.file.endsWith('.md'))
114
116
  // ensure badly named files on unsupported metadata types are not in our subset
115
117
  .filter((/** @type {TYPE.DeltaPkgItem} */ file) => {
116
118
  if (MetadataType[file.type]) {
@@ -210,10 +212,12 @@ const DevOps = {
210
212
  const copied = delta.map((file) =>
211
213
  File.copyFile(
212
214
  file.file,
213
- file.file.replace(
214
- path.normalize(properties.directories.retrieve),
215
- path.normalize(properties.directories.deploy)
216
- )
215
+ path
216
+ .normalize(file.file)
217
+ .replace(
218
+ path.normalize(properties.directories.retrieve),
219
+ path.normalize(properties.directories.deploy)
220
+ )
217
221
  )
218
222
  );
219
223
  const results = await Promise.all(copied);
package/lib/util/util.js CHANGED
@@ -364,21 +364,38 @@ const Util = {
364
364
  // group subtypes per type
365
365
  for (const type of flatList) {
366
366
  if (type.includes('-')) {
367
- const key = type.split('-')[0];
368
- if (finalList[key]) {
367
+ const [key, subKey] = Util.getTypeAndSubType(type);
368
+ if (finalList[key] === null) {
369
+ // if main type is already required, then don't filter by subtypes
369
370
  continue;
371
+ } else if (finalList[key] && subKey) {
372
+ // add another subtype to the set
373
+ finalList[key].add(subKey);
374
+ continue;
375
+ } else {
376
+ // create a new set with the first subtype; subKey will be always set here
377
+ finalList[key] = new Set([subKey]);
378
+ }
379
+ if (subTypeDeps[key]) {
380
+ // check if there are depndent subtypes that need to be added
381
+ const temp = [...subTypeDeps[key]].map((a) => {
382
+ const temp = a.split('-');
383
+ temp.shift(); // remove first item which is the main type
384
+ return temp.join('-'); // subType can include "-"
385
+ });
386
+ finalList[key].add(...temp);
370
387
  }
371
- finalList[key] = subTypeDeps[key]
372
- ? [...subTypeDeps[key]].map((a) => {
373
- const temp = a.split('-');
374
- temp.shift(); // remove first item which is the main type
375
- return temp.join('-'); // subType can include "-"
376
- })
377
- : null;
378
388
  } else {
379
389
  finalList[type] = null;
380
390
  }
381
391
  }
392
+ // convert sets into arrays
393
+ for (const type of Object.keys(finalList)) {
394
+ if (finalList[type] instanceof Set) {
395
+ finalList[type] = [...finalList[type]];
396
+ }
397
+ }
398
+
382
399
  return finalList;
383
400
  },
384
401
 
@@ -487,6 +504,31 @@ const Util = {
487
504
  color: {
488
505
  reset: '\x1B[0m',
489
506
  dim: '\x1B[2m',
507
+ bright: '\x1B[1m',
508
+ underscore: '\x1B[4m',
509
+ blink: '\x1B[5m',
510
+ reverse: '\x1B[7m',
511
+ hidden: '\x1B[8m',
512
+
513
+ fgBlack: '\x1B[30m',
514
+ fgRed: '\x1B[31m',
515
+ fgGreen: '\x1B[32m',
516
+ fgYellow: '\x1B[33m',
517
+ fgBlue: '\x1B[34m',
518
+ fgMagenta: '\x1B[35m',
519
+ fgCyan: '\x1B[36m',
520
+ fgWhite: '\x1B[37m',
521
+ fgGray: '\x1B[90m',
522
+
523
+ bgBlack: '\x1B[40m',
524
+ bgRed: '\x1B[41m',
525
+ bgGreen: '\x1B[42m',
526
+ bgYellow: '\x1B[43m',
527
+ bgBlue: '\x1B[44m',
528
+ bgMagenta: '\x1B[45m',
529
+ bgCyan: '\x1B[46m',
530
+ bgWhite: '\x1B[47m',
531
+ bgGray: '\x1B[100m',
490
532
  },
491
533
  /**
492
534
  * helper that wraps a message in the correct color codes to have them printed gray
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcdev",
3
- "version": "4.3.0",
3
+ "version": "4.3.2",
4
4
  "description": "Accenture Salesforce Marketing Cloud DevTools",
5
5
  "author": "Accenture: joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
6
6
  "license": "MIT",
@@ -50,6 +50,7 @@
50
50
  "lint-test": "eslint test/**/*.js",
51
51
  "upgrade": "npm-check --update",
52
52
  "manual-prepare": "husky install",
53
+ "lint-and-test": "run-s lint test",
53
54
  "test": "mocha",
54
55
  "coverage": "nyc mocha",
55
56
  "version:major": "npm version --no-commit-hooks major",
@@ -33,7 +33,7 @@ describe('interaction', () => {
33
33
  );
34
34
  assert.equal(
35
35
  testUtils.getAPIHistoryLength(),
36
- 7,
36
+ 9,
37
37
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
38
38
  );
39
39
  return;
@@ -114,7 +114,7 @@ describe('interaction', () => {
114
114
 
115
115
  assert.equal(
116
116
  testUtils.getAPIHistoryLength(),
117
- 7,
117
+ 9,
118
118
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
119
119
  );
120
120
  return;
@@ -74,5 +74,5 @@
74
74
  "triggeredSendDefinition"
75
75
  ]
76
76
  },
77
- "version": "4.3.0"
77
+ "version": "4.3.2"
78
78
  }
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('node:path');
3
3
  const { XMLParser } = require('fast-xml-parser');
4
+ const { color } = require('../lib/util/util');
4
5
  const parser = new XMLParser();
5
6
  const attributeParser = new XMLParser({ ignoreAttributes: false });
6
7
  /**
@@ -25,7 +26,11 @@ exports.loadSOAPRecords = async (mcdevAction, type, mid) => {
25
26
  encoding: 'utf8',
26
27
  });
27
28
  }
28
- console.log(`error: Please create file ${testPath}`); // eslint-disable-line no-console
29
+ /* eslint-disable no-console */
30
+ console.log(
31
+ `${color.bgRed}${color.fgBlack}test-error${color.reset}: Please create file ${testPath}`
32
+ );
33
+ /* eslint-enable no-console */
29
34
 
30
35
  return fs.readFile(path.join('test', 'resources', mcdevAction + '-response.xml'), {
31
36
  encoding: 'utf8',
@@ -98,13 +103,15 @@ exports.handleRESTRequest = async (config) => {
98
103
  if (urlObj.searchParams.get('$filter')) {
99
104
  filterName = urlObj.searchParams.get('$filter').split(' eq ')[1];
100
105
  }
101
- const testPath = path.join(
102
- 'test',
103
- 'resources',
104
- config.headers.Authorization.replace('Bearer ', ''),
105
- urlObj.pathname,
106
- config.method + '-response.json'
107
- );
106
+ const testPath = path
107
+ .join(
108
+ 'test',
109
+ 'resources',
110
+ config.headers.Authorization.replace('Bearer ', ''),
111
+ urlObj.pathname,
112
+ config.method + '-response.json'
113
+ )
114
+ .replace(':', '_'); // replace : with _ for Windows
108
115
 
109
116
  if (await fs.pathExists(testPath)) {
110
117
  // build filter logic to ensure templating works
@@ -126,7 +133,11 @@ exports.handleRESTRequest = async (config) => {
126
133
  ];
127
134
  }
128
135
  } else {
129
- console.log(`error: Please create file ${testPath}`); // eslint-disable-line no-console
136
+ /* eslint-disable no-console */
137
+ console.log(
138
+ `${color.bgRed}${color.fgBlack}test-error${color.reset}: Please create file ${testPath}`
139
+ );
140
+ /* eslint-enable no-console */
130
141
 
131
142
  return [
132
143
  404,
@@ -0,0 +1,219 @@
1
+ {
2
+ "id": "dsfdsafdsa-922c-4568-85a5-e5cc77efc3be",
3
+ "key": "0b76dccf-594c-b6dc-1acf-10c4493dcb84",
4
+ "name": "testExisting_temail",
5
+ "lastPublishedDate": "0001-01-01T00:00:00",
6
+ "description": "",
7
+ "version": 1,
8
+ "workflowApiVersion": 1,
9
+ "createdDate": "2022-03-24T02:20:32.74",
10
+ "modifiedDate": "2022-03-24T02:20:40.45",
11
+ "activities": [
12
+ {
13
+ "id": "9606bcb0-9246-4610-9800-963bc77fc20a",
14
+ "key": "EMAILV2-4",
15
+ "name": "testExisting_temail",
16
+ "description": "",
17
+ "type": "EMAILV2",
18
+ "outcomes": [
19
+ {
20
+ "key": "1f44021a-74ac-49be-a07c-67862228214d",
21
+ "arguments": {},
22
+ "metaData": {
23
+ "invalid": false
24
+ }
25
+ }
26
+ ],
27
+ "arguments": {},
28
+ "configurationArguments": {
29
+ "applicationExtensionKey": "jb-email-activity",
30
+ "isModified": true,
31
+ "triggeredSend": {
32
+ "autoAddSubscribers": true,
33
+ "autoUpdateSubscribers": true,
34
+ "bccEmail": "",
35
+ "ccEmail": "",
36
+ "created": {},
37
+ "domainExclusions": [],
38
+ "dynamicEmailSubject": "test email",
39
+ "emailId": 25923,
40
+ "emailSubject": "test email",
41
+ "exclusionFilter": "",
42
+ "isSalesforceTracking": true,
43
+ "isMultipart": true,
44
+ "isSendLogging": false,
45
+ "isStoppedOnJobError": false,
46
+ "modified": {},
47
+ "preHeader": "",
48
+ "priority": 4,
49
+ "sendClassificationId": "1284e9b2-a7b8-e711-80cf-1402ec721c9d",
50
+ "throttleOpens": "1/1/0001 12:00:00 AM",
51
+ "throttleCloses": "1/1/0001 12:00:00 AM",
52
+ "deliveryProfileId": "1084e9b2-a7b8-e711-80cf-1402ec721c9d",
53
+ "senderProfileId": "0f84e9b2-a7b8-e711-80cf-1402ec721c9d",
54
+ "isTrackingClicks": true,
55
+ "publicationListId": 15
56
+ },
57
+ "triggeredSendId": "0a650d90-755e-ed11-b852-48df37d1df5b",
58
+ "triggeredSendKey": "testExisting_temail"
59
+ },
60
+ "metaData": {
61
+ "highThroughput": {
62
+ "definitionKey": "testExisting_temail",
63
+ "dataExtensionId": "21711373-72c1-ec11-b83b-48df37d1deb7"
64
+ },
65
+ "sections": {},
66
+ "isConfigured": true
67
+ },
68
+ "schema": {
69
+ "arguments": {
70
+ "requestID": {
71
+ "dataType": "Text",
72
+ "isNullable": true,
73
+ "direction": "Out",
74
+ "readOnly": false,
75
+ "access": "Hidden"
76
+ },
77
+ "messageKey": {
78
+ "dataType": "Text",
79
+ "isNullable": true,
80
+ "direction": "Out",
81
+ "readOnly": false,
82
+ "access": "Hidden"
83
+ },
84
+ "activityId": {
85
+ "dataType": "Text",
86
+ "isNullable": true,
87
+ "direction": "In",
88
+ "readOnly": false,
89
+ "access": "Hidden"
90
+ },
91
+ "definitionId": {
92
+ "dataType": "Text",
93
+ "isNullable": true,
94
+ "direction": "In",
95
+ "readOnly": true,
96
+ "access": "Hidden"
97
+ },
98
+ "emailSubjectDataBound": {
99
+ "dataType": "Text",
100
+ "isNullable": true,
101
+ "direction": "In",
102
+ "readOnly": true,
103
+ "access": "Hidden"
104
+ },
105
+ "contactId": {
106
+ "dataType": "Number",
107
+ "isNullable": true,
108
+ "direction": "In",
109
+ "readOnly": false,
110
+ "access": "Hidden"
111
+ },
112
+ "contactKey": {
113
+ "dataType": "Text",
114
+ "isNullable": false,
115
+ "direction": "In",
116
+ "readOnly": false,
117
+ "access": "Hidden"
118
+ },
119
+ "emailAddress": {
120
+ "dataType": "Text",
121
+ "isNullable": false,
122
+ "direction": "In",
123
+ "readOnly": false,
124
+ "access": "Hidden"
125
+ },
126
+ "sourceCustomObjectId": {
127
+ "dataType": "Text",
128
+ "isNullable": true,
129
+ "direction": "In",
130
+ "readOnly": false,
131
+ "access": "Hidden"
132
+ },
133
+ "sourceCustomObjectKey": {
134
+ "dataType": "LongNumber",
135
+ "isNullable": true,
136
+ "direction": "In",
137
+ "readOnly": false,
138
+ "access": "Hidden"
139
+ },
140
+ "fieldType": {
141
+ "dataType": "Text",
142
+ "isNullable": true,
143
+ "direction": "In",
144
+ "readOnly": false,
145
+ "access": "Hidden"
146
+ },
147
+ "eventData": {
148
+ "dataType": "Text",
149
+ "isNullable": true,
150
+ "direction": "In",
151
+ "readOnly": false,
152
+ "access": "Hidden"
153
+ },
154
+ "obfuscationProperties": {
155
+ "dataType": "Text",
156
+ "isNullable": true,
157
+ "direction": "In",
158
+ "readOnly": false,
159
+ "access": "Hidden"
160
+ },
161
+ "customObjectKey": {
162
+ "dataType": "LongNumber",
163
+ "isNullable": true,
164
+ "direction": "In",
165
+ "readOnly": true,
166
+ "access": "Hidden"
167
+ },
168
+ "definitionInstanceId": {
169
+ "dataType": "Text",
170
+ "isNullable": false,
171
+ "direction": "In",
172
+ "readOnly": false,
173
+ "access": "Hidden"
174
+ }
175
+ }
176
+ }
177
+ }
178
+ ],
179
+ "triggers": [
180
+ {
181
+ "key": "TRIGGER",
182
+ "name": "TRIGGER",
183
+ "description": "",
184
+ "type": "transactional-api",
185
+ "outcomes": [],
186
+ "arguments": {},
187
+ "configurationArguments": {},
188
+ "metaData": {
189
+ "chainType": "none",
190
+ "configurationRequired": false,
191
+ "iconUrl": "/images/icon_journeyBuilder-event-transactional-blue.svg",
192
+ "title": "Transactional API Event",
193
+ "category": "Transactional",
194
+ "entrySourceGroupConfigUrl": "null"
195
+ }
196
+ }
197
+ ],
198
+ "goals": [],
199
+ "exits": [],
200
+ "notifiers": [],
201
+ "entryMode": "MultipleEntries",
202
+ "definitionType": "Transactional",
203
+ "channel": "email",
204
+ "defaults": {
205
+ "properties": {
206
+ "analyticsTracking": {
207
+ "enabled": false,
208
+ "analyticsType": "google",
209
+ "urlDomainsToTrack": []
210
+ }
211
+ }
212
+ },
213
+ "metaData": {},
214
+ "executionMode": "Production",
215
+ "categoryId": 6298,
216
+ "status": "Published",
217
+ "scheduledStatus": "Draft",
218
+ "definitionId": "dsfdsafdsa-922c-4568-85a5-e5cc77efc3be"
219
+ }