@uipath/maestro-builder-sdk 6.20.5 → 6.21.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 (36) hide show
  1. package/dist/api-index.md +72 -72
  2. package/dist/api-members.md +143 -143
  3. package/dist/check.js +34 -160
  4. package/dist/core/actions.d.ts +0 -126
  5. package/dist/core/actions.js +0 -48
  6. package/dist/core/edit-distance.d.ts +8 -0
  7. package/dist/core/edit-distance.js +26 -0
  8. package/dist/core/js-code-spans.d.ts +24 -0
  9. package/dist/core/js-code-spans.js +148 -0
  10. package/dist/core/nodes/node-type.d.ts +17 -2
  11. package/dist/core/typed-raw-node.js +0 -2
  12. package/dist/decompile.js +107 -36
  13. package/dist/flow-node-registry.js +2 -1
  14. package/dist/flow-node-type.d.ts +6 -0
  15. package/dist/flow-output-backing.d.ts +53 -0
  16. package/dist/flow-output-backing.js +200 -0
  17. package/dist/flow-sdk.d.ts +16 -0
  18. package/dist/flow-sdk.js +11 -0
  19. package/dist/flow-variables.d.ts +6 -4
  20. package/dist/flow-variables.js +6 -4
  21. package/dist/nodes/queue/flow/check.d.ts +35 -0
  22. package/dist/nodes/queue/flow/check.js +126 -0
  23. package/dist/nodes/queue/flow/factories.d.ts +49 -0
  24. package/dist/nodes/queue/flow/factories.js +50 -0
  25. package/dist/nodes/queue/flow/family.d.ts +3 -0
  26. package/dist/nodes/queue/flow/family.js +8 -0
  27. package/dist/nodes/queue/flow/index.d.ts +3 -0
  28. package/dist/nodes/queue/flow/index.js +3 -0
  29. package/dist/nodes/queue/flow/node-type.d.ts +8 -0
  30. package/dist/nodes/queue/flow/node-type.js +265 -0
  31. package/dist/nodes/queue/flow/spec.d.ts +92 -0
  32. package/dist/nodes/queue/flow/spec.js +1 -0
  33. package/dist/serialize.js +70 -183
  34. package/package.json +2 -2
  35. /package/dist/{core/queue-record.d.ts → nodes/queue/flow/record.d.ts} +0 -0
  36. /package/dist/{core/queue-record.js → nodes/queue/flow/record.js} +0 -0
package/dist/serialize.js CHANGED
@@ -55,8 +55,9 @@ import { migrateToSchemaVersion } from './migrate.js';
55
55
  import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
56
56
  import { resolveSchemaVersion } from './schema-version.js';
57
57
  import { planFlowGlobals, planSharedInputs, sharedInputRoots } from './flow-variables.js';
58
+ import { outputBackingGlobal, planOutputBacking } from './flow-output-backing.js';
59
+ import { mapJsCode } from './core/js-code-spans.js';
58
60
  import { prepareCommand } from './core/cli-spelling.js';
59
- import { QUEUE_ITEM_RECORD_SCHEMA } from './core/queue-record.js';
60
61
  import { AGENTIC_PROCESS_FORMS } from './core/agentic-process-forms.js';
61
62
  import { resourceNodeSortOrder } from './core/process-resource-sort-order.js';
62
63
  import { types } from './core/expr.js';
@@ -119,8 +120,6 @@ const NODE_TYPE = {
119
120
  doWhile: 'core.logic.dowhile',
120
121
  subflow: 'core.subflow',
121
122
  terminate: 'core.logic.terminate',
122
- queueCreate: 'core.action.queue.create',
123
- queueCreateAndWait: 'core.action.queue.create-and-wait',
124
123
  // The two AI patterns. `summarize()` emits `deep-rag`: the canvas name is
125
124
  // "Summarize", the wire type is the backend's (`ECS.DeepRag`), and there is
126
125
  // no `uipath.pattern.summarize` node type at all.
@@ -2923,123 +2922,6 @@ function connectionResourceBindings(spec, existing) {
2923
2922
  });
2924
2923
  return { entries };
2925
2924
  }
