@rockcarver/frodo-lib 0.12.1 → 0.12.2-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 (159) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/cjs/api/BaseApi.js +36 -8
  3. package/cjs/api/BaseApi.js.map +1 -1
  4. package/cjs/api/NodeApi.js +190 -0
  5. package/cjs/api/NodeApi.js.map +1 -0
  6. package/cjs/api/NodeApi.test.js.map +1 -0
  7. package/cjs/api/OAuth2ClientApi.js +3 -1
  8. package/cjs/api/OAuth2ClientApi.js.map +1 -1
  9. package/cjs/api/SecretsApi.js +59 -29
  10. package/cjs/api/SecretsApi.js.map +1 -1
  11. package/cjs/api/StartupApi.js +21 -8
  12. package/cjs/api/StartupApi.js.map +1 -1
  13. package/cjs/api/StartupApi.test.js.map +1 -0
  14. package/cjs/api/TreeApi.js +30 -161
  15. package/cjs/api/TreeApi.js.map +1 -1
  16. package/cjs/api/TreeApi.test.js.map +1 -0
  17. package/cjs/api/VariablesApi.js +35 -20
  18. package/cjs/api/VariablesApi.js.map +1 -1
  19. package/cjs/index.js +15 -5
  20. package/cjs/index.js.map +1 -1
  21. package/cjs/ops/AuthenticateOps.js +1 -1
  22. package/cjs/ops/AuthenticateOps.js.map +1 -1
  23. package/cjs/ops/IdpOps.js +1 -1
  24. package/cjs/ops/IdpOps.js.map +1 -1
  25. package/cjs/ops/JourneyOps.js +233 -204
  26. package/cjs/ops/JourneyOps.js.map +1 -1
  27. package/cjs/ops/OAuth2ClientOps.js +27 -20
  28. package/cjs/ops/OAuth2ClientOps.js.map +1 -1
  29. package/cjs/ops/SecretsOps.js +9 -7
  30. package/cjs/ops/SecretsOps.js.map +1 -1
  31. package/cjs/ops/StartupOps.js +61 -71
  32. package/cjs/ops/StartupOps.js.map +1 -1
  33. package/cjs/ops/VariablesOps.js +3 -3
  34. package/cjs/ops/VariablesOps.js.map +1 -1
  35. package/cjs/ops/utils/Console.js +3 -2
  36. package/cjs/ops/utils/Console.js.map +1 -1
  37. package/cjs/ops/utils/ExportImportUtils.js +1 -0
  38. package/cjs/ops/utils/ExportImportUtils.js.map +1 -1
  39. package/esm/api/BaseApi.mjs +35 -7
  40. package/esm/api/NodeApi.mjs +114 -0
  41. package/esm/api/NodeApi.test.mjs +105 -0
  42. package/esm/api/OAuth2ClientApi.mjs +4 -2
  43. package/esm/api/SecretsApi.mjs +59 -29
  44. package/esm/api/StartupApi.mjs +18 -8
  45. package/esm/api/StartupApi.test.mjs +56 -0
  46. package/esm/api/TreeApi.mjs +29 -99
  47. package/esm/api/TreeApi.test.mjs +175 -0
  48. package/esm/api/VariablesApi.mjs +35 -20
  49. package/esm/index.mjs +7 -5
  50. package/esm/ops/AuthenticateOps.mjs +1 -1
  51. package/esm/ops/IdpOps.mjs +1 -1
  52. package/esm/ops/JourneyOps.mjs +186 -154
  53. package/esm/ops/OAuth2ClientOps.mjs +9 -4
  54. package/esm/ops/SecretsOps.mjs +9 -7
  55. package/esm/ops/StartupOps.mjs +59 -62
  56. package/esm/ops/VariablesOps.mjs +3 -3
  57. package/esm/ops/utils/Console.mjs +3 -2
  58. package/esm/ops/utils/ExportImportUtils.mjs +1 -0
  59. package/package.json +7 -4
  60. package/types/api/AuthenticateApi.d.ts +2 -0
  61. package/types/api/AuthenticateApi.d.ts.map +1 -0
  62. package/types/api/BaseApi.d.ts +50 -0
  63. package/types/api/BaseApi.d.ts.map +1 -0
  64. package/types/api/CirclesOfTrustApi.d.ts +24 -0
  65. package/types/api/CirclesOfTrustApi.d.ts.map +1 -0
  66. package/types/api/EmailTemplateApi.d.ts +22 -0
  67. package/types/api/EmailTemplateApi.d.ts.map +1 -0
  68. package/types/api/IdmConfigApi.d.ts +39 -0
  69. package/types/api/IdmConfigApi.d.ts.map +1 -0
  70. package/types/api/LogApi.d.ts +4 -0
  71. package/types/api/LogApi.d.ts.map +1 -0
  72. package/types/api/ManagedObjectApi.d.ts +21 -0
  73. package/types/api/ManagedObjectApi.d.ts.map +1 -0
  74. package/types/api/NodeApi.d.ts +38 -0
  75. package/types/api/NodeApi.d.ts.map +1 -0
  76. package/types/api/OAuth2ClientApi.d.ts +18 -0
  77. package/types/api/OAuth2ClientApi.d.ts.map +1 -0
  78. package/types/api/OAuth2OIDCApi.d.ts +22 -0
  79. package/types/api/OAuth2OIDCApi.d.ts.map +1 -0
  80. package/types/api/OAuth2ProviderApi.d.ts +5 -0
  81. package/types/api/OAuth2ProviderApi.d.ts.map +1 -0
  82. package/types/api/RealmApi.d.ts +30 -0
  83. package/types/api/RealmApi.d.ts.map +1 -0
  84. package/types/api/Saml2Api.d.ts +52 -0
  85. package/types/api/Saml2Api.d.ts.map +1 -0
  86. package/types/api/ScriptApi.d.ts +24 -0
  87. package/types/api/ScriptApi.d.ts.map +1 -0
  88. package/types/api/SecretsApi.d.ts +10 -0
  89. package/types/api/SecretsApi.d.ts.map +1 -0
  90. package/types/api/ServerInfoApi.d.ts +10 -0
  91. package/types/api/ServerInfoApi.d.ts.map +1 -0
  92. package/types/api/SocialIdentityProvidersApi.d.ts +31 -0
  93. package/types/api/SocialIdentityProvidersApi.d.ts.map +1 -0
  94. package/types/api/StartupApi.d.ts +14 -0
  95. package/types/api/StartupApi.d.ts.map +1 -0
  96. package/types/api/ThemeApi.d.ts +54 -0
  97. package/types/api/ThemeApi.d.ts.map +1 -0
  98. package/types/api/TreeApi.d.ts +24 -0
  99. package/types/api/TreeApi.d.ts.map +1 -0
  100. package/types/api/VariablesApi.d.ts +32 -0
  101. package/types/api/VariablesApi.d.ts.map +1 -0
  102. package/types/api/utils/ApiUtils.d.ts +29 -0
  103. package/types/api/utils/ApiUtils.d.ts.map +1 -0
  104. package/types/api/utils/Base64.d.ts +30 -0
  105. package/types/api/utils/Base64.d.ts.map +1 -0
  106. package/types/index.d.ts +26 -0
  107. package/types/index.d.ts.map +1 -0
  108. package/types/ops/AdminOps.d.ts +11 -0
  109. package/types/ops/AdminOps.d.ts.map +1 -0
  110. package/types/ops/AuthenticateOps.d.ts +6 -0
  111. package/types/ops/AuthenticateOps.d.ts.map +1 -0
  112. package/types/ops/CirclesOfTrustOps.d.ts +40 -0
  113. package/types/ops/CirclesOfTrustOps.d.ts.map +1 -0
  114. package/types/ops/ConnectionProfileOps.d.ts +47 -0
  115. package/types/ops/ConnectionProfileOps.d.ts.map +1 -0
  116. package/types/ops/EmailTemplateOps.d.ts +40 -0
  117. package/types/ops/EmailTemplateOps.d.ts.map +1 -0
  118. package/types/ops/IdmOps.d.ts +27 -0
  119. package/types/ops/IdmOps.d.ts.map +1 -0
  120. package/types/ops/IdpOps.d.ts +45 -0
  121. package/types/ops/IdpOps.d.ts.map +1 -0
  122. package/types/ops/JourneyOps.d.ts +151 -0
  123. package/types/ops/JourneyOps.d.ts.map +1 -0
  124. package/types/ops/LogOps.d.ts +5 -0
  125. package/types/ops/LogOps.d.ts.map +1 -0
  126. package/types/ops/ManagedObjectOps.d.ts +14 -0
  127. package/types/ops/ManagedObjectOps.d.ts.map +1 -0
  128. package/types/ops/OAuth2ClientOps.d.ts +24 -0
  129. package/types/ops/OAuth2ClientOps.d.ts.map +1 -0
  130. package/types/ops/OrganizationOps.d.ts +11 -0
  131. package/types/ops/OrganizationOps.d.ts.map +1 -0
  132. package/types/ops/RealmOps.d.ts +22 -0
  133. package/types/ops/RealmOps.d.ts.map +1 -0
  134. package/types/ops/SamlOps.d.ts +51 -0
  135. package/types/ops/SamlOps.d.ts.map +1 -0
  136. package/types/ops/ScriptOps.d.ts +30 -0
  137. package/types/ops/ScriptOps.d.ts.map +1 -0
  138. package/types/ops/SecretsOps.d.ts +63 -0
  139. package/types/ops/SecretsOps.d.ts.map +1 -0
  140. package/types/ops/StartupOps.d.ts +25 -0
  141. package/types/ops/StartupOps.d.ts.map +1 -0
  142. package/types/ops/ThemeOps.d.ts +66 -0
  143. package/types/ops/ThemeOps.d.ts.map +1 -0
  144. package/types/ops/VariablesOps.d.ts +39 -0
  145. package/types/ops/VariablesOps.d.ts.map +1 -0
  146. package/types/ops/utils/Console.d.ts +63 -0
  147. package/types/ops/utils/Console.d.ts.map +1 -0
  148. package/types/ops/utils/DataProtection.d.ts +6 -0
  149. package/types/ops/utils/DataProtection.d.ts.map +1 -0
  150. package/types/ops/utils/ExportImportUtils.d.ts +22 -0
  151. package/types/ops/utils/ExportImportUtils.d.ts.map +1 -0
  152. package/types/ops/utils/OpsUtils.d.ts +27 -0
  153. package/types/ops/utils/OpsUtils.d.ts.map +1 -0
  154. package/types/ops/utils/Wordwrap.d.ts +1 -0
  155. package/types/ops/utils/Wordwrap.d.ts.map +1 -0
  156. package/types/storage/SessionStorage.d.ts +47 -0
  157. package/types/storage/SessionStorage.d.ts.map +1 -0
  158. package/types/storage/StaticStorage.d.ts +14 -0
  159. package/types/storage/StaticStorage.d.ts.map +1 -0
