@uipath/auth 1.196.0 → 1.197.0-preview.59

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.
package/dist/index.js CHANGED
@@ -19153,16 +19153,33 @@ var require_dist = __commonJS((exports) => {
19153
19153
  });
19154
19154
 
19155
19155
  // src/getBaseHtml.ts
19156
- var getBaseHtml = ({ title, message, type }) => {
19156
+ var escapeHtml = (value) => value.replace(/[&<>"']/g, (char) => {
19157
+ switch (char) {
19158
+ case "&":
19159
+ return "&amp;";
19160
+ case "<":
19161
+ return "&lt;";
19162
+ case ">":
19163
+ return "&gt;";
19164
+ case '"':
19165
+ return "&quot;";
19166
+ case "'":
19167
+ return "&#39;";
19168
+ default:
19169
+ return char;
19170
+ }
19171
+ }), getBaseHtml = ({ title, message, type }) => {
19157
19172
  const icon = type === "success" ? "✓" : "✕";
19158
19173
  const iconClass = type === "success" ? "icon-success" : "icon-error";
19174
+ const safeTitle = escapeHtml(title);
19175
+ const safeMessage = escapeHtml(message);
19159
19176
  return `
19160
19177
  <!DOCTYPE html>
19161
19178
  <html lang="en">
19162
19179
  <head>
19163
19180
  <meta charset="UTF-8">
19164
19181
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
19165
- <title>${title} - UiPath CLI</title>
19182
+ <title>${safeTitle} - UiPath CLI</title>
19166
19183
  <link rel="preconnect" href="https://fonts.googleapis.com">
19167
19184
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
19168
19185
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400&family=Poppins:wght@600&display=swap" rel="stylesheet">
@@ -19288,8 +19305,8 @@ var getBaseHtml = ({ title, message, type }) => {
19288
19305
  </div>
19289
19306
  </div>
19290
19307
  <div class="icon ${iconClass}">${icon}</div>
19291
- <h1>${title}</h1>
19292
- <p>${message}</p>
19308
+ <h1>${safeTitle}</h1>
19309
+ <p>${safeMessage}</p>
19293
19310
  <div class="footer">You can close this window</div>
19294
19311
  </div>
19295
19312
  </div>
@@ -19492,6 +19509,13 @@ class NodeAuthStrategy {
19492
19509
  if (c > 31 && (c < 128 || c > 159))
19493
19510
  safeUrl += ch;
19494
19511
  }
19512
+ if (opts?.noBrowser) {
19513
+ if (!opts.onAuthUrl) {
19514
+ throw new Error("Headless login (noBrowser) requires an onAuthUrl handler " + "to surface the authorize URL, but none was provided.");
19515
+ }
19516
+ opts.onAuthUrl(safeUrl);
19517
+ return;
19518
+ }
19495
19519
  const [openError] = await catchError(fs7.utils.open(url));
19496
19520
  if (!openError)
19497
19521
  return;
@@ -19573,6 +19597,12 @@ var normalizeAndValidateBaseUrl = (rawUrl) => {
19573
19597
  }
19574
19598
  return url.pathname.length > 1 ? url.origin : baseUrl;
19575
19599
  };
19600
+ var resolveScopes = (isExternalAppAuth, customScopes, fileScopes) => {
19601
+ const requestedScopes = customScopes?.length ? customScopes : fileScopes ?? [];
19602
+ if (isExternalAppAuth)
19603
+ return requestedScopes;
19604
+ return [...new Set([...DEFAULT_SCOPES, ...requestedScopes])];
19605
+ };
19576
19606
  var resolveConfigAsync = async ({
19577
19607
  customAuthority,
19578
19608
  customClientId,
@@ -19603,7 +19633,7 @@ var resolveConfigAsync = async ({
19603
19633
  clientSecret = fileAuth.clientSecret;
19604
19634
  }
19605
19635
  const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && Boolean(clientSecret);
19606
- const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : isExternalAppAuth ? [] : DEFAULT_SCOPES;
19636
+ const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
19607
19637
  return {
19608
19638
  clientId,
19609
19639
  clientSecret,
@@ -20250,6 +20280,105 @@ var exchangeCodeForTokens = async ({
20250
20280
  };
20251
20281
  // src/loginStatus.ts
20252
20282
  init_src();
20283
+
20284
+ // src/authProfile.ts
20285
+ init_src();
20286
+ init_constants();
20287
+ var DEFAULT_AUTH_PROFILE = "default";
20288
+ var PROFILE_DIR = "profiles";
20289
+ var PROFILE_NAME_RE = /^[A-Za-z0-9._-]+$/;
20290
+ var ACTIVE_AUTH_PROFILE_KEY = Symbol.for("@uipath/auth/ActiveAuthProfile");
20291
+ var AUTH_PROFILE_STORAGE_KEY = Symbol.for("@uipath/auth/ProfileStorage");
20292
+ var globalSlot2 = globalThis;
20293
+ function isAuthProfileStorage(value) {
20294
+ return value !== null && typeof value === "object" && "getStore" in value && "run" in value;
20295
+ }
20296
+ function createProfileStorage() {
20297
+ const [error, mod] = catchError(() => __require("node:async_hooks"));
20298
+ if (error || typeof mod?.AsyncLocalStorage !== "function") {
20299
+ return {
20300
+ getStore: () => {
20301
+ return;
20302
+ },
20303
+ run: (_store, fn) => fn()
20304
+ };
20305
+ }
20306
+ return new mod.AsyncLocalStorage;
20307
+ }
20308
+ function getProfileStorage() {
20309
+ const existing = globalSlot2[AUTH_PROFILE_STORAGE_KEY];
20310
+ if (isAuthProfileStorage(existing)) {
20311
+ return existing;
20312
+ }
20313
+ const storage = createProfileStorage();
20314
+ globalSlot2[AUTH_PROFILE_STORAGE_KEY] = storage;
20315
+ return storage;
20316
+ }
20317
+ var profileStorage = getProfileStorage();
20318
+
20319
+ class AuthProfileValidationError extends Error {
20320
+ constructor(message) {
20321
+ super(message);
20322
+ this.name = "AuthProfileValidationError";
20323
+ }
20324
+ }
20325
+ function normalizeAuthProfileName(profile) {
20326
+ if (profile === undefined || profile === DEFAULT_AUTH_PROFILE) {
20327
+ return;
20328
+ }
20329
+ if (profile.length === 0 || profile === "." || profile === ".." || !PROFILE_NAME_RE.test(profile)) {
20330
+ throw new AuthProfileValidationError(`Invalid profile name "${profile}". Profile names may contain only letters, numbers, '.', '_', and '-'.`);
20331
+ }
20332
+ return profile;
20333
+ }
20334
+ function setActiveAuthProfile(profile) {
20335
+ const normalized = normalizeAuthProfileName(profile);
20336
+ const scopedState = profileStorage.getStore();
20337
+ if (scopedState !== undefined) {
20338
+ if (normalized === undefined) {
20339
+ delete scopedState.profile;
20340
+ return;
20341
+ }
20342
+ scopedState.profile = normalized;
20343
+ return;
20344
+ }
20345
+ if (normalized === undefined) {
20346
+ delete globalSlot2[ACTIVE_AUTH_PROFILE_KEY];
20347
+ return;
20348
+ }
20349
+ globalSlot2[ACTIVE_AUTH_PROFILE_KEY] = { profile: normalized };
20350
+ }
20351
+ function clearActiveAuthProfile() {
20352
+ const scopedState = profileStorage.getStore();
20353
+ if (scopedState !== undefined) {
20354
+ delete scopedState.profile;
20355
+ return;
20356
+ }
20357
+ delete globalSlot2[ACTIVE_AUTH_PROFILE_KEY];
20358
+ }
20359
+ function getActiveAuthProfile() {
20360
+ const scopedState = profileStorage.getStore();
20361
+ if (scopedState !== undefined) {
20362
+ return scopedState.profile;
20363
+ }
20364
+ return globalSlot2[ACTIVE_AUTH_PROFILE_KEY]?.profile;
20365
+ }
20366
+ function runWithAuthProfile(profile, fn) {
20367
+ const normalized = normalizeAuthProfileName(profile);
20368
+ return profileStorage.run(normalized === undefined ? {} : { profile: normalized }, fn);
20369
+ }
20370
+ function resolveAuthProfileFilePath(profile) {
20371
+ const normalized = normalizeAuthProfileName(profile);
20372
+ if (normalized === undefined) {
20373
+ throw new AuthProfileValidationError(`"${DEFAULT_AUTH_PROFILE}" is the built-in profile and does not have a profile file path.`);
20374
+ }
20375
+ const fs7 = getFileSystem();
20376
+ return fs7.path.join(fs7.env.homedir(), UIPATH_HOME_DIR, PROFILE_DIR, normalized, AUTH_FILENAME);
20377
+ }
20378
+ function getActiveAuthProfileFilePath() {
20379
+ const profile = getActiveAuthProfile();
20380
+ return profile ? resolveAuthProfileFilePath(profile) : undefined;
20381
+ }
20253
20382
  // src/utils/jwt.ts
20254
20383
  class InvalidIssuerError extends Error {
20255
20384
  expected;
@@ -20378,23 +20507,74 @@ var readAuthFromEnv = () => {
20378
20507
  organizationId,
20379
20508
  tenantName,
20380
20509
  tenantId,
20381
- expiration
20510
+ expiration,
20511
+ source: "env" /* Env */
20382
20512
  };
20383
20513
  };
20384
20514
 
20515
+ // src/refreshCircuitBreaker.ts
20516
+ init_src();
20517
+ var BREAKER_SUFFIX = ".refresh-state";
20518
+ var BACKOFF_BASE_MS = 60000;
20519
+ var BACKOFF_CAP_MS = 60 * 60 * 1000;
20520
+ var SURFACE_WINDOW_MS = 60 * 60 * 1000;
20521
+ async function refreshTokenFingerprint(refreshToken) {
20522
+ const bytes = new TextEncoder().encode(refreshToken);
20523
+ if (globalThis.crypto?.subtle) {
20524
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
20525
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
20526
+ }
20527
+ const { createHash } = await import("node:crypto");
20528
+ return createHash("sha256").update(refreshToken).digest("hex").slice(0, 16);
20529
+ }
20530
+ function breakerPathFor(authPath) {
20531
+ return `${authPath}${BREAKER_SUFFIX}`;
20532
+ }
20533
+ async function loadRefreshBreaker(authPath) {
20534
+ const fs7 = getFileSystem();
20535
+ try {
20536
+ const content = await fs7.readFile(breakerPathFor(authPath), "utf-8");
20537
+ if (!content)
20538
+ return {};
20539
+ const parsed = JSON.parse(content);
20540
+ return parsed && typeof parsed === "object" ? parsed : {};
20541
+ } catch {
20542
+ return {};
20543
+ }
20544
+ }
20545
+ async function saveRefreshBreaker(authPath, state) {
20546
+ try {
20547
+ const fs7 = getFileSystem();
20548
+ const path3 = breakerPathFor(authPath);
20549
+ await fs7.mkdir(fs7.path.dirname(path3));
20550
+ const tempPath = `${path3}.tmp`;
20551
+ await fs7.writeFile(tempPath, JSON.stringify(state));
20552
+ await fs7.rename(tempPath, path3);
20553
+ } catch {}
20554
+ }
20555
+ async function clearRefreshBreaker(authPath) {
20556
+ const fs7 = getFileSystem();
20557
+ const path3 = breakerPathFor(authPath);
20558
+ try {
20559
+ if (await fs7.exists(path3)) {
20560
+ await fs7.rm(path3);
20561
+ }
20562
+ } catch {}
20563
+ }
20564
+ function nextBackoffMs(attempts) {
20565
+ const shift = Math.max(0, attempts - 1);
20566
+ return Math.min(BACKOFF_BASE_MS * 2 ** shift, BACKOFF_CAP_MS);
20567
+ }
20568
+ function shouldSurface(state, nowMs) {
20569
+ if (state.lastSurfacedAtMs === undefined)
20570
+ return true;
20571
+ return nowMs - state.lastSurfacedAtMs >= SURFACE_WINDOW_MS;
20572
+ }
20573
+
20385
20574
  // src/robotClientFallback.ts
20386
20575
  init_src();
20387
20576
  var DEFAULT_TIMEOUT_MS = 1000;
20388
20577
  var CLOSE_TIMEOUT_MS = 500;
20389
- var NOTICE_SENTINEL = Symbol.for("@uipath/auth/robotFallbackNoticePrinted");
20390
- var printNoticeOnce = () => {
20391
- const slot = globalThis;
20392
- if (slot[NOTICE_SENTINEL])
20393
- return;
20394
- slot[NOTICE_SENTINEL] = true;
20395
- catchError(() => process.stderr.write(`Using UiPath Robot credentials. Run 'uip login' for a dedicated session.
20396
- `));
20397
- };
20398
20578
  var ROBOT_USER_SERVICES_PIPE = "UiPathUserServices";
20399
20579
  var ROBOT_USER_SERVICES_ALTERNATE_PIPE = `${ROBOT_USER_SERVICES_PIPE}Alternate`;
20400
20580
  var PIPE_NAME_MAX_LENGTH = 103;
@@ -20510,7 +20690,6 @@ var tryRobotClientFallback = async (options = {}) => {
20510
20690
  issuerFromToken = issClaim;
20511
20691
  }
20512
20692
  }
20513
- printNoticeOnce();
20514
20693
  return {
20515
20694
  accessToken,
20516
20695
  baseUrl: parsedUrl.baseUrl,
@@ -20740,19 +20919,329 @@ var LoginStatusSource;
20740
20919
  ((LoginStatusSource2) => {
20741
20920
  LoginStatusSource2["File"] = "file";
20742
20921
  LoginStatusSource2["Robot"] = "robot";
20922
+ LoginStatusSource2["Env"] = "env";
20743
20923
  })(LoginStatusSource ||= {});
20744
- function normalizeTokenRefreshFailure() {
20745
- return "stored refresh token is invalid or expired";
20924
+ var getLoginStatusAsync = async (options = {}) => {
20925
+ return getLoginStatusWithDeps(options);
20926
+ };
20927
+ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
20928
+ const {
20929
+ resolveEnvFilePath = resolveEnvFilePathAsync,
20930
+ loadEnvFile = loadEnvFileAsync,
20931
+ saveEnvFile = saveEnvFileAsync,
20932
+ getFs = getFileSystem,
20933
+ refreshToken: refreshTokenFn = refreshAccessToken,
20934
+ resolveConfig = resolveConfigAsync,
20935
+ robotFallback = tryRobotClientFallback,
20936
+ loadBreaker = loadRefreshBreaker,
20937
+ saveBreaker = saveRefreshBreaker,
20938
+ clearBreaker = clearRefreshBreaker
20939
+ } = deps;
20940
+ if (isRobotAuthEnforced()) {
20941
+ return resolveRobotEnforcedStatus(robotFallback);
20942
+ }
20943
+ if (isEnvAuthEnabled()) {
20944
+ return readAuthFromEnv();
20945
+ }
20946
+ const activeProfile = getActiveAuthProfile();
20947
+ const activeProfileFilePath = getActiveAuthProfileFilePath();
20948
+ const usingActiveProfile = activeProfile !== undefined && (options.envFilePath === undefined || options.envFilePath === activeProfileFilePath);
20949
+ const envFilePath = options.envFilePath ?? activeProfileFilePath ?? DEFAULT_ENV_FILENAME;
20950
+ const { ensureTokenValidityMinutes } = options;
20951
+ const { absolutePath } = await resolveEnvFilePath(envFilePath);
20952
+ if (absolutePath === undefined) {
20953
+ if (usingActiveProfile) {
20954
+ return {
20955
+ loginStatus: "Not logged in",
20956
+ hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
20957
+ };
20958
+ }
20959
+ return resolveBorrowedRobotStatus(robotFallback);
20960
+ }
20961
+ const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
20962
+ if ("status" in loaded) {
20963
+ return loaded.status;
20964
+ }
20965
+ const { credentials } = loaded;
20966
+ const globalHint = () => usingActiveProfile ? Promise.resolve(undefined) : getGlobalCredsHint(getFs, loadEnvFile, absolutePath, envFilePath);
20967
+ const expiration = getTokenExpiration(credentials.UIPATH_ACCESS_TOKEN);
20968
+ const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
20969
+ let tokens = {
20970
+ accessToken: credentials.UIPATH_ACCESS_TOKEN,
20971
+ refreshToken: credentials.UIPATH_REFRESH_TOKEN,
20972
+ expiration,
20973
+ lockReleaseFailed: false
20974
+ };
20975
+ const refreshToken = credentials.UIPATH_REFRESH_TOKEN;
20976
+ if (expiration && expiration <= outerThreshold && refreshToken) {
20977
+ const refreshed = await attemptRefresh({
20978
+ absolutePath,
20979
+ credentials,
20980
+ accessToken: credentials.UIPATH_ACCESS_TOKEN,
20981
+ refreshToken,
20982
+ expiration,
20983
+ ensureTokenValidityMinutes,
20984
+ getFs,
20985
+ loadEnvFile,
20986
+ saveEnvFile,
20987
+ refreshFn: refreshTokenFn,
20988
+ resolveConfig,
20989
+ loadBreaker,
20990
+ saveBreaker,
20991
+ clearBreaker,
20992
+ globalHint
20993
+ });
20994
+ if (refreshed.kind === "terminal") {
20995
+ return refreshed.status;
20996
+ }
20997
+ tokens = refreshed.tokens;
20998
+ }
20999
+ return buildFileStatus(tokens, credentials, globalHint);
21000
+ };
21001
+ async function resolveRobotEnforcedStatus(robotFallback) {
21002
+ if (isEnvAuthEnabled()) {
21003
+ throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
21004
+ }
21005
+ const robotCreds = await robotFallback({ force: true });
21006
+ if (!robotCreds) {
21007
+ return {
21008
+ loginStatus: "Not logged in",
21009
+ 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.`
21010
+ };
21011
+ }
21012
+ return buildRobotStatus(robotCreds);
20746
21013
  }
