@uipath/maestro-builder-sdk 6.46.6 → 6.46.7

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.
@@ -5,6 +5,7 @@ import { preserveSchemaVersion } from '../schema-version.js';
5
5
  import { ownEntry } from '../core/own-entry.js';
6
6
  import { isUnrestorableSlotId } from './preserve.js';
7
7
  import { isInSolutionKey, SOLUTION_FOLDER } from './resource-identity.js';
8
+ import { offlineBindingLabel } from './ids.js';
8
9
  const TASK_KIND_METHOD = {
9
10
  process: 'process',
10
11
  agent: 'agent',
@@ -342,7 +343,18 @@ function bindingName(value, refs) {
342
343
  if (typeof value !== 'string' || !value.startsWith('=bindings.'))
343
344
  return undefined;
344
345
  const id = value.slice('=bindings.'.length);
345
- return refs.bindingById.get(id)?.id ?? id;
346
+ return bindingLabel(refs, id);
347
+ }
348
+ /**
349
+ * The name a binding reference decompiles to: the authored label when
350
+ * `serialize` minted the row offline (so a recompile with no bindings.json
351
+ * mints the same row, and a later bindings.json entry for that label matches),
352
+ * else the row id (a bindings.json or Designer row, which the recompile
353
+ * resolves by id).
354
+ */
355
+ function bindingLabel(refs, id) {
356
+ const row = refs.bindingById.get(id);
357
+ return offlineBindingLabel(row) ?? row?.id ?? id;
346
358
  }
347
359
  /**
348
360
  * The literal a resource task's `data.name` / `data.folderPath` names: the
@@ -567,7 +579,7 @@ function externalCall(task, refs, library) {
567
579
  const id = value.slice('=bindings.'.length);
568
580
  if (!refs.bindingById.has(id))
569
581
  throw new Error(`${owner} context ${name} references missing root binding "${id}".`);
570
- return id;
582
+ return bindingLabel(refs, id);
571
583
  };
572
584
  const identity = library.identifyAction({
573
585
  connectorKey: stringValue('connectorKey'),
@@ -22,3 +22,29 @@ export declare class IdGen {
22
22
  conditionId(seed: string): string;
23
23
  ruleId(seed: string): string;
24
24
  }
25
+ /**
26
+ * The seed `serialize` mints an offline binding id from (a connection or
27
+ * folder label no bindings.json declares). One definition for both sides, so
28
+ * {@link offlineBindingLabel} can recognise exactly the ids `serialize` mints.
29
+ *
30
+ * @param resource - The binding's `resource` (`Connection`).
31
+ * @param propertyAttribute - `ConnectionId` or `folderKey`.
32
+ * @param name - The authored label.
33
+ * @param connectionKey - For a folder bound to a connection, that connection's resourceKey.
34
+ * @returns The seed string.
35
+ */
36
+ export declare function offlineBindingSeed(resource: string, propertyAttribute: string, name: string, connectionKey?: string): string;
37
+ /**
38
+ * The authored label behind a root binding row that `serialize` minted offline,
39
+ * or `undefined` for any other row (a bindings.json entry, a Designer row).
40
+ *
41
+ * Offline the label is the row's only real content: a connection row carries
42
+ * it as `resourceKey`, a folder row on a connection as `default`, a plain
43
+ * folder row as `resourceKey`. The row is recognised only when its `id` is
44
+ * exactly the id that label mints, so decompile can name it by the label and
45
+ * a recompile with no bindings mints the same row again.
46
+ *
47
+ * @param row - A root binding entry.
48
+ * @returns The label, or `undefined`.
49
+ */
50
+ export declare function offlineBindingLabel(row: Record<string, unknown> | undefined): string | undefined;
package/dist/case/ids.js CHANGED
@@ -74,3 +74,52 @@ export class IdGen {
74
74
  return this.make('Rule_', 6, seed);
75
75
  }
76
76
  }
