@uipath/maestro-builder-sdk 6.15.1 → 6.15.3

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/serialize.js CHANGED
@@ -16,7 +16,8 @@ import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
16
16
  import { dataFabricUnknownInputs } from './core/typed-raw-node.js';
17
17
  import { isAnswerField } from './core/hitl-answers.js';
18
18
  import { connectionConnectors } from './bindings-v2.js';
19
- import { BindingRefusal, GUID_RE, bindingSelfNameMessage, bindingUndeclaredMessage, undeclaredBinding } from './core/binding-messages.js';
19
+ import { globalNameCollisionMessage, globalNameCollisions } from './core/global-names.js';
20
+ import { BindingRefusal, GUID_RE, bindingMissingMessage, bindingSelfNameMessage, bindingUndeclaredMessage, missingBindingLabels, undeclaredBinding } from './core/binding-messages.js';
20
21
  import { ByoaRefusal, byoaUnverified } from './core/byoa.js';
21
22
  import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitModel, hitlExitViolation, outcomeSlug } from './core/hitl-routing.js';
22
23
  import { declaredExits, hasExits, stopsAtEnd } from './core/step-ports.js';
@@ -3284,7 +3285,7 @@ function clone(x) {
3284
3285
  function subNodeId(obj, nodeId) {
3285
3286
  return JSON.parse(JSON.stringify(obj).split('{nodeId}').join(nodeId));
3286
3287
  }
3287
- const NO_RENAME = { nodeIds: new Map(), runtimeOutputs: new Map(), errorEnvelopes: new Map() };
3288
+ const NO_RENAME = { nodeIds: new Map(), errorEnvelopes: new Map() };
3288
3289
  /**
3289
3290
  * Which runtime variable holds a failed node's envelope, by node type.
3290
3291
  *
@@ -3484,6 +3485,27 @@ function refuseUnverifiedByoa(opts, where, sub) {
3484
3485
  if (message)
3485
3486
  throw new ByoaRefusal(message);
3486
3487
  }
3488
+ /** Refuse a name declared twice across `.input()` / `.output()` / `.var()` — one `variables.globals[]` id each. */
3489
+ function refuseGlobalNameCollisions(inputs, outputs, vars) {
3490
+ const [first] = globalNameCollisions(inputs, outputs, vars);
3491
+ if (first)
3492
+ throw new Error(globalNameCollisionMessage(first));
3493
+ }
3494
+ /**
3495
+ * Refuse a connector-bound node (connector step, event trigger, `.entryPoint`
3496
+ * onEvent, `waitForEvent`) that names no `connection` or no `folder` label.
3497
+ * (An inline agent's connector tool is #875's: `check` refuses it as
3498
+ * INLINE_AGENT_TOOL_CONNECTOR_NO_CONNECTION, and serialize leaves it unbound.)
3499
+ * `resolveBinding` returns `undefined` for an absent label, which used to reach
3500
+ * the node as `detail.connectionId: null` with no binding — valid to compile,
3501
+ * refused by `flow validate` (flow-builder-sdk#890). `check` reports the same
3502
+ * sentence first (BINDING_MISSING).
3503
+ */
3504
+ function requireBindingPair(where, labels, target) {
3505
+ const missing = missingBindingLabels(labels);
3506
+ if (missing.length > 0)
3507
+ throw new BindingRefusal('BINDING_MISSING', bindingMissingMessage(where, missing, target));
3508
+ }
3487
3509
  /**
3488
3510
  * Resolve a symbolic connection/folder name to the resource key that is inlined
3489
3511
  * as `connectionId` / `connectionFolderKey`.
@@ -3709,7 +3731,8 @@ function flattenWhere(where, declared) {
3709
3731
  walk(where, '');
3710
3732
  return out;
3711
3733
  }
3712
- function eventDetail(rc, sub, nodeId, opts) {
3734
+ function eventDetail(rc, sub, nodeId, opts, site) {
3735
+ requireBindingPair(site, sub, eventTarget(sub));
3713
3736
  const conn = resolveBinding(opts, sub.connection, 'connection', `event node "${nodeId}"`, eventTarget(sub));
3714
3737
  const folder = resolveBinding(opts, sub.folder, 'folder', `event node "${nodeId}"`, eventTarget(sub));
3715
3738
  const op = (rc.entry?.operation ?? {});
@@ -3944,7 +3967,7 @@ function newScope(outputs, vars = []) {
3944
3967
  ...outputs.map((o) => [o.name, o.type]),
3945
3968
  ...vars.map((vd) => [vd.name, vd.type]),
3946
3969
  ]),
3947
- rename: { nodeIds: new Map(), runtimeOutputs: new Map(), errorEnvelopes: new Map() },
3970
+ rename: { nodeIds: new Map(), errorEnvelopes: new Map() },
3948
3971
  pending: new Map(),
3949
3972
  agentSchemas: [],
3950
3973
  stepNodeId: new Map(),
@@ -4190,22 +4213,18 @@ function terminateOutputs(scope) {
4190
4213
  * same name (an error in its own right — DUP_STEP).
4191
4214
  */
4192
4215
  function renameRefs(text, rename) {
4193
- if (rename.nodeIds.size === 0 && rename.runtimeOutputs.size === 0 && rename.errorEnvelopes.size === 0)
4216
+ if (rename.nodeIds.size === 0 && rename.errorEnvelopes.size === 0)
4194
4217
  return text;
4195
4218
  // `.error` matches only with a FIELD behind it: a bare `$vars.<step>.error` is
4196
4219
  // the boolean "did this fail" (`err('<step>')`), which is truthy on every
4197
4220
  // family — the envelope object included — and must be left alone.
4198
- return text.replace(/\$vars\.([A-Za-z0-9_]+)(\.output\b|\.error(?=\.[A-Za-z0-9_]))?/g, (m, name, tail) => {
4221
+ return text.replace(/\$vars\.([A-Za-z0-9_]+)(\.error(?=\.[A-Za-z0-9_]))?/g, (m, name, tail) => {
4199
4222
  const to = rename.nodeIds.get(name);
4200
4223
  const nodeId = to && to.length > 0 ? to[0] : name;
4201
4224
  if (!tail)
4202
4225
  return nodeId === name ? m : `$vars.${nodeId}`;
4203
- if (tail === '.error') {
4204
- const envelope = rename.errorEnvelopes.get(name) ?? 'error';
4205
- return `$vars.${nodeId}.${envelope}`;
4206
- }
4207
- const runtimeOutput = rename.runtimeOutputs.get(name) ?? 'output';
4208
- return `$vars.${nodeId}.${runtimeOutput}`;
4226
+ const envelope = rename.errorEnvelopes.get(name) ?? 'error';
4227
+ return `$vars.${nodeId}.${envelope}`;
4209
4228
  });
4210
4229
  }
4211
4230
  /** Every step name a flow declares in its own scope (not its children's). */
@@ -4424,6 +4443,7 @@ export function serialize(built, opts = {}) {
4424
4443
  for (const t of tails)
4425
4444
  addEdge(scope, t, endId);
4426
4445
  }
4446
+ refuseGlobalNameCollisions(child.inputs, child.outputs, child.vars);
4427
4447
  const globals = [];
4428
4448
  for (const inp of child.inputs)
4429
4449
  globals.push({ id: inp.name, name: inp.name, direction: 'in', type: inp.type, triggerNodeId: startId, ...varMeta(inp) });
@@ -4512,7 +4532,7 @@ export function serialize(built, opts = {}) {
4512
4532
  // `detail` (see eventDetail).
4513
4533
  entryPointId: stableId(`${built.id}:start:entryPoint`),
4514
4534
  isDefaultEntryPoint: true,
4515
- detail: eventDetail(eventTriggerRc, built.trigger.subscription, triggerId, opts),
4535
+ detail: eventDetail(eventTriggerRc, built.trigger.subscription, triggerId, opts, 'event trigger'),
4516
4536
  }
4517
4537
  : built.trigger?.kind === 'scheduled'
4518
4538
  ? scheduleInputs(built.trigger.inputs, triggerId)
@@ -4662,6 +4682,7 @@ export function serialize(built, opts = {}) {
4662
4682
  const id = stepUid(scope, step.name);
4663
4683
  const node = makeNode(rc.nodeType, id, step.name, { parentId, requestedVersion: step.options?.version, def: rc.v1def });
4664
4684
  declareListOutputType(node, rc);
4685
+ requireBindingPair(`connector "${step.name}"`, spec, { key: spec.key, action: spec.action });
4665
4686
  const conn = resolveBinding(opts, spec.connection, 'connection', `connector "${step.name}"`, { key: spec.key, action: spec.action });
4666
4687
  const folder = resolveBinding(opts, spec.folder, 'folder', `connector "${step.name}"`, { key: spec.key, action: spec.action });
4667
4688
  // The platform reaches the connection through the flow's `bindings[]`,
@@ -5310,12 +5331,12 @@ export function serialize(built, opts = {}) {
5310
5331
  resourceBindings.set(b.id, b);
5311
5332
  const def = queueItemDef(s, step.name, ids);
5312
5333
  const id = stepUid(scope, step.name);
5313
- // Queue manifests describe the logical result as `output`, which is what
5314
- // out('step', path) type-checks against. The product's BPMN serializer,
5315
- // however, publishes both queue variants under `$vars.<step>.response`.
5316
- // Record that boundary alias once so every SDK expression renderer uses
5317
- // the runtime path while the public output contract stays unchanged.
5318
- scope.rename.runtimeOutputs.set(step.name, 'response');
5334
+ // The result is read as `$vars.<step>.output`, like every other family: the
5335
+ // node's own output block maps the runtime `response` onto the variable
5336
+ // `output` (`source: "=response", var: "output"`), and the product honours
5337
+ // that mapping for both queue variants. (An alias to `.response` lived here
5338
+ // from #273 until #891; a live debug run on 2026-10-01 measured
5339
+ // `.output.Key` populated and `.response` undefined.)
5319
5340
  const node = makeNode(def.nodeType, id, step.name, { parentId, requestedVersion: step.options?.version, def });
5320
5341
  // The node KEEPS its copy of the model here, unlike the rpa families. Two
5321
5342
  // reasons: it is what the one queue instance the repo has carries, and it is
@@ -5618,7 +5639,7 @@ export function serialize(built, opts = {}) {
5618
5639
  refuseUnverifiedByoa(opts, `waitForEvent "${step.name}"`, sub);
5619
5640
  const id = stepUid(scope, step.name);
5620
5641
  const node = makeNode(rc.nodeType, id, step.name, { parentId, requestedVersion: step.options?.version, def: rc.v1def });
5621
- node.inputs = { detail: eventDetail(rc, sub, id, opts) };
5642
+ node.inputs = { detail: eventDetail(rc, sub, id, opts, `waitForEvent "${step.name}"`) };
5622
5643
  // Same connection-binding closure as the connector branch (G-19).
5623
5644
  const { entries: waitConnBindings } = connectionResourceBindings({
5624
5645
  def: rc.v1def,
@@ -5856,7 +5877,7 @@ export function serialize(built, opts = {}) {
5856
5877
  // Record the failure-envelope boundary BEFORE any expression is rendered, so
5857
5878
  // a handler that reads this step resolves against the right variable. The
5858
5879
  // handler is emitted after the step it guards, so recording it here is early
5859
- // enough — the same ordering the queue family's `runtimeOutputs` alias relies on.
5880
+ // enough.
5860
5881
  const envelope = errorEnvelopeVar(type);
5861
5882
  if (envelope)
5862
5883
  scope.rename.errorEnvelopes.set(step.name, envelope);
@@ -6475,7 +6496,7 @@ export function serialize(built, opts = {}) {
6475
6496
  node = makeNode(rc.nodeType, ep.id, 'Event trigger', { def: rc.v1def, requestedVersion });
6476
6497
  node.inputs = {
6477
6498
  entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`),
6478
- detail: eventDetail(rc, sub, ep.id, opts),
6499
+ detail: eventDetail(rc, sub, ep.id, opts, `onEvent() entry point "${ep.id}"`),
6479
6500
  };
6480
6501
  const { entries } = connectionResourceBindings({
6481
6502
  def: rc.v1def,
@@ -6510,6 +6531,9 @@ export function serialize(built, opts = {}) {
6510
6531
  }
6511
6532
  }
6512
6533
  }
6534
+ // Entry-point inputs are rows of the same globals[] (pushed below), so they
6535
+ // share the namespace; `check` reports these as ENTRY_POINT_INPUT_COLLISION.
6536
+ refuseGlobalNameCollisions([...built.inputs, ...entryPoints.flatMap((ep) => ep.inputs)], built.outputs, built.vars);
6513
6537
  const globals = [];
6514
6538
  const triggerNodeId = built.triggerId ?? 'start';
6515
6539
  for (const inp of built.inputs)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.15.1",
3
+ "version": "6.15.3",
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": "a3707b159a49ed3b6611c55bed66622cb6dd1972"
95
+ "gitref": "a85d11af254f270d645ec46d57994ccb800ebc1f"
96
96
  }