@uipath/common 1.1.0 → 1.195.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.
@@ -11,6 +11,14 @@ export interface ErrorDetails {
11
11
  details: string;
12
12
  /** Machine-readable context for agents (HTTP status, request ID, retry-after, etc.) */
13
13
  context?: ErrorContext;
14
+ /**
15
+ * Per-field validation errors lifted from an ASP.NET ProblemDetails body
16
+ * (application/problem+json). Shape: `{ fieldName: ["msg", ...] }`.
17
+ * Surfaced as `Errors` on the OutputFormatter envelope so agents can
18
+ * react to the specific field that failed validation instead of parsing
19
+ * the free-text Message.
20
+ */
21
+ parsedErrors?: Record<string, string[]>;
14
22
  }
15
23
  /**
16
24
  * Options for customising error extraction behaviour.
@@ -80,6 +80,14 @@ export declare class FailureOutput {
80
80
  Instructions: string;
81
81
  Context?: ErrorContext;
82
82
  Log?: string;
83
+ /**
84
+ * Optional structured payload for failure envelopes that need to carry
85
+ * actionable detail beyond the Message string (e.g. JobKey + JobState
86
+ * + SubState for the `jobs start --wait-for-completion` failure path).
87
+ * Mirrors SuccessOutput.Data so consumers can use a single accessor
88
+ * across success / failure paths.
89
+ */
90
+ Data?: DataRecord | DataRecord[];
83
91
  constructor(result: FailureResultType, message: string, instructions: string, context?: ErrorContext);
84
92
  }
85
93
  export type StructuredOutput = SuccessOutput | FailureOutput;
@@ -97,11 +105,47 @@ export type StructuredOutput = SuccessOutput | FailureOutput;
97
105
  * closed-box guarantee must additionally wrap {@link applyFilter}.
98
106
  */
99
107
  export declare function validateOutputFilter(filter: string): Error | null;
108
+ /**
109
+ * Thrown when a `--output-filter` expression parses successfully but fails at
110
+ * evaluation time (e.g. type-coercion errors when functions receive unexpected
111
+ * types). Carries `instructions` and `result` so {@link trackedAction} can
112
+ * surface filter-specific guidance through the failure envelope instead of the
113
+ * generic "unexpected error" fallback.
114
+ *
115
+ * Uses a duck-type `__brand` rather than relying on `instanceof`, because each
116
+ * tool bundles its own copy of `@uipath/common` and class identity differs
117
+ * across bundle boundaries.
118
+ */
119
+ export declare class FilterEvaluationError extends Error {
120
+ readonly __brand: "FilterEvaluationError";
121
+ readonly filter: string;
122
+ readonly instructions: string;
123
+ readonly result: FailureResultType;
124
+ constructor(filter: string, cause: unknown);
125
+ }
100
126
  /**
101
127
  * OutputFormatter namespace for formatting and displaying output.
102
128
  */
