@uipath/solution-sdk 1.202.1 → 1.203.0-preview.180

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 (32) hide show
  1. package/dist/THIRD-PARTY-NOTICES.md +12 -1
  2. package/dist/embedded-file-reader-xxqe8vs8.js +114 -0
  3. package/dist/first-party-service-sd8yaf73.js +27 -0
  4. package/dist/index-1de529jm.js +39 -0
  5. package/dist/index-4zqv4bn2.js +6922 -0
  6. package/dist/index-53w8skv5.js +262 -0
  7. package/dist/index-dqa169gp.js +25 -0
  8. package/dist/index-g0hcxnae.js +237 -0
  9. package/dist/index-gdtpsdn7.js +342 -0
  10. package/dist/index-sby22td6.js +634 -0
  11. package/dist/index-y8tgscfm.js +1381 -0
  12. package/dist/index.js +3660 -15829
  13. package/dist/jmespath-231m3hyn.js +1485 -0
  14. package/dist/js-yaml-88tdqrtd.js +3153 -0
  15. package/dist/resources/index.js +14311 -27794
  16. package/dist/solution-auth.js +6 -2320
  17. package/dist/src/index.d.ts +1 -1
  18. package/dist/src/resources/commands/project-utils.d.ts +5 -0
  19. package/dist/src/resources/index.d.ts +3 -0
  20. package/dist/src/resources/providers/artefact-pair-binding-provider.d.ts +21 -0
  21. package/dist/src/resources/providers/file-storage-provider.d.ts +2 -1
  22. package/dist/src/resources/providers/resource-builder-init.d.ts +12 -12
  23. package/dist/src/resources/providers/solution-access-provider.d.ts +2 -1
  24. package/dist/src/resources/services/entry-point-spec-enhancer.d.ts +21 -2
  25. package/dist/src/resources/services/local-resource-matcher.d.ts +1 -1
  26. package/dist/src/resources/services/project-template-types.d.ts +35 -0
  27. package/dist/src/resources/services/resource-casing.d.ts +24 -0
  28. package/dist/src/resources/services/resource-refresh-service.d.ts +7 -0
  29. package/dist/src/resources/services/resource-remote-sync.d.ts +67 -0
  30. package/dist/src/resources/services/solution-manifest.d.ts +20 -6
  31. package/dist/src/resources/services/sync-resources-from-bindings.d.ts +4 -3
  32. package/package.json +3 -2