20747
- function normalizeTokenRefreshUnavailableFailure() {
20748
- return "token refresh failed before authentication completed";
21014
+ async function resolveBorrowedRobotStatus(robotFallback) {
21015
+ const robotCreds = await robotFallback();
21016
+ return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
20749
21017
  }
20750
- function errorMessage(error) {
20751
- return error instanceof Error ? error.message : String(error);
21018
+ async function loadFileCredentials(loadEnvFile, absolutePath) {
21019
+ let credentials;
21020
+ try {
21021
+ credentials = await loadEnvFile({ envPath: absolutePath });
21022
+ } catch (error) {
21023
+ if (isFileNotFoundError(error)) {
21024
+ return { status: { loginStatus: "Not logged in" } };
21025
+ }
21026
+ throw error;
21027
+ }
21028
+ if (!credentials.UIPATH_ACCESS_TOKEN) {
21029
+ return { status: { loginStatus: "Not logged in" } };
21030
+ }
21031
+ return { credentials };
21032
+ }
21033
+ async function getGlobalCredsHint(getFs, loadEnvFile, absolutePath, envFilePath) {
21034
+ const fs7 = getFs();
21035
+ const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
21036
+ if (absolutePath === globalPath)
21037
+ return;
21038
+ if (!await fs7.exists(globalPath))
21039
+ return;
21040
+ try {
21041
+ const globalCreds = await loadEnvFile({ envPath: globalPath });
21042
+ if (!globalCreds.UIPATH_ACCESS_TOKEN)
21043
+ return;
21044
+ const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
21045
+ if (globalExp && globalExp <= new Date)
21046
+ return;
21047
+ 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.`;
21048
+ } catch {
21049
+ return;
21050
+ }
20752
21051
  }
20753
21052
  function computeExpirationThreshold(ensureTokenValidityMinutes) {
20754
21053
  return new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
20755
21054
  }
21055
+ async function attemptRefresh(ctx) {
21056
+ const shortCircuit = await circuitBreakerShortCircuit(ctx);
21057
+ if (shortCircuit) {
21058
+ return { kind: "terminal", status: shortCircuit };
21059
+ }
21060
+ let release;
21061
+ try {
21062
+ release = await ctx.getFs().acquireLock(ctx.absolutePath);
21063
+ } catch (error) {
21064
+ return {
21065
+ kind: "terminal",
21066
+ status: await lockAcquireFailureStatus(ctx, error)
21067
+ };
21068
+ }
21069
+ let lockedFailure;
21070
+ let lockReleaseFailed = false;
21071
+ let success;
21072
+ try {
21073
+ const outcome = await runRefreshLocked({
21074
+ absolutePath: ctx.absolutePath,
21075
+ refreshToken: ctx.refreshToken,
21076
+ customAuthority: ctx.credentials.UIPATH_URL,
21077
+ ensureTokenValidityMinutes: ctx.ensureTokenValidityMinutes,
21078
+ loadEnvFile: ctx.loadEnvFile,
21079
+ saveEnvFile: ctx.saveEnvFile,
21080
+ refreshFn: ctx.refreshFn,
21081
+ resolveConfig: ctx.resolveConfig,
21082
+ loadBreaker: ctx.loadBreaker,
21083
+ saveBreaker: ctx.saveBreaker,
21084
+ clearBreaker: ctx.clearBreaker
21085
+ });
21086
+ if (outcome.kind === "fail") {
21087
+ lockedFailure = outcome.status;
21088
+ } else {
21089
+ success = outcome;
21090
+ }
21091
+ } finally {
21092
+ try {
21093
+ await release();
21094
+ } catch {
21095
+ lockReleaseFailed = true;
21096
+ }
21097
+ }
21098
+ if (lockedFailure) {
21099
+ const globalHint = await ctx.globalHint();
21100
+ const base = globalHint ? { ...lockedFailure, loginStatus: "Expired", hint: globalHint } : lockedFailure;
21101
+ return {
21102
+ kind: "terminal",
21103
+ status: lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base
21104
+ };
21105
+ }
21106
+ return {
21107
+ kind: "refreshed",
21108
+ tokens: {
21109
+ accessToken: success?.accessToken,
21110
+ refreshToken: success?.refreshToken,
21111
+ expiration: success?.expiration,
21112
+ tokenRefresh: success?.tokenRefresh,
21113
+ persistenceWarning: success?.persistenceWarning,
21114
+ lockReleaseFailed
21115
+ }
21116
+ };
21117
+ }
21118
+ async function buildFileStatus(tokens, credentials, globalHint) {
21119
+ const result = {
21120
+ loginStatus: tokens.expiration && tokens.expiration <= new Date ? "Expired" : "Logged in",
21121
+ accessToken: tokens.accessToken,
21122
+ refreshToken: tokens.refreshToken,
21123
+ baseUrl: credentials.UIPATH_URL,
21124
+ organizationName: credentials.UIPATH_ORGANIZATION_NAME,
21125
+ organizationId: credentials.UIPATH_ORGANIZATION_ID,
21126
+ tenantName: credentials.UIPATH_TENANT_NAME,
21127
+ tenantId: credentials.UIPATH_TENANT_ID,
21128
+ expiration: tokens.expiration,
21129
+ source: "file" /* File */,
21130
+ ...tokens.persistenceWarning ? { hint: tokens.persistenceWarning, persistenceFailed: true } : {},
21131
+ ...tokens.lockReleaseFailed ? { lockReleaseFailed: true } : {},
21132
+ ...tokens.tokenRefresh ? { tokenRefresh: tokens.tokenRefresh } : {}
21133
+ };
21134
+ if (result.loginStatus === "Expired") {
21135
+ const hint = await globalHint();
21136
+ if (hint) {
21137
+ result.hint = hint;
21138
+ }
21139
+ }
21140
+ return result;
21141
+ }
21142
+ function buildRobotStatus(robotCreds) {
21143
+ return {
21144
+ loginStatus: "Logged in",
21145
+ accessToken: robotCreds.accessToken,
21146
+ baseUrl: robotCreds.baseUrl,
21147
+ organizationName: robotCreds.organizationName,
21148
+ organizationId: robotCreds.organizationId,
21149
+ tenantName: robotCreds.tenantName,
21150
+ tenantId: robotCreds.tenantId,
21151
+ issuer: robotCreds.issuer,
21152
+ expiration: getTokenExpiration(robotCreds.accessToken),
21153
+ source: "robot" /* Robot */
21154
+ };
21155
+ }
21156
+ var isFileNotFoundError = (error) => {
21157
+ if (!(error instanceof Object))
21158
+ return false;
21159
+ return error.code === "ENOENT";
21160
+ };
21161
+ async function circuitBreakerShortCircuit(ctx) {
21162
+ const {
21163
+ absolutePath,
21164
+ refreshToken,
21165
+ accessToken,
21166
+ credentials,
21167
+ expiration,
21168
+ loadBreaker,
21169
+ saveBreaker,
21170
+ clearBreaker
21171
+ } = ctx;
21172
+ const fingerprint = await refreshTokenFingerprint(refreshToken);
21173
+ const breaker = await loadBreaker(absolutePath).catch(() => ({}));
21174
+ if (breaker.deadTokenFp && breaker.deadTokenFp !== fingerprint) {
21175
+ await clearBreaker(absolutePath);
21176
+ breaker.deadTokenFp = undefined;
21177
+ }
21178
+ const nowMs = Date.now();
21179
+ const tokenIsDead = breaker.deadTokenFp === fingerprint;
21180
+ const inBackoff = breaker.backoffUntilMs !== undefined && nowMs < breaker.backoffUntilMs;
21181
+ if (!tokenIsDead && !inBackoff)
21182
+ return;
21183
+ const globalHint = await ctx.globalHint();
21184
+ const suppressed = !shouldSurface(breaker, nowMs);
21185
+ if (!suppressed) {
21186
+ await saveBreaker(absolutePath, {
21187
+ ...breaker,
21188
+ lastSurfacedAtMs: nowMs
21189
+ });
21190
+ }
21191
+ 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>.";
21192
+ const backoffHint = "Token refresh is temporarily backed off after a recent network error and will retry automatically once the backoff window elapses.";
21193
+ return {
21194
+ loginStatus: globalHint ? "Expired" : "Refresh Failed",
21195
+ ...globalHint ? {
21196
+ accessToken,
21197
+ refreshToken,
21198
+ baseUrl: credentials.UIPATH_URL,
21199
+ organizationName: credentials.UIPATH_ORGANIZATION_NAME,
21200
+ organizationId: credentials.UIPATH_ORGANIZATION_ID,
21201
+ tenantName: credentials.UIPATH_TENANT_NAME,
21202
+ tenantId: credentials.UIPATH_TENANT_ID,
21203
+ expiration,
21204
+ source: "file" /* File */
21205
+ } : {},
21206
+ hint: globalHint ?? (tokenIsDead ? deadHint : backoffHint),
21207
+ refreshCircuitOpen: true,
21208
+ refreshTelemetrySuppressed: suppressed,
21209
+ tokenRefresh: { attempted: false, success: false }
21210
+ };
21211
+ }
21212
+ async function lockAcquireFailureStatus(ctx, error) {
21213
+ const msg = errorMessage(error);
21214
+ const globalHint = await ctx.globalHint();
21215
+ if (globalHint) {
21216
+ return {
21217
+ loginStatus: "Expired",
21218
+ accessToken: ctx.accessToken,
21219
+ refreshToken: ctx.refreshToken,
21220
+ baseUrl: ctx.credentials.UIPATH_URL,
21221
+ organizationName: ctx.credentials.UIPATH_ORGANIZATION_NAME,
21222
+ organizationId: ctx.credentials.UIPATH_ORGANIZATION_ID,
21223
+ tenantName: ctx.credentials.UIPATH_TENANT_NAME,
21224
+ tenantId: ctx.credentials.UIPATH_TENANT_ID,
21225
+ expiration: ctx.expiration,
21226
+ source: "file" /* File */,
21227
+ hint: globalHint,
21228
+ tokenRefresh: {
21229
+ attempted: false,
21230
+ success: false,
21231
+ errorMessage: `lock acquisition failed: ${msg}`
21232
+ }
21233
+ };
21234
+ }
21235
+ return {
21236
+ loginStatus: "Refresh Failed",
21237
+ 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.",
21238
+ tokenRefresh: {
21239
+ attempted: false,
21240
+ success: false,
21241
+ errorMessage: `lock acquisition failed: ${msg}`
21242
+ }
21243
+ };
21244
+ }
20756
21245
  async function runRefreshLocked(inputs) {
20757
21246
  const {
20758
21247
  absolutePath,
@@ -20762,7 +21251,10 @@ async function runRefreshLocked(inputs) {
20762
21251
  loadEnvFile,
20763
21252
  saveEnvFile,
20764
21253
  refreshFn,
20765
- resolveConfig
21254
+ resolveConfig,
21255
+ loadBreaker,
21256
+ saveBreaker,
21257
+ clearBreaker
20766
21258
  } = inputs;
20767
21259
  const expirationThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
20768
21260
  let fresh;
@@ -20785,6 +21277,7 @@ async function runRefreshLocked(inputs) {
20785
21277
  const freshAccess = fresh.UIPATH_ACCESS_TOKEN;
20786
21278
  const freshExp = freshAccess ? getTokenExpiration(freshAccess) : undefined;
20787
21279
  if (freshAccess && freshExp && freshExp > expirationThreshold) {
21280
+ await clearBreaker(absolutePath);
20788
21281
  return {
20789
21282
  kind: "ok",
20790
21283
  accessToken: freshAccess,
@@ -20808,8 +21301,21 @@ async function runRefreshLocked(inputs) {
20808
21301
  refreshedRefresh = refreshed.refreshToken;
20809
21302
  } catch (error) {
20810
21303
  const isOAuthFailure = isTokenRefreshOAuthFailure(error);
20811
- const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
21304
+ 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.";
20812
21305
  const message = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
21306
+ const fp = await refreshTokenFingerprint(tokenForIdP);
21307
+ if (isOAuthFailure) {
21308
+ await saveBreaker(absolutePath, { deadTokenFp: fp });
21309
+ } else {
21310
+ const prior = await loadBreaker(absolutePath).catch(() => ({}));
21311
+ const attempts = (prior.attempts ?? 0) + 1;
21312
+ await saveBreaker(absolutePath, {
21313
+ ...prior,
21314
+ deadTokenFp: undefined,
21315
+ attempts,
21316
+ backoffUntilMs: Date.now() + nextBackoffMs(attempts)
21317
+ });
21318
+ }
20813
21319
  return {
20814
21320
  kind: "fail",
20815
21321
  status: {
@@ -20838,6 +21344,7 @@ async function runRefreshLocked(inputs) {
20838
21344
  }
20839
21345
  };
20840
21346
  }
21347
+ await clearBreaker(absolutePath);
20841
21348
  try {
20842
21349
  await saveEnvFile({
20843
21350
  envPath: absolutePath,
@@ -20870,212 +21377,15 @@ async function runRefreshLocked(inputs) {
20870
21377
  };
20871
21378
  }
20872
21379
  }
20873
- var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
20874
- const {
20875
- resolveEnvFilePath = resolveEnvFilePathAsync,
20876
- loadEnvFile = loadEnvFileAsync,
20877
- saveEnvFile = saveEnvFileAsync,
20878
- getFs = getFileSystem,
20879
- refreshToken: refreshTokenFn = refreshAccessToken,
20880
- resolveConfig = resolveConfigAsync,
20881
- robotFallback = tryRobotClientFallback
20882
- } = deps;
20883
- if (isRobotAuthEnforced()) {
20884
- if (isEnvAuthEnabled()) {
20885
- throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
20886
- }
20887
- const robotCreds = await robotFallback({ force: true });
20888
- if (!robotCreds) {
20889
- return {
20890
- loginStatus: "Not logged in",
20891
- 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.`
20892
- };
20893
- }
20894
- const expiration2 = getTokenExpiration(robotCreds.accessToken);
20895
- return {
20896
- loginStatus: "Logged in",
20897
- accessToken: robotCreds.accessToken,
20898
- baseUrl: robotCreds.baseUrl,
20899
- organizationName: robotCreds.organizationName,
20900
- organizationId: robotCreds.organizationId,
20901
- tenantName: robotCreds.tenantName,
20902
- tenantId: robotCreds.tenantId,
20903
- issuer: robotCreds.issuer,
20904
- expiration: expiration2,
20905
- source: "robot" /* Robot */
20906
- };
20907
- }
20908
- if (isEnvAuthEnabled()) {
20909
- return readAuthFromEnv();
20910
- }
20911
- const { envFilePath = DEFAULT_ENV_FILENAME, ensureTokenValidityMinutes } = options;
20912
- const { absolutePath } = await resolveEnvFilePath(envFilePath);
20913
- if (absolutePath === undefined) {
20914
- const robotCreds = await robotFallback();
20915
- if (robotCreds) {
20916
- const expiration2 = getTokenExpiration(robotCreds.accessToken);
20917
- const status = {
20918
- loginStatus: "Logged in",
20919
- accessToken: robotCreds.accessToken,
20920
- baseUrl: robotCreds.baseUrl,
20921
- organizationName: robotCreds.organizationName,
20922
- organizationId: robotCreds.organizationId,
20923
- tenantName: robotCreds.tenantName,
20924
- tenantId: robotCreds.tenantId,
20925
- issuer: robotCreds.issuer,
20926
- expiration: expiration2,
20927
- source: "robot" /* Robot */
20928
- };
20929
- return status;
20930
- }
20931
- return { loginStatus: "Not logged in" };
20932
- }
20933
- let credentials;
20934
- try {
20935
- credentials = await loadEnvFile({ envPath: absolutePath });
20936
- } catch (error) {
20937
- if (isFileNotFoundError(error)) {
20938
- return { loginStatus: "Not logged in" };
20939
- }
20940
- throw error;
20941
- }
20942
- if (!credentials.UIPATH_ACCESS_TOKEN) {
20943
- return { loginStatus: "Not logged in" };
20944
- }
20945
- let accessToken = credentials.UIPATH_ACCESS_TOKEN;
20946
- let refreshToken = credentials.UIPATH_REFRESH_TOKEN;
20947
- let expiration = getTokenExpiration(accessToken);
20948
- let persistenceWarning;
20949
- let lockReleaseFailed = false;
20950
- let tokenRefresh;
20951
- const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
20952
- const tryGlobalCredsHint = async () => {
20953
- const fs7 = getFs();
20954
- const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
20955
- if (absolutePath === globalPath)
20956
- return;
20957
- if (!await fs7.exists(globalPath))
20958
- return;
20959
- try {
20960
- const globalCreds = await loadEnvFile({ envPath: globalPath });
20961
- if (!globalCreds.UIPATH_ACCESS_TOKEN)
20962
- return;
20963
- const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
20964
- if (globalExp && globalExp <= new Date)
20965
- return;
20966
- 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.`;
20967
- } catch {
20968
- return;
20969
- }
20970
- };
20971
- if (expiration && expiration <= outerThreshold && refreshToken) {
20972
- let release;
20973
- try {
20974
- release = await getFs().acquireLock(absolutePath);
20975
- } catch (error) {
20976
- const msg = errorMessage(error);
20977
- const globalHint = await tryGlobalCredsHint();
20978
- if (globalHint) {
20979
- return {
20980
- loginStatus: "Expired",
20981
- accessToken,
20982
- refreshToken,
20983
- baseUrl: credentials.UIPATH_URL,
20984
- organizationName: credentials.UIPATH_ORGANIZATION_NAME,
20985
- organizationId: credentials.UIPATH_ORGANIZATION_ID,
20986
- tenantName: credentials.UIPATH_TENANT_NAME,
20987
- tenantId: credentials.UIPATH_TENANT_ID,
20988
- expiration,
20989
- source: "file" /* File */,
20990
- hint: globalHint,
20991
- tokenRefresh: {
20992
- attempted: false,
20993
- success: false,
20994
- errorMessage: `lock acquisition failed: ${msg}`
20995
- }
20996
- };
20997
- }
20998
- return {
20999
- loginStatus: "Refresh Failed",
21000
- 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.",
21001
- tokenRefresh: {
21002
- attempted: false,
21003
- success: false,
21004
- errorMessage: `lock acquisition failed: ${msg}`
21005
- }
21006
- };
21007
- }
21008
- let lockedFailure;
21009
- try {
21010
- const outcome = await runRefreshLocked({
21011
- absolutePath,
21012
- refreshToken,
21013
- customAuthority: credentials.UIPATH_URL,
21014
- ensureTokenValidityMinutes,
21015
- loadEnvFile,
21016
- saveEnvFile,
21017
- refreshFn: refreshTokenFn,
21018
- resolveConfig
21019
- });
21020
- if (outcome.kind === "fail") {
21021
- lockedFailure = outcome.status;
21022
- } else {
21023
- accessToken = outcome.accessToken;
21024
- refreshToken = outcome.refreshToken;
21025
- expiration = outcome.expiration;
21026
- tokenRefresh = outcome.tokenRefresh;
21027
- if (outcome.persistenceWarning) {
21028
- persistenceWarning = outcome.persistenceWarning;
21029
- }
21030
- }
21031
- } finally {
21032
- try {
21033
- await release();
21034
- } catch {
21035
- lockReleaseFailed = true;
21036
- }
21037
- }
21038
- if (lockedFailure) {
21039
- const globalHint = await tryGlobalCredsHint();
21040
- const base = globalHint ? {
21041
- ...lockedFailure,
21042
- loginStatus: "Expired",
21043
- hint: globalHint
21044
- } : lockedFailure;
21045
- return lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base;
21046
- }
21047
- }
21048
- const result = {
21049
- loginStatus: expiration && expiration <= new Date ? "Expired" : "Logged in",
21050
- accessToken,
21051
- refreshToken,
21052
- baseUrl: credentials.UIPATH_URL,
21053
- organizationName: credentials.UIPATH_ORGANIZATION_NAME,
21054
- organizationId: credentials.UIPATH_ORGANIZATION_ID,
21055
- tenantName: credentials.UIPATH_TENANT_NAME,
21056
- tenantId: credentials.UIPATH_TENANT_ID,
21057
- expiration,
21058
- source: "file" /* File */,
21059
- ...persistenceWarning ? { hint: persistenceWarning, persistenceFailed: true } : {},
21060
- ...lockReleaseFailed ? { lockReleaseFailed: true } : {},
21061
- ...tokenRefresh ? { tokenRefresh } : {}
21062
- };
21063
- if (result.loginStatus === "Expired") {
21064
- const globalHint = await tryGlobalCredsHint();
21065
- if (globalHint) {
21066
- result.hint = globalHint;
21067
- }
21068
- }
21069
- return result;
21070
- };
21071
- var isFileNotFoundError = (error) => {
21072
- if (!(error instanceof Object))
21073
- return false;
21074
- return error.code === "ENOENT";
21075
- };
21076
- var getLoginStatusAsync = async (options = {}) => {
21077
- return getLoginStatusWithDeps(options);
21078
- };
21380
+ function normalizeTokenRefreshFailure() {
21381
+ return "stored refresh token is invalid or expired";
21382
+ }
21383
+ function normalizeTokenRefreshUnavailableFailure() {
21384
+ return "token refresh failed before authentication completed";
21385
+ }
21386
+ function errorMessage(error) {
21387
+ return error instanceof Error ? error.message : String(error);
21388
+ }
21079
21389
 
21080
21390
  // src/authContext.ts
21081
21391
  var getAuthContext = async (options = {}) => {
@@ -21137,6 +21447,14 @@ var getAuthEnv = async (options = {}) => {
21137
21447
  return { authEnv, loginStatus: status };
21138
21448
  };
21139
21449
  // src/clientCredentials.ts
21450
+ class ClientCredentialsAuthenticationError extends Error {
21451
+ status;
21452
+ constructor(message, status) {
21453
+ super(message);
21454
+ this.name = "ClientCredentialsAuthenticationError";
21455
+ this.status = status;
21456
+ }
21457
+ }
21140
21458
  var clientCredentialsLogin = async ({
21141
21459
  clientId,
21142
21460
  clientSecret,
@@ -21184,9 +21502,9 @@ Troubleshooting:` + `
21184
21502
  • The requested scopes may not be available for your account` + `
21185
21503
  • Try using default scopes or contact your UiPath administrator`;
21186
21504
  }
21187
- throw new Error(`Client Credentials authentication failed (${tokenResponse.status})
21505
+ throw new ClientCredentialsAuthenticationError(`Client Credentials authentication failed (${tokenResponse.status})
21188
21506
  ` + `Error: ${errorType}
21189
- ` + `Details: ${errorDesc}${troubleshooting}`);
21507
+ ` + `Details: ${errorDesc}${troubleshooting}`, tokenResponse.status);
21190
21508
  }
21191
21509
  return {
21192
21510
  UIPATH_ACCESS_TOKEN: tokenData.access_token,
@@ -21216,6 +21534,49 @@ var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId)
21216
21534
  };
