@rockcarver/frodo-lib 0.12.5 → 0.12.6
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.
- package/CHANGELOG.md +23 -8
- package/cjs/api/ApiTypes.js +42 -0
- package/cjs/api/ApiTypes.js.map +1 -0
- package/cjs/api/Saml2Api.js +1 -1
- package/cjs/api/Saml2Api.js.map +1 -1
- package/cjs/index.js +9 -1
- package/cjs/index.js.map +1 -1
- package/cjs/ops/CirclesOfTrustOps.js +12 -1
- package/cjs/ops/CirclesOfTrustOps.js.map +1 -1
- package/cjs/ops/EmailTemplateOps.js +12 -0
- package/cjs/ops/EmailTemplateOps.js.map +1 -1
- package/cjs/ops/IdpOps.js +12 -1
- package/cjs/ops/IdpOps.js.map +1 -1
- package/cjs/ops/JourneyOps.js +388 -140
- package/cjs/ops/JourneyOps.js.map +1 -1
- package/cjs/ops/NodeOps.js +13 -0
- package/cjs/ops/NodeOps.js.map +1 -1
- package/cjs/ops/OpsTypes.js +6 -0
- package/cjs/ops/OpsTypes.js.map +1 -0
- package/cjs/ops/Saml2Ops.js +24 -1
- package/cjs/ops/Saml2Ops.js.map +1 -1
- package/cjs/ops/ScriptOps.js +12 -0
- package/cjs/ops/ScriptOps.js.map +1 -1
- package/cjs/ops/ThemeOps.js +12 -0
- package/cjs/ops/ThemeOps.js.map +1 -1
- package/cjs/ops/utils/Console.js +18 -1
- package/cjs/ops/utils/Console.js.map +1 -1
- package/cjs/ops/utils/ExportImportUtils.js.map +1 -1
- package/cjs/storage/SessionStorage.js +4 -0
- package/cjs/storage/SessionStorage.js.map +1 -1
- package/esm/api/ApiTypes.mjs +33 -0
- package/esm/api/Saml2Api.mjs +1 -1
- package/esm/index.mjs +2 -0
- package/esm/ops/CirclesOfTrustOps.mjs +11 -1
- package/esm/ops/EmailTemplateOps.mjs +11 -1
- package/esm/ops/IdpOps.mjs +11 -1
- package/esm/ops/JourneyOps.mjs +269 -82
- package/esm/ops/NodeOps.mjs +11 -0
- package/esm/ops/OpsTypes.mjs +2 -0
- package/esm/ops/Saml2Ops.mjs +20 -2
- package/esm/ops/ScriptOps.mjs +10 -0
- package/esm/ops/ThemeOps.mjs +10 -0
- package/esm/ops/utils/Console.mjs +16 -1
- package/esm/storage/SessionStorage.mjs +4 -0
- package/package.json +1 -1
- package/types/api/ApiTypes.d.ts +102 -0
- package/types/api/ApiTypes.d.ts.map +1 -0
- package/types/api/Saml2Api.d.ts +1 -1
- package/types/api/Saml2Api.d.ts.map +1 -1
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -1
- package/types/ops/CirclesOfTrustOps.d.ts +7 -0
- package/types/ops/CirclesOfTrustOps.d.ts.map +1 -1
- package/types/ops/EmailTemplateOps.d.ts +7 -0
- package/types/ops/EmailTemplateOps.d.ts.map +1 -1
- package/types/ops/IdpOps.d.ts +7 -0
- package/types/ops/IdpOps.d.ts.map +1 -1
- package/types/ops/JourneyOps.d.ts +107 -89
- package/types/ops/JourneyOps.d.ts.map +1 -1
- package/types/ops/NodeOps.d.ts +8 -0
- package/types/ops/NodeOps.d.ts.map +1 -1
- package/types/ops/OpsTypes.d.ts +66 -0
- package/types/ops/OpsTypes.d.ts.map +1 -0
- package/types/ops/Saml2Ops.d.ts +13 -0
- package/types/ops/Saml2Ops.d.ts.map +1 -1
- package/types/ops/ScriptOps.d.ts +7 -0
- package/types/ops/ScriptOps.d.ts.map +1 -1
- package/types/ops/ThemeOps.d.ts +7 -0
- package/types/ops/ThemeOps.d.ts.map +1 -1
- package/types/ops/utils/Console.d.ts +9 -1
- package/types/ops/utils/Console.d.ts.map +1 -1
- package/types/ops/utils/ExportImportUtils.d.ts.map +1 -1
- package/types/storage/SessionStorage.d.ts +4 -0
- package/types/storage/SessionStorage.d.ts.map +1 -1
package/esm/ops/JourneyOps.mjs
CHANGED
|
@@ -6,11 +6,18 @@ import { getRealmManagedUser, replaceAll } from './utils/OpsUtils';
|
|
|
6
6
|
import storage from '../storage/SessionStorage';
|
|
7
7
|
import { getNode, putNode, deleteNode, getNodeTypes, getNodesByType } from '../api/NodeApi';
|
|
8
8
|
import { isCloudOnlyNode, isCustomNode, isPremiumNode } from './NodeOps';
|
|
9
|
+
import * as Node from './NodeOps';
|
|
10
|
+
import * as EmailTemplate from './EmailTemplateOps';
|
|
11
|
+
import * as Script from './ScriptOps';
|
|
12
|
+
import * as Theme from './ThemeOps';
|
|
13
|
+
import * as Idp from './IdpOps';
|
|
14
|
+
import * as Saml2 from './Saml2Ops';
|
|
15
|
+
import * as CirclesOfTrust from './CirclesOfTrustOps';
|
|
9
16
|
import { getTrees, getTree, putTree, deleteTree } from '../api/TreeApi';
|
|
10
17
|
import { getEmailTemplate, putEmailTemplate } from '../api/EmailTemplateApi';
|
|
11
18
|
import { getScript } from '../api/ScriptApi';
|
|
12
19
|
import * as global from '../storage/StaticStorage';
|
|
13
|
-
import { printMessage, createProgressIndicator, updateProgressIndicator, stopProgressIndicator, createTable } from './utils/Console';
|
|
20
|
+
import { printMessage, createProgressIndicator, updateProgressIndicator, stopProgressIndicator, createTable, debugMessage } from './utils/Console';
|
|
14
21
|
import wordwrap from './utils/Wordwrap';
|
|
15
22
|
import { getProviderByLocationAndId, getProviders, getProviderMetadata, createProvider, findProviders, updateProvider } from '../api/Saml2Api';
|
|
16
23
|
import { createCircleOfTrust, getCirclesOfTrust, updateCircleOfTrust } from '../api/CirclesOfTrustApi';
|
|
@@ -22,8 +29,22 @@ const containerNodes = ['PageNode', 'CustomPageNode'];
|
|
|
22
29
|
const scriptedNodes = ['ConfigProviderNode', 'ScriptedDecisionNode', 'ClientScriptNode', 'SocialProviderHandlerNode', 'CustomScriptNode'];
|
|
23
30
|
const emailTemplateNodes = ['EmailSuspendNode', 'EmailTemplateNode'];
|
|
24
31
|
const emptyScriptPlaceholder = '[Empty]';
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Get a one-line description of the tree object
|
|
34
|
+
* @param {TreeSkeleton} treeObj circle of trust object to describe
|
|
35
|
+
* @returns {string} a one-line description
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
export function getOneLineDescription(treeObj) {
|
|
39
|
+
const description = `[${treeObj._id['brightCyan']}]`;
|
|
40
|
+
return description;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create an empty single tree export template
|
|
44
|
+
* @returns {SingleTreeExportInterface} an empty single tree export template
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
export function createSingleTreeExportTemplate() {
|
|
27
48
|
return {
|
|
28
49
|
meta: {},
|
|
29
50
|
innerNodes: {},
|
|
@@ -37,8 +58,12 @@ export function createSingleJourneyExportTemplate() {
|
|
|
37
58
|
tree: {}
|
|
38
59
|
};
|
|
39
60
|
}
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Create an empty multi tree export template
|
|
63
|
+
* @returns {MultiTreeExportInterface} an empty multi tree export template
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
export function createMultiTreeExportTemplate() {
|
|
42
67
|
return {
|
|
43
68
|
meta: {},
|
|
44
69
|
trees: {}
|
|
@@ -126,39 +151,22 @@ async function getSaml2NodeDependencies(nodeObject, allProviders, allCirclesOfTr
|
|
|
126
151
|
};
|
|
127
152
|
return saml2NodeDependencies;
|
|
128
153
|
}
|
|
129
|
-
}
|
|
130
|
-
// const nodeList = Object.entries(treeObject.nodes);
|
|
131
|
-
// const results = await Promise.allSettled(
|
|
132
|
-
// nodeList.map(
|
|
133
|
-
// async ([nodeId, nodeInfo]) => await getNode(nodeId, nodeInfo['nodeType'])
|
|
134
|
-
// )
|
|
135
|
-
// );
|
|
136
|
-
// const nodes = results.filter((r) => r.status === 'fulfilled');
|
|
137
|
-
// nodes.map((f) => {
|
|
138
|
-
// return f.status;
|
|
139
|
-
// });
|
|
140
|
-
// const failedList = results.filter((r) => r.status === 'rejected');
|
|
141
|
-
// return nodes;
|
|
142
|
-
// }
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Export options
|
|
146
|
-
*/
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
}
|
|
149
155
|
/**
|
|
150
156
|
* Create export data for a tree/journey with all its nodes and dependencies. The export data can be written to a file as is.
|
|
151
157
|
* @param {string} treeId tree id/name
|
|
152
|
-
* @param {
|
|
153
|
-
* @returns {Promise<
|
|
158
|
+
* @param {TreeExportOptions} options export options
|
|
159
|
+
* @returns {Promise<SingleTreeExportInterface>} a promise that resolves to an object containing the tree and all its nodes and dependencies
|
|
154
160
|
*/
|
|
161
|
+
|
|
162
|
+
|
|
155
163
|
export async function exportJourney(treeId, options = {
|
|
156
164
|
useStringArrays: true,
|
|
157
165
|
deps: true,
|
|
158
166
|
verbose: false
|
|
159
167
|
}) {
|
|
160
168
|
const treeObject = await getTree(treeId);
|
|
161
|
-
const exportData =
|
|
169
|
+
const exportData = createSingleTreeExportTemplate();
|
|
162
170
|
const {
|
|
163
171
|
useStringArrays,
|
|
164
172
|
deps,
|
|
@@ -456,7 +464,7 @@ export async function getJourneys() {
|
|
|
456
464
|
* Export journey by id/name to file
|
|
457
465
|
* @param {string} journeyId journey id/name
|
|
458
466
|
* @param {string} file optional export file name
|
|
459
|
-
* @param {
|
|
467
|
+
* @param {TreeExportOptions} options export options
|
|
460
468
|
*/
|
|
461
469
|
|
|
462
470
|
export async function exportJourneyToFile(journeyId, file, options) {
|
|
@@ -484,10 +492,14 @@ export async function exportJourneyToFile(journeyId, file, options) {
|
|
|
484
492
|
/**
|
|
485
493
|
* Export all journeys to file
|
|
486
494
|
* @param {string} file optional export file name
|
|
487
|
-
* @param {
|
|
495
|
+
* @param {TreeExportOptions} options export options
|
|
488
496
|
*/
|
|
489
497
|
|
|
490
|
-
export async function exportJourneysToFile(file, options
|
|
498
|
+
export async function exportJourneysToFile(file, options = {
|
|
499
|
+
deps: false,
|
|
500
|
+
useStringArrays: false,
|
|
501
|
+
verbose: false
|
|
502
|
+
}) {
|
|
491
503
|
let fileName = file;
|
|
492
504
|
|
|
493
505
|
if (!fileName) {
|
|
@@ -495,7 +507,7 @@ export async function exportJourneysToFile(file, options) {
|
|
|
495
507
|
}
|
|
496
508
|
|
|
497
509
|
const trees = (await getTrees()).result;
|
|
498
|
-
const fileData =
|
|
510
|
+
const fileData = createMultiTreeExportTemplate();
|
|
499
511
|
createProgressIndicator(trees.length, 'Exporting journeys...');
|
|
500
512
|
|
|
501
513
|
for (const tree of trees) {
|
|
@@ -515,7 +527,7 @@ export async function exportJourneysToFile(file, options) {
|
|
|
515
527
|
}
|
|
516
528
|
/**
|
|
517
529
|
* Export all journeys to separate files
|
|
518
|
-
* @param {
|
|
530
|
+
* @param {TreeExportOptions} options export options
|
|
519
531
|
*/
|
|
520
532
|
|
|
521
533
|
export async function exportJourneysToFiles(options) {
|
|
@@ -535,15 +547,12 @@ export async function exportJourneysToFiles(options) {
|
|
|
535
547
|
|
|
536
548
|
stopProgressIndicator('Done');
|
|
537
549
|
}
|
|
538
|
-
/**
|
|
539
|
-
* Import options
|
|
540
|
-
*/
|
|
541
|
-
|
|
542
550
|
/**
|
|
543
551
|
* Helper to import a tree with all dependencies from an import data object (typically read from a file)
|
|
544
|
-
* @param {
|
|
545
|
-
* @param {
|
|
552
|
+
* @param {SingleTreeExportInterface} treeObject tree object containing tree and all its dependencies
|
|
553
|
+
* @param {TreeImportOptions} options import options
|
|
546
554
|
*/
|
|
555
|
+
|
|
547
556
|
export async function importJourney(treeObject, options) {
|
|
548
557
|
const {
|
|
549
558
|
reUuid,
|
|
@@ -795,7 +804,7 @@ export async function importJourney(treeObject, options) {
|
|
|
795
804
|
// and the node's identityResource is the same as the tree's identityResource
|
|
796
805
|
// change it to the current realm managed user identityResource otherwise leave it alone.
|
|
797
806
|
|
|
798
|
-
if (nodeData
|
|
807
|
+
if (nodeData.identityResource && nodeData.identityResource.endsWith('user') && nodeData.identityResource === treeObject.tree.identityResource) {
|
|
799
808
|
nodeData['identityResource'] = `managed/${getRealmManagedUser()}`;
|
|
800
809
|
if (verbose) printMessage(`\n - identityResource: ${nodeData['identityResource']}`, 'info', false);
|
|
801
810
|
}
|
|
@@ -868,7 +877,7 @@ export async function importJourney(treeObject, options) {
|
|
|
868
877
|
var _importError$response9, _importError$response10;
|
|
869
878
|
|
|
870
879
|
printMessage(((_importError$response9 = importError.response) === null || _importError$response9 === void 0 ? void 0 : _importError$response9.data) || importError, 'error');
|
|
871
|
-
|
|
880
|
+
debugMessage(((_importError$response10 = importError.response) === null || _importError$response10 === void 0 ? void 0 : _importError$response10.data) || importError);
|
|
872
881
|
throw new Error(`\nError importing journey flow ${treeId}`);
|
|
873
882
|
}
|
|
874
883
|
}
|
|
@@ -940,7 +949,7 @@ async function resolveDependencies(installedJorneys, journeyMap, unresolvedJourn
|
|
|
940
949
|
* Import a journey from file
|
|
941
950
|
* @param {string} journeyId journey id/name
|
|
942
951
|
* @param {string} file import file name
|
|
943
|
-
* @param {
|
|
952
|
+
* @param {TreeImportOptions} options import options
|
|
944
953
|
*/
|
|
945
954
|
|
|
946
955
|
|
|
@@ -996,7 +1005,7 @@ export async function importJourneyFromFile(journeyId, file, options) {
|
|
|
996
1005
|
/**
|
|
997
1006
|
* Import first journey from file
|
|
998
1007
|
* @param {string} file import file name
|
|
999
|
-
* @param {
|
|
1008
|
+
* @param {TreeImportOptions} options import options
|
|
1000
1009
|
*/
|
|
1001
1010
|
|
|
1002
1011
|
export async function importFirstJourneyFromFile(file, options) {
|
|
@@ -1061,7 +1070,7 @@ export async function importFirstJourneyFromFile(file, options) {
|
|
|
1061
1070
|
/**
|
|
1062
1071
|
* Helper to import multiple trees from a tree map
|
|
1063
1072
|
* @param {Object} treesMap map of trees object
|
|
1064
|
-
* @param {
|
|
1073
|
+
* @param {TreeImportOptions} options import options
|
|
1065
1074
|
*/
|
|
1066
1075
|
|
|
1067
1076
|
async function importAllJourneys(treesMap, options) {
|
|
@@ -1098,7 +1107,7 @@ async function importAllJourneys(treesMap, options) {
|
|
|
1098
1107
|
/**
|
|
1099
1108
|
* Import all journeys from file
|
|
1100
1109
|
* @param {string} file import file name
|
|
1101
|
-
* @param {
|
|
1110
|
+
* @param {TreeImportOptions} options import options
|
|
1102
1111
|
*/
|
|
1103
1112
|
|
|
1104
1113
|
|
|
@@ -1111,7 +1120,7 @@ export async function importJourneysFromFile(file, options) {
|
|
|
1111
1120
|
}
|
|
1112
1121
|
/**
|
|
1113
1122
|
* Import all journeys from separate files
|
|
1114
|
-
* @param {
|
|
1123
|
+
* @param {TreeImportOptions} options import options
|
|
1115
1124
|
*/
|
|
1116
1125
|
|
|
1117
1126
|
export async function importJourneysFromFiles(options) {
|
|
@@ -1129,92 +1138,270 @@ export async function importJourneysFromFiles(options) {
|
|
|
1129
1138
|
importAllJourneys(allJourneysData.trees, options);
|
|
1130
1139
|
}
|
|
1131
1140
|
/**
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1141
|
+
* Get the node reference obbject for a node object. Node reference objects
|
|
1142
|
+
* are used in a tree flow definition and within page nodes to reference
|
|
1143
|
+
* nodes. Among other things, node references contain all the non-configuration
|
|
1144
|
+
* meta data that exists for readaility, like the x/y coordinates of the node
|
|
1145
|
+
* and the display name chosen by the tree designer. The dislay name is the
|
|
1146
|
+
* only intuitive link between the graphical representation of the tree and
|
|
1147
|
+
* the node configurations that make up the tree.
|
|
1148
|
+
* @param nodeObj node object to retrieve the node reference object for
|
|
1149
|
+
* @param singleTreeExport tree export with or without dependencies
|
|
1150
|
+
* @returns {NodeRefSkeletonInterface | InnerNodeRefSkeletonInterface} node reference object
|
|
1134
1151
|
*/
|
|
1135
1152
|
|
|
1136
|
-
export function
|
|
1137
|
-
|
|
1153
|
+
export function getNodeRef(nodeObj, singleTreeExport) {
|
|
1154
|
+
if (singleTreeExport.tree.nodes[nodeObj._id]) {
|
|
1155
|
+
return singleTreeExport.tree.nodes[nodeObj._id];
|
|
1156
|
+
} else {
|
|
1157
|
+
for (const node of Object.values(singleTreeExport.nodes)) {
|
|
1158
|
+
if (containerNodes.includes(node._type._id)) {
|
|
1159
|
+
for (const nodeRef of node.nodes) {
|
|
1160
|
+
if (nodeRef._id === nodeObj._id) {
|
|
1161
|
+
return nodeRef;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1138
1167
|
|
|
1139
|
-
|
|
1168
|
+
return undefined;
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Default tree export resolver used to resolve a tree id/name to a full export
|
|
1172
|
+
* w/o dependencies of that tree from a platform instance.
|
|
1173
|
+
* @param {string} treeId id/name of the tree to resolve
|
|
1174
|
+
* @returns {TreeExportResolverInterface} tree export
|
|
1175
|
+
*/
|
|
1140
1176
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1177
|
+
export const onlineTreeExportResolver = async function (treeId) {
|
|
1178
|
+
debugMessage(`onlineTreeExportResolver(${treeId})`);
|
|
1179
|
+
return await exportJourney(treeId, {
|
|
1180
|
+
deps: false,
|
|
1181
|
+
useStringArrays: false,
|
|
1182
|
+
verbose: false
|
|
1183
|
+
});
|
|
1184
|
+
};
|
|
1185
|
+
/**
|
|
1186
|
+
* Tree export resolver used to resolve a tree id/name to a full export
|
|
1187
|
+
* of that tree from individual `treename.journey.json` export files.
|
|
1188
|
+
* @param {string} treeId id/name of the tree to resolve
|
|
1189
|
+
* @returns {TreeExportResolverInterface} tree export
|
|
1190
|
+
*/
|
|
1191
|
+
|
|
1192
|
+
export const fileByIdTreeExportResolver = async function (treeId) {
|
|
1193
|
+
debugMessage(`fileByIdTreeExportResolver(${treeId})`);
|
|
1194
|
+
let treeExport = createSingleTreeExportTemplate();
|
|
1195
|
+
const file = getTypedFilename(`${treeId}`, 'journey');
|
|
1196
|
+
debugMessage(`fileByIdTreeExportResolver: resolving '${treeId}' to ${file}`);
|
|
1197
|
+
|
|
1198
|
+
try {
|
|
1199
|
+
var _jsonData$tree;
|
|
1200
|
+
|
|
1201
|
+
const jsonData = JSON.parse(fs.readFileSync(file, 'utf8')); // did we resolve the tree we were asked to resolved?
|
|
1202
|
+
|
|
1203
|
+
if (((_jsonData$tree = jsonData.tree) === null || _jsonData$tree === void 0 ? void 0 : _jsonData$tree._id) === treeId) {
|
|
1204
|
+
treeExport = jsonData;
|
|
1205
|
+
} // check if this is a file with multiple trees and get journey by id
|
|
1206
|
+
else if (jsonData.trees && jsonData.trees[treeId]) {
|
|
1207
|
+
treeExport = jsonData.trees[treeId];
|
|
1208
|
+
}
|
|
1209
|
+
} catch (error) {//
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
return treeExport;
|
|
1213
|
+
};
|
|
1214
|
+
/**
|
|
1215
|
+
* Factory that creates a tree export resolver used to resolve a tree id
|
|
1216
|
+
* to a full export of that tree from a multi-tree export file.
|
|
1217
|
+
* @param {string} file multi-tree export file
|
|
1218
|
+
* @returns {TreeExportResolverInterface} tree export resolver
|
|
1219
|
+
*/
|
|
1220
|
+
|
|
1221
|
+
export function createFileParamTreeExportResolver(file) {
|
|
1222
|
+
const fileParamTreeExportResolver = async function (treeId) {
|
|
1223
|
+
debugMessage(`fileParamTreeExportResolver(${treeId})`);
|
|
1224
|
+
let treeExport = createSingleTreeExportTemplate();
|
|
1225
|
+
|
|
1226
|
+
try {
|
|
1227
|
+
var _jsonData$tree2;
|
|
1228
|
+
|
|
1229
|
+
const jsonData = JSON.parse(fs.readFileSync(file, 'utf8')); // did we resolve the tree we were asked to resolved?
|
|
1230
|
+
|
|
1231
|
+
if (((_jsonData$tree2 = jsonData.tree) === null || _jsonData$tree2 === void 0 ? void 0 : _jsonData$tree2._id) === treeId) {
|
|
1232
|
+
treeExport = jsonData;
|
|
1233
|
+
} // check if this is a file with multiple trees and get journey by id
|
|
1234
|
+
else if (jsonData.trees && jsonData.trees[treeId]) {
|
|
1235
|
+
treeExport = jsonData.trees[treeId];
|
|
1236
|
+
} // fall back to fileByIdTreeExportResolver
|
|
1237
|
+
else {
|
|
1238
|
+
treeExport = await fileByIdTreeExportResolver(treeId);
|
|
1239
|
+
}
|
|
1240
|
+
} catch (error) {//
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
return treeExport;
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
debugMessage('fileParamTreeExportResolver:');
|
|
1247
|
+
debugMessage(fileParamTreeExportResolver);
|
|
1248
|
+
return fileParamTreeExportResolver;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Get tree dependencies (all descendent inner trees)
|
|
1252
|
+
* @param {SingleTreeExportInterface} treeExport single tree export
|
|
1253
|
+
* @param {string[]} resolvedTreeIds list of tree ids wich have already been resolved
|
|
1254
|
+
* @param {TreeExportResolverInterface} resolveTreeExport tree export resolver callback function
|
|
1255
|
+
* @returns {Promise<TreeDependencyMapInterface>} a promise that resolves to a tree dependency map
|
|
1256
|
+
*/
|
|
1257
|
+
|
|
1258
|
+
export async function getTreeDescendents(treeExport, resolveTreeExport = onlineTreeExportResolver, resolvedTreeIds = []) {
|
|
1259
|
+
debugMessage(`getTreeDependencies(${treeExport.tree._id}, [${resolvedTreeIds.join(', ')}])`);
|
|
1260
|
+
|
|
1261
|
+
if (!resolvedTreeIds.includes(treeExport.tree._id)) {
|
|
1262
|
+
resolvedTreeIds.push(treeExport.tree._id);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
const treeDependencyMap = {
|
|
1266
|
+
[treeExport.tree._id]: []
|
|
1267
|
+
};
|
|
1268
|
+
const dependencies = [];
|
|
1269
|
+
|
|
1270
|
+
for (const [nodeId, node] of Object.entries(treeExport.tree.nodes)) {
|
|
1271
|
+
const innerTreeId = treeExport.nodes[nodeId].tree;
|
|
1272
|
+
|
|
1273
|
+
if (node.nodeType === 'InnerTreeEvaluatorNode' && !resolvedTreeIds.includes(innerTreeId)) {
|
|
1274
|
+
const innerTreeExport = await resolveTreeExport(innerTreeId);
|
|
1275
|
+
debugMessage(`resolved inner tree: ${innerTreeExport.tree._id}`); // resolvedTreeIds.push(innerTreeId);
|
|
1276
|
+
|
|
1277
|
+
dependencies.push(await getTreeDescendents(innerTreeExport, resolveTreeExport, resolvedTreeIds));
|
|
1146
1278
|
}
|
|
1147
1279
|
}
|
|
1148
1280
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1281
|
+
treeDependencyMap[treeExport.tree._id] = dependencies;
|
|
1282
|
+
return treeDependencyMap;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
function describeTreeDescendents(descendents, depth = 0) {
|
|
1286
|
+
if ([Object.values(descendents)].length) {
|
|
1287
|
+
// heading
|
|
1288
|
+
if (depth === 0) {
|
|
1289
|
+
printMessage(`\nInner Tree Dependencies (${Object.values(descendents)[0].length}):`, 'data');
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
const indent = Array(depth * 2).fill(' ').join('');
|
|
1293
|
+
const [tree] = Object.keys(descendents);
|
|
1294
|
+
printMessage(`${indent}- ${tree}`, 'data');
|
|
1295
|
+
|
|
1296
|
+
for (const descendent of descendents[tree]) {
|
|
1297
|
+
describeTreeDescendents(descendent, depth + 1);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Describe a journey:
|
|
1303
|
+
* - Properties, tags, description, name, metadata
|
|
1304
|
+
* - Inner tree dependency tree
|
|
1305
|
+
* - Node type summary
|
|
1306
|
+
* - Nodes
|
|
1307
|
+
* - Themes
|
|
1308
|
+
* - Scripts
|
|
1309
|
+
* - Email templates
|
|
1310
|
+
* - Social identity providers
|
|
1311
|
+
* - SAML2 entity providers
|
|
1312
|
+
* - SAML2 circles of trust
|
|
1313
|
+
* @param {SingleTreeExportInterface} journeyData journey export object
|
|
1314
|
+
* @param {TreeExportResolverInterface} resolveTreeExport tree export resolver callback function
|
|
1315
|
+
*/
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
export async function describeJourney(journeyData, resolveTreeExport = onlineTreeExportResolver) {
|
|
1319
|
+
var _journeyData$themes;
|
|
1320
|
+
|
|
1321
|
+
const allNodes = { ...journeyData.nodes,
|
|
1322
|
+
...journeyData.innerNodes
|
|
1323
|
+
};
|
|
1324
|
+
const nodeTypeMap = {};
|
|
1325
|
+
|
|
1326
|
+
for (const nodeData of Object.values(allNodes)) {
|
|
1327
|
+
if (nodeTypeMap[nodeData._type._id]) {
|
|
1328
|
+
nodeTypeMap[nodeData._type._id] += 1;
|
|
1152
1329
|
} else {
|
|
1153
|
-
nodeTypeMap[nodeData
|
|
1330
|
+
nodeTypeMap[nodeData._type._id] = 1;
|
|
1154
1331
|
}
|
|
1155
1332
|
}
|
|
1156
1333
|
|
|
1157
|
-
printMessage(
|
|
1158
|
-
|
|
1159
|
-
printMessage(line);
|
|
1334
|
+
printMessage(`${getOneLineDescription(journeyData.tree)}`, 'data');
|
|
1335
|
+
printMessage(Array(`[${journeyData.tree._id}]`['length']).fill('=').join(''));
|
|
1160
1336
|
|
|
1161
1337
|
if (journeyData.tree.description) {
|
|
1162
|
-
printMessage(`\n${journeyData.tree.description}
|
|
1338
|
+
printMessage(`\n${journeyData.tree.description['brightYellow']}`, 'data');
|
|
1163
1339
|
}
|
|
1164
1340
|
|
|
1165
|
-
|
|
1341
|
+
const descendents = await getTreeDescendents(journeyData, resolveTreeExport);
|
|
1342
|
+
describeTreeDescendents(descendents);
|
|
1166
1343
|
|
|
1167
1344
|
if (Object.entries(nodeTypeMap).length) {
|
|
1345
|
+
printMessage(`\nNode Types (${Object.entries(nodeTypeMap).length}):`, 'data');
|
|
1346
|
+
|
|
1168
1347
|
for (const [name, count] of Object.entries(nodeTypeMap)) {
|
|
1169
|
-
printMessage(`-
|
|
1348
|
+
printMessage(`- ${String(count)} [${name['brightCyan']}]`, 'data');
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
if (Object.entries(allNodes).length) {
|
|
1353
|
+
printMessage(`\nNodes (${Object.entries(allNodes).length}):`, 'data');
|
|
1354
|
+
|
|
1355
|
+
for (const nodeObj of Object.values(allNodes)) {
|
|
1356
|
+
printMessage(`- ${Node.getOneLineDescription(nodeObj, getNodeRef(nodeObj, journeyData))}`, 'data');
|
|
1170
1357
|
}
|
|
1171
1358
|
}
|
|
1172
1359
|
|
|
1173
1360
|
if ((_journeyData$themes = journeyData.themes) !== null && _journeyData$themes !== void 0 && _journeyData$themes.length) {
|
|
1174
|
-
printMessage(
|
|
1361
|
+
printMessage(`\nThemes (${journeyData.themes.length}):`, 'data');
|
|
1175
1362
|
|
|
1176
1363
|
for (const themeData of journeyData.themes) {
|
|
1177
|
-
printMessage(`-
|
|
1364
|
+
printMessage(`- ${Theme.getOneLineDescription(themeData)}`, 'data');
|
|
1178
1365
|
}
|
|
1179
1366
|
}
|
|
1180
1367
|
|
|
1181
1368
|
if (Object.entries(journeyData.scripts).length) {
|
|
1182
|
-
printMessage(
|
|
1369
|
+
printMessage(`\nScripts (${Object.entries(journeyData.scripts).length}):`, 'data');
|
|
1183
1370
|
|
|
1184
1371
|
for (const scriptData of Object.values(journeyData.scripts)) {
|
|
1185
|
-
printMessage(`-
|
|
1372
|
+
printMessage(`- ${Script.getOneLineDescription(scriptData)}`, 'data');
|
|
1186
1373
|
}
|
|
1187
1374
|
}
|
|
1188
1375
|
|
|
1189
1376
|
if (Object.entries(journeyData.emailTemplates).length) {
|
|
1190
|
-
printMessage(
|
|
1377
|
+
printMessage(`\nEmail Templates (${Object.entries(journeyData.emailTemplates).length}):`, 'data');
|
|
1191
1378
|
|
|
1192
1379
|
for (const templateData of Object.values(journeyData.emailTemplates)) {
|
|
1193
|
-
printMessage(`- ${
|
|
1380
|
+
printMessage(`- ${EmailTemplate.getOneLineDescription(templateData)}`, 'data');
|
|
1194
1381
|
}
|
|
1195
1382
|
}
|
|
1196
1383
|
|
|
1197
1384
|
if (Object.entries(journeyData.socialIdentityProviders).length) {
|
|
1198
|
-
printMessage(
|
|
1385
|
+
printMessage(`\nSocial Identity Providers (${Object.entries(journeyData.socialIdentityProviders).length}):`, 'data');
|
|
1199
1386
|
|
|
1200
1387
|
for (const socialIdpData of Object.values(journeyData.socialIdentityProviders)) {
|
|
1201
|
-
printMessage(`- ${socialIdpData
|
|
1388
|
+
printMessage(`- ${Idp.getOneLineDescription(socialIdpData)}`, 'data');
|
|
1202
1389
|
}
|
|
1203
1390
|
}
|
|
1204
1391
|
|
|
1205
1392
|
if (Object.entries(journeyData.saml2Entities).length) {
|
|
1206
|
-
printMessage(
|
|
1393
|
+
printMessage(`\nSAML2 Entity Providers (${Object.entries(journeyData.saml2Entities).length}):`, 'data');
|
|
1207
1394
|
|
|
1208
1395
|
for (const entityProviderData of Object.values(journeyData.saml2Entities)) {
|
|
1209
|
-
printMessage(`- ${entityProviderData
|
|
1396
|
+
printMessage(`- ${Saml2.getOneLineDescription(entityProviderData)}`, 'data');
|
|
1210
1397
|
}
|
|
1211
1398
|
}
|
|
1212
1399
|
|
|
1213
1400
|
if (Object.entries(journeyData.circlesOfTrust).length) {
|
|
1214
|
-
printMessage(
|
|
1401
|
+
printMessage(`\nSAML2 Circles Of Trust (${Object.entries(journeyData.circlesOfTrust).length}):`, 'data');
|
|
1215
1402
|
|
|
1216
1403
|
for (const cotData of Object.values(journeyData.circlesOfTrust)) {
|
|
1217
|
-
printMessage(`- ${cotData
|
|
1404
|
+
printMessage(`- ${CirclesOfTrust.getOneLineDescription(cotData)}`, 'data');
|
|
1218
1405
|
}
|
|
1219
1406
|
}
|
|
1220
1407
|
}
|
|
@@ -1322,7 +1509,7 @@ export async function removeOrphanedNodes(orphanedNodes) {
|
|
|
1322
1509
|
}
|
|
1323
1510
|
/**
|
|
1324
1511
|
* Analyze if a journey contains any custom nodes considering the detected or the overridden version.
|
|
1325
|
-
* @param {
|
|
1512
|
+
* @param {SingleTreeExportInterface} journey Journey/tree configuration object
|
|
1326
1513
|
* @returns {boolean} True if the journey/tree contains any custom nodes, false otherwise.
|
|
1327
1514
|
*/
|
|
1328
1515
|
|
|
@@ -1339,7 +1526,7 @@ export function isCustomJourney(journey) {
|
|
|
1339
1526
|
}
|
|
1340
1527
|
/**
|
|
1341
1528
|
* Analyze if a journey contains any premium nodes considering the detected or the overridden version.
|
|
1342
|
-
* @param {
|
|
1529
|
+
* @param {SingleTreeExportInterface} journey Journey/tree configuration object
|
|
1343
1530
|
* @returns {boolean} True if the journey/tree contains any custom nodes, false otherwise.
|
|
1344
1531
|
*/
|
|
1345
1532
|
|
|
@@ -1356,7 +1543,7 @@ export function isPremiumJourney(journey) {
|
|
|
1356
1543
|
}
|
|
1357
1544
|
/**
|
|
1358
1545
|
* Analyze if a journey contains any cloud-only nodes considering the detected or the overridden version.
|
|
1359
|
-
* @param {
|
|
1546
|
+
* @param {SingleTreeExportInterface} journey Journey/tree configuration object
|
|
1360
1547
|
* @returns {boolean} True if the journey/tree contains any cloud-only nodes, false otherwise.
|
|
1361
1548
|
*/
|
|
1362
1549
|
|
|
@@ -1376,7 +1563,7 @@ export function isCloudOnlyJourney(journey) {
|
|
|
1376
1563
|
* - standard: can run on any instance of a ForgeRock platform
|
|
1377
1564
|
* - cloud: utilize nodes, which are exclusively available in the ForgeRock Identity Cloud
|
|
1378
1565
|
* - premium: utilizes nodes, which come at a premium
|
|
1379
|
-
* @param {
|
|
1566
|
+
* @param {SingleTreeExportInterface} journey journey export data
|
|
1380
1567
|
* @returns {string[]} an array of one or multiple classifications
|
|
1381
1568
|
*/
|
|
1382
1569
|
|
package/esm/ops/NodeOps.mjs
CHANGED
|
@@ -9,6 +9,17 @@ const containerNodes = ['PageNode', 'CustomPageNode'];
|
|
|
9
9
|
const scriptedNodes = ['ConfigProviderNode', 'ScriptedDecisionNode', 'ClientScriptNode', 'SocialProviderHandlerNode', 'CustomScriptNode'];
|
|
10
10
|
const emailTemplateNodes = ['EmailSuspendNode', 'EmailTemplateNode'];
|
|
11
11
|
const emptyScriptPlaceholder = '[Empty]';
|
|
12
|
+
/**
|
|
13
|
+
* Get a one-line description of the node
|
|
14
|
+
* @param {NodeSkeleton} nodeObj node object to describe
|
|
15
|
+
* @param {NodeRefSkeletonInterface | InnerNodeRefSkeletonInterface} nodeRef node reference object
|
|
16
|
+
* @returns {string} a one-line description
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export function getOneLineDescription(nodeObj, nodeRef) {
|
|
20
|
+
const description = `[${nodeObj._id['brightCyan']}] ${nodeObj._type._id}${nodeRef ? ' - ' + (nodeRef === null || nodeRef === void 0 ? void 0 : nodeRef.displayName['brightYellow']) : ''}`;
|
|
21
|
+
return description;
|
|
22
|
+
}
|
|
12
23
|
/**
|
|
13
24
|
* Helper to get all SAML2 dependencies for a given node object
|
|
14
25
|
* @param {Object} nodeObject node object
|
package/esm/ops/Saml2Ops.mjs
CHANGED
|
@@ -6,12 +6,30 @@ import { getProviders, findProviders, getProviderByLocationAndId, getProviderMet
|
|
|
6
6
|
import { getScript } from '../api/ScriptApi';
|
|
7
7
|
import { convertBase64TextToArray, convertBase64UrlTextToArray, convertTextArrayToBase64, convertTextArrayToBase64Url, getRealmString, getTypedFilename, saveJsonToFile, saveTextToFile, validateImport } from './utils/ExportImportUtils';
|
|
8
8
|
import { createOrUpdateScript } from './ScriptOps';
|
|
9
|
-
const roleMap = {
|
|
9
|
+
export const roleMap = {
|
|
10
10
|
identityProvider: 'IDP',
|
|
11
11
|
serviceProvider: 'SP',
|
|
12
12
|
attributeQueryProvider: 'AttrQuery',
|
|
13
13
|
xacmlPolicyEnforcementPoint: 'XACML PEP'
|
|
14
|
-
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Get a one-line description of the saml2 provider object
|
|
17
|
+
* @param {Saml2ProviderSkeleton} saml2ProviderObj saml2 provider object to describe
|
|
18
|
+
* @returns {string} a one-line description
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export function getOneLineDescription(saml2ProviderObj) {
|
|
22
|
+
const roles = [];
|
|
23
|
+
|
|
24
|
+
for (const [key, value] of Object.entries(roleMap)) {
|
|
25
|
+
if (saml2ProviderObj[key]) {
|
|
26
|
+
roles.push(value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const description = `[${saml2ProviderObj.entityId['brightCyan']}]${' (' + saml2ProviderObj.entityLocation}${roles.length ? ' ' + roles.join(', ') + ')' : ')'}`;
|
|
31
|
+
return description;
|
|
32
|
+
} // use a function vs a template variable to avoid problems in loops
|
|
15
33
|
|
|
16
34
|
function getFileDataTemplate() {
|
|
17
35
|
return {
|
package/esm/ops/ScriptOps.mjs
CHANGED
|
@@ -6,6 +6,16 @@ import { getScriptByName, getScripts, putScript } from '../api/ScriptApi';
|
|
|
6
6
|
import wordwrap from './utils/Wordwrap';
|
|
7
7
|
import { convertBase64TextToArray, convertTextArrayToBase64, getTypedFilename, saveToFile, titleCase, validateImport } from './utils/ExportImportUtils';
|
|
8
8
|
import storage from '../storage/SessionStorage';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get a one-line description of the script object
|
|
12
|
+
* @param {ScriptSkeleton} scriptObj script object to describe
|
|
13
|
+
* @returns {string} a one-line description
|
|
14
|
+
*/
|
|
15
|
+
export function getOneLineDescription(scriptObj) {
|
|
16
|
+
const description = `[${scriptObj._id['brightCyan']}] ${scriptObj.context} - ${scriptObj.name['brightYellow']}`;
|
|
17
|
+
return description;
|
|
18
|
+
}
|
|
9
19
|
/**
|
|
10
20
|
* List scripts
|
|
11
21
|
*/
|
package/esm/ops/ThemeOps.mjs
CHANGED
|
@@ -2,6 +2,16 @@ import fs from 'fs';
|
|
|
2
2
|
import { deleteTheme, deleteThemeByName, deleteThemes, getTheme, getThemeByName, getThemes, putTheme, putThemeByName, putThemes } from '../api/ThemeApi';
|
|
3
3
|
import { createProgressIndicator, createTable, printMessage, stopProgressIndicator, updateProgressIndicator } from './utils/Console';
|
|
4
4
|
import { getRealmString, getTypedFilename, saveToFile, validateImport } from './utils/ExportImportUtils';
|
|
5
|
+
/**
|
|
6
|
+
* Get a one-line description of the theme
|
|
7
|
+
* @param {ThemeSkeleton} themeObj theme object to describe
|
|
8
|
+
* @returns {string} a one-line description
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export function getOneLineDescription(themeObj) {
|
|
12
|
+
const description = `[${themeObj._id['brightCyan']}] ${themeObj.name['brightYellow']}${themeObj.linkedTrees ? ' (' + themeObj.linkedTrees.join(', ')['brightCyan'] + ')' : ''}`;
|
|
13
|
+
return description;
|
|
14
|
+
}
|
|
5
15
|
/**
|
|
6
16
|
* List all the themes
|
|
7
17
|
* @param {boolean} long Long version, more fields
|