@@ -0,0 +1,1381 @@
1
+ import {
2
+ getFileSystem
3
+ } from "./index-g0hcxnae.js";
4
+ import {
5
+ __require
6
+ } from "./index-1de529jm.js";
7
+
8
+ // ../auth/src/catch-error.ts
9
+ function isPromiseLike(value) {
10
+ return value !== null && typeof value === "object" && typeof value.then === "function";
11
+ }
12
+ function catchError(fnOrPromise) {
13
+ if (isPromiseLike(fnOrPromise)) {
14
+ return settlePromiseLike(fnOrPromise);
15
+ }
16
+ try {
17
+ const result = fnOrPromise();
18
+ if (isPromiseLike(result)) {
19
+ return settlePromiseLike(result);
20
+ }
21
+ return [undefined, result];
22
+ } catch (error) {
23
+ return [
24
+ error instanceof Error ? error : new Error(String(error)),
25
+ undefined
26
+ ];
27
+ }
28
+ }
29
+ function settlePromiseLike(thenable) {
30
+ return Promise.resolve(thenable).then((data) => [undefined, data]).catch((error) => [
31
+ error instanceof Error ? error : new Error(String(error)),
32
+ undefined
33
+ ]);
34
+ }
35
+
36
+ // ../auth/src/constants.ts
37
+ var UIPATH_HOME_DIR = ".uipath";
38
+ var AUTH_FILENAME = ".auth";
39
+ var DEFAULT_BASE_URL = "https://cloud.uipath.com";
40
+ var DEFAULT_AUTH_TIMEOUT_MS = 5 * 60 * 1000;
41
+
42
+ // ../auth/src/config.ts
43
+ var DEFAULT_CLIENT_ID = "36dea5b8-e8bb-423d-8e7b-c808df8f1c00";
44
+ var AUTH_FILE_CONFIG_KEY = Symbol.for("@uipath/auth/AuthFileConfig");
45
+ var globalSlot = globalThis;
46
+ var getAuthFileConfig = () => globalSlot[AUTH_FILE_CONFIG_KEY] ?? {};
47
+
48
+ class InvalidBaseUrlError extends Error {
49
+ url;
50
+ reason;
51
+ constructor(url, reason) {
52
+ super(`Invalid base URL: "${url}"
53
+ ` + `Reason: ${reason}
54
+
55
+ ` + `Expected format: an https:// URL (or bare host — https:// is assumed), e.g. https://cloud.uipath.com (commercial), https://govcloud.uipath.us (Public Sector), or your Automation Suite host (https://<your-host>).
56
+ ` + `You can specify the URL via:
57
+ ` + ` • --authority flag
58
+ ` + ` • UIPATH_URL environment variable
59
+ ` + ` • auth.authority in config file`);
60
+ this.url = url;
61
+ this.reason = reason;
62
+ this.name = "InvalidBaseUrlError";
63
+ }
64
+ }
65
+ var DEFAULT_SCOPES = ["openid", "profile", "offline_access"];
66
+ var normalizeAndValidateBaseUrl = (rawUrl) => {
67
+ let baseUrl = rawUrl;
68
+ if (baseUrl.endsWith("/identity_/")) {
69
+ baseUrl = baseUrl.slice(0, -11);
70
+ } else if (baseUrl.endsWith("/identity_")) {
71
+ baseUrl = baseUrl.slice(0, -10);
72
+ }
73
+ while (baseUrl.endsWith("/")) {
74
+ baseUrl = baseUrl.slice(0, -1);
75
+ }
76
+ const hasScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(baseUrl);
77
+ const [hostCandidate] = baseUrl.split(/[/?#]/, 1);
78
+ if (!hasScheme && hostCandidate.includes(".")) {
79
+ baseUrl = `https://${baseUrl}`;
80
+ }
81
+ const resolvedBaseUrl = baseUrl;
82
+ const [urlError, url] = catchError(() => new URL(resolvedBaseUrl));
83
+ if (urlError) {
84
+ const shapeHint = !hasScheme && !hostCandidate.includes(".") ? ` "${rawUrl.trim()}" is not a URL or a host name. Pass the full authority URL — https://<host>, or just <host> (https:// is assumed).` : ` ${urlError instanceof Error ? urlError.message : "Unknown error"}`;
85
+ throw new InvalidBaseUrlError(baseUrl, `Malformed URL.${shapeHint}`);
86
+ }
87
+ if (url.protocol !== "https:") {
88
+ throw new InvalidBaseUrlError(baseUrl, `Authority must use https:// scheme, got ${url.protocol}//. OIDC token exchange requires TLS end-to-end.`);
89
+ }
90
+ return url.pathname.length > 1 ? url.origin : baseUrl;
91
+ };
92
+ var resolveScopes = (isExternalAppAuth, customScopes, fileScopes) => {
93
+ const requestedScopes = customScopes?.length ? customScopes : fileScopes ?? [];
94
+ if (isExternalAppAuth)
95
+ return requestedScopes;
96
+ return [...new Set([...DEFAULT_SCOPES, ...requestedScopes])];
97
+ };
98
+ var resolveConfigAsync = async ({
99
+ customAuthority,
100
+ customClientId,
101
+ customClientSecret,
102
+ customClientAssertion,
103
+ customScopes
104
+ } = {}) => {
105
+ const fileAuth = getAuthFileConfig();
106
+ let baseUrl = customAuthority;
107
+ if (!baseUrl) {
108
+ baseUrl = process.env.UIPATH_URL;
109
+ }
110
+ if (!baseUrl && fileAuth.authority) {
111
+ baseUrl = fileAuth.authority;
112
+ }
113
+ if (!baseUrl) {
114
+ baseUrl = DEFAULT_BASE_URL;
115
+ }
116
+ baseUrl = normalizeAndValidateBaseUrl(baseUrl);
117
+ let clientId = customClientId;
118
+ if (!clientId && fileAuth.clientId) {
119
+ clientId = fileAuth.clientId;
120
+ }
121
+ if (!clientId) {
122
+ clientId = DEFAULT_CLIENT_ID;
123
+ }
124
+ let clientSecret = customClientSecret;
125
+ if (!clientSecret && fileAuth.clientSecret) {
126
+ clientSecret = fileAuth.clientSecret;
127
+ }
128
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
129
+ const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
130
+ return {
131
+ clientId,
132
+ clientSecret,
133
+ scopes,
134
+ baseUrl,
135
+ authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
136
+ tokenEndpoint: `${baseUrl}/identity_/connect/token`
137
+ };
138
+ };
139
+
140
+ // ../auth/src/utils/platform.ts
141
+ function isBrowser() {
142
+ return typeof globalThis !== "undefined" && "window" in globalThis && "document" in globalThis;
143
+ }
144
+
145
+ // ../auth/src/authProfile.ts
146
+ var DEFAULT_AUTH_PROFILE = "default";
147
+ var PROFILE_DIR = "profiles";
148
+ var PROFILE_NAME_RE = /^[A-Za-z0-9._-]+$/;
149
+ var ACTIVE_AUTH_PROFILE_KEY = Symbol.for("@uipath/auth/ActiveAuthProfile");
150
+ var AUTH_PROFILE_STORAGE_KEY = Symbol.for("@uipath/auth/ProfileStorage");
151
+ var globalSlot2 = globalThis;
152
+ function isAuthProfileStorage(value) {
153
+ return value !== null && typeof value === "object" && "getStore" in value && "run" in value;
154
+ }
155
+ function createProfileStorage() {
156
+ const [error, mod] = catchError(() => __require("node:async_hooks"));
157
+ if (error || typeof mod?.AsyncLocalStorage !== "function") {
158
+ return {
159
+ getStore: () => {
160
+ return;
161
+ },
162
+ run: (_store, fn) => fn()
163
+ };
164
+ }
165
+ return new mod.AsyncLocalStorage;
166
+ }
167
+ function getProfileStorage() {
168
+ const existing = globalSlot2[AUTH_PROFILE_STORAGE_KEY];
169
+ if (isAuthProfileStorage(existing)) {
170
+ return existing;
171
+ }
172
+ const storage = createProfileStorage();
173
+ globalSlot2[AUTH_PROFILE_STORAGE_KEY] = storage;
174
+ return storage;
175
+ }
176
+ var profileStorage = getProfileStorage();
177
+
178
+ class AuthProfileValidationError extends Error {
179
+ constructor(message) {
180
+ super(message);
181
+ this.name = "AuthProfileValidationError";
182
+ }
183
+ }
184
+ function normalizeAuthProfileName(profile) {
185
+ if (profile === undefined || profile === DEFAULT_AUTH_PROFILE) {
186
+ return;
187
+ }
188
+ if (profile.length === 0 || profile === "." || profile === ".." || !PROFILE_NAME_RE.test(profile)) {
189
+ throw new AuthProfileValidationError(`Invalid profile name "${profile}". Profile names may contain only letters, numbers, '.', '_', and '-'.`);
190
+ }
191
+ return profile;
192
+ }
193
+ function getActiveAuthProfile() {
194
+ const scopedState = profileStorage.getStore();
195
+ if (scopedState !== undefined) {
196
+ return scopedState.profile;
197
+ }
198
+ return globalSlot2[ACTIVE_AUTH_PROFILE_KEY]?.profile;
199
+ }
200
+ function resolveAuthProfileFilePath(profile) {
201
+ const normalized = normalizeAuthProfileName(profile);
202
+ if (normalized === undefined) {
203
+ throw new AuthProfileValidationError(`"${DEFAULT_AUTH_PROFILE}" is the built-in profile and does not have a profile file path.`);
204
+ }
205
+ const fs = getFileSystem();
206
+ return fs.path.join(fs.env.homedir(), UIPATH_HOME_DIR, PROFILE_DIR, normalized, AUTH_FILENAME);
207
+ }
208
+ function getActiveAuthProfileFilePath() {
209
+ const profile = getActiveAuthProfile();
210
+ return profile ? resolveAuthProfileFilePath(profile) : undefined;
211
+ }
212
+
213
+ // ../auth/src/utils/jwt.ts
214
+ class InvalidIssuerError extends Error {
215
+ expected;
216
+ actual;
217
+ constructor(expected, actual) {
218
+ const actualText = actual ?? "<missing>";
219
+ super(`Token issuer does not match the authority used to log in.
220
+ ` + `Expected: ${expected}
221
+ ` + `Actual: ${actualText}
222
+
223
+ ` + `The identity server that issued this token is not the one ` + `you pointed --authority at. Refusing to save credentials.`);
224
+ this.expected = expected;
225
+ this.actual = actual;
226
+ this.name = "InvalidIssuerError";
227
+ }
228
+ }
229
+ var parseJWT = (token) => {
230
+ try {
231
+ const parts = token.split(".");
232
+ const base64Url = parts[1];
233
+ if (!base64Url) {
234
+ throw new Error("Invalid JWT token format - missing payload section");
235
+ }
236
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
237
+ let decodedString;
238
+ if (isBrowser() && typeof atob !== "undefined") {
239
+ decodedString = atob(base64);
240
+ } else {
241
+ decodedString = Buffer.from(base64, "base64").toString();
242
+ }
243
+ const jsonPayload = decodeURIComponent(decodedString.split("").map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`).join(""));
244
+ const parsed = JSON.parse(jsonPayload);
245
+ return parsed;
246
+ } catch (error) {
247
+ throw new Error(`Failed to parse JWT: ${error instanceof Error ? error.message : "Unknown error"}`);
248
+ }
249
+ };
250
+ var assertIssuerMatchesAuthority = (token, authority) => {
251
+ let payload;
252
+ try {
253
+ payload = parseJWT(token);
254
+ } catch (error) {
255
+ throw new InvalidIssuerError(`${authority.replace(/\/+$/, "")}/identity_`, `<unparseable: ${error instanceof Error ? error.message : "unknown error"}>`);
256
+ }
257
+ const stripTrailingSlash = (s) => s.replace(/\/+$/, "");
258
+ const expected = `${stripTrailingSlash(authority)}/identity_`;
259
+ const actual = typeof payload.iss === "string" ? stripTrailingSlash(payload.iss) : undefined;
260
+ if (actual !== expected) {
261
+ throw new InvalidIssuerError(expected, payload.iss);
262
+ }
263
+ };
264
+ var getTokenExpiration = (accessToken) => {
265
+ try {
266
+ const parts = accessToken.split(".");
267
+ if (parts.length !== 3) {
268
+ return;
269
+ }
270
+ const payload = parts[1];
271
+ const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
272
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
273
+ const decoded = atob(padded);
274
+ const claims = JSON.parse(decoded);
275
+ if (typeof claims.exp !== "number") {
276
+ return;
277
+ }
278
+ return new Date(claims.exp * 1000);
279
+ } catch {
280
+ return;
281
+ }
282
+ };
283
+
284
+ // ../auth/src/sessionIdentity.ts
285
+ var parseAuthFlow = (value) => value === "authorization_code" || value === "client_credentials" || value === "federated_credentials" ? value : undefined;
286
+ var decodeClaims = (accessToken) => {
287
+ const [error, claims] = catchError(() => parseJWT(accessToken));
288
+ return error ? undefined : claims;
289
+ };
290
+ var asString = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
291
+ var resolveIdentityType = (claims, authFlow, email) => {
292
+ const subType = asString(claims?.sub_type);
293
+ if (subType) {
294
+ return subType.startsWith("service") ? "Application" : "User";
295
+ }
296
+ if (authFlow) {
297
+ return authFlow === "authorization_code" ? "User" : "Application";
298
+ }
299
+ if (email)
300
+ return "User";
301
+ if (asString(claims?.client_id) && !asString(claims?.sub)) {
302
+ return "Application";
303
+ }
304
+ return;
305
+ };
306
+ var looksLikeEmail = (value) => value?.includes("@") ?? false;
307
+ var pickEmail = (claims) => {
308
+ for (const candidate of [claims?.email, claims?.preferred_username]) {
309
+ const value = asString(candidate);
310
+ if (looksLikeEmail(value))
311
+ return value;
312
+ }
313
+ return;
314
+ };
315
+ var pickName = (claims) => {
316
+ const username = asString(claims?.preferred_username);
317
+ return asString(claims?.name) ?? (looksLikeEmail(username) ? undefined : username);
318
+ };
319
+ var resolveSessionIdentity = (accessToken, authFlow) => {
320
+ const claims = accessToken ? decodeClaims(accessToken) : undefined;
321
+ const email = pickEmail(claims);
322
+ const type = resolveIdentityType(claims, authFlow, email);
323
+ if (!type)
324
+ return;
325
+ const identity = { type };
326
+ if (authFlow)
327
+ identity.authFlow = authFlow;
328
+ if (type === "User") {
329
+ const userId = asString(claims?.sub);
330
+ if (userId)
331
+ identity.userId = userId;
332
+ if (email)
333
+ identity.userEmail = email;
334
+ const name = pickName(claims);
335
+ if (name)
336
+ identity.userName = name;
337
+ return identity;
338
+ }
339
+ const clientId = asString(claims?.client_id);
340
+ if (clientId)
341
+ identity.clientId = clientId;
342
+ return identity;
343
+ };
344
+
345
+ // ../auth/src/envAuth.ts
346
+ var ENV_AUTH_ENABLE_VAR = "UIPATH_CLI_ENABLE_ENV_AUTH";
347
+ var ENFORCE_ROBOT_AUTH_VAR = "UIPATH_CLI_ENFORCE_ROBOT_AUTH";
348
+ var ENV_AUTH_VARS = {
349
+ token: "UIPATH_CLI_AUTH_TOKEN",
350
+ organizationName: "UIPATH_CLI_ORGANIZATION_NAME",
351
+ organizationId: "UIPATH_CLI_ORGANIZATION_ID",
352
+ tenantName: "UIPATH_CLI_TENANT_NAME",
353
+ tenantId: "UIPATH_CLI_TENANT_ID"
354
+ };
355
+
356
+ class EnvAuthConfigError extends Error {
357
+ constructor(message) {
358
+ super(message);
359
+ this.name = "EnvAuthConfigError";
360
+ }
361
+ }
362
+ var isEnvAuthEnabled = () => process.env[ENV_AUTH_ENABLE_VAR] === "true";
363
+ var isRobotAuthEnforced = () => process.env[ENFORCE_ROBOT_AUTH_VAR] === "true";
364
+ var requireEnv = (name) => {
365
+ const value = process.env[name];
366
+ if (!value) {
367
+ throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true but ${name} is not set. ` + `Set ${name} to enable env-var authentication.`);
368
+ }
369
+ return value;
370
+ };
371
+ var OPAQUE_TOKEN_BASE_URL_VAR = "UIPATH_URL";
372
+ var resolveBaseUrl = (rawUrl, failureContext) => {
373
+ const [baseUrlError, baseUrl] = catchError(() => normalizeAndValidateBaseUrl(rawUrl));
374
+ if (baseUrlError) {
375
+ if (baseUrlError instanceof InvalidBaseUrlError) {
376
+ throw baseUrlError;
377
+ }
378
+ throw new EnvAuthConfigError(`${failureContext}: ` + `${baseUrlError instanceof Error ? baseUrlError.message : String(baseUrlError)}`);
379
+ }
380
+ return baseUrl;
381
+ };
382
+ var readAuthFromEnv = () => {
383
+ const accessToken = requireEnv(ENV_AUTH_VARS.token);
384
+ const organizationName = requireEnv(ENV_AUTH_VARS.organizationName);
385
+ const organizationId = requireEnv(ENV_AUTH_VARS.organizationId);
386
+ const tenantName = requireEnv(ENV_AUTH_VARS.tenantName);
387
+ const tenantId = requireEnv(ENV_AUTH_VARS.tenantId);
388
+ const [parseError, payload] = catchError(() => parseJWT(accessToken));
389
+ if (parseError) {
390
+ const parseErrorMessage = parseError instanceof Error ? parseError.message : String(parseError);
391
+ const rawUrl = process.env[OPAQUE_TOKEN_BASE_URL_VAR];
392
+ if (!rawUrl) {
393
+ throw new EnvAuthConfigError(`${ENV_AUTH_VARS.token} is not a JWT (treating it as an opaque token, ` + `e.g. a Personal Access Token). Set ${OPAQUE_TOKEN_BASE_URL_VAR} to the ` + `UiPath base URL if this is a PAT, or fix the token if it was meant to ` + `be a JWT (parse error: ${parseErrorMessage}).`);
394
+ }
395
+ const baseUrl2 = resolveBaseUrl(rawUrl, `Failed to validate ${OPAQUE_TOKEN_BASE_URL_VAR}`);
396
+ return {
397
+ loginStatus: "Logged in",
398
+ accessToken,
399
+ baseUrl: baseUrl2,
400
+ organizationName,
401
+ organizationId,
402
+ tenantName,
403
+ tenantId,
404
+ source: "env-vars" /* EnvironmentVariables */,
405
+ hint: "Token is opaque (not a JWT) - expiration and identity cannot be " + "determined locally. Commands will fail with 401 once it is revoked or " + `expired. If this was meant to be a JWT instead of a PAT, note: ${parseErrorMessage}`
406
+ };
407
+ }
408
+ const iss = payload.iss;
409
+ if (typeof iss !== "string" || iss.length === 0) {
410
+ throw new EnvAuthConfigError(`${ENV_AUTH_VARS.token} has no 'iss' claim; cannot determine ` + `the UiPath server. Ensure the token was issued by a UiPath identity server.`);
411
+ }
412
+ const baseUrl = resolveBaseUrl(iss, "Failed to derive server URL from token 'iss' claim");
413
+ const expiration = getTokenExpiration(accessToken);
414
+ const loginStatus = expiration && expiration <= new Date ? "Expired" : "Logged in";
415
+ const identity = resolveSessionIdentity(accessToken);
416
+ return {
417
+ loginStatus,
418
+ accessToken,
419
+ baseUrl,
420
+ organizationName,
421
+ organizationId,
422
+ tenantName,
423
+ tenantId,
424
+ expiration,
425
+ source: "env-vars" /* EnvironmentVariables */,
426
+ ...identity ? { identity } : {}
427
+ };
428
+ };
429
+
430
+ // ../auth/src/refreshCircuitBreaker.ts
431
+ var BREAKER_SUFFIX = ".refresh-state";
432
+ var BACKOFF_BASE_MS = 60000;
433
+ var BACKOFF_CAP_MS = 60 * 60 * 1000;
434
+ var SURFACE_WINDOW_MS = 60 * 60 * 1000;
435
+ async function refreshTokenFingerprint(refreshToken) {
436
+ const bytes = new TextEncoder().encode(refreshToken);
437
+ if (globalThis.crypto?.subtle) {
438
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
439
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
440
+ }
441
+ const { createHash } = await import("node:crypto");
442
+ return createHash("sha256").update(refreshToken).digest("hex").slice(0, 16);
443
+ }
444
+ function breakerPathFor(authPath) {
445
+ return `${authPath}${BREAKER_SUFFIX}`;
446
+ }
447
+ async function loadRefreshBreaker(authPath) {
448
+ const fs = getFileSystem();
449
+ try {
450
+ const content = await fs.readFile(breakerPathFor(authPath), "utf-8");
451
+ if (!content)
452
+ return {};
453
+ const parsed = JSON.parse(content);
454
+ return parsed && typeof parsed === "object" ? parsed : {};
455
+ } catch {
456
+ return {};
457
+ }
458
+ }
459
+ async function saveRefreshBreaker(authPath, state) {
460
+ try {
461
+ const fs = getFileSystem();
462
+ const path = breakerPathFor(authPath);
463
+ await fs.mkdir(fs.path.dirname(path));
464
+ const tempPath = `${path}.tmp`;
465
+ await fs.writeFile(tempPath, JSON.stringify(state));
466
+ await fs.rename(tempPath, path);
467
+ } catch {}
468
+ }
469
+ async function clearRefreshBreaker(authPath) {
470
+ const fs = getFileSystem();
471
+ const path = breakerPathFor(authPath);
472
+ try {
473
+ if (await fs.exists(path)) {
474
+ await fs.rm(path);
475
+ }
476
+ } catch {}
477
+ }
478
+ function nextBackoffMs(attempts) {
479
+ const shift = Math.max(0, attempts - 1);
480
+ return Math.min(BACKOFF_BASE_MS * 2 ** shift, BACKOFF_CAP_MS);
481
+ }
482
+ function shouldSurface(state, nowMs) {
483
+ if (state.lastSurfacedAtMs === undefined)
484
+ return true;
485
+ return nowMs - state.lastSurfacedAtMs >= SURFACE_WINDOW_MS;
486
+ }
487
+
488
+ // ../auth/src/robotClientFallback.ts
489
+ var DEFAULT_TIMEOUT_MS = 1000;
490
+ var CLOSE_TIMEOUT_MS = 500;
491
+ var ROBOT_USER_SERVICES_PIPE = "UiPathUserServices";
492
+ var ROBOT_USER_SERVICES_ALTERNATE_PIPE = `${ROBOT_USER_SERVICES_PIPE}Alternate`;
493
+ var PIPE_NAME_MAX_LENGTH = 103;
494
+ var getRobotIpcPipeNames = async () => {
495
+ const fs = getFileSystem();
496
+ const username = fs.env.getenv("USER") ?? fs.env.getenv("USERNAME");
497
+ if (!username) {
498
+ throw new Error("Unable to determine current username");
499
+ }
500
+ const tempPath = fs.env.getenv("TMPDIR") ?? "/tmp/";
501
+ return [ROBOT_USER_SERVICES_PIPE, ROBOT_USER_SERVICES_ALTERNATE_PIPE].map((baseName) => fs.path.join(tempPath, `${baseName}_${username}`).substring(0, PIPE_NAME_MAX_LENGTH));
502
+ };
503
+ var defaultIsRobotIpcAvailable = async () => {
504
+ if (process.platform === "win32") {
505
+ return true;
506
+ }
507
+ const [pipeNamesError, pipeNames] = await catchError(getRobotIpcPipeNames());
508
+ if (pipeNamesError || !pipeNames) {
509
+ return false;
510
+ }
511
+ const fs = getFileSystem();
512
+ for (const pipeName of pipeNames) {
513
+ const [existsError, exists] = await catchError(fs.exists(pipeName));
514
+ if (!existsError && exists === true) {
515
+ return true;
516
+ }
517
+ }
518
+ return false;
519
+ };
520
+ var withTimeout = (promise, timeoutMs) => new Promise((resolve, reject) => {
521
+ const timer = setTimeout(() => reject(new Error(`Robot IPC call timed out after ${timeoutMs}ms`)), timeoutMs);
522
+ promise.then((value) => {
523
+ clearTimeout(timer);
524
+ resolve(value);
525
+ }, (error) => {
526
+ clearTimeout(timer);
527
+ reject(error);
528
+ });
529
+ });
530
+ var parseResourceUrl = (url) => {
531
+ const [error, parsed] = catchError(() => new URL(url));
532
+ if (error || !parsed)
533
+ return;
534
+ const segments = parsed.pathname.split("/").filter(Boolean);
535
+ return {
536
+ baseUrl: parsed.origin,
537
+ organizationName: segments[0],
538
+ tenantName: segments[1]
539
+ };
540
+ };
541
+ var ROBOT_CLIENT_LOADER_KEY = Symbol.for("@uipath/auth/RobotClientLoader");
542
+ var getRegisteredRobotClientLoader = () => {
543
+ const loader = globalThis[ROBOT_CLIENT_LOADER_KEY];
544
+ return typeof loader === "function" ? loader : undefined;
545
+ };
546
+ var defaultLoadModule = async () => {
547
+ const hostLoader = getRegisteredRobotClientLoader();
548
+ if (!hostLoader) {
549
+ return;
550
+ }
551
+ const [error, mod] = await catchError(() => hostLoader());
552
+ if (error || !mod) {
553
+ return;
554
+ }
555
+ return mod;
556
+ };
557
+ var tryRobotClientFallback = async (options = {}) => {
558
+ if (isBrowser())
559
+ return;
560
+ if (!options.force) {
561
+ if (process.env.CI || process.env.GITHUB_ACTIONS) {
562
+ return;
563
+ }
564
+ if (process.env.UIPATH_URL) {
565
+ return;
566
+ }
567
+ }
568
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
569
+ const isRobotIpcAvailable = options.isRobotIpcAvailable ?? defaultIsRobotIpcAvailable;
570
+ const loadModule = options.loadModule ?? defaultLoadModule;
571
+ if (!await isRobotIpcAvailable()) {
572
+ return;
573
+ }
574
+ const mod = await loadModule();
575
+ if (!mod)
576
+ return;
577
+ const [ctorError, proxy] = catchError(() => new mod.RobotProxyConstructor);
578
+ if (ctorError || !proxy) {
579
+ return;
580
+ }
581
+ try {
582
+ const enabled = await withTimeout(proxy.interactiveConnectFlow.IsEnabled(), timeoutMs);
583
+ if (!enabled) {
584
+ return;
585
+ }
586
+ const [resourceUrl, accessToken] = await Promise.all([
587
+ withTimeout(proxy.accessProvider.GetResourceUrl("Orchestrator"), timeoutMs),
588
+ withTimeout(proxy.accessProvider.GetAccessToken("Orchestrator", false), timeoutMs)
589
+ ]);
590
+ if (!accessToken) {
591
+ return;
592
+ }
593
+ const parsedUrl = parseResourceUrl(resourceUrl);
594
+ if (!parsedUrl) {
595
+ return;
596
+ }
597
+ let organizationIdFromToken;
598
+ let tenantIdFromToken;
599
+ let issuerFromToken;
600
+ const [jwtError, claims] = catchError(() => parseJWT(accessToken));
601
+ if (!jwtError && claims) {
602
+ const rawOrgId = claims.prtId ?? claims.organizationId ?? claims.prt_id;
603
+ if (typeof rawOrgId === "string" && rawOrgId.length > 0) {
604
+ organizationIdFromToken = rawOrgId;
605
+ }
606
+ const tenantClaim = claims.tenantId ?? claims.tenant_id;
607
+ if (typeof tenantClaim === "string" && tenantClaim.length > 0) {
608
+ tenantIdFromToken = tenantClaim;
609
+ }
610
+ const issClaim = claims.iss;
611
+ if (typeof issClaim === "string" && issClaim.length > 0) {
612
+ issuerFromToken = issClaim;
613
+ }
614
+ }
615
+ return {
616
+ accessToken,
617
+ baseUrl: parsedUrl.baseUrl,
618
+ organizationName: parsedUrl.organizationName,
619
+ organizationId: organizationIdFromToken ?? parsedUrl.organizationName,
620
+ tenantName: parsedUrl.tenantName,
621
+ tenantId: tenantIdFromToken,
622
+ issuer: issuerFromToken
623
+ };
624
+ } catch {
625
+ return;
626
+ } finally {
627
+ await catchError(() => withTimeout(proxy.CloseAsync(), CLOSE_TIMEOUT_MS));
628
+ }
629
+ };
630
+
631
+ // ../auth/src/tokenRefresh.ts
632
+ var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
633
+
634
+ class TokenRefreshOAuthError extends Error {
635
+ __brand = "TokenRefreshOAuthError";
636
+ constructor() {
637
+ super(TOKEN_REFRESH_REAUTHENTICATE_MESSAGE);
638
+ this.name = "TokenRefreshOAuthError";
639
+ }
640
+ }
641
+ function isTokenRefreshOAuthFailure(error) {
642
+ return error instanceof TokenRefreshOAuthError;
643
+ }
644
+ var refreshAccessToken = async ({
645
+ refreshToken,
646
+ tokenEndpoint,
647
+ clientId,
648
+ expectedAuthority
649
+ }) => {
650
+ const tokenParams = new URLSearchParams({
651
+ grant_type: "refresh_token",
652
+ refresh_token: refreshToken,
653
+ client_id: clientId
654
+ });
655
+ const tokenResponse = await fetch(tokenEndpoint, {
656
+ method: "POST",
657
+ headers: {
658
+ "Content-Type": "application/x-www-form-urlencoded"
659
+ },
660
+ body: tokenParams
661
+ });
662
+ const tokenData = await tokenResponse.json();
663
+ if (!tokenResponse.ok) {
664
+ throw new TokenRefreshOAuthError;
665
+ }
666
+ const newAccessToken = tokenData.access_token;
667
+ const newRefreshToken = tokenData.refresh_token;
668
+ if (typeof newAccessToken !== "string" || typeof newRefreshToken !== "string") {
669
+ throw new Error("Token refresh response is missing access_token or refresh_token");
670
+ }
671
+ if (expectedAuthority) {
672
+ assertIssuerMatchesAuthority(newAccessToken, expectedAuthority);
673
+ }
674
+ return { accessToken: newAccessToken, refreshToken: newRefreshToken };
675
+ };
676
+
677
+ // ../auth/src/types.ts
678
+ var AUTH_FLOW_ENV_VAR = "UIPATH_AUTH_FLOW";
679
+
680
+ // ../auth/src/utils/envFile.ts
681
+ var DEFAULT_ENV_FILENAME = `${UIPATH_HOME_DIR}/${AUTH_FILENAME}`;
682
+ var KNOWN_ERROR_CODES = new Set([
683
+ "EISDIR",
684
+ "EACCES",
685
+ "EPERM",
686
+ "ELOOP",
687
+ "ENOTDIR",
688
+ "EUNKNOWN"
689
+ ]);
690
+ var errorCode = (err) => {
691
+ if (err !== null && typeof err === "object" && "code" in err && typeof err.code === "string") {
692
+ const raw = err.code;
693
+ return KNOWN_ERROR_CODES.has(raw) ? raw : "EUNKNOWN";
694
+ }
695
+ return "EUNKNOWN";
696
+ };
697
+ var probeAsync = async (fs, candidate) => {
698
+ try {
699
+ const stats = await fs.stat(candidate);
700
+ if (stats === null) {
701
+ return { exists: false };
702
+ }
703
+ if (!stats.isFile()) {
704
+ return {
705
+ exists: false,
706
+ unusable: {
707
+ reason: "not-a-file",
708
+ code: "EISDIR",
709
+ message: `Path is not a regular file: ${candidate}`
710
+ }
711
+ };
712
+ }
713
+ return { exists: true };
714
+ } catch (err) {
715
+ return {
716
+ exists: false,
717
+ unusable: {
718
+ reason: "unreadable",
719
+ code: errorCode(err),
720
+ message: err instanceof Error ? err.message : String(err)
721
+ }
722
+ };
723
+ }
724
+ };
725
+ var resolveEnvFileLocationAsync = async (envFilePath = DEFAULT_ENV_FILENAME, opts) => {
726
+ const fs = getFileSystem();
727
+ if (fs.path.isAbsolute(envFilePath)) {
728
+ const probe2 = await probeAsync(fs, envFilePath);
729
+ return probe2.exists ? { exists: true, absolutePath: envFilePath, source: "absolute" } : {
730
+ exists: false,
731
+ absolutePath: envFilePath,
732
+ source: "absolute",
733
+ ...probe2.unusable ? { unusable: probe2.unusable } : {}
734
+ };
735
+ }
736
+ const cwd = opts?.cwd ?? fs.env.cwd();
737
+ let searchDir = cwd;
738
+ while (true) {
739
+ const candidate = fs.path.join(searchDir, envFilePath);
740
+ const probe2 = await probeAsync(fs, candidate);
741
+ if (probe2.exists) {
742
+ return {
743
+ exists: true,
744
+ absolutePath: candidate,
745
+ source: searchDir === cwd ? "cwd" : "ancestor"
746
+ };
747
+ }
748
+ const parentDir = fs.path.dirname(searchDir);
749
+ if (parentDir === searchDir) {
750
+ break;
751
+ }
752
+ searchDir = parentDir;
753
+ }
754
+ const homePath = fs.path.join(fs.env.homedir(), envFilePath);
755
+ const probe = await probeAsync(fs, homePath);
756
+ if (probe.exists) {
757
+ return { exists: true, absolutePath: homePath, source: "home" };
758
+ }
759
+ return {
760
+ exists: false,
761
+ absolutePath: homePath,
762
+ source: "default",
763
+ ...probe.unusable ? { unusable: probe.unusable } : {}
764
+ };
765
+ };
766
+ var resolveEnvFilePathAsync = async (envFilePath = DEFAULT_ENV_FILENAME, opts) => {
767
+ const location = await resolveEnvFileLocationAsync(envFilePath, opts);
768
+ if (location.exists) {
769
+ return { absolutePath: location.absolutePath };
770
+ }
771
+ return {
772
+ absolutePath: undefined,
773
+ errorMessage: location.source === "absolute" ? `Environment file not found: ${envFilePath}` : `Unable to locate environment file: ${envFilePath}. Run 'uip login' to authenticate.`
774
+ };
775
+ };
776
+ var parseEnvContent = (content) => {
777
+ const env = {};
778
+ for (const line of content.split(`
779
+ `)) {
780
+ const trimmed = line.trim();
781
+ if (!trimmed || trimmed.startsWith("#")) {
782
+ continue;
783
+ }
784
+ const equalIndex = trimmed.indexOf("=");
785
+ if (equalIndex === -1) {
786
+ continue;
787
+ }
788
+ const key = trimmed.slice(0, equalIndex).trim();
789
+ let value = trimmed.slice(equalIndex + 1).trim();
790
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
791
+ value = value.slice(1, -1);
792
+ }
793
+ env[key] = value;
794
+ }
795
+ return env;
796
+ };
797
+ var loadEnvFileAsync = async ({ envPath }) => {
798
+ const fs = getFileSystem();
799
+ const absolutePath = fs.path.isAbsolute(envPath) ? envPath : fs.path.join(fs.env.cwd(), envPath);
800
+ if (!await fs.exists(absolutePath)) {
801
+ throw new Error(`Environment file not found: ${envPath}`);
802
+ }
803
+ const content = await fs.readFile(absolutePath, "utf-8");
804
+ if (content === null) {
805
+ throw new Error(`Environment file not found: ${envPath}`);
806
+ }
807
+ return parseEnvContent(content);
808
+ };
809
+ var saveEnvFileAsync = async ({
810
+ envPath,
811
+ data,
812
+ merge = true
813
+ }) => {
814
+ const fs = getFileSystem();
815
+ const absolutePath = fs.path.isAbsolute(envPath) ? envPath : fs.path.join(fs.env.homedir(), envPath);
816
+ let existingData = {};
817
+ if (merge && await fs.exists(absolutePath)) {
818
+ try {
819
+ existingData = await loadEnvFileAsync({ envPath: absolutePath });
820
+ } catch {}
821
+ }
822
+ const finalData = { ...existingData, ...data };
823
+ const lines = [];
824
+ for (const [key, value] of Object.entries(finalData)) {
825
+ if (value === undefined) {
826
+ continue;
827
+ }
828
+ const needsQuotes = value.includes(" ") || value.includes("#");
829
+ const finalValue = needsQuotes ? `"${value}"` : value;
830
+ lines.push(`${key}=${finalValue}`);
831
+ }
832
+ const content = `${lines.join(`
833
+ `)}
834
+ `;
835
+ const dir = fs.path.dirname(absolutePath);
836
+ await fs.mkdir(dir);
837
+ const tempPath = `${absolutePath}.tmp`;
838
+ await fs.writeFile(tempPath, content);
839
+ await fs.rename(tempPath, absolutePath);
840
+ };
841
+
842
+ // ../auth/src/loginStatus.ts
843
+ var getLoginStatusAsync = async (options = {}) => {
844
+ return getLoginStatusWithDeps(options);
845
+ };
846
+ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
847
+ const {
848
+ resolveEnvFilePath = resolveEnvFilePathAsync,
849
+ loadEnvFile = loadEnvFileAsync,
850
+ saveEnvFile = saveEnvFileAsync,
851
+ getFs = getFileSystem,
852
+ refreshToken: refreshTokenFn = refreshAccessToken,
853
+ resolveConfig = resolveConfigAsync,
854
+ robotFallback = tryRobotClientFallback,
855
+ loadBreaker = loadRefreshBreaker,
856
+ saveBreaker = saveRefreshBreaker,
857
+ clearBreaker = clearRefreshBreaker
858
+ } = deps;
859
+ if (isRobotAuthEnforced()) {
860
+ return resolveRobotEnforcedStatus(robotFallback);
861
+ }
862
+ if (isEnvAuthEnabled()) {
863
+ return readAuthFromEnv();
864
+ }
865
+ const activeProfile = getActiveAuthProfile();
866
+ const activeProfileFilePath = getActiveAuthProfileFilePath();
867
+ const usingActiveProfile = activeProfile !== undefined && (options.envFilePath === undefined || options.envFilePath === activeProfileFilePath);
868
+ const envFilePath = options.envFilePath ?? activeProfileFilePath ?? DEFAULT_ENV_FILENAME;
869
+ const { ensureTokenValidityMinutes } = options;
870
+ const { absolutePath } = await resolveEnvFilePath(envFilePath);
871
+ if (absolutePath === undefined) {
872
+ if (usingActiveProfile) {
873
+ return {
874
+ loginStatus: "Not logged in",
875
+ hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
876
+ };
877
+ }
878
+ return resolveBorrowedRobotStatus(robotFallback);
879
+ }
880
+ const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
881
+ if ("status" in loaded) {
882
+ return loaded.status;
883
+ }
884
+ const { credentials } = loaded;
885
+ const globalHint = () => usingActiveProfile ? Promise.resolve(undefined) : getGlobalCredsHint(getFs, loadEnvFile, absolutePath, envFilePath);
886
+ const expiration = getTokenExpiration(credentials.UIPATH_ACCESS_TOKEN);
887
+ const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
888
+ let tokens = {
889
+ accessToken: credentials.UIPATH_ACCESS_TOKEN,
890
+ refreshToken: credentials.UIPATH_REFRESH_TOKEN,
891
+ expiration,
892
+ lockReleaseFailed: false
893
+ };
894
+ const refreshToken = credentials.UIPATH_REFRESH_TOKEN;
895
+ if (expiration && expiration <= outerThreshold && refreshToken) {
896
+ const refreshed = await attemptRefresh({
897
+ absolutePath,
898
+ credentials,
899
+ accessToken: credentials.UIPATH_ACCESS_TOKEN,
900
+ refreshToken,
901
+ expiration,
902
+ ensureTokenValidityMinutes,
903
+ getFs,
904
+ loadEnvFile,
905
+ saveEnvFile,
906
+ refreshFn: refreshTokenFn,
907
+ resolveConfig,
908
+ loadBreaker,
909
+ saveBreaker,
910
+ clearBreaker,
911
+ globalHint
912
+ });
913
+ if (refreshed.kind === "terminal") {
914
+ return refreshed.status;
915
+ }
916
+ tokens = refreshed.tokens;
917
+ }
918
+ return buildFileStatus(tokens, credentials, globalHint);
919
+ };
920
+ async function resolveRobotEnforcedStatus(robotFallback) {
921
+ if (isEnvAuthEnabled()) {
922
+ throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
923
+ }
924
+ const robotCreds = await robotFallback({ force: true });
925
+ if (!robotCreds) {
926
+ return {
927
+ loginStatus: "Not logged in",
928
+ hint: `${ENFORCE_ROBOT_AUTH_VAR}=true but the UiPath Robot ` + `session is unavailable. Start and sign in to the Assistant, ` + `or unset ${ENFORCE_ROBOT_AUTH_VAR} to fall back to file or ` + `env-var authentication.`
929
+ };
930
+ }
931
+ return buildRobotStatus(robotCreds);
932
+ }
933
+ async function resolveBorrowedRobotStatus(robotFallback) {
934
+ const robotCreds = await robotFallback();
935
+ return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
936
+ }
937
+ async function loadFileCredentials(loadEnvFile, absolutePath) {
938
+ let credentials;
939
+ try {
940
+ credentials = await loadEnvFile({ envPath: absolutePath });
941
+ } catch (error) {
942
+ if (isFileNotFoundError(error)) {
943
+ return { status: { loginStatus: "Not logged in" } };
944
+ }
945
+ throw error;
946
+ }
947
+ if (!credentials.UIPATH_ACCESS_TOKEN) {
948
+ return { status: { loginStatus: "Not logged in" } };
949
+ }
950
+ return { credentials };
951
+ }
952
+ async function getGlobalCredsHint(getFs, loadEnvFile, absolutePath, envFilePath) {
953
+ const fs = getFs();
954
+ const globalPath = fs.path.join(fs.env.homedir(), envFilePath);
955
+ if (absolutePath === globalPath)
956
+ return;
957
+ if (!await fs.exists(globalPath))
958
+ return;
959
+ try {
960
+ const globalCreds = await loadEnvFile({ envPath: globalPath });
961
+ if (!globalCreds.UIPATH_ACCESS_TOKEN)
962
+ return;
963
+ const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
964
+ if (globalExp && globalExp <= new Date)
965
+ return;
966
+ 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.`;
967
+ } catch {
968
+ return;
969
+ }
970
+ }
971
+ function computeExpirationThreshold(ensureTokenValidityMinutes) {
972
+ return new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
973
+ }
974
+ async function attemptRefresh(ctx) {
975
+ const shortCircuit = await circuitBreakerShortCircuit(ctx);
976
+ if (shortCircuit) {
977
+ return { kind: "terminal", status: shortCircuit };
978
+ }
979
+ let release;
980
+ try {
981
+ release = await ctx.getFs().acquireLock(ctx.absolutePath);
982
+ } catch (error) {
983
+ return {
984
+ kind: "terminal",
985
+ status: await lockAcquireFailureStatus(ctx, error)
986
+ };
987
+ }
988
+ let lockedFailure;
989
+ let lockReleaseFailed = false;
990
+ let success;
991
+ try {
992
+ const outcome = await runRefreshLocked({
993
+ absolutePath: ctx.absolutePath,
994
+ refreshToken: ctx.refreshToken,
995
+ customAuthority: ctx.credentials.UIPATH_URL,
996
+ ensureTokenValidityMinutes: ctx.ensureTokenValidityMinutes,
997
+ loadEnvFile: ctx.loadEnvFile,
998
+ saveEnvFile: ctx.saveEnvFile,
999
+ refreshFn: ctx.refreshFn,
1000
+ resolveConfig: ctx.resolveConfig,
1001
+ loadBreaker: ctx.loadBreaker,
1002
+ saveBreaker: ctx.saveBreaker,
1003
+ clearBreaker: ctx.clearBreaker
1004
+ });
1005
+ if (outcome.kind === "fail") {
1006
+ lockedFailure = outcome.status;
1007
+ } else {
1008
+ success = outcome;
1009
+ }
1010
+ } finally {
1011
+ try {
1012
+ await release();
1013
+ } catch {
1014
+ lockReleaseFailed = true;
1015
+ }
1016
+ }
1017
+ if (lockedFailure) {
1018
+ const globalHint = await ctx.globalHint();
1019
+ const base = globalHint ? { ...lockedFailure, loginStatus: "Expired", hint: globalHint } : lockedFailure;
1020
+ return {
1021
+ kind: "terminal",
1022
+ status: lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base
1023
+ };
1024
+ }
1025
+ return {
1026
+ kind: "refreshed",
1027
+ tokens: {
1028
+ accessToken: success?.accessToken,
1029
+ refreshToken: success?.refreshToken,
1030
+ expiration: success?.expiration,
1031
+ tokenRefresh: success?.tokenRefresh,
1032
+ persistenceWarning: success?.persistenceWarning,
1033
+ lockReleaseFailed
1034
+ }
1035
+ };
1036
+ }
1037
+ async function buildFileStatus(tokens, credentials, globalHint) {
1038
+ const result = {
1039
+ loginStatus: tokens.expiration && tokens.expiration <= new Date ? "Expired" : "Logged in",
1040
+ accessToken: tokens.accessToken,
1041
+ refreshToken: tokens.refreshToken,
1042
+ baseUrl: credentials.UIPATH_URL,
1043
+ organizationName: credentials.UIPATH_ORGANIZATION_NAME,
1044
+ organizationId: credentials.UIPATH_ORGANIZATION_ID,
1045
+ tenantName: credentials.UIPATH_TENANT_NAME,
1046
+ tenantId: credentials.UIPATH_TENANT_ID,
1047
+ expiration: tokens.expiration,
1048
+ source: "saved-login" /* SavedLogin */,
1049
+ ...identityFields(tokens.accessToken, credentials),
1050
+ ...tokens.persistenceWarning ? { hint: tokens.persistenceWarning, persistenceFailed: true } : {},
1051
+ ...tokens.lockReleaseFailed ? { lockReleaseFailed: true } : {},
1052
+ ...tokens.tokenRefresh ? { tokenRefresh: tokens.tokenRefresh } : {}
1053
+ };
1054
+ if (result.loginStatus === "Expired") {
1055
+ const hint = await globalHint();
1056
+ if (hint) {
1057
+ result.hint = hint;
1058
+ }
1059
+ }
1060
+ return result;
1061
+ }
1062
+ function identityFields(accessToken, credentials) {
1063
+ const identity = resolveSessionIdentity(accessToken, parseAuthFlow(credentials[AUTH_FLOW_ENV_VAR]));
1064
+ return identity ? { identity } : {};
1065
+ }
1066
+ function buildRobotStatus(robotCreds) {
1067
+ const identity = resolveSessionIdentity(robotCreds.accessToken);
1068
+ return {
1069
+ loginStatus: "Logged in",
1070
+ accessToken: robotCreds.accessToken,
1071
+ baseUrl: robotCreds.baseUrl,
1072
+ organizationName: robotCreds.organizationName,
1073
+ organizationId: robotCreds.organizationId,
1074
+ tenantName: robotCreds.tenantName,
1075
+ tenantId: robotCreds.tenantId,
1076
+ issuer: robotCreds.issuer,
1077
+ expiration: getTokenExpiration(robotCreds.accessToken),
1078
+ source: "robot" /* Robot */,
1079
+ ...identity ? { identity } : {}
1080
+ };
1081
+ }
1082
+ var isFileNotFoundError = (error) => {
1083
+ if (!(error instanceof Object))
1084
+ return false;
1085
+ return error.code === "ENOENT";
1086
+ };
1087
+ async function circuitBreakerShortCircuit(ctx) {
1088
+ const {
1089
+ absolutePath,
1090
+ refreshToken,
1091
+ accessToken,
1092
+ credentials,
1093
+ expiration,
1094
+ loadBreaker,
1095
+ saveBreaker,
1096
+ clearBreaker
1097
+ } = ctx;
1098
+ const fingerprint = await refreshTokenFingerprint(refreshToken);
1099
+ const breaker = await loadBreaker(absolutePath).catch(() => ({}));
1100
+ if (breaker.deadTokenFp && breaker.deadTokenFp !== fingerprint) {
1101
+ await clearBreaker(absolutePath);
1102
+ breaker.deadTokenFp = undefined;
1103
+ }
1104
+ const nowMs = Date.now();
1105
+ const tokenIsDead = breaker.deadTokenFp === fingerprint;
1106
+ const inBackoff = breaker.backoffUntilMs !== undefined && nowMs < breaker.backoffUntilMs;
1107
+ if (!tokenIsDead && !inBackoff)
1108
+ return;
1109
+ const globalHint = await ctx.globalHint();
1110
+ const suppressed = !shouldSurface(breaker, nowMs);
1111
+ if (!suppressed) {
1112
+ await saveBreaker(absolutePath, {
1113
+ ...breaker,
1114
+ lastSurfacedAtMs: nowMs
1115
+ });
1116
+ }
1117
+ const deadHint = "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired. In a non-interactive context, authenticate with: uip login --client-id <id> --client-secret <secret> -t <tenant>.";
1118
+ const backoffHint = "Token refresh is temporarily backed off after a recent network error and will retry automatically once the backoff window elapses.";
1119
+ return {
1120
+ loginStatus: globalHint ? "Expired" : "Refresh Failed",
1121
+ ...globalHint ? {
1122
+ accessToken,
1123
+ refreshToken,
1124
+ baseUrl: credentials.UIPATH_URL,
1125
+ organizationName: credentials.UIPATH_ORGANIZATION_NAME,
1126
+ organizationId: credentials.UIPATH_ORGANIZATION_ID,
1127
+ tenantName: credentials.UIPATH_TENANT_NAME,
1128
+ tenantId: credentials.UIPATH_TENANT_ID,
1129
+ expiration,
1130
+ source: "saved-login" /* SavedLogin */,
1131
+ ...identityFields(accessToken, credentials)
1132
+ } : {},
1133
+ hint: globalHint ?? (tokenIsDead ? deadHint : backoffHint),
1134
+ refreshCircuitOpen: true,
1135
+ refreshTelemetrySuppressed: suppressed,
1136
+ tokenRefresh: { attempted: false, success: false }
1137
+ };
1138
+ }
1139
+ async function lockAcquireFailureStatus(ctx, error) {
1140
+ const msg = errorMessage(error);
1141
+ const globalHint = await ctx.globalHint();
1142
+ if (globalHint) {
1143
+ return {
1144
+ loginStatus: "Expired",
1145
+ accessToken: ctx.accessToken,
1146
+ refreshToken: ctx.refreshToken,
1147
+ baseUrl: ctx.credentials.UIPATH_URL,
1148
+ organizationName: ctx.credentials.UIPATH_ORGANIZATION_NAME,
1149
+ organizationId: ctx.credentials.UIPATH_ORGANIZATION_ID,
1150
+ tenantName: ctx.credentials.UIPATH_TENANT_NAME,
1151
+ tenantId: ctx.credentials.UIPATH_TENANT_ID,
1152
+ expiration: ctx.expiration,
1153
+ source: "saved-login" /* SavedLogin */,
1154
+ ...identityFields(ctx.accessToken, ctx.credentials),
1155
+ hint: globalHint,
1156
+ tokenRefresh: {
1157
+ attempted: false,
1158
+ success: false,
1159
+ errorMessage: `lock acquisition failed: ${msg}`
1160
+ }
1161
+ };
1162
+ }
1163
+ return {
1164
+ loginStatus: "Refresh Failed",
1165
+ 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.",
1166
+ tokenRefresh: {
1167
+ attempted: false,
1168
+ success: false,
1169
+ errorMessage: `lock acquisition failed: ${msg}`
1170
+ }
1171
+ };
1172
+ }
1173
+ async function runRefreshLocked(inputs) {
1174
+ const {
1175
+ absolutePath,
1176
+ refreshToken: callerRefreshToken,
1177
+ customAuthority,
1178
+ ensureTokenValidityMinutes,
1179
+ loadEnvFile,
1180
+ saveEnvFile,
1181
+ refreshFn,
1182
+ resolveConfig,
1183
+ loadBreaker,
1184
+ saveBreaker,
1185
+ clearBreaker
1186
+ } = inputs;
1187
+ const expirationThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
1188
+ let fresh;
1189
+ try {
1190
+ fresh = await loadEnvFile({ envPath: absolutePath });
1191
+ } catch (error) {
1192
+ return {
1193
+ kind: "fail",
1194
+ status: {
1195
+ loginStatus: "Refresh Failed",
1196
+ hint: "Could not read the auth file while refreshing. Retry, or run 'uip login' to re-authenticate.",
1197
+ tokenRefresh: {
1198
+ attempted: false,
1199
+ success: false,
1200
+ errorMessage: `auth file read failed: ${errorMessage(error)}`
1201
+ }
1202
+ }
1203
+ };
1204
+ }
1205
+ const freshAccess = fresh.UIPATH_ACCESS_TOKEN;
1206
+ const freshExp = freshAccess ? getTokenExpiration(freshAccess) : undefined;
1207
+ if (freshAccess && freshExp && freshExp > expirationThreshold) {
1208
+ await clearBreaker(absolutePath);
1209
+ return {
1210
+ kind: "ok",
1211
+ accessToken: freshAccess,
1212
+ refreshToken: fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken,
1213
+ expiration: freshExp,
1214
+ tokenRefresh: { attempted: false, success: true }
1215
+ };
1216
+ }
1217
+ const tokenForIdP = fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken;
1218
+ let refreshedAccess;
1219
+ let refreshedRefresh;
1220
+ try {
1221
+ const config = await resolveConfig({ customAuthority });
1222
+ const refreshed = await refreshFn({
1223
+ refreshToken: tokenForIdP,
1224
+ tokenEndpoint: config.tokenEndpoint,
1225
+ clientId: config.clientId,
1226
+ expectedAuthority: customAuthority
1227
+ });
1228
+ refreshedAccess = refreshed.accessToken;
1229
+ refreshedRefresh = refreshed.refreshToken;
1230
+ } catch (error) {
1231
+ const isOAuthFailure = isTokenRefreshOAuthFailure(error);
1232
+ const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired. In a non-interactive context, authenticate with: uip login --client-id <id> --client-secret <secret> -t <tenant>." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
1233
+ const message = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
1234
+ const fp = await refreshTokenFingerprint(tokenForIdP);
1235
+ if (isOAuthFailure) {
1236
+ await saveBreaker(absolutePath, { deadTokenFp: fp });
1237
+ } else {
1238
+ const prior = await loadBreaker(absolutePath).catch(() => ({}));
1239
+ const attempts = (prior.attempts ?? 0) + 1;
1240
+ await saveBreaker(absolutePath, {
1241
+ ...prior,
1242
+ deadTokenFp: undefined,
1243
+ attempts,
1244
+ backoffUntilMs: Date.now() + nextBackoffMs(attempts)
1245
+ });
1246
+ }
1247
+ return {
1248
+ kind: "fail",
1249
+ status: {
1250
+ loginStatus: "Refresh Failed",
1251
+ hint,
1252
+ tokenRefresh: {
1253
+ attempted: true,
1254
+ success: false,
1255
+ errorMessage: message
1256
+ }
1257
+ }
1258
+ };
1259
+ }
1260
+ const refreshedExp = getTokenExpiration(refreshedAccess);
1261
+ if (!refreshedExp || refreshedExp <= new Date) {
1262
+ return {
1263
+ kind: "fail",
1264
+ status: {
1265
+ loginStatus: "Refresh Failed",
1266
+ hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
1267
+ tokenRefresh: {
1268
+ attempted: true,
1269
+ success: false,
1270
+ errorMessage: "refreshed token has no valid expiration claim"
1271
+ }
1272
+ }
1273
+ };
1274
+ }
1275
+ await clearBreaker(absolutePath);
1276
+ try {
1277
+ await saveEnvFile({
1278
+ envPath: absolutePath,
1279
+ data: {
1280
+ UIPATH_ACCESS_TOKEN: refreshedAccess,
1281
+ UIPATH_REFRESH_TOKEN: refreshedRefresh
1282
+ },
1283
+ merge: true
1284
+ });
1285
+ return {
1286
+ kind: "ok",
1287
+ accessToken: refreshedAccess,
1288
+ refreshToken: refreshedRefresh,
1289
+ expiration: refreshedExp,
1290
+ tokenRefresh: { attempted: true, success: true }
1291
+ };
1292
+ } catch (error) {
1293
+ const msg = errorMessage(error);
1294
+ return {
1295
+ kind: "ok",
1296
+ accessToken: refreshedAccess,
1297
+ refreshToken: refreshedRefresh,
1298
+ expiration: refreshedExp,
1299
+ 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.`,
1300
+ tokenRefresh: {
1301
+ attempted: true,
1302
+ success: true,
1303
+ errorMessage: `persistence failed: ${msg}`
1304
+ }
1305
+ };
1306
+ }
1307
+ }
1308
+ function normalizeTokenRefreshFailure() {
1309
+ return "stored refresh token is invalid or expired";
1310
+ }
1311
+ function normalizeTokenRefreshUnavailableFailure() {
1312
+ return "token refresh failed before authentication completed";
1313
+ }
1314
+ function errorMessage(error) {
1315
+ return error instanceof Error ? error.message : String(error);
1316
+ }
1317
+
1318
+ // ../auth/src/authContext.ts
1319
+ var getAuthContext = async (options = {}) => {
1320
+ const status = await getLoginStatusAsync({
1321
+ ensureTokenValidityMinutes: options.ensureTokenValidityMinutes,
1322
+ envFilePath: options.envFilePath
1323
+ });
1324
+ if (status.loginStatus !== "Logged in" || !status.baseUrl || !status.accessToken) {
1325
+ throw new Error(status.hint ? `Not logged in. ${status.hint}` : "Not logged in. Run 'uip login' first.");
1326
+ }
1327
+ const tenantName = options.tenant ?? status.tenantName;
1328
+ if (options.requireOrganizationId && !status.organizationId) {
1329
+ throw new Error("Organization ID not available. Ensure you are logged in with an organization context.");
1330
+ }
1331
+ if (options.requireOrganizationName && !status.organizationName) {
1332
+ throw new Error("Organization name not available. Ensure you are logged in with an organization context.");
1333
+ }
1334
+ if (options.requireTenantId && !status.tenantId) {
1335
+ throw new Error("Tenant ID not available. Ensure UIPATH_TENANT_ID is set.");
1336
+ }
1337
+ if (options.requireTenantName && tenantName === undefined) {
1338
+ throw new Error("Tenant not provided and UIPATH_TENANT_NAME not set. Run 'uip login' to select a tenant, or use 'uip login tenant set <tenant>' to switch tenants.");
1339
+ }
1340
+ return {
1341
+ baseUrl: status.baseUrl,
1342
+ accessToken: status.accessToken,
1343
+ organizationId: status.organizationId,
1344
+ organizationName: status.organizationName,
1345
+ tenantId: status.tenantId,
1346
+ tenantName
1347
+ };
1348
+ };
1349
+ // ../auth/src/tenantSelection.ts
1350
+ var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
1351
+
1352
+ // ../auth/src/selectTenant.ts
1353
+ var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
1354
+ var INVALID_TENANT_CODE = "INVALID_TENANT";
1355
+ var TENANT_SELECTION_CODES = new Set([
1356
+ TENANT_SELECTION_REQUIRED_CODE,
1357
+ INVALID_TENANT_CODE
1358
+ ]);
1359
+ // src/solution-auth.ts
1360
+ async function getSolutionAuthContext(options) {
1361
+ const ctx = await getAuthContext({
1362
+ tenant: options.tenant,
1363
+ ensureTokenValidityMinutes: options.loginValidity ?? 10,
1364
+ envFilePath: options.envFilePath,
1365
+ requireOrganizationId: true,
1366
+ requireTenantName: true
1367
+ });
1368
+ const organizationId = ctx.organizationId;
1369
+ const tenantName = ctx.tenantName;
1370
+ const basePath = `${ctx.baseUrl}/${organizationId}/${tenantName}/automationsolutions_`;
1371
+ return {
1372
+ accessToken: ctx.accessToken,
1373
+ basePath,
1374
+ organizationId,
1375
+ tenantName
1376
+ };
1377
+ }
1378
+
1379
+ export { getLoginStatusAsync, getAuthContext, getSolutionAuthContext };
1380
+
1381
+ //# debugId=23A570105E3E594664756E2164756E21