2926
- /**
2927
- * Build the definition for one queue-item node.
2928
- *
2929
- * Unlike `rpaWorkflowDef`, this one starts from the BUNDLED definition — the queue
2930
- * node types are generic (no tenant key in the type), so the platform's own copy
2931
- * can be shipped and is: `core-definitions.json` carries both at `@1.2`, verbatim
2932
- * from the catalogue the running `uip` consults (`@uipath/flow-core/manifest`'s
2933
- * `ootbNodes`). A test pins that the emitted definition is that copy plus exactly
2934
- * the three per-instance edits below, so the bundled snapshot stays diffable
2935
- * against upstream.
2936
- *
2937
- * VERSION 1.2, not the 1.0 the bundled sample carries. The platform is two
2938
- * migrations on, and both are semantic: 1.0 → 1.1 re-types `itemData` from
2939
- * `string` to `object`, and 1.1 → 1.2 makes the field validate as an object
2940
- * expression. `shared/sample-flows/queue-operations.flow` is v1.0-era (a JSON
2941
- * STRING in `itemData`) and dated 2026-05-20 — the shape the platform no longer
2942
- * writes. Reading it for the surface would have shipped the wrong field TYPE.
2943
- *
2944
- * The three per-instance edits:
2945
- *
2946
- * - `model.bindings.resourceKey` — the queue's own Orchestrator key. The shipped
2947
- * definition ships it BLANK, because only an instance knows which queue.
2948
- * - `model.context` — the `=bindings.<id>` references. The definition ships
2949
- * `<bindings.name>` placeholders; an instance names the actual binding ids,
2950
- * which is the second way `resourceBindings` can be resolved and the
2951
- * shape the bundled sample has.
2952
- * - `outputDefinition.output.schema` — the queue item's record for a plain
2953
- * create, or the author's `returns` for a create-and-wait. Without a schema a
2954
- * downstream read is unresolvable.
2955
- */
2956
- function queueItemDef(spec, stepName, ids, version) {
2957
- const nodeType = spec.wait ? NODE_TYPE.queueCreateAndWait : NODE_TYPE.queueCreate;
2958
- // The template at the AUTHOR'S version, when the bundle has it. Starting from
2959
- // the default and handing it to makeNode with the pin refused every other
2960
- // bundled version — the bug #988 fixed for inline agents (#1128). An
2961
- // unbundled pin falls back to the default, and makeNode's exact-version
2962
- // refusal names what is bundled.
2963
- const base = (version !== undefined ? DEFS[`${nodeType}@${version}`] : undefined) ?? defByType.get(nodeType);
2964
- if (!base)
2965
- throw new Error(`no bundled definition for "${nodeType}"`);
2966
- const def = jsonClone(base);
2967
- def.model.bindings.resourceKey = spec.key;
2968
- def.model.context = [
2969
- { name: 'name', type: 'string', value: `=bindings.${ids.name}`, default: spec.queue },
2970
- { name: 'folderPath', type: 'string', value: `=bindings.${ids.folderPath}`, default: spec.folderPath },
2971
- { name: '_label', type: 'string', value: stepName },
2972
- ];
2973
- const schema = spec.wait
2974
- ? (spec.returns && Object.keys(spec.returns).length
2975
- ? {
2976
- type: 'object',
2977
- properties: Object.fromEntries(Object.entries(spec.returns).map(([k, t]) => [k, { type: t }])),
2978
- }
2979
- : undefined)
2980
- : jsonClone(QUEUE_ITEM_RECORD_SCHEMA);
2981
- if (schema)
2982
- def.outputDefinition.output.schema = schema;
2983
- return def;
2984
- }
2985
- /**
2986
- * The two bindings a queue reference carries — the same `name` + `folderPath` pair
2987
- * the process families use, keyed to the queue's own Orchestrator key rather than
2988
- * to a `<folderPath>.<name>` string. That is what the only queue instance the repo
2989
- * has (`sample-flows/queue-operations.flow`) uses, and it is the queue's stable
2990
- * identity: a queue can be renamed, its key cannot.
2991
- *
2992
- * ONE PAIR PER QUEUE, not per step. Bindings are addressed by
2993
- * `resource + resourceKey + propertyAttribute` — that is the key a bindings
2994
- * lookup map is built on — so a second pair for the same queue is not a second
2995
- * reference, it is a duplicate that shadows the first: both nodes resolve to
2996
- * whichever was inserted last, and the other pair sits in the file referenced by
2997
- * nothing. So two steps on the same queue SHARE these, and the ids come from the
2998
- * queue rather than from a step name.
2999
- *
3000
- * (The rpa family mints its pair from the STEP name, so two steps starting the same
3001
- * process emit the same duplicate-and-shadow shape. Nothing exercises it today —
3002
- * every rpa flow in the repo has one process step — and changing those ids would
3003
- * rewrite the rpa goldens, so it is recorded as a finding rather than fixed here.)
3004
- */
3005
- function queueItemBindings(spec, existing) {
3006
- const found = (attr) => [...existing.values()].find((b) => b.resource === 'queue' && b.resourceKey === spec.key && b.propertyAttribute === attr)?.id;
3007
- const already = { name: found('name'), folderPath: found('folderPath') };
3008
- if (already.name && already.folderPath) {
3009
- return { ids: { name: already.name, folderPath: already.folderPath }, entries: [] };
3010
- }
3011
- // A readable, stable id per queue. Two queues that share a NAME across folders
3012
- // would collide, so the id is suffixed until it is free.
3013
- const slug = spec.queue.replace(/[^A-Za-z0-9]/g, '') || 'Queue';
3014
- let base = `b${slug.charAt(0).toUpperCase()}${slug.slice(1)}`;
3015
- for (let n = 2; existing.has(`${base}Name`) || existing.has(`${base}FolderPath`); n++) {
3016
- base = `b${slug.charAt(0).toUpperCase()}${slug.slice(1)}${n}`;
3017
- }
3018
- const ids = { name: `${base}Name`, folderPath: `${base}FolderPath` };
3019
- return {
3020
- ids,
3021
- entries: [
3022
- {
3023
- id: ids.name,
3024
- name: 'name',
3025
- type: 'string',
3026
- resource: 'queue',
3027
- resourceKey: spec.key,
3028
- default: spec.queue,
3029
- propertyAttribute: 'name',
3030
- },
3031
- {
3032
- id: ids.folderPath,
3033
- name: 'folderPath',
3034
- type: 'string',
3035
- resource: 'queue',
3036
- resourceKey: spec.key,
3037
- default: spec.folderPath,
3038
- propertyAttribute: 'folderPath',
3039
- },
3040
- ],
3041
- };
3042
- }
3043
2925
  /**
3044
2926
  * Encode a scheduled trigger's single `every` interval into the three inputs the
3045
2927
  * platform's node carries.
@@ -3589,10 +3471,11 @@ function applyAuthorLayout(layout, scope, where) {
3589
3471
  * identically into ExpressionValue envelopes.
3590
3472
  */
