snow-flow-test 10.0.1-test.185 → 10.0.1-test.187

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.185",
3
+ "version": "10.0.1-test.187",
4
4
  "name": "snow-flow-test",
5
5
  "description": "Snow-Flow Test - ServiceNow Multi-Agent Development Framework",
6
6
  "license": "Elastic-2.0",
@@ -1009,7 +1009,7 @@ async function addActionViaGraphQL(
1009
1009
  inputResult.actionParams, uuid
1010
1010
  );
1011
1011
  steps.record_action = recordActionResult.steps;
1012
- var hasRecordPills = recordActionResult.labelCacheEntries.length > 0;
1012
+ var hasRecordPills = (recordActionResult.labelCacheUpdates.length + recordActionResult.labelCacheInserts.length) > 0;
1013
1013
 
1014
1014
  // For record actions: clear data pill values from INSERT — they'll be set via separate UPDATE
1015
1015
  // (Flow Designer's GraphQL API ignores labelCache during INSERT, it only works with UPDATE)
@@ -1064,19 +1064,30 @@ async function addActionViaGraphQL(
1064
1064
  if (!actionId) return { success: false, steps, error: 'GraphQL action INSERT returned no ID' };
1065
1065
 
1066
1066
  // Step 2: UPDATE with data pill values + labelCache (separate mutation, matching UI behavior)
1067
- // The Flow Designer UI always sets data pill references via a separate UPDATE.
1067
+ // The Flow Designer UI uses labelCache UPDATE for existing pills (record-level)
1068
+ // and labelCache INSERT for new pills (field-level in values).
1068
1069
  if (hasRecordPills) {
1069
1070
  var updateInputs: any[] = [];
1070
- // Collect all inputs that have data pill values
1071
+ // Collect inputs for the UPDATE mutation
1071
1072
  for (var ri = 0; ri < recordActionResult.inputs.length; ri++) {
1072
1073
  var inp = recordActionResult.inputs[ri];
1073
1074
  var val = inp.value?.value || '';
1074
1075
  if (inp.name === 'record' && val.startsWith('{{')) {
1075
1076
  updateInputs.push({ name: 'record', value: { schemaless: false, schemalessValue: '', value: val } });
1076
1077
  } else if (inp.name === 'table_name') {
1077
- updateInputs.push({ name: 'table_name', displayValue: inp.displayValue || { value: '' }, value: inp.value || { value: '' } });
1078
- } else if (inp.name === 'values' && val) {
1079
- updateInputs.push({ name: 'values', value: { schemaless: false, schemalessValue: '', value: val } });
1078
+ // displayValue must use full schemaless format: {schemaless, schemalessValue, value}
1079
+ updateInputs.push({
1080
+ name: 'table_name',
1081
+ displayValue: inp.displayValue || { schemaless: false, schemalessValue: '', value: '' },
1082
+ value: inp.value || { schemaless: false, schemalessValue: '', value: '' }
1083
+ });
1084
+ } else if (inp.name === 'values') {
1085
+ // UI sends {name: "values"} without value property when empty, with value when set
1086
+ if (val) {
1087
+ updateInputs.push({ name: 'values', value: { schemaless: false, schemalessValue: '', value: val } });
1088
+ } else {
1089
+ updateInputs.push({ name: 'values' });
1090
+ }
1080
1091
  }
1081
1092
  }
1082
1093
 
@@ -1084,7 +1095,7 @@ async function addActionViaGraphQL(
1084
1095
  try {
1085
1096
  var updatePatch: any = {
1086
1097
  flowId: flowId,
1087
- labelCache: { insert: recordActionResult.labelCacheEntries },
1098
+ labelCache: {} as any,
1088
1099
  actions: {
1089
1100
  update: [{
1090
1101
  uiUniqueIdentifier: uuid,
@@ -1093,8 +1104,18 @@ async function addActionViaGraphQL(
1093
1104
  }]
1094
1105
  }
1095
1106
  };
1096
- await executeFlowPatchMutation(client, updatePatch, actionResponseFields);
1097
- steps.record_update = { success: true, inputCount: updateInputs.length };
1107
+ // Record-level pills → labelCache UPDATE (already exist from trigger)
1108
+ if (recordActionResult.labelCacheUpdates.length > 0) {
1109
+ updatePatch.labelCache.update = recordActionResult.labelCacheUpdates;
1110
+ }
1111
+ // Field-level pills → labelCache INSERT (new entries)
1112
+ if (recordActionResult.labelCacheInserts.length > 0) {
1113
+ updatePatch.labelCache.insert = recordActionResult.labelCacheInserts;
1114
+ }
1115
+ // Log the exact GraphQL mutation for debugging
1116
+ steps.record_update_mutation = jsToGraphQL(updatePatch);
1117
+ var actionUpdateResult = await executeFlowPatchMutation(client, updatePatch, actionResponseFields);
1118
+ steps.record_update = { success: true, inputCount: updateInputs.length, response: actionUpdateResult };
1098
1119
  } catch (ue: any) {
1099
1120
  steps.record_update = { success: false, error: ue.message };
1100
1121
  // Action was created — update failure is non-fatal
@@ -1558,31 +1579,29 @@ async function transformActionInputsForRecordAction(
1558
1579
  }
1559
1580
 
1560
1581
  // ── 4. Build labelCache entries for data pills ────────────────────
1582
+ // The record-level pill (e.g. "Created or Updated_1.current") already exists in the
1583
+ // flow's labelCache from the trigger. The UI sends a labelCache UPDATE (not INSERT)
1584
+ // with just name + usedInstances to register this action's usage.
1585
+ // Field-level pills (e.g. "Created or Updated_1.current.assigned_to") are new and need INSERT.
1586
+ var labelCacheUpdates: any[] = [];
1587
+ var labelCacheInserts: any[] = [];
1588
+
1561
1589
  if (dataPillBase && usedInstances.length > 0) {
1562
1590
  var tableRef = triggerInfo.tableRef || triggerInfo.table || '';
1563
1591
  var tblLabel = triggerInfo.tableLabel || '';
1564
1592
 
1565
- // Record-level data pill entry (for the `record` input selecting the whole record)
1566
- labelCacheEntries.push({
1593
+ // Record-level pill — UPDATE existing entry with new usedInstances (minimal: name + usedInstances only)
1594
+ labelCacheUpdates.push({
1567
1595
  name: dataPillBase,
1568
- label: 'Trigger - Record ' + triggerInfo.triggerName + '\u27a1' + tblLabel + ' Record',
1569
- reference: tableRef,
1570
- reference_display: tblLabel,
1571
- type: 'reference',
1572
- base_type: 'reference',
1573
- parent_table_name: tableRef,
1574
- column_name: '',
1575
- usedInstances: usedInstances,
1576
- choices: {}
1596
+ usedInstances: usedInstances
1577
1597
  });
1578
1598
 
1579
- // Field-level data pill entries for any field references in the `values` string
1599
+ // Field-level data pill entries for any field references in the `values` string → INSERT (new pills)
1580
1600
  var valuesStr = '';
1581
1601
  var valuesInp = actionInputs.find(function (inp: any) { return inp.name === 'values'; });
1582
1602
  if (valuesInp) valuesStr = valuesInp.value?.value || '';
1583
1603
 
1584
1604
  if (valuesStr && valuesStr.includes('{{')) {
1585
- // Extract field-level pills from values like "assigned_to={{dataPillBase.assigned_to}}"
1586
1605
  var pillRegex = /\{\{([^}]+)\}\}/g;
1587
1606
  var pillMatch;
1588
1607
  var seenPills: Record<string, boolean> = {};
@@ -1593,12 +1612,10 @@ async function transformActionInputsForRecordAction(
1593
1612
  if (seenPills[fullPillName]) continue;
1594
1613
  seenPills[fullPillName] = true;
1595
1614
 
1596
- // Extract field name from pill (e.g. "Created or Updated_1.current.assigned_to" → "assigned_to")
1597
1615
  var dotParts = fullPillName.split('.');
1598
1616
  var fieldCol = dotParts.length > 2 ? dotParts[dotParts.length - 1] : '';
1599
1617
 
1600
1618
  if (fieldCol) {
1601
- // Look up field metadata from sys_dictionary
1602
1619
  var fMeta: { type: string; label: string } = { type: 'string', label: fieldCol.replace(/_/g, ' ').replace(/\b\w/g, function (c: string) { return c.toUpperCase(); }) };
1603
1620
  try {
1604
1621
  var dictResp = await client.get('/api/now/table/sys_dictionary', {
@@ -1616,7 +1633,7 @@ async function transformActionInputsForRecordAction(
1616
1633
  }
1617
1634
  } catch (_) {}
1618
1635
 
1619
- labelCacheEntries.push({
1636
+ labelCacheInserts.push({
1620
1637
  name: fullPillName,
1621
1638
  label: 'Trigger - Record ' + triggerInfo.triggerName + '\u27a1' + tblLabel + ' Record\u27a1' + fMeta.label,
1622
1639
  reference: '',
@@ -1632,10 +1649,14 @@ async function transformActionInputsForRecordAction(
1632
1649
  }
1633
1650
  }
1634
1651
 
1635
- steps.label_cache = { count: labelCacheEntries.length, pills: labelCacheEntries.map(function (e: any) { return e.name; }), usedInstances: usedInstances.length };
1652
+ steps.label_cache = {
1653
+ updates: labelCacheUpdates.map(function (e: any) { return e.name; }),
1654
+ inserts: labelCacheInserts.map(function (e: any) { return e.name; }),
1655
+ usedInstances: usedInstances.length
1656
+ };
1636
1657
  }
1637
1658
 
1638
- return { inputs: actionInputs, labelCacheEntries, steps };
1659
+ return { inputs: actionInputs, labelCacheUpdates, labelCacheInserts, steps };
1639
1660
  }
1640
1661
 
1641
1662
  // ── FLOW LOGIC (If/Else, For Each, etc.) ─────────────────────────────
@@ -1818,8 +1839,10 @@ async function addFlowLogicViaGraphQL(
1818
1839
  }]
1819
1840
  }
1820
1841
  };
1821
- await executeFlowPatchMutation(client, updatePatch, logicResponseFields);
1822
- steps.condition_update = { success: true };
1842
+ // Log the exact GraphQL mutation for debugging
1843
+ steps.condition_update_mutation = jsToGraphQL(updatePatch);
1844
+ var updateResult = await executeFlowPatchMutation(client, updatePatch, logicResponseFields);
1845
+ steps.condition_update = { success: true, response: updateResult };
1823
1846
  } catch (ue: any) {
1824
1847
  steps.condition_update = { success: false, error: ue.message };
1825
1848
  // Element was created successfully — condition update failure is non-fatal