@@ -1,12 +1,11 @@
1
- /* eslint-disable no-param-reassign */
2
1
  import fs from 'fs';
3
- import yesno from 'yesno';
4
2
  import { v4 as uuidv4 } from 'uuid';
5
3
  import _ from 'lodash';
6
4
  import { convertBase64TextToArray, getTypedFilename, saveJsonToFile, getRealmString, convertTextArrayToBase64, convertTextArrayToBase64Url } from './utils/ExportImportUtils';
7
5
  import { getRealmManagedUser, replaceAll } from './utils/OpsUtils';
8
6
  import storage from '../storage/SessionStorage';
9
- import { getNode, putNode, deleteNode, getTrees, getTree, putTree, getNodeTypes, getNodesByType, deleteTree } from '../api/TreeApi';
7
+ import { getNode, putNode, deleteNode, getNodeTypes, getNodesByType } from '../api/NodeApi';
8
+ import { getTrees, getTree, putTree, deleteTree } from '../api/TreeApi';
10
9
  import { getEmailTemplate, putEmailTemplate } from '../api/EmailTemplateApi';
11
10
  import { getScript } from '../api/ScriptApi';
12
11
  import * as global from '../storage/StaticStorage';
@@ -21,9 +20,10 @@ import { createOrUpdateScript } from './ScriptOps';
21
20
  const containerNodes = ['PageNode', 'CustomPageNode'];
