@servicenow/sdk-build-plugins 4.7.2 → 4.8.1

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.
Files changed (114) hide show
  1. package/dist/alias/alias-plugin.d.ts +2 -0
  2. package/dist/alias/alias-plugin.js +183 -0
  3. package/dist/alias/alias-plugin.js.map +1 -0
  4. package/dist/alias/alias-template-plugin.d.ts +2 -0
  5. package/dist/alias/alias-template-plugin.js +232 -0
  6. package/dist/alias/alias-template-plugin.js.map +1 -0
  7. package/dist/alias/index.d.ts +3 -0
  8. package/dist/alias/index.js +20 -0
  9. package/dist/alias/index.js.map +1 -0
  10. package/dist/alias/retry-policy-plugin.d.ts +2 -0
  11. package/dist/alias/retry-policy-plugin.js +119 -0
  12. package/dist/alias/retry-policy-plugin.js.map +1 -0
  13. package/dist/arrow-function-plugin.d.ts +1 -0
  14. package/dist/arrow-function-plugin.js +60 -21
  15. package/dist/arrow-function-plugin.js.map +1 -1
  16. package/dist/atf/test-plugin.js +1 -1
  17. package/dist/atf/test-plugin.js.map +1 -1
  18. package/dist/basic-syntax-plugin.js +7 -7
  19. package/dist/basic-syntax-plugin.js.map +1 -1
  20. package/dist/column/index.d.ts +2 -0
  21. package/dist/column/index.js +13 -0
  22. package/dist/column/index.js.map +1 -0
  23. package/dist/dashboard/dashboard-plugin.js +4 -0
  24. package/dist/dashboard/dashboard-plugin.js.map +1 -1
  25. package/dist/data-lookup-plugin.d.ts +2 -0
  26. package/dist/data-lookup-plugin.js +159 -0
  27. package/dist/data-lookup-plugin.js.map +1 -0
  28. package/dist/flow/flow-logic/flow-logic-diagnostics.js +2 -1
  29. package/dist/flow/flow-logic/flow-logic-diagnostics.js.map +1 -1
  30. package/dist/flow/flow-logic/flow-logic-plugin.js.map +1 -1
  31. package/dist/flow/plugins/flow-action-definition-plugin.js +81 -16
  32. package/dist/flow/plugins/flow-action-definition-plugin.js.map +1 -1
  33. package/dist/flow/plugins/flow-definition-plugin.js +70 -7
  34. package/dist/flow/plugins/flow-definition-plugin.js.map +1 -1
  35. package/dist/flow/plugins/flow-instance-plugin.d.ts +35 -1
  36. package/dist/flow/plugins/flow-instance-plugin.js +241 -7
  37. package/dist/flow/plugins/flow-instance-plugin.js.map +1 -1
  38. package/dist/flow/plugins/step-instance-plugin.js +61 -1
  39. package/dist/flow/plugins/step-instance-plugin.js.map +1 -1
  40. package/dist/flow/post-install.d.ts +2 -1
  41. package/dist/flow/post-install.js +31 -4
  42. package/dist/flow/post-install.js.map +1 -1
  43. package/dist/flow/utils/complex-object-resolver.js +4 -2
  44. package/dist/flow/utils/complex-object-resolver.js.map +1 -1
  45. package/dist/flow/utils/datapill-transformer.d.ts +5 -72
  46. package/dist/flow/utils/datapill-transformer.js +199 -28
  47. package/dist/flow/utils/datapill-transformer.js.map +1 -1
  48. package/dist/flow/utils/flow-constants.d.ts +7 -0
  49. package/dist/flow/utils/flow-constants.js +6 -1
  50. package/dist/flow/utils/flow-constants.js.map +1 -1
  51. package/dist/flow/utils/flow-io-to-record.js +24 -15
  52. package/dist/flow/utils/flow-io-to-record.js.map +1 -1
  53. package/dist/flow/utils/flow-shapes.d.ts +8 -2
  54. package/dist/flow/utils/flow-shapes.js +19 -0
  55. package/dist/flow/utils/flow-shapes.js.map +1 -1
  56. package/dist/flow/utils/flow-variable-processor.d.ts +6 -6
  57. package/dist/flow/utils/flow-variable-processor.js +8 -8
  58. package/dist/flow/utils/flow-variable-processor.js.map +1 -1
  59. package/dist/form-plugin.js +35 -24
  60. package/dist/form-plugin.js.map +1 -1
  61. package/dist/index.d.ts +5 -1
  62. package/dist/index.js +6 -1
  63. package/dist/index.js.map +1 -1
  64. package/dist/now-attach-plugin.d.ts +1 -1
  65. package/dist/now-config-plugin.js +2 -1
  66. package/dist/now-config-plugin.js.map +1 -1
  67. package/dist/now-delete-plugin.d.ts +2 -0
  68. package/dist/now-delete-plugin.js +64 -0
  69. package/dist/now-delete-plugin.js.map +1 -0
  70. package/dist/record-plugin.d.ts +10 -0
  71. package/dist/record-plugin.js +15 -1
  72. package/dist/record-plugin.js.map +1 -1
  73. package/dist/repack/lint/Rules.js +17 -7
  74. package/dist/repack/lint/Rules.js.map +1 -1
  75. package/dist/rest-message-plugin.d.ts +2 -0
  76. package/dist/rest-message-plugin.js +331 -0
  77. package/dist/rest-message-plugin.js.map +1 -0
  78. package/dist/script-include-plugin.js +1 -1
  79. package/dist/script-include-plugin.js.map +1 -1
  80. package/dist/server-module-plugin/sbom-builder.js +17 -7
  81. package/dist/server-module-plugin/sbom-builder.js.map +1 -1
  82. package/dist/static-content-plugin.js +17 -7
  83. package/dist/static-content-plugin.js.map +1 -1
  84. package/package.json +7 -6
  85. package/src/alias/alias-plugin.ts +221 -0
  86. package/src/alias/alias-template-plugin.ts +271 -0
  87. package/src/alias/index.ts +3 -0
  88. package/src/alias/retry-policy-plugin.ts +138 -0
  89. package/src/arrow-function-plugin.ts +67 -23
  90. package/src/atf/test-plugin.ts +1 -1
  91. package/src/basic-syntax-plugin.ts +7 -7
  92. package/src/column/index.ts +7 -0
  93. package/src/dashboard/dashboard-plugin.ts +4 -0
  94. package/src/data-lookup-plugin.ts +191 -0
  95. package/src/flow/flow-logic/flow-logic-diagnostics.ts +2 -1
  96. package/src/flow/flow-logic/flow-logic-plugin.ts +0 -1
  97. package/src/flow/plugins/flow-action-definition-plugin.ts +92 -25
  98. package/src/flow/plugins/flow-definition-plugin.ts +114 -8
  99. package/src/flow/plugins/flow-instance-plugin.ts +264 -7
  100. package/src/flow/plugins/step-instance-plugin.ts +74 -2
  101. package/src/flow/post-install.ts +36 -5
  102. package/src/flow/utils/complex-object-resolver.ts +4 -2
  103. package/src/flow/utils/datapill-transformer.ts +248 -36
  104. package/src/flow/utils/flow-constants.ts +8 -0
  105. package/src/flow/utils/flow-io-to-record.ts +28 -14
  106. package/src/flow/utils/flow-shapes.ts +19 -0
  107. package/src/flow/utils/flow-variable-processor.ts +21 -10
  108. package/src/form-plugin.ts +47 -26
  109. package/src/index.ts +5 -1
  110. package/src/now-config-plugin.ts +2 -1
  111. package/src/now-delete-plugin.ts +82 -0
  112. package/src/record-plugin.ts +17 -2
  113. package/src/rest-message-plugin.ts +391 -0
  114. package/src/script-include-plugin.ts +4 -1
