@uipath/maestro-builder-sdk 6.16.10 → 6.16.12
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/registry/prepare/connections.js +13 -2
- package/dist/serialize.d.ts +11 -0
- package/dist/serialize.js +73 -18
- package/package.json +2 -2
|
@@ -279,10 +279,21 @@ export function solutionConnectionIds(cwd, connectorKey) {
|
|
|
279
279
|
* module's rule intact — ambiguity is never resolved by guessing.
|
|
280
280
|
*/
|
|
281
281
|
export async function candidateConnections(client, connectorKey, name) {
|
|
282
|
+
// Both listings are always needed here, so they run at once: each is a `uip`
|
|
283
|
+
// process and a tenant round trip (~1 s each, measured in the n8n-vs-flow
|
|
284
|
+
// adhoc run of 2026-10-06), and neither depends on the other. Started in
|
|
285
|
+
// own-folder-then-tenant order, merged in that order, and a failure is
|
|
286
|
+
// reported in that order too — the result is what the sequential loop gave.
|
|
287
|
+
const settled = await Promise.allSettled([false, true].map((allFolders) => listConnections(client, { allFolders })));
|
|
288
|
+
const listings = settled.map((outcome) => {
|
|
289
|
+
if (outcome.status === "rejected")
|
|
290
|
+
throw outcome.reason;
|
|
291
|
+
return outcome.value;
|
|
292
|
+
});
|
|
282
293
|
const ordered = [];
|
|
283
294
|
const seen = new Set();
|
|
284
|
-
for (const
|
|
285
|
-
for (const row of enabledConnections(
|
|
295
|
+
for (const listing of listings) {
|
|
296
|
+
for (const row of enabledConnections(listing, connectorKey, name)) {
|
|
286
297
|
const identifier = pyStrAny(pyGet(row, "Id", ""));
|
|
287
298
|
if (identifier && seen.has(identifier))
|
|
288
299
|
continue;
|
package/dist/serialize.d.ts
CHANGED
|
@@ -88,6 +88,17 @@ export declare function serializeWithSidecars(built: BuiltFlow, opts?: Serialize
|
|
|
88
88
|
}>;
|
|
89
89
|
};
|
|
90
90
|
export declare function serialize(built: BuiltFlow, opts?: SerializeOpts): any;
|
|
91
|
+
/**
|
|
92
|
+
* Node ids and edge ids are each one namespace over the WHOLE file: the root
|
|
93
|
+
* and every `subflows` entry. Pack flattens subflows into one BPMN document, so
|
|
94
|
+
* two scopes sharing an id make it drop one element or crash in layout
|
|
95
|
+
* (`Cannot read properties of undefined (reading 'get')`), while `check` and
|
|
96
|
+
* `uip maestro flow validate` both pass. #938 shipped that way for `.stepToRef`
|
|
97
|
+
* edges; this check stops the next id scheme that forgets the file is shared.
|
|
98
|
+
*
|
|
99
|
+
* @throws Error naming each duplicated id and the scopes that carry it.
|
|
100
|
+
*/
|
|
101
|
+
export declare function assertFileWideIdsUnique(flow: any): void;
|
|
91
102
|
/**
|
|
92
103
|
* Every `<bindings.NAME>` placeholder a node's definition carries in its
|
|
93
104
|
* `model.context` must resolve to a `bindings[]` entry for THAT node.
|
package/dist/serialize.js
CHANGED
|
@@ -3633,14 +3633,15 @@ const STICKY_NOTE_TYPE_VERSION = '1.0.0';
|
|
|
3633
3633
|
* — a note colliding with a step would be silently dropped by the id-keyed
|
|
3634
3634
|
* layout and merge paths downstream.
|
|
3635
3635
|
*/
|
|
3636
|
-
function emitStickyNotes(built, scope) {
|
|
3636
|
+
function emitStickyNotes(built, scope, claimNoteId) {
|
|
3637
3637
|
const notes = built.stickyNotes;
|
|
3638
3638
|
if (!notes?.length)
|
|
3639
3639
|
return;
|
|
3640
3640
|
const taken = new Set(scope.nodes.map((n) => n.id));
|
|
3641
3641
|
const seen = new Set();
|
|
3642
3642
|
notes.forEach((note, i) => {
|
|
3643
|
-
const
|
|
3643
|
+
const authorId = note.id ?? `stickyNote_${i + 1}`;
|
|
3644
|
+
const id = authorId;
|
|
3644
3645
|
if (taken.has(id)) {
|
|
3645
3646
|
throw new Error(`.stickyNotes(): id "${id}" is already a node in this flow. A sticky note is a real node, `
|
|
3646
3647
|
+ `so its id has to be unique — name it something else.`);
|
|
@@ -3657,12 +3658,18 @@ function emitStickyNotes(built, scope) {
|
|
|
3657
3658
|
if ((note.width === undefined) !== (note.height === undefined)) {
|
|
3658
3659
|
throw new Error(`.stickyNotes(): note "${id}" needs both width and height, or neither.`);
|
|
3659
3660
|
}
|
|
3661
|
+
// Node ids are one namespace over the whole file (#938): pack merges every
|
|
3662
|
+
// subflow into one BPMN document. The author's id is kept unless another
|
|
3663
|
+
// scope already holds it — a child with notes, called from two steps — and
|
|
3664
|
+
// `.layout()` finds a renamed note through `noteNodeId`.
|
|
3665
|
+
const emittedId = claimNoteId(authorId);
|
|
3666
|
+
(scope.noteNodeId ??= new Map()).set(authorId, emittedId);
|
|
3660
3667
|
// The envelope Studio Web writes for a note (flow-v1 canvas: the add path
|
|
3661
3668
|
// sets `typeVersion: '1.0.0'` and no display, and `nodeToInstance` persists
|
|
3662
3669
|
// `display` as `{}`). Both fields are required on every node by
|
|
3663
3670
|
// `flow validate`, manifest or not (#869).
|
|
3664
3671
|
scope.nodes.push({
|
|
3665
|
-
id,
|
|
3672
|
+
id: emittedId,
|
|
3666
3673
|
type: 'stickyNote',
|
|
3667
3674
|
typeVersion: STICKY_NOTE_TYPE_VERSION,
|
|
3668
3675
|
ui: {
|
|
@@ -3685,7 +3692,9 @@ function applyAuthorLayout(layout, scope, where) {
|
|
|
3685
3692
|
if (!layout)
|
|
3686
3693
|
return undefined;
|
|
3687
3694
|
const resolveId = (key) => {
|
|
3688
|
-
const id = scope.stepNodeId.get(key)
|
|
3695
|
+
const id = scope.stepNodeId.get(key)
|
|
3696
|
+
?? scope.noteNodeId?.get(key)
|
|
3697
|
+
?? (scope.nodes.some((n) => n.id === key) ? key : undefined);
|
|
3689
3698
|
if (!id) {
|
|
3690
3699
|
throw new Error(`${where}.layout: "${key}" names no step or node in this flow. Layout keys are the flow's own step names (plus the trigger id and "end").`);
|
|
3691
3700
|
}
|
|
@@ -4366,20 +4375,18 @@ function newScope(outputs, vars = []) {
|
|
|
4366
4375
|
* exact class of failure `.onError` used to have (an error path that vanishes in
|
|
4367
4376
|
* conversion with every rung green). So it throws instead.
|
|
4368
4377
|
*/
|
|
4369
|
-
function resolveRejoins(scope) {
|
|
4378
|
+
function resolveRejoins(scope, addEdge) {
|
|
4370
4379
|
for (const { from, target } of scope.pendingEdges) {
|
|
4371
4380
|
const id = scope.stepNodeId.get(target);
|
|
4372
4381
|
if (!id) {
|
|
4373
4382
|
throw new Error(`.stepToRef('${target}') names a step this flow does not have. Known steps: `
|
|
4374
4383
|
+ `${[...scope.stepNodeId.keys()].join(', ') || '(none)'}.`);
|
|
4375
4384
|
}
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
targetPort: 'input',
|
|
4382
|
-
});
|
|
4385
|
+
// Through the serializer's own `addEdge`, so the id comes from the one
|
|
4386
|
+
// file-wide counter. A per-scope count (`edge_ref_${scope.edges.length}`)
|
|
4387
|
+
// gave two subflow copies of one child the same edge id; pack then dropped
|
|
4388
|
+
// one copy's edge or crashed in layout (flow-builder-sdk#938).
|
|
4389
|
+
addEdge(scope, from, id);
|
|
4383
4390
|
}
|
|
4384
4391
|
scope.pendingEdges.length = 0;
|
|
4385
4392
|
}
|
|
@@ -4653,6 +4660,18 @@ export function serialize(built, opts = {}) {
|
|
|
4653
4660
|
takenIds.add(id);
|
|
4654
4661
|
return id;
|
|
4655
4662
|
}
|
|
4663
|
+
/**
|
|
4664
|
+
* A sticky note's id: the author's id as written when nothing in the file
|
|
4665
|
+
* holds it yet, else `claimId`'s de-duplicated form. Not sanitized first, so
|
|
4666
|
+
* an explicit note id the file does not collide on is emitted unchanged.
|
|
4667
|
+
*/
|
|
4668
|
+
function claimNoteId(base) {
|
|
4669
|
+
if (!takenIds.has(base)) {
|
|
4670
|
+
takenIds.add(base);
|
|
4671
|
+
return base;
|
|
4672
|
+
}
|
|
4673
|
+
return claimId(base);
|
|
4674
|
+
}
|
|
4656
4675
|
/**
|
|
4657
4676
|
* `uid` for a node that IS an author's step, recording which id that step got.
|
|
4658
4677
|
*
|
|
@@ -4672,8 +4691,9 @@ export function serialize(built, opts = {}) {
|
|
|
4672
4691
|
* Base and quick-form human tasks emitted so far, by node id. `addEdge` holds
|
|
4673
4692
|
* every edge out of one to the product's handle rule (`hitlExitViolation`), so
|
|
4674
4693
|
* `completed` on a task with outcomes fails at the edge that would write it;
|
|
4675
|
-
* `assertHitlExitInvariant` repeats the check over each finished scope
|
|
4676
|
-
*
|
|
4694
|
+
* `assertHitlExitInvariant` repeats the check over each finished scope, as a
|
|
4695
|
+
* guard for any future edge that is pushed without coming through here (parked
|
|
4696
|
+
* `.stepToRef` rejoins now do come through here, #938).
|
|
4677
4697
|
*/
|
|
4678
4698
|
const hitlNodes = new Map();
|
|
4679
4699
|
/**
|
|
@@ -4796,10 +4816,10 @@ export function serialize(built, opts = {}) {
|
|
|
4796
4816
|
globals.push({ id: o.name, name: o.name, direction: 'out', type: o.type, ...varMeta(o) });
|
|
4797
4817
|
for (const vd of childGlobals.vars)
|
|
4798
4818
|
globals.push({ id: vd.name, name: vd.name, direction: 'inout', type: vd.type, ...varMeta(vd) });
|
|
4799
|
-
resolveRejoins(scope);
|
|
4819
|
+
resolveRejoins(scope, addEdge);
|
|
4800
4820
|
assertHitlExitInvariant(scope.nodes, scope.edges);
|
|
4801
4821
|
typeAgentInputSchemas(scope, globals);
|
|
4802
|
-
emitStickyNotes(child, scope);
|
|
4822
|
+
emitStickyNotes(child, scope, claimNoteId);
|
|
4803
4823
|
const layoutEdges = applyAuthorLayout(child.layout, scope, `subflow "${nodeId}"`);
|
|
4804
4824
|
assertNodeEnvelope(scope.nodes, `subflow "${nodeId}"`);
|
|
4805
4825
|
return {
|
|
@@ -6964,10 +6984,10 @@ export function serialize(built, opts = {}) {
|
|
|
6964
6984
|
globals.push({ id: inp.name, name: inp.name, direction: 'in', type: inp.type, triggerNodeId: ep.id, ...varMeta(inp) });
|
|
6965
6985
|
}
|
|
6966
6986
|
}
|
|
6967
|
-
resolveRejoins(root);
|
|
6987
|
+
resolveRejoins(root, addEdge);
|
|
6968
6988
|
assertHitlExitInvariant(root.nodes, root.edges);
|
|
6969
6989
|
typeAgentInputSchemas(root, globals);
|
|
6970
|
-
emitStickyNotes(built, root);
|
|
6990
|
+
emitStickyNotes(built, root, claimNoteId);
|
|
6971
6991
|
const rootLayoutEdges = applyAuthorLayout(built.layout, root, `flow "${built.id}"`);
|
|
6972
6992
|
assertNodeEnvelope(root.nodes, `flow "${built.id}"`);
|
|
6973
6993
|
// The FILE-FORMAT version this document declares: the author's
|
|
@@ -7002,9 +7022,44 @@ export function serialize(built, opts = {}) {
|
|
|
7002
7022
|
// so every family and every emission order is covered by one rule, not by
|
|
7003
7023
|
// each call site remembering it (flow-builder-sdk#865/#866).
|
|
7004
7024
|
assertBindingPlaceholdersResolve(flow);
|
|
7025
|
+
assertFileWideIdsUnique(flow);
|
|
7005
7026
|
connectionConnectors(flow);
|
|
7006
7027
|
return flow;
|
|
7007
7028
|
}
|
|
7029
|
+
/**
|
|
7030
|
+
* Node ids and edge ids are each one namespace over the WHOLE file: the root
|
|
7031
|
+
* and every `subflows` entry. Pack flattens subflows into one BPMN document, so
|
|
7032
|
+
* two scopes sharing an id make it drop one element or crash in layout
|
|
7033
|
+
* (`Cannot read properties of undefined (reading 'get')`), while `check` and
|
|
7034
|
+
* `uip maestro flow validate` both pass. #938 shipped that way for `.stepToRef`
|
|
7035
|
+
* edges; this check stops the next id scheme that forgets the file is shared.
|
|
7036
|
+
*
|
|
7037
|
+
* @throws Error naming each duplicated id and the scopes that carry it.
|
|
7038
|
+
*/
|
|
7039
|
+
export function assertFileWideIdsUnique(flow) {
|
|
7040
|
+
const scopes = [['root', flow]];
|
|
7041
|
+
for (const [name, sub] of Object.entries(flow?.subflows ?? {}))
|
|
7042
|
+
scopes.push([`subflows.${name}`, sub]);
|
|
7043
|
+
const dupes = [];
|
|
7044
|
+
for (const kind of ['nodes', 'edges']) {
|
|
7045
|
+
const seen = new Map();
|
|
7046
|
+
for (const [where, scope] of scopes) {
|
|
7047
|
+
for (const el of Array.isArray(scope?.[kind]) ? scope[kind] : []) {
|
|
7048
|
+
const id = el?.id;
|
|
7049
|
+
if (typeof id !== 'string')
|
|
7050
|
+
continue;
|
|
7051
|
+
const first = seen.get(id);
|
|
7052
|
+
if (first !== undefined)
|
|
7053
|
+
dupes.push(`${kind.slice(0, -1)} id "${id}" in ${first} and ${where}`);
|
|
7054
|
+
else
|
|
7055
|
+
seen.set(id, where);
|
|
7056
|
+
}
|
|
7057
|
+
}
|
|
7058
|
+
}
|
|
7059
|
+
if (dupes.length) {
|
|
7060
|
+
throw new Error(`serialize: ids must be unique across the root and all subflows; duplicated: ${dupes.join('; ')}.`);
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7008
7063
|
/**
|
|
7009
7064
|
* Every `<bindings.NAME>` placeholder a node's definition carries in its
|
|
7010
7065
|
* `model.context` must resolve to a `bindings[]` entry for THAT node.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.16.
|
|
3
|
+
"version": "6.16.12",
|
|
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": "
|
|
95
|
+
"gitref": "a17e4a3af0cefe7881625c5888b282c4ea4a0546"
|
|
96
96
|
}
|