21217
21535
 
21218
21536
  // src/selectTenant.ts
21537
+ var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
21538
+ var INVALID_TENANT_CODE = "INVALID_TENANT";
21539
+
21540
+ class TenantSelectionError extends Error {
21541
+ availableTenants;
21542
+ organizationName;
21543
+ constructor(message, organizationName, availableTenants) {
21544
+ super(message);
21545
+ this.organizationName = organizationName;
21546
+ this.availableTenants = availableTenants;
21547
+ }
21548
+ }
21549
+
21550
+ class TenantSelectionRequiredError extends TenantSelectionError {
21551
+ code = TENANT_SELECTION_REQUIRED_CODE;
21552
+ constructor(organizationName, availableTenants) {
21553
+ super(`Multiple tenants available in organization "${organizationName}"; none selected.`, organizationName, availableTenants);
21554
+ this.name = "TenantSelectionRequiredError";
21555
+ }
21556
+ }
21557
+
21558
+ class InvalidTenantError extends TenantSelectionError {
21559
+ code = INVALID_TENANT_CODE;
21560
+ requestedTenant;
21561
+ constructor(requestedTenant, organizationName, availableTenants) {
21562
+ super(`Invalid tenant requested: "${requestedTenant}"
21563
+ ` + `Organization: ${organizationName}
21564
+ ` + `Available tenants: ${availableTenants.join(", ")}`, organizationName, availableTenants);
21565
+ this.name = "InvalidTenantError";
21566
+ this.requestedTenant = requestedTenant;
21567
+ }
21568
+ }
21569
+ var TENANT_SELECTION_CODES = new Set([
21570
+ TENANT_SELECTION_REQUIRED_CODE,
21571
+ INVALID_TENANT_CODE
21572
+ ]);
21573
+ function isTenantSelectionError(error) {
21574
+ if (!(error instanceof Object) || !("code" in error)) {
21575
+ return false;
21576
+ }
21577
+ const code = error.code;
21578
+ return typeof code === "string" && TENANT_SELECTION_CODES.has(code) && Array.isArray(error.availableTenants);
21579
+ }
21219
21580
  var selectTenantWithDeps = async (baseUrl, accessToken, organizationId, targetTenantName, interactive, deps = {}) => {
21220
21581
  const {
21221
21582
  fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
@@ -21228,13 +21589,10 @@ var selectTenantWithDeps = async (baseUrl, accessToken, organizationId, targetTe
21228
21589
  }
21229
21590
  const tenantNames = tenants.map((tenant) => tenant.name);
21230
21591
  let selectedIndex;
21231
- if (targetTenantName) {
21592
+ if (targetTenantName !== undefined) {
21232
21593
  selectedIndex = tenants.findIndex((tenant) => tenant.name === targetTenantName);
21233
21594
  if (selectedIndex === -1) {
21234
- const availableTenants = tenants.map((t) => t.name).join(", ");
21235
- throw new Error(`Invalid tenant requested: "${targetTenantName}"
21236
- ` + `Organization: ${organization.name}
21237
- ` + `Available tenants: ${availableTenants}`);
21595
+ throw new InvalidTenantError(targetTenantName, organization.name, tenantNames);
21238
21596
  }
21239
21597
  } else if (tenants.length === 1) {
21240
21598
  selectedIndex = 0;
@@ -21244,7 +21602,7 @@ var selectTenantWithDeps = async (baseUrl, accessToken, organizationId, targetTe
21244
21602
  }
21245
21603
  selectedIndex = await selectFromList(tenantNames, "Select a tenant:");
21246
21604
  } else {
21247
- selectedIndex = 0;
21605
+ throw new TenantSelectionRequiredError(organization.name, tenantNames);
21248
21606
  }
21249
21607
  const selectedTenant = tenants[selectedIndex];
21250
21608
  return [selectedTenant.name, selectedTenant.id, organization.name];
@@ -21273,7 +21631,8 @@ var interactiveLoginWithDeps = async (options, deps) => {
21273
21631
  organization,
21274
21632
  interactive,
21275
21633
  onEvent,
21276
- timeoutMs
21634
+ timeoutMs,
21635
+ noBrowser
21277
21636
  } = options;
21278
21637
  const emit = (event) => {
21279
21638
  if (!onEvent)
@@ -21282,12 +21641,22 @@ var interactiveLoginWithDeps = async (options, deps) => {
21282
21641
  onEvent(event);
21283
21642
  } catch {}
21284
21643
  };
21644
+ const deliverAuthUrl = (url) => {
21645
+ try {
21646
+ onEvent?.({ type: "auth-url", url });
21647
+ } catch (error) {
21648
+ throw new Error("Failed to deliver the authorize URL to the onEvent subscriber; " + "cannot continue headless login.", { cause: error });
21649
+ }
21650
+ };
21285
21651
  const config = await resolveConfig({
21286
21652
  customAuthority: authority,
21287
21653
  customClientId: clientId,
21288
21654
  customClientSecret: clientSecret
21289
21655
  });
21290
21656
  const { clientSecret: resolvedSecret } = config;
21657
+ if (noBrowser && !resolvedSecret && !onEvent) {
21658
+ throw new Error("noBrowser login requires an onEvent subscriber to receive the " + "auth-url event — the authorize URL is delivered through it.");
21659
+ }
21291
21660
  const authPromise = resolvedSecret ? (async () => {
21292
21661
  return await clientCredentials({
21293
21662
  clientId: config.clientId,
@@ -21302,7 +21671,9 @@ var interactiveLoginWithDeps = async (options, deps) => {
21302
21671
  clientSecret,
21303
21672
  scope,
21304
21673
  organization,
21305
- timeoutMs
21674
+ timeoutMs,
21675
+ noBrowser,
21676
+ onAuthUrl: noBrowser ? (url) => deliverAuthUrl(url) : undefined
21306
21677
  });
21307
21678
  return {
21308
21679
  UIPATH_ACCESS_TOKEN: authTokens.accessToken,
@@ -21333,10 +21704,12 @@ var interactiveLoginWithDeps = async (options, deps) => {
21333
21704
  credentials.UIPATH_TENANT_NAME = tenantName;
21334
21705
  credentials.UIPATH_TENANT_ID = tenantId;
21335
21706
  } catch (error) {
21336
- emit({
21337
- type: "tenant-fetch-failed",
21338
- message: error instanceof Error ? error.message : String(error)
21339
- });
21707
+ if (!isTenantSelectionError(error)) {
21708
+ emit({
21709
+ type: "tenant-fetch-failed",
21710
+ message: error instanceof Error ? error.message : String(error)
21711
+ });
21712
+ }
21340
21713
  throw error;
21341
21714
  }
21342
21715
  const fs7 = getFs();
@@ -21401,10 +21774,12 @@ init_src();
21401
21774
  async function logoutWithDeps(options, deps = {}) {
21402
21775
  const {
21403
21776
  resolveEnvFilePath = resolveEnvFilePathAsync,
21404
- getFileSystem: getFs = getFileSystem
21777
+ getFileSystem: getFs = getFileSystem,
21778
+ clearBreaker = clearRefreshBreaker,
21779
+ getActiveProfileFilePath = getActiveAuthProfileFilePath
21405
21780
  } = deps;
21406
21781
  const fs7 = getFs();
21407
- const { absolutePath } = await resolveEnvFilePath(options.file);
21782
+ const { absolutePath } = await resolveEnvFilePath(options.file ?? getActiveProfileFilePath());
21408
21783
  if (absolutePath && await fs7.exists(absolutePath)) {
21409
21784
  let release;
21410
21785
  try {
@@ -21416,6 +21791,7 @@ async function logoutWithDeps(options, deps = {}) {
21416
21791
  }
21417
21792
  try {
21418
21793
  await fs7.rm(absolutePath);
21794
+ await clearBreaker(absolutePath);
21419
21795
  } finally {
21420
21796
  if (release) {
21421
21797
  await release().catch(() => {});
@@ -21446,7 +21822,9 @@ var authenticate = async ({
21446
21822
  redirectUri,
21447
21823
  scope,
21448
21824
  organization,
21449
- timeoutMs
21825
+ timeoutMs,
21826
+ noBrowser,
21827
+ onAuthUrl
21450
21828
  }) => {
21451
21829
  const config = await resolveConfigAsync({
21452
21830
  customAuthority: baseUrl,
@@ -21496,7 +21874,7 @@ var authenticate = async ({
21496
21874
  const { NodeAuthStrategy: NodeAuthStrategy2 } = await Promise.resolve().then(() => (init_node_strategy(), exports_node_strategy));
21497
21875
  strategy = new NodeAuthStrategy2;
21498
21876
  }
21499
- const code = await strategy.execute(authUrl, effectiveRedirectUriUrl, state, { timeoutMs });
21877
+ const code = await strategy.execute(authUrl, effectiveRedirectUriUrl, state, { timeoutMs, noBrowser, onAuthUrl });
21500
21878
  return await exchangeCodeForTokens({
21501
21879
  code,
21502
21880
  codeVerifier: code_verifier,
@@ -21508,17 +21886,25 @@ var authenticate = async ({
21508
21886
  };
21509
21887
  export {
21510
21888
  setAuthFileConfig,
21889
+ setActiveAuthProfile,
21511
21890
  selectTenantWithDeps,
21891
+ saveRefreshBreaker,
21512
21892
  saveEnvFileAsync,
21893
+ runWithAuthProfile,
21513
21894
  resolveEnvFilePathAsync,
21514
21895
  resolveEnvFileLocationAsync,
21896
+ resolveAuthProfileFilePath,
21897
+ refreshTokenFingerprint,
21515
21898
  refreshAccessToken,
21516
21899
  readAuthFromEnv,
21517
21900
  parseJWT,
21901
+ normalizeAuthProfileName,
21518
21902
  logoutWithDeps,
21519
21903
  logout,
21904
+ loadRefreshBreaker,
21520
21905
  loadEnvFileAsync,
21521
21906
  isTokenRefreshOAuthFailure,
21907
+ isTenantSelectionError,
21522
21908
  isRobotAuthEnforced,
21523
21909
  isNode,
21524
21910
  isEnvAuthEnabled,
@@ -21529,17 +21915,31 @@ export {
21529
21915
  getLoginStatusAsync,
21530
21916
  getAuthEnv,
21531
21917
  getAuthContext,
21918
+ getActiveAuthProfileFilePath,
21919
+ getActiveAuthProfile,
21532
21920
  fetchTenantsAndOrganizations,
21533
21921
  clientCredentialsLogin,
21922
+ clearRefreshBreaker,
21923
+ clearActiveAuthProfile,
21534
21924
  authenticate,
21535
21925
  TokenRefreshOAuthError,
21926
+ TenantSelectionRequiredError,
21927
+ TenantSelectionError,
21928
+ TENANT_SELECTION_REQUIRED_CODE,
21536
21929
  LoginStatusSource,
21930
+ InvalidTenantError,
21537
21931
  InvalidBaseUrlError,
21932
+ INVALID_TENANT_CODE,
21538
21933
  EnvAuthConfigError,
21539
21934
  ENV_AUTH_VARS,
21540
21935
  ENV_AUTH_ENABLE_VAR,
21541
21936
  ENFORCE_ROBOT_AUTH_VAR,
21542
21937
  DEFAULT_ENV_FILENAME,
21938
+ DEFAULT_AUTH_PROFILE,
21543
21939
  DEFAULT_AUTH_FILENAME,
21940
+ ClientCredentialsAuthenticationError,
21941
+ AuthProfileValidationError,
21544
21942
  AUTH_TIMEOUT_ERROR_CODE
21545
21943
  };
21944
+
21945
+ //# debugId=B1F2D5989CE27CF464756E2164756E21