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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.1-test.111",
3
+ "version": "10.0.1-test.112",
4
4
  "name": "snow-flow-test",
5
5
  "description": "Snow-Flow Test - ServiceNow Multi-Agent Development Framework",
6
6
  "license": "Elastic-2.0",
@@ -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
- ' // Step 1: Create sys_hub_flow via GlideRecord (triggers all BRs)',
89
- ' var flow = new GlideRecord("sys_hub_flow");',
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
- ' if (body.flow_definition) {',
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
- ' var ver = new GlideRecord("sys_hub_flow_version");',
118
- ' ver.initialize();',
119
- ' ver.setValue("flow", flowSysId);',
120
- ' ver.setValue("name", "1.0");',
121
- ' ver.setValue("version", "1.0");',
122
- ' ver.setValue("state", shouldActivate ? "published" : "draft");',
123
- ' ver.setValue("active", true);',
124
- ' ver.setValue("compile_state", "compiled");',
125
- ' ver.setValue("is_current", true);',
126
- ' if (shouldActivate) ver.setValue("published_flow", flowSysId);',
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 (verErr) {',
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
- ' // Step 3: Create trigger instance (non-manual, non-subflow only)',
147
- ' if (!isSubflow && triggerType !== "manual") {',
169
+ // ── TIER 2: GlideRecord INSERT as draft UPDATE to published ──
170
+ ' if (!flowSysId) {',
148
171
  ' try {',
149
- ' var triggerMap = {',
150
- ' "record_created": "sn_fd.trigger.record_created",',
151
- ' "record_updated": "sn_fd.trigger.record_updated",',
152
- ' "scheduled": "sn_fd.trigger.scheduled"',
153
- ' };',
154
- ' var triggerIntName = triggerMap[triggerType] || "";',
155
- ' if (triggerIntName) {',
156
- ' var trigDef = new GlideRecord("sys_hub_action_type_definition");',
157
- ' trigDef.addQuery("internal_name", triggerIntName);',
158
- ' trigDef.query();',
159
- ' if (trigDef.next()) {',
160
- ' var trigInst = new GlideRecord("sys_hub_trigger_instance");',
161
- ' trigInst.initialize();',
162
- ' trigInst.setValue("flow", flowSysId);',
163
- ' trigInst.setValue("action_type", trigDef.getUniqueValue());',
164
- ' trigInst.setValue("name", triggerType);',
165
- ' trigInst.setValue("order", 0);',
166
- ' trigInst.setValue("active", true);',
167
- ' if (triggerTable) trigInst.setValue("table", triggerTable);',
168
- ' if (triggerCondition) trigInst.setValue("condition", triggerCondition);',
169
- ' var trigSysId = trigInst.insert();',
170
- ' result.steps.trigger = { success: !!trigSysId, sys_id: trigSysId + "" };',
171
- ' } else {',
172
- ' result.steps.trigger = { success: false, error: "Trigger type definition not found: " + triggerIntName };',
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 (trigErr) {',
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
- ' // Step 4: Create action instances',
181
- ' var actionsCreated = 0;',
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 act = activities[ai];',
185
- ' var actTypeName = act.type || "script";',
186
- ' var actDef = new GlideRecord("sys_hub_action_type_definition");',
187
- ' actDef.addQuery("internal_name", "CONTAINS", actTypeName);',
188
- ' actDef.addOrCondition("name", "CONTAINS", actTypeName);',
189
- ' actDef.query();',
190
- ' var actInst = new GlideRecord("sys_hub_action_instance");',
191
- ' actInst.initialize();',
192
- ' actInst.setValue("flow", flowSysId);',
193
- ' actInst.setValue("name", act.name || ("Action " + (ai + 1)));',
194
- ' actInst.setValue("order", (ai + 1) * 100);',
195
- ' actInst.setValue("active", true);',
196
- ' if (actDef.next()) {',
197
- ' actInst.setValue("action_type", actDef.getUniqueValue());',
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
- ' if (actInst.insert()) actionsCreated++;',
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
- ' // Step 5: Create flow variables (subflows)',
207
- ' var varsCreated = 0;',
208
- ' if (isSubflow) {',
209
- ' for (var vi = 0; vi < inputs.length; vi++) {',
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 inp = inputs[vi];',
212
- ' var fv = new GlideRecord("sys_hub_flow_variable");',
213
- ' fv.initialize();',
214
- ' fv.setValue("flow", flowSysId);',
215
- ' fv.setValue("name", inp.name);',
216
- ' fv.setValue("label", inp.label || inp.name);',
217
- ' fv.setValue("type", inp.type || "string");',
218
- ' fv.setValue("mandatory", inp.mandatory || false);',
219
- ' fv.setValue("default_value", inp.default_value || "");',
220
- ' fv.setValue("variable_type", "input");',
221
- ' if (fv.insert()) varsCreated++;',
222
- ' } catch (vErr) { /* best-effort */ }',
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
- ' for (var vo = 0; vo < outputs.length; vo++) {',
294
+ '',
295
+ ' var actionsCreated = 0;',
296
+ ' for (var ai = 0; ai < activities.length; ai++) {',
225
297
  ' try {',
226
- ' var out = outputs[vo];',
227
- ' var ov = new GlideRecord("sys_hub_flow_variable");',
228
- ' ov.initialize();',
229
- ' ov.setValue("flow", flowSysId);',
230
- ' ov.setValue("name", out.name);',
231
- ' ov.setValue("label", out.label || out.name);',
232
- ' ov.setValue("type", out.type || "string");',
233
- ' ov.setValue("variable_type", "output");',
234
- ' if (ov.insert()) varsCreated++;',
235
- ' } catch (vErr) { /* best-effort */ }',
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 = true;',
241
- ' result.flow_sys_id = flowSysId + "";',
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 or subflow with GlideRecord (triggers all BRs + version record)',
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 = '4.0.0';
1690
+ export const version = '5.0.0';
1540
1691
  export const author = 'Snow-Flow Team';