@uipath/apms-tool 1.1.0 → 1.2.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 (3) hide show
  1. package/dist/index.js +655 -151
  2. package/dist/tool.js +655 -151
  3. package/package.json +28 -36
package/dist/tool.js CHANGED
@@ -706,6 +706,7 @@ var init_open = __esm(() => {
706
706
  });
707
707
 
708
708
  // ../../filesystem/src/node.ts
709
+ import { randomUUID } from "node:crypto";
709
710
  import { existsSync } from "node:fs";
710
711
  import * as fs6 from "node:fs/promises";
711
712
  import * as os2 from "node:os";
@@ -787,6 +788,90 @@ class NodeFileSystem {
787
788
  async mkdir(dirPath) {
788
789
  await fs6.mkdir(dirPath, { recursive: true });
789
790
  }
791
+ async acquireLock(lockPath) {
792
+ const canonicalPath = await this.canonicalizeLockTarget(lockPath);
793
+ const lockFile = `${canonicalPath}.lock`;
794
+ const ownerId = randomUUID();
795
+ const start = Date.now();
796
+ while (true) {
797
+ try {
798
+ await fs6.writeFile(lockFile, ownerId, { flag: "wx" });
799
+ return this.createLockRelease(lockFile, ownerId);
800
+ } catch (error) {
801
+ if (!this.hasErrnoCode(error, "EEXIST")) {
802
+ throw error;
803
+ }
804
+ const stats = await fs6.stat(lockFile).catch(() => null);
805
+ if (stats && Date.now() - stats.mtimeMs > LOCK_STALE_MS) {
806
+ const reclaimed = await fs6.rm(lockFile, { force: true }).then(() => true).catch(() => false);
807
+ if (reclaimed)
808
+ continue;
809
+ }
810
+ if (Date.now() - start > LOCK_MAX_WAIT_MS) {
811
+ throw new Error(`ELOCKED: timed out waiting for lock on ${canonicalPath}`);
812
+ }
813
+ await new Promise((resolve2) => setTimeout(resolve2, LOCK_RETRY_MIN_MS + Math.random() * LOCK_RETRY_JITTER_MS));
814
+ }
815
+ }
816
+ }
817
+ async canonicalizeLockTarget(lockPath) {
818
+ const absolute = path2.resolve(lockPath);
819
+ const fullReal = await fs6.realpath(absolute).catch(() => null);
820
+ if (fullReal)
821
+ return fullReal;
822
+ const parent = path2.dirname(absolute);
823
+ const base = path2.basename(absolute);
824
+ const canonicalParent = await fs6.realpath(parent).catch(() => parent);
825
+ return path2.join(canonicalParent, base);
826
+ }
827
+ createLockRelease(lockFile, ownerId) {
828
+ const heartbeatStart = Date.now();
829
+ let heartbeatTimer;
830
+ let stopped = false;
831
+ const stopHeartbeat = () => {
832
+ stopped = true;
833
+ if (heartbeatTimer)
834
+ clearTimeout(heartbeatTimer);
835
+ };
836
+ const scheduleNextHeartbeat = () => {
837
+ if (stopped)
838
+ return;
839
+ if (Date.now() - heartbeatStart >= LOCK_MAX_HOLD_MS) {
840
+ stopped = true;
841
+ return;
842
+ }
843
+ heartbeatTimer = setTimeout(() => {
844
+ runHeartbeat();
845
+ }, LOCK_HEARTBEAT_MS);
846
+ heartbeatTimer.unref?.();
847
+ };
848
+ const runHeartbeat = async () => {
849
+ if (stopped)
850
+ return;
851
+ const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
852
+ if (stopped)
853
+ return;
854
+ if (current !== ownerId) {
855
+ stopped = true;
856
+ return;
857
+ }
858
+ const now = Date.now() / 1000;
859
+ await fs6.utimes(lockFile, now, now).catch(() => {});
860
+ scheduleNextHeartbeat();
861
+ };
862
+ scheduleNextHeartbeat();
863
+ let released = false;
864
+ return async () => {
865
+ if (released)
866
+ return;
867
+ released = true;
868
+ stopHeartbeat();
869
+ const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
870
+ if (current === ownerId) {
871
+ await fs6.rm(lockFile, { force: true });
872
+ }
873
+ };
874
+ }
790
875
  async rm(filePath) {
791
876
  await fs6.rm(filePath, { recursive: true, force: true });
792
877
  }
@@ -832,9 +917,13 @@ class NodeFileSystem {
832
917
  }
833
918
  }
834
919
  isEnoent(error) {
835
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
920
+ return this.hasErrnoCode(error, "ENOENT");
921
+ }
922
+ hasErrnoCode(error, code) {
923
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
836
924
  }
837
925
  }
926
+ var LOCK_HEARTBEAT_MS = 5000, LOCK_STALE_MS = 15000, LOCK_MAX_WAIT_MS = 20000, LOCK_MAX_HOLD_MS = 60000, LOCK_RETRY_MIN_MS = 100, LOCK_RETRY_JITTER_MS = 200;
838
927
  var init_node = __esm(() => {
839
928
  init_open();
840
929
  });
