@uipath/maestro-builder-sdk 6.18.10 → 6.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/api-index.md +185 -184
  2. package/dist/api-members.md +504 -473
  3. package/dist/check.js +177 -650
  4. package/dist/core/actions.d.ts +119 -760
  5. package/dist/core/actions.js +0 -306
  6. package/dist/core/error-port.d.ts +6 -0
  7. package/dist/core/error-port.js +9 -0
  8. package/dist/core/node-classes.d.ts +4 -63
  9. package/dist/core/node-classes.js +0 -112
  10. package/dist/core/nodes/family.d.ts +36 -0
  11. package/dist/core/nodes/family.js +1 -0
  12. package/dist/core/nodes/node-type.d.ts +136 -0
  13. package/dist/core/nodes/node-type.js +1 -0
  14. package/dist/core/nodes/registry.d.ts +57 -0
  15. package/dist/core/nodes/registry.js +122 -0
  16. package/dist/core/nodes/versioned.d.ts +50 -0
  17. package/dist/core/nodes/versioned.js +46 -0
  18. package/dist/core/typed-raw-node.d.ts +13 -62
  19. package/dist/core/typed-raw-node.js +40 -154
  20. package/dist/decompile.js +92 -271
  21. package/dist/flow-definitions.d.ts +10 -0
  22. package/dist/flow-definitions.js +35 -0
  23. package/dist/flow-node-registry.d.ts +13 -0
  24. package/dist/flow-node-registry.js +19 -0
  25. package/dist/flow-node-type.d.ts +192 -0
  26. package/dist/flow-node-type.js +1 -0
  27. package/dist/flow-sdk.d.ts +7 -0
  28. package/dist/flow-sdk.js +8 -0
  29. package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
  30. package/dist/nodes/data-fabric/flow/check.js +164 -0
  31. package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
  32. package/dist/nodes/data-fabric/flow/factories.js +134 -0
  33. package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
  34. package/dist/nodes/data-fabric/flow/family.js +9 -0
  35. package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
  36. package/dist/nodes/data-fabric/flow/index.js +8 -0
  37. package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
  38. package/dist/nodes/data-fabric/flow/raw.js +100 -0
  39. package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
  40. package/dist/nodes/data-fabric/flow/shared.js +174 -0
  41. package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
  42. package/dist/nodes/data-fabric/flow/spec.js +1 -0
  43. package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
  44. package/dist/nodes/data-fabric/flow/verbs.js +239 -0
  45. package/dist/nodes/delay/flow/check.d.ts +16 -0
  46. package/dist/nodes/delay/flow/check.js +86 -0
  47. package/dist/nodes/delay/flow/factories.d.ts +28 -0
  48. package/dist/nodes/delay/flow/factories.js +38 -0
  49. package/dist/nodes/delay/flow/family.d.ts +3 -0
  50. package/dist/nodes/delay/flow/family.js +8 -0
  51. package/dist/nodes/delay/flow/index.d.ts +3 -0
  52. package/dist/nodes/delay/flow/index.js +3 -0
  53. package/dist/nodes/delay/flow/node-type.d.ts +13 -0
  54. package/dist/nodes/delay/flow/node-type.js +71 -0
  55. package/dist/nodes/delay/flow/spec.d.ts +43 -0
  56. package/dist/nodes/delay/flow/spec.js +16 -0
  57. package/dist/nodes/document/flow/factories.d.ts +27 -0
  58. package/dist/nodes/document/flow/factories.js +30 -0
  59. package/dist/nodes/document/flow/family.d.ts +3 -0
  60. package/dist/nodes/document/flow/family.js +7 -0
  61. package/dist/nodes/document/flow/index.d.ts +3 -0
  62. package/dist/nodes/document/flow/index.js +3 -0
  63. package/dist/nodes/document/flow/node-type.d.ts +14 -0
  64. package/dist/nodes/document/flow/node-type.js +150 -0
  65. package/dist/nodes/document/flow/spec.d.ts +65 -0
  66. package/dist/nodes/document/flow/spec.js +1 -0
  67. package/dist/nodes/mock/flow/factories.d.ts +51 -0
  68. package/dist/nodes/mock/flow/factories.js +47 -0
  69. package/dist/nodes/mock/flow/family.d.ts +3 -0
  70. package/dist/nodes/mock/flow/family.js +7 -0
  71. package/dist/nodes/mock/flow/index.d.ts +2 -0
  72. package/dist/nodes/mock/flow/index.js +2 -0
  73. package/dist/nodes/mock/flow/node-type.d.ts +11 -0
  74. package/dist/nodes/mock/flow/node-type.js +51 -0
  75. package/dist/nodes/script/flow/check.d.ts +19 -0
  76. package/dist/nodes/script/flow/check.js +49 -0
  77. package/dist/nodes/script/flow/factories.d.ts +14 -0
  78. package/dist/nodes/script/flow/factories.js +15 -0
  79. package/dist/nodes/script/flow/family.d.ts +3 -0
  80. package/dist/nodes/script/flow/family.js +8 -0
  81. package/dist/nodes/script/flow/index.d.ts +3 -0
  82. package/dist/nodes/script/flow/index.js +3 -0
  83. package/dist/nodes/script/flow/node-type.d.ts +7 -0
  84. package/dist/nodes/script/flow/node-type.js +125 -0
  85. package/dist/nodes/script/flow/spec.d.ts +52 -0
  86. package/dist/nodes/script/flow/spec.js +1 -0
  87. package/dist/nodes/transform/flow/check.d.ts +6 -0
  88. package/dist/nodes/transform/flow/check.js +229 -0
  89. package/dist/nodes/transform/flow/factories.d.ts +52 -0
  90. package/dist/nodes/transform/flow/factories.js +53 -0
  91. package/dist/nodes/transform/flow/family.d.ts +3 -0
  92. package/dist/nodes/transform/flow/family.js +8 -0
  93. package/dist/nodes/transform/flow/index.d.ts +3 -0
  94. package/dist/nodes/transform/flow/index.js +3 -0
  95. package/dist/nodes/transform/flow/node-type.d.ts +7 -0
  96. package/dist/nodes/transform/flow/node-type.js +244 -0
  97. package/dist/nodes/transform/flow/spec.d.ts +116 -0
  98. package/dist/nodes/transform/flow/spec.js +10 -0
  99. package/dist/raw-node-advice.d.ts +16 -0
  100. package/dist/raw-node-advice.js +36 -0
  101. package/dist/raw-node.d.ts +71 -0
  102. package/dist/raw-node.js +116 -0
  103. package/dist/serialize.js +138 -492
  104. package/package.json +2 -2