77
+ /**
78
+ * The seed `serialize` mints an offline binding id from (a connection or
79
+ * folder label no bindings.json declares). One definition for both sides, so
80
+ * {@link offlineBindingLabel} can recognise exactly the ids `serialize` mints.
81
+ *
82
+ * @param resource - The binding's `resource` (`Connection`).
83
+ * @param propertyAttribute - `ConnectionId` or `folderKey`.
84
+ * @param name - The authored label.
85
+ * @param connectionKey - For a folder bound to a connection, that connection's resourceKey.
86
+ * @returns The seed string.
87
+ */
88
+ export function offlineBindingSeed(resource, propertyAttribute, name, connectionKey) {
89
+ return connectionKey === undefined
90
+ ? `binding:${resource}:${propertyAttribute}:${name}`
91
+ : `binding:${resource}:${propertyAttribute}:${connectionKey}:${name}`;
92
+ }
93
+ /** The binding id {@link IdGen.make} gives `seed` at salt 0..3 (`b` + 8 base-62). */
94
+ function offlineBindingIds(seed) {
95
+ return [0, 1, 2, 3].map((salt) => 'b' + base62(salt === 0 ? seed : `${seed}~${salt}`, 8));
96
+ }
97
+ /**
98
+ * The authored label behind a root binding row that `serialize` minted offline,
99
+ * or `undefined` for any other row (a bindings.json entry, a Designer row).
100
+ *
101
+ * Offline the label is the row's only real content: a connection row carries
102
+ * it as `resourceKey`, a folder row on a connection as `default`, a plain
103
+ * folder row as `resourceKey`. The row is recognised only when its `id` is
104
+ * exactly the id that label mints, so decompile can name it by the label and
105
+ * a recompile with no bindings mints the same row again.
106
+ *
107
+ * @param row - A root binding entry.
108
+ * @returns The label, or `undefined`.
109
+ */
110
+ export function offlineBindingLabel(row) {
111
+ if (!row || typeof row.id !== 'string')
112
+ return undefined;
113
+ const { id, resource, propertyAttribute, resourceKey } = row;
114
+ if (typeof resource !== 'string' || typeof propertyAttribute !== 'string' || typeof resourceKey !== 'string')
115
+ return undefined;
116
+ const candidates = [
117
+ [resourceKey, offlineBindingSeed(resource, propertyAttribute, resourceKey)],
118
+ ];
119
+ if (propertyAttribute === 'folderKey' && typeof row.default === 'string')
120
+ candidates.push([row.default, offlineBindingSeed(resource, propertyAttribute, row.default, resourceKey)]);
121
+ for (const [label, seed] of candidates)
122
+ if (offlineBindingIds(seed).includes(id))
123
+ return label;
124
+ return undefined;
125
+ }
@@ -8,7 +8,7 @@
8
8
  * `metadata.caseExitRules`. Symbolic references in rules (a stage label, a task
9
9
  * name) are resolved here to the generated ids.
10
10
  */
11
- import { IdGen } from './ids.js';
11
+ import { IdGen, offlineBindingSeed } from './ids.js';
12
12
  import { isUnrestorableSlotId } from './preserve.js';
13
13
  import { v31TaskSets } from './task-sets.js';
14
14
  import { buildConnectorInputs, nestConnectorBody, transportHttpMethod } from '../core/connector-inputs.js';