103
129
  export declare namespace OutputFormatter {
104
- function success(data: SuccessOutput): void;
130
+ /**
131
+ * Emit a success envelope.
132
+ *
133
+ * By default every key in `data.Data` is normalized to PascalCase for
134
+ * cross-command output consistency (see {@link normalizeDataKeys}).
135
+ *
136
+ * Pass `{ preserveDataKeys: true }` when the `Data` payload is content that
137
+ * is copied verbatim back into a UiPath artifact and whose key casing is
138
+ * therefore load-bearing — most notably `registry get` node definitions,
139
+ * whose camelCase field names (`inputDefinition`, `inputString`, …) are
140
+ * pasted straight into `.flow` files. PascalCasing those names produces a
141
+ * flow that passes `flow validate` but faults at runtime (the agent/job
142
+ * receives `InputString` while its schema requires `inputString`). With
143
+ * this flag the `Data` payload keeps its original casing; the envelope
144
+ * keys (`Result`/`Code`/`Data`/`Log`/…) are still PascalCased.
145
+ */
146
+ function success(data: SuccessOutput, options?: {
147
+ preserveDataKeys?: boolean;
148
+ }): void;
105
149
  /**
106
150
  * Format and display an error, then set {@link process.exitCode} to the
107
151
  * value from {@link EXIT_CODES} for `data.Result` (falls back to 1).
@@ -3387,10 +3387,15 @@ async function extractErrorDetails(error, options) {
3387
3387
  }
3388
3388
  if (parsedBody?.errorCode && typeof parsedBody.errorCode === "string") {
3389
3389
  context.errorCode = parsedBody.errorCode;
3390
+ } else if (parsedBody?.code && typeof parsedBody.code === "string") {
3391
+ context.errorCode = parsedBody.code;
3390
3392
  }
3391
3393
  if (parsedBody?.requestId && typeof parsedBody.requestId === "string") {
3392
3394
  context.requestId = parsedBody.requestId;
3393
3395
  }
3396
+ if (parsedBody?.traceId && typeof parsedBody.traceId === "string") {
3397
+ context.traceId = parsedBody.traceId;
3398
+ }
3394
3399
  if (status === 429) {
3395
3400
  const resp = response;
3396
3401
  const headersObj = resp?.headers;
@@ -3410,7 +3415,35 @@ async function extractErrorDetails(error, options) {
3410
3415
  }
3411
3416
  }
3412
3417
  const hasContext = Object.keys(context).length > 0;
3413
- return { result, message, details, ...hasContext ? { context } : {} };
3418
+ let parsedErrors;
3419
+ if (parsedBody?.errors && typeof parsedBody.errors === "object") {
3420
+ const errors = {};
3421
+ for (const [field, raw] of Object.entries(parsedBody.errors)) {
3422
+ if (Array.isArray(raw)) {
3423
+ const messages = raw.map((entry) => {
3424
+ if (typeof entry === "string")
3425
+ return entry;
3426
+ if (entry && typeof entry === "object" && typeof entry.message === "string") {
3427
+ return entry.message;
3428
+ }
3429
+ return String(entry);
3430
+ }).filter(Boolean);
3431
+ if (messages.length > 0)
3432
+ errors[field] = messages;
3433
+ } else if (typeof raw === "string") {
3434
+ errors[field] = [raw];
3435
+ }
3436
+ }
3437
+ if (Object.keys(errors).length > 0)
3438
+ parsedErrors = errors;
3439
+ }
3440
+ return {
3441
+ result,
3442
+ message,
3443
+ details,
3444
+ ...hasContext ? { context } : {},
3445
+ ...parsedErrors ? { parsedErrors } : {}
3446
+ };
3414
3447
  }
3415
3448
  async function extractErrorMessage(error, options) {
3416
3449
  const { message } = await extractErrorDetails(error, options);
@@ -5314,6 +5347,28 @@ var BACKOFF_DEFAULTS = {
5314
5347
  };
5315
5348
  var MIN_INTERVAL_MS = 100;
5316
5349
 
5350
+ // src/polling/poll-failure-mapping.ts
5351
+ var REASON_BY_OUTCOME = {
5352
+ [PollOutcome.Timeout]: "poll_timeout",
5353
+ [PollOutcome.Failed]: "poll_failed",
5354
+ [PollOutcome.Interrupted]: "poll_failed",
5355
+ [PollOutcome.Aborted]: "poll_aborted"
5356
+ };
5357
+ function mapPollFailure(pollResult, label) {
5358
+ const outcome = pollResult.outcome;
5359
+ const errMsg = pollResult.error?.message ?? "too many consecutive errors";
5360
+ const messageByOutcome = {
5361
+ [PollOutcome.Timeout]: `${label} polling timed out`,
5362
+ [PollOutcome.Failed]: `${label} polling failed: ${errMsg}`,
5363
+ [PollOutcome.Interrupted]: `${label} polling was interrupted`,
5364
+ [PollOutcome.Aborted]: `${label} polling was aborted`
5365
+ };
5366
+ return {
5367
+ reason: REASON_BY_OUTCOME[outcome],
5368
+ message: messageByOutcome[outcome],
5369
+ exitCode: outcome === PollOutcome.Timeout ? 2 : 1
5370
+ };
5371
+ }
5317
5372
  // src/polling/poll-until.ts
5318
5373
  function resolveIntervalFn(options) {
5319
5374
  if (typeof options.intervalMs === "function") {
@@ -5766,6 +5821,7 @@ export {
5766
5821
  parseLimit,
5767
5822
  parseBoundedInt,
5768
5823
  msToDuration,
5824
+ mapPollFailure,
5769
5825
  logger,
5770
5826
  isTerminalStatus,
5771
5827
  isSuccessStatus,
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export * from "./output-sink";
22
22
  export * from "./polling";
23
23
  export * from "./registry";
24
24
  export * from "./screen-logger";
25
+ export * from "./sdk-user-agent";
25
26
  export * from "./singleton";
26
27
  export * from "./telemetry/node.js";
27
28
  export { setGlobalTelemetryProperties } from "./telemetry/node-appinsights-telemetry-provider.js";
package/dist/index.js CHANGED
@@ -2126,6 +2126,7 @@ var require_commander = __commonJS((exports) => {
2126
2126
  });
2127
2127
 
2128
2128
  // ../filesystem/src/node.ts
2129
+ import { randomUUID } from "node:crypto";
2129
2130
  import { existsSync } from "node:fs";
2130
2131
  import * as fs6 from "node:fs/promises";
2131
2132
  import * as os2 from "node:os";
@@ -2742,6 +2743,13 @@ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
2742
2743
  var open_default = open;
2743
2744
 
2744
2745
  // ../filesystem/src/node.ts
2746
+ var LOCK_HEARTBEAT_MS = 5000;
2747
+ var LOCK_STALE_MS = 15000;
2748
+ var LOCK_MAX_WAIT_MS = 20000;
2749
+ var LOCK_MAX_HOLD_MS = 60000;
2750
+ var LOCK_RETRY_MIN_MS = 100;
2751
+ var LOCK_RETRY_JITTER_MS = 200;
2752
+
2745
2753
  class NodeFileSystem {
2746
2754
  path = {
2747
2755
  join: path2.join,
@@ -2818,6 +2826,90 @@ class NodeFileSystem {
2818
2826
  async mkdir(dirPath) {
2819
2827
  await fs6.mkdir(dirPath, { recursive: true });
2820
2828
  }
2829
+ async acquireLock(lockPath) {
2830
+ const canonicalPath = await this.canonicalizeLockTarget(lockPath);
2831
+ const lockFile = `${canonicalPath}.lock`;
2832
+ const ownerId = randomUUID();
2833
+ const start = Date.now();
2834
+ while (true) {
2835
+ try {
2836
+ await fs6.writeFile(lockFile, ownerId, { flag: "wx" });
2837
+ return this.createLockRelease(lockFile, ownerId);
2838
+ } catch (error) {
2839
+ if (!this.hasErrnoCode(error, "EEXIST")) {
2840
+ throw error;
2841
+ }
2842
+ const stats = await fs6.stat(lockFile).catch(() => null);
2843
+ if (stats && Date.now() - stats.mtimeMs > LOCK_STALE_MS) {
2844
+ const reclaimed = await fs6.rm(lockFile, { force: true }).then(() => true).catch(() => false);
2845
+ if (reclaimed)
2846
+ continue;
2847
+ }
2848
+ if (Date.now() - start > LOCK_MAX_WAIT_MS) {
2849
+ throw new Error(`ELOCKED: timed out waiting for lock on ${canonicalPath}`);
2850
+ }
2851
+ await new Promise((resolve2) => setTimeout(resolve2, LOCK_RETRY_MIN_MS + Math.random() * LOCK_RETRY_JITTER_MS));
2852
+ }
2853
+ }
2854
+ }
2855
+ async canonicalizeLockTarget(lockPath) {
2856
+ const absolute = path2.resolve(lockPath);
2857
+ const fullReal = await fs6.realpath(absolute).catch(() => null);
2858
+ if (fullReal)
2859
+ return fullReal;
2860
+ const parent = path2.dirname(absolute);
2861
+ const base = path2.basename(absolute);
2862
+ const canonicalParent = await fs6.realpath(parent).catch(() => parent);
2863
+ return path2.join(canonicalParent, base);
2864
+ }
2865
+ createLockRelease(lockFile, ownerId) {
2866
+ const heartbeatStart = Date.now();
2867
+ let heartbeatTimer;
2868
+ let stopped = false;
2869
+ const stopHeartbeat = () => {
2870
+ stopped = true;
2871
+ if (heartbeatTimer)
2872
+ clearTimeout(heartbeatTimer);
2873
+ };
2874
+ const scheduleNextHeartbeat = () => {
2875
+ if (stopped)
2876
+ return;
2877
+ if (Date.now() - heartbeatStart >= LOCK_MAX_HOLD_MS) {
2878
+ stopped = true;
2879
+ return;
2880
+ }
2881
+ heartbeatTimer = setTimeout(() => {
2882
+ runHeartbeat();
2883
+ }, LOCK_HEARTBEAT_MS);
2884
+ heartbeatTimer.unref?.();
2885
+ };
2886
+ const runHeartbeat = async () => {
2887
+ if (stopped)
2888
+ return;
2889
+ const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
2890
+ if (stopped)
2891
+ return;
2892
+ if (current !== ownerId) {
2893
+ stopped = true;
2894
+ return;
2895
+ }
2896
+ const now = Date.now() / 1000;
2897
+ await fs6.utimes(lockFile, now, now).catch(() => {});
2898
+ scheduleNextHeartbeat();
2899
+ };
2900
+ scheduleNextHeartbeat();
2901
+ let released = false;
2902
+ return async () => {
2903
+ if (released)
2904
+ return;
2905
+ released = true;
2906
+ stopHeartbeat();
2907
+ const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
2908
+ if (current === ownerId) {
2909
+ await fs6.rm(lockFile, { force: true });
2910
+ }
2911
+ };
2912
+ }
2821
2913
  async rm(filePath) {
2822
2914
  await fs6.rm(filePath, { recursive: true, force: true });
2823
2915
  }
@@ -2863,7 +2955,10 @@ class NodeFileSystem {
2863
2955
  }
2864
2956
  }
2865
2957
  isEnoent(error) {
2866
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
2958
+ return this.hasErrnoCode(error, "ENOENT");
2959
+ }
2960
+ hasErrnoCode(error, code) {
2961
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
2867
2962
  }
2868
2963
  }
2869
2964
 
@@ -3005,10 +3100,15 @@ async function extractErrorDetails(error, options) {
3005
3100
  }
3006
3101
  if (parsedBody?.errorCode && typeof parsedBody.errorCode === "string") {
3007
3102
  context.errorCode = parsedBody.errorCode;
3103
+ } else if (parsedBody?.code && typeof parsedBody.code === "string") {
3104
+ context.errorCode = parsedBody.code;
3008
3105
  }
3009
3106
  if (parsedBody?.requestId && typeof parsedBody.requestId === "string") {
3010
3107
  context.requestId = parsedBody.requestId;
3011
3108
  }
3109
+ if (parsedBody?.traceId && typeof parsedBody.traceId === "string") {
3110
+ context.traceId = parsedBody.traceId;
3111
+ }
3012
3112
  if (status === 429) {
3013
3113
  const resp = response;
3014
3114
  const headersObj = resp?.headers;
@@ -3028,7 +3128,35 @@ async function extractErrorDetails(error, options) {
3028
3128
  }
3029
3129
  }
3030
3130
  const hasContext = Object.keys(context).length > 0;
3031
- return { result, message, details, ...hasContext ? { context } : {} };
3131
+ let parsedErrors;
3132
+ if (parsedBody?.errors && typeof parsedBody.errors === "object") {
3133
+ const errors = {};
3134
+ for (const [field, raw] of Object.entries(parsedBody.errors)) {
3135
+ if (Array.isArray(raw)) {
3136
+ const messages = raw.map((entry) => {
3137
+ if (typeof entry === "string")
3138
+ return entry;
3139
+ if (entry && typeof entry === "object" && typeof entry.message === "string") {
3140
+ return entry.message;
3141
+ }
3142
+ return String(entry);
3143
+ }).filter(Boolean);
3144
+ if (messages.length > 0)
3145
+ errors[field] = messages;
3146
+ } else if (typeof raw === "string") {
3147
+ errors[field] = [raw];
3148
+ }
3149
+ }
3150
+ if (Object.keys(errors).length > 0)
3151
+ parsedErrors = errors;
3152
+ }
3153
+ return {
3154
+ result,
3155
+ message,
3156
+ details,
3157
+ ...hasContext ? { context } : {},
3158
+ ...parsedErrors ? { parsedErrors } : {}
3159
+ };
3032
3160
  }
3033
3161
  async function extractErrorMessage(error, options) {
3034
3162
  const { message } = await extractErrorDetails(error, options);
@@ -8943,6 +9071,7 @@ class FailureOutput {
8943
9071
  Instructions;
8944
9072
  Context;
8945
9073
  Log;
9074
+ Data;
8946
9075
  constructor(result, message, instructions, context) {
8947
9076
  this.Result = result;
8948
9077
  this.Message = message;
@@ -8965,6 +9094,60 @@ function escapeNonAscii(jsonText) {
8965
9094
  function needsAsciiSafeJson(sink) {
8966
9095
  return process.platform === "win32" && !sink.capabilities.isInteractive;
8967
9096
  }
9097
+ function isPlainRecord(value) {
9098
+ if (value === null || typeof value !== "object")
9099
+ return false;
9100
+ const prototype = Object.getPrototypeOf(value);
9101
+ return prototype === Object.prototype || prototype === null;
9102
+ }
9103
+ function toLowerCamelCaseKey(key) {
9104
+ if (!key)
9105
+ return key;
9106
+ if (/[_\-\s]/.test(key)) {
9107
+ const [firstPart, ...restParts] = key.split(/[_\-\s]+/).filter(Boolean);
9108
+ if (!firstPart)
9109
+ return key;
9110
+ return [
9111
+ toLowerCamelCaseSimpleKey(firstPart),
9112
+ ...restParts.map((part) => {
9113
+ const normalized = toLowerCamelCaseSimpleKey(part);
9114
+ return normalized.charAt(0).toUpperCase() + normalized.slice(1);
9115
+ })
9116
+ ].join("");
9117
+ }
9118
+ return toLowerCamelCaseSimpleKey(key);
9119
+ }
9120
+ function toLowerCamelCaseSimpleKey(key) {
9121
+ if (/^[A-Z0-9]+$/.test(key))
9122
+ return key.toLowerCase();
9123
+ return key.replace(/^[A-Z]+(?=[A-Z][a-z]|\d|$)|^[A-Z]/, (match) => match.toLowerCase());
9124
+ }
9125
+ function toPascalCaseKey(key) {
9126
+ const lowerCamelKey = toLowerCamelCaseKey(key);
9127
+ return lowerCamelKey ? lowerCamelKey.charAt(0).toUpperCase() + lowerCamelKey.slice(1) : lowerCamelKey;
9128
+ }
9129
+ function toPascalCaseData(value) {
9130
+ if (Array.isArray(value))
9131
+ return value.map(toPascalCaseData);
9132
+ if (!isPlainRecord(value))
9133
+ return value;
9134
+ const result = {};
9135
+ for (const [key, nestedValue] of Object.entries(value)) {
9136
+ result[toPascalCaseKey(key)] = toPascalCaseData(nestedValue);
9137
+ }
9138
+ return result;
9139
+ }
9140
+ function normalizeDataKeys(data) {
9141
+ return toPascalCaseData(data);
9142
+ }
9143
+ function normalizeOutputKeys(data) {
9144
+ const result = {};
9145
+ for (const [key, value] of Object.entries(data)) {
9146
+ const pascalKey = toPascalCaseKey(key);
9147
+ result[pascalKey] = pascalKey === "Data" ? value : toPascalCaseData(value);
9148
+ }
9149
+ return result;
9150
+ }
8968
9151
  function printOutput(data, format2 = "json", logFn, asciiSafe = false) {
8969
9152
  if (!data) {
8970
9153
  logFn("Empty response object. No data to display.");
@@ -9027,7 +9210,7 @@ function wrapText(text, width) {
9027
9210
  function printTable(data, logFn, externalLogValue) {
9028
9211
  if (data.length === 0)
9029
9212
  return;
9030
- const keys = Object.keys(data[0]).filter((key) => key !== "Code" && key !== "Log");
9213
+ const keys = Object.keys(data[0]).filter((key) => !["code", "log"].includes(key.toLowerCase()));
9031
9214
  const maxWidths = keys.map((key) => Math.max(key.length, ...data.map((item) => cellToString(item[key]).length)));
9032
9215
  const header = keys.map((key, i2) => key.padEnd(maxWidths[i2])).join(" | ");
9033
9216
  logFn(header);
@@ -9042,7 +9225,7 @@ function printTable(data, logFn, externalLogValue) {
9042
9225
  }
9043
9226
  }
9044
9227
  function printVerticalTable(data, logFn = console.log, externalLogValue) {
9045
- const keys = Object.keys(data).filter((key) => key !== "Code" && key !== "Log");
9228
+ const keys = Object.keys(data).filter((key) => !["code", "log"].includes(key.toLowerCase()));
9046
9229
  if (keys.length === 0)
9047
9230
  return;
9048
9231
  const maxKeyWidth = Math.max(...keys.map((key) => key.length));
@@ -9058,7 +9241,7 @@ function printVerticalTable(data, logFn = console.log, externalLogValue) {
9058
9241
  function printResizableTable(data, logFn = console.log, externalLogValue) {
9059
9242
  if (data.length === 0)
9060
9243
  return;
9061
- const keys = Object.keys(data[0]).filter((key) => key !== "Code" && key !== "Log");
9244
+ const keys = Object.keys(data[0]).filter((key) => !["code", "log"].includes(key.toLowerCase()));
9062
9245
  if (keys.length === 0)
9063
9246
  return;
9064
9247
  if (!process.stdout.isTTY) {
@@ -9142,8 +9325,27 @@ function validateOutputFilter(filter) {
9142
9325
  return err instanceof Error ? err : new Error(String(err));
9143
9326
  }
9144
9327
  }
9328
+
9329
+ class FilterEvaluationError extends Error {
9330
+ __brand = "FilterEvaluationError";
9331
+ filter;
9332
+ instructions;
9333
+ result = RESULTS.ValidationError;
9334
+ constructor(filter, cause) {
9335
+ const underlying = cause instanceof Error ? cause.message : String(cause);
9336
+ super(`Filter '${filter}' failed to evaluate: ${underlying}`);
9337
+ this.name = "FilterEvaluationError";
9338
+ this.filter = filter;
9339
+ this.instructions = `The --output-filter expression '${filter}' failed at evaluation time. ` + "Note that --output-filter operates on the 'Data' field of the envelope, not the full object. " + "For example, on a list result use 'length(@)' instead of 'Data | length(@)'.";
9340
+ }
9341
+ }
9145
9342
  function applyFilter(data, filter) {
9146
- const result = search(data, filter);
9343
+ let result;
9344
+ try {
9345
+ result = search(data, filter);
9346
+ } catch (err) {
9347
+ throw new FilterEvaluationError(filter, err);
9348
+ }
9147
9349
  if (result == null)
9148
9350
  return [];
9149
9351
  if (Array.isArray(result)) {
@@ -9160,13 +9362,18 @@ function applyFilter(data, filter) {
9160
9362
  }
9161
9363
  var OutputFormatter;
9162
9364
  ((OutputFormatter) => {
9163
- function success(data) {
9365
+ function success(data, options) {
9164
9366
  data.Log ??= getLogFilePath() || undefined;
9367
+ const normalize = !options?.preserveDataKeys;
9368
+ if (normalize) {
9369
+ data.Data = normalizeDataKeys(data.Data);
9370
+ }
9165
9371
  const filter = getOutputFilter();
9166
9372
  if (filter) {
9167
- data.Data = applyFilter(data.Data, filter);
9373
+ const filtered = applyFilter(data.Data, filter);
9374
+ data.Data = normalize ? normalizeDataKeys(filtered) : filtered;
9168
9375
  }
9169
- logOutput(data, getOutputFormat());
9376
+ logOutput(normalizeOutputKeys(data), getOutputFormat());
9170
9377
  }
9171
9378
  OutputFormatter.success = success;
9172
9379
  function error(data) {
@@ -9176,7 +9383,7 @@ var OutputFormatter;
9176
9383
  result: data.Result,
9177
9384
  message: data.Message
9178
9385
  });
9179
- logOutput(data, getOutputFormat());
9386
+ logOutput(normalizeOutputKeys(data), getOutputFormat());
9180
9387
  }
9181
9388
  OutputFormatter.error = error;
9182
9389
  function emitList(code, items, opts) {
@@ -9197,13 +9404,14 @@ var OutputFormatter;
9197
9404
  function log(data) {
9198
9405
  const format2 = getOutputFormat();
9199
9406
  const sink = getOutputSink();
9407
+ const normalized = toPascalCaseData(data);
9200
9408
  if (format2 === "json") {
9201
- const json2 = JSON.stringify(data);
9409
+ const json2 = JSON.stringify(normalized);
9202
9410
  const safe = needsAsciiSafeJson(sink) ? escapeNonAscii(json2) : json2;
9203
9411
  sink.writeErr(`${safe}
9204
9412
  `);
9205
9413
  } else {
9206
- for (const [key, value] of Object.entries(data)) {
9414
+ for (const [key, value] of Object.entries(normalized)) {
9207
9415
  sink.writeErr(`${key}: ${value}
9208
9416
  `);
9209
9417
  }
@@ -9212,12 +9420,16 @@ var OutputFormatter;
9212
9420
  OutputFormatter.log = log;
9213
9421
  function formatToString(data) {
9214
9422
  const filter = getOutputFilter();
9215
- if (filter && "Data" in data && data.Data != null) {
9216
- data.Data = applyFilter(data.Data, filter);
9423
+ if ("Data" in data && data.Data != null) {
9424
+ data.Data = normalizeDataKeys(data.Data);
9425
+ if (filter) {
9426
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
9427
+ }
9217
9428
  }
9429
+ const output = normalizeOutputKeys(data);
9218
9430
  const lines = [];
9219
9431
  const sink = getOutputSink();
9220
- printOutput(data, getOutputFormat(), (msg) => {
9432
+ printOutput(output, getOutputFormat(), (msg) => {
9221
9433
  lines.push(msg);
9222
9434
  }, needsAsciiSafeJson(sink));
9223
9435
  return lines.join(`
@@ -10828,6 +11040,28 @@ var BACKOFF_DEFAULTS = {
10828
11040
  };
10829
11041
  var MIN_INTERVAL_MS = 100;
10830
11042
 
11043
+ // src/polling/poll-failure-mapping.ts
11044
+ var REASON_BY_OUTCOME = {
11045
+ [PollOutcome.Timeout]: "poll_timeout",
11046
+ [PollOutcome.Failed]: "poll_failed",
11047
+ [PollOutcome.Interrupted]: "poll_failed",
11048
+ [PollOutcome.Aborted]: "poll_aborted"
11049
+ };
11050
+ function mapPollFailure(pollResult, label) {
11051
+ const outcome = pollResult.outcome;
11052
+ const errMsg = pollResult.error?.message ?? "too many consecutive errors";
11053
+ const messageByOutcome = {
11054
+ [PollOutcome.Timeout]: `${label} polling timed out`,
11055
+ [PollOutcome.Failed]: `${label} polling failed: ${errMsg}`,
11056
+ [PollOutcome.Interrupted]: `${label} polling was interrupted`,
11057
+ [PollOutcome.Aborted]: `${label} polling was aborted`
11058
+ };
11059
+ return {
11060
+ reason: REASON_BY_OUTCOME[outcome],
11061
+ message: messageByOutcome[outcome],
11062
+ exitCode: outcome === PollOutcome.Timeout ? 2 : 1
11063
+ };
11064
+ }
10831
11065
  // src/polling/poll-until.ts
10832
11066
  function resolveIntervalFn(options) {
10833
11067
  if (typeof options.intervalMs === "function") {
@@ -11244,6 +11478,112 @@ var ScreenLogger;
11244
11478
  }
11245
11479
  ScreenLogger.progress = progress;
11246
11480
  })(ScreenLogger ||= {});
11481
+ // src/sdk-user-agent.ts
11482
+ var USER_AGENT_HEADER = "User-Agent";
11483
+ var sdkUserAgentHostToken = singleton("SdkUserAgentHostToken");
11484
+ function userAgentPatchKey(userAgent) {
11485
+ return Symbol.for(`@uipath/common/sdk-user-agent/${userAgent}`);
11486
+ }
11487
+ function splitUserAgentTokens(value) {
11488
+ return value?.trim().split(/\s+/).filter(Boolean) ?? [];
11489
+ }
11490
+ function appendUserAgentToken(value, userAgent) {
11491
+ const tokens = splitUserAgentTokens(value);
11492
+ const seen = new Set(tokens);
11493
+ for (const token of splitUserAgentTokens(userAgent)) {
11494
+ if (!seen.has(token)) {
11495
+ tokens.push(token);
11496
+ seen.add(token);
11497
+ }
11498
+ }
11499
+ return tokens.join(" ");
11500
+ }
11501
+ function getEffectiveUserAgent(userAgent) {
11502
+ return appendUserAgentToken(sdkUserAgentHostToken.get(), userAgent);
11503
+ }
11504
+ function isHeadersLike(headers) {
11505
+ return typeof headers === "object" && headers !== null && "get" in headers && typeof headers.get === "function" && "set" in headers && typeof headers.set === "function";
11506
+ }
11507
+ function getSdkUserAgentToken(pkg) {
11508
+ const packageName = pkg.name.replace(/^@uipath\//, "");
11509
+ return getEffectiveUserAgent(`${packageName}/${pkg.version}`);
11510
+ }
11511
+ function setSdkUserAgentHostToken(token) {
11512
+ if (token === undefined) {
11513
+ sdkUserAgentHostToken.clear();
11514
+ return;
11515
+ }
11516
+ sdkUserAgentHostToken.set(token);
11517
+ }
11518
+ function addSdkUserAgentHeader(headers, userAgent) {
11519
+ const result = { ...headers ?? {} };
11520
+ const effectiveUserAgent = getEffectiveUserAgent(userAgent);
11521
+ const headerName = Object.keys(result).find((key) => key.toLowerCase() === USER_AGENT_HEADER.toLowerCase());
11522
+ if (headerName) {
11523
+ result[headerName] = appendUserAgentToken(result[headerName], effectiveUserAgent);
11524
+ } else {
11525
+ result[USER_AGENT_HEADER] = effectiveUserAgent;
11526
+ }
11527
+ return result;
11528
+ }
11529
+ function withSdkUserAgentHeader(headers, userAgent) {
11530
+ const effectiveUserAgent = getEffectiveUserAgent(userAgent);
11531
+ if (isHeadersLike(headers)) {
11532
+ headers.set(USER_AGENT_HEADER, appendUserAgentToken(headers.get(USER_AGENT_HEADER), effectiveUserAgent));
11533
+ return headers;
11534
+ }
11535
+ if (Array.isArray(headers)) {
11536
+ const result = headers.map((entry) => {
11537
+ const [key, value] = entry;
11538
+ return [key, value];
11539
+ });
11540
+ const headerIndex = result.findIndex(([key]) => key.toLowerCase() === USER_AGENT_HEADER.toLowerCase());
11541
+ if (headerIndex >= 0) {
11542
+ const [key, value] = result[headerIndex];
11543
+ result[headerIndex] = [
11544
+ key,
11545
+ appendUserAgentToken(value, effectiveUserAgent)
11546
+ ];
11547
+ } else {
11548
+ result.push([USER_AGENT_HEADER, effectiveUserAgent]);
11549
+ }
11550
+ return result;
11551
+ }
11552
+ return addSdkUserAgentHeader(typeof headers === "object" && headers !== null ? { ...headers } : {}, effectiveUserAgent);
11553
+ }
11554
+ function withUserAgentInitOverride(initOverrides, userAgent) {
11555
+ return async (requestContext) => {
11556
+ const initWithUserAgent = {
11557
+ ...requestContext.init,
11558
+ headers: withSdkUserAgentHeader(requestContext.init.headers, userAgent)
11559
+ };
11560
+ const override = typeof initOverrides === "function" ? await initOverrides({
11561
+ ...requestContext,
11562
+ init: initWithUserAgent
11563
+ }) : initOverrides;
11564
+ return {
11565
+ ...override ?? {},
11566
+ headers: withSdkUserAgentHeader(override?.headers ?? initWithUserAgent.headers, userAgent)
11567
+ };
11568
+ };
11569
+ }
11570
+ function installSdkUserAgentHeader(BaseApiClass, userAgent) {
11571
+ const prototype = BaseApiClass.prototype;
11572
+ const patchKey = userAgentPatchKey(userAgent);
11573
+ if (prototype[patchKey]) {
11574
+ return;
11575
+ }
11576
+ if (typeof prototype.request !== "function") {
11577
+ throw new Error("Generated BaseAPI request function not found.");
11578
+ }
11579
+ const originalRequest = prototype.request;
11580
+ prototype.request = function requestWithUserAgent(context, initOverrides) {
11581
+ return originalRequest.call(this, context, withUserAgentInitOverride(initOverrides, userAgent));
11582
+ };
11583
+ Object.defineProperty(prototype, patchKey, {
11584
+ value: true
11585
+ });
11586
+ }
11247
11587
  // src/tool-provider.ts
11248
11588
  var factorySlot = singleton("PackagerFactoryProvider");
11249
11589
  function setPackagerFactoryProvider(provider) {
@@ -11439,13 +11779,17 @@ Command.prototype.trackedAction = function(context, fn, properties) {
11439
11779
  const [error] = await catchError(fn(...args));
11440
11780
  if (error) {
11441
11781
  errorMessage = error instanceof Error ? error.message : String(error);
11442
- logger.error(`[trackedAction] ${telemetryName} failed: ${errorMessage}`);
11782
+ logger.debug(`[trackedAction] ${telemetryName} failed: ${errorMessage}`);
11783
+ const typed = error;
11784
+ const customInstructions = typeof typed.instructions === "string" ? typed.instructions : undefined;
11785
+ const customResult = typeof typed.result === "string" && typed.result !== RESULTS.Success && Object.values(RESULTS).includes(typed.result) ? typed.result : undefined;
11786
+ const finalResult = customResult ?? RESULTS.Failure;
11443
11787
  OutputFormatter.error({
11444
- Result: RESULTS.Failure,
11788
+ Result: finalResult,
11445
11789
  Message: errorMessage,
11446
- Instructions: "An unexpected error occurred. Run with --log-level debug for details."
11790
+ Instructions: customInstructions ?? "An unexpected error occurred. Run with --log-level debug for details."
11447
11791
  });
11448
- context.exit(1);
11792
+ context.exit(EXIT_CODES[finalResult]);
11449
11793
  }
11450
11794
  const durationMs = performance.now() - startTime;
11451
11795
  const success = !error && (process.exitCode === undefined || process.exitCode === 0);
@@ -11459,6 +11803,7 @@ Command.prototype.trackedAction = function(context, fn, properties) {
11459
11803
  });
11460
11804
  };
11461
11805
  export {
11806
+ withSdkUserAgentHeader,
11462
11807
  withCompleter,
11463
11808
  warnDeprecatedTenantOption,
11464
11809
  warnDeprecatedOptionAlias,
@@ -11467,6 +11812,7 @@ export {
11467
11812
  telemetryFlushAndShutdown,
11468
11813
  telemetry,
11469
11814
  singleton,
11815
+ setSdkUserAgentHostToken,
11470
11816
  setProcessContextPollSignal,
11471
11817
  setPackagerFactoryProvider,
11472
11818
  setOutputFormatExplicit,
@@ -11491,6 +11837,7 @@ export {
11491
11837
  parseBoundedInt,
11492
11838
  parseAttachmentSpec,
11493
11839
  msToDuration,
11840
+ mapPollFailure,
11494
11841
  logger,
11495
11842
  isTerminalStatus,
11496
11843
  isTelemetryDisabled,
@@ -11499,7 +11846,9 @@ export {
11499
11846
  isGuid,
11500
11847
  isFailureStatus,
11501
11848
  instructionsFor,
11849
+ installSdkUserAgentHeader,
11502
11850
  installConsoleGuard,
11851
+ getSdkUserAgentToken,
11503
11852
  getOutputSink,
11504
11853
  getOutputFormatExplicit,
11505
11854
  getOutputFormat,
@@ -11528,6 +11877,7 @@ export {
11528
11877
  buildActionCenterTaskUrl,
11529
11878
  buildActionCenterInboxUrl,
11530
11879
  appendOption,
11880
+ addSdkUserAgentHeader,
11531
11881
  addHiddenDeprecatedTenantOption,
11532
11882
  UIPATH_HOME_DIR,
11533
11883
  TelemetryService,
@@ -11542,6 +11892,7 @@ export {
11542
11892
  MIN_INTERVAL_MS,
11543
11893
  LogLevel,
11544
11894
  JsonPathError,
11895
+ FilterEvaluationError,
11545
11896
  FailureOutput,
11546
11897
  ErrorDecision,
11547
11898
  EXIT_CODES,
@@ -19,8 +19,7 @@
19
19
  *
20
20
  * The `path` argument on {@link buildOrchestratorUrl} is left as a string
21
21
  * **without** automatic encoding so callers can include OData filter syntax
22
- * and existing URL-encoded query strings; this matches the existing inline
23
- * pattern used in `solution-tool/src/services/apps-binding-sync.ts`.
22
+ * and existing URL-encoded query strings.
24
23
  *
25
24
  * For the Studio Web URL pattern (`/{org}/studio_/...`) — which has no
26
25
  * tenant segment by design — see `packages/maestro-sdk` instead. That
@@ -1,5 +1,7 @@
1
1
  export { createPollAbortController } from "./abort-controller";
2
2
  export { msToDuration } from "./format-utils";
3
+ export type { PollFailureMapped, PollFailureReason, } from "./poll-failure-mapping";
4
+ export { mapPollFailure } from "./poll-failure-mapping";
3
5
  export { pollUntil } from "./poll-until";
4
6
  export { isFailureStatus, isSuccessStatus, isTerminalStatus, } from "./terminal-statuses";
5
7
  export type { BackoffConfig, OnErrorCallback, PollContext, PollUntilOptions, PollUntilResult, } from "./types";
@@ -0,0 +1,21 @@
1
+ import { PollOutcome } from "./types";
2
+ /** Canonical taxonomy for poll-loop failures; library callers branch on this without parsing the message. */
3
+ export type PollFailureReason = "poll_timeout" | "poll_failed" | "poll_aborted";
4
+ export interface PollFailureMapped {
5
+ reason: PollFailureReason;
6
+ /** `${label} polling {timed out | failed: <err> | was interrupted | was aborted}`. */
7
+ message: string;
8
+ /** `2` for Timeout, `1` otherwise. */
9
+ exitCode: number;
10
+ }
11
+ /**
12
+ * Maps a non-completed `pollUntil` result to `{ reason, message, exitCode }`.
13
+ * `label` prefixes the message (e.g. `"Deployment"` → `"Deployment polling timed out"`).
14
+ * Caller must check the outcome is non-completed before invoking.
15
+ */
16
+ export declare function mapPollFailure(pollResult: {
17
+ outcome: PollOutcome;
18
+ error?: {
19
+ message?: string;
20
+ };
21
+ }, label: string): PollFailureMapped;
package/package.json CHANGED
@@ -1,50 +1,45 @@
1
1
  {
2
- "name": "@uipath/common",
3
- "version": "1.1.0",
4
- "description": "Common infrastructure needed by uip tools.",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/UiPath/cli.git",
8
- "directory": "packages/common"
2
+ "name": "@uipath/common",
3
+ "license": "MIT",
4
+ "version": "1.195.0",
5
+ "description": "Common infrastructure needed by uip tools.",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/UiPath/cli.git",
9
+ "directory": "packages/common"
10
+ },
11
+ "publishConfig": {
12
+ "registry": "https://registry.npmjs.org/"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "exports": {
17
+ ".": {
18
+ "browser": {
19
+ "types": "./dist/index.browser.d.ts",
20
+ "default": "./dist/index.browser.js"
21
+ },
22
+ "default": {
23
+ "types": "./dist/index.d.ts",
24
+ "default": "./dist/index.js"
25
+ }
9
26
  },
10
- "publishConfig": {
11
- "registry": "https://registry.npmjs.org/"
27
+ "./sdk-user-agent": {
28
+ "types": "./dist/sdk-user-agent.d.ts",
29
+ "default": "./dist/sdk-user-agent.js"
12
30
  },
13
- "type": "module",
14
- "main": "./dist/index.js",
15
- "exports": {
16
- ".": {
17
- "browser": {
18
- "types": "./dist/index.browser.d.ts",
19
- "default": "./dist/index.browser.js"
20
- },
21
- "default": {
22
- "types": "./dist/index.d.ts",
23
- "default": "./dist/index.js"
24
- }
25
- },
26
- "./telemetry": {
27
- "types": "./dist/telemetry/index.d.ts",
28
- "default": "./dist/telemetry/index.js"
29
- }
30
- },
31
- "files": [
32
- "dist"
33
- ],
34
- "maintainers": [
35
- "aoltean16",
36
- "mihaigirleanu",
37
- "vlad-uipath"
38
- ],
39
- "devDependencies": {
40
- "@jmespath-community/jmespath": "^1.3.0",
41
- "@types/js-yaml": "^4.0.9",
42
- "@types/node": "^25.5.2",
43
- "@uipath/filesystem": "1.1.0",
44
- "commander": "^14.0.3",
45
- "js-yaml": "^4.1.0",
46
- "jsonpath-plus": "^10.4.0",
47
- "typescript": "^6.0.2"
48
- },
49
- "gitHead": "06e8c8f566df4b87da4a008635483c62f64f33f0"
31
+ "./telemetry": {
32
+ "types": "./dist/telemetry/index.d.ts",
33
+ "default": "./dist/telemetry/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "maintainers": [
40
+ "aoltean16",
41
+ "mihaigirleanu",
42
+ "vlad-uipath"
43
+ ],
44
+ "gitHead": "65fabb84552758b2710d8ca68470e70a9b1d19bc"
50
45
  }