snow-flow 10.0.1-dev.402 → 10.0.1-dev.404
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
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Create, list, get, update, activate, deactivate, delete and publish
|
|
5
5
|
* Flow Designer flows and subflows.
|
|
6
6
|
*
|
|
7
|
-
* For create/create_subflow: uses a
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Falls back to Table API if the
|
|
7
|
+
* For create/create_subflow: uses a Scheduled Job (sysauto_script) that
|
|
8
|
+
* runs GlideRecord server-side, ensuring sys_hub_flow_version records are
|
|
9
|
+
* created, flow_definition is set, and sn_fd engine registration is
|
|
10
|
+
* attempted. Falls back to Table API if the scheduled job fails.
|
|
11
11
|
*
|
|
12
12
|
* All other actions (list, get, update, activate, etc.) use the Table API.
|
|
13
13
|
*/
|
|
@@ -65,6 +65,7 @@ async function createFlowViaScheduledJob(
|
|
|
65
65
|
activities?: Array<{ name: string; type?: string; inputs?: any }>;
|
|
66
66
|
inputs?: Array<{ name: string; label?: string; type?: string; mandatory?: boolean; default_value?: string }>;
|
|
67
67
|
outputs?: Array<{ name: string; label?: string; type?: string }>;
|
|
68
|
+
flowDefinition?: any;
|
|
68
69
|
}
|
|
69
70
|
): Promise<{
|
|
70
71
|
success: boolean;
|
|
@@ -77,6 +78,7 @@ async function createFlowViaScheduledJob(
|
|
|
77
78
|
error?: string;
|
|
78
79
|
}> {
|
|
79
80
|
var resultPropName = 'snow_flow.factory_result.' + Date.now();
|
|
81
|
+
var flowDefStr = params.flowDefinition ? JSON.stringify(params.flowDefinition) : '';
|
|
80
82
|
|
|
81
83
|
// Build the server-side ES5 script
|
|
82
84
|
var script = [
|
|
@@ -94,6 +96,7 @@ async function createFlowViaScheduledJob(
|
|
|
94
96
|
" var trigType = '" + escForScript(params.triggerType || 'manual') + "';",
|
|
95
97
|
" var trigTable = '" + escForScript(params.triggerTable || '') + "';",
|
|
96
98
|
" var trigCondition = '" + escForScript(params.triggerCondition || '') + "';",
|
|
99
|
+
" var flowDefStr = '" + escForScript(flowDefStr) + "';",
|
|
97
100
|
" var activitiesJson = '" + escForScript(JSON.stringify(params.activities || [])) + "';",
|
|
98
101
|
" var inputsJson = '" + escForScript(JSON.stringify(params.inputs || [])) + "';",
|
|
99
102
|
" var outputsJson = '" + escForScript(JSON.stringify(params.outputs || [])) + "';",
|
|
@@ -103,6 +106,7 @@ async function createFlowViaScheduledJob(
|
|
|
103
106
|
" var flowSysId = null;",
|
|
104
107
|
" var verSysId = null;",
|
|
105
108
|
"",
|
|
109
|
+
// ── TIER 1: sn_fd.FlowDesigner API ──
|
|
106
110
|
" try {",
|
|
107
111
|
" if (typeof sn_fd !== 'undefined' && sn_fd.FlowDesigner && typeof sn_fd.FlowDesigner.createFlow === 'function') {",
|
|
108
112
|
" var fdR = sn_fd.FlowDesigner.createFlow({ name: flowName, description: flowDesc, type: isSubflow ? 'subflow' : 'flow', category: flowCat, run_as: runAs });",
|
|
@@ -119,6 +123,7 @@ async function createFlowViaScheduledJob(
|
|
|
119
123
|
" }",
|
|
120
124
|
" } catch(t1e) { r.steps.tier1 = { success: false, error: t1e.getMessage ? t1e.getMessage() : t1e + '' }; }",
|
|
121
125
|
"",
|
|
126
|
+
// ── TIER 2: GlideRecord with flow_definition ──
|
|
122
127
|
" if (!flowSysId) {",
|
|
123
128
|
" try {",
|
|
124
129
|
" var f = new GlideRecord('sys_hub_flow');",
|
|
@@ -128,6 +133,7 @@ async function createFlowViaScheduledJob(
|
|
|
128
133
|
" f.setValue('run_as', runAs); f.setValue('active', false);",
|
|
129
134
|
" f.setValue('status', 'draft'); f.setValue('validated', true);",
|
|
130
135
|
" f.setValue('type', isSubflow ? 'subflow' : 'flow');",
|
|
136
|
+
" if (flowDefStr) { f.setValue('flow_definition', flowDefStr); f.setValue('latest_snapshot', flowDefStr); }",
|
|
131
137
|
" flowSysId = f.insert();",
|
|
132
138
|
" r.steps.flow_insert = { success: !!flowSysId, sys_id: flowSysId + '' };",
|
|
133
139
|
" if (flowSysId) {",
|
|
@@ -137,6 +143,7 @@ async function createFlowViaScheduledJob(
|
|
|
137
143
|
" v.setValue('version', '1.0'); v.setValue('state', 'draft');",
|
|
138
144
|
" v.setValue('active', true); v.setValue('compile_state', 'draft');",
|
|
139
145
|
" v.setValue('is_current', true);",
|
|
146
|
+
" if (flowDefStr) v.setValue('flow_definition', flowDefStr);",
|
|
140
147
|
" verSysId = v.insert();",
|
|
141
148
|
" r.steps.version_insert = { success: !!verSysId, sys_id: verSysId + '' };",
|
|
142
149
|
" if (verSysId) {",
|
|
@@ -158,24 +165,45 @@ async function createFlowViaScheduledJob(
|
|
|
158
165
|
"",
|
|
159
166
|
// ── Trigger, action, variable creation (runs for any tier) ──
|
|
160
167
|
" if (flowSysId) {",
|
|
161
|
-
// Trigger
|
|
168
|
+
// Trigger — search broadly for trigger definition (internal_name varies per instance)
|
|
162
169
|
" if (!isSubflow && trigType !== 'manual') {",
|
|
163
170
|
" try {",
|
|
164
|
-
" var
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
171
|
+
" var trigSearchTerms = {",
|
|
172
|
+
" 'record_created': ['record_created', 'record_insert', 'created'],",
|
|
173
|
+
" 'record_updated': ['record_updated', 'record_update', 'updated'],",
|
|
174
|
+
" 'scheduled': ['scheduled', 'timer', 'schedule']",
|
|
175
|
+
" };",
|
|
176
|
+
" var terms = trigSearchTerms[trigType] || [trigType];",
|
|
177
|
+
" var trigDef = null;",
|
|
178
|
+
" var trigDefId = null;",
|
|
179
|
+
" var trigSearchLog = [];",
|
|
180
|
+
" for (var ts = 0; ts < terms.length; ts++) {",
|
|
181
|
+
" var tg = new GlideRecord('sys_hub_action_type_definition');",
|
|
182
|
+
" tg.addQuery('internal_name', 'CONTAINS', terms[ts]);",
|
|
183
|
+
" tg.addQuery('type', 'trigger');",
|
|
184
|
+
" tg.setLimit(1); tg.query();",
|
|
185
|
+
" if (tg.next()) { trigDef = tg; trigDefId = tg.getUniqueValue(); trigSearchLog.push(terms[ts] + ':found'); break; }",
|
|
186
|
+
" trigSearchLog.push(terms[ts] + ':not_found');",
|
|
187
|
+
" }",
|
|
188
|
+
" if (!trigDefId) {",
|
|
189
|
+
" var tg2 = new GlideRecord('sys_hub_action_type_definition');",
|
|
190
|
+
" tg2.addQuery('name', 'CONTAINS', trigType.replace('_', ' '));",
|
|
191
|
+
" tg2.addQuery('type', 'trigger');",
|
|
192
|
+
" tg2.setLimit(1); tg2.query();",
|
|
193
|
+
" if (tg2.next()) { trigDef = tg2; trigDefId = tg2.getUniqueValue(); trigSearchLog.push('name_search:found'); }",
|
|
194
|
+
" else { trigSearchLog.push('name_search:not_found'); }",
|
|
195
|
+
" }",
|
|
196
|
+
" if (trigDefId) {",
|
|
197
|
+
" var trigInst = new GlideRecord('sys_hub_trigger_instance');",
|
|
198
|
+
" trigInst.initialize();",
|
|
199
|
+
" trigInst.setValue('flow', flowSysId); trigInst.setValue('action_type', trigDefId);",
|
|
200
|
+
" trigInst.setValue('name', trigType); trigInst.setValue('order', 0); trigInst.setValue('active', true);",
|
|
201
|
+
" if (trigTable) trigInst.setValue('table', trigTable);",
|
|
202
|
+
" if (trigCondition) trigInst.setValue('condition', trigCondition);",
|
|
203
|
+
" var trigId = trigInst.insert();",
|
|
204
|
+
" r.steps.trigger = { success: !!trigId, sys_id: trigId + '', def_name: trigDef.getValue('name'), search: trigSearchLog };",
|
|
205
|
+
" } else {",
|
|
206
|
+
" r.steps.trigger = { success: false, error: 'No trigger def found', search: trigSearchLog };",
|
|
179
207
|
" }",
|
|
180
208
|
" } catch(te) { r.steps.trigger = { success: false, error: te.getMessage ? te.getMessage() : te + '' }; }",
|
|
181
209
|
" }",
|
|
@@ -216,10 +244,46 @@ async function createFlowViaScheduledJob(
|
|
|
216
244
|
" }",
|
|
217
245
|
" }",
|
|
218
246
|
" r.steps.variables = { success: true, created: varsCreated };",
|
|
247
|
+
"",
|
|
248
|
+
// ── Engine probe (discovery only — do NOT call publish/compile) ──
|
|
249
|
+
// Previous versions called FlowAPI.publish() which caused StackOverflowError
|
|
250
|
+
// and corrupted the flow. Now we only probe which APIs exist for diagnostics.
|
|
251
|
+
// The flow is left as a clean draft; user publishes via Flow Designer UI.
|
|
252
|
+
" r.steps.engine = { apis_found: [], mode: 'probe_only' };",
|
|
253
|
+
" try {",
|
|
254
|
+
" if (typeof sn_fd !== 'undefined') {",
|
|
255
|
+
" r.steps.engine.sn_fd = 'available';",
|
|
256
|
+
" var probeNames = ['FlowDesigner', 'FlowCompiler', 'FlowAPI', 'FlowPublisher'];",
|
|
257
|
+
" for (var pn = 0; pn < probeNames.length; pn++) {",
|
|
258
|
+
" try {",
|
|
259
|
+
" if (sn_fd[probeNames[pn]]) {",
|
|
260
|
+
" r.steps.engine.apis_found.push(probeNames[pn]);",
|
|
261
|
+
" var methods = [];",
|
|
262
|
+
" var pObj = sn_fd[probeNames[pn]];",
|
|
263
|
+
" var checkMethods = ['createFlow','publishFlow','activateFlow','compileFlow','compile','publish','getFlow'];",
|
|
264
|
+
" for (var cm = 0; cm < checkMethods.length; cm++) {",
|
|
265
|
+
" if (typeof pObj[checkMethods[cm]] === 'function') methods.push(checkMethods[cm]);",
|
|
266
|
+
" }",
|
|
267
|
+
" if (methods.length > 0) r.steps.engine[probeNames[pn] + '_methods'] = methods;",
|
|
268
|
+
" }",
|
|
269
|
+
" } catch(e) {}",
|
|
270
|
+
" }",
|
|
271
|
+
" } else {",
|
|
272
|
+
" r.steps.engine.sn_fd = 'unavailable';",
|
|
273
|
+
" }",
|
|
274
|
+
" try {",
|
|
275
|
+
" if (typeof GlideFlowDesigner !== 'undefined') {",
|
|
276
|
+
" r.steps.engine.apis_found.push('GlideFlowDesigner');",
|
|
277
|
+
" }",
|
|
278
|
+
" } catch(e) {}",
|
|
279
|
+
" } catch(engineErr) {",
|
|
280
|
+
" r.steps.engine.error = engineErr.getMessage ? engineErr.getMessage() : engineErr + '';",
|
|
281
|
+
" }",
|
|
219
282
|
" }",
|
|
220
283
|
"",
|
|
221
284
|
" r.flow_sys_id = flowSysId ? flowSysId + '' : null;",
|
|
222
285
|
" r.version_sys_id = verSysId ? verSysId + '' : null;",
|
|
286
|
+
// ── Post-engine check: re-read latest_version ──
|
|
223
287
|
" if (flowSysId) {",
|
|
224
288
|
" var cf = new GlideRecord('sys_hub_flow');",
|
|
225
289
|
" if (cf.get(flowSysId)) {",
|
|
@@ -252,9 +316,10 @@ async function createFlowViaScheduledJob(
|
|
|
252
316
|
});
|
|
253
317
|
var jobSysId = jobResp.data.result?.sys_id;
|
|
254
318
|
|
|
255
|
-
// 3. Poll for result (
|
|
319
|
+
// 3. Poll for result (adaptive: 5×1s + 5×2s + 5×3s = 30s max)
|
|
256
320
|
for (var i = 0; i < 15; i++) {
|
|
257
|
-
|
|
321
|
+
var delay = i < 5 ? 1000 : i < 10 ? 2000 : 3000;
|
|
322
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
258
323
|
var propResp = await client.get('/api/now/table/sys_properties', {
|
|
259
324
|
params: {
|
|
260
325
|
sysparm_query: 'name=' + resultPropName,
|
|
@@ -1234,7 +1299,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1234
1299
|
delete flowDefinition.trigger;
|
|
1235
1300
|
}
|
|
1236
1301
|
|
|
1237
|
-
// ──
|
|
1302
|
+
// ── Pipeline: Scheduled Job (primary) → Table API (fallback) ──
|
|
1238
1303
|
var flowSysId: string | null = null;
|
|
1239
1304
|
var usedMethod = 'table_api';
|
|
1240
1305
|
var versionCreated = false;
|
|
@@ -1245,7 +1310,7 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1245
1310
|
|
|
1246
1311
|
// Diagnostics: track every step for debugging "flow cannot be found" issues
|
|
1247
1312
|
var diagnostics: any = {
|
|
1248
|
-
factory_bootstrap:
|
|
1313
|
+
factory_bootstrap: 'skipped (direct scheduled job)',
|
|
1249
1314
|
factory_namespace: null,
|
|
1250
1315
|
factory_call: null,
|
|
1251
1316
|
table_api_used: false,
|
|
@@ -1256,154 +1321,65 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1256
1321
|
post_verify: null
|
|
1257
1322
|
};
|
|
1258
1323
|
|
|
1324
|
+
// ── Scheduled Job (primary — server-side GlideRecord) ───────
|
|
1325
|
+
// This runs inside ServiceNow as a system job, so it CAN set
|
|
1326
|
+
// computed fields like latest_version that Table API cannot.
|
|
1327
|
+
// Also attempts sn_fd engine registration server-side.
|
|
1259
1328
|
try {
|
|
1260
|
-
var
|
|
1261
|
-
diagnostics.factory_bootstrap = 'success';
|
|
1262
|
-
diagnostics.factory_namespace = factory.namespace;
|
|
1263
|
-
|
|
1264
|
-
// Call /discover to learn what sn_fd APIs exist on this instance
|
|
1265
|
-
var discovery = await discoverInstanceCapabilities(client, factory.namespace);
|
|
1266
|
-
if (discovery) {
|
|
1267
|
-
diagnostics.instance_build = discovery.build_tag || discovery.build_name || 'unknown';
|
|
1268
|
-
diagnostics.available_apis = discovery.apis || {};
|
|
1269
|
-
diagnostics.available_methods = discovery.methods || {};
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
var factoryPayload = {
|
|
1329
|
+
var scheduledResult = await createFlowViaScheduledJob(client, {
|
|
1273
1330
|
name: flowName,
|
|
1274
1331
|
description: flowDescription,
|
|
1275
|
-
|
|
1332
|
+
internalName: sanitizeInternalName(flowName),
|
|
1333
|
+
isSubflow: isSubflow,
|
|
1276
1334
|
category: flowCategory,
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1335
|
+
runAs: flowRunAs,
|
|
1336
|
+
shouldActivate: shouldActivate,
|
|
1337
|
+
triggerType: triggerType,
|
|
1338
|
+
triggerTable: flowTable,
|
|
1339
|
+
triggerCondition: triggerCondition,
|
|
1282
1340
|
activities: activitiesArg.map(function (act: any, idx: number) {
|
|
1283
|
-
return { name: act.name, type: act.type || 'script', inputs: act.inputs || {}
|
|
1341
|
+
return { name: act.name, type: act.type || 'script', inputs: act.inputs || {} };
|
|
1284
1342
|
}),
|
|
1285
1343
|
inputs: inputsArg,
|
|
1286
1344
|
outputs: outputsArg,
|
|
1287
|
-
|
|
1345
|
+
flowDefinition: flowDefinition
|
|
1346
|
+
});
|
|
1347
|
+
diagnostics.scheduled_job = {
|
|
1348
|
+
success: scheduledResult.success,
|
|
1349
|
+
tierUsed: scheduledResult.tierUsed,
|
|
1350
|
+
latestVersionSet: scheduledResult.latestVersionSet,
|
|
1351
|
+
latestVersionValue: scheduledResult.latestVersionValue,
|
|
1352
|
+
steps: scheduledResult.steps,
|
|
1353
|
+
error: scheduledResult.error
|
|
1288
1354
|
};
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
try {
|
|
1294
|
-
factoryResp = await client.post(factoryEndpoint, factoryPayload);
|
|
1295
|
-
} catch (callError: any) {
|
|
1296
|
-
// 404 = API was deleted externally → invalidate cache, retry once
|
|
1297
|
-
if (callError.response?.status === 404) {
|
|
1298
|
-
invalidateFlowFactoryCache();
|
|
1299
|
-
var retryFactory = await ensureFlowFactoryAPI(client, context.instanceUrl);
|
|
1300
|
-
diagnostics.factory_namespace = retryFactory.namespace;
|
|
1301
|
-
var retryEndpoint = '/api/' + retryFactory.namespace + '/' + FLOW_FACTORY_API_ID + '/create';
|
|
1302
|
-
factoryResp = await client.post(retryEndpoint, factoryPayload);
|
|
1303
|
-
} else {
|
|
1304
|
-
throw callError;
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
var factoryResult = factoryResp.data?.result || factoryResp.data;
|
|
1309
|
-
if (factoryResult && factoryResult.success && factoryResult.flow_sys_id) {
|
|
1310
|
-
var tierUsed = factoryResult.tier_used || 'unknown';
|
|
1311
|
-
diagnostics.factory_call = 'success';
|
|
1312
|
-
diagnostics.factory_tier = tierUsed;
|
|
1313
|
-
diagnostics.factory_steps = factoryResult.steps || {};
|
|
1314
|
-
flowSysId = factoryResult.flow_sys_id;
|
|
1315
|
-
usedMethod = 'scripted_rest_api';
|
|
1316
|
-
versionCreated = !!factoryResult.version_created;
|
|
1355
|
+
if (scheduledResult.success && scheduledResult.flowSysId) {
|
|
1356
|
+
flowSysId = scheduledResult.flowSysId;
|
|
1357
|
+
usedMethod = 'scheduled_job (' + (scheduledResult.tierUsed || 'unknown') + ')';
|
|
1358
|
+
versionCreated = !!scheduledResult.versionSysId;
|
|
1317
1359
|
diagnostics.version_created = versionCreated;
|
|
1318
|
-
diagnostics.version_method = '
|
|
1319
|
-
diagnostics.
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
if (steps.trigger) {
|
|
1324
|
-
triggerCreated = !!steps.trigger.success;
|
|
1325
|
-
if (!steps.trigger.success && steps.trigger.error) {
|
|
1326
|
-
factoryWarnings.push('Trigger: ' + steps.trigger.error);
|
|
1327
|
-
}
|
|
1360
|
+
diagnostics.version_method = 'scheduled_job';
|
|
1361
|
+
diagnostics.latest_version_auto_set = scheduledResult.latestVersionSet;
|
|
1362
|
+
// Extract engine registration results from scheduled job
|
|
1363
|
+
if (scheduledResult.steps?.engine) {
|
|
1364
|
+
diagnostics.engine_registration = scheduledResult.steps.engine;
|
|
1328
1365
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1366
|
+
// Extract trigger/action/variable results from scheduled job
|
|
1367
|
+
if (scheduledResult.steps?.trigger) {
|
|
1368
|
+
triggerCreated = !!scheduledResult.steps.trigger.success;
|
|
1369
|
+
if (!scheduledResult.steps.trigger.success && scheduledResult.steps.trigger.error) {
|
|
1370
|
+
factoryWarnings.push('Trigger: ' + scheduledResult.steps.trigger.error);
|
|
1371
|
+
}
|
|
1331
1372
|
}
|
|
1332
|
-
if (steps
|
|
1333
|
-
|
|
1373
|
+
if (scheduledResult.steps?.actions) {
|
|
1374
|
+
actionsCreated = scheduledResult.steps.actions.created || 0;
|
|
1334
1375
|
}
|
|
1335
|
-
if (
|
|
1336
|
-
|
|
1376
|
+
if (scheduledResult.steps?.variables) {
|
|
1377
|
+
varsCreated = scheduledResult.steps.variables.created || 0;
|
|
1337
1378
|
}
|
|
1338
1379
|
}
|
|
1339
|
-
} catch (
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
var factoryErrMsg = statusCode
|
|
1343
|
-
? 'HTTP ' + statusCode + ': ' + (factoryError.response?.data?.error?.message || factoryError.message || 'unknown')
|
|
1344
|
-
: (factoryError.message || 'unknown');
|
|
1345
|
-
diagnostics.factory_bootstrap = diagnostics.factory_bootstrap || ('error: ' + factoryErrMsg);
|
|
1346
|
-
diagnostics.factory_call = diagnostics.factory_call || ('error: ' + factoryErrMsg);
|
|
1347
|
-
if (statusCode !== 403) {
|
|
1348
|
-
factoryWarnings.push('Flow Factory unavailable (' + factoryErrMsg + '), using Table API fallback');
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
// ── Scheduled Job fallback (server-side GlideRecord) ────────
|
|
1353
|
-
// This runs inside ServiceNow as a system job, so it CAN set
|
|
1354
|
-
// computed fields like latest_version that Table API cannot.
|
|
1355
|
-
if (!flowSysId) {
|
|
1356
|
-
try {
|
|
1357
|
-
var scheduledResult = await createFlowViaScheduledJob(client, {
|
|
1358
|
-
name: flowName,
|
|
1359
|
-
description: flowDescription,
|
|
1360
|
-
internalName: sanitizeInternalName(flowName),
|
|
1361
|
-
isSubflow: isSubflow,
|
|
1362
|
-
category: flowCategory,
|
|
1363
|
-
runAs: flowRunAs,
|
|
1364
|
-
shouldActivate: shouldActivate,
|
|
1365
|
-
triggerType: triggerType,
|
|
1366
|
-
triggerTable: flowTable,
|
|
1367
|
-
triggerCondition: triggerCondition,
|
|
1368
|
-
activities: activitiesArg.map(function (act: any, idx: number) {
|
|
1369
|
-
return { name: act.name, type: act.type || 'script', inputs: act.inputs || {} };
|
|
1370
|
-
}),
|
|
1371
|
-
inputs: inputsArg,
|
|
1372
|
-
outputs: outputsArg
|
|
1373
|
-
});
|
|
1374
|
-
diagnostics.scheduled_job = {
|
|
1375
|
-
success: scheduledResult.success,
|
|
1376
|
-
tierUsed: scheduledResult.tierUsed,
|
|
1377
|
-
latestVersionSet: scheduledResult.latestVersionSet,
|
|
1378
|
-
latestVersionValue: scheduledResult.latestVersionValue,
|
|
1379
|
-
steps: scheduledResult.steps,
|
|
1380
|
-
error: scheduledResult.error
|
|
1381
|
-
};
|
|
1382
|
-
if (scheduledResult.success && scheduledResult.flowSysId) {
|
|
1383
|
-
flowSysId = scheduledResult.flowSysId;
|
|
1384
|
-
usedMethod = 'scheduled_job (' + (scheduledResult.tierUsed || 'unknown') + ')';
|
|
1385
|
-
versionCreated = !!scheduledResult.versionSysId;
|
|
1386
|
-
diagnostics.version_created = versionCreated;
|
|
1387
|
-
diagnostics.version_method = 'scheduled_job';
|
|
1388
|
-
diagnostics.latest_version_auto_set = scheduledResult.latestVersionSet;
|
|
1389
|
-
// Extract trigger/action/variable results from scheduled job
|
|
1390
|
-
if (scheduledResult.steps?.trigger) {
|
|
1391
|
-
triggerCreated = !!scheduledResult.steps.trigger.success;
|
|
1392
|
-
if (!scheduledResult.steps.trigger.success && scheduledResult.steps.trigger.error) {
|
|
1393
|
-
factoryWarnings.push('Trigger: ' + scheduledResult.steps.trigger.error);
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
if (scheduledResult.steps?.actions) {
|
|
1397
|
-
actionsCreated = scheduledResult.steps.actions.created || 0;
|
|
1398
|
-
}
|
|
1399
|
-
if (scheduledResult.steps?.variables) {
|
|
1400
|
-
varsCreated = scheduledResult.steps.variables.created || 0;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
} catch (schedErr: any) {
|
|
1404
|
-
diagnostics.scheduled_job = { error: schedErr.message || 'unknown' };
|
|
1405
|
-
factoryWarnings.push('Scheduled job fallback failed: ' + (schedErr.message || schedErr));
|
|
1406
|
-
}
|
|
1380
|
+
} catch (schedErr: any) {
|
|
1381
|
+
diagnostics.scheduled_job = { error: schedErr.message || 'unknown' };
|
|
1382
|
+
factoryWarnings.push('Scheduled job failed: ' + (schedErr.message || schedErr));
|
|
1407
1383
|
}
|
|
1408
1384
|
|
|
1409
1385
|
// ── Table API fallback (last resort) ─────────────────────────
|
|
@@ -1500,39 +1476,53 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1500
1476
|
}
|
|
1501
1477
|
|
|
1502
1478
|
// Create trigger instance (non-manual flows only)
|
|
1479
|
+
// Search broadly — internal_name varies across ServiceNow instances
|
|
1503
1480
|
if (!isSubflow && triggerType !== 'manual') {
|
|
1504
1481
|
try {
|
|
1505
|
-
var
|
|
1506
|
-
'record_created': '
|
|
1507
|
-
'record_updated': '
|
|
1508
|
-
'scheduled': '
|
|
1482
|
+
var trigSearchTerms: Record<string, string[]> = {
|
|
1483
|
+
'record_created': ['record_created', 'record_insert', 'created'],
|
|
1484
|
+
'record_updated': ['record_updated', 'record_update', 'updated'],
|
|
1485
|
+
'scheduled': ['scheduled', 'timer', 'schedule']
|
|
1509
1486
|
};
|
|
1510
|
-
var
|
|
1487
|
+
var searchTerms = trigSearchTerms[triggerType] || [triggerType];
|
|
1488
|
+
var triggerDefId: string | null = null;
|
|
1511
1489
|
|
|
1512
|
-
|
|
1490
|
+
for (var tsi = 0; tsi < searchTerms.length && !triggerDefId; tsi++) {
|
|
1513
1491
|
var triggerDefResp = await client.get('/api/now/table/sys_hub_action_type_definition', {
|
|
1514
1492
|
params: {
|
|
1515
|
-
sysparm_query: '
|
|
1493
|
+
sysparm_query: 'internal_nameLIKE' + searchTerms[tsi] + '^type=trigger',
|
|
1516
1494
|
sysparm_fields: 'sys_id',
|
|
1517
1495
|
sysparm_limit: 1
|
|
1518
1496
|
}
|
|
1519
1497
|
});
|
|
1498
|
+
triggerDefId = triggerDefResp.data.result?.[0]?.sys_id || null;
|
|
1499
|
+
}
|
|
1520
1500
|
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1501
|
+
// Fallback: search by display name
|
|
1502
|
+
if (!triggerDefId) {
|
|
1503
|
+
var trigNameResp = await client.get('/api/now/table/sys_hub_action_type_definition', {
|
|
1504
|
+
params: {
|
|
1505
|
+
sysparm_query: 'nameLIKE' + triggerType.replace(/_/g, ' ') + '^type=trigger',
|
|
1506
|
+
sysparm_fields: 'sys_id',
|
|
1507
|
+
sysparm_limit: 1
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
triggerDefId = trigNameResp.data.result?.[0]?.sys_id || null;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
if (triggerDefId) {
|
|
1514
|
+
var triggerData: any = {
|
|
1515
|
+
flow: flowSysId,
|
|
1516
|
+
action_type: triggerDefId,
|
|
1517
|
+
name: triggerType,
|
|
1518
|
+
order: 0,
|
|
1519
|
+
active: true
|
|
1520
|
+
};
|
|
1521
|
+
if (flowTable) triggerData.table = flowTable;
|
|
1522
|
+
if (triggerCondition) triggerData.condition = triggerCondition;
|
|
1523
|
+
|
|
1524
|
+
await client.post('/api/now/table/sys_hub_trigger_instance', triggerData);
|
|
1525
|
+
triggerCreated = true;
|
|
1536
1526
|
}
|
|
1537
1527
|
} catch (triggerError) {
|
|
1538
1528
|
// Best-effort
|
|
@@ -1604,10 +1594,11 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1604
1594
|
|
|
1605
1595
|
}
|
|
1606
1596
|
|
|
1607
|
-
// ── Register flow with Flow Designer engine
|
|
1608
|
-
//
|
|
1609
|
-
//
|
|
1610
|
-
|
|
1597
|
+
// ── Register flow with Flow Designer engine (Table API only) ──
|
|
1598
|
+
// For scheduled job path, engine registration is done server-side
|
|
1599
|
+
// inside the job script (via sn_fd APIs). Only call the external
|
|
1600
|
+
// REST-based registration for the Table API fallback path.
|
|
1601
|
+
if (flowSysId && usedMethod.startsWith('table_api')) {
|
|
1611
1602
|
var engineResult = await registerFlowWithEngine(client, flowSysId, shouldActivate);
|
|
1612
1603
|
diagnostics.engine_registration = {
|
|
1613
1604
|
success: engineResult.success,
|
|
@@ -1722,29 +1713,38 @@ export async function execute(args: any, context: ServiceNowContext): Promise<To
|
|
|
1722
1713
|
|
|
1723
1714
|
// Diagnostics section
|
|
1724
1715
|
createSummary.blank().line('Diagnostics:');
|
|
1725
|
-
if (diagnostics.
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
createSummary.indented('Factory namespace: ' + (diagnostics.factory_namespace || 'n/a'));
|
|
1730
|
-
createSummary.indented('Factory call: ' + (diagnostics.factory_call || 'not attempted'));
|
|
1731
|
-
if (diagnostics.factory_tier) {
|
|
1732
|
-
createSummary.indented('Factory tier used: ' + diagnostics.factory_tier);
|
|
1733
|
-
}
|
|
1734
|
-
if (diagnostics.available_apis && Object.keys(diagnostics.available_apis).length > 0) {
|
|
1735
|
-
var apiStr = Object.keys(diagnostics.available_apis).map(function (k: string) { return k + '=' + diagnostics.available_apis[k]; }).join(', ');
|
|
1736
|
-
createSummary.indented('Available APIs: ' + apiStr);
|
|
1716
|
+
if (diagnostics.scheduled_job) {
|
|
1717
|
+
var sj = diagnostics.scheduled_job;
|
|
1718
|
+
createSummary.indented('Scheduled job: ' + (sj.success ? 'success' : 'failed') + (sj.tierUsed ? ' (' + sj.tierUsed + ')' : ''));
|
|
1719
|
+
if (sj.error) createSummary.indented(' Error: ' + sj.error);
|
|
1737
1720
|
}
|
|
1738
1721
|
createSummary.indented('Table API used: ' + diagnostics.table_api_used);
|
|
1739
1722
|
createSummary.indented('Version created: ' + diagnostics.version_created + (diagnostics.version_method ? ' (' + diagnostics.version_method + ')' : ''));
|
|
1740
1723
|
if (diagnostics.engine_registration) {
|
|
1741
|
-
|
|
1742
|
-
if (
|
|
1743
|
-
|
|
1744
|
-
|
|
1724
|
+
var eng = diagnostics.engine_registration;
|
|
1725
|
+
if (eng.sn_fd) {
|
|
1726
|
+
// Server-side engine registration (from scheduled job)
|
|
1727
|
+
var engineLabel = 'sn_fd=' + eng.sn_fd;
|
|
1728
|
+
if (eng.apis_found && eng.apis_found.length > 0) {
|
|
1729
|
+
engineLabel += ', APIs=[' + eng.apis_found.join(', ') + ']';
|
|
1730
|
+
}
|
|
1731
|
+
if (eng.publish) engineLabel += ', publishFlow=' + eng.publish;
|
|
1732
|
+
if (eng.compile) engineLabel += ', compile=' + eng.compile;
|
|
1733
|
+
if (eng.error) engineLabel += ', error=' + eng.error;
|
|
1734
|
+
createSummary.indented('Engine (server-side): ' + engineLabel);
|
|
1735
|
+
} else if (eng.success !== undefined) {
|
|
1736
|
+
// REST-based engine registration (Table API path)
|
|
1737
|
+
createSummary.indented('Engine registration: ' + (eng.success ? eng.method : 'FAILED'));
|
|
1738
|
+
if (eng.attempts) {
|
|
1739
|
+
for (var ea = 0; ea < eng.attempts.length; ea++) {
|
|
1740
|
+
createSummary.indented(' ' + eng.attempts[ea]);
|
|
1741
|
+
}
|
|
1745
1742
|
}
|
|
1746
1743
|
}
|
|
1747
1744
|
}
|
|
1745
|
+
if (diagnostics.latest_version_auto_set !== undefined) {
|
|
1746
|
+
createSummary.indented('latest_version: ' + (diagnostics.latest_version_auto_set ? 'set' : 'null'));
|
|
1747
|
+
}
|
|
1748
1748
|
if (diagnostics.post_verify) {
|
|
1749
1749
|
if (diagnostics.post_verify.error) {
|
|
1750
1750
|
createSummary.indented('Post-verify: error — ' + diagnostics.post_verify.error);
|