@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.
- package/dist/api-index.md +185 -184
- package/dist/api-members.md +504 -473
- package/dist/bpmn/uipath-moddle.v1.json +5 -0
- package/dist/case/decompile-cli.js +2 -8
- package/dist/check.js +177 -650
- package/dist/core/actions.d.ts +119 -760
- package/dist/core/actions.js +0 -306
- package/dist/core/error-port.d.ts +6 -0
- package/dist/core/error-port.js +9 -0
- package/dist/core/node-classes.d.ts +4 -63
- package/dist/core/node-classes.js +0 -112
- package/dist/core/nodes/family.d.ts +36 -0
- package/dist/core/nodes/family.js +1 -0
- package/dist/core/nodes/node-type.d.ts +136 -0
- package/dist/core/nodes/node-type.js +1 -0
- package/dist/core/nodes/registry.d.ts +57 -0
- package/dist/core/nodes/registry.js +122 -0
- package/dist/core/nodes/versioned.d.ts +50 -0
- package/dist/core/nodes/versioned.js +46 -0
- package/dist/core/typed-raw-node.d.ts +13 -62
- package/dist/core/typed-raw-node.js +40 -154
- package/dist/decompile-cli.js +2 -9
- package/dist/decompile.js +92 -271
- package/dist/flow-definitions.d.ts +10 -0
- package/dist/flow-definitions.js +35 -0
- package/dist/flow-node-registry.d.ts +13 -0
- package/dist/flow-node-registry.js +19 -0
- package/dist/flow-node-type.d.ts +192 -0
- package/dist/flow-node-type.js +1 -0
- package/dist/flow-sdk.d.ts +7 -0
- package/dist/flow-sdk.js +8 -0
- package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
- package/dist/nodes/data-fabric/flow/check.js +164 -0
- package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
- package/dist/nodes/data-fabric/flow/factories.js +134 -0
- package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
- package/dist/nodes/data-fabric/flow/family.js +9 -0
- package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
- package/dist/nodes/data-fabric/flow/index.js +8 -0
- package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
- package/dist/nodes/data-fabric/flow/raw.js +100 -0
- package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
- package/dist/nodes/data-fabric/flow/shared.js +174 -0
- package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
- package/dist/nodes/data-fabric/flow/spec.js +1 -0
- package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
- package/dist/nodes/data-fabric/flow/verbs.js +239 -0
- package/dist/nodes/delay/flow/check.d.ts +16 -0
- package/dist/nodes/delay/flow/check.js +86 -0
- package/dist/nodes/delay/flow/factories.d.ts +28 -0
- package/dist/nodes/delay/flow/factories.js +38 -0
- package/dist/nodes/delay/flow/family.d.ts +3 -0
- package/dist/nodes/delay/flow/family.js +8 -0
- package/dist/nodes/delay/flow/index.d.ts +3 -0
- package/dist/nodes/delay/flow/index.js +3 -0
- package/dist/nodes/delay/flow/node-type.d.ts +13 -0
- package/dist/nodes/delay/flow/node-type.js +71 -0
- package/dist/nodes/delay/flow/spec.d.ts +43 -0
- package/dist/nodes/delay/flow/spec.js +16 -0
- package/dist/nodes/document/flow/factories.d.ts +27 -0
- package/dist/nodes/document/flow/factories.js +30 -0
- package/dist/nodes/document/flow/family.d.ts +3 -0
- package/dist/nodes/document/flow/family.js +7 -0
- package/dist/nodes/document/flow/index.d.ts +3 -0
- package/dist/nodes/document/flow/index.js +3 -0
- package/dist/nodes/document/flow/node-type.d.ts +14 -0
- package/dist/nodes/document/flow/node-type.js +150 -0
- package/dist/nodes/document/flow/spec.d.ts +65 -0
- package/dist/nodes/document/flow/spec.js +1 -0
- package/dist/nodes/mock/flow/factories.d.ts +51 -0
- package/dist/nodes/mock/flow/factories.js +47 -0
- package/dist/nodes/mock/flow/family.d.ts +3 -0
- package/dist/nodes/mock/flow/family.js +7 -0
- package/dist/nodes/mock/flow/index.d.ts +2 -0
- package/dist/nodes/mock/flow/index.js +2 -0
- package/dist/nodes/mock/flow/node-type.d.ts +11 -0
- package/dist/nodes/mock/flow/node-type.js +51 -0
- package/dist/nodes/script/flow/check.d.ts +19 -0
- package/dist/nodes/script/flow/check.js +49 -0
- package/dist/nodes/script/flow/factories.d.ts +14 -0
- package/dist/nodes/script/flow/factories.js +15 -0
- package/dist/nodes/script/flow/family.d.ts +3 -0
- package/dist/nodes/script/flow/family.js +8 -0
- package/dist/nodes/script/flow/index.d.ts +3 -0
- package/dist/nodes/script/flow/index.js +3 -0
- package/dist/nodes/script/flow/node-type.d.ts +7 -0
- package/dist/nodes/script/flow/node-type.js +125 -0
- package/dist/nodes/script/flow/spec.d.ts +52 -0
- package/dist/nodes/script/flow/spec.js +1 -0
- package/dist/nodes/transform/flow/check.d.ts +6 -0
- package/dist/nodes/transform/flow/check.js +229 -0
- package/dist/nodes/transform/flow/factories.d.ts +52 -0
- package/dist/nodes/transform/flow/factories.js +53 -0
- package/dist/nodes/transform/flow/family.d.ts +3 -0
- package/dist/nodes/transform/flow/family.js +8 -0
- package/dist/nodes/transform/flow/index.d.ts +3 -0
- package/dist/nodes/transform/flow/index.js +3 -0
- package/dist/nodes/transform/flow/node-type.d.ts +7 -0
- package/dist/nodes/transform/flow/node-type.js +244 -0
- package/dist/nodes/transform/flow/spec.d.ts +116 -0
- package/dist/nodes/transform/flow/spec.js +10 -0
- package/dist/raw-node-advice.d.ts +16 -0
- package/dist/raw-node-advice.js +36 -0
- package/dist/raw-node.d.ts +71 -0
- package/dist/raw-node.js +116 -0
- package/dist/registry/uip/launch.d.ts +11 -1
- package/dist/registry/uip/launch.js +50 -43
- package/dist/registry/uip/pipeline-front-door.d.ts +2 -0
- package/dist/registry/uip/pipeline-front-door.js +88 -0
- package/dist/serialize.js +138 -492
- 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
|
+
}
|