package/dist/decompile.js CHANGED
@@ -28,13 +28,11 @@
28
28
  * display labels on plain steps, and formatting are not preserved (layout is
29
29
  * re-attached by `flow-merge`; see `docs/FLOW_PARITY.md`).
30
30
  */
31
- import { readFileSync } from 'node:fs';
32
31
  import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
33
32
  import { preserveSchemaVersion } from './schema-version.js';
34
- import { dirname, join } from 'node:path';
35
- import { fileURLToPath } from 'node:url';
36
- import { inferScriptShape } from './core/script-return.js';
37
- import { DEFAULT_TRIGGER_ID } from './core/expr.js';
33
+ import { BUNDLED_DEFINITIONS, bundledVersions, hasBundledDefinition } from './flow-definitions.js';
34
+ import { DEFAULT_TRIGGER_ID, Expr } from './core/expr.js';
35
+ import { FLOW_NODE_TYPES } from './flow-node-registry.js';
38
36
  import { commentText } from './core/comment-text.js';
39
37
  import { tsLiteral, tsNumber, tsText } from './core/ts-literal.js';
40
38
  import { parseIxpProjectType } from './core/actions.js';
@@ -89,16 +87,6 @@ function warnOnce(message) {
89
87
  runWarned.add(message);
90
88
  runWarn?.(message);
91
89
  }
92
- /**
93
- * The `<nodeType>@<version>` pairs this SDK bundles for core nodes — the same
94
- * file `serialize` resolves an explicit `{ version }` against (design §2.6:
95
- * exact, no floating). Decompile preserves the file's pair (design §5.3), so
96
- * when the file pins a version the bundle lacks, `compile` WILL refuse the
97
- * emitted source; saying so here is the difference between a loop that fails
98
- * at step 2 with a hint and one that fails at step 2 with a puzzle.
99
- */
100
- const CORE_DEFINITIONS = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'core-definitions.json'), 'utf8'));
101
- const CORE_DEFINITION_KEYS = new Set(Object.keys(CORE_DEFINITIONS));
102
90
  /**
103
91
  * The label the canvas gives a freshly dropped `node`: its definition's
104
92
  * `display.label`, from the file's own `definitions[]`, else the bundled core
@@ -106,7 +94,7 @@ const CORE_DEFINITION_KEYS = new Set(Object.keys(CORE_DEFINITIONS));
106
94
  */
