@uipath/maestro-builder-sdk 6.29.0 → 6.29.1

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.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The source handles a node's definition declares, read against the node's own
3
+ * inputs — one reader for every layer that has to know which ports a node can
4
+ * leave on (`merge-roundtrip.ts`'s handle checks, `decompile`'s arm recovery for
5
+ * a node with no typed factory, and `.stepSwitch` over a `rawNode`).
6
+ *
7
+ * A definition lists its handles in `handleConfiguration[].handles[]`. A static
8
+ * handle is its `id`; a REPEATED one is a template expanded once per item of an
9
+ * input array:
10
+ *
11
+ * ```
12
+ * { id: 'case-{item.id}', type: 'source', repeat: 'inputs.criteria' }
13
+ * inputs.criteria = [{ id: 'returns' }, { id: 'billing' }]
14
+ * → case-returns, case-billing
15
+ * ```
16
+ *
17
+ * This is how `core.logic.agentic-switch` (one exit per choice, plus `default`)
18
+ * and `core.logic.switch` (one per case) declare their exits.
19
+ */
20
+ type Def = {
21
+ readonly [k: string]: unknown;
22
+ } | undefined;
23
+ /**
24
+ * Every source handle `def` declares for a node with `inputs`, in declaration
25
+ * order, templates expanded. `undefined` when `def` has no
26
+ * `handleConfiguration`, or has a template this cannot expand (a `repeat` that
27
+ * is not an `inputs.` path), so a caller can tell "no handles" from "cannot
28
+ * know".
29
+ */
30
+ export declare function expandSourceHandles(def: Def, inputs: unknown): string[] | undefined;
31
+ /**
32
+ * The FORWARD exits a node's definition declares when it has more than one —
33
+ * every source handle except `error` and an agent's artifact handles, templates
34
+ * expanded. `undefined` for a definition with one forward exit or fewer, or one
35
+ * whose handles cannot be known: such a node has no fan-out to route.
36
+ */
37
+ export declare function forwardFanOut(def: Def, inputs: unknown): string[] | undefined;
38
+ export {};
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The source handles a node's definition declares, read against the node's own
3
+ * inputs — one reader for every layer that has to know which ports a node can
4
+ * leave on (`merge-roundtrip.ts`'s handle checks, `decompile`'s arm recovery for
5
+ * a node with no typed factory, and `.stepSwitch` over a `rawNode`).
6
+ *
7
+ * A definition lists its handles in `handleConfiguration[].handles[]`. A static
8
+ * handle is its `id`; a REPEATED one is a template expanded once per item of an
9
+ * input array:
10
+ *
11
+ * ```
12
+ * { id: 'case-{item.id}', type: 'source', repeat: 'inputs.criteria' }
13
+ * inputs.criteria = [{ id: 'returns' }, { id: 'billing' }]
14
+ * → case-returns, case-billing
15
+ * ```
16
+ *
17
+ * This is how `core.logic.agentic-switch` (one exit per choice, plus `default`)
18
+ * and `core.logic.switch` (one per case) declare their exits.
19
+ */
20
+ /**
21
+ * Every source handle `def` declares for a node with `inputs`, in declaration
22
+ * order, templates expanded. `undefined` when `def` has no
23
+ * `handleConfiguration`, or has a template this cannot expand (a `repeat` that
24
+ * is not an `inputs.` path), so a caller can tell "no handles" from "cannot
25
+ * know".
26
+ */
27
+ export function expandSourceHandles(def, inputs) {
28
+ const groups = def?.handleConfiguration;
29
+ if (!Array.isArray(groups))
30
+ return undefined;
31
+ const out = [];
32
+ for (const g of groups) {
33
+ for (const h of (g?.handles ?? [])) {
34
+ if (h?.type !== 'source' || typeof h.id !== 'string')
35
+ continue;
36
+ const template = /\{item\.([A-Za-z0-9_]+)\}/.exec(h.id);
37
+ if (!template) {
38
+ if (!out.includes(h.id))
39
+ out.push(h.id);
40
+ continue;
41
+ }
42
+ if (typeof h.repeat !== 'string' || !h.repeat.startsWith('inputs.'))
43
+ return undefined;
44
+ let items = inputs;
45
+ for (const seg of h.repeat.slice('inputs.'.length).split('.'))
46
+ items = items?.[seg];
47
+ for (const item of Array.isArray(items) ? items : []) {
48
+ const v = item?.[template[1]];
49
+ if (typeof v !== 'string' && typeof v !== 'number')
50
+ continue;
51
+ const id = h.id.replace(template[0], String(v));
52
+ if (!out.includes(id))
53
+ out.push(id);
54
+ }
55
+ }
56
+ }
57
+ return out;
58
+ }
59
+ /**
60
+ * Source handles that are not exits: `error` (routed by `.onError()`) and an
61
+ * agent's artifact handles, which attach its tools, context, escalations and
62
+ * memory rather than continue the flow.
63
+ */
64
+ const NOT_FORWARD = new Set(['error', 'tool', 'context', 'escalation', 'memory']);
65
+ /**
66
+ * The FORWARD exits a node's definition declares when it has more than one —
67
+ * every source handle except `error` and an agent's artifact handles, templates
68
+ * expanded. `undefined` for a definition with one forward exit or fewer, or one
69
+ * whose handles cannot be known: such a node has no fan-out to route.
70
+ */
71
+ export function forwardFanOut(def, inputs) {
72
+ const handles = expandSourceHandles(def, inputs)?.filter((h) => !NOT_FORWARD.has(h));
73
+ return handles !== undefined && handles.length > 1 ? handles : undefined;
74
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The exits `.stepSwitch` routes over when its step is a `rawNode`: the
3
+ * manifest's forward source handles, `repeat` ones expanded over the node's
4
+ * inputs, each arm's `value` being its port. A `core.logic.agentic-switch`
5
+ * with choices `returns` and `billing` has `case-returns`, `case-billing` and
6
+ * `default`:
7
+ *
8
+ * ```ts
9
+ * .stepSwitch('route', rawNode({ nodeType: 'core.logic.agentic-switch', … }), [
10
+ * { value: 'case-returns', body: (b) => b.step('returns', …) },
11
+ * { value: 'case-billing', body: (b) => b.step('billing', …) },
12
+ * { value: 'default', body: (b) => b.step('triage', …) },
13
+ * ])
14
+ * ```
15
+ *
16
+ * Internal, not package API: `raw-node.ts` (whose module the package
17
+ * re-exports) puts the answer on its node under this symbol, and
18
+ * `flow-step-exits.ts` reads it. `decompile` reads the same handles off the
19
+ * file's definition, so what it emits recompiles (#1141).
20
+ */
21
+ import type { DeclaredExit } from './step-ports.js';
22
+ /** The method a raw node answers its exits under. */
23
+ export declare const RAW_NODE_EXITS: unique symbol;
24
+ /**
25
+ * `action`'s exits when it is a raw node whose manifest declares more than one
26
+ * forward exit; `undefined` otherwise (then it has nothing to route).
27
+ */
28
+ export declare function rawNodeExits(action: unknown): DeclaredExit[] | undefined;
@@ -0,0 +1,10 @@
1
+ /** The method a raw node answers its exits under. */
2
+ export const RAW_NODE_EXITS = Symbol('rawNodeExits');
3
+ /**
4
+ * `action`'s exits when it is a raw node whose manifest declares more than one
5
+ * forward exit; `undefined` otherwise (then it has nothing to route).
6
+ */
7
+ export function rawNodeExits(action) {
8
+ const own = action?.[RAW_NODE_EXITS];
9
+ return typeof own === 'function' ? own.call(action) : undefined;
10
+ }
package/dist/decompile.js CHANGED
@@ -46,6 +46,7 @@ import { mapJsCode } from './core/js-code-spans.js';
46
46
  import { missingBindingLabels } from './core/binding-messages.js';
47
47
  import { prepareCommand } from './core/cli-spelling.js';
48
48
  import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
49
+ import { forwardFanOut } from './core/definition-handles.js';
49
50
  import { STICKY_NOTE_TYPE } from './core/definitionless-node-types.js';
50
51
  import { eventFilterFromTreeLeaf } from './core/event-filters.js';
51
52
  import { sdkFormFieldType } from './core/form-field-type.js';
@@ -2534,7 +2535,9 @@ function declaredExitsOfNode(node) {
2534
2535
  // A registered type that declares exits answers from its own spec, lifted off
2535
2536
  // this node; one that declares none is not lifted at all (this runs per edge).
2536
2537
  const impl = registeredImpl(node);
2537
- if (!impl?.exits)
2538
+ if (!impl)
2539
+ return rawNodeExits(node);
2540
+ if (!impl.exits)
2538
2541
  return undefined;
2539
2542
  const lifted = liftRegistered(node, impl);
2540
2543
  const exits = lifted && impl.exits(lifted.spec);
@@ -2542,6 +2545,34 @@ function declaredExitsOfNode(node) {
2542
2545
  return undefined;
2543
2546
  return exits.map((e) => ({ value: e.value, port: e.port }));
2544
2547
  }
2548
+ /**
2549
+ * The exits of a node that decompiles to a `rawNode` (a type this SDK has no
2550
+ * factory for, carried with the file's own definition): that definition's
2551
+ * forward source handles, `repeat` ones expanded over the node's inputs, when it
2552
+ * has more than one. `core.logic.agentic-switch` declares `case-{item.id}` over
2553
+ * `inputs.criteria` plus `default`, so a node with choices `returns` and
2554
+ * `billing` has the exits `case-returns`, `case-billing`, `default`. Each exit's
2555
+ * value is its port, which is what `.stepSwitch` over a `rawNode` matches
2556
+ * (`rawNodeExits` in raw-node.ts reads the same handles off the manifest).
2557
+ *
2558
+ * Without this, a fully wired multi-exit raw node had ONE exit to the walker:
2559
+ * it emitted `.step(...)` with a TODO and dropped every arm (#1141).
2560
+ *
2561
+ * `undefined` for every node the decompiler names some other way (the walker's
2562
+ * structural types, triggers, connectors, agents, published resources, IxP):
2563
+ * their exits are not a raw node's, and an agent's artifact handles (`tool`,
2564
+ * `context`, …) are not exits at all.
2565
+ */
2566
+ function rawNodeExits(node) {
2567
+ const type = String(node.type);
2568
+ if (Object.values(T).includes(type) || isTrigger(type))
2569
+ return undefined;
2570
+ if (['uipath.connector.', 'uipath.core.', 'uipath.ixp.', 'uipath.agent.', 'uipath.conversational.']
2571
+ .some((p) => type.startsWith(p)))
2572
+ return undefined;
2573
+ const def = runDefs.get(`${type}@${node.typeVersion}`) ?? runDefs.get(type);
2574
+ return forwardFanOut(def, node.inputs)?.map((port) => ({ value: port, port }));
2575
+ }
2545
2576
  /**
2546
2577
  * Split a switch case expression into `<discriminant> === <literal>`, the only
2547
2578
  * form `.switch(on, [{ value }])` models. Returns `undefined` for any other
@@ -8,6 +8,7 @@
8
8
  import { resolveVersion } from './core/nodes/versioned.js';
9
9
  import { declaredExits } from './core/step-ports.js';
10
10
  import { FLOW_NODE_TYPES } from './flow-node-registry.js';
11
+ import { rawNodeExits } from './core/raw-node-exits.js';
11
12
  /**
12
13
  * The author-declared exits of a step's spec: a registered type's own `exits`,
13
14
  * at the version the step resolves to (its pin, else the type's choice; an
@@ -16,6 +17,10 @@ import { FLOW_NODE_TYPES } from './flow-node-registry.js';
16
17
  * here, so they agree on what a port means.
17
18
  */
18
19
  export function stepExits(spec, pinnedVersion) {
20
+ // A `rawNode` declares its exits through the manifest it carries (#1141).
21
+ const raw = rawNodeExits(spec);
22
+ if (raw !== undefined)
23
+ return raw;
19
24
  const entry = typeof spec?.kind === 'string' ? FLOW_NODE_TYPES.byKind(spec.kind, spec) : undefined;
20
25
  if (!entry)
21
26
  return declaredExits(spec, pinnedVersion);
@@ -50,6 +50,7 @@
50
50
  * merged file still has it.
51
51
  */
52
52
  import { bindingIdentity } from './core/binding-identity.js';
53
+ import { expandSourceHandles } from './core/definition-handles.js';
53
54
  import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
54
55
  /** A file's definitions, keyed `nodeType@version`. */
55
56
  function defsOf(f) {
@@ -279,32 +280,8 @@ export function roundTripFindings(original, baseline, merged) {
279
280
  }
280
281
  /** The source handles a node's definition declares, or `undefined` when they cannot be known. */
281
282
  function declaredSourceHandles(node, def) {
282
- const groups = def?.handleConfiguration;
283
- if (!Array.isArray(groups))
284
- return undefined;
285
- const out = new Set();
286
- for (const g of groups) {
287
- for (const h of (g?.handles ?? [])) {
288
- if (h?.type !== 'source' || typeof h.id !== 'string')
289
- continue;
290
- const template = /\{item\.([A-Za-z0-9_]+)\}/.exec(h.id);
291
- if (!template) {
292
- out.add(h.id);
293
- continue;
294
- }
295
- if (typeof h.repeat !== 'string' || !h.repeat.startsWith('inputs.'))
296
- return undefined; // a template this check cannot expand
297
- let items = node.inputs;
298
- for (const seg of h.repeat.slice('inputs.'.length).split('.'))
299
- items = items?.[seg];
300
- for (const item of Array.isArray(items) ? items : []) {
301
- const v = item?.[template[1]];
302
- if (typeof v === 'string' || typeof v === 'number')
303
- out.add(h.id.replace(template[0], String(v)));
304
- }
305
- }
306
- }
307
- return out;
283
+ const handles = expandSourceHandles(def, node.inputs);
284
+ return handles === undefined ? undefined : new Set(handles);
308
285
  }
309
286
  /**
310
287
  * The handles a node derives from its own inputs, in order: a definition's
package/dist/raw-node.js CHANGED
@@ -8,6 +8,8 @@
8
8
  import { FlowAction, } from './core/node-classes.js';
9
9
  import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
10
10
  import { rawNodeInputProblem, rawNodeTypedFamilyWarning } from './raw-node-advice.js';
11
+ import { forwardFanOut } from './core/definition-handles.js';
12
+ import { RAW_NODE_EXITS } from './core/raw-node-exits.js';
11
13
  /**
12
14
  * Place a node this SDK has no factory for, carrying its definition verbatim
13
15
  * (`uipath.exotic.thing@2.1` and the manifest the platform served for it).
@@ -88,6 +90,11 @@ class RawNode extends FlowAction {
88
90
  out.push({ code: 'RAW_NODE_TYPED_FAMILY', severity: 'warning', message: typed });
89
91
  return out;
90
92
  }
93
+ /** Its exits, for `.stepSwitch` (core/raw-node-exits.ts). */
94
+ [RAW_NODE_EXITS]() {
95
+ const manifest = this.spec.manifest;
96
+ return forwardFanOut(manifest, this.spec.inputs ?? {})?.map((port) => ({ value: port, port }));
97
+ }
91
98
  contribute(context) {
92
99
  // compile does not run diagnostics(); refuse here too so the escape hatch
93
100
  // cannot emit an unconfigured connector node. (An input a registered node
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.29.0",
3
+ "version": "6.29.1",
4
4
  "description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.uipath.com/maestro",
@@ -92,5 +92,5 @@
92
92
  "@types/node": "^22.7.0",
93
93
  "esbuild": "^0.28.1"
94
94
  },
95
- "gitref": "af71b0c21f732f056d19e802af1c987fd8528336"
95
+ "gitref": "5dee9e0ebdef1bca6c586f4802285a0f429ae432"
96
96
  }