@uipath/maestro-builder-sdk 6.18.9 → 6.19.0

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 (111) hide show
  1. package/dist/api-index.md +185 -184
  2. package/dist/api-members.md +504 -473
  3. package/dist/bpmn/uipath-moddle.v1.json +5 -0
  4. package/dist/case/decompile-cli.js +2 -8
  5. package/dist/check.js +177 -650
  6. package/dist/core/actions.d.ts +119 -760
  7. package/dist/core/actions.js +0 -306
  8. package/dist/core/error-port.d.ts +6 -0
  9. package/dist/core/error-port.js +9 -0
  10. package/dist/core/node-classes.d.ts +4 -63
  11. package/dist/core/node-classes.js +0 -112
  12. package/dist/core/nodes/family.d.ts +36 -0
  13. package/dist/core/nodes/family.js +1 -0
  14. package/dist/core/nodes/node-type.d.ts +136 -0
  15. package/dist/core/nodes/node-type.js +1 -0
  16. package/dist/core/nodes/registry.d.ts +57 -0
  17. package/dist/core/nodes/registry.js +122 -0
  18. package/dist/core/nodes/versioned.d.ts +50 -0
  19. package/dist/core/nodes/versioned.js +46 -0
  20. package/dist/core/typed-raw-node.d.ts +13 -62
  21. package/dist/core/typed-raw-node.js +40 -154
  22. package/dist/decompile-cli.js +2 -9
  23. package/dist/decompile.js +92 -271
  24. package/dist/flow-definitions.d.ts +10 -0
  25. package/dist/flow-definitions.js +35 -0
  26. package/dist/flow-node-registry.d.ts +13 -0
  27. package/dist/flow-node-registry.js +19 -0
  28. package/dist/flow-node-type.d.ts +192 -0
  29. package/dist/flow-node-type.js +1 -0
  30. package/dist/flow-sdk.d.ts +7 -0
  31. package/dist/flow-sdk.js +8 -0
  32. package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
  33. package/dist/nodes/data-fabric/flow/check.js +164 -0
  34. package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
  35. package/dist/nodes/data-fabric/flow/factories.js +134 -0
  36. package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
  37. package/dist/nodes/data-fabric/flow/family.js +9 -0
  38. package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
  39. package/dist/nodes/data-fabric/flow/index.js +8 -0
  40. package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
  41. package/dist/nodes/data-fabric/flow/raw.js +100 -0
  42. package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
  43. package/dist/nodes/data-fabric/flow/shared.js +174 -0
  44. package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
  45. package/dist/nodes/data-fabric/flow/spec.js +1 -0
  46. package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
  47. package/dist/nodes/data-fabric/flow/verbs.js +239 -0
  48. package/dist/nodes/delay/flow/check.d.ts +16 -0
  49. package/dist/nodes/delay/flow/check.js +86 -0
  50. package/dist/nodes/delay/flow/factories.d.ts +28 -0
  51. package/dist/nodes/delay/flow/factories.js +38 -0
  52. package/dist/nodes/delay/flow/family.d.ts +3 -0
  53. package/dist/nodes/delay/flow/family.js +8 -0
  54. package/dist/nodes/delay/flow/index.d.ts +3 -0
  55. package/dist/nodes/delay/flow/index.js +3 -0
  56. package/dist/nodes/delay/flow/node-type.d.ts +13 -0
  57. package/dist/nodes/delay/flow/node-type.js +71 -0
  58. package/dist/nodes/delay/flow/spec.d.ts +43 -0
  59. package/dist/nodes/delay/flow/spec.js +16 -0
  60. package/dist/nodes/document/flow/factories.d.ts +27 -0
  61. package/dist/nodes/document/flow/factories.js +30 -0
  62. package/dist/nodes/document/flow/family.d.ts +3 -0
  63. package/dist/nodes/document/flow/family.js +7 -0
  64. package/dist/nodes/document/flow/index.d.ts +3 -0
  65. package/dist/nodes/document/flow/index.js +3 -0
  66. package/dist/nodes/document/flow/node-type.d.ts +14 -0
  67. package/dist/nodes/document/flow/node-type.js +150 -0
  68. package/dist/nodes/document/flow/spec.d.ts +65 -0
  69. package/dist/nodes/document/flow/spec.js +1 -0
  70. package/dist/nodes/mock/flow/factories.d.ts +51 -0
  71. package/dist/nodes/mock/flow/factories.js +47 -0
  72. package/dist/nodes/mock/flow/family.d.ts +3 -0
  73. package/dist/nodes/mock/flow/family.js +7 -0
  74. package/dist/nodes/mock/flow/index.d.ts +2 -0
  75. package/dist/nodes/mock/flow/index.js +2 -0
  76. package/dist/nodes/mock/flow/node-type.d.ts +11 -0
  77. package/dist/nodes/mock/flow/node-type.js +51 -0
  78. package/dist/nodes/script/flow/check.d.ts +19 -0
  79. package/dist/nodes/script/flow/check.js +49 -0
  80. package/dist/nodes/script/flow/factories.d.ts +14 -0
  81. package/dist/nodes/script/flow/factories.js +15 -0
  82. package/dist/nodes/script/flow/family.d.ts +3 -0
  83. package/dist/nodes/script/flow/family.js +8 -0
  84. package/dist/nodes/script/flow/index.d.ts +3 -0
  85. package/dist/nodes/script/flow/index.js +3 -0
  86. package/dist/nodes/script/flow/node-type.d.ts +7 -0
  87. package/dist/nodes/script/flow/node-type.js +125 -0
  88. package/dist/nodes/script/flow/spec.d.ts +52 -0
  89. package/dist/nodes/script/flow/spec.js +1 -0
  90. package/dist/nodes/transform/flow/check.d.ts +6 -0
  91. package/dist/nodes/transform/flow/check.js +229 -0
  92. package/dist/nodes/transform/flow/factories.d.ts +52 -0
  93. package/dist/nodes/transform/flow/factories.js +53 -0
  94. package/dist/nodes/transform/flow/family.d.ts +3 -0
  95. package/dist/nodes/transform/flow/family.js +8 -0
  96. package/dist/nodes/transform/flow/index.d.ts +3 -0
  97. package/dist/nodes/transform/flow/index.js +3 -0
  98. package/dist/nodes/transform/flow/node-type.d.ts +7 -0
  99. package/dist/nodes/transform/flow/node-type.js +244 -0
  100. package/dist/nodes/transform/flow/spec.d.ts +116 -0
  101. package/dist/nodes/transform/flow/spec.js +10 -0
  102. package/dist/raw-node-advice.d.ts +16 -0
  103. package/dist/raw-node-advice.js +36 -0
  104. package/dist/raw-node.d.ts +71 -0
  105. package/dist/raw-node.js +116 -0
  106. package/dist/registry/uip/launch.d.ts +11 -1
  107. package/dist/registry/uip/launch.js +50 -43
  108. package/dist/registry/uip/pipeline-front-door.d.ts +2 -0
  109. package/dist/registry/uip/pipeline-front-door.js +88 -0
  110. package/dist/serialize.js +138 -492
  111. package/package.json +2 -2
