@uipath/maestro-builder-sdk 6.49.1 → 6.49.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.
@@ -106,10 +106,12 @@ export function buildConnectorInputs(rc, inputs, opts) {
106
106
  // container the runtime composes from `bodyParameters`, so it is listed without
107
107
  // a value and is never an author input — see `readFields` in core/library.ts.
108
108
  const partValues = new Map();
109
+ const bare = bareArraySpellings(fields, byName);
109
110
  for (const f of fields) {
110
- const flat = Object.prototype.hasOwnProperty.call(inputs, f.name);
111
+ const flatKey = flatInputKey(inputs, f.name, bare, dialect);
112
+ const flat = flatKey !== undefined;
111
113
  let nested = flat
112
- ? { found: true, value: inputs[f.name], projectedArrays: 0 }
114
+ ? { found: true, value: inputs[flatKey], projectedArrays: 0 }
113
115
  : readConnectorPath(inputs, f.name, dialect);
114
116
  if (!nested.found) {
115
117
  // A required LOOKUP field is missing far more often because the author does
@@ -326,6 +328,51 @@ function place(target, parts, index, value) {
326
328
  target[part.key] = next;
327
329
  place(next, parts, index + 1, value);
328
330
  }
331
+ /**
332
+ * The flat key the product writes for each array LEAF field, by its wire name:
333
+ * `fields.components_arrayRemap_name` for `fields.components_arrayRemap_name[*]`.
334
+ *
335
+ * Product-authored flows key `bodyParameters` either way (86 Slack
336
+ * `create-group-direct-message` nodes in the eval archive, almost all from the v1
337
+ * CLI arm, carry bare `users`; 85 carry `users[*]`; a Studio Web save in
338
+ * #1402 carried a bare Jira key), and the runtime reads both the same for an array
339
+ * value (flow-v1 `convertDotNotationToNested`). The nested reader already strips
340
+ * the marker, so `{ users: [...] }` compiled, but a DOTTED bare key reached only
341
+ * the exact flat lookup and was refused as unknown — so a designer-saved Jira
342
+ * flow decompiled to source that did not compile back (#1402).
343
+ *
344
+ * Only a trailing `[*]` with none before it: `contacts.id` is not `contacts[*].id`
345
+ * (the runtime nests it as an object, not a list). A bare name that is itself a
346
+ * declared field keeps its own meaning.
347
+ */
348
+ function bareArraySpellings(fields, declared) {
349
+ const bare = new Map();
350
+ for (const f of fields) {
351
+ if (!f.name.endsWith('[*]'))
352
+ continue;
353
+ const key = f.name.slice(0, -3);
354
+ if (key.includes('[*]') || declared.has(key))
355
+ continue;
356
+ bare.set(f.name, key);
357
+ }
358
+ return bare;
359
+ }
360
+ /**
361
+ * The flat key `inputs` carries field `name` under: its wire name, or its bare
362
+ * spelling when the value there is an array or opaque. A bare SCALAR is left to
363
+ * the nested reader, which refuses it ("expected array"), as before: under
364
+ * `users[*]` the runtime would wrap `"U1,U2"` into `["U1,U2"]`, a different
365
+ * request from the one the bare key sends.
366
+ */
367
+ function flatInputKey(inputs, name, bare, dialect) {
368
+ if (Object.prototype.hasOwnProperty.call(inputs, name))
369
+ return name;
370
+ const key = bare.get(name);
371
+ if (key === undefined || !Object.prototype.hasOwnProperty.call(inputs, key))
372
+ return undefined;
373
+ const value = inputs[key];
374
+ return Array.isArray(value) || dialect.isOpaque(value) ? key : undefined;
375
+ }
329
376
  function connectorPath(name) {
330
377
  return name.split('.').map((raw) => ({
331
378
  key: raw.endsWith('[*]') ? raw.slice(0, -3) : raw,
@@ -385,6 +432,7 @@ function buildConnectorInputTrie(fields) {
385
432
  function validateNestedConnectorKeys(fields, inputs, exact, dialect) {
386
433
  const root = buildConnectorInputTrie(fields);
387
434
  const errs = [];
435
+ const bare = new Set(bareArraySpellings(fields, exact).values());
388
436
  const visit = (value, node, path) => {
389
437
  if (dialect.isOpaque(value))
390
438
  return;
@@ -422,6 +470,13 @@ function validateNestedConnectorKeys(fields, inputs, exact, dialect) {
422
470
  if (exact.has(key))
423
471
  continue; // backwards-compatible flat authoring
424
472
  const node = root.children.get(key);
473
+ // A dotted bare array key (`fields.labels` for `fields.labels[*]`); a
474
+ // top-level one (`users`) is a trie child and is checked by `visit` below.
475
+ if (!node && bare.has(key)) {
476
+ if (!Array.isArray(value) && !dialect.isOpaque(value))
477
+ errs.push(`input "${key}" expected array, got ${typeof value}`);
478
+ continue;
479
+ }
425
480
  if (!node) {
426
481
  const near = nearestField(key, [...exact.keys()]);
427
482
  errs.push(`unknown input "${key}"${near ? ` — did you mean "${near}"?` : ''}`);
@@ -0,0 +1,14 @@
1
+ import type { UipClient } from "../uip/client.js";
2
+ /**
3
+ * Set by `uip` for the processes it starts: the login profile the run is for.
4
+ * Empty or unset means the default login.
5
+ */
6
+ export declare const INHERITED_PROFILE_ENV = "UIPATH_CLI_INHERITED_PROFILE";
7
+ /**
8
+ * Refuse unless the `uip` on PATH answers as `profile`.
9
+ *
10
+ * A `uip` older than {@link INHERITED_PROFILE_ENV} ignores it and reads the
11
+ * default login, which can be another customer's tenant, and nothing downstream
12
+ * notices (UiPath/cli#5485).
13
+ */
14
+ export declare function assertInheritedProfile(client: UipClient, profile: string): Promise<void>;
@@ -0,0 +1,28 @@
1
+ import { Refusal } from "../errors.js";
2
+ import { loginStatus } from "../uip/commands.js";
3
+ import { failureReason, getCI, parseEnvelope } from "../uip/envelope.js";
4
+ /**
5
+ * Set by `uip` for the processes it starts: the login profile the run is for.
6
+ * Empty or unset means the default login.
7
+ */
8
+ export const INHERITED_PROFILE_ENV = "UIPATH_CLI_INHERITED_PROFILE";
9
+ /**
10
+ * Refuse unless the `uip` on PATH answers as `profile`.
11
+ *
12
+ * A `uip` older than {@link INHERITED_PROFILE_ENV} ignores it and reads the
13
+ * default login, which can be another customer's tenant, and nothing downstream
14
+ * notices (UiPath/cli#5485).
15
+ */
16
+ export async function assertInheritedProfile(client, profile) {
17
+ const result = await client.run(loginStatus());
18
+ const data = result.code === 0 ? getCI(parseEnvelope(result.stdout), "Data") : undefined;
19
+ if (data === undefined) {
20
+ throw new Refusal(`could not confirm login profile "${profile}": ${failureReason(result)}`, "PROFILE_UNCONFIRMED");
21
+ }
22
+ const actual = getCI(data, "Profile");
23
+ if (actual === profile)
24
+ return;
25
+ const answeredAs = typeof actual === "string" ? `profile "${actual}"` : "the default login";
26
+ const tenant = `${String(getCI(data, "Organization"))}/${String(getCI(data, "Tenant"))}`;
27
+ throw new Refusal(`this run is for login profile "${profile}", but the uip on PATH answers as ${answeredAs} (${tenant}). Run 'uip update', then retry.`, "PROFILE_MISMATCH");
28
+ }
@@ -2,6 +2,7 @@ import { resolve } from 'node:path';
2
2
  import { reportResult } from '../cli-result.js';
3
3
  import { PACKAGE_NAME } from "../package-name.js";
4
4
  import { exitCodeOf } from "./errors.js";
5
+ import { assertInheritedProfile, INHERITED_PROFILE_ENV } from "./prepare/inherited-profile.js";
5
6
  import { exitText } from "./prepare/messages.js";
6
7
  import { defaultOverlayOut, prepareConnector as runPipeline } from "./prepare/pipeline.js";
7
8
  import { consoleReporter } from "./reporter.js";
@@ -64,6 +65,9 @@ export async function prepareConnector(options) {
64
65
  // once, as a warning, and the calls spawn as they did before.
65
66
  const client = defaultUipClient({ host: { onFallback: (reason) => consoleReporter.warn(` WARN: ${reason}`) } });
66
67
  try {
68
+ const profile = process.env[INHERITED_PROFILE_ENV];
69
+ if (profile)
70
+ await assertInheritedProfile(client, profile);
67
71
  return await runPipeline(pipelineOptions(options), {
68
72
  client,
69
73
  reporter: consoleReporter,
@@ -15,6 +15,7 @@ export declare const UIP = "uip";
15
15
  export declare function connectionArgs(connectionId?: string): string[];
16
16
  /** `-f name=value` per parent field, in the order given. */
17
17
  export declare function fieldArgs(parentFields: ReadonlyMap<string, string> | Readonly<Record<string, string>> | undefined): string[];
18
+ export declare function loginStatus(): string[];
18
19
  export declare function registrySearchConnectors(): string[];
19
20
  export declare function registrySearch(query: string): string[];
20
21
  /**
@@ -22,6 +22,9 @@ export function fieldArgs(parentFields) {
22
22
  const entries = parentFields instanceof Map ? [...parentFields.entries()] : Object.entries(parentFields);
23
23
  return entries.flatMap(([name, value]) => ["-f", `${name}=${value}`]);
24
24
  }
25
+ export function loginStatus() {
26
+ return [UIP, "login", "status", "--output", "json"];
27
+ }
25
28
  export function registrySearchConnectors() {
26
29
  return [UIP, "maestro", "flow", "registry", "search", "--filter", "tags:in=connector", "--output", "json"];
27
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.49.1",
3
+ "version": "6.49.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": "784ae01c8e59d695dc0c711a7ff1be52dda3c98f"
95
+ "gitref": "0187c4bea37cd0a8fd78aae6125b040583097f96"
96
96
  }