3591
3473
  function renderUpdates(updates, rename) {
3592
- return Object.entries(updates).map(([variableId, val]) => {
3474
+ return Object.entries(updates).map(([name, val]) => {
3593
3475
  const expr = toExpr(val);
3594
3476
  const expression = expr.literal ? '=js:' + JSON.stringify(expr.value) : '=js:' + renameRefs(expr.js, rename);
3595
- return { variableId, expression };
3477
+ // An output is never an update target: its backing Variable is (#1092).
3478
+ return { variableId: rename.updates?.get(name) ?? name, expression };
3596
3479
  });
3597
3480
  }
3598
3481
  /**
@@ -3778,7 +3661,6 @@ export function bundledActionNodeType(spec) {
3778
3661
  switch (spec?.kind) {
3779
3662
  case 'http': return spec.inputs?.managed ? NODE_TYPE.httpV2 : NODE_TYPE.http;
3780
3663
  case 'hitl': return hitlNodeType(spec.inputs);
3781
- case 'queueItem': return spec.inputs?.wait ? NODE_TYPE.queueCreateAndWait : NODE_TYPE.queueCreate;
3782
3664
  case 'inlineAgent': return INLINE_AGENT_TYPE;
3783
3665
  case 'subflow':
3784
3666
  case 'summarize':
@@ -4263,7 +4145,14 @@ function emittableGlobals(built, where, kind = 'root') {
4263
4145
  if (plan.problems.length) {
4264
4146
  throw new Error(`${where}: ${plan.problems.map((p) => `[${p.code}] ${p.message}`).join(' ')}`);
4265
4147
  }
4266
- return plan;
4148
+ // An output the flow sets from inside gets an `inout` Variable to hold the
4149
+ // value; the End copies it into the Output (#1092, `flow-output-backing.ts`).
4150
+ const sharedOutputs = new Set(shared.targets.filter((t) => t.declaredAs === 'output').map((t) => t.name));
4151
+ const backing = planOutputBacking(built, plan.outputs, plan.vars, sharedOutputs);
4152
+ if (backing.problems.length) {
4153
+ throw new Error(`${where}: ${backing.problems.map((p) => `[${p.code}] ${p.message}`).join(' ')}`);
4154
+ }
4155
+ return { ...plan, backing: backing.backing, backingReads: backing.reads };
4267
4156
  }
4268
4157
  /**
4269
4158
  * The flow's `{ shared }` input plan (#924), refused here as `check` refuses it
@@ -4284,17 +4173,20 @@ function sharedInputsOf(built, where, kind) {
4284
4173
  throw new Error(`${where}: ${errors.map((p) => `[${p.code}] ${p.message}`).join(' ')}`);
4285
4174
  return plan;
4286
4175
  }
4287
- function newScope(outputs, vars = []) {
4176
+ function newScope(outputs, vars = [], backing = new Map(), backingReads = backing) {
4177
+ const typeOf = new Map(outputs.map((o) => [o.name, o.type]));
4288
4178
  return {
4289
4179
  nodes: [],
4290
4180
  edges: [],
4291
4181
  variableUpdates: {},
4292
- outputType: new Map(outputs.map((o) => [o.name, o.type])),
4182
+ outputType: typeOf,
4293
4183
  endVarType: new Map([
4294
4184
  ...outputs.map((o) => [o.name, o.type]),
4185
+ ...[...backing].map(([o, b]) => [b, typeOf.get(o)]),
4295
4186
  ...vars.map((vd) => [vd.name, vd.type]),
4296
4187
  ]),
4297
- rename: { nodeIds: new Map(), errorEnvelopes: new Map() },
4188
+ backing,
4189
+ rename: { nodeIds: new Map(), errorEnvelopes: new Map(), vars: new Map(backingReads), updates: new Map(backing) },
4298
4190
  pending: new Map(),
4299
4191
  agentSchemas: [],
4300
4192
  stepNodeId: new Map(),
@@ -4535,11 +4427,11 @@ function isTypeDesc(type) {
4535
4427
  * An End node's `outputs` map: every variable this scope exposes as a flow
4536
4428
  * output, in declaration order.
4537
4429
  *
4538
- * `explicit` holds the sources a `.return({…})` named. Everything else maps to
4539
- * ITSELF (`$vars.<name>`) — "this output is whatever the variable holds when the
4540
- * flow leaves here", which is what Studio Web wires when you add a variable to
4541
- * an End node, and the only sensible reading for a `.var(…)` counter or an
4542
- * output another branch returns.
4430
+ * `explicit` holds the sources a `.return({…})` named. Everything else gets
4431
+ * `fillInSource`: a Variable maps to ITSELF (`$vars.<name>`), "whatever it holds
4432
+ * when the flow leaves here"; an output maps from its backing Variable when a
4433
+ * step sets it, else to `null` (#1092). An End never reads `$vars.<output>`:
4434
+ * Studio Web does not declare Outputs on `$vars`.
4543
4435
  *
4544
4436
  * Emitting the full set is not cosmetic. The product's output-mapping rule warns
4545
4437
  * `MISSING_OUTPUT_MAPPING` once per (End node × unmapped output variable), and
@@ -4552,8 +4444,7 @@ function isTypeDesc(type) {
4552
4444
  function endOutputs(scope, explicit = {}) {
4553
4445
  const outs = {};
4554
4446
  for (const [name, type] of scope.endVarType) {
4555
- const source = explicit[name] ?? `=js:$vars.${name}`;
4556
- outs[name] = { type, description: '', source, var: name };
4447
+ outs[name] = { type, description: '', source: explicit[name] ?? fillInSource(scope, name), var: name };
4557
4448
  }
4558
4449
  // A `.return(…)` naming something the flow never declared is a check() error
4559
4450
  // (RETURN_UNDECLARED), but serialize must not silently swallow the mapping if
@@ -4564,6 +4455,23 @@ function endOutputs(scope, explicit = {}) {
4564
4455
  }
4565
4456
  return outs;
4566
4457
  }
4458
+ /**
4459
+ * What an End maps a variable to when no `.return()` named it here.
4460
+ *
4461
+ * - A Variable (`inout`, a backing one included) maps to itself: "whatever it
4462
+ * holds when the flow leaves here".
4463
+ * - An Output with a backing Variable maps from that Variable (#1092).
4464
+ * - Any other Output was never set on the way (only `.return()` values set
4465
+ * it, and this End returns none), so it maps to `null`. That is the value the
4466
+ * old `$vars.<output>` read gave on this path, without reading an Output,
4467
+ * which Studio Web does not allow.
4468
+ */
4469
+ function fillInSource(scope, name) {
4470
+ if (!scope.outputType.has(name))
4471
+ return `=js:$vars.${name}`;
4472
+ const backing = scope.backing.get(name);
4473
+ return backing ? `=js:$vars.${backing}` : '=js:null';
4474
+ }
4567
4475
  /**
4568
4476
  * A Terminate event has no action result, but it is still a terminal event. The
4569
4477
  * product's output-mapping validator therefore requires every flow output on it,
@@ -4586,19 +4494,23 @@ function terminateOutputs(scope) {
4586
4494
  * same name (an error in its own right — DUP_STEP).
4587
4495
  */
4588
4496
  function renameRefs(text, rename) {
4589
- if (rename.nodeIds.size === 0 && rename.errorEnvelopes.size === 0)
4497
+ if (rename.nodeIds.size === 0 && rename.errorEnvelopes.size === 0 && !rename.vars?.size)
4590
4498
  return text;
4591
4499
  // `.error` matches only with a FIELD behind it: a bare `$vars.<step>.error` is
4592
4500
  // the boolean "did this fail" (`err('<step>')`), which is truthy on every
4593
4501
  // family — the envelope object included — and must be left alone.
4594
- return text.replace(/\$vars\.([A-Za-z0-9_]+)(\.error(?=\.[A-Za-z0-9_]))?/g, (m, name, tail) => {
4502
+ // Only code is rewritten: `"$vars.summary"` in a script is text (#1092).
4503
+ return mapJsCode(text, (code) => code.replace(/\$vars\.([A-Za-z0-9_]+)(\.error(?=\.[A-Za-z0-9_]))?/g, (m, name, tail) => {
4504
+ const backing = rename.vars?.get(name);
4505
+ if (backing)
4506
+ return `$vars.${backing}${tail ?? ''}`;
4595
4507
  const to = rename.nodeIds.get(name);
4596
4508
  const nodeId = to && to.length > 0 ? to[0] : name;
4597
4509
  if (!tail)
4598
4510
  return nodeId === name ? m : `$vars.${nodeId}`;
4599
4511
  const envelope = rename.errorEnvelopes.get(name) ?? 'error';
4600
4512
  return `$vars.${nodeId}.${envelope}`;
4601
- });
4513
+ }));
4602
4514
  }
4603
4515
  /** Every step name a flow declares in its own scope (not its children's). */
4604
4516
  function stepNamesOf(steps, out = []) {
@@ -4743,7 +4655,7 @@ export function serialize(built, opts = {}) {
4743
4655
  const sidecars = opts.sidecars ?? [];
4744
4656
  const subflows = {};
4745
4657
  const rootGlobals = emittableGlobals(built, `flow "${built.id}"`);
4746
- const root = newScope(rootGlobals.outputs, rootGlobals.vars);
4658
+ const root = newScope(rootGlobals.outputs, rootGlobals.vars, rootGlobals.backing, rootGlobals.backingReads);
4747
4659
  // `input('x')` lowers eagerly to `$vars.start.output.x` — `start` being the
4748
4660
  // trigger node's default id. When the flow renames the trigger, register that
4749
4661
  // rename so the SAME pass that rewrites step-name references rewrites these
@@ -4920,7 +4832,7 @@ export function serialize(built, opts = {}) {
4920
4832
  */
4921
4833
  function emitSubflowBody(child, nodeId) {
4922
4834
  const childGlobals = emittableGlobals(child, `subflow "${nodeId}"`, 'subflow');
4923
- const scope = newScope(childGlobals.outputs, childGlobals.vars);
4835
+ const scope = newScope(childGlobals.outputs, childGlobals.vars, childGlobals.backing, childGlobals.backingReads);
4924
4836
  // Claim this copy's node ids UP FRONT, so the rename map is complete before
4925
4837
  // the first expression renders. A child's step names are free the first
4926
4838
  // time it runs; if any of them is already taken — which is what a second
@@ -4958,6 +4870,11 @@ export function serialize(built, opts = {}) {
4958
4870
  globals.push({ id: inp.name, name: inp.name, direction: 'in', type: inp.type, triggerNodeId: startId, ...varMeta(inp) });
4959
4871
  for (const o of childGlobals.outputs)
4960
4872
  globals.push({ id: o.name, name: o.name, direction: 'out', type: o.type, ...varMeta(o) });
4873
+ for (const o of childGlobals.outputs) {
4874
+ const b = childGlobals.backing.get(o.name);
4875
+ if (b)
4876
+ globals.push(outputBackingGlobal(o, b));
4877
+ }
4961
4878
  for (const vd of childGlobals.vars)
4962
4879
  globals.push({ id: vd.name, name: vd.name, direction: 'inout', type: vd.type, ...varMeta(vd) });
4963
4880
  resolveRejoins(scope, addEdge);
@@ -5080,10 +4997,6 @@ export function serialize(built, opts = {}) {
5080
4997
  return 'default';
5081
4998
  if (type === NODE_TYPE.loop)
5082
4999
  return 'success';
5083
- // Both queue definitions declare exactly one source handle, `success` — and
5084
- // the shipped `sample-flows/queue-operations.flow` wires its edges to it.
5085
- if (type === NODE_TYPE.queueCreate || type === NODE_TYPE.queueCreateAndWait)
5086
- return 'success';
5087
5000
  // Every human-task definition declares one static source handle, `completed`.
5088
5001
  // It is the real exit only where the product draws it: action-app,
5089
5002
  // document-validation, and a task with no outcomes. A base or quick-form task
@@ -5205,6 +5118,7 @@ export function serialize(built, opts = {}) {
5205
5118
  mint: (seed) => stableId(`${built.id}:${id}:${seed}`),
5206
5119
  bind: (b) => { bound.push(b); },
5207
5120
  definition: (typeName, version) => bundledDefinition(typeName, version),
5121
+ bindings: resourceBindings,
5208
5122
  };
5209
5123
  const bound = [];
5210
5124
  const contribution = impl.serialize(spec, ctx);
@@ -5965,42 +5879,6 @@ export function serialize(built, opts = {}) {
5965
5879
  addEdge(scope, t, id);
5966
5880
  return [{ node: id, port: successPort(def.nodeType) }];
5967
5881
  }
5968
- if (spec.kind === 'queueItem') {
5969
- const s = spec.inputs;
5970
- // The bindings first: two steps on the same queue share one pair, and the
5971
- // node's `model.context` has to name the ids that actually exist.
5972
- const { ids, entries } = queueItemBindings(s, resourceBindings);
5973
- for (const b of entries)
5974
- resourceBindings.set(b.id, b);
5975
- const def = queueItemDef(s, step.name, ids, step.options?.version);
5976
- const id = stepUid(scope, step.name);
5977
- // The result is read as `$vars.<step>.output`, like every other family: the
5978
- // node's own output block maps the runtime `response` onto the variable
5979
- // `output` (`source: "=response", var: "output"`), and the product honours
5980
- // that mapping for both queue variants. (An alias to `.response` lived here
5981
- // from #273 until #891; a live debug run on 2026-10-01 measured
5982
- // `.output.Key` populated and `.response` undefined.)
5983
- const node = makeNode(def.nodeType, id, step.name, { parentId, requestedVersion: step.options?.version, def });
5984
- // The node KEEPS its copy of the model here, unlike the rpa families. Two
5985
- // reasons: it is what the one queue instance the repo has carries, and it is
5986
- // what `makeNode` does for every other core action node with a model (http,
5987
- // script, transform). The model resolves from either place since #94, and a
5988
- // bindings lookup reads node-first for the same reason.
5989
- node.inputs = {
5990
- queue: { name: s.queue, folderPath: s.folderPath, key: s.key },
5991
- // `itemData`, not `item`: the surface's name is friendlier, the node's is
5992
- // the platform's. The reference documents the mapping.
5993
- itemData: renderMap(s.item ?? {}, scope.rename),
5994
- priority: s.priority ?? 'Normal',
5995
- reference: s.reference === undefined ? '' : renderValue(s.reference, scope.rename),
5996
- deferDate: s.deferDate === undefined ? '' : renderValue(s.deferDate, scope.rename),
5997
- dueDate: s.dueDate === undefined ? '' : renderValue(s.dueDate, scope.rename),
5998
- };
5999
- scope.nodes.push(node);
6000
- for (const t of tails)
6001
- addEdge(scope, t, id);
6002
- return [{ node: id, port: successPort(def.nodeType) }];
6003
- }
6004
5882
  if (spec.kind === 'conversationalAgent') {
6005
5883
  // The text CONVERSATIONAL agent: the inline agent's cluster shape (a
6006
5884
  // minted `source` plus an `agent.json` sidecar) with the family's own
@@ -6919,10 +6797,14 @@ export function serialize(built, opts = {}) {
6919
6797
  for (const [name, expr] of Object.entries(step.values)) {
6920
6798
  const src = expr.literal ? '=js:' + JSON.stringify(expr.value) : '=js:' + renameRefs(expr.js, scope.rename);
6921
6799
  explicit[name] = src;
6922
- // Only the values the author actually RETURNED are written back to the
6923
- // variable. The identity mappings `endOutputs` fills in read a
6924
- // variable; a variableUpdate for one would be a no-op assignment.
6925
- updates.push({ variableId: name, expression: src });
6800
+ // The End's output mapping is what sets an Output; Studio Web writes
6801
+ // no variable update for it (`end-node-sets-output.flow`), and an
6802
+ // Output is not an update target (#1092). A returned `.var()` is a
6803
+ // Variable, so it is still written back. The identity mappings
6804
+ // `endOutputs` fills in read a variable; an update for one would be
6805
+ // a no-op assignment.
6806
+ if (!scope.outputType.has(name))
6807
+ updates.push({ variableId: name, expression: src });
6926
6808
  }
6927
6809
  emitEnd(scope, id, tails, { label: step.options?.label, parentId, requestedVersion: step.options?.version, explicit });
6928
6810
  const extra = step.options?.updates ?? {};
@@ -7073,6 +6955,11 @@ export function serialize(built, opts = {}) {
7073
6955
  globals.push({ id: inp.name, name: inp.name, direction: 'in', type: inp.type, triggerNodeId, ...varMeta(inp) });
7074
6956
  for (const o of rootGlobals.outputs)
7075
6957
  globals.push({ id: o.name, name: o.name, direction: 'out', type: o.type, ...varMeta(o) });
6958
+ for (const o of rootGlobals.outputs) {
6959
+ const b = rootGlobals.backing.get(o.name);
6960
+ if (b)
6961
+ globals.push(outputBackingGlobal(o, b));
6962
+ }
7076
6963
  for (const vd of rootGlobals.vars)
7077
6964
  globals.push({ id: vd.name, name: vd.name, direction: 'inout', type: vd.type, ...varMeta(vd) });
7078
6965
  for (const ep of entryPoints) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.20.5",
3
+ "version": "6.21.0",
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": "2ed3ce64cea5047f9da44c287cacc18f0f66f37d"
95
+ "gitref": "c72d3cea4a18fc9bad9e6a10a817f7534b6de674"
96
96
  }