snow-flow 10.0.1-dev.453 → 10.0.1-dev.455
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
|
@@ -38,23 +38,46 @@ function generateUUID(): string {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Get the current max global order from the flow's version payload.
|
|
43
|
+
*
|
|
44
|
+
* IMPORTANT: Flow Designer elements (actions, flow logic, subflows) are NOT stored as
|
|
45
|
+
* individual records in sys_hub_action_instance / sys_hub_flow_logic / sys_hub_sub_flow_instance.
|
|
46
|
+
* They only exist inside the sys_hub_flow_version.payload (managed by the GraphQL API).
|
|
47
|
+
* Table API queries on these tables will always return 0 results.
|
|
48
|
+
*
|
|
49
|
+
* This function reads the version payload to determine the current max order.
|
|
50
|
+
* If the payload can't be read/parsed, it returns 0 (caller should use explicit order).
|
|
51
|
+
*/
|
|
52
|
+
async function getMaxOrderFromVersion(client: any, flowId: string): Promise<number> {
|
|
53
|
+
try {
|
|
54
|
+
const resp = await client.get('/api/now/table/sys_hub_flow_version', {
|
|
55
|
+
params: {
|
|
56
|
+
sysparm_query: 'flow=' + flowId + '^ORDERBYDESCsys_created_on',
|
|
57
|
+
sysparm_fields: 'sys_id,payload',
|
|
58
|
+
sysparm_limit: 1
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const payload = resp.data.result?.[0]?.payload;
|
|
62
|
+
if (!payload) return 0;
|
|
63
|
+
// Payload may be JSON containing flow elements with order fields
|
|
64
|
+
const parsed = typeof payload === 'string' ? JSON.parse(payload) : payload;
|
|
65
|
+
// Extract max order from any structure — search recursively for "order" values
|
|
66
|
+
let maxOrder = 0;
|
|
67
|
+
const findOrders = (obj: any) => {
|
|
68
|
+
if (!obj || typeof obj !== 'object') return;
|
|
69
|
+
if (obj.order !== undefined) {
|
|
70
|
+
const o = parseInt(String(obj.order), 10);
|
|
71
|
+
if (!isNaN(o) && o > maxOrder) maxOrder = o;
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(obj)) obj.forEach(findOrders);
|
|
74
|
+
else Object.values(obj).forEach(findOrders);
|
|
75
|
+
};
|
|
76
|
+
findOrders(parsed);
|
|
77
|
+
return maxOrder;
|
|
78
|
+
} catch (_) {
|
|
79
|
+
return 0;
|
|
56
80
|
}
|
|
57
|
-
return maxOrder + 1;
|
|
58
81
|
}
|
|
59
82
|
|
|
60
83
|
async function executeFlowPatchMutation(
|
|
@@ -171,161 +194,43 @@ async function buildActionInputsForInsert(
|
|
|
171
194
|
return { inputs, resolvedInputs, actionParams };
|
|
172
195
|
}
|
|
173
196
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
async function findElementsToReorder(
|
|
180
|
-
client: any,
|
|
181
|
-
flowId: string,
|
|
182
|
-
targetOrder: number
|
|
183
|
-
): Promise<{ flowLogicUpdates: any[]; actionUpdates: any[]; subflowUpdates: any[] }> {
|
|
184
|
-
var flowLogicUpdates: any[] = [];
|
|
185
|
-
var actionUpdates: any[] = [];
|
|
186
|
-
var subflowUpdates: any[] = [];
|
|
187
|
-
|
|
188
|
-
// Flow logic blocks
|
|
189
|
-
try {
|
|
190
|
-
var resp = await client.get('/api/now/table/sys_hub_flow_logic', {
|
|
191
|
-
params: {
|
|
192
|
-
sysparm_query: 'flow=' + flowId + '^order>=' + targetOrder,
|
|
193
|
-
sysparm_fields: 'sys_id,order,ui_unique_identifier',
|
|
194
|
-
sysparm_limit: 100
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
for (var rec of (resp.data.result || [])) {
|
|
198
|
-
var uuid = str(rec.ui_unique_identifier);
|
|
199
|
-
var curOrder = parseInt(str(rec.order) || '0', 10);
|
|
200
|
-
if (uuid && curOrder >= targetOrder) {
|
|
201
|
-
flowLogicUpdates.push({ order: String(curOrder + 1), uiUniqueIdentifier: uuid, type: 'flowlogic' });
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
} catch (_) {}
|
|
205
|
-
|
|
206
|
-
// Action instances
|
|
207
|
-
try {
|
|
208
|
-
var resp2 = await client.get('/api/now/table/sys_hub_action_instance', {
|
|
209
|
-
params: {
|
|
210
|
-
sysparm_query: 'flow=' + flowId + '^order>=' + targetOrder,
|
|
211
|
-
sysparm_fields: 'sys_id,order,ui_unique_identifier',
|
|
212
|
-
sysparm_limit: 100
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
for (var rec2 of (resp2.data.result || [])) {
|
|
216
|
-
var uuid2 = str(rec2.ui_unique_identifier);
|
|
217
|
-
var curOrder2 = parseInt(str(rec2.order) || '0', 10);
|
|
218
|
-
if (uuid2 && curOrder2 >= targetOrder) {
|
|
219
|
-
actionUpdates.push({ order: String(curOrder2 + 1), uiUniqueIdentifier: uuid2, type: 'action' });
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
} catch (_) {}
|
|
223
|
-
|
|
224
|
-
// Subflow instances
|
|
225
|
-
try {
|
|
226
|
-
var resp3 = await client.get('/api/now/table/sys_hub_sub_flow_instance', {
|
|
227
|
-
params: {
|
|
228
|
-
sysparm_query: 'flow=' + flowId + '^order>=' + targetOrder,
|
|
229
|
-
sysparm_fields: 'sys_id,order,ui_unique_identifier',
|
|
230
|
-
sysparm_limit: 100
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
for (var rec3 of (resp3.data.result || [])) {
|
|
234
|
-
var uuid3 = str(rec3.ui_unique_identifier);
|
|
235
|
-
var curOrder3 = parseInt(str(rec3.order) || '0', 10);
|
|
236
|
-
if (uuid3 && curOrder3 >= targetOrder) {
|
|
237
|
-
subflowUpdates.push({ order: String(curOrder3 + 1), uiUniqueIdentifier: uuid3, type: 'subflow' });
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
} catch (_) {}
|
|
241
|
-
|
|
242
|
-
return { flowLogicUpdates, actionUpdates, subflowUpdates };
|
|
243
|
-
}
|
|
197
|
+
// Note: reordering of existing elements is NOT possible via Table API because
|
|
198
|
+
// Flow Designer elements only exist in the version payload (managed by GraphQL).
|
|
199
|
+
// The caller must provide the correct global order. When inserting between existing
|
|
200
|
+
// elements, the caller should include the necessary sibling updates in the same
|
|
201
|
+
// GraphQL mutation (matching how the Flow Designer UI works).
|
|
244
202
|
|
|
245
203
|
/**
|
|
246
|
-
* Calculate the insert order for
|
|
247
|
-
*
|
|
204
|
+
* Calculate the insert order for a new flow element.
|
|
205
|
+
*
|
|
206
|
+
* Flow Designer uses GLOBAL ordering: all elements (actions, flow logic, subflows)
|
|
207
|
+
* share a single sequential numbering (1, 2, 3, 4, 5...).
|
|
208
|
+
*
|
|
209
|
+
* IMPORTANT: Flow elements do NOT exist as individual records in the Table API.
|
|
210
|
+
* They only live inside the version payload managed by the GraphQL API.
|
|
211
|
+
* Therefore we CANNOT query Table API to find existing elements or their orders.
|
|
212
|
+
*
|
|
213
|
+
* Order computation strategy:
|
|
214
|
+
* 1. If explicit order is provided → use it as the global order (the caller knows best)
|
|
215
|
+
* 2. Otherwise → try to determine max order from version payload, return max + 1
|
|
248
216
|
*/
|
|
249
217
|
async function calculateInsertOrder(
|
|
250
218
|
client: any,
|
|
251
219
|
flowId: string,
|
|
252
|
-
|
|
220
|
+
_parentUiId?: string,
|
|
253
221
|
explicitOrder?: number
|
|
254
|
-
): Promise<
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
//
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
var pResp = await client.get('/api/now/table/sys_hub_flow_logic', {
|
|
267
|
-
params: {
|
|
268
|
-
sysparm_query: 'flow=' + flowId + '^ui_unique_identifier=' + parentUiId,
|
|
269
|
-
sysparm_fields: 'sys_id,order',
|
|
270
|
-
sysparm_limit: 1
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
var found = pResp.data.result?.[0];
|
|
274
|
-
if (found) {
|
|
275
|
-
parentSysId = str(found.sys_id);
|
|
276
|
-
parentOrder = parseInt(str(found.order) || '0', 10);
|
|
277
|
-
}
|
|
278
|
-
} catch (_) {}
|
|
279
|
-
|
|
280
|
-
if (!parentSysId) {
|
|
281
|
-
// Fallback: append at end
|
|
282
|
-
var fallbackOrder = await getNextOrder(client, flowId);
|
|
283
|
-
return { insertOrder: fallbackOrder, reorders: noReorders };
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Find max order of existing children of this parent (query by both sys_id and UUID)
|
|
287
|
-
var maxChildOrder = parentOrder;
|
|
288
|
-
for (var table of ['sys_hub_action_instance', 'sys_hub_flow_logic', 'sys_hub_sub_flow_instance']) {
|
|
289
|
-
try {
|
|
290
|
-
var cResp = await client.get('/api/now/table/' + table, {
|
|
291
|
-
params: {
|
|
292
|
-
sysparm_query: 'flow=' + flowId + '^parent=' + parentSysId + '^ORDERBYDESCorder',
|
|
293
|
-
sysparm_fields: 'order',
|
|
294
|
-
sysparm_limit: 1
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
var childOrder = parseInt(str(cResp.data.result?.[0]?.order) || '0', 10);
|
|
298
|
-
if (childOrder > maxChildOrder) maxChildOrder = childOrder;
|
|
299
|
-
} catch (_) {}
|
|
300
|
-
// Also try querying by parent UUID (GraphQL may store UUID in parent field)
|
|
301
|
-
try {
|
|
302
|
-
var cResp2 = await client.get('/api/now/table/' + table, {
|
|
303
|
-
params: {
|
|
304
|
-
sysparm_query: 'flow=' + flowId + '^parent=' + parentUiId + '^ORDERBYDESCorder',
|
|
305
|
-
sysparm_fields: 'order',
|
|
306
|
-
sysparm_limit: 1
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
var childOrder2 = parseInt(str(cResp2.data.result?.[0]?.order) || '0', 10);
|
|
310
|
-
if (childOrder2 > maxChildOrder) maxChildOrder = childOrder2;
|
|
311
|
-
} catch (_) {}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Insert after last child; bump everything at that position
|
|
315
|
-
var insertOrder = maxChildOrder + 1;
|
|
316
|
-
var reorderInfo = await findElementsToReorder(client, flowId, insertOrder);
|
|
317
|
-
return { insertOrder: insertOrder, reorders: reorderInfo };
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// ── Top-level with explicit order: bump elements at that position ──
|
|
321
|
-
if (explicitOrder) {
|
|
322
|
-
var reorders = await findElementsToReorder(client, flowId, explicitOrder);
|
|
323
|
-
return { insertOrder: explicitOrder, reorders };
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// ── Top-level without order: append at end ──
|
|
327
|
-
var nextOrder = await getNextOrder(client, flowId);
|
|
328
|
-
return { insertOrder: nextOrder, reorders: noReorders };
|
|
222
|
+
): Promise<number> {
|
|
223
|
+
// Explicit order provided: trust it as the correct global order.
|
|
224
|
+
// This matches how the Flow Designer UI works — it computes the correct global
|
|
225
|
+
// order client-side and sends it in the mutation.
|
|
226
|
+
if (explicitOrder) return explicitOrder;
|
|
227
|
+
|
|
228
|
+
// No explicit order: try to find max order from version payload
|
|
229
|
+
const maxOrder = await getMaxOrderFromVersion(client, flowId);
|
|
230
|
+
if (maxOrder > 0) return maxOrder + 1;
|
|
231
|
+
|
|
232
|
+
// Last resort fallback
|
|
233
|
+
return 1;
|
|
329
234
|
}
|
|
330
235
|
|
|
331
236
|
async function addTriggerViaGraphQL(
|
|
@@ -498,17 +403,9 @@ async function addActionViaGraphQL(
|
|
|
498
403
|
steps.available_inputs = inputResult.actionParams.map((p: any) => ({ element: p.element, label: p.label }));
|
|
499
404
|
steps.resolved_inputs = inputResult.resolvedInputs;
|
|
500
405
|
|
|
501
|
-
// Calculate insertion order
|
|
502
|
-
const
|
|
503
|
-
const resolvedOrder = orderCalc.insertOrder;
|
|
406
|
+
// Calculate insertion order
|
|
407
|
+
const resolvedOrder = await calculateInsertOrder(client, flowId, parentUiId, order);
|
|
504
408
|
steps.insert_order = resolvedOrder;
|
|
505
|
-
if (orderCalc.reorders.flowLogicUpdates.length > 0 || orderCalc.reorders.actionUpdates.length > 0 || orderCalc.reorders.subflowUpdates.length > 0) {
|
|
506
|
-
steps.reordered_elements = {
|
|
507
|
-
flowLogics: orderCalc.reorders.flowLogicUpdates.length,
|
|
508
|
-
actions: orderCalc.reorders.actionUpdates.length,
|
|
509
|
-
subflows: orderCalc.reorders.subflowUpdates.length
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
409
|
|
|
513
410
|
const uuid = generateUUID();
|
|
514
411
|
const actionResponseFields = 'actions { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }' +
|
|
@@ -534,24 +431,9 @@ async function addActionViaGraphQL(
|
|
|
534
431
|
}
|
|
535
432
|
};
|
|
536
433
|
|
|
537
|
-
//
|
|
538
|
-
var flowLogicUpdates: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
434
|
+
// Add parent flow logic update signal (tells GraphQL the parent was modified)
|
|
539
435
|
if (parentUiId) {
|
|
540
|
-
|
|
541
|
-
// Avoid duplicating if the parent is already in the reorder list
|
|
542
|
-
var parentAlreadyIncluded = flowLogicUpdates.some(function (u: any) { return u.uiUniqueIdentifier === parentUiId; });
|
|
543
|
-
if (!parentAlreadyIncluded) {
|
|
544
|
-
flowLogicUpdates.push({ uiUniqueIdentifier: parentUiId, type: 'flowlogic' });
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
if (flowLogicUpdates.length > 0) {
|
|
548
|
-
flowPatch.flowLogics = { update: flowLogicUpdates };
|
|
549
|
-
}
|
|
550
|
-
if (orderCalc.reorders.actionUpdates.length > 0) {
|
|
551
|
-
flowPatch.actions.update = orderCalc.reorders.actionUpdates;
|
|
552
|
-
}
|
|
553
|
-
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
554
|
-
flowPatch.subflows = { update: orderCalc.reorders.subflowUpdates };
|
|
436
|
+
flowPatch.flowLogics = { update: [{ uiUniqueIdentifier: parentUiId, type: 'flowlogic' }] };
|
|
555
437
|
}
|
|
556
438
|
|
|
557
439
|
try {
|
|
@@ -618,9 +500,8 @@ async function addFlowLogicViaGraphQL(
|
|
|
618
500
|
}
|
|
619
501
|
if (!defId) return { success: false, error: 'Flow logic definition not found for: ' + logicType, steps };
|
|
620
502
|
|
|
621
|
-
// Calculate insertion order
|
|
622
|
-
const
|
|
623
|
-
const resolvedOrder = orderCalc.insertOrder;
|
|
503
|
+
// Calculate insertion order
|
|
504
|
+
const resolvedOrder = await calculateInsertOrder(client, flowId, parentUiId, order);
|
|
624
505
|
steps.insert_order = resolvedOrder;
|
|
625
506
|
|
|
626
507
|
const uuid = generateUUID();
|
|
@@ -657,24 +538,9 @@ async function addFlowLogicViaGraphQL(
|
|
|
657
538
|
}
|
|
658
539
|
};
|
|
659
540
|
|
|
660
|
-
//
|
|
661
|
-
var flowLogicUpdatesForPatch: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
541
|
+
// Add parent flow logic update signal
|
|
662
542
|
if (parentUiId) {
|
|
663
|
-
|
|
664
|
-
var parentAlreadyInList = flowLogicUpdatesForPatch.some(function (u: any) { return u.uiUniqueIdentifier === parentUiId; });
|
|
665
|
-
if (!parentAlreadyInList) {
|
|
666
|
-
flowLogicUpdatesForPatch.push({ uiUniqueIdentifier: parentUiId, type: 'flowlogic' });
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
if (flowLogicUpdatesForPatch.length > 0) {
|
|
670
|
-
if (!flowPatch.flowLogics.update) flowPatch.flowLogics.update = [];
|
|
671
|
-
flowPatch.flowLogics.update = flowPatch.flowLogics.update.concat(flowLogicUpdatesForPatch);
|
|
672
|
-
}
|
|
673
|
-
if (orderCalc.reorders.actionUpdates.length > 0) {
|
|
674
|
-
flowPatch.actions = { update: orderCalc.reorders.actionUpdates };
|
|
675
|
-
}
|
|
676
|
-
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
677
|
-
flowPatch.subflows = { update: orderCalc.reorders.subflowUpdates };
|
|
543
|
+
flowPatch.flowLogics.update = [{ uiUniqueIdentifier: parentUiId, type: 'flowlogic' }];
|
|
678
544
|
}
|
|
679
545
|
|
|
680
546
|
try {
|
|
@@ -748,9 +614,8 @@ async function addSubflowCallViaGraphQL(
|
|
|
748
614
|
|
|
749
615
|
if (!subflowName) subflowName = subflowId;
|
|
750
616
|
|
|
751
|
-
// Calculate insertion order
|
|
752
|
-
const
|
|
753
|
-
const resolvedOrder = orderCalc.insertOrder;
|
|
617
|
+
// Calculate insertion order
|
|
618
|
+
const resolvedOrder = await calculateInsertOrder(client, flowId, parentUiId, order);
|
|
754
619
|
steps.insert_order = resolvedOrder;
|
|
755
620
|
|
|
756
621
|
const uuid = generateUUID();
|
|
@@ -785,23 +650,9 @@ async function addSubflowCallViaGraphQL(
|
|
|
785
650
|
}
|
|
786
651
|
};
|
|
787
652
|
|
|
788
|
-
//
|
|
789
|
-
var subFlowLogicUpdates: any[] = orderCalc.reorders.flowLogicUpdates.slice();
|
|
653
|
+
// Add parent flow logic update signal
|
|
790
654
|
if (parentUiId) {
|
|
791
|
-
|
|
792
|
-
if (!parentIncluded) {
|
|
793
|
-
subFlowLogicUpdates.push({ uiUniqueIdentifier: parentUiId, type: 'flowlogic' });
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
if (subFlowLogicUpdates.length > 0) {
|
|
797
|
-
subPatch.flowLogics = { update: subFlowLogicUpdates };
|
|
798
|
-
}
|
|
799
|
-
if (orderCalc.reorders.actionUpdates.length > 0) {
|
|
800
|
-
subPatch.actions = { update: orderCalc.reorders.actionUpdates };
|
|
801
|
-
}
|
|
802
|
-
if (orderCalc.reorders.subflowUpdates.length > 0) {
|
|
803
|
-
if (!subPatch.subflows.update) subPatch.subflows.update = [];
|
|
804
|
-
subPatch.subflows.update = subPatch.subflows.update.concat(orderCalc.reorders.subflowUpdates);
|
|
655
|
+
subPatch.flowLogics = { update: [{ uiUniqueIdentifier: parentUiId, type: 'flowlogic' }] };
|
|
805
656
|
}
|
|
806
657
|
|
|
807
658
|
try {
|
|
@@ -1094,7 +945,7 @@ export const toolDefinition: MCPToolDefinition = {
|
|
|
1094
945
|
},
|
|
1095
946
|
order: {
|
|
1096
947
|
type: 'number',
|
|
1097
|
-
description: '
|
|
948
|
+
description: 'GLOBAL position/order of the element in the flow (for add_* actions). Flow Designer uses global sequential ordering across ALL elements (1, 2, 3...). For nested elements (e.g. action inside If block), the order must be global — not relative to the parent. Example: If block at order 2, first child should be order 3, second child order 4, etc. Each add_* response includes insert_order — use the previous insert_order + 1 for the next element.'
|
|
1098
949
|
},
|
|
1099
950
|
type: {
|
|
1100
951
|
type: 'string',
|