22
21
  const scriptedNodes = ['ConfigProviderNode', 'ScriptedDecisionNode', 'ClientScriptNode', 'SocialProviderHandlerNode', 'CustomScriptNode'];
23
22
  const emailTemplateNodes = ['EmailSuspendNode', 'EmailTemplateNode'];
24
- const emptyScriptPlaceholder = '[Empty]'; // use a function vs a template variable to avoid problems in loops
23
+ const emptyScriptPlaceholder = '[Empty]';
25
24
 
26
- function getSingleTreeFileDataTemplate() {
25
+ // use a function vs a template variable to avoid problems in loops
26
+ function createSingleTreeExportTemplate() {
27
27
  return {
28
28
  meta: {},
29
29
  innerNodes: {},
@@ -36,10 +36,10 @@ function getSingleTreeFileDataTemplate() {
36
36
  circlesOfTrust: {},
37
37
  tree: {}
38
38
  };
39
- } // use a function vs a template variable to avoid problems in loops
40
-
39
+ }
41
40
 
42
- function getMultipleTreesFileDataTemplate() {
41
+ // use a function vs a template variable to avoid problems in loops
42
+ function createMultipleTreesExportTemplate() {
43
43
  return {
44
44
  meta: {},
45
45
  trees: {}
@@ -113,18 +113,39 @@ async function getSaml2NodeDependencies(nodeObject, allProviders, allCirclesOfTr
113
113
  };
114
114
  return saml2NodeDependencies;
115
115
  });
116
- }
116
+ } // export async function getTreeNodes(treeObject) {
117
+ // const nodeList = Object.entries(treeObject.nodes);
118
+ // const results = await Promise.allSettled(
119
+ // nodeList.map(
120
+ // async ([nodeId, nodeInfo]) => await getNode(nodeId, nodeInfo['nodeType'])
121
+ // )
122
+ // );
123
+ // const nodes = results.filter((r) => r.status === 'fulfilled');
124
+ // nodes.map((f) => {
125
+ // return f.status;
126
+ // });
127
+ // const failedList = results.filter((r) => r.status === 'rejected');
128
+ // return nodes;
129
+ // }
130
+
117
131
  /**
118
- * Helper method to create export data for a tree with all its
119
- * dependencies. The export data can be written to a file as is
120
- * (but it doesn't contain meta data).
121
- * @param {Object} treeObject tree object
122
- * @param {Object} exportData export data
123
- * @param {Object} options options object
132
+ * Export options
124
133
  */
125
134
 
126
135
 
