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