@@ -81,6 +81,8 @@ export function serialize(built, opts = {}) {
81
81
  library: opts.library,
82
82
  bindings: opts.bindings,
83
83
  bindingSink: new Map(),
84
+ ids,
85
+ offlineBindingIds: new Map(),
84
86
  varCompanions: new Map(),
85
87
  outputIds: new Set(),
86
88
  ownOutputVars: ownOutputVars(built),
@@ -1469,6 +1471,20 @@ function ioSlot(name, bodyObj, elementId) {
1469
1471
  const v = `v${name}`;
1470
1472
  return { name, type: 'json', target: name, body: bodyObj, var: v, id: v, elementId };
1471
1473
  }
1474
+ /**
1475
+ * The binding id for a label no bindings.json declares. The row's
1476
+ * `resourceKey`/`default` stays the label, and the id is minted from it (`b` +
1477
+ * 8, as Studio Web mints one), once per label; `offlineBindingLabel` reverses
1478
+ * it for decompile.
1479
+ */
1480
+ function offlineBindingId(resolver, seed) {
1481
+ let id = resolver.offlineBindingIds.get(seed);
1482
+ if (id === undefined) {
1483
+ id = resolver.ids.make('b', 8, seed);
1484
+ resolver.offlineBindingIds.set(seed, id);
1485
+ }
1486
+ return id;
1487
+ }
1472
1488
  /** Resolve a symbolic connection/folder to a root binding entry (collected once),
1473
1489
  * returning its id + resourceKey for the `=bindings.<id>` reference. */
1474
1490
  function bindingRef(resolver, name, resource, propertyAttribute, displayName, site) {
@@ -1483,8 +1499,12 @@ function bindingRef(resolver, name, resource, propertyAttribute, displayName, si
1483
1499
  if (refused)
1484
1500
  throw refused;
1485
1501
  const entry = resolver.bindings?.entry(name);
1486
- const id = entry?.id ?? name;
1487
1502
  const resourceKey = entry?.resourceKey ?? entry?.default ?? name;
1503
+ // Only a label with no bindings.json entry gets a minted id: an entry's
1504
+ // `resourceKey` is the real key, so its id (or its name) cannot clash with it.
1505
+ const id = entry
1506
+ ? String(entry.id ?? name)
1507
+ : offlineBindingId(resolver, offlineBindingSeed(resource, propertyAttribute, name));
1488
1508
  if (!resolver.bindingSink.has(id)) {
1489
1509
  resolver.bindingSink.set(id, {
1490
1510
  id,
@@ -1501,7 +1521,8 @@ function bindingRef(resolver, name, resource, propertyAttribute, displayName, si
1501
1521
  /**
1502
1522
  * A connector's folder is a property of its connection:
1503
1523
  * { resourceKey: <connection key>, default: <folder key>, propertyAttribute: 'folderKey' }.
1504
- * One folder label on two connections gets one row each: `shared`, `shared_2`.
1524
+ * One folder label on two connections gets one row each: `shared`, `shared_2`
1525
+ * (offline, the minted id is seeded on the connection, so the rows differ anyway).
1505
1526
  * One connection with two different folders is refused: a connection lives in
1506
1527
  * one folder, and the syncs group rows by `resourceKey`, so one value would win.
1507
1528
  * Without a connection the folder binds as a plain binding.
@@ -1515,7 +1536,9 @@ function folderBindingRef(resolver, name, connection, site) {
1515
1536
  if (refused)
1516
1537
  throw refused;
1517
1538
  const entry = resolver.bindings?.entry(name);
1518
- const baseId = entry?.id ?? name;
1539
+ const baseId = entry
1540
+ ? String(entry.id ?? name)
1541
+ : offlineBindingId(resolver, offlineBindingSeed('Connection', 'folderKey', name, connection.resourceKey));
1519
1542
  const folderKey = entry?.default ?? entry?.resourceKey ?? name;
1520
1543
  const matches = (row) => row?.resourceKey === connection.resourceKey && row?.default === folderKey
1521
1544
  && row?.propertyAttribute === 'folderKey';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.46.6",
3
+ "version": "6.46.7",
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",
@@ -93,5 +93,5 @@
93
93
  "@types/node": "^22.7.0",
94
94
  "esbuild": "^0.28.1"
95
95
  },
96
- "gitref": "64e024e591ad47ef3ebcdebe54d8a07ead2aa871"
96
+ "gitref": "68e27a784a7d9b4fff5177074148d05e0c993a65"
97
97
  }