107
95
  function definitionLabel(node) {
108
96
  const key = `${node.type}@${node.typeVersion}`;
109
- const def = runDefs.get(key) ?? CORE_DEFINITIONS[key] ?? runDefs.get(node.type);
97
+ const def = runDefs.get(key) ?? BUNDLED_DEFINITIONS[key] ?? runDefs.get(node.type);
110
98
  const label = def?.display?.label;
111
99
  return typeof label === 'string' ? label : undefined;
112
100
  }
@@ -124,11 +112,17 @@ function verClause(node) {
124
112
  + `the file's definitions[] disagrees with the instance.`);
125
113
  }
126
114
  }
127
- if (node.type.startsWith('core.') && !CORE_DEFINITION_KEYS.has(`${node.type}@${tv}`)) {
128
- const shipped = [...CORE_DEFINITION_KEYS]
129
- .filter((k) => k.startsWith(`${node.type}@`))
130
- .map((k) => k.slice(node.type.length + 1));
131
- warnOnce(`node ${tsLiteral(node.id)} pins ${node.type}@${tv}, but this SDK bundles ${node.type}@${shipped.join(', ') || '<none>'} only; `
115
+ // Decompile preserves the file's pair (design §5.3), but `serialize` resolves an
116
+ // explicit { version } against the bundle exactly (design §2.6), so a pin the
117
+ // bundle lacks WILL fail `compile`; saying so here is the difference between a
118
+ // loop that fails at step 2 with a hint and one that fails with a puzzle.
119
+ // A registered type resolves against its registered versions, which the bundle
120
+ // may exceed; every other core type against the bundle.
121
+ const registered = FLOW_NODE_TYPES.byTypeName(node.type);
122
+ const shipped = registered ? Object.keys(registered.type.versions)
123
+ : node.type.startsWith('core.') && !hasBundledDefinition(node.type, tv) ? bundledVersions(node.type) : undefined;
124
+ if (shipped && !shipped.includes(tv)) {
125
+ warnOnce(`node ${tsLiteral(node.id)} pins ${node.type}@${tv}, but this SDK ${registered ? 'registers' : 'bundles'} ${node.type}@${shipped.join(', ') || '<none>'} only; `
132
126
  + `\`compile\` will refuse the emitted { version: ${tsLiteral(tv)} } (versions resolve exactly, flow-builder-sdk#71). `
133
127
  + `The source keeps the file's pair; to recompile, drop that { version } and the node takes the SDK's pinned version.`);
134
128
  }
@@ -210,21 +204,11 @@ const T = {
210
204
  endCall: 'uipath.conversational.voice.end-call',
211
205
  http: 'core.action.http',
212
206
  httpV2: 'core.action.http.v2',
213
- script: 'core.action.script',
214
- transform: 'core.action.transform',
215
- delay: 'core.logic.delay',
216
- mock: 'core.logic.mock',
217
207
  decision: 'core.logic.decision',
218
208
  switch: 'core.logic.switch',
219
209
  merge: 'core.logic.merge',
220
210
  loop: 'core.logic.loop',
221
211
  doWhile: 'core.logic.dowhile',
222
- dataFabricRead: 'core.datafabric.read',
223
- dataFabricCreate: 'core.datafabric.create',
224
- dataFabricDelete: 'core.datafabric.delete',
225
- documentClassify: 'uipath.document.classify',
226
- dynamicExtract: 'uipath.ixp.extract-document-builder',
227
- dataFabricUpdate: 'core.datafabric.update',
228
212
  subflow: 'core.subflow',
229
213
  terminate: 'core.logic.terminate',
230
214
  end: 'core.control.end',
@@ -503,147 +487,91 @@ class Graph {
503
487
  }
504
488
  }
505
489
  // ─── Node → step-spec source ──────────────────────────────────────────────────
490
+ /**
491
+ * A serialized value back as a spec holds it: `=js:` text (bare, or in a
492
+ * `{ type: 'jsExpression', expression }` object) becomes an `Expr`; anything else
493
+ * is a literal and stays itself.
494
+ */
495
+ function specValue(raw) {
496
+ if (typeof raw === 'string')
497
+ return raw.startsWith('=js:') ? new Expr(raw.slice(4)) : raw;
498
+ const o = raw;
499
+ if (o && typeof o === 'object' && o.type === 'jsExpression' && typeof o.expression === 'string')
500
+ return new Expr(o.expression);
501
+ return raw;
502
+ }
503
+ /**
504
+ * Print a node whose type is registered (flow-node-registry.ts): the node type
505
+ * deserializes it to its spec and prints the factory call. A node at a version
506
+ * the type does not register is lifted by its default version's implementation —
507
+ * as every built-in family lifts any version today — and keeps its own
508
+ * `{ version }` on the step, which compile then refuses; `verClause` warns at
509
+ * decompile time that it will. `undefined` when the type is not registered, or the node type declines
510
+ * the node; the caller's branches take it from there.
511
+ */
512
+ function emitRegisteredSpec(node, imp, inputNames) {
513
+ const entry = typeof node.type === 'string' ? FLOW_NODE_TYPES.byTypeName(node.type) : undefined;
514
+ if (!entry)
515
+ return undefined;
516
+ const version = String(node.typeVersion ?? '');
517
+ const impl = (Object.hasOwn(entry.type.versions, version)
518
+ ? entry.type.versions[version]
519
+ : entry.type.versions[entry.type.defaultVersion]);
520
+ const ctx = {
521
+ nodeId: node.id,
522
+ expr: specValue,
523
+ sourceText: unwrapSource,
524
+ plainValue: unwrapPlain,
525
+ stepName: (nodeId) => nodeId,
526
+ definition: () => runDefs.get(`${node.type}@${version}`) ?? runDefs.get(node.type),
527
+ warn: warnOnce,
528
+ };
529
+ const spec = impl.deserialize(node, ctx);
530
+ if (spec === undefined)
531
+ return undefined;
532
+ // A spec value as source, recursing into arrays and plain objects so an Expr
533
+ // nested in one (a filter row's value) prints as the helper an author writes —
534
+ // in the `{ k: v }` / `[a, b]` spelling the hand-written printers use.
535
+ const printValue = (v) => {
536
+ if (v instanceof Expr)
537
+ return v.literal ? tsLiteral(v.value) : emitRef(v.js, imp, inputNames);
538
+ if (Array.isArray(v))
539
+ return `[${v.map(printValue).join(', ')}]`;
540
+ if (v && typeof v === 'object') {
541
+ const parts = Object.entries(v).filter(([, x]) => x !== undefined).map(([k, x]) => `${key(k)}: ${printValue(x)}`);
542
+ return parts.length ? `{ ${parts.join(', ')} }` : '{}';
543
+ }
544
+ return tsLiteral(v);
545
+ };
546
+ const print = {
547
+ value: printValue,
548
+ string: (t) => tsLiteral(t),
549
+ json: (v) => tsLiteral(v),
550
+ key: (k) => key(k),
551
+ helper: (name) => imp.use(name),
552
+ };
553
+ const call = impl.print?.(spec, print) ?? {
554
+ factory: impl.factory,
555
+ options: Object.entries(spec.inputs ?? {})
556
+ .map(([k, v]) => [k, v === undefined ? undefined : print.value(v)]),
557
+ };
558
+ const options = opts((call.options ?? []).map(([k, v]) => [k, v]));
559
+ const args = [...(call.positional ?? []), ...(options ? [options] : [])];
560
+ return `${imp.use(call.factory)}(${args.join(', ')})`;
561
+ }
506
562
  /**
507
563
  * Emit the action-spec argument for a `.step(id, <spec>)` call — e.g.
508
564
  * `script({ code: "…" })`. Returns `undefined` for a node that is not a plain
509
565
  * action (control-flow / trigger / end), which the traversal handles specially.
510
566
  */
511
567
  function emitStepSpec(node, imp, inputNames, o, graph) {
568
+ // A registered node type lifts itself; every other type falls through to the
569
+ // branches below until its family is ported (FB014's pins are the list).
570
+ const lifted = emitRegisteredSpec(node, imp, inputNames);
571
+ if (lifted !== undefined)
572
+ return lifted;
512
573
  const inputs = node.inputs ?? {};
513
574
  switch (node.type) {
514
- case T.mock:
515
- return `${imp.use('mock')}()`;
516
- case T.script: {
517
- const code = typeof inputs.script === 'string' ? inputs.script : '';
518
- // `returns` is emitted only when the node's declared output type is
519
- // something re-compiling the body would NOT produce on its own. Serialize
520
- // infers from the body first (see `scriptOutputs`), so a script whose type
521
- // is already plain in its code round-trips without it — emitting one there
522
- // would add an argument the author never wrote to every such step.
523
- return `${imp.use('script')}(${opts([['code', tsLiteral(code)], ...scriptReturnsOpt(node, code)])})`;
524
- }
525
- case T.delay: {
526
- // serialize's `delayInputs` writes `{timerType, timerPreset, timerValue?}`
527
- // for a duration and `{timerType:'timeDate', timerDate}` for an absolute
528
- // wait. Invert all three spellings.
529
- if (inputs.timerType === 'timeDate') {
530
- const until = typeof inputs.timerDate === 'string' ? inputs.timerDate : '';
531
- return `${imp.use('delay')}(${opts([['until', tsLiteral(until)]])})`;
532
- }
533
- const duration = inputs.timerPreset === 'custom'
534
- ? (typeof inputs.timerValue === 'string' ? inputs.timerValue : '')
535
- : (typeof inputs.timerPreset === 'string' ? inputs.timerPreset : '');
536
- return `${imp.use('delay')}(${opts([['duration', tsLiteral(duration)]])})`;
537
- }
538
- case T.documentClassify:
539
- case T.dynamicExtract: {
540
- const fr = unwrapSource(inputs.fileRef) ?? '';
541
- const fileSrc = fr.startsWith('=js:') ? emitBareExpr(fr.slice(4), imp, inputNames) : tsLiteral(fr);
542
- const pageRange = typeof inputs.pageRange === 'string' && inputs.pageRange !== '' ? tsLiteral(inputs.pageRange) : undefined;
543
- if (node.type === T.documentClassify) {
544
- const split = unwrapPlain(inputs.splitPages);
545
- return `${imp.use('documentClassify')}(${opts([
546
- ['fileRef', fileSrc],
547
- ['pageRange', pageRange],
548
- ['splitPages', split === true ? 'true' : undefined],
549
- ])})`;
550
- }
551
- const schema = inputs.schemaDocument !== undefined ? tsLiteral(inputs.schemaDocument) : undefined;
552
- return `${imp.use('dynamicExtract')}(${opts([
553
- ['fileRef', fileSrc],
554
- ['schema', schema],
555
- ['pageRange', pageRange],
556
- ])})`;
557
- }
558
- case T.dataFabricRead:
559
- case T.dataFabricCreate:
560
- case T.dataFabricUpdate:
561
- case T.dataFabricDelete: {
562
- const cfg = (inputs.entityConfig ?? {});
563
- const entity = tsText(cfg.entityName);
564
- const folder = typeof cfg._folderKey === 'string' ? tsLiteral(cfg._folderKey) : undefined;
565
- const resourceKey = typeof cfg._resourceKey === 'string' ? tsLiteral(cfg._resourceKey) : undefined;
566
- const val = (v) => {
567
- // 1.3 let `recordId` and a create's field value be a `{ type:
568
- // 'jsExpression', expression }` object as well as a `=js:` string. A
569
- // product-authored node can carry either; both recover as an expression.
570
- const obj = v;
571
- if (obj && typeof obj === 'object' && obj.type === 'jsExpression') {
572
- return emitBareExpr(String(obj.expression ?? ''), imp, inputNames);
573
- }
574
- const raw = typeof v === 'string' ? v : String(v ?? '');
575
- return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames) : tsLiteral(raw);
576
- };
577
- const fieldObject = (rows) => {
578
- const list = Array.isArray(rows) ? rows : [];
579
- return `{ ${list.map((r) => `${key(String(r.field ?? ''))}: ${val(r.value)}`).join(', ')} }`;
580
- };
581
- const record = cfg.recordSource === 'fromRead'
582
- ? `{ fromRead: ${tsText(cfg.readEntityNodeId)} }`
583
- : `{ byId: ${val(cfg.recordId)} }`;
584
- if (node.type === T.dataFabricRead) {
585
- // The array is what the platform serializer reads and what compile
586
- // writes; the grouped object is the newer authoring shape, tolerated
587
- // here so a canvas-authored file still decompiles. Both flatten to the
588
- // builder's row list, where `or: true` marks each new OR alternative.
589
- const filterRow = (r, or = false) => opts([
590
- ['field', tsText(r.field)],
591
- ['operator', r.operator !== undefined && r.operator !== '=' ? tsLiteral(String(r.operator)) : undefined],
592
- ['value', val(r.value)],
593
- ['or', or ? 'true' : undefined],
594
- ]);
595
- const q = cfg._filters;
596
- let rows = [];
597
- if (Array.isArray(q)) {
598
- rows = q.map((r, i) => filterRow(r, i > 0 && r['join'] === 'OR'));
599
- }
600
- else if (q && typeof q === 'object') {
601
- // Grouped: each root row and each group is one alternative, so every
602
- // one but the first opens with `or: true`.
603
- const alts = [
604
- ...(Array.isArray(q.rows) ? q.rows.map((r) => [r]) : []),
605
- ...(Array.isArray(q.groups) ? q.groups : [])
606
- .map((g) => (Array.isArray(g.rows) ? g.rows : [])),
607
- ].filter((a) => a.length);
608
- rows = alts.flatMap((alt, ai) => alt.map((r, ri) => filterRow(r, ai > 0 && ri === 0)));
609
- }
610
- const filters = rows.length ? `[${rows.join(', ')}]` : undefined;
611
- // `resultMode` only exists from 1.4, and recovering it re-selects 1.4 on
612
- // the way back out — so a 1.0 node stays a 1.0 node through the round trip.
613
- const mode = cfg.resultMode === 'single' || cfg.resultMode === 'multiple'
614
- ? tsLiteral(cfg.resultMode) : undefined;
615
- const sort = cfg._sort && typeof cfg._sort === 'object'
616
- ? opts([
617
- ['field', tsText(cfg._sort.field)],
618
- ['direction', cfg._sort.direction === 'desc' ? tsLiteral('desc') : undefined],
619
- ])
620
- : undefined;
621
- const fields = Array.isArray(cfg._selectedFieldNames) && cfg._selectedFieldNames.length
622
- ? `[${cfg._selectedFieldNames.map((f) => tsLiteral(String(f))).join(', ')}]`
623
- : undefined;
624
- return `${imp.use('dataFabricRead')}(${opts([
625
- ['entity', entity], ['filters', filters], ['resultMode', mode],
626
- ['limit', typeof cfg._recordLimit === 'number' ? String(cfg._recordLimit) : undefined],
627
- ['skip', typeof cfg._skip === 'number' ? String(cfg._skip) : undefined],
628
- ['sort', sort], ['fields', fields],
629
- ['folderKey', folder], ['resourceKey', resourceKey],
630
- ])})`;
631
- }
632
- if (node.type === T.dataFabricCreate) {
633
- return `${imp.use('dataFabricCreate')}(${opts([
634
- ['entity', entity], ['values', fieldObject(cfg.fieldValues)], ['folderKey', folder], ['resourceKey', resourceKey],
635
- ])})`;
636
- }
637
- if (node.type === T.dataFabricDelete) {
638
- return `${imp.use('dataFabricDelete')}(${opts([
639
- ['entity', entity], ['record', record], ['folderKey', folder], ['resourceKey', resourceKey],
640
- ])})`;
641
- }
642
- return `${imp.use('dataFabricUpdate')}(${opts([
643
- ['entity', entity], ['record', record], ['set', fieldObject(cfg.fieldUpdates)],
644
- ['folderKey', folder], ['resourceKey', resourceKey],
645
- ])})`;
646
- }
647
575
  case T.createOutgoingCall:
648
576
  case T.endCall: {
649
577
  const i = (node.inputs ?? {});
@@ -766,8 +694,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
766
694
  case T.httpV2:
767
695
  return emitHttp(node, true, imp, inputNames);
768
696
  default:
769
- if (node.type.startsWith('core.action.transform'))
770
- return emitTransform(node, imp, inputNames);
771
697
  // A connector action node: `uipath.connector.<key>.<action>` (but NOT the
772
698
  // event nodes `uipath.connector.event.*` / `.trigger.*`, which are triggers).
773
699
  if (node.type.startsWith('uipath.connector.') && !node.type.startsWith('uipath.connector.event.') && !node.type.startsWith('uipath.connector.trigger.')) {
@@ -823,49 +749,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
823
749
  return unsupportedSpec(node, imp, o);
824
750
  }
825
751
  }
826
- /**
827
- * The `returns` argument for a script step, or nothing.
828
- *
829
- * Recovers what the author declared by DIFFERENCE: the node says what its output
830
- * is, `inferScriptShape` says what re-compiling the body would declare on its
831
- * own, and only a gap between the two needs writing down. Fields are recovered
832
- * the same way — a property map the body does not produce is one the author gave
833
- * as `returns: {…}`.
834
- */
835
- function scriptReturnsOpt(node, code) {
836
- const out = node.outputs?.output;
837
- const declared = typeof out?.type === 'string' ? out.type : undefined;
838
- if (!declared)
839
- return [];
840
- const props = out?.properties;
841
- // What re-compiling this body with NO `returns` would declare. Mirror
842
- // `scriptOutputs` exactly: an inference of a bare `object` (or none at all)
843
- // leaves the definition's own `{type:'object'}` standing, untouched.
844
- const inferred = inferScriptShape(code);
845
- const effective = inferred && !(inferred.type === 'object' && !inferred.properties)
846
- ? inferred
847
- : { type: 'object', properties: undefined };
848
- const same = effective.type === declared
849
- && JSON.stringify(sortKeys(effective.properties ?? {})) === JSON.stringify(sortKeys(props ?? {}));
850
- if (same)
851
- return [];
852
- // Not what the body alone would say — so the author declared it, and it has to
853
- // be written back or the round-trip loses it. That includes declaring the OPEN
854
- // object over a body that looks typed, which is a real thing to want.
855
- if (props && Object.keys(props).length > 0) {
856
- // A field map is the richer statement, so it wins when there is one.
857
- const entries = Object.entries(props)
858
- .filter(([, v]) => typeof v?.type === 'string')
859
- .map(([k, v]) => [k, tsLiteral(v.type)]);
860
- if (entries.length > 0)
861
- return [['returns', opts(entries)]];
862
- }
863
- return [['returns', tsLiteral(declared)]];
864
- }
865
- /** Key-sorted copy, so a property map compares by content and not by order. */
866
- function sortKeys(o) {
867
- return Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b)));
868
- }
869
752
  /**
870
753
  * Invert an HTTP node. The plain node (`core.action.http`) keeps its request at
871
754
  * the top level (`url` / `method` / `headers` / `queryParams` / `body` /
@@ -926,68 +809,6 @@ function emitHttp(node, managed, imp, inputNames) {
926
809
  ]);
927
810
  return `${imp.use('http')}(${spec})`;
928
811
  }
929
- /**
930
- * Invert a Transform node (generic `core.action.transform` or a `.map` / `.filter`
931
- * / `.group-by` variant). The `collection` is a bare `$vars.…` path; each
932
- * operation's serialized `{id,type,config}` becomes a builder operation object.
933
- * (The variant node types carry a `groupBy` operation spelled with a hyphen in
934
- * the type — `group-by` — but `groupBy` in the operation, the platform's own
935
- * mismatch, mirrored here.)
936
- */
937
- function emitTransform(node, imp, inputNames) {
938
- const inputs = node.inputs ?? {};
939
- const suffix = node.type.slice('core.action.transform'.length).replace(/^\./, '');
940
- const variant = suffix || undefined; // 'map' | 'filter' | 'group-by' | undefined
941
- const collRaw = unwrapSource(inputs.collection);
942
- const collection = collRaw !== undefined
943
- ? emitBareExpr(collRaw.startsWith('=js:') ? collRaw.slice(4) : collRaw, imp, inputNames)
944
- : `${imp.use('lit')}([])`;
945
- const ops = Array.isArray(inputs.operations) ? inputs.operations : [];
946
- const opSrcs = ops.map((op) => {
947
- const cfg = op?.config ?? {};
948
- if (op?.type === 'filter') {
949
- const filters = (cfg.filters ?? []).map((f) => objLit([
950
- ['field', tsLiteral(f.field)],
951
- ['condition', tsLiteral(f.condition)],
952
- ...(f.value !== undefined ? [['value', tsLiteral(f.value)]] : []),
953
- ]));
954
- return objLit([
955
- ['type', tsLiteral('filter')],
956
- ...(cfg.operation !== undefined ? [['operation', tsLiteral(cfg.operation)]] : []),
957
- ['filters', `[${filters.join(', ')}]`],
958
- ]);
959
- }
960
- if (op?.type === 'map') {
961
- const mappings = (cfg.mappings ?? []).map((m) => objLit([
962
- ['field', tsLiteral(m.field)],
963
- ...(m.transformation && m.transformation !== 'copy' ? [['transformation', tsLiteral(m.transformation)]] : []),
964
- ...(m.renameTo ? [['renameTo', tsLiteral(m.renameTo)]] : []),
965
- ]));
966
- return objLit([
967
- ['type', tsLiteral('map')],
968
- ...(cfg.keepOriginalFields ? [['keepOriginalFields', boolLit(cfg.keepOriginalFields)]] : []),
969
- ['mappings', `[${mappings.join(', ')}]`],
970
- ]);
971
- }
972
- // groupBy
973
- const aggs = (cfg.aggregations ?? []).map((a) => objLit([
974
- ['operation', tsLiteral(a.operation)],
975
- ['alias', tsLiteral(a.alias)],
976
- ...(a.field ? [['field', tsLiteral(a.field)]] : []),
977
- ]));
978
- return objLit([
979
- ['type', tsLiteral('groupBy')],
980
- ['groupByField', tsLiteral(cfg.groupByField)],
981
- ['aggregations', `[${aggs.join(', ')}]`],
982
- ]);
983
- });
984
- const spec = opts([
985
- ['collection', collection],
986
- ['variant', variant ? tsLiteral(variant) : undefined],
987
- ['operations', `[${opSrcs.join(', ')}]`],
988
- ]);
989
- return `${imp.use('transform')}(${spec})`;
990
- }
991
812
  /**
992
813
  * Split a connector `nodeType` (`uipath.connector.<key>.<action>`) into key +
993
814
  * action. Mirrors `core/connectors.ts`'s `splitConnectorNodeType`.
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The bundled definitions, keyed `<nodeType>@<version>`. Deep-frozen: every reader
3
+ * shares this one copy, so a write meant for one node must clone first, and one
4
+ * that does not throws at its own site instead of leaking into another reader.
5
+ */
6
+ export declare const BUNDLED_DEFINITIONS: Readonly<Record<string, any>>;
7
+ /** Whether the SDK bundles `<typeName>@<version>`. */
8
+ export declare function hasBundledDefinition(typeName: string, version: string): boolean;
9
+ /** The versions of `typeName` the SDK bundles, in bundle order. */
10
+ export declare function bundledVersions(typeName: string): string[];
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The node definitions this SDK bundles for Flow (`core-definitions.json`, keyed
3
+ * `<nodeType>@<version>`): the one parse of the bundle, shared by `serialize`,
4
+ * `decompile` and the node-type registry's validation.
5
+ *
6
+ * Kept apart from `serialize.ts` so the registry can depend on the bundle without
7
+ * importing the serializer that depends on the registry.
8
+ */
9
+ import { readFileSync } from 'node:fs';
10
+ import { dirname, join } from 'node:path';
11
+ import { fileURLToPath } from 'node:url';
12
+ /**
13
+ * The bundled definitions, keyed `<nodeType>@<version>`. Deep-frozen: every reader
14
+ * shares this one copy, so a write meant for one node must clone first, and one
15
+ * that does not throws at its own site instead of leaking into another reader.
16
+ */
17
+ export const BUNDLED_DEFINITIONS = deepFreeze(JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'core-definitions.json'), 'utf8')));
18
+ function deepFreeze(value) {
19
+ if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
20
+ Object.freeze(value);
21
+ for (const child of Object.values(value))
22
+ deepFreeze(child);
23
+ }
24
+ return value;
25
+ }
26
+ const BUNDLED_KEYS = new Set(Object.keys(BUNDLED_DEFINITIONS));
27
+ /** Whether the SDK bundles `<typeName>@<version>`. */
28
+ export function hasBundledDefinition(typeName, version) {
29
+ return BUNDLED_KEYS.has(`${typeName}@${version}`);
30
+ }
31
+ /** The versions of `typeName` the SDK bundles, in bundle order. */
32
+ export function bundledVersions(typeName) {
33
+ const prefix = `${typeName}@`;
34
+ return [...BUNDLED_KEYS].filter((k) => k.startsWith(prefix)).map((k) => k.slice(prefix.length));
35
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Flow's node-type registry: every Flow node family, listed explicitly
3
+ * (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §4.5).
4
+ *
5
+ * While a kind is not listed here, `serialize`, `check` and `decompile` handle it
6
+ * with their existing branches — the FB014 pins in `tests/lint/pins.txt` are what
7
+ * is left to port.
8
+ */
9
+ import { NodeTypeRegistry } from './core/nodes/registry.js';
10
+ import type { FlowContexts, FlowNodeFamily } from './flow-node-type.js';
11
+ /** The families, in no significant order. Adding one is the whole of registering it. */
12
+ export declare const FLOW_NODE_FAMILIES: readonly FlowNodeFamily[];
13
+ export declare const FLOW_NODE_TYPES: NodeTypeRegistry<FlowContexts>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Flow's node-type registry: every Flow node family, listed explicitly
3
+ * (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §4.5).
4
+ *
5
+ * While a kind is not listed here, `serialize`, `check` and `decompile` handle it
6
+ * with their existing branches — the FB014 pins in `tests/lint/pins.txt` are what
7
+ * is left to port.
8
+ */
9
+ import { NodeTypeRegistry } from './core/nodes/registry.js';
10
+ import { hasBundledDefinition } from './flow-definitions.js';
11
+ import { dataFabricFlowFamily } from './nodes/data-fabric/flow/family.js';
12
+ import { delayFlowFamily } from './nodes/delay/flow/family.js';
13
+ import { documentFlowFamily } from './nodes/document/flow/family.js';
14
+ import { mockFlowFamily } from './nodes/mock/flow/family.js';
15
+ import { scriptFlowFamily } from './nodes/script/flow/family.js';
16
+ import { transformFlowFamily } from './nodes/transform/flow/family.js';
17
+ /** The families, in no significant order. Adding one is the whole of registering it. */
18
+ export const FLOW_NODE_FAMILIES = [dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, mockFlowFamily, scriptFlowFamily, transformFlowFamily];
19
+ export const FLOW_NODE_TYPES = new NodeTypeRegistry('flow', FLOW_NODE_FAMILIES, { hasBundledDefinition });