@uipath/maestro-builder-sdk 6.18.10 → 6.20.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 (134) hide show
  1. package/dist/api-index.md +185 -184
  2. package/dist/api-members.md +506 -473
  3. package/dist/check.js +358 -695
  4. package/dist/cli/commands/flow.js +3 -0
  5. package/dist/compile-cli.js +51 -0
  6. package/dist/core/actions.d.ts +132 -765
  7. package/dist/core/actions.js +1 -307
  8. package/dist/core/binding-identity.d.ts +22 -0
  9. package/dist/core/binding-identity.js +28 -0
  10. package/dist/core/context-index.d.ts +34 -0
  11. package/dist/core/context-index.js +38 -0
  12. package/dist/core/definitionless-node-types.d.ts +16 -0
  13. package/dist/core/definitionless-node-types.js +16 -0
  14. package/dist/core/error-port.d.ts +6 -0
  15. package/dist/core/error-port.js +9 -0
  16. package/dist/core/form-field-type.d.ts +33 -0
  17. package/dist/core/form-field-type.js +30 -0
  18. package/dist/core/hitl-routing.d.ts +8 -0
  19. package/dist/core/hitl-routing.js +17 -1
  20. package/dist/core/node-classes.d.ts +4 -63
  21. package/dist/core/node-classes.js +0 -112
  22. package/dist/core/nodes/family.d.ts +36 -0
  23. package/dist/core/nodes/family.js +1 -0
  24. package/dist/core/nodes/node-type.d.ts +136 -0
  25. package/dist/core/nodes/node-type.js +1 -0
  26. package/dist/core/nodes/registry.d.ts +57 -0
  27. package/dist/core/nodes/registry.js +122 -0
  28. package/dist/core/nodes/versioned.d.ts +50 -0
  29. package/dist/core/nodes/versioned.js +46 -0
  30. package/dist/core/process-resource-sort-order.d.ts +40 -0
  31. package/dist/core/process-resource-sort-order.js +44 -0
  32. package/dist/core/typed-raw-node.d.ts +13 -62
  33. package/dist/core/typed-raw-node.js +40 -154
  34. package/dist/core/wire-expr.d.ts +27 -0
  35. package/dist/core/wire-expr.js +34 -0
  36. package/dist/decompile-cli.js +11 -1
  37. package/dist/decompile.d.ts +8 -3
  38. package/dist/decompile.js +665 -354
  39. package/dist/flow-definitions.d.ts +10 -0
  40. package/dist/flow-definitions.js +35 -0
  41. package/dist/flow-expr-check.js +1 -1
  42. package/dist/flow-node-registry.d.ts +13 -0
  43. package/dist/flow-node-registry.js +19 -0
  44. package/dist/flow-node-type.d.ts +192 -0
  45. package/dist/flow-node-type.js +1 -0
  46. package/dist/flow-sdk.d.ts +40 -1
  47. package/dist/flow-sdk.js +29 -2
  48. package/dist/flow-step-tree.js +2 -1
  49. package/dist/index.d.ts +2 -1
  50. package/dist/index.js +1 -0
  51. package/dist/merge-cli.js +25 -8
  52. package/dist/merge-roundtrip.d.ts +81 -0
  53. package/dist/merge-roundtrip.js +404 -0
  54. package/dist/merge.d.ts +35 -6
  55. package/dist/merge.js +124 -24
  56. package/dist/node-placement.d.ts +93 -0
  57. package/dist/node-placement.js +163 -0
  58. package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
  59. package/dist/nodes/data-fabric/flow/check.js +164 -0
  60. package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
  61. package/dist/nodes/data-fabric/flow/factories.js +134 -0
  62. package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
  63. package/dist/nodes/data-fabric/flow/family.js +9 -0
  64. package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
  65. package/dist/nodes/data-fabric/flow/index.js +8 -0
  66. package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
  67. package/dist/nodes/data-fabric/flow/raw.js +100 -0
  68. package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
  69. package/dist/nodes/data-fabric/flow/shared.js +174 -0
  70. package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
  71. package/dist/nodes/data-fabric/flow/spec.js +1 -0
  72. package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
  73. package/dist/nodes/data-fabric/flow/verbs.js +239 -0
  74. package/dist/nodes/delay/flow/check.d.ts +16 -0
  75. package/dist/nodes/delay/flow/check.js +86 -0
  76. package/dist/nodes/delay/flow/factories.d.ts +28 -0
  77. package/dist/nodes/delay/flow/factories.js +38 -0
  78. package/dist/nodes/delay/flow/family.d.ts +3 -0
  79. package/dist/nodes/delay/flow/family.js +8 -0
  80. package/dist/nodes/delay/flow/index.d.ts +3 -0
  81. package/dist/nodes/delay/flow/index.js +3 -0
  82. package/dist/nodes/delay/flow/node-type.d.ts +13 -0
  83. package/dist/nodes/delay/flow/node-type.js +71 -0
  84. package/dist/nodes/delay/flow/spec.d.ts +43 -0
  85. package/dist/nodes/delay/flow/spec.js +16 -0
  86. package/dist/nodes/document/flow/factories.d.ts +27 -0
  87. package/dist/nodes/document/flow/factories.js +30 -0
  88. package/dist/nodes/document/flow/family.d.ts +3 -0
  89. package/dist/nodes/document/flow/family.js +7 -0
  90. package/dist/nodes/document/flow/index.d.ts +3 -0
  91. package/dist/nodes/document/flow/index.js +3 -0
  92. package/dist/nodes/document/flow/node-type.d.ts +14 -0
  93. package/dist/nodes/document/flow/node-type.js +150 -0
  94. package/dist/nodes/document/flow/spec.d.ts +65 -0
  95. package/dist/nodes/document/flow/spec.js +1 -0
  96. package/dist/nodes/mock/flow/factories.d.ts +51 -0
  97. package/dist/nodes/mock/flow/factories.js +47 -0
  98. package/dist/nodes/mock/flow/family.d.ts +3 -0
  99. package/dist/nodes/mock/flow/family.js +7 -0
  100. package/dist/nodes/mock/flow/index.d.ts +2 -0
  101. package/dist/nodes/mock/flow/index.js +2 -0
  102. package/dist/nodes/mock/flow/node-type.d.ts +11 -0
  103. package/dist/nodes/mock/flow/node-type.js +51 -0
  104. package/dist/nodes/script/flow/check.d.ts +19 -0
  105. package/dist/nodes/script/flow/check.js +49 -0
  106. package/dist/nodes/script/flow/factories.d.ts +14 -0
  107. package/dist/nodes/script/flow/factories.js +15 -0
  108. package/dist/nodes/script/flow/family.d.ts +3 -0
  109. package/dist/nodes/script/flow/family.js +8 -0
  110. package/dist/nodes/script/flow/index.d.ts +3 -0
  111. package/dist/nodes/script/flow/index.js +3 -0
  112. package/dist/nodes/script/flow/node-type.d.ts +7 -0
  113. package/dist/nodes/script/flow/node-type.js +125 -0
  114. package/dist/nodes/script/flow/spec.d.ts +52 -0
  115. package/dist/nodes/script/flow/spec.js +1 -0
  116. package/dist/nodes/transform/flow/check.d.ts +6 -0
  117. package/dist/nodes/transform/flow/check.js +229 -0
  118. package/dist/nodes/transform/flow/factories.d.ts +52 -0
  119. package/dist/nodes/transform/flow/factories.js +53 -0
  120. package/dist/nodes/transform/flow/family.d.ts +3 -0
  121. package/dist/nodes/transform/flow/family.js +8 -0
  122. package/dist/nodes/transform/flow/index.d.ts +3 -0
  123. package/dist/nodes/transform/flow/index.js +3 -0
  124. package/dist/nodes/transform/flow/node-type.d.ts +7 -0
  125. package/dist/nodes/transform/flow/node-type.js +245 -0
  126. package/dist/nodes/transform/flow/spec.d.ts +116 -0
  127. package/dist/nodes/transform/flow/spec.js +10 -0
  128. package/dist/raw-node-advice.d.ts +16 -0
  129. package/dist/raw-node-advice.js +36 -0
  130. package/dist/raw-node.d.ts +71 -0
  131. package/dist/raw-node.js +116 -0
  132. package/dist/registry/uip/pipeline-front-door.js +5 -3
  133. package/dist/serialize.js +246 -549
  134. package/package.json +2 -2