127
- async function exportTree(treeObject, exportData, options) {
136
+ /**
137
+ * Create export data for a tree with all its nodes and dependencies. The export data can be written to a file as is.
138
+ * @param {string} treeId tree id/name
139
+ * @param {ExportOptions} options export options
140
+ * @returns {Promise<SingleTreeExportTemplate>} a promise that resolves to an object containing the tree and all its nodes and dependencies
141
+ */
142
+ export async function exportTree(treeId, options = {
143
+ useStringArrays: true,
144
+ deps: true,
145
+ verbose: false
146
+ }) {
147
+ const treeObject = await getTree(treeId);
148
+ const exportData = createSingleTreeExportTemplate();
128
149
  const {
129
150
  useStringArrays,
130
151
  deps,
@@ -151,7 +172,7 @@ async function exportTree(treeObject, exportData, options) {
151
172
  const themes = []; // get all the nodes
152
173
 
153
174
  for (const [nodeId, nodeInfo] of Object.entries(treeObject.nodes)) {
154
- nodePromises.push(getNode(nodeId, nodeInfo['nodeType']).then(response => response.data));
175
+ nodePromises.push(getNode(nodeId, nodeInfo['nodeType']));
155
176
  }
156
177
 
157
178
  if (verbose && nodePromises.length > 0) printMessage(' - Nodes:');
@@ -216,7 +237,7 @@ async function exportTree(treeObject, exportData, options) {
216
237
 
217
238
  if (containerNodes.includes(nodeType)) {
218
239
  for (const innerNode of nodeObject.nodes) {
219
- innerNodePromises.push(getNode(innerNode._id, innerNode.nodeType).then(response => response.data));
240
+ innerNodePromises.push(getNode(innerNode._id, innerNode.nodeType));
220
241
  } // frodo supports themes in platform deployments
221
242
 
222
243
 
@@ -375,14 +396,33 @@ async function exportTree(treeObject, exportData, options) {
375
396
  });
376
397
  });
377
398
  }
399
+
400
+ return exportData;
378
401
  }
379
402
  /**
380
- * Export journey by id/name to file
381
- * @param {String} journeyId journey id/name
382
- * @param {String} file optional export file name
383
- * @param {Object} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output, deps:boolean: include dependencies
403
+ * Get all the journeys/trees without all their nodes and dependencies.
404
+ * @returns {Promise<unknown[]>} a promise that resolves to an array of journey objects
384
405
  */
385
406
 
407
+ export async function getJourneys() {
408
+ let journeys = [];
409
+
410
+ try {
411
+ journeys = await getTrees();
412
+ } catch (error) {
413
+ printMessage(`${error.message}`, 'error');
414
+ printMessage(error.response.data, 'error');
415
+ }
416
+
417
+ journeys.sort((a, b) => a._id.localeCompare(b._id));
418
+ return journeys;
419
+ }
420
+ /**
421
+ * Export journey by id/name to file
422
+ * @param {string} journeyId journey id/name
423
+ * @param {string} file optional export file name
424
+ * @param {ExportOptions} options export options
425
+ */
386
426
 
387
427
  export async function exportJourneyToFile(journeyId, file, options) {
388
428
  const {
@@ -395,26 +435,21 @@ export async function exportJourneyToFile(journeyId, file, options) {
395
435
  }
396
436
 
397
437
  if (!verbose) createProgressIndicator(undefined, `${journeyId}`, 'indeterminate');
398
- await getTree(journeyId).then(async response => {
399
- const treeData = response.data;
400
- const fileData = getSingleTreeFileDataTemplate();
401
438
 
402
- try {
403
- await exportTree(treeData, fileData, options);
404
- if (verbose) createProgressIndicator(undefined, `${journeyId}`, 'indeterminate');
405
- saveJsonToFile(fileData, fileName);
406
- stopProgressIndicator(`Exported ${journeyId.brightCyan} to ${fileName.brightCyan}.`, 'success');
407
- } catch (error) {
408
- if (verbose) createProgressIndicator(undefined, `${journeyId}`, 'indeterminate');
409
- stopProgressIndicator(`Error exporting journey ${journeyId}: ${error}`, 'fail');
410
- }
411
- }).catch(err => {
412
- stopProgressIndicator(err.message, 'fail');
413
- });
439
+ try {
440
+ const fileData = await exportTree(journeyId, options);
441
+ if (verbose) createProgressIndicator(undefined, `${journeyId}`, 'indeterminate');
442
+ saveJsonToFile(fileData, fileName);
443
+ stopProgressIndicator(`Exported ${journeyId['brightCyan']} to ${fileName['brightCyan']}.`, 'success');
444
+ } catch (error) {
445
+ if (verbose) createProgressIndicator(undefined, `${journeyId}`, 'indeterminate');
446
+ stopProgressIndicator(`Error exporting journey ${journeyId}: ${error}`, 'fail');
447
+ }
414
448
  }
415
449
  /**
416
450
  * Export all journeys to file
417
- * @param {String} file optional export file name
451
+ * @param {string} file optional export file name
452
+ * @param {ExportOptions} options export options
418
453
  */
419
454
 
420
455
  export async function exportJourneysToFile(file, options) {
@@ -424,20 +459,16 @@ export async function exportJourneysToFile(file, options) {
424
459
  fileName = getTypedFilename(`all${getRealmString()}Journeys`, 'journeys');
425
460
  }
426
461
 
427
- const trees = (await getTrees()).data.result;
428
- const fileData = getMultipleTreesFileDataTemplate();
462
+ const trees = await getTrees();
463
+ const fileData = createMultipleTreesExportTemplate();
429
464
  createProgressIndicator(trees.length, 'Exporting journeys...');
430
465
 
431
466
  for (const tree of trees) {
432
467
  updateProgressIndicator(`${tree._id}`);
433
468
 
434
469
  try {
435
- // eslint-disable-next-line no-await-in-loop
436
- const treeData = (await getTree(tree._id)).data;
437
- const exportData = getSingleTreeFileDataTemplate();
438
- delete exportData.meta; // eslint-disable-next-line no-await-in-loop
439
-
440
- await exportTree(treeData, exportData, options);
470
+ const exportData = await exportTree(tree._id, options);
471
+ delete exportData.meta;
441
472
  fileData.trees[tree._id] = exportData;
442
473
  } catch (error) {
443
474
  printMessage(`Error exporting journey ${tree._id}: ${error}`, 'error');
@@ -449,59 +480,39 @@ export async function exportJourneysToFile(file, options) {
449
480
  }
450
481
  /**
451
482
  * Export all journeys to separate files
483
+ * @param {ExportOptions} options export options
452
484
  */
453
485
 
454
486
  export async function exportJourneysToFiles(options) {
455
- const trees = (await getTrees()).data.result;
487
+ const trees = await getTrees();
456
488
  createProgressIndicator(trees.length, 'Exporting journeys...');
457
489
 
458
490
  for (const tree of trees) {
459
491
  updateProgressIndicator(`${tree._id}`);
460
- const fileName = getTypedFilename(`${tree._id}`, 'journey'); // eslint-disable-next-line no-await-in-loop
492
+ const fileName = getTypedFilename(`${tree._id}`, 'journey');
461
493
 
462
- const treeData = (await getTree(tree._id)).data;
463
- const exportData = getSingleTreeFileDataTemplate(); // eslint-disable-next-line no-await-in-loop
464
-
465
- await exportTree(treeData, exportData, options);
466
- saveJsonToFile(exportData, fileName);
494
+ try {
495
+ const exportData = await exportTree(tree._id, options);
496
+ saveJsonToFile(exportData, fileName);
497
+ } catch (error) {// do we need to report status here?
498
+ }
467
499
  }
468
500
 
469
501
  stopProgressIndicator('Done');
470
502
  }
471
503
  /**
472
- * Get data for journey by id/name
473
- * @param {String} journeyId journey id/name
474
- * @returns {Object} object containing all journey data
504
+ * Import options
475
505
  */
476
506
 
477
- export async function getJourneyData(journeyId) {
478
- createProgressIndicator(undefined, `${journeyId}`, 'indeterminate');
479
- const journeyData = getSingleTreeFileDataTemplate();
480
- const treeData = (await getTree(journeyId).catch(err => {
481
- stopProgressIndicator(null, 'success');
482
- printMessage(err, 'error');
483
- }))['data'];
484
- updateProgressIndicator();
485
- await exportTree(treeData, journeyData, {
486
- useStringArrays: true
487
- });
488
- stopProgressIndicator(null, 'success');
489
- return journeyData;
490
- }
491
507
  /**
492
508
  * Helper to import a tree with all dependencies from an import data object (typically read from a file)
493
- * @param {Object} treeObject tree object containing tree and all its dependencies
494
- * @param {Object} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output
509
+ * @param {SingleTreeExportTemplate} treeObject tree object containing tree and all its dependencies
510
+ * @param {ImportOptions} options import options
495
511
  */
496
-
497
- async function importTree(treeObject, options) {
498
- const {
499
- reUuid
500
- } = options;
501
- const {
502
- deps
503
- } = options;
512
+ export async function importTree(treeObject, options) {
504
513
  const {
514
+ reUuid,
515
+ deps,
505
516
  verbose
506
517
  } = options;
507
518
  if (verbose) printMessage(`\n- ${treeObject.tree._id}\n`, 'info', false);
@@ -555,8 +566,8 @@ async function importTree(treeObject, options) {
555
566
  const themes = {};
556
567
 
557
568
  for (const theme of treeObject.themes) {
558
- if (verbose) printMessage(` - ${theme._id} (${theme.name})`, 'info');
559
- themes[theme._id] = theme;
569
+ if (verbose) printMessage(` - ${theme['_id']} (${theme['name']})`, 'info');
570
+ themes[theme['_id']] = theme;
560
571
  }
561
572
 
562
573
  try {
@@ -775,7 +786,7 @@ async function importTree(treeObject, options) {
775
786
  // Set the identityResource for the tree to the selected resource.
776
787
 
777
788
 
778
- if (treeObject.tree.identityResource && treeObject.tree.identityResource.endsWith('user')) {
789
+ if (treeObject.tree.identityResource && treeObject.tree['identityResource'].endsWith('user')) {
779
790
  treeObject.tree.identityResource = `managed/${getRealmManagedUser()}`;
780
791
  if (verbose) printMessage(` - identityResource: ${treeObject.tree.identityResource}`, 'info', false);
781
792
  }
@@ -820,7 +831,6 @@ async function importTree(treeObject, options) {
820
831
  * @param {int} index Depth of recursion
821
832
  */
822
833
 
823
-
824
834
  async function resolveDependencies(installedJorneys, journeyMap, unresolvedJourneys, resolvedJourneys, index = -1) {
825
835
  let before = -1;
826
836
  let after = index;
@@ -877,9 +887,9 @@ async function resolveDependencies(installedJorneys, journeyMap, unresolvedJourn
877
887
  }
878
888
  /**
879
889
  * Import a journey from file
880
- * @param {String} journeyId journey id/name
881
- * @param {String} file import file name
882
- * @param {boolean} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output
890
+ * @param {string} journeyId journey id/name
891
+ * @param {string} file import file name
892
+ * @param {ImportOptions} options import options
883
893
  */
884
894
 
885
895
 
@@ -900,7 +910,7 @@ export async function importJourneyFromFile(journeyId, file, options) {
900
910
 
901
911
  if (journeyData && journeyId === journeyData.tree._id) {
902
912
  // attempt dependency resolution for single tree import
903
- const installedJourneys = (await getTrees()).data.result.map(x => x._id);
913
+ const installedJourneys = (await getTrees()).map(x => x._id);
904
914
  const unresolvedJourneys = {};
905
915
  const resolvedJourneys = [];
906
916
  createProgressIndicator(undefined, 'Resolving dependencies', 'indeterminate');
@@ -934,8 +944,8 @@ export async function importJourneyFromFile(journeyId, file, options) {
934
944
  }
935
945
  /**
936
946
  * Import first journey from file
937
- * @param {String} file import file name
938
- * @param {boolean} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output
947
+ * @param {string} file import file name
948
+ * @param {ImportOptions} options import options
939
949
  */
940
950
 
941
951
  export async function importFirstJourneyFromFile(file, options) {
@@ -965,7 +975,7 @@ export async function importFirstJourneyFromFile(file, options) {
965
975
 
966
976
  if (journeyData && journeyId) {
967
977
  // attempt dependency resolution for single tree import
968
- const installedJourneys = (await getTrees()).data.result.map(x => x._id);
978
+ const installedJourneys = (await getTrees()).map(x => x._id);
969
979
  const unresolvedJourneys = {};
970
980
  const resolvedJourneys = [];
971
981
  createProgressIndicator(undefined, 'Resolving dependencies', 'indeterminate');
@@ -1000,11 +1010,11 @@ export async function importFirstJourneyFromFile(file, options) {
1000
1010
  /**
1001
1011
  * Helper to import multiple trees from a tree map
1002
1012
  * @param {Object} treesMap map of trees object
1003
- * @param {boolean} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output
1013
+ * @param {ImportOptions} options import options
1004
1014
  */
1005
1015
 
1006
1016
  async function importAllTrees(treesMap, options) {
1007
- const installedJourneys = (await getTrees()).data.result.map(x => x._id);
1017
+ const installedJourneys = (await getTrees()).map(x => x._id);
1008
1018
  const unresolvedJourneys = {};
1009
1019
  const resolvedJourneys = [];
1010
1020
  createProgressIndicator(undefined, 'Resolving dependencies', 'indeterminate');
@@ -1036,8 +1046,8 @@ async function importAllTrees(treesMap, options) {
1036
1046
  }
1037
1047
  /**
1038
1048
  * Import all journeys from file
1039
- * @param {*} file import file name
1040
- * @param {boolean} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output
1049
+ * @param {string} file import file name
1050
+ * @param {ImportOptions} options import options
1041
1051
  */
1042
1052
 
1043
1053
 
@@ -1050,7 +1060,7 @@ export async function importJourneysFromFile(file, options) {
1050
1060
  }
1051
1061
  /**
1052
1062
  * Import all journeys from separate files
1053
- * @param {boolean} options reUuid:boolean: re-uuid all node objects, verbose:boolean: verbose output
1063
+ * @param {ImportOptions} options import options
1054
1064
  */
1055
1065
 
1056
1066
  export async function importJourneysFromFiles(options) {
@@ -1107,23 +1117,50 @@ export function describeTree(treeData) {
1107
1117
  treeMap['nodeTypes'] = nodeTypeMap;
1108
1118
  treeMap['scripts'] = scriptsMap;
1109
1119
  treeMap['emailTemplates'] = emailTemplatesMap;
1120
+ printMessage(`\nJourney: ${treeMap['treeName']}`, 'data');
1121
+ printMessage('========');
1122
+ printMessage('\nNodes:', 'data');
1123
+
1124
+ if (Object.entries(treeMap['nodeTypes']).length) {
1125
+ for (const [name, count] of Object.entries(treeMap['nodeTypes'])) {
1126
+ printMessage(`- ${name}: ${count}`, 'data');
1127
+ }
1128
+ }
1129
+
1130
+ if (Object.entries(treeMap['scripts']).length) {
1131
+ printMessage('\nScripts:', 'data');
1132
+
1133
+ for (const [name, desc] of Object.entries(treeMap['scripts'])) {
1134
+ printMessage(`- ${name}: ${desc}`, 'data');
1135
+ }
1136
+ }
1137
+
1138
+ if (Object.entries(treeMap['emailTemplates']).length) {
1139
+ printMessage('\nEmail Templates:', 'data');
1140
+
1141
+ for (const [id] of Object.entries(treeMap['emailTemplates'])) {
1142
+ printMessage(`- ${id}`, 'data');
1143
+ }
1144
+ }
1145
+
1110
1146
  return treeMap;
1111
1147
  }
1112
1148
  /**
1113
1149
  * Find all node configuration objects that are no longer referenced by any tree
1150
+ * @returns {Promise<unknown[]>} a promise that resolves to an array of orphaned nodes
1114
1151
  */
1115
1152
 
1116
- async function findOrphanedNodes() {
1153
+ export async function findOrphanedNodes() {
1117
1154
  const allNodes = [];
1118
1155
  const orphanedNodes = [];
1119
1156
  let types = [];
1120
- const allJourneys = (await getTrees()).data.result;
1157
+ const allJourneys = await getTrees();
1121
1158
  let errorMessage = '';
1122
1159
  const errorTypes = [];
1123
1160
  createProgressIndicator(undefined, `Counting total nodes...`, 'indeterminate');
1124
1161
 
1125
1162
  try {
1126
- types = (await getNodeTypes()).data.result;
1163
+ types = await getNodeTypes();
1127
1164
  } catch (error) {
1128
1165
  printMessage('Error retrieving all available node types:', 'error');
1129
1166
  printMessage(error.response.data, 'error');
@@ -1133,7 +1170,7 @@ async function findOrphanedNodes() {
1133
1170
  for (const type of types) {
1134
1171
  try {
1135
1172
  // eslint-disable-next-line no-await-in-loop, no-loop-func
1136
- (await getNodesByType(type._id)).data.result.forEach(node => {
1173
+ (await getNodesByType(type._id)).forEach(node => {
1137
1174
  allNodes.push(node);
1138
1175
  updateProgressIndicator(`${allNodes.length} total nodes${errorMessage}`);
1139
1176
  });
@@ -1162,7 +1199,7 @@ async function findOrphanedNodes() {
1162
1199
 
1163
1200
  if (containerNodes.includes(node.nodeType)) {
1164
1201
  // eslint-disable-next-line no-await-in-loop
1165
- const containerNode = (await getNode(nodeId, node.nodeType)).data;
1202
+ const containerNode = await getNode(nodeId, node.nodeType);
1166
1203
  containerNode.nodes.forEach(n => {
1167
1204
  activeNodes.push(n._id);
1168
1205
  updateProgressIndicator(`${activeNodes.length} active nodes`);
@@ -1182,41 +1219,27 @@ async function findOrphanedNodes() {
1182
1219
  /**
1183
1220
  * Remove orphaned nodes
1184
1221
  * @param {[Object]} orphanedNodes Pass in an array of orphaned node configuration objects to remove
1222
+ * @returns {Promise<unknown[]>} a promise that resolves to an array nodes that encountered errors deleting
1185
1223
  */
1186
1224
 
1187
-
1188
- async function removeOrphanedNodes(orphanedNodes) {
1225
+ export async function removeOrphanedNodes(orphanedNodes) {
1226
+ const errorNodes = [];
1189
1227
  createProgressIndicator(orphanedNodes.length, 'Removing orphaned nodes...');
1190
1228
 
1191
1229
  for (const node of orphanedNodes) {
1192
- updateProgressIndicator(`Removing ${node._id}...`); // eslint-disable-next-line no-await-in-loop
1230
+ updateProgressIndicator(`Removing ${node['_id']}...`);
1193
1231
 
1194
- await deleteNode(node._id, node._type._id).catch(deleteError => {
1195
- printMessage(`${deleteError}`, 'error');
1196
- });
1232
+ try {
1233
+ // eslint-disable-next-line no-await-in-loop
1234
+ await deleteNode(node['_id'], node['_type']['_id']);
1235
+ } catch (deleteError) {
1236
+ errorNodes.push(node);
1237
+ printMessage(` ${deleteError}`, 'error');
1238
+ }
1197
1239
  }
1198
1240
 
1199
1241
  stopProgressIndicator(`Removed ${orphanedNodes.length} orphaned nodes.`);
1200
- }
1201
- /**
1202
- * Prune orphaned nodes
1203
- */
1204
-
1205
-
1206
- export async function prune() {
1207
- const orphanedNodes = await findOrphanedNodes();
1208
-
1209
- if (orphanedNodes.length > 0) {
1210
- const ok = await yesno({
1211
- question: 'Prune (permanently delete) orphaned nodes? (y|n):'
1212
- });
1213
-
1214
- if (ok) {
1215
- await removeOrphanedNodes(orphanedNodes);
1216
- }
1217
- } else {
1218
- printMessage('No orphaned nodes found.');
1219
- }
1242
+ return errorNodes;
1220
1243
  }
1221
1244
  const OOTB_NODE_TYPES_7 = ['AcceptTermsAndConditionsNode', 'AccountActiveDecisionNode', 'AccountLockoutNode', 'AgentDataStoreDecisionNode', 'AnonymousSessionUpgradeNode', 'AnonymousUserNode', 'AttributeCollectorNode', 'AttributePresentDecisionNode', 'AttributeValueDecisionNode', 'AuthLevelDecisionNode', 'ChoiceCollectorNode', 'ConsentNode', 'CookiePresenceDecisionNode', 'CreateObjectNode', 'CreatePasswordNode', 'DataStoreDecisionNode', 'DeviceGeoFencingNode', 'DeviceLocationMatchNode', 'DeviceMatchNode', 'DeviceProfileCollectorNode', 'DeviceSaveNode', 'DeviceTamperingVerificationNode', 'DisplayUserNameNode', 'EmailSuspendNode', 'EmailTemplateNode', 'IdentifyExistingUserNode', 'IncrementLoginCountNode', 'InnerTreeEvaluatorNode', 'IotAuthenticationNode', 'IotRegistrationNode', 'KbaCreateNode', 'KbaDecisionNode', 'KbaVerifyNode', 'LdapDecisionNode', 'LoginCountDecisionNode', 'MessageNode', 'MetadataNode', 'MeterNode', 'ModifyAuthLevelNode', 'OneTimePasswordCollectorDecisionNode', 'OneTimePasswordGeneratorNode', 'OneTimePasswordSmsSenderNode', 'OneTimePasswordSmtpSenderNode', 'PageNode', 'PasswordCollectorNode', 'PatchObjectNode', 'PersistentCookieDecisionNode', 'PollingWaitNode', 'ProfileCompletenessDecisionNode', 'ProvisionDynamicAccountNode', 'ProvisionIdmAccountNode', 'PushAuthenticationSenderNode', 'PushResultVerifierNode', 'QueryFilterDecisionNode', 'RecoveryCodeCollectorDecisionNode', 'RecoveryCodeDisplayNode', 'RegisterLogoutWebhookNode', 'RemoveSessionPropertiesNode', 'RequiredAttributesDecisionNode', 'RetryLimitDecisionNode', 'ScriptedDecisionNode', 'SelectIdPNode', 'SessionDataNode', 'SetFailureUrlNode', 'SetPersistentCookieNode', 'SetSessionPropertiesNode', 'SetSuccessUrlNode', 'SocialFacebookNode', 'SocialGoogleNode', 'SocialNode', 'SocialOAuthIgnoreProfileNode', 'SocialOpenIdConnectNode', 'SocialProviderHandlerNode', 'TermsAndConditionsDecisionNode', 'TimeSinceDecisionNode', 'TimerStartNode', 'TimerStopNode', 'UsernameCollectorNode', 'ValidatedPasswordNode', 'ValidatedUsernameNode', 'WebAuthnAuthenticationNode', 'WebAuthnDeviceStorageNode', 'WebAuthnRegistrationNode', 'ZeroPageLoginNode', 'product-CertificateCollectorNode', 'product-CertificateUserExtractorNode', 'product-CertificateValidationNode', 'product-KerberosNode', 'product-ReCaptchaNode', 'product-Saml2Node', 'product-WriteFederationInformationNode'];
1222
1245
  const OOTB_NODE_TYPES_7_1 = ['PushRegistrationNode', 'GetAuthenticatorAppNode', 'MultiFactorRegistrationOptionsNode', 'OptOutMultiFactorAuthenticationNode'].concat(OOTB_NODE_TYPES_7);
@@ -1229,10 +1252,9 @@ const OOTB_NODE_TYPES_6 = ['AbstractSocialAuthLoginNode', 'AccountLockoutNode',
1229
1252
  * @returns {boolean} True if the journey/tree contains any custom nodes, false otherwise.
1230
1253
  */
1231
1254
 
1232
- async function isCustom(journey) {
1255
+ export async function isCustom(journey) {
1233
1256
  let ootbNodeTypes = [];
1234
- const nodeList = journey.nodes; // console.log(nodeList);
1235
- // console.log(storage.session.getAmVersion());
1257
+ const nodeList = journey.nodes;
1236
1258
 
1237
1259
  switch (storage.session.getAmVersion()) {
1238
1260
  case '7.1.0':
@@ -1240,7 +1262,6 @@ async function isCustom(journey) {
1240
1262
  break;
1241
1263
 
1242
1264
  case '7.2.0':
1243
- // console.log("here");
1244
1265
  ootbNodeTypes = OOTB_NODE_TYPES_7_2.slice(0);
1245
1266
  break;
1246
1267
 
@@ -1286,7 +1307,7 @@ async function isCustom(journey) {
1286
1307
 
1287
1308
  if (containerNodes.includes(nodeList[node].nodeType)) {
1288
1309
  results.push( // eslint-disable-next-line no-await-in-loop
1289
- (await getNode(node, nodeList[node].nodeType))['data']);
1310
+ await getNode(node, nodeList[node].nodeType));
1290
1311
  }
1291
1312
  }
1292
1313
  }
@@ -1311,14 +1332,14 @@ async function isCustom(journey) {
1311
1332
  * List all the journeys/trees
1312
1333
  * @param {boolean} long Long version, all the fields
1313
1334
  * @param {boolean} analyze Analyze journeys/trees for custom nodes (expensive)
1335
+ * @returns {Promise<unknown[]>} a promise that resolves to an array journey objects
1314
1336
  */
1315
1337
 
1316
-
1317
1338
  export async function listJourneys(long = false, analyze = false) {
1318
1339
  let journeys = [];
1319
1340
 
1320
1341
  try {
1321
- journeys = (await getTrees()).data.result;
1342
+ journeys = await getTrees();
1322
1343
  } catch (error) {
1323
1344
  printMessage(`${error.message}`, 'error');
1324
1345
  printMessage(error.response.data, 'error');
@@ -1348,14 +1369,16 @@ export async function listJourneys(long = false, analyze = false) {
1348
1369
  });
1349
1370
  printMessage(table.toString(), 'data');
1350
1371
  }
1372
+
1373
+ return journeys;
1351
1374
  }
1352
1375
  /**
1353
1376
  * Delete a journey
1354
- * @param {String} journeyId journey id/name
1377
+ * @param {string} journeyId journey id/name
1355
1378
  * @param {Object} options deep=true also delete all the nodes and inner nodes, verbose=true print verbose info
1356
1379
  */
1357
1380
 
1358
- export async function deleteJourney(journeyId, options, spinner = true) {
1381
+ export async function deleteJourney(journeyId, options, progress = true) {
1359
1382
  const {
1360
1383
  deep
1361
1384
  } = options;
@@ -1365,29 +1388,29 @@ export async function deleteJourney(journeyId, options, spinner = true) {
1365
1388
  const status = {
1366
1389
  nodes: {}
1367
1390
  };
1368
- if (spinner) createProgressIndicator(undefined, `Deleting ${journeyId}...`, 'indeterminate');
1369
- if (spinner && verbose) stopProgressIndicator();
1391
+ if (progress) createProgressIndicator(undefined, `Deleting ${journeyId}...`, 'indeterminate');
1392
+ if (progress && verbose) stopProgressIndicator();
1370
1393
  return deleteTree(journeyId).then(async deleteTreeResponse => {
1371
1394
  status['status'] = 'success';
1372
1395
  const nodePromises = [];
1373
1396
  if (verbose) printMessage(`Deleted ${journeyId} (tree)`, 'info');
1374
1397
 
1375
1398
  if (deep) {
1376
- for (const [nodeId, nodeObject] of Object.entries(deleteTreeResponse.data.nodes)) {
1399
+ for (const [nodeId, nodeObject] of Object.entries(deleteTreeResponse.nodes)) {
1377
1400
  // delete inner nodes (nodes inside container nodes)
1378
1401
  if (containerNodes.includes(nodeObject['nodeType'])) {
1379
1402
  try {
1380
1403
  // eslint-disable-next-line no-await-in-loop
1381
- const pageNode = (await getNode(nodeId, nodeObject['nodeType'])).data;
1404
+ const containerNode = await getNode(nodeId, nodeObject['nodeType']);
1382
1405
  if (verbose) printMessage(`Read ${nodeId} (${nodeObject['nodeType']}) from ${journeyId}`, 'info');
1383
1406
 
1384
- for (const innerNodeObject of pageNode.nodes) {
1407
+ for (const innerNodeObject of containerNode.nodes) {
1385
1408
  nodePromises.push(deleteNode(innerNodeObject._id, innerNodeObject.nodeType).then(response2 => {
1386
1409
  status.nodes[innerNodeObject._id] = {
1387
1410
  status: 'success'
1388
1411
  };
1389
1412
  if (verbose) printMessage(`Deleted ${innerNodeObject._id} (${innerNodeObject.nodeType}) from ${journeyId}`, 'info');
1390
- return response2.data;
1413
+ return response2;
1391
1414
  }).catch(error => {
1392
1415
  status.nodes[innerNodeObject._id] = {
1393
1416
  status: 'error',
@@ -1398,18 +1421,27 @@ export async function deleteJourney(journeyId, options, spinner = true) {
1398
1421
  } // finally delete the container node
1399
1422
 
1400
1423
 
1401
- nodePromises.push(deleteNode(nodeId, nodeObject['nodeType']).then(response2 => {
1402
- status.nodes[nodeId] = {
1424
+ nodePromises.push(deleteNode(containerNode._id, containerNode['_type']['_id']).then(response2 => {
1425
+ status.nodes[containerNode._id] = {
1403
1426
  status: 'success'
1404
1427
  };
1405
- if (verbose) printMessage(`Deleted ${nodeId} (${nodeObject['nodeType']}) from ${journeyId}`, 'info');
1406
- return response2.data;
1428
+ if (verbose) printMessage(`Deleted ${containerNode._id} (${containerNode['_type']['_id']}) from ${journeyId}`, 'info');
1429
+ return response2;
1407
1430
  }).catch(error => {
1408
- status.nodes[nodeId] = {
1409
- status: 'error',
1410
- error
1411
- };
1412
- if (verbose) printMessage(`Error deleting container node ${nodeId} (${nodeObject['nodeType']}) from ${journeyId}: ${error}`, 'error');
1431
+ var _error$response, _error$response$data;
1432
+
1433
+ if ((error === null || error === void 0 ? void 0 : (_error$response = error.response) === null || _error$response === void 0 ? void 0 : (_error$response$data = _error$response.data) === null || _error$response$data === void 0 ? void 0 : _error$response$data.code) === 500 && error.response.data.message === 'Unable to read SMS config: Node did not exist') {
1434
+ status.nodes[containerNode._id] = {
1435
+ status: 'success'
1436
+ };
1437
+ if (verbose) printMessage(`Deleted ${containerNode._id} (${containerNode['_type']['_id']}) from ${journeyId}`, 'info');
1438
+ } else {
1439
+ status.nodes[containerNode._id] = {
1440
+ status: 'error',
1441
+ error
1442
+ };
1443
+ if (verbose) printMessage(`Error deleting container node ${containerNode._id} (${containerNode['_type']['_id']}) from ${journeyId}: ${error.response.data.message}`, 'error');
1444
+ }
1413
1445
  }));
1414
1446
  } catch (error) {
1415
1447
  if (verbose) printMessage(`Error getting container node ${nodeId} (${nodeObject['nodeType']}) from ${journeyId}: ${error}`, 'error');
@@ -1421,7 +1453,7 @@ export async function deleteJourney(journeyId, options, spinner = true) {
1421
1453
  status: 'success'
1422
1454
  };
1423
1455
  if (verbose) printMessage(`Deleted ${nodeId} (${nodeObject['nodeType']}) from ${journeyId}`, 'info');
1424
- return response.data;
1456
+ return response;
1425
1457
  }).catch(error => {
1426
1458
  status.nodes[nodeId] = {
1427
1459
  status: 'error',
@@ -1436,7 +1468,7 @@ export async function deleteJourney(journeyId, options, spinner = true) {
1436
1468
 
1437
1469
  await Promise.allSettled(nodePromises); // report status
1438
1470
 
1439
- if (spinner) {
1471
+ if (progress) {
1440
1472
  let nodeCount = 0;
1441
1473
  let errorCount = 0;
1442
1474
 
@@ -1471,7 +1503,7 @@ export async function deleteJourneys(options) {
1471
1503
  verbose
1472
1504
  } = options;
1473
1505
  const status = {};
1474
- const trees = (await getTrees()).data.result;
1506
+ const trees = await getTrees();
1475
1507
  createProgressIndicator(trees.length, 'Deleting journeys...');
1476
1508
 
1477
1509
  for (const tree of trees) {