@@ -848,7 +937,7 @@ var init_src = __esm(() => {
848
937
 
849
938
  // ../../../node_modules/@uipath/coreipc/index.js
850
939
  var require_coreipc = __commonJS((exports, module) => {
851
- var __dirname = "/Users/alexandru.oltean/github/cli/node_modules/@uipath/coreipc";
940
+ var __dirname = "/home/runner/work/cli/cli/node_modules/@uipath/coreipc";
852
941
  /*! For license information please see index.js.LICENSE.txt */
853
942
  (function(e, t) {
854
943
  typeof exports == "object" && typeof module == "object" ? module.exports = t() : typeof define == "function" && define.amd ? define([], t) : typeof exports == "object" ? exports.ipc = t() : e.ipc = t();
@@ -19040,10 +19129,15 @@ var require_dist = __commonJS((exports) => {
19040
19129
  exports.RobotProxyConstructor = RobotProxyConstructor;
19041
19130
  __exportStar(require_agent(), exports);
19042
19131
  });
19132
+ // ../../auth/src/server.ts
19133
+ var init_server = __esm(() => {
19134
+ init_constants();
19135
+ });
19043
19136
  // package.json
19044
19137
  var package_default = {
19045
19138
  name: "@uipath/apms-tool",
19046
- version: "1.1.0",
19139
+ license: "MIT",
19140
+ version: "1.2.0",
19047
19141
  description: "CLI plugin for the UiPath Access Policy Management Service.",
19048
19142
  private: false,
19049
19143
  repository: {
@@ -19087,6 +19181,136 @@ var package_default = {
19087
19181
  }
19088
19182
  };
19089
19183
 
19184
+ // ../../common/src/singleton.ts
19185
+ var PREFIX = "@uipath/common/";
19186
+ var _g = globalThis;
19187
+ function singleton(ctorOrName) {
19188
+ const name = typeof ctorOrName === "string" ? ctorOrName : ctorOrName.name;
19189
+ const key = Symbol.for(PREFIX + name);
19190
+ return {
19191
+ get(fallback) {
19192
+ return _g[key] ?? fallback;
19193
+ },
19194
+ set(value) {
19195
+ _g[key] = value;
19196
+ },
19197
+ clear() {
19198
+ delete _g[key];
19199
+ },
19200
+ getOrInit(factory, guard) {
19201
+ const existing = _g[key];
19202
+ if (existing != null && typeof existing === "object") {
19203
+ if (!guard || guard(existing)) {
19204
+ return existing;
19205
+ }
19206
+ }
19207
+ const instance = factory();
19208
+ _g[key] = instance;
19209
+ return instance;
19210
+ }
19211
+ };
19212
+ }
19213
+
19214
+ // ../../common/src/sdk-user-agent.ts
19215
+ var USER_AGENT_HEADER = "User-Agent";
19216
+ var sdkUserAgentHostToken = singleton("SdkUserAgentHostToken");
19217
+ function userAgentPatchKey(userAgent) {
19218
+ return Symbol.for(`@uipath/common/sdk-user-agent/${userAgent}`);
19219
+ }
19220
+ function splitUserAgentTokens(value) {
19221
+ return value?.trim().split(/\s+/).filter(Boolean) ?? [];
19222
+ }
19223
+ function appendUserAgentToken(value, userAgent) {
19224
+ const tokens = splitUserAgentTokens(value);
19225
+ const seen = new Set(tokens);
19226
+ for (const token of splitUserAgentTokens(userAgent)) {
19227
+ if (!seen.has(token)) {
19228
+ tokens.push(token);
19229
+ seen.add(token);
19230
+ }
19231
+ }
19232
+ return tokens.join(" ");
19233
+ }
19234
+ function getEffectiveUserAgent(userAgent) {
19235
+ return appendUserAgentToken(sdkUserAgentHostToken.get(), userAgent);
19236
+ }
19237
+ function isHeadersLike(headers) {
19238
+ return typeof headers === "object" && headers !== null && "get" in headers && typeof headers.get === "function" && "set" in headers && typeof headers.set === "function";
19239
+ }
19240
+ function getSdkUserAgentToken(pkg) {
19241
+ const packageName = pkg.name.replace(/^@uipath\//, "");
19242
+ return getEffectiveUserAgent(`${packageName}/${pkg.version}`);
19243
+ }
19244
+ function addSdkUserAgentHeader(headers, userAgent) {
19245
+ const result = { ...headers ?? {} };
19246
+ const effectiveUserAgent = getEffectiveUserAgent(userAgent);
19247
+ const headerName = Object.keys(result).find((key) => key.toLowerCase() === USER_AGENT_HEADER.toLowerCase());
19248
+ if (headerName) {
19249
+ result[headerName] = appendUserAgentToken(result[headerName], effectiveUserAgent);
19250
+ } else {
19251
+ result[USER_AGENT_HEADER] = effectiveUserAgent;
19252
+ }
19253
+ return result;
19254
+ }
19255
+ function withSdkUserAgentHeader(headers, userAgent) {
19256
+ const effectiveUserAgent = getEffectiveUserAgent(userAgent);
19257
+ if (isHeadersLike(headers)) {
19258
+ headers.set(USER_AGENT_HEADER, appendUserAgentToken(headers.get(USER_AGENT_HEADER), effectiveUserAgent));
19259
+ return headers;
19260
+ }
19261
+ if (Array.isArray(headers)) {
19262
+ const result = headers.map((entry) => {
19263
+ const [key, value] = entry;
19264
+ return [key, value];
19265
+ });
19266
+ const headerIndex = result.findIndex(([key]) => key.toLowerCase() === USER_AGENT_HEADER.toLowerCase());
19267
+ if (headerIndex >= 0) {
19268
+ const [key, value] = result[headerIndex];
19269
+ result[headerIndex] = [
19270
+ key,
19271
+ appendUserAgentToken(value, effectiveUserAgent)
19272
+ ];
19273
+ } else {
19274
+ result.push([USER_AGENT_HEADER, effectiveUserAgent]);
19275
+ }
19276
+ return result;
19277
+ }
19278
+ return addSdkUserAgentHeader(typeof headers === "object" && headers !== null ? { ...headers } : {}, effectiveUserAgent);
19279
+ }
19280
+ function withUserAgentInitOverride(initOverrides, userAgent) {
19281
+ return async (requestContext) => {
19282
+ const initWithUserAgent = {
19283
+ ...requestContext.init,
19284
+ headers: withSdkUserAgentHeader(requestContext.init.headers, userAgent)
19285
+ };
19286
+ const override = typeof initOverrides === "function" ? await initOverrides({
19287
+ ...requestContext,
19288
+ init: initWithUserAgent
19289
+ }) : initOverrides;
19290
+ return {
19291
+ ...override ?? {},
19292
+ headers: withSdkUserAgentHeader(override?.headers ?? initWithUserAgent.headers, userAgent)
19293
+ };
19294
+ };
19295
+ }
19296
+ function installSdkUserAgentHeader(BaseApiClass, userAgent) {
19297
+ const prototype = BaseApiClass.prototype;
19298
+ const patchKey = userAgentPatchKey(userAgent);
19299
+ if (prototype[patchKey]) {
19300
+ return;
19301
+ }
19302
+ if (typeof prototype.request !== "function") {
19303
+ throw new Error("Generated BaseAPI request function not found.");
19304
+ }
19305
+ const originalRequest = prototype.request;
19306
+ prototype.request = function requestWithUserAgent(context, initOverrides) {
19307
+ return originalRequest.call(this, context, withUserAgentInitOverride(initOverrides, userAgent));
19308
+ };
19309
+ Object.defineProperty(prototype, patchKey, {
19310
+ value: true
19311
+ });
19312
+ }
19313
+
19090
19314
  // ../apms-sdk/generated/src/runtime.ts
19091
19315
  var BASE_PATH = "http://localhost:35599".replace(/\/+$/, "");
19092
19316
 
@@ -19336,6 +19560,57 @@ class VoidApiResponse {
19336
19560
  return;
19337
19561
  }
19338
19562
  }
19563
+ // ../apms-sdk/package.json
19564
+ var package_default2 = {
19565
+ name: "@uipath/apms-sdk",
19566
+ license: "MIT",
19567
+ version: "1.2.0",
19568
+ description: "SDK for the UiPath Access Policy Management Service API.",
19569
+ repository: {
19570
+ type: "git",
19571
+ url: "https://github.com/UiPath/cli.git",
19572
+ directory: "packages/admin/apms-sdk"
19573
+ },
19574
+ publishConfig: {
19575
+ registry: "https://npm.pkg.github.com/@uipath"
19576
+ },
19577
+ keywords: [
19578
+ "uipath",
19579
+ "access-policy-management",
19580
+ "apms",
19581
+ "sdk"
19582
+ ],
19583
+ type: "module",
19584
+ main: "./dist/index.js",
19585
+ types: "./dist/src/index.d.ts",
19586
+ exports: {
19587
+ ".": {
19588
+ types: "./dist/src/index.d.ts",
19589
+ default: "./dist/index.js"
19590
+ }
19591
+ },
19592
+ files: [
19593
+ "dist"
19594
+ ],
19595
+ private: true,
19596
+ scripts: {
19597
+ build: "bun build ./src/index.ts --outdir dist --format esm --target node && tsc -p tsconfig.build.json --noCheck",
19598
+ generate: "bun run src/scripts/generate-sdk.ts",
19599
+ lint: "biome check ."
19600
+ },
19601
+ devDependencies: {
19602
+ "@openapitools/openapi-generator-cli": "^2.31.1",
19603
+ "@types/node": "^25.5.2",
19604
+ "@uipath/auth": "workspace:*",
19605
+ "@uipath/common": "workspace:*",
19606
+ "@uipath/filesystem": "workspace:*",
19607
+ typescript: "^6.0.2"
19608
+ }
19609
+ };
19610
+
19611
+ // ../apms-sdk/src/user-agent.ts
19612
+ var SDK_USER_AGENT = getSdkUserAgentToken(package_default2);
19613
+ installSdkUserAgentHeader(BaseAPI, SDK_USER_AGENT);
19339
19614
 
19340
19615
  // ../apms-sdk/generated/src/models/UiPathPlatformServiceAccessPolicyManagementDomainDataStatus.ts
19341
19616
  function UiPathPlatformServiceAccessPolicyManagementDomainDataStatusToJSON(value) {
@@ -20339,32 +20614,7 @@ class InvalidBaseUrlError extends Error {
20339
20614
  this.name = "InvalidBaseUrlError";
20340
20615
  }
20341
20616
  }
20342
- var DEFAULT_SCOPES = [
20343
- "offline_access",
20344
- "ProcessMining",
20345
- "OrchestratorApiUserAccess",
20346
- "StudioWebBackend",
20347
- "IdentityServerApi",
20348
- "ConnectionService",
20349
- "DataService",
20350
- "DataServiceApiUserAccess",
20351
- "DocumentUnderstanding",
20352
- "EnterpriseContextService",
20353
- "Directory",
20354
- "JamJamApi",
20355
- "LLMGateway",
20356
- "LLMOps",
20357
- "OMS",
20358
- "RCS.FolderAuthorization",
20359
- "RCS.TagsManagement",
20360
- "TestmanagerApiUserAccess",
20361
- "AutomationSolutions",
20362
- "StudioWebTypeCacheService",
20363
- "Docs.GPT.Search",
20364
- "Insights",
20365
- "ReferenceToken",
20366
- "Audit.Read"
20367
- ];
20617
+ var DEFAULT_SCOPES = ["openid", "profile", "offline_access"];
20368
20618
  var normalizeAndValidateBaseUrl = (rawUrl) => {
20369
20619
  let baseUrl = rawUrl;
20370
20620
  if (baseUrl.endsWith("/identity_/")) {
@@ -20414,7 +20664,8 @@ var resolveConfigAsync = async ({
20414
20664
  if (!clientSecret && fileAuth.clientSecret) {
20415
20665
  clientSecret = fileAuth.clientSecret;
20416
20666
  }
20417
- const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : DEFAULT_SCOPES;
20667
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && Boolean(clientSecret);
20668
+ const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : isExternalAppAuth ? [] : DEFAULT_SCOPES;
20418
20669
  return {
20419
20670
  clientId,
20420
20671
  clientSecret,
@@ -20914,6 +21165,129 @@ function normalizeTokenRefreshFailure() {
20914
21165
  function normalizeTokenRefreshUnavailableFailure() {
20915
21166
  return "token refresh failed before authentication completed";
20916
21167
  }
21168
+ function errorMessage(error) {
21169
+ return error instanceof Error ? error.message : String(error);
21170
+ }
21171
+ function computeExpirationThreshold(ensureTokenValidityMinutes) {
21172
+ return new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
21173
+ }
21174
+ async function runRefreshLocked(inputs) {
21175
+ const {
21176
+ absolutePath,
21177
+ refreshToken: callerRefreshToken,
21178
+ customAuthority,
21179
+ ensureTokenValidityMinutes,
21180
+ loadEnvFile,
21181
+ saveEnvFile,
21182
+ refreshFn,
21183
+ resolveConfig
21184
+ } = inputs;
21185
+ const expirationThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
21186
+ let fresh;
21187
+ try {
21188
+ fresh = await loadEnvFile({ envPath: absolutePath });
21189
+ } catch (error) {
21190
+ return {
21191
+ kind: "fail",
21192
+ status: {
21193
+ loginStatus: "Refresh Failed",
21194
+ hint: "Could not read the auth file while refreshing. Retry, or run 'uip login' to re-authenticate.",
21195
+ tokenRefresh: {
21196
+ attempted: false,
21197
+ success: false,
21198
+ errorMessage: `auth file read failed: ${errorMessage(error)}`
21199
+ }
21200
+ }
21201
+ };
21202
+ }
21203
+ const freshAccess = fresh.UIPATH_ACCESS_TOKEN;
21204
+ const freshExp = freshAccess ? getTokenExpiration(freshAccess) : undefined;
21205
+ if (freshAccess && freshExp && freshExp > expirationThreshold) {
21206
+ return {
21207
+ kind: "ok",
21208
+ accessToken: freshAccess,
21209
+ refreshToken: fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken,
21210
+ expiration: freshExp,
21211
+ tokenRefresh: { attempted: false, success: true }
21212
+ };
21213
+ }
21214
+ const tokenForIdP = fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken;
21215
+ let refreshedAccess;
21216
+ let refreshedRefresh;
21217
+ try {
21218
+ const config = await resolveConfig({ customAuthority });
21219
+ const refreshed = await refreshFn({
21220
+ refreshToken: tokenForIdP,
21221
+ tokenEndpoint: config.tokenEndpoint,
21222
+ clientId: config.clientId,
21223
+ expectedAuthority: customAuthority
21224
+ });
21225
+ refreshedAccess = refreshed.accessToken;
21226
+ refreshedRefresh = refreshed.refreshToken;
21227
+ } catch (error) {
21228
+ const isOAuthFailure = isTokenRefreshOAuthFailure(error);
21229
+ const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
21230
+ const message = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
21231
+ return {
21232
+ kind: "fail",
21233
+ status: {
21234
+ loginStatus: "Refresh Failed",
21235
+ hint,
21236
+ tokenRefresh: {
21237
+ attempted: true,
21238
+ success: false,
21239
+ errorMessage: message
21240
+ }
21241
+ }
21242
+ };
21243
+ }
21244
+ const refreshedExp = getTokenExpiration(refreshedAccess);
21245
+ if (!refreshedExp || refreshedExp <= new Date) {
21246
+ return {
21247
+ kind: "fail",
21248
+ status: {
21249
+ loginStatus: "Refresh Failed",
21250
+ hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
21251
+ tokenRefresh: {
21252
+ attempted: true,
21253
+ success: false,
21254
+ errorMessage: "refreshed token has no valid expiration claim"
21255
+ }
21256
+ }
21257
+ };
21258
+ }
21259
+ try {
21260
+ await saveEnvFile({
21261
+ envPath: absolutePath,
21262
+ data: {
21263
+ UIPATH_ACCESS_TOKEN: refreshedAccess,
21264
+ UIPATH_REFRESH_TOKEN: refreshedRefresh
21265
+ },
21266
+ merge: true
21267
+ });
21268
+ return {
21269
+ kind: "ok",
21270
+ accessToken: refreshedAccess,
21271
+ refreshToken: refreshedRefresh,
21272
+ expiration: refreshedExp,
21273
+ tokenRefresh: { attempted: true, success: true }
21274
+ };
21275
+ } catch (error) {
21276
+ const msg = errorMessage(error);
21277
+ return {
21278
+ kind: "ok",
21279
+ accessToken: refreshedAccess,
21280
+ refreshToken: refreshedRefresh,
21281
+ expiration: refreshedExp,
21282
+ persistenceWarning: `Access token refreshed in memory but could not be written to ${absolutePath}: ${msg}. The next CLI invocation will fail until the file can be updated — run 'uip login' to re-authenticate.`,
21283
+ tokenRefresh: {
21284
+ attempted: true,
21285
+ success: true,
21286
+ errorMessage: `persistence failed: ${msg}`
21287
+ }
21288
+ };
21289
+ }
21290
+ }
20917
21291
  var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
20918
21292
  const {
20919
21293
  resolveEnvFilePath = resolveEnvFilePathAsync,
@@ -20988,73 +21362,103 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
20988
21362
  let refreshToken = credentials.UIPATH_REFRESH_TOKEN;
20989
21363
  let expiration = getTokenExpiration(accessToken);
20990
21364
  let persistenceWarning;
21365
+ let lockReleaseFailed = false;
20991
21366
  let tokenRefresh;
20992
- const expirationThreshold = new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
20993
- if (expiration && expiration <= expirationThreshold && refreshToken) {
20994
- let refreshedAccess;
20995
- let refreshedRefresh;
21367
+ const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
21368
+ const tryGlobalCredsHint = async () => {
21369
+ const fs7 = getFs();
21370
+ const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
21371
+ if (absolutePath === globalPath)
21372
+ return;
21373
+ if (!await fs7.exists(globalPath))
21374
+ return;
20996
21375
  try {
20997
- const config = await resolveConfig({
20998
- customAuthority: credentials.UIPATH_URL
20999
- });
21000
- const refreshed = await refreshTokenFn({
21001
- refreshToken,
21002
- tokenEndpoint: config.tokenEndpoint,
21003
- clientId: config.clientId,
21004
- expectedAuthority: credentials.UIPATH_URL
21005
- });
21006
- refreshedAccess = refreshed.accessToken;
21007
- refreshedRefresh = refreshed.refreshToken;
21008
- } catch (error) {
21009
- const isOAuthFailure = isTokenRefreshOAuthFailure(error);
21010
- const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
21011
- const errorMessage = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
21012
- return {
21013
- loginStatus: "Refresh Failed",
21014
- hint,
21015
- tokenRefresh: {
21016
- attempted: true,
21017
- success: false,
21018
- errorMessage
21019
- }
21020
- };
21376
+ const globalCreds = await loadEnvFile({ envPath: globalPath });
21377
+ if (!globalCreds.UIPATH_ACCESS_TOKEN)
21378
+ return;
21379
+ const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
21380
+ if (globalExp && globalExp <= new Date)
21381
+ return;
21382
+ return `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
21383
+ } catch {
21384
+ return;
21021
21385
  }
21022
- const refreshedExp = getTokenExpiration(refreshedAccess);
21023
- if (!refreshedExp || refreshedExp <= new Date) {
21386
+ };
21387
+ if (expiration && expiration <= outerThreshold && refreshToken) {
21388
+ let release;
21389
+ try {
21390
+ release = await getFs().acquireLock(absolutePath);
21391
+ } catch (error) {
21392
+ const msg = errorMessage(error);
21393
+ const globalHint = await tryGlobalCredsHint();
21394
+ if (globalHint) {
21395
+ return {
21396
+ loginStatus: "Expired",
21397
+ accessToken,
21398
+ refreshToken,
21399
+ baseUrl: credentials.UIPATH_URL,
21400
+ organizationName: credentials.UIPATH_ORGANIZATION_NAME,
21401
+ organizationId: credentials.UIPATH_ORGANIZATION_ID,
21402
+ tenantName: credentials.UIPATH_TENANT_NAME,
21403
+ tenantId: credentials.UIPATH_TENANT_ID,
21404
+ expiration,
21405
+ source: "file" /* File */,
21406
+ hint: globalHint,
21407
+ tokenRefresh: {
21408
+ attempted: false,
21409
+ success: false,
21410
+ errorMessage: `lock acquisition failed: ${msg}`
21411
+ }
21412
+ };
21413
+ }
21024
21414
  return {
21025
21415
  loginStatus: "Refresh Failed",
21026
- hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
21416
+ hint: "Could not acquire the auth-file lock — too many concurrent `uip` processes, or a permission issue on the auth directory. Retry, or run 'uip login' to re-authenticate.",
21027
21417
  tokenRefresh: {
21028
- attempted: true,
21418
+ attempted: false,
21029
21419
  success: false,
21030
- errorMessage: "refreshed token has no valid expiration claim"
21420
+ errorMessage: `lock acquisition failed: ${msg}`
21031
21421
  }
21032
21422
  };
21033
21423
  }
21034
- accessToken = refreshedAccess;
21035
- refreshToken = refreshedRefresh;
21036
- expiration = refreshedExp;
21424
+ let lockedFailure;
21037
21425
  try {
21038
- await saveEnvFile({
21039
- envPath: absolutePath,
21040
- data: {
21041
- UIPATH_ACCESS_TOKEN: accessToken,
21042
- UIPATH_REFRESH_TOKEN: refreshToken
21043
- },
21044
- merge: true
21426
+ const outcome = await runRefreshLocked({
21427
+ absolutePath,
21428
+ refreshToken,
21429
+ customAuthority: credentials.UIPATH_URL,
21430
+ ensureTokenValidityMinutes,
21431
+ loadEnvFile,
21432
+ saveEnvFile,
21433
+ refreshFn: refreshTokenFn,
21434
+ resolveConfig
21045
21435
  });
21046
- tokenRefresh = {
21047
- attempted: true,
21048
- success: true
21049
- };
21050
- } catch (error) {
21051
- const msg = error instanceof Error ? error.message : String(error);
21052
- persistenceWarning = `Access token refreshed in memory but could not be written to ${absolutePath}: ${msg}. The next CLI invocation will fail until the file can be updated — run 'uip login' to re-authenticate.`;
21053
- tokenRefresh = {
21054
- attempted: true,
21055
- success: true,
21056
- errorMessage: `persistence failed: ${msg}`
21057
- };
21436
+ if (outcome.kind === "fail") {
21437
+ lockedFailure = outcome.status;
21438
+ } else {
21439
+ accessToken = outcome.accessToken;
21440
+ refreshToken = outcome.refreshToken;
21441
+ expiration = outcome.expiration;
21442
+ tokenRefresh = outcome.tokenRefresh;
21443
+ if (outcome.persistenceWarning) {
21444
+ persistenceWarning = outcome.persistenceWarning;
21445
+ }
21446
+ }
21447
+ } finally {
21448
+ try {
21449
+ await release();
21450
+ } catch {
21451
+ lockReleaseFailed = true;
21452
+ }
21453
+ }
21454
+ if (lockedFailure) {
21455
+ const globalHint = await tryGlobalCredsHint();
21456
+ const base = globalHint ? {
21457
+ ...lockedFailure,
21458
+ loginStatus: "Expired",
21459
+ hint: globalHint
21460
+ } : lockedFailure;
21461
+ return lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base;
21058
21462
  }
21059
21463
  }
21060
21464
  const result = {
@@ -21069,23 +21473,13 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
21069
21473
  expiration,
21070
21474
  source: "file" /* File */,
21071
21475
  ...persistenceWarning ? { hint: persistenceWarning, persistenceFailed: true } : {},
21476
+ ...lockReleaseFailed ? { lockReleaseFailed: true } : {},
21072
21477
  ...tokenRefresh ? { tokenRefresh } : {}
21073
21478
  };
21074
21479
  if (result.loginStatus === "Expired") {
21075
- const fs7 = getFs();
21076
- const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
21077
- if (absolutePath !== globalPath && await fs7.exists(globalPath)) {
21078
- try {
21079
- const globalCreds = await loadEnvFile({
21080
- envPath: globalPath
21081
- });
21082
- if (globalCreds.UIPATH_ACCESS_TOKEN) {
21083
- const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
21084
- if (!globalExp || globalExp > new Date) {
21085
- result.hint = `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
21086
- }
21087
- }
21088
- } catch {}
21480
+ const globalHint = await tryGlobalCredsHint();
21481
+ if (globalHint) {
21482
+ result.hint = globalHint;
21089
21483
  }
21090
21484
  }
21091
21485
  return result;
@@ -21102,6 +21496,10 @@ var getLoginStatusAsync = async (options = {}) => {
21102
21496
  init_src();
21103
21497
  // ../../auth/src/logout.ts
21104
21498
  init_src();
21499
+
21500
+ // ../../auth/src/index.ts
21501
+ init_server();
21502
+
21105
21503
  // ../apms-sdk/src/client-factory.ts
21106
21504
  var STRIP_PREFIX_RE = /\/accesspolicy_\/api\/(?:accessPolicy\/)?organization\/[^/]+/;
21107
21505
  function rewriteApmsUrl(url) {
@@ -21132,6 +21530,7 @@ async function resolveConfig(options) {
21132
21530
  config: new Configuration({
21133
21531
  basePath,
21134
21532
  accessToken: async () => bearerToken,
21533
+ headers: addSdkUserAgentHeader(undefined, SDK_USER_AGENT),
21135
21534
  fetchApi
21136
21535
  }),
21137
21536
  organizationId: status.organizationId
@@ -21281,10 +21680,15 @@ async function extractErrorDetails(error, options) {
21281
21680
  }
21282
21681
  if (parsedBody?.errorCode && typeof parsedBody.errorCode === "string") {
21283
21682
  context.errorCode = parsedBody.errorCode;
21683
+ } else if (parsedBody?.code && typeof parsedBody.code === "string") {
21684
+ context.errorCode = parsedBody.code;
21284
21685
  }
21285
21686
  if (parsedBody?.requestId && typeof parsedBody.requestId === "string") {
21286
21687
  context.requestId = parsedBody.requestId;
21287
21688
  }
21689
+ if (parsedBody?.traceId && typeof parsedBody.traceId === "string") {
21690
+ context.traceId = parsedBody.traceId;
21691
+ }
21288
21692
  if (status === 429) {
21289
21693
  const resp = response;
21290
21694
  const headersObj = resp?.headers;
@@ -21304,7 +21708,35 @@ async function extractErrorDetails(error, options) {
21304
21708
  }
21305
21709
  }
21306
21710
  const hasContext = Object.keys(context).length > 0;
21307
- return { result, message, details, ...hasContext ? { context } : {} };
21711
+ let parsedErrors;
21712
+ if (parsedBody?.errors && typeof parsedBody.errors === "object") {
21713
+ const errors = {};
21714
+ for (const [field, raw] of Object.entries(parsedBody.errors)) {
21715
+ if (Array.isArray(raw)) {
21716
+ const messages = raw.map((entry) => {
21717
+ if (typeof entry === "string")
21718
+ return entry;
21719
+ if (entry && typeof entry === "object" && typeof entry.message === "string") {
21720
+ return entry.message;
21721
+ }
21722
+ return String(entry);
21723
+ }).filter(Boolean);
21724
+ if (messages.length > 0)
21725
+ errors[field] = messages;
21726
+ } else if (typeof raw === "string") {
21727
+ errors[field] = [raw];
21728
+ }
21729
+ }
21730
+ if (Object.keys(errors).length > 0)
21731
+ parsedErrors = errors;
21732
+ }
21733
+ return {
21734
+ result,
21735
+ message,
21736
+ details,
21737
+ ...hasContext ? { context } : {},
21738
+ ...parsedErrors ? { parsedErrors } : {}
21739
+ };
21308
21740
  }
21309
21741
  async function extractErrorMessage(error, options) {
21310
21742
  const { message } = await extractErrorDetails(error, options);
@@ -21317,36 +21749,6 @@ Command.prototype.examples = function(examples) {
21317
21749
  examplesByCommand.set(this, examples);
21318
21750
  return this;
21319
21751
  };
21320
- // ../../common/src/singleton.ts
21321
- var PREFIX = "@uipath/common/";
21322
- var _g = globalThis;
21323
- function singleton(ctorOrName) {
21324
- const name = typeof ctorOrName === "string" ? ctorOrName : ctorOrName.name;
21325
- const key = Symbol.for(PREFIX + name);
21326
- return {
21327
- get(fallback) {
21328
- return _g[key] ?? fallback;
21329
- },
21330
- set(value) {
21331
- _g[key] = value;
21332
- },
21333
- clear() {
21334
- delete _g[key];
21335
- },
21336
- getOrInit(factory, guard) {
21337
- const existing = _g[key];
21338
- if (existing != null && typeof existing === "object") {
21339
- if (!guard || guard(existing)) {
21340
- return existing;
21341
- }
21342
- }
21343
- const instance = factory();
21344
- _g[key] = instance;
21345
- return instance;
21346
- }
21347
- };
21348
- }
21349
-
21350
21752
  // ../../common/src/output-context.ts
21351
21753
  function createStorage() {
21352
21754
  const [error, mod] = catchError2(() => __require("node:async_hooks"));
@@ -26436,6 +26838,60 @@ function escapeNonAscii(jsonText) {
26436
26838
  function needsAsciiSafeJson(sink) {
26437
26839
  return process.platform === "win32" && !sink.capabilities.isInteractive;
26438
26840
  }
26841
+ function isPlainRecord(value) {
26842
+ if (value === null || typeof value !== "object")
26843
+ return false;
26844
+ const prototype = Object.getPrototypeOf(value);
26845
+ return prototype === Object.prototype || prototype === null;
26846
+ }
26847
+ function toLowerCamelCaseKey(key) {
26848
+ if (!key)
26849
+ return key;
26850
+ if (/[_\-\s]/.test(key)) {
26851
+ const [firstPart, ...restParts] = key.split(/[_\-\s]+/).filter(Boolean);
26852
+ if (!firstPart)
26853
+ return key;
26854
+ return [
26855
+ toLowerCamelCaseSimpleKey(firstPart),
26856
+ ...restParts.map((part) => {
26857
+ const normalized = toLowerCamelCaseSimpleKey(part);
26858
+ return normalized.charAt(0).toUpperCase() + normalized.slice(1);
26859
+ })
26860
+ ].join("");
26861
+ }
26862
+ return toLowerCamelCaseSimpleKey(key);
26863
+ }
26864
+ function toLowerCamelCaseSimpleKey(key) {
26865
+ if (/^[A-Z0-9]+$/.test(key))
26866
+ return key.toLowerCase();
26867
+ return key.replace(/^[A-Z]+(?=[A-Z][a-z]|\d|$)|^[A-Z]/, (match) => match.toLowerCase());
26868
+ }
26869
+ function toPascalCaseKey(key) {
26870
+ const lowerCamelKey = toLowerCamelCaseKey(key);
26871
+ return lowerCamelKey ? lowerCamelKey.charAt(0).toUpperCase() + lowerCamelKey.slice(1) : lowerCamelKey;
26872
+ }
26873
+ function toPascalCaseData(value) {
26874
+ if (Array.isArray(value))
26875
+ return value.map(toPascalCaseData);
26876
+ if (!isPlainRecord(value))
26877
+ return value;
26878
+ const result = {};
26879
+ for (const [key, nestedValue] of Object.entries(value)) {
26880
+ result[toPascalCaseKey(key)] = toPascalCaseData(nestedValue);
26881
+ }
26882
+ return result;
26883
+ }
26884
+ function normalizeDataKeys(data) {
26885
+ return toPascalCaseData(data);
26886
+ }
26887
+ function normalizeOutputKeys(data) {
26888
+ const result = {};
26889
+ for (const [key, value] of Object.entries(data)) {
26890
+ const pascalKey = toPascalCaseKey(key);
26891
+ result[pascalKey] = pascalKey === "Data" ? value : toPascalCaseData(value);
26892
+ }
26893
+ return result;
26894
+ }
26439
26895
  function printOutput(data, format = "json", logFn, asciiSafe = false) {
26440
26896
  if (!data) {
26441
26897
  logFn("Empty response object. No data to display.");
@@ -26498,7 +26954,7 @@ function wrapText(text, width) {
26498
26954
  function printTable(data, logFn, externalLogValue) {
26499
26955
  if (data.length === 0)
26500
26956
  return;
26501
- const keys = Object.keys(data[0]).filter((key) => key !== "Code" && key !== "Log");
26957
+ const keys = Object.keys(data[0]).filter((key) => !["code", "log"].includes(key.toLowerCase()));
26502
26958
  const maxWidths = keys.map((key) => Math.max(key.length, ...data.map((item) => cellToString(item[key]).length)));
26503
26959
  const header = keys.map((key, i2) => key.padEnd(maxWidths[i2])).join(" | ");
26504
26960
  logFn(header);
@@ -26513,7 +26969,7 @@ function printTable(data, logFn, externalLogValue) {
26513
26969
  }
26514
26970
  }
26515
26971
  function printVerticalTable(data, logFn = console.log, externalLogValue) {
26516
- const keys = Object.keys(data).filter((key) => key !== "Code" && key !== "Log");
26972
+ const keys = Object.keys(data).filter((key) => !["code", "log"].includes(key.toLowerCase()));
26517
26973
  if (keys.length === 0)
26518
26974
  return;
26519
26975
  const maxKeyWidth = Math.max(...keys.map((key) => key.length));
@@ -26529,7 +26985,7 @@ function printVerticalTable(data, logFn = console.log, externalLogValue) {
26529
26985
  function printResizableTable(data, logFn = console.log, externalLogValue) {
26530
26986
  if (data.length === 0)
26531
26987
  return;
26532
- const keys = Object.keys(data[0]).filter((key) => key !== "Code" && key !== "Log");
26988
+ const keys = Object.keys(data[0]).filter((key) => !["code", "log"].includes(key.toLowerCase()));
26533
26989
  if (keys.length === 0)
26534
26990
  return;
26535
26991
  if (!process.stdout.isTTY) {
@@ -26605,8 +27061,26 @@ function printResizableTable(data, logFn = console.log, externalLogValue) {
26605
27061
  function toYaml(data) {
26606
27062
  return dump(data);
26607
27063
  }
27064
+ class FilterEvaluationError extends Error {
27065
+ __brand = "FilterEvaluationError";
27066
+ filter;
27067
+ instructions;
27068
+ result = RESULTS.ValidationError;
27069
+ constructor(filter, cause) {
27070
+ const underlying = cause instanceof Error ? cause.message : String(cause);
27071
+ super(`Filter '${filter}' failed to evaluate: ${underlying}`);
27072
+ this.name = "FilterEvaluationError";
27073
+ this.filter = filter;
27074
+ 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(@)'.";
27075
+ }
27076
+ }
26608
27077
  function applyFilter(data, filter) {
26609
- const result = search(data, filter);
27078
+ let result;
27079
+ try {
27080
+ result = search(data, filter);
27081
+ } catch (err) {
27082
+ throw new FilterEvaluationError(filter, err);
27083
+ }
26610
27084
  if (result == null)
26611
27085
  return [];
26612
27086
  if (Array.isArray(result)) {
@@ -26623,13 +27097,18 @@ function applyFilter(data, filter) {
26623
27097
  }
26624
27098
  var OutputFormatter;
26625
27099
  ((OutputFormatter) => {
26626
- function success(data) {
27100
+ function success(data, options) {
26627
27101
  data.Log ??= getLogFilePath() || undefined;
27102
+ const normalize = !options?.preserveDataKeys;
27103
+ if (normalize) {
27104
+ data.Data = normalizeDataKeys(data.Data);
27105
+ }
26628
27106
  const filter = getOutputFilter();
26629
27107
  if (filter) {
26630
- data.Data = applyFilter(data.Data, filter);
27108
+ const filtered = applyFilter(data.Data, filter);
27109
+ data.Data = normalize ? normalizeDataKeys(filtered) : filtered;
26631
27110
  }
26632
- logOutput(data, getOutputFormat());
27111
+ logOutput(normalizeOutputKeys(data), getOutputFormat());
26633
27112
  }
26634
27113
  OutputFormatter.success = success;
26635
27114
  function error(data) {
@@ -26639,7 +27118,7 @@ var OutputFormatter;
26639
27118
  result: data.Result,
26640
27119
  message: data.Message
26641
27120
  });
26642
- logOutput(data, getOutputFormat());
27121
+ logOutput(normalizeOutputKeys(data), getOutputFormat());
26643
27122
  }
26644
27123
  OutputFormatter.error = error;
26645
27124
  function emitList(code, items, opts) {
@@ -26660,13 +27139,14 @@ var OutputFormatter;
26660
27139
  function log(data) {
26661
27140
  const format = getOutputFormat();
26662
27141
  const sink = getOutputSink();
27142
+ const normalized = toPascalCaseData(data);
26663
27143
  if (format === "json") {
26664
- const json2 = JSON.stringify(data);
27144
+ const json2 = JSON.stringify(normalized);
26665
27145
  const safe = needsAsciiSafeJson(sink) ? escapeNonAscii(json2) : json2;
26666
27146
  sink.writeErr(`${safe}
26667
27147
  `);
26668
27148
  } else {
26669
- for (const [key, value] of Object.entries(data)) {
27149
+ for (const [key, value] of Object.entries(normalized)) {
26670
27150
  sink.writeErr(`${key}: ${value}
26671
27151
  `);
26672
27152
  }
@@ -26675,12 +27155,16 @@ var OutputFormatter;
26675
27155
  OutputFormatter.log = log;
26676
27156
  function formatToString(data) {
26677
27157
  const filter = getOutputFilter();
26678
- if (filter && "Data" in data && data.Data != null) {
26679
- data.Data = applyFilter(data.Data, filter);
27158
+ if ("Data" in data && data.Data != null) {
27159
+ data.Data = normalizeDataKeys(data.Data);
27160
+ if (filter) {
27161
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
27162
+ }
26680
27163
  }
27164
+ const output = normalizeOutputKeys(data);
26681
27165
  const lines = [];
26682
27166
  const sink = getOutputSink();
26683
- printOutput(data, getOutputFormat(), (msg) => {
27167
+ printOutput(output, getOutputFormat(), (msg) => {
26684
27168
  lines.push(msg);
26685
27169
  }, needsAsciiSafeJson(sink));
26686
27170
  return lines.join(`
@@ -28095,6 +28579,22 @@ JSONPath.prototype.vm = vm;
28095
28579
  import { Option } from "commander";
28096
28580
  // ../../common/src/option-validators.ts
28097
28581
  import { InvalidArgumentError } from "commander";
28582
+ // ../../common/src/polling/types.ts
28583
+ var PollOutcome = {
28584
+ Completed: "completed",
28585
+ Timeout: "timeout",
28586
+ Interrupted: "interrupted",
28587
+ Aborted: "aborted",
28588
+ Failed: "failed"
28589
+ };
28590
+
28591
+ // ../../common/src/polling/poll-failure-mapping.ts
28592
+ var REASON_BY_OUTCOME = {
28593
+ [PollOutcome.Timeout]: "poll_timeout",
28594
+ [PollOutcome.Failed]: "poll_failed",
28595
+ [PollOutcome.Interrupted]: "poll_failed",
28596
+ [PollOutcome.Aborted]: "poll_aborted"
28597
+ };
28098
28598
  // ../../common/src/polling/terminal-statuses.ts
28099
28599
  var TERMINAL_STATUSES = new Set([
28100
28600
  "completed",
@@ -28303,17 +28803,21 @@ Command2.prototype.trackedAction = function(context, fn, properties) {
28303
28803
  const telemetryName = deriveCommandPath(command);
28304
28804
  const props = typeof properties === "function" ? properties(...args) : properties;
28305
28805
  const startTime = performance.now();
28306
- let errorMessage;
28806
+ let errorMessage2;
28307
28807
  const [error] = await catchError2(fn(...args));
28308
28808
  if (error) {
28309
- errorMessage = error instanceof Error ? error.message : String(error);
28310
- logger.error(`[trackedAction] ${telemetryName} failed: ${errorMessage}`);
28809
+ errorMessage2 = error instanceof Error ? error.message : String(error);
28810
+ logger.debug(`[trackedAction] ${telemetryName} failed: ${errorMessage2}`);
28811
+ const typed = error;
28812
+ const customInstructions = typeof typed.instructions === "string" ? typed.instructions : undefined;
28813
+ const customResult = typeof typed.result === "string" && typed.result !== RESULTS.Success && Object.values(RESULTS).includes(typed.result) ? typed.result : undefined;
28814
+ const finalResult = customResult ?? RESULTS.Failure;
28311
28815
  OutputFormatter.error({
28312
- Result: RESULTS.Failure,
28313
- Message: errorMessage,
28314
- Instructions: "An unexpected error occurred. Run with --log-level debug for details."
28816
+ Result: finalResult,
28817
+ Message: errorMessage2,
28818
+ Instructions: customInstructions ?? "An unexpected error occurred. Run with --log-level debug for details."
28315
28819
  });
28316
- context.exit(1);
28820
+ context.exit(EXIT_CODES[finalResult]);
28317
28821
  }
28318
28822
  const durationMs = performance.now() - startTime;
28319
28823
  const success = !error && (process.exitCode === undefined || process.exitCode === 0);
@@ -28322,7 +28826,7 @@ Command2.prototype.trackedAction = function(context, fn, properties) {
28322
28826
  ...props,
28323
28827
  duration: String(durationMs),
28324
28828
  success: String(success),
28325
- ...errorMessage ? { errorMessage } : {}
28829
+ ...errorMessage2 ? { errorMessage: errorMessage2 } : {}
28326
28830
  }));
28327
28831
  });
28328
28832
  };