@@ -0,0 +1,134 @@
1
+ /**
2
+ * The Flow Data Fabric factories: `dataFabricRead()`, `dataFabricCreate()`,
3
+ * `dataFabricUpdate()` and `dataFabricDelete()`. Moved from core/actions.ts in
4
+ * Phase 2c of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the package entry re-exports
5
+ * them, so authors import them exactly as before.
6
+ */
7
+ import { builtinActionSpec } from '../../../core/actions.js';
8
+ /**
9
+ * Query entity records from Data Fabric (`core.datafabric.read`). The result
10
+ * publishes to the step's `output`; downstream references re-fetch fresh data
11
+ * at activation time (the engine re-runs the query rather than caching).
12
+ *
13
+ * @remarks
14
+ * This node is **read-one AND query-many**, on its 1.4 definition: `resultMode:
15
+ * 'multiple'` publishes the matching records under `output.results`, and the
16
+ * platform renames the node "Query entity records" to say so. The SDK still
17
+ * pins 1.0 — read-one — as the no-`{ version }` default, so passing
18
+ * `resultMode` is what selects 1.4; see {@link DataFabricReadInputs.resultMode}.
19
+ *
20
+ * The native family covers all four CRUD verbs: this one,
21
+ * {@link dataFabricCreate}, {@link dataFabricUpdate} and
22
+ * {@link dataFabricDelete}. What it does NOT cover is get-by-id, a query row
23
+ * limit, file record fields, and entity events — those are operations on the
24
+ * SAME product reached through its Integration Service connector,
25
+ * `uipath-uipath-dataservice` (the tenant displays it as **UiPath Data
26
+ * Fabric**). So a flow that needs one of those still straddles two surfaces,
27
+ * and the connector remains the one surface that covers everything:
28
+ *
29
+ * ```ts
30
+ * .step('byId', connector('uipath-uipath-dataservice', 'get-entity-record-by-id',
31
+ * { entityName: 'Contracts', recordId: input('id') }, { connection: 'df' }))
32
+ * ```
33
+ *
34
+ * Get-by-id matters for long text. This node is a query even when it reads one
35
+ * record by an `Id` filter, and a Data Service query returns a PREVIEW of a
36
+ * long-text (`MULTILINE_MAX`) field: the first 10,000 characters plus
37
+ * `...[Truncated]`, with no flag in the output. A 15,551-character value comes
38
+ * back as 10,014 characters. When a field may exceed 10,000 characters, read
39
+ * it with `get-entity-record-by-id`, which returns the whole value
40
+ * (flow-builder-sdk#954).
41
+ *
42
+ * A connector operation's body fields come from the entity, so the library
43
+ * cannot carry them: run `uip maestro registry prepare uipath-uipath-dataservice
44
+ * get-entity-record-by-id -f entityName=<Entity>` first.
45
+ * The routing table is in the `data-fabric.md` reference and the parent-field
46
+ * loop in `connector-params.md` — cited by name rather than linked, because this
47
+ * comment renders both into the flat corpus, where those files sit alongside
48
+ * it, and onto the site, where each symbol is its own page and a relative
49
+ * `./data-fabric` resolves to nothing.
50
+ *
51
+ * @param inputs - The entity, optional filter rows, result mode, and folder scope.
52
+ * @returns An action spec to pass to `.step(name, …)`.
53
+ */
54
+ export function dataFabricRead(inputs) {
55
+ return builtinActionSpec({ kind: 'dataFabricRead', inputs });
56
+ }
57
+ /**
58
+ * Create an entity record in Data Fabric (`core.datafabric.create`). The new
59
+ * record publishes to the step's `output`, so a following
60
+ * {@link dataFabricUpdate} or {@link dataFabricDelete} can read its id.
61
+ *
62
+ * @remarks
63
+ * `values` must name at least one column — the node's schema rejects an empty
64
+ * field list rather than inserting a blank row, and `check` says so before the
65
+ * platform does. Field names are the ENTITY's, so copy them from the scenario
66
+ * or the tenant; nothing offline can tell a real column from a typo.
67
+ *
68
+ * The published `output` is the record as a query returns it, so a long-text
69
+ * (`MULTILINE_MAX`) field longer than 10,000 characters comes back cut, with
70
+ * `...[Truncated]` appended, even though the whole value was stored. Use the
71
+ * value you passed in, or re-read the record with the connector's
72
+ * `get-entity-record-by-id`, when the whole text is needed (flow-builder-sdk#954).
73
+ *
74
+ * See {@link dataFabricRead} for what the native family still does not cover
75
+ * and which connector operation covers it.
76
+ *
77
+ * @param inputs - The entity, the columns the record starts with, and folder scope.
78
+ * @returns An action spec to pass to `.step(name, …)`.
79
+ */
80
+ export function dataFabricCreate(inputs) {
81
+ return builtinActionSpec({ kind: 'dataFabricCreate', inputs });
82
+ }
83
+ /**
84
+ * Update an entity record in Data Fabric (`core.datafabric.update`). Target the
85
+ * record by id or through an earlier {@link dataFabricRead} step; downstream
86
+ * reads of this step observe the record AFTER the write.
87
+ *
88
+ * @remarks
89
+ * `set` must write at least one column: an empty `set` is a no-op the platform
90
+ * reports as success, so `check` rejects it.
91
+ *
92
+ * See {@link dataFabricRead} for what the native family still does not cover
93
+ * and which connector operation covers it.
94
+ *
95
+ * @param inputs - The entity, the record selector, and the columns to write.
96
+ * @returns An action spec to pass to `.step(name, …)`.
97
+ */
98
+ export function dataFabricUpdate(inputs) {
99
+ assertOneRecordRef(inputs.record, 'dataFabricUpdate');
100
+ return builtinActionSpec({ kind: 'dataFabricUpdate', inputs });
101
+ }
102
+ /**
103
+ * Delete an entity record from Data Fabric (`core.datafabric.delete`). Target
104
+ * the record by id or through an earlier {@link dataFabricRead} step, exactly
105
+ * as {@link dataFabricUpdate} does.
106
+ *
107
+ * @remarks
108
+ * A delete **publishes nothing** — its definition declares no output — so
109
+ * `$vars.<step>.output` is undefined at run time and `check` rejects a read of
110
+ * it. Take what you need off the read step that found the record, before the
111
+ * delete.
112
+ *
113
+ * See {@link dataFabricRead} for what the native family still does not cover
114
+ * and which connector operation covers it.
115
+ *
116
+ * @param inputs - The entity, the record selector, and folder scope.
117
+ * @returns An action spec to pass to `.step(name, …)`.
118
+ */
119
+ export function dataFabricDelete(inputs) {
120
+ assertOneRecordRef(inputs.record, 'dataFabricDelete');
121
+ return builtinActionSpec({ kind: 'dataFabricDelete', inputs });
122
+ }
123
+ /**
124
+ * `record` names exactly ONE of `{ byId }` / `{ fromRead }`. Both forms are
125
+ * optional properties on the same object type, so TypeScript alone cannot
126
+ * refuse `{}` — and an empty selector compiles into a write with no target.
127
+ */
128
+ function assertOneRecordRef(record, factory) {
129
+ const byId = record?.byId !== undefined;
130
+ const fromRead = typeof record?.fromRead === 'string';
131
+ if (byId === fromRead) {
132
+ throw new Error(`${factory}() targets exactly ONE of record: { byId } or record: { fromRead: '<step>' }.`);
133
+ }
134
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The Flow Data Fabric node family, as flow-node-registry.ts lists it:
3
+ * `core.datafabric.{read,create,update,delete}`. See README.md in this directory
4
+ * for the developer notes, and index.ts for the public surface.
5
+ */
6
+ import type { FlowNodeFamily } from '../../../flow-node-type.js';
7
+ export declare const dataFabricFlowFamily: FlowNodeFamily;
@@ -0,0 +1,9 @@
1
+ import { checkFromRead, DATA_FABRIC_DIAGNOSTICS } from './check.js';
2
+ import { dataFabricCreate, dataFabricDelete, dataFabricRead, dataFabricUpdate } from './verbs.js';
3
+ export const dataFabricFlowFamily = {
4
+ id: 'data-fabric',
5
+ title: 'Data Fabric',
6
+ types: [dataFabricRead, dataFabricCreate, dataFabricUpdate, dataFabricDelete],
7
+ diagnostics: DATA_FABRIC_DIAGNOSTICS,
8
+ check: checkFromRead,
9
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The Flow Data Fabric family's public surface: its authoring types and
3
+ * factories, which the package entry re-exports. Another family that shares a
4
+ * type with this one imports it from here (FB013). The node types themselves are
5
+ * registered through `family.ts`.
6
+ */
7
+ export * from './spec.js';
8
+ export * from './factories.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The Flow Data Fabric family's public surface: its authoring types and
3
+ * factories, which the package entry re-exports. Another family that shares a
4
+ * type with this one imports it from here (FB013). The node types themselves are
5
+ * registered through `family.ts`.
6
+ */
7
+ export * from './spec.js';
8
+ export * from './factories.js';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * What `rawNode` reports for a raw Data Fabric node: the typed spelling of each
3
+ * verb, what the factories write and do not (the hint), and the `entityConfig`
4
+ * keys the product reads — a raw node carrying any other key is refused at a
5
+ * version the SDK bundles. Moved from core/typed-raw-node.ts in Phase 3 of
6
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; messages unchanged.
7
+ */
8
+ import type { FlowRawNodeAdvice } from '../../../flow-node-type.js';
9
+ /**
10
+ * Every `entityConfig` key the product reads or persists on a Data Fabric node,
11
+ * across the four verbs. flow-workbench develop `eed682f19`:
12
+ *
13
+ * - services `serialization/entity-vdo.ts` `interface EntityConfig` (:229-272):
14
+ * `entityName`, `resultMode`, `_recordLimit`, `_skip`, `_sort`,
15
+ * `_selectedFieldNames`, `_filters`, `_entityFields`, `_relatedFields`,
16
+ * `_folderKey`, `_entityKey`, `_resourceKey`, `_outputSchema`;
17
+ * `CreateEntityConfig` (:719) adds `fieldValues`; `UpdateEntityConfig` (:744)
18
+ * adds `recordSource`, `readEntityNodeId`, `recordId`, `fieldUpdates`.
19
+ * - canvas `properties-panel/EntityConfigField.tsx` `EntityConfigInputs`
20
+ * (:85-110) and `entity/useEntityPanelState.ts` `EntitySelectionPatch`
21
+ * (:248-270), which the panels persist on an entity pick:
22
+ * `_entityDisplayName`, `_choiceSets`, `_folderPath`, `_entitySubType`.
23
+ * - Create/Update/DeleteEntityConfigField.tsx declare nothing beyond these.
24
+ *
25
+ * One union rather than one set per verb: a key another verb reads is at worst
26
+ * ignored, and a per-verb split would refuse a canvas-written key on a verb
27
+ * whose panel happens not to declare it. The test pins every key the typed
28
+ * factories write to this set.
29
+ */
30
+ export declare const ENTITY_CONFIG_KEYS: ReadonlySet<string>;
31
+ /** The advice for one verb: its typed spelling, the family hint, and the key check. */
32
+ export declare function rawNodeAdvice(nodeType: string, factory: string): FlowRawNodeAdvice;
@@ -0,0 +1,100 @@
1
+ const isPlainObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v) && Object.getPrototypeOf(v) === Object.prototype;
2
+ /**
3
+ * Every `entityConfig` key the product reads or persists on a Data Fabric node,
4
+ * across the four verbs. flow-workbench develop `eed682f19`:
5
+ *
6
+ * - services `serialization/entity-vdo.ts` `interface EntityConfig` (:229-272):
7
+ * `entityName`, `resultMode`, `_recordLimit`, `_skip`, `_sort`,
8
+ * `_selectedFieldNames`, `_filters`, `_entityFields`, `_relatedFields`,
9
+ * `_folderKey`, `_entityKey`, `_resourceKey`, `_outputSchema`;
10
+ * `CreateEntityConfig` (:719) adds `fieldValues`; `UpdateEntityConfig` (:744)
11
+ * adds `recordSource`, `readEntityNodeId`, `recordId`, `fieldUpdates`.
12
+ * - canvas `properties-panel/EntityConfigField.tsx` `EntityConfigInputs`
13
+ * (:85-110) and `entity/useEntityPanelState.ts` `EntitySelectionPatch`
14
+ * (:248-270), which the panels persist on an entity pick:
15
+ * `_entityDisplayName`, `_choiceSets`, `_folderPath`, `_entitySubType`.
16
+ * - Create/Update/DeleteEntityConfigField.tsx declare nothing beyond these.
17
+ *
18
+ * One union rather than one set per verb: a key another verb reads is at worst
19
+ * ignored, and a per-verb split would refuse a canvas-written key on a verb
20
+ * whose panel happens not to declare it. The test pins every key the typed
21
+ * factories write to this set.
22
+ */
23
+ export const ENTITY_CONFIG_KEYS = new Set([
24
+ 'entityName', 'resultMode',
25
+ '_recordLimit', '_skip', '_sort', '_selectedFieldNames', '_filters',
26
+ '_entityFields', '_relatedFields', '_choiceSets', '_outputSchema',
27
+ '_folderKey', '_folderPath', '_entityKey', '_resourceKey', '_entityDisplayName', '_entitySubType',
28
+ 'fieldValues', 'fieldUpdates', 'recordSource', 'readEntityNodeId', 'recordId',
29
+ ]);
30
+ /**
31
+ * What the Data Fabric factories write, and what they do not, as the typed-family
32
+ * warning states it. The factories do not author the canvas's column snapshots,
33
+ * so a related-path filter (`customer.Name`) still needs a raw node carrying
34
+ * `_entityFields` (`DataFabricFilter.field`, spec.ts).
35
+ */
36
+ const DATAFABRIC_HINT = ' The factory writes the query and write keys: `filters` becomes `_filters` (flat rows; `or: true` '
37
+ + 'starts each OR alternative), `sort` is `_sort`, `limit`/`skip`/`fields` are '
38
+ + '`_recordLimit`/`_skip`/`_selectedFieldNames`, `values`/`set` are `fieldValues`/`fieldUpdates`, '
39
+ + 'and `record` is `recordSource`. It does not write the column snapshots `_entityFields`, '
40
+ + '`_relatedFields`, `_choiceSets` or `_outputSchema`; a related-path filter such as '
41
+ + '`customer.Name` needs `_entityFields`, so for that a raw node is still the way.';
42
+ /**
43
+ * Why a `core.datafabric.*` node's inputs carry a key the product never reads,
44
+ * or `undefined` when they do not.
45
+ *
46
+ * This is where the eval failure became possible. A raw node renders its inputs
47
+ * verbatim, and `core.datafabric.read@1.4`'s registry definition declares only
48
+ * `entityName` and `resultMode`, so `validate` cannot see any other key. Measured
49
+ * on the eval archive (2026-09-23, skill-flow-datafabric-native-contract-intake-pipeline):
50
+ * the agent wrote `_sortOptions: [{ fieldName, isDescending }]` in place of
51
+ * `_sort`, `check` printed "no issues", `validate` said Valid, and the query
52
+ * would have run unsorted. The allowed set is what the product reads
53
+ * ({@link ENTITY_CONFIG_KEYS}), so `_entityFields` and the other
54
+ * canvas snapshots stay legal.
55
+ *
56
+ * Severity follows the version: at a bundled `<nodeType>@<version>` the key set
57
+ * is known, so the key is refused (`error`); at a version this SDK has not
58
+ * synced, a newer node could read a new key, so it is reported (`warning`).
59
+ *
60
+ * @param nodeType - The node's type.
61
+ * @param factory - The typed spelling, as the warning names it.
62
+ * @param version - The version the node is emitted at.
63
+ * @param inputs - The node's inputs, before rendering.
64
+ * @param bundled - Whether the SDK bundles `<nodeType>@<version>`.
65
+ * @returns The diagnostic, or `undefined` for a clean node or a non-Data-Fabric type.
66
+ */
67
+ function unknownInputs(nodeType, factory, version, inputs, bundled) {
68
+ if (!isPlainObject(inputs))
69
+ return undefined;
70
+ const unknown = Object.keys(inputs).filter((k) => k !== 'entityConfig');
71
+ const cfg = inputs.entityConfig;
72
+ if (isPlainObject(cfg)) {
73
+ for (const k of Object.keys(cfg))
74
+ if (!ENTITY_CONFIG_KEYS.has(k))
75
+ unknown.push(`entityConfig.${k}`);
76
+ }
77
+ if (unknown.length === 0)
78
+ return undefined;
79
+ const named = unknown.map((k) => `\`${k}\``).join(', ');
80
+ const base = `${nodeType}@${version} carries ${named}, which the platform never reads: Data Fabric `
81
+ + `nodes read only \`inputs.entityConfig\`, with the keys ${[...ENTITY_CONFIG_KEYS].join(', ')} `
82
+ + `(flow-workbench entity-vdo.ts \`EntityConfig\` and the entity panels). \`validate\` cannot see `
83
+ + `the key, so it compiles and is ignored at run time; for example a sort is \`_sort: { field, direction }\`, `
84
+ + `not \`_sortOptions\`. The typed factory, ${factory}, writes only keys the node reads.`;
85
+ if (bundled)
86
+ return { severity: 'error', message: base };
87
+ return {
88
+ severity: 'warning',
89
+ message: `${base} This SDK does not bundle ${nodeType}@${version}, so a newer node may read the key; `
90
+ + 'it compiles as written.',
91
+ };
92
+ }
93
+ /** The advice for one verb: its typed spelling, the family hint, and the key check. */
94
+ export function rawNodeAdvice(nodeType, factory) {
95
+ return {
96
+ factory,
97
+ hint: DATAFABRIC_HINT,
98
+ inputProblem: (inputs, version, bundled) => unknownInputs(nodeType, factory, version, inputs, bundled),
99
+ };
100
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * What the four Flow Data Fabric verbs share: the `entityConfig` envelope every
3
+ * one of them serializes into, the record selector update and delete use, the
4
+ * folder-scope bindings, and the lift back to source.
5
+ *
6
+ * Moved verbatim from serialize.ts / decompile.ts (Phase 2 of
7
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md); the comments that explain each wire
8
+ * decision came with the code.
9
+ */
10
+ import { Expr } from '../../../core/expr.js';
11
+ import type { DataFabricFilter, DataFabricRecordRef } from './spec.js';
12
+ import type { FlowPrintContext, FlowSerializeContext } from '../../../flow-node-type.js';
13
+ /** The scope options every verb takes. */
14
+ export interface ScopeInputs {
15
+ entity: string;
16
+ folderKey?: string;
17
+ resourceKey?: string;
18
+ }
19
+ /** A serialized node's `entityConfig`, as the lift reads it. */
20
+ export type EntityConfig = Record<string, unknown>;
21
+ export declare function entityConfigOf(node: unknown): EntityConfig;
22
+ /** `entityConfig` as every verb starts it. */
23
+ export declare function baseConfig(inputs: ScopeInputs): EntityConfig;
24
+ /**
25
+ * `recordSource` is how update and delete both name their target; the read
26
+ * step's emitted node id is rename-aware, for subflow copies.
27
+ */
28
+ export declare function targetRecord(cfg: EntityConfig, record: DataFabricRecordRef, ctx: FlowSerializeContext): void;
29
+ /** A `{ <field>: <value> }` map as the `{ field, value }` rows create and update write. */
30
+ export declare function fieldRows(values: Record<string, string | Expr> | undefined, ctx: FlowSerializeContext): {
31
+ field: string;
32
+ value: string;
33
+ }[];
34
+ /**
35
+ * The flat `_filters` array. `join: 'OR'` on a row STARTS a new alternative —
36
+ * `entity-vdo.ts`'s `buildQesFromEntityConfig` splits the array into runs on that
37
+ * key, ANDs within a run, and ORs the runs together. So the query model is
38
+ * disjunctive: `alt1 OR alt2 OR …`, each `alt` an AND of its rows, which is why
39
+ * `[A, B(or), C]` is `A OR (B AND C)` and not `(A OR B) AND C`.
40
+ *
41
+ * The grouped `{ logicalOperator, rows, groups }` object the authoring guide
42
+ * shows is a NEWER shape: the vendored converter the local engine runs throws
43
+ * `(filters ?? []).filter is not a function` on it, so emitting it would trade
44
+ * a working offline rung for a shape only the current platform can read. The
45
+ * array is the form both accept.
46
+ */
47
+ export declare function filterRows(filters: ReadonlyArray<DataFabricFilter>, ctx: FlowSerializeContext): Array<Record<string, unknown>>;
48
+ /**
49
+ * The folder scope, last in `entityConfig`. A folder-scoped entity is portable
50
+ * only with its `Entity` bindings; the half-authored form is refused by check(),
51
+ * so reaching here with both means emit both. Same id for the same (entity,
52
+ * resourceKey), so two steps on one entity share one pair rather than
53
+ * duplicating it.
54
+ */
55
+ export declare function applyScope(cfg: EntityConfig, inputs: ScopeInputs, ctx: FlowSerializeContext): void;
56
+ /**
57
+ * A serialized value back as the spec holds it. 1.3 let `recordId` and a
58
+ * create's field value be a `{ type: 'jsExpression', expression }` object as well
59
+ * as a `=js:` string; a product-authored node can carry either, and both recover
60
+ * as an expression. Anything else is TEXT — a number in a field row prints as
61
+ * `"5"`, as it always has.
62
+ */
63
+ export declare function liftValue(v: unknown): Expr | string;
64
+ /** The scope options, read back. */
65
+ export declare function liftScope(cfg: EntityConfig): ScopeInputs;
66
+ /** The record selector, read back. */
67
+ export declare function liftRecord(cfg: EntityConfig): DataFabricRecordRef;
68
+ /** `{ field, value }` rows back as the `{ <field>: <value> }` map. */
69
+ export declare function liftFields(rows: unknown): Record<string, Expr | string>;
70
+ /** `entity`, then the verb's own options, then the scope — the order every verb prints in. */
71
+ export declare function scopeOptions(inputs: ScopeInputs, ctx: FlowPrintContext): {
72
+ entity: [string, string];
73
+ tail: Array<[string, string | undefined]>;
74
+ };
75
+ export declare function printRecord(record: DataFabricRecordRef, ctx: FlowPrintContext): string;
76
+ /** A field map as `{ k: v, … }` — `{ }` when empty, exactly as the decompiler always wrote it. */
77
+ export declare function printFields(values: Record<string, unknown> | undefined, ctx: FlowPrintContext): string;
@@ -0,0 +1,174 @@
1
+ /**
2
+ * What the four Flow Data Fabric verbs share: the `entityConfig` envelope every
3
+ * one of them serializes into, the record selector update and delete use, the
4
+ * folder-scope bindings, and the lift back to source.
5
+ *
6
+ * Moved verbatim from serialize.ts / decompile.ts (Phase 2 of
7
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md); the comments that explain each wire
8
+ * decision came with the code.
9
+ */
10
+ import { Expr } from '../../../core/expr.js';
11
+ export function entityConfigOf(node) {
12
+ const inputs = node?.inputs ?? {};
13
+ return (inputs.entityConfig ?? {});
14
+ }
15
+ /** `entityConfig` as every verb starts it. */
16
+ export function baseConfig(inputs) {
17
+ return { entityName: inputs.entity };
18
+ }
19
+ /**
20
+ * `recordSource` is how update and delete both name their target; the read
21
+ * step's emitted node id is rename-aware, for subflow copies.
22
+ */
23
+ export function targetRecord(cfg, record, ctx) {
24
+ const r = record;
25
+ if (typeof r.fromRead === 'string') {
26
+ cfg.recordSource = 'fromRead';
27
+ cfg.readEntityNodeId = ctx.stepNodeId(r.fromRead);
28
+ }
29
+ else {
30
+ cfg.recordSource = 'byId';
31
+ cfg.recordId = String(ctx.render(r.byId));
32
+ }
33
+ }
34
+ /** A `{ <field>: <value> }` map as the `{ field, value }` rows create and update write. */
35
+ export function fieldRows(values, ctx) {
36
+ return Object.entries(values ?? {}).map(([field, value]) => ({
37
+ field,
38
+ value: String(ctx.render(value)),
39
+ }));
40
+ }
41
+ /**
42
+ * The flat `_filters` array. `join: 'OR'` on a row STARTS a new alternative —
43
+ * `entity-vdo.ts`'s `buildQesFromEntityConfig` splits the array into runs on that
44
+ * key, ANDs within a run, and ORs the runs together. So the query model is
45
+ * disjunctive: `alt1 OR alt2 OR …`, each `alt` an AND of its rows, which is why
46
+ * `[A, B(or), C]` is `A OR (B AND C)` and not `(A OR B) AND C`.
47
+ *
48
+ * The grouped `{ logicalOperator, rows, groups }` object the authoring guide
49
+ * shows is a NEWER shape: the vendored converter the local engine runs throws
50
+ * `(filters ?? []).filter is not a function` on it, so emitting it would trade
51
+ * a working offline rung for a shape only the current platform can read. The
52
+ * array is the form both accept.
53
+ */
54
+ export function filterRows(filters, ctx) {
55
+ return filters.map((f, i) => ({
56
+ field: f.field,
57
+ operator: f.operator ?? '=',
58
+ value: String(ctx.render(f.value)),
59
+ // Never on the first row: a leading `join` starts an empty run, which the
60
+ // platform's own loop guards against, and which means nothing anyway.
61
+ ...(i > 0 && f.or ? { join: 'OR' } : {}),
62
+ }));
63
+ }
64
+ /**
65
+ * The folder scope, last in `entityConfig`. A folder-scoped entity is portable
66
+ * only with its `Entity` bindings; the half-authored form is refused by check(),
67
+ * so reaching here with both means emit both. Same id for the same (entity,
68
+ * resourceKey), so two steps on one entity share one pair rather than
69
+ * duplicating it.
70
+ */
71
+ export function applyScope(cfg, inputs, ctx) {
72
+ if (inputs.folderKey !== undefined)
73
+ cfg._folderKey = inputs.folderKey;
74
+ if (inputs.folderKey !== undefined && inputs.resourceKey !== undefined) {
75
+ cfg._resourceKey = inputs.resourceKey;
76
+ for (const entry of entityBindings(inputs.entity, inputs.folderKey, inputs.resourceKey))
77
+ ctx.bind(entry);
78
+ }
79
+ }
80
+ /**
81
+ * The two `bindings[]` rows a FOLDER-SCOPED entity needs to survive export to
82
+ * another org, and the `_resourceKey` that ties them to the node.
83
+ *
84
+ * Nothing else emits `resource: 'Entity'`: the kind is matched by
85
+ * `(resourceKey, propertyAttribute)` rather than by name, carries no
86
+ * `resourceSubType`, spells the folder attribute `folderKey` (never
87
+ * `folderPath` — a folderPath row receives the Orchestrator FQN, which the
88
+ * Data Fabric query rejects even in the source org), and puts a DISPLAY label
89
+ * in `name`. The capital `E` is load-bearing: packaging ignores a lowercase
90
+ * row, so deploy emits no override at all.
91
+ *
92
+ * A tenant-scoped entity needs none of this — it serializes as a dotted
93
+ * literal — which is why the pair is emitted only when the author supplied
94
+ * both `folderKey` and `resourceKey`.
95
+ */
96
+ function entityBindings(entity, folderKey, resourceKey) {
97
+ const base = `b${entity.replace(/[^A-Za-z0-9]/g, '')}Entity`;
98
+ return [
99
+ {
100
+ id: `${base}Name`,
101
+ name: entity,
102
+ type: 'string',
103
+ resource: 'Entity',
104
+ resourceKey,
105
+ default: entity,
106
+ propertyAttribute: 'name',
107
+ },
108
+ {
109
+ id: `${base}Folder`,
110
+ name: `${entity}Folder`,
111
+ type: 'string',
112
+ resource: 'Entity',
113
+ resourceKey,
114
+ default: folderKey,
115
+ propertyAttribute: 'folderKey',
116
+ },
117
+ ];
118
+ }
119
+ // ─── The lift ──────────────────────────────────────────────────────────────────
120
+ /**
121
+ * A serialized value back as the spec holds it. 1.3 let `recordId` and a
122
+ * create's field value be a `{ type: 'jsExpression', expression }` object as well
123
+ * as a `=js:` string; a product-authored node can carry either, and both recover
124
+ * as an expression. Anything else is TEXT — a number in a field row prints as
125
+ * `"5"`, as it always has.
126
+ */
127
+ export function liftValue(v) {
128
+ const obj = v;
129
+ if (obj && typeof obj === 'object' && obj.type === 'jsExpression')
130
+ return new Expr(String(obj.expression ?? ''));
131
+ const raw = typeof v === 'string' ? v : String(v ?? '');
132
+ return raw.startsWith('=js:') ? new Expr(raw.slice(4)) : raw;
133
+ }
134
+ /** The scope options, read back. */
135
+ export function liftScope(cfg) {
136
+ return {
137
+ entity: String(cfg.entityName ?? ''),
138
+ ...(typeof cfg._folderKey === 'string' ? { folderKey: cfg._folderKey } : {}),
139
+ ...(typeof cfg._resourceKey === 'string' ? { resourceKey: cfg._resourceKey } : {}),
140
+ };
141
+ }
142
+ /** The record selector, read back. */
143
+ export function liftRecord(cfg) {
144
+ return cfg.recordSource === 'fromRead'
145
+ ? { fromRead: String(cfg.readEntityNodeId ?? '') }
146
+ : { byId: liftValue(cfg.recordId) };
147
+ }
148
+ /** `{ field, value }` rows back as the `{ <field>: <value> }` map. */
149
+ export function liftFields(rows) {
150
+ const list = Array.isArray(rows) ? rows : [];
151
+ const out = {};
152
+ for (const r of list)
153
+ out[String(r.field ?? '')] = liftValue(r.value);
154
+ return out;
155
+ }
156
+ // ─── Printing ──────────────────────────────────────────────────────────────────
157
+ /** `entity`, then the verb's own options, then the scope — the order every verb prints in. */
158
+ export function scopeOptions(inputs, ctx) {
159
+ return {
160
+ entity: ['entity', ctx.string(inputs.entity)],
161
+ tail: [
162
+ ['folderKey', inputs.folderKey !== undefined ? ctx.string(inputs.folderKey) : undefined],
163
+ ['resourceKey', inputs.resourceKey !== undefined ? ctx.string(inputs.resourceKey) : undefined],
164
+ ],
165
+ };
166
+ }
167
+ export function printRecord(record, ctx) {
168
+ const r = record;
169
+ return typeof r.fromRead === 'string' ? `{ fromRead: ${ctx.string(r.fromRead)} }` : `{ byId: ${ctx.value(r.byId)} }`;
170
+ }
171
+ /** A field map as `{ k: v, … }` — `{ }` when empty, exactly as the decompiler always wrote it. */
172
+ export function printFields(values, ctx) {
173
+ return `{ ${Object.entries(values ?? {}).map(([k, v]) => `${ctx.key(k)}: ${ctx.value(v)}`).join(', ')} }`;
174
+ }