snow-flow 10.0.1-dev.421 → 10.0.1-dev.423
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
|
@@ -152,43 +152,7 @@ async function createFlowViaScheduledJob(
|
|
|
152
152
|
" verSysId = v.insert();",
|
|
153
153
|
" r.steps.version_insert = { success: !!verSysId, sys_id: verSysId + '' };",
|
|
154
154
|
"",
|
|
155
|
-
//
|
|
156
|
-
// Reference snapshot fields: parent_flow, master, internal_name, type, run_as,
|
|
157
|
-
// access, active, status, name, sc_callable, callable_by_client_api
|
|
158
|
-
" var snapId = null;",
|
|
159
|
-
" try {",
|
|
160
|
-
" var snap = new GlideRecord('sys_hub_flow_snapshot');",
|
|
161
|
-
" if (snap.isValid()) {",
|
|
162
|
-
" snap.initialize();",
|
|
163
|
-
" snap.setValue('name', flowName);",
|
|
164
|
-
" snap.setValue('internal_name', intName);",
|
|
165
|
-
" snap.setValue('parent_flow', flowSysId);",
|
|
166
|
-
" snap.setValue('type', isSubflow ? 'subflow' : 'flow');",
|
|
167
|
-
" snap.setValue('run_as', runAs);",
|
|
168
|
-
" snap.setValue('access', 'public');",
|
|
169
|
-
" snap.setValue('active', true);",
|
|
170
|
-
" snap.setValue('master', true);",
|
|
171
|
-
" snap.setValue('status', 'published');",
|
|
172
|
-
" snap.setValue('label_cache', '[]');",
|
|
173
|
-
" try { snap.setValue('sc_callable', false); } catch(e) {}",
|
|
174
|
-
" try { snap.setValue('callable_by_client_api', false); } catch(e) {}",
|
|
175
|
-
" snapId = snap.insert();",
|
|
176
|
-
" r.steps.snapshot_insert = { success: !!snapId, sys_id: snapId + '' };",
|
|
177
|
-
" } else { r.steps.snapshot_insert = { success: false, error: 'table not valid' }; }",
|
|
178
|
-
" } catch(snapE) { r.steps.snapshot_insert = { success: false, error: snapE.getMessage ? snapE.getMessage() : snapE + '' }; }",
|
|
179
|
-
"",
|
|
180
|
-
// Set latest_snapshot on flow to point to the snapshot record
|
|
181
|
-
" var snapshotRef = snapId || verSysId;",
|
|
182
|
-
" if (snapshotRef) {",
|
|
183
|
-
" try {",
|
|
184
|
-
" var flowUpd = new GlideRecord('sys_hub_flow');",
|
|
185
|
-
" if (flowUpd.get(flowSysId)) {",
|
|
186
|
-
" flowUpd.setValue('latest_snapshot', snapshotRef);",
|
|
187
|
-
" flowUpd.update();",
|
|
188
|
-
" r.steps.latest_snapshot_set = { value: snapshotRef + '', source: snapId ? 'snapshot' : 'version' };",
|
|
189
|
-
" }",
|
|
190
|
-
" } catch(lsE) { r.steps.latest_snapshot_set = { error: lsE.getMessage ? lsE.getMessage() : lsE + '' }; }",
|
|
191
|
-
" }",
|
|
155
|
+
// No snapshot/latest_snapshot — let the engine create these via Business Rule post-compile
|
|
192
156
|
" r.tier_used = 'gliderecord_scheduled'; r.success = true;",
|
|
193
157
|
" }",
|
|
194
158
|
" } catch(t2e) { r.steps.tier2 = { success: false, error: t2e.getMessage ? t2e.getMessage() : t2e + '' }; }",
|
|
@@ -297,157 +261,8 @@ async function createFlowViaScheduledJob(
|
|
|
297
261
|
" }",
|
|
298
262
|
" }",
|
|
299
263
|
" r.steps.variables = { success: true, created: varsCreated };",
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
// Reference flow analysis: snapshot has its OWN action instances (flow=snapshot_id).
|
|
303
|
-
// Flow Designer loads the snapshot and queries instances where flow=snapshot_id.
|
|
304
|
-
" if (snapId) {",
|
|
305
|
-
" var snapTrigCreated = 0; var snapActCreated = 0;",
|
|
306
|
-
// Duplicate trigger instances
|
|
307
|
-
" var trigQ = new GlideRecord('sys_hub_trigger_instance');",
|
|
308
|
-
" trigQ.addQuery('flow', flowSysId); trigQ.query();",
|
|
309
|
-
" while (trigQ.next()) {",
|
|
310
|
-
" try {",
|
|
311
|
-
" var st = new GlideRecord('sys_hub_trigger_instance');",
|
|
312
|
-
" st.initialize();",
|
|
313
|
-
" st.setValue('flow', snapId);",
|
|
314
|
-
" st.setValue('name', trigQ.getValue('name'));",
|
|
315
|
-
" st.setValue('order', trigQ.getValue('order'));",
|
|
316
|
-
" st.setValue('active', trigQ.getValue('active'));",
|
|
317
|
-
" var atVal = trigQ.getValue('action_type');",
|
|
318
|
-
" if (atVal) st.setValue('action_type', atVal);",
|
|
319
|
-
" var tblVal = trigQ.getValue('table');",
|
|
320
|
-
" if (tblVal) st.setValue('table', tblVal);",
|
|
321
|
-
" var condVal = trigQ.getValue('condition');",
|
|
322
|
-
" if (condVal) st.setValue('condition', condVal);",
|
|
323
|
-
" if (st.insert()) snapTrigCreated++;",
|
|
324
|
-
" } catch(e) {}",
|
|
325
|
-
" }",
|
|
326
|
-
// Duplicate action instances
|
|
327
|
-
" var actQ = new GlideRecord('sys_hub_action_instance');",
|
|
328
|
-
" actQ.addQuery('flow', flowSysId); actQ.query();",
|
|
329
|
-
" while (actQ.next()) {",
|
|
330
|
-
" try {",
|
|
331
|
-
" var sa = new GlideRecord('sys_hub_action_instance');",
|
|
332
|
-
" sa.initialize();",
|
|
333
|
-
" sa.setValue('flow', snapId);",
|
|
334
|
-
" sa.setValue('name', actQ.getValue('name'));",
|
|
335
|
-
" sa.setValue('order', actQ.getValue('order'));",
|
|
336
|
-
" sa.setValue('active', actQ.getValue('active'));",
|
|
337
|
-
" var aatVal = actQ.getValue('action_type');",
|
|
338
|
-
" if (aatVal) sa.setValue('action_type', aatVal);",
|
|
339
|
-
" if (sa.insert()) snapActCreated++;",
|
|
340
|
-
" } catch(e) {}",
|
|
341
|
-
" }",
|
|
342
|
-
" r.steps.snapshot_instances = { triggers: snapTrigCreated, actions: snapActCreated };",
|
|
343
|
-
" }",
|
|
344
|
-
"",
|
|
345
|
-
// ── Reference: deep-inspect a published flow to find what latest_snapshot points to ──
|
|
346
|
-
" r.steps.reference_flow = null;",
|
|
347
|
-
" try {",
|
|
348
|
-
" var refGr = new GlideRecord('sys_hub_flow');",
|
|
349
|
-
" refGr.addQuery('status', 'published');",
|
|
350
|
-
" refGr.addQuery('active', true);",
|
|
351
|
-
" refGr.setLimit(1); refGr.query();",
|
|
352
|
-
" if (refGr.next()) {",
|
|
353
|
-
" var refId = refGr.getUniqueValue();",
|
|
354
|
-
" var refLs = refGr.getValue('latest_snapshot') + '';",
|
|
355
|
-
" r.steps.reference_flow = {",
|
|
356
|
-
" sys_id: refId,",
|
|
357
|
-
" name: refGr.getValue('name'),",
|
|
358
|
-
" latest_snapshot_value: refLs,",
|
|
359
|
-
" latest_version: refGr.getValue('latest_version') + ''",
|
|
360
|
-
" };",
|
|
361
|
-
// Read the reference snapshot record fields (sys_hub_flow_snapshot)
|
|
362
|
-
" if (refLs !== 'null' && refLs.length === 32) {",
|
|
363
|
-
" try {",
|
|
364
|
-
" var refSnap = new GlideRecord('sys_hub_flow_snapshot');",
|
|
365
|
-
" if (refSnap.get(refLs)) {",
|
|
366
|
-
" r.steps.reference_flow.snapshot_table = 'sys_hub_flow_snapshot';",
|
|
367
|
-
// Read all non-null fields to learn the schema
|
|
368
|
-
" var snapFields = {};",
|
|
369
|
-
" var snapEl = refSnap.getFields();",
|
|
370
|
-
" for (var si = 0; si < snapEl.size(); si++) {",
|
|
371
|
-
" var sField = snapEl.get(si);",
|
|
372
|
-
" var sName = sField.getName() + '';",
|
|
373
|
-
" var sVal = refSnap.getValue(sName);",
|
|
374
|
-
" if (sVal && sName.indexOf('sys_') !== 0) {",
|
|
375
|
-
" var sStr = sVal + '';",
|
|
376
|
-
" snapFields[sName] = sStr.length > 100 ? sStr.substring(0, 100) + '...(len:' + sStr.length + ')' : sStr;",
|
|
377
|
-
" }",
|
|
378
|
-
" }",
|
|
379
|
-
" r.steps.reference_flow.snapshot_fields = snapFields;",
|
|
380
|
-
" }",
|
|
381
|
-
" } catch(snapRefE) { r.steps.reference_flow.snapshot_error = snapRefE + ''; }",
|
|
382
|
-
" }",
|
|
383
|
-
// Count trigger/action instances for reference flow AND its snapshot
|
|
384
|
-
" var refTrig = new GlideAggregate('sys_hub_trigger_instance');",
|
|
385
|
-
" refTrig.addQuery('flow', refId); refTrig.addAggregate('COUNT'); refTrig.query();",
|
|
386
|
-
" r.steps.reference_flow.trigger_count_on_flow = refTrig.next() ? parseInt(refTrig.getAggregate('COUNT')) : 0;",
|
|
387
|
-
" var refAct = new GlideAggregate('sys_hub_action_instance');",
|
|
388
|
-
" refAct.addQuery('flow', refId); refAct.addAggregate('COUNT'); refAct.query();",
|
|
389
|
-
" r.steps.reference_flow.action_count_on_flow = refAct.next() ? parseInt(refAct.getAggregate('COUNT')) : 0;",
|
|
390
|
-
// KEY: check if snapshot has its OWN action/trigger instances
|
|
391
|
-
" if (refLs !== 'null' && refLs.length === 32) {",
|
|
392
|
-
" var snapTrig = new GlideAggregate('sys_hub_trigger_instance');",
|
|
393
|
-
" snapTrig.addQuery('flow', refLs); snapTrig.addAggregate('COUNT'); snapTrig.query();",
|
|
394
|
-
" r.steps.reference_flow.trigger_count_on_snapshot = snapTrig.next() ? parseInt(snapTrig.getAggregate('COUNT')) : 0;",
|
|
395
|
-
" var snapAct = new GlideAggregate('sys_hub_action_instance');",
|
|
396
|
-
" snapAct.addQuery('flow', refLs); snapAct.addAggregate('COUNT'); snapAct.query();",
|
|
397
|
-
" r.steps.reference_flow.action_count_on_snapshot = snapAct.next() ? parseInt(snapAct.getAggregate('COUNT')) : 0;",
|
|
398
|
-
// Check sys_class_name of the snapshot (to understand table hierarchy)
|
|
399
|
-
" try {",
|
|
400
|
-
" var snapMeta = new GlideRecord('sys_metadata');",
|
|
401
|
-
" if (snapMeta.get(refLs)) {",
|
|
402
|
-
" r.steps.reference_flow.snapshot_sys_class = snapMeta.getValue('sys_class_name') + '';",
|
|
403
|
-
" }",
|
|
404
|
-
" } catch(e) {}",
|
|
405
|
-
// Check table hierarchy: does sys_hub_flow_snapshot extend sys_hub_flow?
|
|
406
|
-
" try {",
|
|
407
|
-
" var td = GlideDBObjectManager.get().getAbsoluteBase('sys_hub_flow_snapshot');",
|
|
408
|
-
" r.steps.reference_flow.snapshot_base_table = td + '';",
|
|
409
|
-
" } catch(e) { r.steps.reference_flow.snapshot_base_table = 'error'; }",
|
|
410
|
-
" }",
|
|
411
|
-
" }",
|
|
412
|
-
" } catch(refE) { r.steps.reference_flow = { error: refE + '' }; }",
|
|
413
|
-
"",
|
|
414
|
-
// ── Engine: try FlowAPI.compile on snapshot and flow ──
|
|
415
|
-
" r.steps.engine = { mode: 'compile', sn_fd: typeof sn_fd !== 'undefined' ? 'available' : 'unavailable' };",
|
|
416
|
-
" if (typeof sn_fd !== 'undefined' && sn_fd.FlowAPI) {",
|
|
417
|
-
" r.steps.engine.FlowAPI = 'available';",
|
|
418
|
-
// Try compile on snapshot first (snapshot extends sys_hub_flow_block)
|
|
419
|
-
" if (snapId) {",
|
|
420
|
-
" try {",
|
|
421
|
-
" var snapCompResult = sn_fd.FlowAPI.compile(snapId);",
|
|
422
|
-
" r.steps.engine.compile_snapshot = snapCompResult ? (snapCompResult + '').substring(0, 200) : 'success (null return)';",
|
|
423
|
-
" } catch(sce) { r.steps.engine.compile_snapshot = 'error: ' + (sce.getMessage ? sce.getMessage() : sce + ''); }",
|
|
424
|
-
" }",
|
|
425
|
-
// Then compile the flow record itself
|
|
426
|
-
" if (flowSysId) {",
|
|
427
|
-
" try {",
|
|
428
|
-
" var flowCompResult = sn_fd.FlowAPI.compile(flowSysId);",
|
|
429
|
-
" r.steps.engine.compile_flow = flowCompResult ? (flowCompResult + '').substring(0, 200) : 'success (null return)';",
|
|
430
|
-
" } catch(fce) { r.steps.engine.compile_flow = 'error: ' + (fce.getMessage ? fce.getMessage() : fce + ''); }",
|
|
431
|
-
" }",
|
|
432
|
-
// After compile, re-read snapshot to check if label_cache was populated
|
|
433
|
-
" if (snapId) {",
|
|
434
|
-
" try {",
|
|
435
|
-
" var postSnap = new GlideRecord('sys_hub_flow_snapshot');",
|
|
436
|
-
" if (postSnap.get(snapId)) {",
|
|
437
|
-
" var lc = postSnap.getValue('label_cache') + '';",
|
|
438
|
-
" r.steps.engine.label_cache_after_compile = lc.length > 5 ? lc.substring(0, 100) + '...(len:' + lc.length + ')' : lc;",
|
|
439
|
-
" }",
|
|
440
|
-
" } catch(e) {}",
|
|
441
|
-
" }",
|
|
442
|
-
// Try other known APIs
|
|
443
|
-
" var otherApis = ['FlowDesigner', 'FlowPublisher', 'FlowCompiler'];",
|
|
444
|
-
" r.steps.engine.other_apis = {};",
|
|
445
|
-
" for (var oa = 0; oa < otherApis.length; oa++) {",
|
|
446
|
-
" r.steps.engine.other_apis[otherApis[oa]] = typeof sn_fd[otherApis[oa]] !== 'undefined' ? 'available' : 'unavailable';",
|
|
447
|
-
" }",
|
|
448
|
-
" } else {",
|
|
449
|
-
" r.steps.engine.FlowAPI = 'unavailable';",
|
|
450
|
-
" }",
|
|
264
|
+
// Engine compilation delegated to Business Rule (runs in Flow Designer context)
|
|
265
|
+
" r.steps.engine = 'deferred_to_business_rule';",
|
|
451
266
|
" }",
|
|
452
267
|
"",
|
|
453
268
|
" r.flow_sys_id = flowSysId ? flowSysId + '' : null;",
|
|
@@ -535,6 +350,188 @@ async function createFlowViaScheduledJob(
|
|
|
535
350
|
}
|
|
536
351
|
}
|
|
537
352
|
|
|
353
|
+
// ── Business Rule compile: create a temp BR on sys_hub_flow to trigger engine compile ──
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* After the scheduled job creates the flow records, this function:
|
|
357
|
+
* 1. Creates a temporary Business Rule on sys_hub_flow (after update)
|
|
358
|
+
* 2. PATCHes the flow record to trigger the BR
|
|
359
|
+
* 3. The BR runs in the Flow Designer engine context and tries to compile/publish
|
|
360
|
+
* 4. Reads the result from a sys_property
|
|
361
|
+
* 5. Cleans up both the BR and the property
|
|
362
|
+
*
|
|
363
|
+
* Why a BR instead of scheduled job? BRs on sys_hub_flow run in the Flow Designer
|
|
364
|
+
* application scope, which may have access to APIs (like sn_fd.FlowDesigner) that
|
|
365
|
+
* aren't available in global-scope scheduled jobs.
|
|
366
|
+
*/
|
|
367
|
+
async function tryCompileViaBusinessRule(
|
|
368
|
+
client: any,
|
|
369
|
+
flowSysId: string,
|
|
370
|
+
flowDescription: string
|
|
371
|
+
): Promise<{ success: boolean; result?: any; error?: string }> {
|
|
372
|
+
var brResultProp = 'snow_flow.br_compile.' + Date.now();
|
|
373
|
+
|
|
374
|
+
// The BR script: runs server-side in sys_hub_flow context
|
|
375
|
+
// Probes all available APIs and tries compile/publish
|
|
376
|
+
var brScript = [
|
|
377
|
+
"(function executeRule(current, previous) {",
|
|
378
|
+
" var PROP = '" + escForScript(brResultProp) + "';",
|
|
379
|
+
" var r = { fired: true, context: 'business_rule', flow_id: current.sys_id + '' };",
|
|
380
|
+
" try {",
|
|
381
|
+
// Probe sn_fd namespace
|
|
382
|
+
" if (typeof sn_fd !== 'undefined') {",
|
|
383
|
+
" r.sn_fd = 'available';",
|
|
384
|
+
" var snfdKeys = [];",
|
|
385
|
+
" try { for (var k in sn_fd) { snfdKeys.push(k + ':' + typeof sn_fd[k]); } } catch(e) {}",
|
|
386
|
+
" r.sn_fd_keys = snfdKeys;",
|
|
387
|
+
"",
|
|
388
|
+
// Try FlowDesigner (not available in scheduled job, might be available in BR)
|
|
389
|
+
" if (typeof sn_fd.FlowDesigner !== 'undefined') {",
|
|
390
|
+
" r.FlowDesigner = 'available';",
|
|
391
|
+
" var fdMethods = [];",
|
|
392
|
+
" try { for (var fm in sn_fd.FlowDesigner) { if (typeof sn_fd.FlowDesigner[fm] === 'function') fdMethods.push(fm); } } catch(e) {}",
|
|
393
|
+
" r.FlowDesigner_methods = fdMethods;",
|
|
394
|
+
" try {",
|
|
395
|
+
" sn_fd.FlowDesigner.publishFlow(current.sys_id + '');",
|
|
396
|
+
" r.publishFlow = 'success';",
|
|
397
|
+
" } catch(pe) { r.publishFlow = (pe.getMessage ? pe.getMessage() : pe + '').substring(0, 200); }",
|
|
398
|
+
" } else { r.FlowDesigner = 'unavailable'; }",
|
|
399
|
+
"",
|
|
400
|
+
// Try FlowAPI
|
|
401
|
+
" if (typeof sn_fd.FlowAPI !== 'undefined') {",
|
|
402
|
+
" r.FlowAPI = 'available';",
|
|
403
|
+
" var faMethods = [];",
|
|
404
|
+
" try { for (var am in sn_fd.FlowAPI) { if (typeof sn_fd.FlowAPI[am] === 'function') faMethods.push(am); } } catch(e) {}",
|
|
405
|
+
" r.FlowAPI_methods = faMethods;",
|
|
406
|
+
" try {",
|
|
407
|
+
" var compRes = sn_fd.FlowAPI.compile(current.sys_id + '');",
|
|
408
|
+
" r.compile = compRes ? (compRes + '').substring(0, 200) : 'success (null return)';",
|
|
409
|
+
" } catch(ce) { r.compile = 'error: ' + (ce.getMessage ? ce.getMessage() : ce + '').substring(0, 200); }",
|
|
410
|
+
" try {",
|
|
411
|
+
" var pubRes = sn_fd.FlowAPI.publish(current.sys_id + '');",
|
|
412
|
+
" r.publish = pubRes ? (pubRes + '').substring(0, 200) : 'success (null return)';",
|
|
413
|
+
" } catch(pue) { r.publish = 'error: ' + (pue.getMessage ? pue.getMessage() : pue + '').substring(0, 200); }",
|
|
414
|
+
" } else { r.FlowAPI = 'unavailable'; }",
|
|
415
|
+
"",
|
|
416
|
+
// Search for flow-related Script Includes
|
|
417
|
+
" var si = new GlideRecord('sys_script_include');",
|
|
418
|
+
" si.addQuery('name', 'CONTAINS', 'FlowDesigner');",
|
|
419
|
+
" si.addOrCondition('name', 'CONTAINS', 'FlowCompiler');",
|
|
420
|
+
" si.addOrCondition('name', 'CONTAINS', 'FlowPublish');",
|
|
421
|
+
" si.addQuery('active', true);",
|
|
422
|
+
" si.setLimit(15); si.query();",
|
|
423
|
+
" r.script_includes = [];",
|
|
424
|
+
" while (si.next()) {",
|
|
425
|
+
" r.script_includes.push(si.getValue('name') + ' [api:' + si.getValue('api_name') + ', scope:' + si.getValue('sys_scope') + ']');",
|
|
426
|
+
" }",
|
|
427
|
+
"",
|
|
428
|
+
// Try instantiating common Script Includes
|
|
429
|
+
" var tryClasses = ['FlowDesignerScriptable', 'FlowDesignerService', 'FlowDesignerPublishService',",
|
|
430
|
+
" 'FlowDesignerCompileService', 'FlowDesignerActionService', 'sn_fd.FlowDesignerScriptable'];",
|
|
431
|
+
" r.script_include_tests = {};",
|
|
432
|
+
" for (var tc = 0; tc < tryClasses.length; tc++) {",
|
|
433
|
+
" try {",
|
|
434
|
+
" var cls = eval(tryClasses[tc]);",
|
|
435
|
+
" if (typeof cls === 'function') {",
|
|
436
|
+
" var inst = new cls();",
|
|
437
|
+
" r.script_include_tests[tryClasses[tc]] = 'instantiated';",
|
|
438
|
+
// Try compile/publish methods on instance
|
|
439
|
+
" if (typeof inst.compile === 'function') {",
|
|
440
|
+
" try { inst.compile(current.sys_id + ''); r.script_include_tests[tryClasses[tc] + '.compile'] = 'success'; }",
|
|
441
|
+
" catch(e) { r.script_include_tests[tryClasses[tc] + '.compile'] = (e + '').substring(0, 100); }",
|
|
442
|
+
" }",
|
|
443
|
+
" if (typeof inst.publishFlow === 'function') {",
|
|
444
|
+
" try { inst.publishFlow(current.sys_id + ''); r.script_include_tests[tryClasses[tc] + '.publishFlow'] = 'success'; }",
|
|
445
|
+
" catch(e) { r.script_include_tests[tryClasses[tc] + '.publishFlow'] = (e + '').substring(0, 100); }",
|
|
446
|
+
" }",
|
|
447
|
+
" } else { r.script_include_tests[tryClasses[tc]] = 'not a function: ' + typeof cls; }",
|
|
448
|
+
" } catch(e) { r.script_include_tests[tryClasses[tc]] = 'error: ' + (e + '').substring(0, 100); }",
|
|
449
|
+
" }",
|
|
450
|
+
" } else { r.sn_fd = 'unavailable'; }",
|
|
451
|
+
"",
|
|
452
|
+
// Post-check: read back flow state
|
|
453
|
+
" var post = new GlideRecord('sys_hub_flow');",
|
|
454
|
+
" if (post.get(current.sys_id + '')) {",
|
|
455
|
+
" r.post_latest_version = post.getValue('latest_version') + '';",
|
|
456
|
+
" r.post_latest_snapshot = post.getValue('latest_snapshot') + '';",
|
|
457
|
+
" r.post_status = post.getValue('status') + '';",
|
|
458
|
+
" }",
|
|
459
|
+
" } catch(topE) { r.error = (topE.getMessage ? topE.getMessage() : topE + '').substring(0, 300); }",
|
|
460
|
+
" gs.setProperty(PROP, JSON.stringify(r));",
|
|
461
|
+
"})(current, previous);"
|
|
462
|
+
].join('\n');
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
// 1. Create result property
|
|
466
|
+
await client.post('/api/now/table/sys_properties', {
|
|
467
|
+
name: brResultProp,
|
|
468
|
+
value: 'pending',
|
|
469
|
+
type: 'string',
|
|
470
|
+
description: 'Snow-Flow BR compile result (auto-cleanup)'
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// 2. Create temporary Business Rule on sys_hub_flow
|
|
474
|
+
var brResp = await client.post('/api/now/table/sys_script', {
|
|
475
|
+
name: 'Snow-Flow Auto-Compile (temp-cleanup)',
|
|
476
|
+
collection: 'sys_hub_flow',
|
|
477
|
+
when: 'after',
|
|
478
|
+
action_insert: false,
|
|
479
|
+
action_update: true,
|
|
480
|
+
action_delete: false,
|
|
481
|
+
active: true,
|
|
482
|
+
script: brScript,
|
|
483
|
+
order: 10000,
|
|
484
|
+
filter_condition: 'sys_id=' + flowSysId
|
|
485
|
+
});
|
|
486
|
+
var brSysId = brResp.data?.result?.sys_id;
|
|
487
|
+
|
|
488
|
+
// 3. PATCH the flow record to trigger the BR (tiny description change)
|
|
489
|
+
await new Promise(resolve => setTimeout(resolve, 1000)); // Let BR register
|
|
490
|
+
await client.patch('/api/now/table/sys_hub_flow/' + flowSysId, {
|
|
491
|
+
description: (flowDescription || '').trim() + ' '
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// 4. Poll for result (5 attempts, 2s each = 10s max)
|
|
495
|
+
for (var i = 0; i < 5; i++) {
|
|
496
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
497
|
+
var propResp = await client.get('/api/now/table/sys_properties', {
|
|
498
|
+
params: {
|
|
499
|
+
sysparm_query: 'name=' + brResultProp,
|
|
500
|
+
sysparm_fields: 'sys_id,value',
|
|
501
|
+
sysparm_limit: 1
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
var propRecord = propResp.data.result?.[0];
|
|
505
|
+
var propValue = propRecord?.value;
|
|
506
|
+
|
|
507
|
+
if (propValue && propValue !== 'pending') {
|
|
508
|
+
// Got result — clean up
|
|
509
|
+
try { if (propRecord?.sys_id) await client.delete('/api/now/table/sys_properties/' + propRecord.sys_id); } catch (_) {}
|
|
510
|
+
try { if (brSysId) await client.delete('/api/now/table/sys_script/' + brSysId); } catch (_) {}
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
return { success: true, result: JSON.parse(propValue) };
|
|
514
|
+
} catch (_) {
|
|
515
|
+
return { success: true, result: { raw: propValue.substring(0, 500) } };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Timeout — clean up
|
|
521
|
+
try {
|
|
522
|
+
var cleanProp = await client.get('/api/now/table/sys_properties', {
|
|
523
|
+
params: { sysparm_query: 'name=' + brResultProp, sysparm_fields: 'sys_id', sysparm_limit: 1 }
|
|
524
|
+
});
|
|
525
|
+
if (cleanProp.data.result?.[0]?.sys_id) await client.delete('/api/now/table/sys_properties/' + cleanProp.data.result[0].sys_id);
|
|
526
|
+
} catch (_) {}
|
|
527
|
+
try { if (brSysId) await client.delete('/api/now/table/sys_script/' + brSysId); } catch (_) {}
|
|
528
|
+
|
|
529
|
+
return { success: false, error: 'Business Rule did not fire within 10s — BR may not have registered or flow update was ignored' };
|
|
530
|
+
} catch (e: any) {
|
|
531
|
+
return { success: false, error: 'BR compile setup failed: ' + (e.message || e) };
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
538
535
|
// ── Flow Factory (Scripted REST API bootstrap) ──────────────────────
|
|
539
536
|
|
|
540
537
|
var FLOW_FACTORY_API_NAME = 'Snow-Flow Flow Factory';
|
|
@@ -1554,6 +1551,22 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1554
1551
|
factoryWarnings.push('Scheduled job failed: ' + (schedErr.message || schedErr));
|
|
1555
1552
|
}
|
|
1556
1553
|
|
|
1554
|
+
// ── Business Rule compile: trigger engine in Flow Designer context ──
|
|
1555
|
+
if (flowSysId) {
|
|
1556
|
+
try {
|
|
1557
|
+
var brResult = await tryCompileViaBusinessRule(client, flowSysId, flowDescription);
|
|
1558
|
+
diagnostics.br_compile = brResult.result || { error: brResult.error };
|
|
1559
|
+
if (brResult.success && brResult.result) {
|
|
1560
|
+
// Check if publish or compile succeeded
|
|
1561
|
+
if (brResult.result.publishFlow === 'success' || brResult.result.publish === 'success (null return)') {
|
|
1562
|
+
factoryWarnings.length = 0; // Clear warnings — compilation worked!
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
} catch (brErr: any) {
|
|
1566
|
+
diagnostics.br_compile = { error: brErr.message || 'unknown' };
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1557
1570
|
// ── Table API fallback (last resort) ─────────────────────────
|
|
1558
1571
|
if (!flowSysId) {
|
|
1559
1572
|
diagnostics.table_api_used = true;
|
|
@@ -1877,32 +1890,36 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1877
1890
|
}
|
|
1878
1891
|
createSummary.indented('Table API used: ' + diagnostics.table_api_used);
|
|
1879
1892
|
createSummary.indented('Version created: ' + diagnostics.version_created + (diagnostics.version_method ? ' (' + diagnostics.version_method + ')' : ''));
|
|
1893
|
+
// Business Rule compile results
|
|
1894
|
+
if (diagnostics.br_compile) {
|
|
1895
|
+
var br = diagnostics.br_compile;
|
|
1896
|
+
if (br.error) {
|
|
1897
|
+
createSummary.indented('BR compile: FAILED — ' + br.error);
|
|
1898
|
+
} else {
|
|
1899
|
+
createSummary.indented('BR compile: fired=' + (br.fired || false));
|
|
1900
|
+
createSummary.indented(' sn_fd=' + (br.sn_fd || 'unknown') + ', FlowDesigner=' + (br.FlowDesigner || 'unknown') + ', FlowAPI=' + (br.FlowAPI || 'unknown'));
|
|
1901
|
+
if (br.FlowDesigner_methods) createSummary.indented(' FlowDesigner methods: [' + br.FlowDesigner_methods.join(', ') + ']');
|
|
1902
|
+
if (br.FlowAPI_methods) createSummary.indented(' FlowAPI methods: [' + br.FlowAPI_methods.join(', ') + ']');
|
|
1903
|
+
if (br.publishFlow) createSummary.indented(' FlowDesigner.publishFlow: ' + br.publishFlow);
|
|
1904
|
+
if (br.compile) createSummary.indented(' FlowAPI.compile: ' + br.compile);
|
|
1905
|
+
if (br.publish) createSummary.indented(' FlowAPI.publish: ' + br.publish);
|
|
1906
|
+
if (br.sn_fd_keys && br.sn_fd_keys.length > 0) createSummary.indented(' sn_fd keys: [' + br.sn_fd_keys.join(', ') + ']');
|
|
1907
|
+
if (br.script_includes && br.script_includes.length > 0) createSummary.indented(' Script Includes: [' + br.script_includes.join(', ') + ']');
|
|
1908
|
+
if (br.script_include_tests) {
|
|
1909
|
+
var siKeys = Object.keys(br.script_include_tests);
|
|
1910
|
+
for (var sk = 0; sk < siKeys.length; sk++) {
|
|
1911
|
+
createSummary.indented(' SI ' + siKeys[sk] + ': ' + br.script_include_tests[siKeys[sk]]);
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
if (br.post_latest_version) createSummary.indented(' post_latest_version: ' + br.post_latest_version);
|
|
1915
|
+
if (br.post_latest_snapshot) createSummary.indented(' post_latest_snapshot: ' + br.post_latest_snapshot);
|
|
1916
|
+
if (br.post_status) createSummary.indented(' post_status: ' + br.post_status);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1880
1919
|
if (diagnostics.engine_registration) {
|
|
1881
1920
|
var eng = diagnostics.engine_registration;
|
|
1882
|
-
if (eng.
|
|
1883
|
-
|
|
1884
|
-
var engineLabel = 'sn_fd=' + eng.sn_fd + ', FlowAPI=' + (eng.FlowAPI || 'unknown');
|
|
1885
|
-
if (eng.compile_snapshot) engineLabel += ', compile(snapshot)=' + eng.compile_snapshot;
|
|
1886
|
-
if (eng.compile_flow) engineLabel += ', compile(flow)=' + eng.compile_flow;
|
|
1887
|
-
if (eng.label_cache_after_compile) engineLabel += ', label_cache=' + eng.label_cache_after_compile;
|
|
1888
|
-
createSummary.indented('Engine (compile): ' + engineLabel);
|
|
1889
|
-
if (eng.other_apis) {
|
|
1890
|
-
var apiList = Object.keys(eng.other_apis).map(function(k: string) { return k + '=' + eng.other_apis[k]; }).join(', ');
|
|
1891
|
-
createSummary.indented(' Other APIs: ' + apiList);
|
|
1892
|
-
}
|
|
1893
|
-
} else if (eng.sn_fd) {
|
|
1894
|
-
// Legacy probe-only mode (from scheduled job)
|
|
1895
|
-
var legacyLabel = 'sn_fd=' + eng.sn_fd;
|
|
1896
|
-
if (eng.apis_found && eng.apis_found.length > 0) {
|
|
1897
|
-
legacyLabel += ', APIs=[' + eng.apis_found.join(', ') + ']';
|
|
1898
|
-
}
|
|
1899
|
-
if (eng.publish) legacyLabel += ', publishFlow=' + eng.publish;
|
|
1900
|
-
if (eng.compile) legacyLabel += ', compile=' + eng.compile;
|
|
1901
|
-
if (eng.error) legacyLabel += ', error=' + eng.error;
|
|
1902
|
-
createSummary.indented('Engine (server-side): ' + legacyLabel);
|
|
1903
|
-
} else if (eng.success !== undefined) {
|
|
1904
|
-
// REST-based engine registration (Table API path)
|
|
1905
|
-
createSummary.indented('Engine registration: ' + (eng.success ? eng.method : 'FAILED'));
|
|
1921
|
+
if (eng.success !== undefined) {
|
|
1922
|
+
createSummary.indented('Engine REST registration: ' + (eng.success ? eng.method : 'FAILED'));
|
|
1906
1923
|
if (eng.attempts) {
|
|
1907
1924
|
for (var ea = 0; ea < eng.attempts.length; ea++) {
|
|
1908
1925
|
createSummary.indented(' ' + eng.attempts[ea]);
|