@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,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Flow Data Fabric family's authoring types, and its four kinds' entries in
|
|
3
|
+
* `FlowActionSpecs` (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §4.6). Moved from
|
|
4
|
+
* core/actions.ts in Phase 2c; the family adds its kinds to the map here, by
|
|
5
|
+
* declaration merging, so `ActionSpec` gains them wherever this module is part of
|
|
6
|
+
* the program — the package entry re-exports it, so that is everywhere.
|
|
7
|
+
*/
|
|
8
|
+
import type { Expr } from '../../../core/expr.js';
|
|
9
|
+
/**
|
|
10
|
+
* The comparison operators the Data Fabric query serializer can emit, spelled
|
|
11
|
+
* exactly as the file carries them.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* There is deliberately no `not in`, `not contains`, or null check — the
|
|
15
|
+
* serializer cannot emit them, and a filter it cannot emit takes the WHOLE
|
|
16
|
+
* query down rather than dropping one row. `is any of` is the legacy spelling
|
|
17
|
+
* of `in` and is still read, but author `in`.
|
|
18
|
+
*/
|
|
19
|
+
export type DataFabricOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'contains' | 'starts with' | 'ends with' | 'in';
|
|
20
|
+
/** One filter row on a Data Fabric query — rows AND together unless `or` is set. */
|
|
21
|
+
export interface DataFabricFilter {
|
|
22
|
+
/**
|
|
23
|
+
* The entity column to filter on. A dotted related path (`customer.Name`) is
|
|
24
|
+
* capped at 3 segments and needs the canvas's `_entityFields` snapshot, which
|
|
25
|
+
* the SDK does not author — keep from-scratch filters on the entity's own
|
|
26
|
+
* columns.
|
|
27
|
+
*/
|
|
28
|
+
field: string;
|
|
29
|
+
/** Comparison operator; `=` when omitted. */
|
|
30
|
+
operator?: DataFabricOperator;
|
|
31
|
+
/**
|
|
32
|
+
* The comparison value. An `Expr` re-evaluates at activation time.
|
|
33
|
+
*
|
|
34
|
+
* A choice-set column compares against the choice's numeric `numberId`, never
|
|
35
|
+
* its label — a label matches nothing.
|
|
36
|
+
*/
|
|
37
|
+
value: string | Expr;
|
|
38
|
+
/**
|
|
39
|
+
* Start a new OR alternative at this row.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* The query model is disjunctive — `alt1 OR alt2 OR …`, each alternative an
|
|
43
|
+
* AND of its own rows — so `or` SPLITS the list rather than joining one row
|
|
44
|
+
* to the one before it. `[A, B(or), C]` is therefore `A OR (B AND C)`, not
|
|
45
|
+
* `(A OR B) AND C`; to get the latter, write it out as
|
|
46
|
+
* `(A AND C) OR (B AND C)`.
|
|
47
|
+
*
|
|
48
|
+
* Ignored on the first row, which has no earlier alternative to split from.
|
|
49
|
+
*/
|
|
50
|
+
or?: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** How a multi-record query orders its rows before the limit is applied. */
|
|
53
|
+
export interface DataFabricSort {
|
|
54
|
+
/** The column to order by — a real one; a sort on a missing column is not caught by `validate`. */
|
|
55
|
+
field: string;
|
|
56
|
+
/** `'asc'` when omitted. */
|
|
57
|
+
direction?: 'asc' | 'desc';
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Which record a Data Fabric write targets — exactly ONE of the two forms.
|
|
61
|
+
*
|
|
62
|
+
* @remarks
|
|
63
|
+
* `{ byId }` names a record id, literal or expression. `{ fromRead }` names an
|
|
64
|
+
* earlier {@link dataFabricRead} STEP and reuses the record that step found, so
|
|
65
|
+
* the id never has to be carried by hand; `check` rejects a name no read step
|
|
66
|
+
* has. Shared by {@link dataFabricUpdate} and {@link dataFabricDelete} — the
|
|
67
|
+
* platform gives them the same `recordSource` shape.
|
|
68
|
+
*/
|
|
69
|
+
export type DataFabricRecordRef = {
|
|
70
|
+
byId: string | Expr;
|
|
71
|
+
fromRead?: never;
|
|
72
|
+
} | {
|
|
73
|
+
fromRead: string;
|
|
74
|
+
byId?: never;
|
|
75
|
+
};
|
|
76
|
+
export interface DataFabricReadInputs {
|
|
77
|
+
/** The Data Fabric entity's name, e.g. `'Invoices'`. */
|
|
78
|
+
entity: string;
|
|
79
|
+
/** Filter rows selecting the record(s) to query. Omit to take everything the entity holds. */
|
|
80
|
+
filters?: DataFabricFilter[];
|
|
81
|
+
/**
|
|
82
|
+
* `'single'` publishes ONE record as the step's `output`; `'multiple'`
|
|
83
|
+
* publishes the matching records under `output.results`.
|
|
84
|
+
*
|
|
85
|
+
* Setting either selects the node's **1.4** definition, which is where
|
|
86
|
+
* `resultMode` exists at all — the SDK's pinned default is 1.0, the
|
|
87
|
+
* read-one-record node this family started as. Omit it and nothing changes:
|
|
88
|
+
* the step stays on 1.0 and reads one record, as it always did.
|
|
89
|
+
*
|
|
90
|
+
* A `'single'` read faults only on an OVER-match; zero matches completes
|
|
91
|
+
* normally and leaves the step's output unresolved, so treat "not found" as a
|
|
92
|
+
* branch rather than an error.
|
|
93
|
+
*/
|
|
94
|
+
resultMode?: 'single' | 'multiple';
|
|
95
|
+
/**
|
|
96
|
+
* Row cap for a `'multiple'` query. The emitted query ALWAYS carries a limit:
|
|
97
|
+
* omitting this resolves to 100, and 1000 is a hard ceiling — a larger value
|
|
98
|
+
* truncates silently, so page with `skip` instead.
|
|
99
|
+
*/
|
|
100
|
+
limit?: number;
|
|
101
|
+
/** Rows to skip before the limit — the paging half of `limit`. */
|
|
102
|
+
skip?: number;
|
|
103
|
+
/** Order rows before the limit applies. Without it a limited slice is arbitrary. */
|
|
104
|
+
sort?: DataFabricSort;
|
|
105
|
+
/** Only these columns. Omit for every column the entity has. */
|
|
106
|
+
fields?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* Folder key (GUID) for a folder-scoped entity — its `folderId` from
|
|
109
|
+
* `uip df entities list --include-folders`.
|
|
110
|
+
*
|
|
111
|
+
* Requires `resourceKey`: `folderKey` alone serializes the folder as a
|
|
112
|
+
* source-org LITERAL, which looks portable and breaks on cross-org deploy, so
|
|
113
|
+
* `check` refuses the pair being half-authored.
|
|
114
|
+
*/
|
|
115
|
+
folderKey?: string;
|
|
116
|
+
/**
|
|
117
|
+
* The key the entity's reference is registered under in the solution, from
|
|
118
|
+
* `uip solution resources list --kind Entity`.
|
|
119
|
+
*
|
|
120
|
+
* @remarks
|
|
121
|
+
* Only meaningful with `folderKey`. Supplying both emits the two
|
|
122
|
+
* `resource: 'Entity'` binding rows (`propertyAttribute` `name` and
|
|
123
|
+
* `folderKey`) that let the flow deploy to another org. Nothing mints this
|
|
124
|
+
* key for a hand-authored flow — if you cannot resolve one, keep the entity
|
|
125
|
+
* tenant-scoped and omit both.
|
|
126
|
+
*/
|
|
127
|
+
resourceKey?: string;
|
|
128
|
+
}
|
|
129
|
+
export interface DataFabricCreateInputs {
|
|
130
|
+
/** The Data Fabric entity's name, e.g. `'Invoices'`. */
|
|
131
|
+
entity: string;
|
|
132
|
+
/**
|
|
133
|
+
* The columns the new record starts with, by field name. At least one is
|
|
134
|
+
* required — the node's schema rejects an empty field list rather than
|
|
135
|
+
* inserting a blank row.
|
|
136
|
+
*/
|
|
137
|
+
values: Record<string, string | Expr>;
|
|
138
|
+
/**
|
|
139
|
+
* Folder key (GUID) for a folder-scoped entity — its `folderId` from
|
|
140
|
+
* `uip df entities list --include-folders`.
|
|
141
|
+
*
|
|
142
|
+
* Requires `resourceKey`: `folderKey` alone serializes the folder as a
|
|
143
|
+
* source-org LITERAL, which looks portable and breaks on cross-org deploy, so
|
|
144
|
+
* `check` refuses the pair being half-authored.
|
|
145
|
+
*/
|
|
146
|
+
folderKey?: string;
|
|
147
|
+
/**
|
|
148
|
+
* The key the entity's reference is registered under in the solution, from
|
|
149
|
+
* `uip solution resources list --kind Entity`.
|
|
150
|
+
*
|
|
151
|
+
* @remarks
|
|
152
|
+
* Only meaningful with `folderKey`. Supplying both emits the two
|
|
153
|
+
* `resource: 'Entity'` binding rows (`propertyAttribute` `name` and
|
|
154
|
+
* `folderKey`) that let the flow deploy to another org. Nothing mints this
|
|
155
|
+
* key for a hand-authored flow — if you cannot resolve one, keep the entity
|
|
156
|
+
* tenant-scoped and omit both.
|
|
157
|
+
*/
|
|
158
|
+
resourceKey?: string;
|
|
159
|
+
}
|
|
160
|
+
export interface DataFabricUpdateInputs {
|
|
161
|
+
/** The Data Fabric entity's name, e.g. `'Invoices'`. */
|
|
162
|
+
entity: string;
|
|
163
|
+
/** Which record to update — see {@link DataFabricRecordRef}. */
|
|
164
|
+
record: DataFabricRecordRef;
|
|
165
|
+
/**
|
|
166
|
+
* The columns to write, by field name. An empty string is a real write — it
|
|
167
|
+
* clears the column.
|
|
168
|
+
*/
|
|
169
|
+
set: Record<string, string | Expr>;
|
|
170
|
+
/**
|
|
171
|
+
* Folder key (GUID) for a folder-scoped entity — its `folderId` from
|
|
172
|
+
* `uip df entities list --include-folders`.
|
|
173
|
+
*
|
|
174
|
+
* Requires `resourceKey`: `folderKey` alone serializes the folder as a
|
|
175
|
+
* source-org LITERAL, which looks portable and breaks on cross-org deploy, so
|
|
176
|
+
* `check` refuses the pair being half-authored.
|
|
177
|
+
*/
|
|
178
|
+
folderKey?: string;
|
|
179
|
+
/**
|
|
180
|
+
* The key the entity's reference is registered under in the solution, from
|
|
181
|
+
* `uip solution resources list --kind Entity`.
|
|
182
|
+
*
|
|
183
|
+
* @remarks
|
|
184
|
+
* Only meaningful with `folderKey`. Supplying both emits the two
|
|
185
|
+
* `resource: 'Entity'` binding rows (`propertyAttribute` `name` and
|
|
186
|
+
* `folderKey`) that let the flow deploy to another org. Nothing mints this
|
|
187
|
+
* key for a hand-authored flow — if you cannot resolve one, keep the entity
|
|
188
|
+
* tenant-scoped and omit both.
|
|
189
|
+
*/
|
|
190
|
+
resourceKey?: string;
|
|
191
|
+
}
|
|
192
|
+
export interface DataFabricDeleteInputs {
|
|
193
|
+
/** The Data Fabric entity's name, e.g. `'Invoices'`. */
|
|
194
|
+
entity: string;
|
|
195
|
+
/** Which record to delete — see {@link DataFabricRecordRef}. */
|
|
196
|
+
record: DataFabricRecordRef;
|
|
197
|
+
/**
|
|
198
|
+
* Folder key (GUID) for a folder-scoped entity — its `folderId` from
|
|
199
|
+
* `uip df entities list --include-folders`.
|
|
200
|
+
*
|
|
201
|
+
* Requires `resourceKey`: `folderKey` alone serializes the folder as a
|
|
202
|
+
* source-org LITERAL, which looks portable and breaks on cross-org deploy, so
|
|
203
|
+
* `check` refuses the pair being half-authored.
|
|
204
|
+
*/
|
|
205
|
+
folderKey?: string;
|
|
206
|
+
/**
|
|
207
|
+
* The key the entity's reference is registered under in the solution, from
|
|
208
|
+
* `uip solution resources list --kind Entity`.
|
|
209
|
+
*
|
|
210
|
+
* @remarks
|
|
211
|
+
* Only meaningful with `folderKey`. Supplying both emits the two
|
|
212
|
+
* `resource: 'Entity'` binding rows (`propertyAttribute` `name` and
|
|
213
|
+
* `folderKey`) that let the flow deploy to another org. Nothing mints this
|
|
214
|
+
* key for a hand-authored flow — if you cannot resolve one, keep the entity
|
|
215
|
+
* tenant-scoped and omit both.
|
|
216
|
+
*/
|
|
217
|
+
resourceKey?: string;
|
|
218
|
+
}
|
|
219
|
+
declare module '../../../core/actions.js' {
|
|
220
|
+
interface FlowActionSpecs {
|
|
221
|
+
/** The spec {@link dataFabricRead} builds. */
|
|
222
|
+
dataFabricRead: {
|
|
223
|
+
inputs: DataFabricReadInputs;
|
|
224
|
+
};
|
|
225
|
+
/** The spec {@link dataFabricCreate} builds. */
|
|
226
|
+
dataFabricCreate: {
|
|
227
|
+
inputs: DataFabricCreateInputs;
|
|
228
|
+
};
|
|
229
|
+
/** The spec {@link dataFabricUpdate} builds. */
|
|
230
|
+
dataFabricUpdate: {
|
|
231
|
+
inputs: DataFabricUpdateInputs;
|
|
232
|
+
};
|
|
233
|
+
/** The spec {@link dataFabricDelete} builds. */
|
|
234
|
+
dataFabricDelete: {
|
|
235
|
+
inputs: DataFabricDeleteInputs;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four Flow Data Fabric verbs as node types: read (1.0 and 1.4), create
|
|
3
|
+
* (1.3), update (1.0 and 1.3) and delete (1.3). Each version's implementation is
|
|
4
|
+
* the same code today — the serialized shape is identical across the bundled
|
|
5
|
+
* versions — so a version is one `verb(version)` call; a version that changes the
|
|
6
|
+
* shape gets its own implementation (design §7).
|
|
7
|
+
*/
|
|
8
|
+
import type { DataFabricCreateInputs, DataFabricDeleteInputs, DataFabricReadInputs, DataFabricUpdateInputs } from './spec.js';
|
|
9
|
+
import type { FlowNodeType, FlowVersionedNodeType } from '../../../flow-node-type.js';
|
|
10
|
+
export type DataFabricReadSpec = {
|
|
11
|
+
kind: 'dataFabricRead';
|
|
12
|
+
inputs: DataFabricReadInputs;
|
|
13
|
+
};
|
|
14
|
+
export type DataFabricCreateSpec = {
|
|
15
|
+
kind: 'dataFabricCreate';
|
|
16
|
+
inputs: DataFabricCreateInputs;
|
|
17
|
+
};
|
|
18
|
+
export type DataFabricUpdateSpec = {
|
|
19
|
+
kind: 'dataFabricUpdate';
|
|
20
|
+
inputs: DataFabricUpdateInputs;
|
|
21
|
+
};
|
|
22
|
+
export type DataFabricDeleteSpec = {
|
|
23
|
+
kind: 'dataFabricDelete';
|
|
24
|
+
inputs: DataFabricDeleteInputs;
|
|
25
|
+
};
|
|
26
|
+
export declare const dataFabricRead: FlowVersionedNodeType<DataFabricReadSpec>;
|
|
27
|
+
export declare const dataFabricCreate: FlowNodeType<DataFabricCreateSpec>;
|
|
28
|
+
export declare const dataFabricUpdate: FlowVersionedNodeType<DataFabricUpdateSpec>;
|
|
29
|
+
export declare const dataFabricDelete: FlowNodeType<DataFabricDeleteSpec>;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { applyScope, baseConfig, entityConfigOf, fieldRows, filterRows, liftFields, liftRecord, liftScope, liftValue, printFields, printRecord, scopeOptions, targetRecord, } from './shared.js';
|
|
2
|
+
import { checkCreate, checkRead, checkUpdate, checkWrite } from './check.js';
|
|
3
|
+
import { rawNodeAdvice } from './raw.js';
|
|
4
|
+
/**
|
|
5
|
+
* Every Data Fabric node carries no node-level `model`, whichever path emits it
|
|
6
|
+
* (a verb, or a rawNode of its definition). Studio Web never writes one
|
|
7
|
+
* (flow-core node.ts: "`node.model` is never written"; canvas `nodeToInstance`
|
|
8
|
+
* omits it), and export seeds it from the definition (services bpmn-to-xml.ts),
|
|
9
|
+
* so a copy could only go stale. `outputs` stay: the canvas persists them
|
|
10
|
+
* (`source: '=response'`), and `variables.nodes[]` is derived from them.
|
|
11
|
+
*/
|
|
12
|
+
const NODE_MODEL = 'omit';
|
|
13
|
+
/** The typed spellings RAW_NODE_TYPED_FAMILY names, as core/typed-raw-node.ts wrote them. */
|
|
14
|
+
const READ_ADVICE = rawNodeAdvice('core.datafabric.read', "dataFabricRead({ entity, resultMode: 'single' | 'multiple', filters: [{ field, operator, value, or }], "
|
|
15
|
+
+ 'sort: { field, direction }, limit, skip, fields, folderKey })');
|
|
16
|
+
const CREATE_ADVICE = rawNodeAdvice('core.datafabric.create', 'dataFabricCreate({ entity, values: { <field>: <value> }, folderKey })');
|
|
17
|
+
const UPDATE_ADVICE = rawNodeAdvice('core.datafabric.update', 'dataFabricUpdate({ entity, record: { byId } | { fromRead }, set: { <field>: <value> }, folderKey })');
|
|
18
|
+
const DELETE_ADVICE = rawNodeAdvice('core.datafabric.delete', 'dataFabricDelete({ entity, record: { byId } | { fromRead }, folderKey })');
|
|
19
|
+
/** `{ k: v, … }` from present entries, `''` when none — the decompiler's `opts()`. */
|
|
20
|
+
function obj(entries, ctx) {
|
|
21
|
+
const parts = entries.filter(([, v]) => v !== undefined).map(([k, v]) => `${ctx.key(k)}: ${v}`);
|
|
22
|
+
return parts.length ? `{ ${parts.join(', ')} }` : '';
|
|
23
|
+
}
|
|
24
|
+
// ─── read ──────────────────────────────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* The family's read node grew from "Read entity" into "Query entity records" at
|
|
27
|
+
* 1.4, and `entityConfig.resultMode` is the input that expresses the difference.
|
|
28
|
+
* The SDK keeps 1.0 pinned as the default, the same way every other family keeps
|
|
29
|
+
* its older default — a flow that reads one record must not change version
|
|
30
|
+
* because the platform moved. So `resultMode` SELECTS 1.4, exactly as a Quartz
|
|
31
|
+
* `every` selects the scheduled trigger's 1.2.
|
|
32
|
+
*/
|
|
33
|
+
function readAt(version) {
|
|
34
|
+
return {
|
|
35
|
+
kind: 'dataFabricRead', typeName: 'core.datafabric.read', version, factory: 'dataFabricRead', definition: 'bundled',
|
|
36
|
+
nodeModel: NODE_MODEL, rawNode: READ_ADVICE,
|
|
37
|
+
serialize: ({ inputs }, ctx) => {
|
|
38
|
+
if (version === '1.0' && inputs.resultMode !== undefined) {
|
|
39
|
+
throw new Error("dataFabricRead(): { resultMode } needs the node's 1.4 definition, but { version: '1.0' } was "
|
|
40
|
+
+ 'requested. Drop the version, request 1.4, or drop resultMode.');
|
|
41
|
+
}
|
|
42
|
+
const cfg = baseConfig(inputs);
|
|
43
|
+
// Only 1.4 declares it, and only 1.4 is emitted when it is set (see
|
|
44
|
+
// `select`) — so writing it can never land on a 1.0 node, where it would
|
|
45
|
+
// be an input the definition does not know.
|
|
46
|
+
if (inputs.resultMode !== undefined)
|
|
47
|
+
cfg.resultMode = inputs.resultMode;
|
|
48
|
+
if (inputs.limit !== undefined)
|
|
49
|
+
cfg._recordLimit = inputs.limit;
|
|
50
|
+
if (inputs.skip !== undefined)
|
|
51
|
+
cfg._skip = inputs.skip;
|
|
52
|
+
if (inputs.sort !== undefined)
|
|
53
|
+
cfg._sort = { field: inputs.sort.field, direction: inputs.sort.direction ?? 'asc' };
|
|
54
|
+
if (inputs.fields?.length)
|
|
55
|
+
cfg._selectedFieldNames = [...inputs.fields];
|
|
56
|
+
if (inputs.filters?.length)
|
|
57
|
+
cfg._filters = filterRows(inputs.filters, ctx);
|
|
58
|
+
applyScope(cfg, inputs, ctx);
|
|
59
|
+
return { inputs: { entityConfig: cfg } };
|
|
60
|
+
},
|
|
61
|
+
deserialize: (node) => {
|
|
62
|
+
const cfg = entityConfigOf(node);
|
|
63
|
+
const inputs = { ...liftScope(cfg) };
|
|
64
|
+
const filters = liftFilters(cfg._filters);
|
|
65
|
+
if (filters.length)
|
|
66
|
+
inputs.filters = filters;
|
|
67
|
+
// `resultMode` only exists from 1.4, and recovering it re-selects 1.4 on
|
|
68
|
+
// the way back out — so a 1.0 node stays a 1.0 node through the round trip.
|
|
69
|
+
if (cfg.resultMode === 'single' || cfg.resultMode === 'multiple')
|
|
70
|
+
inputs.resultMode = cfg.resultMode;
|
|
71
|
+
if (typeof cfg._recordLimit === 'number')
|
|
72
|
+
inputs.limit = cfg._recordLimit;
|
|
73
|
+
if (typeof cfg._skip === 'number')
|
|
74
|
+
inputs.skip = cfg._skip;
|
|
75
|
+
if (cfg._sort && typeof cfg._sort === 'object') {
|
|
76
|
+
const sort = cfg._sort;
|
|
77
|
+
inputs.sort = { field: String(sort.field ?? ''), ...(sort.direction === 'desc' ? { direction: 'desc' } : {}) };
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(cfg._selectedFieldNames) && cfg._selectedFieldNames.length) {
|
|
80
|
+
inputs.fields = cfg._selectedFieldNames.map((f) => String(f));
|
|
81
|
+
}
|
|
82
|
+
return { kind: 'dataFabricRead', inputs };
|
|
83
|
+
},
|
|
84
|
+
print: ({ inputs }, ctx) => {
|
|
85
|
+
const { entity, tail } = scopeOptions(inputs, ctx);
|
|
86
|
+
const filterRow = (f) => obj([
|
|
87
|
+
['field', ctx.string(f.field)],
|
|
88
|
+
['operator', f.operator !== undefined && f.operator !== '=' ? ctx.string(f.operator) : undefined],
|
|
89
|
+
['value', ctx.value(f.value)],
|
|
90
|
+
['or', f.or ? 'true' : undefined],
|
|
91
|
+
], ctx);
|
|
92
|
+
return {
|
|
93
|
+
factory: 'dataFabricRead',
|
|
94
|
+
options: [
|
|
95
|
+
entity,
|
|
96
|
+
['filters', inputs.filters?.length ? `[${inputs.filters.map(filterRow).join(', ')}]` : undefined],
|
|
97
|
+
['resultMode', inputs.resultMode !== undefined ? ctx.string(inputs.resultMode) : undefined],
|
|
98
|
+
['limit', inputs.limit !== undefined ? String(inputs.limit) : undefined],
|
|
99
|
+
['skip', inputs.skip !== undefined ? String(inputs.skip) : undefined],
|
|
100
|
+
['sort', inputs.sort !== undefined
|
|
101
|
+
? obj([
|
|
102
|
+
['field', ctx.string(inputs.sort.field)],
|
|
103
|
+
['direction', inputs.sort.direction === 'desc' ? ctx.string('desc') : undefined],
|
|
104
|
+
], ctx)
|
|
105
|
+
: undefined],
|
|
106
|
+
['fields', inputs.fields !== undefined ? `[${inputs.fields.map((f) => ctx.string(f)).join(', ')}]` : undefined],
|
|
107
|
+
...tail,
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
check: ({ inputs }, ctx) => checkRead(inputs, ctx),
|
|
112
|
+
expressions: ({ inputs }) => (inputs.filters ?? []).map((f) => ({ value: f.value })),
|
|
113
|
+
output: () => ({ kind: 'opaque' }),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* `_filters` back as the builder's row list, where `or: true` marks each new OR
|
|
118
|
+
* alternative. The array is what the platform serializer reads and what compile
|
|
119
|
+
* writes; the grouped object is the newer authoring shape, tolerated here so a
|
|
120
|
+
* canvas-authored file still decompiles.
|
|
121
|
+
*/
|
|
122
|
+
function liftFilters(q) {
|
|
123
|
+
const row = (r, or) => ({
|
|
124
|
+
field: String(r.field ?? ''),
|
|
125
|
+
...(r.operator !== undefined && r.operator !== '=' ? { operator: String(r.operator) } : {}),
|
|
126
|
+
value: liftValue(r.value),
|
|
127
|
+
...(or ? { or: true } : {}),
|
|
128
|
+
});
|
|
129
|
+
if (Array.isArray(q))
|
|
130
|
+
return q.map((r, i) => row(r, i > 0 && r['join'] === 'OR'));
|
|
131
|
+
if (q && typeof q === 'object') {
|
|
132
|
+
const g = q;
|
|
133
|
+
// Grouped: each root row and each group is one alternative, so every one
|
|
134
|
+
// but the first opens with `or: true`.
|
|
135
|
+
const alts = [
|
|
136
|
+
...(Array.isArray(g.rows) ? g.rows.map((r) => [r]) : []),
|
|
137
|
+
...(Array.isArray(g.groups) ? g.groups : [])
|
|
138
|
+
.map((grp) => (Array.isArray(grp.rows) ? grp.rows : [])),
|
|
139
|
+
].filter((a) => a.length);
|
|
140
|
+
return alts.flatMap((alt, ai) => alt.map((r, ri) => row(r, ai > 0 && ri === 0)));
|
|
141
|
+
}
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
export const dataFabricRead = {
|
|
145
|
+
kind: 'dataFabricRead', typeName: 'core.datafabric.read', factory: 'dataFabricRead', defaultVersion: '1.0',
|
|
146
|
+
versions: { '1.0': readAt('1.0'), '1.4': readAt('1.4') },
|
|
147
|
+
select: ({ inputs }) => (inputs?.resultMode !== undefined ? '1.4' : '1.0'),
|
|
148
|
+
};
|
|
149
|
+
// ─── create ────────────────────────────────────────────────────────────────────
|
|
150
|
+
export const dataFabricCreate = {
|
|
151
|
+
kind: 'dataFabricCreate', typeName: 'core.datafabric.create', version: '1.3', factory: 'dataFabricCreate',
|
|
152
|
+
definition: 'bundled', nodeModel: NODE_MODEL, rawNode: CREATE_ADVICE,
|
|
153
|
+
serialize: ({ inputs }, ctx) => {
|
|
154
|
+
const cfg = baseConfig(inputs);
|
|
155
|
+
cfg.fieldValues = fieldRows(inputs.values, ctx);
|
|
156
|
+
applyScope(cfg, inputs, ctx);
|
|
157
|
+
return { inputs: { entityConfig: cfg } };
|
|
158
|
+
},
|
|
159
|
+
deserialize: (node) => {
|
|
160
|
+
const cfg = entityConfigOf(node);
|
|
161
|
+
const scope = liftScope(cfg);
|
|
162
|
+
return { kind: 'dataFabricCreate', inputs: { ...scope, values: liftFields(cfg.fieldValues) } };
|
|
163
|
+
},
|
|
164
|
+
print: ({ inputs }, ctx) => {
|
|
165
|
+
const { entity, tail } = scopeOptions(inputs, ctx);
|
|
166
|
+
return { factory: 'dataFabricCreate', options: [entity, ['values', printFields(inputs.values, ctx)], ...tail] };
|
|
167
|
+
},
|
|
168
|
+
check: ({ inputs }, ctx) => checkCreate(inputs, ctx),
|
|
169
|
+
expressions: ({ inputs }) => Object.values(inputs.values ?? {}).map((value) => ({ value })),
|
|
170
|
+
output: () => ({ kind: 'opaque' }),
|
|
171
|
+
};
|
|
172
|
+
// ─── update ────────────────────────────────────────────────────────────────────
|
|
173
|
+
function updateAt(version) {
|
|
174
|
+
return {
|
|
175
|
+
kind: 'dataFabricUpdate', typeName: 'core.datafabric.update', version, factory: 'dataFabricUpdate', definition: 'bundled',
|
|
176
|
+
nodeModel: NODE_MODEL, rawNode: UPDATE_ADVICE,
|
|
177
|
+
serialize: ({ inputs }, ctx) => {
|
|
178
|
+
const cfg = baseConfig(inputs);
|
|
179
|
+
targetRecord(cfg, inputs.record, ctx);
|
|
180
|
+
cfg.fieldUpdates = fieldRows(inputs.set, ctx);
|
|
181
|
+
applyScope(cfg, inputs, ctx);
|
|
182
|
+
return { inputs: { entityConfig: cfg } };
|
|
183
|
+
},
|
|
184
|
+
deserialize: (node) => {
|
|
185
|
+
const cfg = entityConfigOf(node);
|
|
186
|
+
const scope = liftScope(cfg);
|
|
187
|
+
return { kind: 'dataFabricUpdate', inputs: { ...scope, record: liftRecord(cfg), set: liftFields(cfg.fieldUpdates) } };
|
|
188
|
+
},
|
|
189
|
+
print: ({ inputs }, ctx) => {
|
|
190
|
+
const { entity, tail } = scopeOptions(inputs, ctx);
|
|
191
|
+
return {
|
|
192
|
+
factory: 'dataFabricUpdate',
|
|
193
|
+
options: [entity, ['record', printRecord(inputs.record, ctx)], ['set', printFields(inputs.set, ctx)], ...tail],
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
check: ({ inputs }, ctx) => checkUpdate(inputs, ctx),
|
|
197
|
+
expressions: ({ inputs }) => [
|
|
198
|
+
{ value: inputs.record?.byId },
|
|
199
|
+
...Object.values(inputs.set ?? {}).map((value) => ({ value })),
|
|
200
|
+
],
|
|
201
|
+
output: () => ({ kind: 'opaque' }),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
export const dataFabricUpdate = {
|
|
205
|
+
kind: 'dataFabricUpdate', typeName: 'core.datafabric.update', factory: 'dataFabricUpdate', defaultVersion: '1.0',
|
|
206
|
+
versions: { '1.0': updateAt('1.0'), '1.3': updateAt('1.3') },
|
|
207
|
+
};
|
|
208
|
+
// ─── delete ────────────────────────────────────────────────────────────────────
|
|
209
|
+
export const dataFabricDelete = {
|
|
210
|
+
kind: 'dataFabricDelete', typeName: 'core.datafabric.delete', version: '1.3', factory: 'dataFabricDelete',
|
|
211
|
+
definition: 'bundled', nodeModel: NODE_MODEL, rawNode: DELETE_ADVICE,
|
|
212
|
+
serialize: ({ inputs }, ctx) => {
|
|
213
|
+
const cfg = baseConfig(inputs);
|
|
214
|
+
targetRecord(cfg, inputs.record, ctx);
|
|
215
|
+
applyScope(cfg, inputs, ctx);
|
|
216
|
+
return { inputs: { entityConfig: cfg } };
|
|
217
|
+
},
|
|
218
|
+
deserialize: (node) => {
|
|
219
|
+
const cfg = entityConfigOf(node);
|
|
220
|
+
const scope = liftScope(cfg);
|
|
221
|
+
return { kind: 'dataFabricDelete', inputs: { ...scope, record: liftRecord(cfg) } };
|
|
222
|
+
},
|
|
223
|
+
print: ({ inputs }, ctx) => {
|
|
224
|
+
const { entity, tail } = scopeOptions(inputs, ctx);
|
|
225
|
+
return { factory: 'dataFabricDelete', options: [entity, ['record', printRecord(inputs.record, ctx)], ...tail] };
|
|
226
|
+
},
|
|
227
|
+
check: ({ inputs }, ctx) => checkWrite(inputs, ctx),
|
|
228
|
+
expressions: ({ inputs }) => [{ value: inputs.record?.byId }],
|
|
229
|
+
// A Data Fabric delete is the one verb of the family whose definition declares
|
|
230
|
+
// no outputDefinition at all — the record is gone, so there is nothing to
|
|
231
|
+
// publish. Read the record on the step that FOUND it instead, which on the
|
|
232
|
+
// `{ fromRead }` form is already in the flow.
|
|
233
|
+
output: () => ({
|
|
234
|
+
kind: 'none',
|
|
235
|
+
code: 'DATAFABRIC_DELETE_HAS_NO_OUTPUT',
|
|
236
|
+
message: ({ node, ref, reader }) => `Delete "${node}" produces no output, but "${ref}" reads one in "${reader}". `
|
|
237
|
+
+ 'A Data Fabric delete declares no outputs — take the value off the dataFabricRead step that found the record, before the delete.',
|
|
238
|
+
}),
|
|
239
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Delay family's rules. Moved verbatim from check.ts in Phase 4 of
|
|
3
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; codes and messages unchanged.
|
|
4
|
+
*/
|
|
5
|
+
import type { DiagnosticCatalog } from '../../../core/nodes/family.js';
|
|
6
|
+
import type { FlowCheckContext } from '../../../flow-node-type.js';
|
|
7
|
+
import { type DelayInputs } from './spec.js';
|
|
8
|
+
export declare const DELAY_DIAGNOSTICS: DiagnosticCatalog;
|
|
9
|
+
/**
|
|
10
|
+
* Diagnose a `delay` step's wait.
|
|
11
|
+
*
|
|
12
|
+
* Rung 1 is the only place an author hears about a bad duration in time to fix
|
|
13
|
+
* it cheaply. Anything downstream speaks in terms of `timerPreset`/`timerValue`,
|
|
14
|
+
* the two fields the serializer writes, rather than the one field the author typed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkDelay(inputs: DelayInputs | undefined, ctx: FlowCheckContext): void;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { DELAY_PRESETS } from './spec.js';
|
|
2
|
+
export const DELAY_DIAGNOSTICS = {
|
|
3
|
+
DELAY_UNTIL_NOT_ISO: { severity: 'error', summary: '`until` is not an ISO-8601 date-time' },
|
|
4
|
+
DELAY_NO_DURATION: { severity: 'error', summary: 'no `duration`, so no wait at all' },
|
|
5
|
+
DELAY_NOT_ISO: { severity: 'error', summary: '`duration` is not an ISO-8601 duration' },
|
|
6
|
+
DELAY_ZERO: { severity: 'error', summary: 'a zero-length duration' },
|
|
7
|
+
DELAY_CALENDAR: { severity: 'error', summary: 'a calendar-relative duration no local rung can run' },
|
|
8
|
+
DELAY_HAS_NO_OUTPUT: { severity: 'error', summary: "a read of a delay's output" },
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* An EXACT ISO-8601 duration: weeks/days plus a time part, at least one
|
|
12
|
+
* component. Copied in shape from the delay definition's own
|
|
13
|
+
* `timerValue.pattern`, minus the years and months — see DELAY_CALENDAR below.
|
|
14
|
+
*/
|
|
15
|
+
const DURATION_RE = /^P(?!$)(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/;
|
|
16
|
+
/** Grammatical ISO-8601 duration, including the calendar-relative parts. */
|
|
17
|
+
const ANY_DURATION_RE = /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/;
|
|
18
|
+
/** Natural-language guesses an author might reach for, mapped to a duration. */
|
|
19
|
+
const DURATION_WORDS = [
|
|
20
|
+
['second', 'PT30S'], ['minute', 'PT15M'], ['hour', 'PT1H'],
|
|
21
|
+
['day', 'P1D'], ['daily', 'P1D'], ['week', 'P1W'], ['weekly', 'P1W'],
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Diagnose a `delay` step's wait.
|
|
25
|
+
*
|
|
26
|
+
* Rung 1 is the only place an author hears about a bad duration in time to fix
|
|
27
|
+
* it cheaply. Anything downstream speaks in terms of `timerPreset`/`timerValue`,
|
|
28
|
+
* the two fields the serializer writes, rather than the one field the author typed.
|
|
29
|
+
*/
|
|
30
|
+
export function checkDelay(inputs, ctx) {
|
|
31
|
+
const step = ctx.step;
|
|
32
|
+
const at = (code, message, suggestion) => ctx.report(code, message, suggestion || undefined);
|
|
33
|
+
const untilRaw = inputs?.until;
|
|
34
|
+
if (typeof untilRaw === 'string' && untilRaw.trim() !== '') {
|
|
35
|
+
// The absolute-date arm: an ISO-8601 date-time, e.g. 2026-09-01T09:00:00Z.
|
|
36
|
+
const until = untilRaw.trim();
|
|
37
|
+
if (!/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/.test(until)) {
|
|
38
|
+
at('DELAY_UNTIL_NOT_ISO', `Delay "${step}"'s until ${JSON.stringify(untilRaw)} is not an ISO-8601 date-time. `
|
|
39
|
+
+ `Use e.g. '2026-09-01T09:00:00Z' (a timezone-less value is read in the tenant's zone).`, `until: '2026-09-01T09:00:00Z'`);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const raw = inputs?.duration;
|
|
44
|
+
if (raw === undefined || raw === null || (typeof raw === 'string' && raw.trim() === '')) {
|
|
45
|
+
at('DELAY_NO_DURATION', `Delay "${step}" has no \`duration\`, so it carries no wait at all and the flow runs straight `
|
|
46
|
+
+ `past it. Give it an ISO-8601 duration — ${DELAY_PRESETS.slice(0, 8).join(', ')} … are the `
|
|
47
|
+
+ `designer's presets, and any other exact duration works too.`, `duration: 'PT15M'`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const d = String(raw).trim();
|
|
51
|
+
if (!ANY_DURATION_RE.test(d)) {
|
|
52
|
+
at('DELAY_NOT_ISO', `Delay "${step}"'s duration ${JSON.stringify(raw)} is not an ISO-8601 duration. The format is `
|
|
53
|
+
+ `"P" plus a date part and/or "T" plus a time part — PT30S, PT15M, PT2H, P1D, P1W. Note the `
|
|
54
|
+
+ `"T": P1M is a MONTH, PT1M is a minute.`, nearestDuration(d));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (!/[1-9]/.test(d)) {
|
|
58
|
+
at('DELAY_ZERO', `Delay "${step}"'s duration ${JSON.stringify(d)} is zero-length, so the step waits for no time `
|
|
59
|
+
+ `at all. Use a non-zero duration, or drop the step.`, `duration: 'PT15M'`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Grammatical, and the platform runs it — but a month is not a fixed number
|
|
63
|
+
// of milliseconds, so NO local rung can run the flow at all.
|
|
64
|
+
// Rejected here rather than approximated: guessing 30 days would
|
|
65
|
+
// put a silent disagreement with the deployed engine back into the pipeline.
|
|
66
|
+
if (!DURATION_RE.test(d)) {
|
|
67
|
+
at('DELAY_CALENDAR', `Delay "${step}"'s duration ${JSON.stringify(d)} is calendar-relative: how long a month or a `
|
|
68
|
+
+ `year is depends on when it starts. The platform resolves that at run time, but the local `
|
|
69
|
+
+ `timer takes a fixed millisecond count, so this flow could not be replayed or run offline.`, `duration: 'P30D'`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Best guess at what the author meant, for a `DELAY_NOT_ISO` suggestion. */
|
|
73
|
+
function nearestDuration(d) {
|
|
74
|
+
// The likeliest slip: a time-part duration written without its "T".
|
|
75
|
+
if (/^P\d+[HMS]$/.test(d) && ANY_DURATION_RE.test(`PT${d.slice(1)}`))
|
|
76
|
+
return `duration: 'PT${d.slice(1)}'`;
|
|
77
|
+
const lower = d.toLowerCase();
|
|
78
|
+
const n = /(\d+)/.exec(lower)?.[1];
|
|
79
|
+
const word = DURATION_WORDS.find(([w]) => lower.includes(w));
|
|
80
|
+
if (!word)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (!n)
|
|
83
|
+
return `duration: '${word[1]}'`;
|
|
84
|
+
const unit = word[1].replace(/\d+/, '');
|
|
85
|
+
return `duration: '${unit.startsWith('PT') ? `PT${n}${unit.slice(2)}` : `P${n}${unit.slice(1)}`}'`;
|
|
86
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Delay factory, `delay()`. Moved from core/actions.ts in Phase 4 of
|
|
3
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the package entry re-exports it.
|
|
4
|
+
*/
|
|
5
|
+
import { type ActionSpec } from '../../../core/actions.js';
|
|
6
|
+
import type { DelayInputs } from './spec.js';
|
|
7
|
+
/**
|
|
8
|
+
* Declare a delay — a step that pauses the flow for a fixed length of time and
|
|
9
|
+
* then carries on.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* A delay produces nothing: there is no `out('settle')` to read. It is a wait,
|
|
13
|
+
* not a value.
|
|
14
|
+
*
|
|
15
|
+
* The node itself splits that one duration across two fields (`timerPreset`
|
|
16
|
+
* holds it directly, or the literal `"custom"` with the real value in
|
|
17
|
+
* `timerValue`); the serializer picks the encoding, so you state the wait once.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* **Wait thirty seconds before carrying on**
|
|
21
|
+
* ```ts
|
|
22
|
+
* .step('settle', delay({ duration: 'PT30S' }))
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @param inputs - How long to wait (`duration`), as an ISO-8601 duration.
|
|
26
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function delay(inputs: DelayInputs): ActionSpec;
|