snow-flow-test 10.0.1-test.111 → 10.0.1-test.112
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/package.json
CHANGED
|
@@ -45,8 +45,67 @@ var _bootstrapPromise: Promise<{ namespace: string; apiSysId: string }> | null =
|
|
|
45
45
|
* This runs server-side on ServiceNow and triggers all Business Rules,
|
|
46
46
|
* unlike direct Table API inserts which skip sys_hub_flow_version creation.
|
|
47
47
|
*/
|
|
48
|
+
/**
|
|
49
|
+
* Discover script — GET /discover endpoint.
|
|
50
|
+
* Probes which sn_fd APIs, methods and fields are available on this instance.
|
|
51
|
+
*/
|
|
52
|
+
var FLOW_FACTORY_DISCOVER_SCRIPT = [
|
|
53
|
+
'(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {',
|
|
54
|
+
' var r = {',
|
|
55
|
+
' build_tag: gs.getProperty("glide.buildtag") || "unknown",',
|
|
56
|
+
' build_name: gs.getProperty("glide.buildname") || "unknown",',
|
|
57
|
+
' apis: {}, methods: {}, fields: {}',
|
|
58
|
+
' };',
|
|
59
|
+
' try { r.apis.sn_fd = typeof sn_fd !== "undefined" ? "available" : "unavailable"; } catch(e) { r.apis.sn_fd = "unavailable"; }',
|
|
60
|
+
' var apiNames = ["FlowDesigner","FlowAPI","FlowPublisher","FlowCompiler"];',
|
|
61
|
+
' for (var i = 0; i < apiNames.length; i++) {',
|
|
62
|
+
' try {',
|
|
63
|
+
' if (typeof sn_fd !== "undefined") { r.apis[apiNames[i]] = typeof sn_fd[apiNames[i]]; }',
|
|
64
|
+
' else { r.apis[apiNames[i]] = "no_sn_fd"; }',
|
|
65
|
+
' } catch(e) { r.apis[apiNames[i]] = "error:" + e; }',
|
|
66
|
+
' }',
|
|
67
|
+
' var globalNames = ["GlideFlowDesigner","FlowDesignerInternalAPI","FlowDesignerAPI"];',
|
|
68
|
+
' for (var g = 0; g < globalNames.length; g++) {',
|
|
69
|
+
' try {',
|
|
70
|
+
' var gv = this[globalNames[g]];',
|
|
71
|
+
' r.apis[globalNames[g]] = gv ? typeof gv : "undefined";',
|
|
72
|
+
' } catch(e) { r.apis[globalNames[g]] = "error:" + e; }',
|
|
73
|
+
' }',
|
|
74
|
+
' try {',
|
|
75
|
+
' if (typeof sn_fd !== "undefined" && sn_fd.FlowDesigner) {',
|
|
76
|
+
' var fd = sn_fd.FlowDesigner;',
|
|
77
|
+
' var mns = ["createFlow","publishFlow","activateFlow","compileFlow","createDraftFlow","getFlow"];',
|
|
78
|
+
' for (var m = 0; m < mns.length; m++) { r.methods[mns[m]] = typeof fd[mns[m]]; }',
|
|
79
|
+
' }',
|
|
80
|
+
' } catch(e) { r.methods._error = e + ""; }',
|
|
81
|
+
' try {',
|
|
82
|
+
' var gr = new GlideRecord("sys_hub_flow_version");',
|
|
83
|
+
' var fns = ["compiled_definition","compile_state","is_current","published_flow","flow_definition"];',
|
|
84
|
+
' for (var f = 0; f < fns.length; f++) { r.fields[fns[f]] = gr.isValidField(fns[f]); }',
|
|
85
|
+
' } catch(e) { r.fields._error = e + ""; }',
|
|
86
|
+
' try {',
|
|
87
|
+
' var br = new GlideRecord("sys_script");',
|
|
88
|
+
' br.addQuery("collection","sys_hub_flow"); br.addQuery("active",true); br.query();',
|
|
89
|
+
' r.flow_br_count = br.getRowCount();',
|
|
90
|
+
' var brv = new GlideRecord("sys_script");',
|
|
91
|
+
' brv.addQuery("collection","sys_hub_flow_version"); brv.addQuery("active",true); brv.query();',
|
|
92
|
+
' r.version_br_count = brv.getRowCount();',
|
|
93
|
+
' } catch(e) { r.br_error = e + ""; }',
|
|
94
|
+
' response.setStatus(200);',
|
|
95
|
+
' response.setBody(r);',
|
|
96
|
+
'})(request, response);'
|
|
97
|
+
].join('\n');
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create script — POST /create endpoint.
|
|
101
|
+
* Three-tier approach:
|
|
102
|
+
* Tier 1: sn_fd.FlowDesigner API (handles everything internally)
|
|
103
|
+
* Tier 2: GlideRecord INSERT as draft → UPDATE to published (triggers compilation BRs)
|
|
104
|
+
* Tier 3: Raw GlideRecord INSERT (last resort, may not register with engine)
|
|
105
|
+
*/
|
|
48
106
|
var FLOW_FACTORY_SCRIPT = [
|
|
49
107
|
'(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {',
|
|
108
|
+
// ── Body parsing (3-method cascade) ──
|
|
50
109
|
' var body = null;',
|
|
51
110
|
' var parseLog = [];',
|
|
52
111
|
' try {',
|
|
@@ -69,7 +128,7 @@ var FLOW_FACTORY_SCRIPT = [
|
|
|
69
128
|
' response.setBody({ success: false, error: "No parseable body", parseLog: parseLog, bodyType: typeof request.body });',
|
|
70
129
|
' return;',
|
|
71
130
|
' }',
|
|
72
|
-
' var result = { success: false, steps: {}, parseLog: parseLog };',
|
|
131
|
+
' var result = { success: false, steps: {}, tier_used: null, parseLog: parseLog };',
|
|
73
132
|
'',
|
|
74
133
|
' try {',
|
|
75
134
|
' var flowName = body.name || "Unnamed Flow";',
|
|
@@ -84,170 +143,201 @@ var FLOW_FACTORY_SCRIPT = [
|
|
|
84
143
|
' var activities = body.activities || [];',
|
|
85
144
|
' var inputs = body.inputs || [];',
|
|
86
145
|
' var outputs = body.outputs || [];',
|
|
146
|
+
' var flowDef = body.flow_definition;',
|
|
147
|
+
' var flowDefStr = flowDef ? (typeof flowDef === "string" ? flowDef : JSON.stringify(flowDef)) : "";',
|
|
148
|
+
' var intName = flowName.toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");',
|
|
87
149
|
'',
|
|
88
|
-
'
|
|
89
|
-
' var
|
|
90
|
-
' flow.initialize();',
|
|
91
|
-
' flow.setValue("name", flowName);',
|
|
92
|
-
' flow.setValue("description", flowDesc);',
|
|
93
|
-
' flow.setValue("internal_name", flowName.toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, ""));',
|
|
94
|
-
' flow.setValue("category", flowCategory);',
|
|
95
|
-
' flow.setValue("run_as", runAs);',
|
|
96
|
-
' flow.setValue("active", shouldActivate);',
|
|
97
|
-
' flow.setValue("status", shouldActivate ? "published" : "draft");',
|
|
98
|
-
' flow.setValue("validated", true);',
|
|
99
|
-
' flow.setValue("type", isSubflow ? "subflow" : "flow");',
|
|
150
|
+
' var flowSysId = null;',
|
|
151
|
+
' var verSysId = null;',
|
|
100
152
|
'',
|
|
101
|
-
|
|
102
|
-
' flow.setValue("flow_definition", typeof body.flow_definition === "string" ? body.flow_definition : JSON.stringify(body.flow_definition));',
|
|
103
|
-
' flow.setValue("latest_snapshot", typeof body.flow_definition === "string" ? body.flow_definition : JSON.stringify(body.flow_definition));',
|
|
104
|
-
' }',
|
|
105
|
-
'',
|
|
106
|
-
' var flowSysId = flow.insert();',
|
|
107
|
-
' if (!flowSysId) {',
|
|
108
|
-
' result.error = "Failed to insert sys_hub_flow record";',
|
|
109
|
-
' response.setStatus(500);',
|
|
110
|
-
' response.setBody(result);',
|
|
111
|
-
' return;',
|
|
112
|
-
' }',
|
|
113
|
-
' result.steps.flow = { success: true, sys_id: flowSysId + "" };',
|
|
114
|
-
'',
|
|
115
|
-
' // Step 2: Create sys_hub_flow_version (this is what Table API misses!)',
|
|
153
|
+
// ── TIER 1: sn_fd.FlowDesigner API ──
|
|
116
154
|
' try {',
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
'
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
-
'
|
|
127
|
-
' if (body.flow_definition) {',
|
|
128
|
-
' ver.setValue("flow_definition", typeof body.flow_definition === "string" ? body.flow_definition : JSON.stringify(body.flow_definition));',
|
|
129
|
-
' }',
|
|
130
|
-
' var verSysId = ver.insert();',
|
|
131
|
-
' if (verSysId) {',
|
|
132
|
-
' result.steps.version = { success: true, sys_id: verSysId + "" };',
|
|
133
|
-
' // Update flow to point to latest version',
|
|
134
|
-
' var flowUpd = new GlideRecord("sys_hub_flow");',
|
|
135
|
-
' if (flowUpd.get(flowSysId)) {',
|
|
136
|
-
' flowUpd.setValue("latest_version", verSysId);',
|
|
137
|
-
' flowUpd.update();',
|
|
155
|
+
' if (typeof sn_fd !== "undefined" && sn_fd.FlowDesigner && typeof sn_fd.FlowDesigner.createFlow === "function") {',
|
|
156
|
+
' var fdResult = sn_fd.FlowDesigner.createFlow({ name: flowName, description: flowDesc, type: isSubflow ? "subflow" : "flow", category: flowCategory, run_as: runAs });',
|
|
157
|
+
' if (fdResult) {',
|
|
158
|
+
' flowSysId = (typeof fdResult === "object" ? fdResult.sys_id || fdResult.getValue("sys_id") : fdResult) + "";',
|
|
159
|
+
' result.tier_used = "sn_fd_api";',
|
|
160
|
+
' result.steps.tier1 = { success: true, api: "sn_fd.FlowDesigner.createFlow" };',
|
|
161
|
+
' if (shouldActivate && typeof sn_fd.FlowDesigner.publishFlow === "function") {',
|
|
162
|
+
' try { sn_fd.FlowDesigner.publishFlow(flowSysId); result.steps.tier1_publish = { success: true }; }',
|
|
163
|
+
' catch(pe) { result.steps.tier1_publish = { success: false, error: pe + "" }; }',
|
|
164
|
+
' }',
|
|
138
165
|
' }',
|
|
139
|
-
' } else {',
|
|
140
|
-
' result.steps.version = { success: false, error: "Insert returned empty sys_id" };',
|
|
141
166
|
' }',
|
|
142
|
-
' } catch (
|
|
143
|
-
' result.steps.version = { success: false, error: verErr.getMessage ? verErr.getMessage() : verErr + "" };',
|
|
144
|
-
' }',
|
|
167
|
+
' } catch(t1e) { result.steps.tier1 = { success: false, error: t1e.getMessage ? t1e.getMessage() : t1e + "" }; }',
|
|
145
168
|
'',
|
|
146
|
-
|
|
147
|
-
' if (!
|
|
169
|
+
// ── TIER 2: GlideRecord INSERT as draft → UPDATE to published ──
|
|
170
|
+
' if (!flowSysId) {',
|
|
148
171
|
' try {',
|
|
149
|
-
' var
|
|
150
|
-
'
|
|
151
|
-
'
|
|
152
|
-
'
|
|
153
|
-
'
|
|
154
|
-
'
|
|
155
|
-
'
|
|
156
|
-
'
|
|
157
|
-
'
|
|
158
|
-
'
|
|
159
|
-
'
|
|
160
|
-
'
|
|
161
|
-
'
|
|
162
|
-
'
|
|
163
|
-
'
|
|
164
|
-
'
|
|
165
|
-
'
|
|
166
|
-
'
|
|
167
|
-
'
|
|
168
|
-
'
|
|
169
|
-
'
|
|
170
|
-
'
|
|
171
|
-
'
|
|
172
|
-
'
|
|
172
|
+
' var flow = new GlideRecord("sys_hub_flow");',
|
|
173
|
+
' flow.initialize();',
|
|
174
|
+
' flow.setValue("name", flowName);',
|
|
175
|
+
' flow.setValue("description", flowDesc);',
|
|
176
|
+
' flow.setValue("internal_name", intName);',
|
|
177
|
+
' flow.setValue("category", flowCategory);',
|
|
178
|
+
' flow.setValue("run_as", runAs);',
|
|
179
|
+
' flow.setValue("active", false);',
|
|
180
|
+
' flow.setValue("status", "draft");',
|
|
181
|
+
' flow.setValue("validated", true);',
|
|
182
|
+
' flow.setValue("type", isSubflow ? "subflow" : "flow");',
|
|
183
|
+
' if (flowDefStr) { flow.setValue("flow_definition", flowDefStr); flow.setValue("latest_snapshot", flowDefStr); }',
|
|
184
|
+
' flowSysId = flow.insert();',
|
|
185
|
+
' result.steps.flow_insert = { success: !!flowSysId, sys_id: flowSysId + "", as_draft: true };',
|
|
186
|
+
'',
|
|
187
|
+
' if (flowSysId) {',
|
|
188
|
+
' var ver = new GlideRecord("sys_hub_flow_version");',
|
|
189
|
+
' ver.initialize();',
|
|
190
|
+
' ver.setValue("flow", flowSysId);',
|
|
191
|
+
' ver.setValue("name", "1.0");',
|
|
192
|
+
' ver.setValue("version", "1.0");',
|
|
193
|
+
' ver.setValue("state", "draft");',
|
|
194
|
+
' ver.setValue("active", true);',
|
|
195
|
+
' ver.setValue("compile_state", "draft");',
|
|
196
|
+
' ver.setValue("is_current", true);',
|
|
197
|
+
' if (flowDefStr) ver.setValue("flow_definition", flowDefStr);',
|
|
198
|
+
' verSysId = ver.insert();',
|
|
199
|
+
' result.steps.version_insert = { success: !!verSysId, sys_id: verSysId + "", as_draft: true };',
|
|
200
|
+
'',
|
|
201
|
+
' if (verSysId) {',
|
|
202
|
+
' var linkUpd = new GlideRecord("sys_hub_flow");',
|
|
203
|
+
' if (linkUpd.get(flowSysId)) { linkUpd.setValue("latest_version", verSysId); linkUpd.update(); }',
|
|
204
|
+
' }',
|
|
205
|
+
'',
|
|
206
|
+
' if (shouldActivate) {',
|
|
207
|
+
' var flowPub = new GlideRecord("sys_hub_flow");',
|
|
208
|
+
' if (flowPub.get(flowSysId)) {',
|
|
209
|
+
' flowPub.setValue("status", "published");',
|
|
210
|
+
' flowPub.setValue("active", true);',
|
|
211
|
+
' flowPub.update();',
|
|
212
|
+
' result.steps.flow_publish_update = { success: true };',
|
|
213
|
+
' }',
|
|
214
|
+
' if (verSysId) {',
|
|
215
|
+
' var verPub = new GlideRecord("sys_hub_flow_version");',
|
|
216
|
+
' if (verPub.get(verSysId)) {',
|
|
217
|
+
' verPub.setValue("state", "published");',
|
|
218
|
+
' verPub.setValue("compile_state", "compiled");',
|
|
219
|
+
' verPub.setValue("published_flow", flowSysId);',
|
|
220
|
+
' verPub.update();',
|
|
221
|
+
' result.steps.version_publish_update = { success: true };',
|
|
222
|
+
' }',
|
|
223
|
+
' }',
|
|
173
224
|
' }',
|
|
225
|
+
' result.tier_used = "gliderecord_draft_then_publish";',
|
|
226
|
+
' result.success = true;',
|
|
174
227
|
' }',
|
|
175
|
-
' } catch (
|
|
176
|
-
' result.steps.trigger = { success: false, error: trigErr.getMessage ? trigErr.getMessage() : trigErr + "" };',
|
|
177
|
-
' }',
|
|
228
|
+
' } catch(t2e) { result.steps.tier2 = { success: false, error: t2e.getMessage ? t2e.getMessage() : t2e + "" }; }',
|
|
178
229
|
' }',
|
|
179
230
|
'',
|
|
180
|
-
|
|
181
|
-
'
|
|
182
|
-
' for (var ai = 0; ai < activities.length; ai++) {',
|
|
231
|
+
// ── TIER 3: Raw GlideRecord INSERT (last resort) ──
|
|
232
|
+
' if (!flowSysId) {',
|
|
183
233
|
' try {',
|
|
184
|
-
' var
|
|
185
|
-
'
|
|
186
|
-
'
|
|
187
|
-
'
|
|
188
|
-
'
|
|
189
|
-
'
|
|
190
|
-
'
|
|
191
|
-
'
|
|
192
|
-
'
|
|
193
|
-
'
|
|
194
|
-
'
|
|
195
|
-
'
|
|
196
|
-
'
|
|
197
|
-
'
|
|
234
|
+
' var rawFlow = new GlideRecord("sys_hub_flow");',
|
|
235
|
+
' rawFlow.initialize();',
|
|
236
|
+
' rawFlow.setValue("name", flowName);',
|
|
237
|
+
' rawFlow.setValue("description", flowDesc);',
|
|
238
|
+
' rawFlow.setValue("internal_name", intName);',
|
|
239
|
+
' rawFlow.setValue("category", flowCategory);',
|
|
240
|
+
' rawFlow.setValue("run_as", runAs);',
|
|
241
|
+
' rawFlow.setValue("active", shouldActivate);',
|
|
242
|
+
' rawFlow.setValue("status", shouldActivate ? "published" : "draft");',
|
|
243
|
+
' rawFlow.setValue("validated", true);',
|
|
244
|
+
' rawFlow.setValue("type", isSubflow ? "subflow" : "flow");',
|
|
245
|
+
' if (flowDefStr) { rawFlow.setValue("flow_definition", flowDefStr); rawFlow.setValue("latest_snapshot", flowDefStr); }',
|
|
246
|
+
' flowSysId = rawFlow.insert();',
|
|
247
|
+
' if (flowSysId) {',
|
|
248
|
+
' var rawVer = new GlideRecord("sys_hub_flow_version");',
|
|
249
|
+
' rawVer.initialize();',
|
|
250
|
+
' rawVer.setValue("flow", flowSysId);',
|
|
251
|
+
' rawVer.setValue("name", "1.0"); rawVer.setValue("version", "1.0");',
|
|
252
|
+
' rawVer.setValue("state", shouldActivate ? "published" : "draft");',
|
|
253
|
+
' rawVer.setValue("active", true); rawVer.setValue("compile_state", "compiled");',
|
|
254
|
+
' rawVer.setValue("is_current", true);',
|
|
255
|
+
' if (shouldActivate) rawVer.setValue("published_flow", flowSysId);',
|
|
256
|
+
' if (flowDefStr) rawVer.setValue("flow_definition", flowDefStr);',
|
|
257
|
+
' verSysId = rawVer.insert();',
|
|
258
|
+
' if (verSysId) {',
|
|
259
|
+
' var rawLink = new GlideRecord("sys_hub_flow");',
|
|
260
|
+
' if (rawLink.get(flowSysId)) { rawLink.setValue("latest_version", verSysId); rawLink.update(); }',
|
|
261
|
+
' }',
|
|
262
|
+
' result.tier_used = "gliderecord_raw";',
|
|
263
|
+
' result.success = true;',
|
|
198
264
|
' }',
|
|
199
|
-
'
|
|
200
|
-
' } catch (actErr) {',
|
|
201
|
-
' // Best-effort per action',
|
|
202
|
-
' }',
|
|
265
|
+
' } catch(t3e) { result.steps.tier3 = { success: false, error: t3e.getMessage ? t3e.getMessage() : t3e + "" }; }',
|
|
203
266
|
' }',
|
|
204
|
-
' result.steps.actions = { success: true, created: actionsCreated, requested: activities.length };',
|
|
205
267
|
'',
|
|
206
|
-
|
|
207
|
-
'
|
|
208
|
-
'
|
|
209
|
-
'
|
|
268
|
+
// ── Common: trigger, actions, variables ──
|
|
269
|
+
' if (flowSysId) {',
|
|
270
|
+
' result.flow_sys_id = flowSysId + "";',
|
|
271
|
+
' result.version_sys_id = verSysId ? verSysId + "" : null;',
|
|
272
|
+
' result.version_created = !!verSysId;',
|
|
273
|
+
'',
|
|
274
|
+
' if (!isSubflow && triggerType !== "manual") {',
|
|
210
275
|
' try {',
|
|
211
|
-
' var
|
|
212
|
-
' var
|
|
213
|
-
'
|
|
214
|
-
'
|
|
215
|
-
'
|
|
216
|
-
'
|
|
217
|
-
'
|
|
218
|
-
'
|
|
219
|
-
'
|
|
220
|
-
'
|
|
221
|
-
'
|
|
222
|
-
'
|
|
276
|
+
' var triggerMap = { "record_created": "sn_fd.trigger.record_created", "record_updated": "sn_fd.trigger.record_updated", "scheduled": "sn_fd.trigger.scheduled" };',
|
|
277
|
+
' var trigIntName = triggerMap[triggerType] || "";',
|
|
278
|
+
' if (trigIntName) {',
|
|
279
|
+
' var trigDef = new GlideRecord("sys_hub_action_type_definition");',
|
|
280
|
+
' trigDef.addQuery("internal_name", trigIntName); trigDef.query();',
|
|
281
|
+
' if (trigDef.next()) {',
|
|
282
|
+
' var trigInst = new GlideRecord("sys_hub_trigger_instance");',
|
|
283
|
+
' trigInst.initialize();',
|
|
284
|
+
' trigInst.setValue("flow", flowSysId); trigInst.setValue("action_type", trigDef.getUniqueValue());',
|
|
285
|
+
' trigInst.setValue("name", triggerType); trigInst.setValue("order", 0); trigInst.setValue("active", true);',
|
|
286
|
+
' if (triggerTable) trigInst.setValue("table", triggerTable);',
|
|
287
|
+
' if (triggerCondition) trigInst.setValue("condition", triggerCondition);',
|
|
288
|
+
' var trigSysId = trigInst.insert();',
|
|
289
|
+
' result.steps.trigger = { success: !!trigSysId, sys_id: trigSysId + "" };',
|
|
290
|
+
' } else { result.steps.trigger = { success: false, error: "Trigger def not found: " + trigIntName }; }',
|
|
291
|
+
' }',
|
|
292
|
+
' } catch(te) { result.steps.trigger = { success: false, error: te.getMessage ? te.getMessage() : te + "" }; }',
|
|
223
293
|
' }',
|
|
224
|
-
'
|
|
294
|
+
'',
|
|
295
|
+
' var actionsCreated = 0;',
|
|
296
|
+
' for (var ai = 0; ai < activities.length; ai++) {',
|
|
225
297
|
' try {',
|
|
226
|
-
' var
|
|
227
|
-
' var
|
|
228
|
-
'
|
|
229
|
-
'
|
|
230
|
-
'
|
|
231
|
-
'
|
|
232
|
-
'
|
|
233
|
-
'
|
|
234
|
-
' if (
|
|
235
|
-
'
|
|
298
|
+
' var act = activities[ai];',
|
|
299
|
+
' var actDef = new GlideRecord("sys_hub_action_type_definition");',
|
|
300
|
+
' actDef.addQuery("internal_name", "CONTAINS", act.type || "script");',
|
|
301
|
+
' actDef.addOrCondition("name", "CONTAINS", act.type || "script"); actDef.query();',
|
|
302
|
+
' var actInst = new GlideRecord("sys_hub_action_instance");',
|
|
303
|
+
' actInst.initialize();',
|
|
304
|
+
' actInst.setValue("flow", flowSysId); actInst.setValue("name", act.name || "Action " + (ai + 1));',
|
|
305
|
+
' actInst.setValue("order", (ai + 1) * 100); actInst.setValue("active", true);',
|
|
306
|
+
' if (actDef.next()) actInst.setValue("action_type", actDef.getUniqueValue());',
|
|
307
|
+
' if (actInst.insert()) actionsCreated++;',
|
|
308
|
+
' } catch(ae) {}',
|
|
309
|
+
' }',
|
|
310
|
+
' result.steps.actions = { success: true, created: actionsCreated, requested: activities.length };',
|
|
311
|
+
'',
|
|
312
|
+
' var varsCreated = 0;',
|
|
313
|
+
' if (isSubflow) {',
|
|
314
|
+
' for (var vi = 0; vi < inputs.length; vi++) {',
|
|
315
|
+
' try { var inp = inputs[vi]; var fv = new GlideRecord("sys_hub_flow_variable"); fv.initialize();',
|
|
316
|
+
' fv.setValue("flow",flowSysId); fv.setValue("name",inp.name); fv.setValue("label",inp.label||inp.name);',
|
|
317
|
+
' fv.setValue("type",inp.type||"string"); fv.setValue("mandatory",inp.mandatory||false);',
|
|
318
|
+
' fv.setValue("default_value",inp.default_value||""); fv.setValue("variable_type","input");',
|
|
319
|
+
' if (fv.insert()) varsCreated++;',
|
|
320
|
+
' } catch(ve) {}',
|
|
321
|
+
' }',
|
|
322
|
+
' for (var vo = 0; vo < outputs.length; vo++) {',
|
|
323
|
+
' try { var out = outputs[vo]; var ov = new GlideRecord("sys_hub_flow_variable"); ov.initialize();',
|
|
324
|
+
' ov.setValue("flow",flowSysId); ov.setValue("name",out.name); ov.setValue("label",out.label||out.name);',
|
|
325
|
+
' ov.setValue("type",out.type||"string"); ov.setValue("variable_type","output");',
|
|
326
|
+
' if (ov.insert()) varsCreated++;',
|
|
327
|
+
' } catch(ve) {}',
|
|
328
|
+
' }',
|
|
236
329
|
' }',
|
|
330
|
+
' result.steps.variables = { success: true, created: varsCreated };',
|
|
237
331
|
' }',
|
|
238
|
-
' result.steps.variables = { success: true, created: varsCreated };',
|
|
239
332
|
'',
|
|
240
|
-
' result.success
|
|
241
|
-
'
|
|
242
|
-
' result.version_created = !!(result.steps.version && result.steps.version.success);',
|
|
243
|
-
' response.setStatus(201);',
|
|
333
|
+
' if (result.success) response.setStatus(201);',
|
|
334
|
+
' else response.setStatus(500);',
|
|
244
335
|
'',
|
|
245
336
|
' } catch (e) {',
|
|
246
337
|
' result.success = false;',
|
|
247
338
|
' result.error = e.getMessage ? e.getMessage() : e + "";',
|
|
248
339
|
' response.setStatus(500);',
|
|
249
340
|
' }',
|
|
250
|
-
'',
|
|
251
341
|
' response.setBody(result);',
|
|
252
342
|
'})(request, response);'
|
|
253
343
|
].join('\n');
|
|
@@ -398,7 +488,7 @@ async function ensureFlowFactoryAPI(
|
|
|
398
488
|
name: 'create',
|
|
399
489
|
active: true,
|
|
400
490
|
relative_path: '/create',
|
|
401
|
-
short_description: 'Create a flow
|
|
491
|
+
short_description: 'Create a flow/subflow via 3-tier approach: sn_fd API → draft+publish → raw GlideRecord',
|
|
402
492
|
operation_script: FLOW_FACTORY_SCRIPT,
|
|
403
493
|
requires_authentication: true,
|
|
404
494
|
enforce_acl: 'false'
|
|
@@ -409,6 +499,23 @@ async function ensureFlowFactoryAPI(
|
|
|
409
499
|
throw new Error('Failed to create Scripted REST operation: ' + (opError.message || opError));
|
|
410
500
|
}
|
|
411
501
|
|
|
502
|
+
// 5b. Deploy the GET /discover resource (API capability probing)
|
|
503
|
+
try {
|
|
504
|
+
await client.post('/api/now/table/sys_ws_operation', {
|
|
505
|
+
web_service_definition: apiSysId,
|
|
506
|
+
http_method: 'GET',
|
|
507
|
+
name: 'discover',
|
|
508
|
+
active: true,
|
|
509
|
+
relative_path: '/discover',
|
|
510
|
+
short_description: 'Probe available sn_fd APIs, methods and fields for this ServiceNow instance',
|
|
511
|
+
operation_script: FLOW_FACTORY_DISCOVER_SCRIPT,
|
|
512
|
+
requires_authentication: true,
|
|
513
|
+
enforce_acl: 'false'
|
|
514
|
+
});
|
|
515
|
+
} catch (_) {
|
|
516
|
+
// Non-fatal: create endpoint is more important than discover
|
|
517
|
+
}
|
|
518
|
+
|
|
412
519
|
// 6. Probe to discover the namespace ServiceNow assigned
|
|
413
520
|
var resolvedNs = await probeFlowFactoryNamespace(client, apiSysId, instanceUrl);
|
|
414
521
|
if (!resolvedNs) {
|
|
@@ -431,6 +538,29 @@ async function ensureFlowFactoryAPI(
|
|
|
431
538
|
*/
|
|
432
539
|
function invalidateFlowFactoryCache(): void {
|
|
433
540
|
_flowFactoryCache = null;
|
|
541
|
+
_discoveryCache = null;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Call the /discover endpoint on the Flow Factory API to learn which
|
|
546
|
+
* sn_fd APIs and methods are available on the target ServiceNow instance.
|
|
547
|
+
* Results are cached alongside the factory cache.
|
|
548
|
+
*/
|
|
549
|
+
var _discoveryCache: any = null;
|
|
550
|
+
|
|
551
|
+
async function discoverInstanceCapabilities(
|
|
552
|
+
client: any,
|
|
553
|
+
namespace: string
|
|
554
|
+
): Promise<any> {
|
|
555
|
+
if (_discoveryCache) return _discoveryCache;
|
|
556
|
+
try {
|
|
557
|
+
var discoverEndpoint = '/api/' + namespace + '/' + FLOW_FACTORY_API_ID + '/discover';
|
|
558
|
+
var resp = await client.get(discoverEndpoint);
|
|
559
|
+
_discoveryCache = resp.data?.result || resp.data || null;
|
|
560
|
+
return _discoveryCache;
|
|
561
|
+
} catch (_) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
434
564
|
}
|
|
435
565
|
|
|
436
566
|
/**
|
|
@@ -780,6 +910,14 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
780
910
|
diagnostics.factory_bootstrap = 'success';
|
|
781
911
|
diagnostics.factory_namespace = factory.namespace;
|
|
782
912
|
|
|
913
|
+
// Call /discover to learn what sn_fd APIs exist on this instance
|
|
914
|
+
var discovery = await discoverInstanceCapabilities(client, factory.namespace);
|
|
915
|
+
if (discovery) {
|
|
916
|
+
diagnostics.instance_build = discovery.build_tag || discovery.build_name || 'unknown';
|
|
917
|
+
diagnostics.available_apis = discovery.apis || {};
|
|
918
|
+
diagnostics.available_methods = discovery.methods || {};
|
|
919
|
+
}
|
|
920
|
+
|
|
783
921
|
var factoryPayload = {
|
|
784
922
|
name: flowName,
|
|
785
923
|
description: flowDescription,
|
|
@@ -818,12 +956,15 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
818
956
|
|
|
819
957
|
var factoryResult = factoryResp.data?.result || factoryResp.data;
|
|
820
958
|
if (factoryResult && factoryResult.success && factoryResult.flow_sys_id) {
|
|
959
|
+
var tierUsed = factoryResult.tier_used || 'unknown';
|
|
821
960
|
diagnostics.factory_call = 'success';
|
|
961
|
+
diagnostics.factory_tier = tierUsed;
|
|
962
|
+
diagnostics.factory_steps = factoryResult.steps || {};
|
|
822
963
|
flowSysId = factoryResult.flow_sys_id;
|
|
823
964
|
usedMethod = 'scripted_rest_api';
|
|
824
965
|
versionCreated = !!factoryResult.version_created;
|
|
825
966
|
diagnostics.version_created = versionCreated;
|
|
826
|
-
diagnostics.version_method = 'factory';
|
|
967
|
+
diagnostics.version_method = 'factory (' + tierUsed + ')';
|
|
827
968
|
diagnostics.version_fields_set = ['flow', 'name', 'version', 'state', 'active', 'compile_state', 'is_current', 'published_flow'];
|
|
828
969
|
|
|
829
970
|
// Extract step details
|
|
@@ -1138,9 +1279,19 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1138
1279
|
|
|
1139
1280
|
// Diagnostics section
|
|
1140
1281
|
createSummary.blank().line('Diagnostics:');
|
|
1282
|
+
if (diagnostics.instance_build) {
|
|
1283
|
+
createSummary.indented('Instance build: ' + diagnostics.instance_build);
|
|
1284
|
+
}
|
|
1141
1285
|
createSummary.indented('Factory bootstrap: ' + (diagnostics.factory_bootstrap || 'not attempted'));
|
|
1142
1286
|
createSummary.indented('Factory namespace: ' + (diagnostics.factory_namespace || 'n/a'));
|
|
1143
1287
|
createSummary.indented('Factory call: ' + (diagnostics.factory_call || 'not attempted'));
|
|
1288
|
+
if (diagnostics.factory_tier) {
|
|
1289
|
+
createSummary.indented('Factory tier used: ' + diagnostics.factory_tier);
|
|
1290
|
+
}
|
|
1291
|
+
if (diagnostics.available_apis && Object.keys(diagnostics.available_apis).length > 0) {
|
|
1292
|
+
var apiStr = Object.keys(diagnostics.available_apis).map(function (k: string) { return k + '=' + diagnostics.available_apis[k]; }).join(', ');
|
|
1293
|
+
createSummary.indented('Available APIs: ' + apiStr);
|
|
1294
|
+
}
|
|
1144
1295
|
createSummary.indented('Table API used: ' + diagnostics.table_api_used);
|
|
1145
1296
|
createSummary.indented('Version created: ' + diagnostics.version_created + (diagnostics.version_method ? ' (' + diagnostics.version_method + ')' : ''));
|
|
1146
1297
|
if (diagnostics.engine_registration) {
|
|
@@ -1536,5 +1687,5 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1536
1687
|
}
|
|
1537
1688
|
}
|
|
1538
1689
|
|
|
1539
|
-
export const version = '
|
|
1690
|
+
export const version = '5.0.0';
|
|
1540
1691
|
export const author = 'Snow-Flow Team';
|