@@ -36,7 +36,7 @@ import { STEP_PILL_TYPE_REGEX, stripPillType, collectPillTypes } from '../utils/
36
36
  import { COLUMN_TYPE_TO_API } from '../../column/column-helper'
37
37
  import { buildComplexObjectFromSchema, parseAttributesToObject } from '../utils/schema-to-flow-object'
38
38
  import { normalizeInputValue } from './flow-instance-plugin'
39
- import { ApprovalRulesShape, ApprovalDueDateShape } from '../utils/flow-shapes'
39
+ import { ApprovalRulesShape, ApprovalDueDateShape, getRefSysId } from '../utils/flow-shapes'
40
40
  import { ArrowFunctionShape } from '../../arrow-function-plugin'
41
41
  import { FDInlineScriptCallShape } from './inline-script-plugin'
42
42
  import { StepInstanceShape, StepInstancePlugin } from './step-instance-plugin'
@@ -62,9 +62,7 @@ function resolveInlineScripts(
62
62
  allInputScripts: Record[],
63
63
  stepInstance: Record
64
64
  ): void {
65
- const inputScriptRecords = allInputScripts.filter(
66
- (r: Record) => r.get('instance')?.asString()?.getValue() === stepSysId
67
- )
65
+ const inputScriptRecords = allInputScripts.filter((r: Record) => getRefSysId(r.get('instance')) === stepSysId)
68
66
 
69
67
  for (const scriptRecord of inputScriptRecords) {
70
68
  const inputName = scriptRecord.get('input_name')?.asString()?.getValue()
@@ -1650,14 +1648,12 @@ export const ActionDefinitionPlugin = Plugin.create({
1650
1648
  // sys_hub_status_condition holds the individual conditions.
1651
1649
  const actionStatusMetadata = descendants
1652
1650
  .query('sys_hub_action_status_metadata')
1653
- .filter((r) => r.get('action_type_id')?.asString()?.getValue() === actionSysId)
1651
+ .filter((r) => getRefSysId(r.get('action_type_id')) === actionSysId)
1654
1652
  const actionStatusMetadataIds = actionStatusMetadata.map((r) => r.getId().getValue())
1655
1653
  const statusConditions = descendants
1656
1654
  .query('sys_hub_status_condition')
1657
1655
  .filter((r) =>
1658
- actionStatusMetadataIds.includes(
1659
- r.get('action_status_metadata_id')?.asString()?.getValue() ?? ''
1660
- )
1656
+ actionStatusMetadataIds.includes(getRefSysId(r.get('action_status_metadata_id')) ?? '')
1661
1657
  )
1662
1658
 
1663
1659
  // Filter inputs/outputs to only those belonging to this action definition,
@@ -1668,11 +1664,11 @@ export const ActionDefinitionPlugin = Plugin.create({
1668
1664
  Number(b.get('order')?.asString()?.getValue() ?? 0)
1669
1665
  const actionInputs = descendants
1670
1666
  .query('sys_hub_action_input')
1671
- .filter((r) => r.get('model')?.asString()?.getValue() === actionSysId)
1667
+ .filter((r) => getRefSysId(r.get('model')) === actionSysId)
1672
1668
  .sort(sortByOrder)
1673
1669
  const actionOutputs = descendants
1674
1670
  .query('sys_hub_action_output')
1675
- .filter((r) => r.get('model')?.asString()?.getValue() === actionSysId)
1671
+ .filter((r) => getRefSysId(r.get('model')) === actionSysId)
1676
1672
  .sort(sortByOrder)
1677
1673
 
1678
1674
  const inputs = buildVariableShapes(actionInputs, descendants)
@@ -1694,7 +1690,7 @@ export const ActionDefinitionPlugin = Plugin.create({
1694
1690
  // excluding snapshot-parented step instances
1695
1691
  const stepInstances = descendants
1696
1692
  .query('sys_hub_step_instance')
1697
- .filter((s) => s.get('action')?.asString()?.getValue() === actionSysId)
1693
+ .filter((s) => getRefSysId(s.get('action')) === actionSysId)
1698
1694
  const stepShapes: Shape[] = []
1699
1695
  const cidToIdentifierMap = new Map<string, IdentifierShape>()
1700
1696
 
@@ -1730,7 +1726,7 @@ export const ActionDefinitionPlugin = Plugin.create({
1730
1726
 
1731
1727
  // Filter variable values for this step instance
1732
1728
  const stepVarValues = allVariableValues.filter(
1733
- (v) => v.get('document_key')?.asString()?.getValue() === stepSysId
1729
+ (v) => getRefSysId(v.get('document_key')) === stepSysId
1734
1730
  )
1735
1731
 
1736
1732
  // Build reverse lookup: element name → uiType
@@ -1764,7 +1760,7 @@ export const ActionDefinitionPlugin = Plugin.create({
1764
1760
  // Build a lookup of ext input datapill values from element_mappings
1765
1761
  const extInputMappingValues: globalThis.Record<string, string> = {}
1766
1762
  const stepElementMappings = allElementMappings.filter(
1767
- (m) => m.get('id')?.asString()?.getValue() === stepSysId
1763
+ (m) => getRefSysId(m.get('id')) === stepSysId
1768
1764
  )
1769
1765
  for (const mapping of stepElementMappings) {
1770
1766
  const rawFieldName = mapping.get('field')?.asString()?.getValue()
@@ -1834,9 +1830,7 @@ export const ActionDefinitionPlugin = Plugin.create({
1834
1830
  }
1835
1831
 
1836
1832
  // Build inputVariables from sys_hub_step_ext_input records
1837
- const stepExtInputs = allExtInputs.filter(
1838
- (r) => r.get('model_id')?.asString()?.getValue() === stepSysId
1839
- )
1833
+ const stepExtInputs = allExtInputs.filter((r) => getRefSysId(r.get('model_id')) === stepSysId)
1840
1834
  if (stepExtInputs.length > 0) {
1841
1835
  const inputVariablesObj: Props = {}
1842
1836
  for (const extInput of stepExtInputs) {
@@ -1849,7 +1843,7 @@ export const ActionDefinitionPlugin = Plugin.create({
1849
1843
  // Find value from sys_variable_value or element_mapping (datapill)
1850
1844
  // Prioritize pills from sys_element_mapping over static values from sys_variable_value
1851
1845
  const varValueRecord = stepVarValues.find(
1852
- (v) => v.get('variable')?.asString()?.getValue() === extInputSysId
1846
+ (v) => getRefSysId(v.get('variable')) === extInputSysId
1853
1847
  )
1854
1848
  const value =
1855
1849
  extInputMappingValues[elementName] ??
@@ -1869,9 +1863,7 @@ export const ActionDefinitionPlugin = Plugin.create({
1869
1863
  }
1870
1864
 
1871
1865
  // Build outputVariables from sys_hub_step_ext_output records
1872
- const stepExtOutputs = allExtOutputs.filter(
1873
- (r) => r.get('model_id')?.asString()?.getValue() === stepSysId
1874
- )
1866
+ const stepExtOutputs = allExtOutputs.filter((r) => getRefSysId(r.get('model_id')) === stepSysId)
1875
1867
  if (stepExtOutputs.length > 0) {
1876
1868
  const outputVariablesObj: Props = {}
1877
1869
  for (const extOutput of stepExtOutputs) {
@@ -2085,7 +2077,7 @@ export const ActionDefinitionPlugin = Plugin.create({
2085
2077
  const candidateIds = new Set<string>([actionSysId])
2086
2078
  const snapshots = descendants
2087
2079
  .query('sys_hub_action_type_snapshot')
2088
- .filter((s) => s.get('parent_action')?.asString()?.getValue() === actionSysId)
2080
+ .filter((s) => getRefSysId(s.get('parent_action')) === actionSysId)
2089
2081
  for (const snap of snapshots) {
2090
2082
  candidateIds.add(snap.getId().getValue())
2091
2083
  }
@@ -2095,7 +2087,7 @@ export const ActionDefinitionPlugin = Plugin.create({
2095
2087
  .query('sys_element_mapping')
2096
2088
  .filter(
2097
2089
  (m) =>
2098
- candidateIds.has(m.get('id')?.asString()?.getValue() ?? '') &&
2090
+ candidateIds.has(getRefSysId(m.get('id')) ?? '') &&
2099
2091
  (m.get('table')?.asString()?.getValue() ?? '').startsWith(ACTION_OUTPUT_TABLE_PREFIX)
2100
2092
  )
2101
2093
 
@@ -2104,7 +2096,7 @@ export const ActionDefinitionPlugin = Plugin.create({
2104
2096
  const varSysIdToElement = new Map<string, string>()
2105
2097
  const snapshotOutputs = descendants
2106
2098
  .query('sys_hub_action_output')
2107
- .filter((r) => candidateIds.has(r.get('model')?.asString()?.getValue() ?? ''))
2099
+ .filter((r) => candidateIds.has(getRefSysId(r.get('model')) ?? ''))
2108
2100
  for (const outputRec of [...snapshotOutputs, ...actionOutputs]) {
2109
2101
  const element = outputRec.get('element')?.asString()?.getValue()
2110
2102
  if (element) {
@@ -2193,9 +2185,11 @@ export const ActionDefinitionPlugin = Plugin.create({
2193
2185
  }
2194
2186
 
2195
2187
  // Build args: config + optional body with step instances
2188
+ const masterSnapshotId = record.get('master_snapshot')?.ifString()?.getValue()
2196
2189
  const actionConfig = record.transform(({ $ }) => ({
2197
2190
  $id: $.val(NowIdShape.from(record)),
2198
2191
  name: $,
2192
+ internalName: $.from('internal_name'),
2199
2193
  annotation: $.def(''),
2200
2194
  description: $.def(''),
2201
2195
  access: $.def('public'),
@@ -2203,6 +2197,7 @@ export const ActionDefinitionPlugin = Plugin.create({
2203
2197
  protectionPolicy: $.from('sys_policy').def(''),
2204
2198
  inputs: $.val(inputs),
2205
2199
  outputs: $.val(outputs),
2200
+ ...(masterSnapshotId ? { masterSnapshot: $.val(masterSnapshotId) } : {}),
2206
2201
  }))
2207
2202
 
2208
2203
  const args: unknown[] = [actionConfig]
@@ -2280,12 +2275,14 @@ export const ActionDefinitionPlugin = Plugin.create({
2280
2275
 
2281
2276
  const inputsConfig = actionConfiguration.get('inputs').ifObject()?.asObject()
2282
2277
 
2278
+ const actionInternalName = actionConfiguration.get('internalName').ifString()?.getValue()
2283
2279
  let actionDefinitionRecord = await factory.createRecord({
2284
2280
  source: callExpression,
2285
2281
  table: 'sys_hub_action_type_definition',
2286
2282
  explicitId: actionConfiguration.get('$id'),
2287
2283
  properties: actionConfiguration.transform(({ $ }) => ({
2288
2284
  name: $,
2285
+ ...(actionInternalName ? { internal_name: $.val(actionInternalName) } : {}),
2289
2286
  annotation: $.def(''),
2290
2287
  description: $.def(''),
2291
2288
  access: $.def('public'),
@@ -2574,8 +2571,9 @@ export const ActionDefinitionPlugin = Plugin.create({
2574
2571
  const collectedStepPills = extractStepPillsFromRecords(relatedRecords, cidToLabelMap, pillTypeMap)
2575
2572
  const dotWalkPills = extractActionDotWalkPills(relatedRecords, pillTypeMap)
2576
2573
 
2574
+ let labelCacheJson: string | undefined
2577
2575
  if (inputsConfig) {
2578
- const labelCacheJson = buildActionLabelCache(inputsConfig, {
2576
+ labelCacheJson = buildActionLabelCache(inputsConfig, {
2579
2577
  stepPills: collectedStepPills,
2580
2578
  dotWalkPills,
2581
2579
  cidToLabelMap,
@@ -2585,9 +2583,78 @@ export const ActionDefinitionPlugin = Plugin.create({
2585
2583
  }
2586
2584
  }
2587
2585
 
2586
+ const masterSnapshotFromConfig = actionConfiguration.get('masterSnapshot')?.ifString()?.getValue()
2587
+
2588
+ if (!masterSnapshotFromConfig) {
2589
+ return {
2590
+ success: true,
2591
+ value: actionDefinitionRecord.with(...relatedRecords),
2592
+ }
2593
+ }
2594
+
2595
+ let snapshotRecord = await factory.createRecord({
2596
+ source: callExpression,
2597
+ table: 'sys_hub_action_type_snapshot',
2598
+ explicitId: masterSnapshotFromConfig,
2599
+ properties: actionConfiguration.transform(({ $ }) => ({
2600
+ access: $.def('public'),
2601
+ active: $.val(false),
2602
+ annotation: $.def(''),
2603
+ callable_by_client_api: $.val(false),
2604
+ category: $.def(''),
2605
+ description: $.def(''),
2606
+ master: $.val(true),
2607
+ name: $,
2608
+ natlang: $.def(''),
2609
+ parent_action: $.val(actionDefinitionRecord.getId().getValue()),
2610
+ state: $.val('draft'),
2611
+ sys_policy: $.from('protectionPolicy').def(''),
2612
+ system_level: $.val(false),
2613
+ })),
2614
+ })
2615
+
2616
+ if (labelCacheJson) {
2617
+ snapshotRecord = snapshotRecord.merge({ label_cache: labelCacheJson })
2618
+ }
2619
+
2620
+ const snapshotRelatedRecords: Record[] = []
2621
+
2622
+ if (inputsConfig) {
2623
+ const { variableRecords: snapInputRecords, complexObjectRecords: snapInputComplexObjects } =
2624
+ await buildVariableRecords({
2625
+ variablesConfig: inputsConfig,
2626
+ parentRecord: snapshotRecord,
2627
+ factory,
2628
+ diagnostics,
2629
+ parentTable: 'sys_hub_action_type_snapshot',
2630
+ varTable: 'sys_hub_action_input',
2631
+ })
2632
+ snapshotRelatedRecords.push(...snapInputRecords, ...snapInputComplexObjects)
2633
+ }
2634
+
2635
+ if (outputsConfig) {
2636
+ const { variableRecords: snapOutputRecords, complexObjectRecords: snapOutputComplexObjects } =
2637
+ await buildVariableRecords({
2638
+ variablesConfig: outputsConfig,
2639
+ parentRecord: snapshotRecord,
2640
+ factory,
2641
+ diagnostics,
2642
+ parentTable: 'sys_hub_action_type_snapshot',
2643
+ varTable: 'sys_hub_action_output',
2644
+ isOutput: true,
2645
+ })
2646
+ snapshotRelatedRecords.push(...snapOutputRecords, ...snapOutputComplexObjects)
2647
+ }
2648
+
2649
+ const snapshotId = snapshotRecord.getId().getValue()
2650
+ const finalActionRecord = actionDefinitionRecord.merge({
2651
+ latest_snapshot: snapshotId,
2652
+ master_snapshot: snapshotId,
2653
+ })
2654
+
2588
2655
  return {
2589
2656
  success: true,
2590
- value: actionDefinitionRecord.with(...relatedRecords),
2657
+ value: finalActionRecord.with(...relatedRecords, snapshotRecord, ...snapshotRelatedRecords),
2591
2658
  }
2592
2659
  },
2593
2660
  },
@@ -82,7 +82,12 @@ import { isDataPill } from '../utils/complex-object-resolver'
82
82
  import { wrapWithDataPillCall, extractDataPillNames } from '../utils/pill-shape-helpers'
83
83
  import { ArrayShape } from '@servicenow/sdk-build-core'
84
84
  import { processFlowInputs, processFlowOutputs, processFlowVariables } from '../utils/flow-variable-processor'
85
- import { buildUuidToIdentifierMap, processInstanceForDatapills, uuidToRecordMap } from '../utils/datapill-transformer'
85
+ import {
86
+ buildUuidToIdentifierMap,
87
+ detectHoistedOutputBindings,
88
+ processInstanceForDatapills,
89
+ uuidToRecordMap,
90
+ } from '../utils/datapill-transformer'
86
91
  import {
87
92
  DEFAULT_PARAM_NAME,
88
93
  PARALLEL_ORDER_SEPARATOR,
@@ -646,7 +651,6 @@ function extractAllPills(
646
651
  })
647
652
  }
648
653
  } else {
649
- // NOT a forEach parameter - preserve full property path
650
654
  expression = new PropertyAccessShape({
651
655
  source,
652
656
  elements: [identifier, property],
@@ -774,6 +778,7 @@ function transformDataPill(
774
778
  // {{flowVariables}} and {{outputs}} should remain as bare PropertyAccessShape without wrapping
775
779
  if (stringValue === '{{flowVariables}}' || stringValue === '{{outputs}}') {
776
780
  const allPills = extractAllPills(stringValue, uuidToIdentifierMap, source, diagnostics, parameterName)
781
+
777
782
  if (allPills.length === 1 && allPills[0]?.expression.is(PropertyAccessShape)) {
778
783
  return allPills[0].expression as PropertyAccessShape
779
784
  }
@@ -1497,7 +1502,7 @@ function postProcessAssignSubflowOutputs(
1497
1502
  subflowDefinitionRecord: Record,
1498
1503
  logger: Logger
1499
1504
  ): ValuesJSON {
1500
- if (!valuesJSON || !valuesJSON.outputsToAssign || !Array.isArray(valuesJSON.outputsToAssign)) {
1505
+ if (!valuesJSON?.outputsToAssign || !Array.isArray(valuesJSON.outputsToAssign)) {
1501
1506
  return valuesJSON
1502
1507
  }
1503
1508
 
@@ -1682,6 +1687,8 @@ export const FlowDefinitionPlugin = Plugin.create({
1682
1687
  return deleteMultipleDiff(existing, incoming, descendants, context)
1683
1688
  },
1684
1689
  async toShape(record, { descendants, diagnostics, transform, database, logger }) {
1690
+ const masterSnapshotId = record.get('master_snapshot')?.ifString()?.getValue()
1691
+
1685
1692
  let type = record.get('type')?.getValue()
1686
1693
  if (!type) {
1687
1694
  logger.warn(`sys_hub_flow record has no type specified, defaulting to 'flow'`)
@@ -1771,6 +1778,15 @@ export const FlowDefinitionPlugin = Plugin.create({
1771
1778
  // Use recordToShapeMap to access ui_id from records (datapills reference ui_id, not $id)
1772
1779
  const uuidToIdentifierMap = buildUuidToIdentifierMap(recordToShapeMap)
1773
1780
 
1781
+ // Hoisting guard: if any action nested inside a DoInParallel or TryCatch block has its output
1782
+ // referenced from outside that block, fall back to Record() API.
1783
+ if (detectHoistedOutputBindings(allInstances)) {
1784
+ logger.warn(
1785
+ `Hoisting detected: action instance outputs are referenced outside their DoInParallel/TryCatch scope, falling back to Record() api. Flow = ${record.getId().getValue()}`
1786
+ )
1787
+ return { success: false }
1788
+ }
1789
+
1774
1790
  // For the flow body, only use top-level instances (those without parent_ui_id). Also exclude Catch
1775
1791
  // records — they are subsumed into their paired Try's `wfa.flowLogic.tryCatch(...)` shape via
1776
1792
  // `connected_to`, and emitting them separately would produce a duplicate top-level statement.
@@ -1830,7 +1846,6 @@ export const FlowDefinitionPlugin = Plugin.create({
1830
1846
  // 2. Semantic pills: {{trigger.property}}, {{flow_variable.name}} → references to flow parameters (e.g., {{trigger.table_name}} → params.trigger.table_name)
1831
1847
 
1832
1848
  // Process all instances (Action, Subflow, and Flow Logic) recursively
1833
- // This handles datapill transformation for all instance types and their nested children
1834
1849
  instanceShapes.forEach((instanceShape: Shape, index) => {
1835
1850
  const result = processInstanceForDatapills(
1836
1851
  instanceShape,
@@ -1848,6 +1863,7 @@ export const FlowDefinitionPlugin = Plugin.create({
1848
1863
  instanceShapes[index] = result.shape
1849
1864
  }
1850
1865
  })
1866
+
1851
1867
  const flowBody = new ArrowFunctionShape({
1852
1868
  source: record,
1853
1869
  parameters: [new IdentifierShape({ source: record, name: paramName })],
@@ -1862,6 +1878,7 @@ export const FlowDefinitionPlugin = Plugin.create({
1862
1878
  record.transform(({ $ }) => ({
1863
1879
  $id: $.val(NowIdShape.from(record)),
1864
1880
  name: $,
1881
+ internalName: $.from('internal_name'),
1865
1882
  description: $.def(EMPTY_STRING),
1866
1883
  protectionPolicy: $.from('sys_policy').def(EMPTY_STRING),
1867
1884
  runAs: $.from('run_as').def(RUN_AS_DEFAULT),
@@ -1877,6 +1894,7 @@ export const FlowDefinitionPlugin = Plugin.create({
1877
1894
  flowPriority: $.from('flow_priority')
1878
1895
  .map((p) => p.ifString()?.getValue() || FLOW_PRIORITY_DEFAULT)
1879
1896
  .def(FLOW_PRIORITY_DEFAULT),
1897
+ ...(masterSnapshotId ? { masterSnapshot: $.val(masterSnapshotId) } : {}),
1880
1898
  ...(isSubflow
1881
1899
  ? {
1882
1900
  annotation: $.def(EMPTY_STRING),
@@ -1975,12 +1993,14 @@ export const FlowDefinitionPlugin = Plugin.create({
1975
1993
  }
1976
1994
 
1977
1995
  const roles = flowConfiguration.get('runWithRoles').ifArray()?.getElements() ?? []
1996
+ const internalName = flowConfiguration.get('internalName').ifString()?.getValue()
1978
1997
  const flowDefinitionRecord = await factory.createRecord({
1979
1998
  source: callExpression,
1980
1999
  table: 'sys_hub_flow',
1981
2000
  explicitId: flowConfiguration.get('$id'),
1982
2001
  properties: flowConfiguration.transform(({ $ }) => ({
1983
2002
  name: $,
2003
+ ...(internalName ? { internal_name: $.val(internalName) } : {}),
1984
2004
  annotation: $.def(EMPTY_STRING),
1985
2005
  description: $.def(EMPTY_STRING),
1986
2006
  access: $.def(ACCESS_DEFAULT),
@@ -2046,9 +2066,11 @@ export const FlowDefinitionPlugin = Plugin.create({
2046
2066
  relatedRecords.push(...flowVarRecords)
2047
2067
  }
2048
2068
 
2069
+ const inputsConfig = isSubflow ? flowConfiguration.get('inputs').ifObject()?.asObject() : undefined
2070
+ const outputsConfig = isSubflow ? flowConfiguration.get('outputs').ifObject()?.asObject() : undefined
2071
+
2049
2072
  if (isSubflow) {
2050
2073
  // Process subflow inputs and outputs
2051
- const inputsConfig = flowConfiguration.get('inputs').ifObject()?.asObject()
2052
2074
  const inputRecords = await processFlowInputs(
2053
2075
  inputsConfig,
2054
2076
  flowDefinitionRecord,
@@ -2057,7 +2079,6 @@ export const FlowDefinitionPlugin = Plugin.create({
2057
2079
  )
2058
2080
  relatedRecords.push(...inputRecords)
2059
2081
 
2060
- const outputsConfig = flowConfiguration.get('outputs').ifObject()?.asObject()
2061
2082
  const outputRecords = await processFlowOutputs(
2062
2083
  outputsConfig,
2063
2084
  flowDefinitionRecord,
@@ -2260,16 +2281,101 @@ export const FlowDefinitionPlugin = Plugin.create({
2260
2281
  )
2261
2282
 
2262
2283
  const labelCacheData = Array.from(labelCacheMap.values())
2284
+ const labelCacheValue = labelCacheData.length > 0 ? JSON.stringify(labelCacheData) : '[]'
2285
+
2263
2286
  const flowDefWithMetadata =
2264
2287
  labelCacheData.length > 0
2265
2288
  ? flowDefinitionRecord.merge({
2266
- label_cache: JSON.stringify(labelCacheData),
2289
+ label_cache: labelCacheValue,
2267
2290
  })
2268
2291
  : flowDefinitionRecord
2269
2292
 
2293
+ const masterSnapshotFromConfig = flowConfiguration.get('masterSnapshot')?.ifString()?.getValue()
2294
+
2295
+ if (!masterSnapshotFromConfig) {
2296
+ return {
2297
+ success: true,
2298
+ value: flowDefWithMetadata.with(...relatedRecords),
2299
+ }
2300
+ }
2301
+
2302
+ const snapshotRecord = await factory.createRecord({
2303
+ source: callExpression,
2304
+ table: 'sys_hub_flow_snapshot',
2305
+ explicitId: masterSnapshotFromConfig,
2306
+ properties: flowConfiguration.transform(({ $ }) => ({
2307
+ access: $.def(ACCESS_DEFAULT),
2308
+ active: $.val(false),
2309
+ allow_high_security_roles: $.def(BOOLEAN_FALSE_STRING),
2310
+ annotation: $.def(EMPTY_STRING),
2311
+ attributes: $.def(EMPTY_STRING),
2312
+ callable_by_client_api: $.def(BOOLEAN_FALSE_STRING),
2313
+ category: $.def(EMPTY_STRING),
2314
+ description: $.def(EMPTY_STRING),
2315
+ flow_priority: $.from('flowPriority').def(FLOW_PRIORITY_DEFAULT),
2316
+ label_cache: $.val(labelCacheValue),
2317
+ master: $.val(true),
2318
+ name: $,
2319
+ natlang: $.def(EMPTY_STRING),
2320
+ outputs: $.def(EMPTY_STRING),
2321
+ parent_flow: $.val(flowDefinitionRecord.getId().getValue()),
2322
+ remote_trigger_id: $.def(EMPTY_STRING),
2323
+ run_as: $.from('runAs').def(RUN_AS_DEFAULT),
2324
+ run_with_roles: $.val(
2325
+ Array.from(
2326
+ new Set(roles.map((r) => r.ifRecord()?.getId().getValue() ?? r.getValue()))
2327
+ ).join(',')
2328
+ ),
2329
+ sc_callable: $.def(BOOLEAN_FALSE_STRING),
2330
+ status: $.val(FLOW_STATUS_DRAFT),
2331
+ sys_policy: $.from('protectionPolicy').def(EMPTY_STRING),
2332
+ type: isFlow ? $.def(FLOW_TYPE_FLOW) : $.def(FLOW_TYPE_SUBFLOW),
2333
+ version: $.def(FLOW_VERSION),
2334
+ })),
2335
+ })
2336
+
2337
+ const snapshotRelatedRecords: Record[] = []
2338
+
2339
+ if (isSubflow) {
2340
+ const snapshotInputRecords = await processFlowInputs(
2341
+ inputsConfig,
2342
+ snapshotRecord,
2343
+ factory,
2344
+ diagnostics,
2345
+ 'sys_hub_flow_snapshot'
2346
+ )
2347
+ snapshotRelatedRecords.push(...snapshotInputRecords)
2348
+
2349
+ const snapshotOutputRecords = await processFlowOutputs(
2350
+ outputsConfig,
2351
+ snapshotRecord,
2352
+ factory,
2353
+ diagnostics,
2354
+ 'sys_hub_flow_snapshot'
2355
+ )
2356
+ snapshotRelatedRecords.push(...snapshotOutputRecords)
2357
+ }
2358
+
2359
+ if (flowConfiguration.has('flowVariables')) {
2360
+ const snapshotVarRecords = await processFlowVariables(
2361
+ flowConfiguration.get('flowVariables').asObject(),
2362
+ snapshotRecord,
2363
+ factory,
2364
+ diagnostics,
2365
+ 'sys_hub_flow_snapshot'
2366
+ )
2367
+ snapshotRelatedRecords.push(...snapshotVarRecords)
2368
+ }
2369
+
2370
+ const snapshotId = snapshotRecord.getId().getValue()
2371
+ const finalFlowRecord = flowDefWithMetadata.merge({
2372
+ latest_snapshot: snapshotId,
2373
+ master_snapshot: snapshotId,
2374
+ })
2375
+
2270
2376
  return {
2271
2377
  success: true,
2272
- value: flowDefWithMetadata.with(...relatedRecords),
2378
+ value: finalFlowRecord.with(...relatedRecords, snapshotRecord, ...snapshotRelatedRecords),
2273
2379
  }
2274
2380
  },
2275
2381
  },