@@ -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;
@@ -0,0 +1,38 @@
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 { builtinActionSpec } from '../../../core/actions.js';
6
+ /**
7
+ * Declare a delay — a step that pauses the flow for a fixed length of time and
8
+ * then carries on.
9
+ *
10
+ * @remarks
11
+ * A delay produces nothing: there is no `out('settle')` to read. It is a wait,
12
+ * not a value.
13
+ *
14
+ * The node itself splits that one duration across two fields (`timerPreset`
15
+ * holds it directly, or the literal `"custom"` with the real value in
16
+ * `timerValue`); the serializer picks the encoding, so you state the wait once.
17
+ *
18
+ * @example
19
+ * **Wait thirty seconds before carrying on**
20
+ * ```ts
21
+ * .step('settle', delay({ duration: 'PT30S' }))
22
+ * ```
23
+ *
24
+ * @param inputs - How long to wait (`duration`), as an ISO-8601 duration.
25
+ * @returns An action spec to pass to `.step(name, …)`.
26
+ */
27
+ export function delay(inputs) {
28
+ // Key presence, not value shape: `{ duration: undefined }` picks the
29
+ // duration arm and flows to check()'s DELAY_NO_DURATION diagnostic — the
30
+ // factory only rejects picking BOTH arms or NEITHER.
31
+ const hasDuration = 'duration' in inputs;
32
+ const hasUntil = 'until' in inputs;
33
+ if (hasDuration === hasUntil) {
34
+ throw new Error("delay() takes exactly ONE of { duration } (an ISO-8601 duration, e.g. 'PT15M') or "
35
+ + "{ until } (an ISO-8601 date-time, e.g. '2026-09-01T09:00:00Z').");
36
+ }
37
+ return builtinActionSpec({ kind: 'delay', inputs });
38
+ }
@@ -0,0 +1,3 @@
1
+ /** The Delay node family, as flow-node-registry.ts lists it: `core.logic.delay`. */
2
+ import type { FlowNodeFamily } from '../../../flow-node-type.js';
3
+ export declare const delayFlowFamily: FlowNodeFamily;
@@ -0,0 +1,8 @@
1
+ import { DELAY_DIAGNOSTICS } from './check.js';
2
+ import { delayNodeType } from './node-type.js';
3
+ export const delayFlowFamily = {
4
+ id: 'delay',
5
+ title: 'Delay',
6
+ types: [delayNodeType],
7
+ diagnostics: DELAY_DIAGNOSTICS,
8
+ };
@@ -0,0 +1,3 @@
1
+ /** The Delay family's public surface, which the package entry re-exports. */
2
+ export * from './spec.js';
3
+ export * from './factories.js';
@@ -0,0 +1,3 @@
1
+ /** The Delay family's public surface, which the package entry re-exports. */
2
+ export * from './spec.js';
3
+ export * from './factories.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The Delay node type, `core.logic.delay` (bundled 1.0.0 and 1.0). Moved from
3
+ * serialize.ts / check.ts / decompile.ts in Phase 4 of
4
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; serialized output, codes and messages
5
+ * unchanged.
6
+ */
7
+ import type { FlowVersionedNodeType } from '../../../flow-node-type.js';
8
+ import { type DelayInputs } from './spec.js';
9
+ export type DelaySpec = {
10
+ kind: 'delay';
11
+ inputs: DelayInputs;
12
+ };
13
+ export declare const delayNodeType: FlowVersionedNodeType<DelaySpec>;
@@ -0,0 +1,71 @@
1
+ import { DELAY_PRESETS } from './spec.js';
2
+ import { checkDelay } from './check.js';
3
+ /**
4
+ * Encode a delay's single `duration` into the two inputs the platform's node
5
+ * carries — the SAME split as the scheduled trigger above, on the same field
6
+ * names, because it is the same designer control: `timerPreset` holds the
7
+ * duration when it is one of the dropdown's twelve, and otherwise holds the
8
+ * literal `"custom"` with the real duration in `timerValue`. flow-v1's timer
9
+ * serializer collapses them straight back (`event-definition.ts:31`), so the
10
+ * two encodings are the same wait.
11
+ *
12
+ * Both are shapes the platform actually deploys — 26 of 26 archived
13
+ * `skill-flow-delay` flows carry the preset form, 35 of 38 archived
14
+ * `skill-flow-terminate` flows the custom form — so this is a choice of
15
+ * encoding, not of correctness. Emitting the preset when one fits keeps the
16
+ * node's Duration dropdown showing a value instead of "Custom".
17
+ *
18
+ * `timerType` is `timeDuration` for a `duration` and `timeDate` for `until`,
19
+ * because the platform's timer serializer resolves a body as
20
+ * "preset, else timerValue" for EVERY kind and so never reads `timerDate` while
21
+ * a duration is present (flow-builder-sdk#70).
22
+ */
23
+ function delayInputs(inputs) {
24
+ // An absolute-date wait (`until`) is the definition's timeDate arm: it
25
+ // requires timerDate, while the top-level required timerPreset is satisfied
26
+ // with the literal 'custom' (the timeDuration-only allOf never fires).
27
+ const until = String(inputs?.until ?? '').trim();
28
+ if (until) {
29
+ return { timerType: 'timeDate', timerPreset: 'custom', timerDate: until };
30
+ }
31
+ const duration = String(inputs?.duration ?? '').trim();
32
+ const isPreset = DELAY_PRESETS.includes(duration);
33
+ return {
34
+ timerType: 'timeDuration',
35
+ timerPreset: isPreset ? duration : 'custom',
36
+ ...(isPreset ? {} : { timerValue: duration }),
37
+ };
38
+ }
39
+ function delayAt(version) {
40
+ return {
41
+ kind: 'delay', typeName: 'core.logic.delay', version, factory: 'delay', definition: 'bundled',
42
+ rawNode: { factory: 'delay({ duration })' },
43
+ serialize: ({ inputs }) => ({ inputs: delayInputs(inputs) }),
44
+ // The three spellings delayInputs writes — `{ timerType, timerPreset,
45
+ // timerValue? }` for a duration and `{ timerType: 'timeDate', timerDate }`
46
+ // for an absolute wait — back to the factory's one.
47
+ deserialize: (node) => {
48
+ const inputs = node.inputs ?? {};
49
+ if (inputs.timerType === 'timeDate') {
50
+ return { kind: 'delay', inputs: { until: typeof inputs.timerDate === 'string' ? inputs.timerDate : '' } };
51
+ }
52
+ const duration = inputs.timerPreset === 'custom'
53
+ ? (typeof inputs.timerValue === 'string' ? inputs.timerValue : '')
54
+ : (typeof inputs.timerPreset === 'string' ? inputs.timerPreset : '');
55
+ return { kind: 'delay', inputs: { duration } };
56
+ },
57
+ check: ({ inputs }, ctx) => checkDelay(inputs, ctx),
58
+ // check collected no expressions for a delay before the port; unchanged by it.
59
+ expressions: () => [],
60
+ output: () => ({
61
+ kind: 'none',
62
+ code: 'DELAY_HAS_NO_OUTPUT',
63
+ message: ({ node, ref, reader }) => `Delay "${node}" produces no output, but "${ref}" reads one in "${reader}". `
64
+ + 'A delay only waits — read the step that computed the value instead.',
65
+ }),
66
+ };
67
+ }
68
+ export const delayNodeType = {
69
+ kind: 'delay', typeName: 'core.logic.delay', factory: 'delay', defaultVersion: '1.0.0',
70
+ versions: { '1.0.0': delayAt('1.0.0'), '1.0': delayAt('1.0') },
71
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * The Delay family's authoring types (`core.logic.delay`), and its kind's entry in
3
+ * `FlowActionSpecs`. Moved from core/actions.ts in Phase 4 of
4
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md.
5
+ */
6
+ /**
7
+ * The twelve durations the designer's dropdown offers. Purely an ENCODING
8
+ * detail: a duration in this list ships as `timerPreset: '<duration>'` and any
9
+ * other ships as `timerPreset: 'custom'` + `timerValue: '<duration>'`. Both
10
+ * deploy and both wait the same length of time — the author never picks.
11
+ * `core-definitions.test.ts` pins this list against the definition's own form.
12
+ */
13
+ export declare const DELAY_PRESETS: readonly ["PT5S", "PT15S", "PT30S", "PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D", "P1W"];
14
+ export type DelayInputs = {
15
+ /**
16
+ * How long to wait, as an ISO-8601 duration: `PT30S`, `PT15M`, `PT2H`,
17
+ * `P1D`, `P1W`. `PT` separates the time part, so `P1M` is a MONTH and
18
+ * `PT1M` is a minute.
19
+ * ISO-8601 duration format documentation is here:
20
+ * {@link https://docs.digi.com/resources/documentation/digidocs/90001488-13/reference/r_iso_8601_duration_format.htm}
21
+ */
22
+ duration: string;
23
+ /** Impossible together with `duration` — a delay waits one way or the other. */
24
+ until?: never;
25
+ } | {
26
+ /**
27
+ * Wait until an ABSOLUTE date-time, ISO-8601: `2026-09-01T09:00:00Z` or
28
+ * `2026-09-01T09:00:00+02:00`. The platform's timeDate timer: the run
29
+ * parks until the wall clock reaches this moment (already-past dates
30
+ * fire immediately).
31
+ */
32
+ until: string;
33
+ /** Impossible together with `until` — a delay waits one way or the other. */
34
+ duration?: never;
35
+ };
36
+ declare module '../../../core/actions.js' {
37
+ interface FlowActionSpecs {
38
+ /** The spec {@link delay} builds. */
39
+ delay: {
40
+ inputs: DelayInputs;
41
+ };
42
+ }
43
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The Delay family's authoring types (`core.logic.delay`), and its kind's entry in
3
+ * `FlowActionSpecs`. Moved from core/actions.ts in Phase 4 of
4
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md.
5
+ */
6
+ /**
7
+ * The twelve durations the designer's dropdown offers. Purely an ENCODING
8
+ * detail: a duration in this list ships as `timerPreset: '<duration>'` and any
9
+ * other ships as `timerPreset: 'custom'` + `timerValue: '<duration>'`. Both
10
+ * deploy and both wait the same length of time — the author never picks.
11
+ * `core-definitions.test.ts` pins this list against the definition's own form.
12
+ */
13
+ export const DELAY_PRESETS = [
14
+ 'PT5S', 'PT15S', 'PT30S', 'PT1M', 'PT5M', 'PT15M', 'PT30M',
15
+ 'PT1H', 'PT6H', 'PT12H', 'P1D', 'P1W',
16
+ ];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The document factories, `documentClassify()` and `dynamicExtract()`. Moved
3
+ * from core/actions.ts in Phase 4 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the
4
+ * package entry re-exports them.
5
+ */
6
+ import { type ActionSpec } from '../../../core/actions.js';
7
+ import type { DocumentClassifyInputs, DynamicExtractInputs } from './spec.js';
8
+ /**
9
+ * Classify a document into a document type (`uipath.document.classify`). The
10
+ * result publishes `ClassificationResult` — an array of typed classifications
11
+ * with page ranges and confidences.
12
+ *
13
+ * @param inputs - The file reference and optional page range / split / model settings.
14
+ * @returns An action spec to pass to `.step(name, …)`.
15
+ */
16
+ export declare function documentClassify(inputs: DocumentClassifyInputs): ActionSpec;
17
+ /**
18
+ * Extract fields from a document with an INLINE schema — Dynamic Extract
19
+ * (`uipath.ixp.extract-document-builder`), the newer of the two extraction
20
+ * shapes. No deployed IXP project is referenced: the extraction schema rides
21
+ * the node. The result publishes `ExtractionResult` (and `Taxonomy`).
22
+ *
23
+ * @param inputs - The file reference, the inline extraction schema, and
24
+ * optional page range / model settings.
25
+ * @returns An action spec to pass to `.step(name, …)`.
26
+ */
27
+ export declare function dynamicExtract(inputs: DynamicExtractInputs): ActionSpec;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The document factories, `documentClassify()` and `dynamicExtract()`. Moved
3
+ * from core/actions.ts in Phase 4 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the
4
+ * package entry re-exports them.
5
+ */
6
+ import { builtinActionSpec } from '../../../core/actions.js';
7
+ /**
8
+ * Classify a document into a document type (`uipath.document.classify`). The
9
+ * result publishes `ClassificationResult` — an array of typed classifications
10
+ * with page ranges and confidences.
11
+ *
12
+ * @param inputs - The file reference and optional page range / split / model settings.
13
+ * @returns An action spec to pass to `.step(name, …)`.
14
+ */
15
+ export function documentClassify(inputs) {
16
+ return builtinActionSpec({ kind: 'documentClassify', inputs });
17
+ }
18
+ /**
19
+ * Extract fields from a document with an INLINE schema — Dynamic Extract
20
+ * (`uipath.ixp.extract-document-builder`), the newer of the two extraction
21
+ * shapes. No deployed IXP project is referenced: the extraction schema rides
22
+ * the node. The result publishes `ExtractionResult` (and `Taxonomy`).
23
+ *
24
+ * @param inputs - The file reference, the inline extraction schema, and
25
+ * optional page range / model settings.
26
+ * @returns An action spec to pass to `.step(name, …)`.
27
+ */
28
+ export function dynamicExtract(inputs) {
29
+ return builtinActionSpec({ kind: 'dynamicExtract', inputs });
30
+ }
@@ -0,0 +1,3 @@
1
+ /** The document node family, as flow-node-registry.ts lists it: Document Classify and Dynamic Extract. */
2
+ import type { FlowNodeFamily } from '../../../flow-node-type.js';
3
+ export declare const documentFlowFamily: FlowNodeFamily;