codex-multi-auth 2.21.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +8 -5
- package/config/schema/config.schema.json +8 -0
- package/dist/lib/accounts.d.ts +5 -0
- package/dist/lib/accounts.js +33 -4
- package/dist/lib/api-route-store.d.ts +7 -0
- package/dist/lib/api-route-store.js +100 -31
- package/dist/lib/auth/account-access.js +2 -1
- package/dist/lib/auth/auth.js +3 -2
- package/dist/lib/auth/device-auth.js +2 -1
- package/dist/lib/auth/http.d.ts +1 -0
- package/dist/lib/auth/http.js +1 -0
- package/dist/lib/codex-manager/account-manager-commands.js +1 -0
- package/dist/lib/codex-manager/api-login-menu.d.ts +1 -1
- package/dist/lib/codex-manager/api-login-menu.js +4 -6
- package/dist/lib/codex-manager/commands/locale.d.ts +12 -0
- package/dist/lib/codex-manager/commands/locale.js +25 -0
- package/dist/lib/codex-manager/commands/status.d.ts +5 -1
- package/dist/lib/codex-manager/commands/status.js +501 -13
- package/dist/lib/codex-manager/help.js +3 -1
- package/dist/lib/codex-manager.js +98 -23
- package/dist/lib/config.js +3 -0
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.js +1 -0
- package/dist/lib/locale.d.ts +7 -0
- package/dist/lib/locale.js +35 -0
- package/dist/lib/model-route-policy.d.ts +1 -0
- package/dist/lib/model-route-policy.js +2 -1
- package/dist/lib/quota-probe.js +2 -1
- package/dist/lib/request/proxy-fetch.d.ts +5 -0
- package/dist/lib/request/proxy-fetch.js +37 -0
- package/dist/lib/request/url-rewriting.js +17 -0
- package/dist/lib/runtime/account-model-catalog.d.ts +3 -0
- package/dist/lib/runtime/account-model-catalog.js +7 -2
- package/dist/lib/runtime/api-model-capabilities.d.ts +11 -2
- package/dist/lib/runtime/api-model-capabilities.js +155 -24
- package/dist/lib/runtime/app-bind.d.ts +7 -0
- package/dist/lib/runtime/app-bind.js +92 -1
- package/dist/lib/runtime/automatic-api-checks.d.ts +15 -0
- package/dist/lib/runtime/automatic-api-checks.js +188 -0
- package/dist/lib/runtime/model-discovery-status.d.ts +11 -1
- package/dist/lib/runtime/model-discovery-status.js +64 -49
- package/dist/lib/runtime/persisted-api-capabilities.d.ts +20 -0
- package/dist/lib/runtime/persisted-api-capabilities.js +387 -0
- package/dist/lib/runtime/responses-websocket.d.ts +48 -5
- package/dist/lib/runtime/responses-websocket.js +275 -39
- package/dist/lib/runtime/rotation-account-selection.d.ts +25 -5
- package/dist/lib/runtime/rotation-account-selection.js +94 -4
- package/dist/lib/runtime/rotation-proxy-state.d.ts +26 -0
- package/dist/lib/runtime/rotation-proxy-state.js +376 -4
- package/dist/lib/runtime/rotation-server-types.d.ts +6 -0
- package/dist/lib/runtime/rotation-token-refresh.d.ts +23 -1
- package/dist/lib/runtime/rotation-token-refresh.js +218 -27
- package/dist/lib/runtime-rotation-proxy.js +601 -105
- package/dist/lib/schemas.d.ts +5 -0
- package/dist/lib/schemas.js +1 -0
- package/dist/lib/storage/credential-sidecars.js +34 -2
- package/dist/lib/storage/file-lock.d.ts +2 -0
- package/dist/lib/storage/file-lock.js +44 -30
- package/dist/lib/usage/ledger.js +1 -0
- package/dist/lib/usage/redaction.js +1 -0
- package/dist/lib/usage/types.d.ts +1 -1
- package/dist/lib/web-dashboard-html.d.ts +1 -0
- package/dist/lib/web-dashboard-html.js +66 -0
- package/dist/lib/web-dashboard.d.ts +36 -0
- package/dist/lib/web-dashboard.js +322 -0
- package/package.json +3 -1
- package/scripts/codex-app-router.js +86 -14
- package/scripts/codex-routing.js +1 -0
- package/scripts/codex.js +150 -13
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AccountManager, type ManagedAccount } from "../accounts.js";
|
|
2
2
|
import type { ModelFamily } from "../prompts/codex.js";
|
|
3
3
|
/** @internal */
|
|
4
4
|
export declare const DEFAULT_AUTH_FAILURE_COOLDOWN_MS = 30000;
|
|
5
5
|
/** @internal */
|
|
6
6
|
export declare function applyMonotonicAuthCooldown(accountManager: AccountManager, account: ManagedAccount, cooldownMs: number): void;
|
|
7
|
+
type RuntimeRefreshTarget = {
|
|
8
|
+
accountManager: AccountManager;
|
|
9
|
+
account: ManagedAccount;
|
|
10
|
+
};
|
|
11
|
+
/** @internal Resolve an account onto the latest runtime manager replacement. */
|
|
12
|
+
export declare function resolveRuntimeRefreshTarget(accountManager: AccountManager, account: ManagedAccount): RuntimeRefreshTarget | null;
|
|
13
|
+
/** @internal Test-only reset for process-global refresh commit/redirect state. */
|
|
14
|
+
export declare function resetRuntimeRefreshStateForTests(): void;
|
|
15
|
+
/** @internal Wait until every refresh-auth commit already targeting this manager settles. */
|
|
16
|
+
export declare function waitForRuntimeRefreshCommits(accountManager: AccountManager): Promise<void>;
|
|
17
|
+
/** @internal Redirect late refresh state from requests that captured a superseded manager. */
|
|
18
|
+
export declare function redirectRuntimeRefreshCommits(previousManager: AccountManager, replacementManager: AccountManager): void;
|
|
7
19
|
/** @internal */
|
|
8
20
|
export declare function ensureFreshAccessToken(params: {
|
|
9
21
|
accountManager: AccountManager;
|
|
@@ -17,8 +29,18 @@ export declare function ensureFreshAccessToken(params: {
|
|
|
17
29
|
ok: true;
|
|
18
30
|
accessToken: string;
|
|
19
31
|
account: ManagedAccount;
|
|
32
|
+
accountManager: AccountManager;
|
|
20
33
|
} | {
|
|
21
34
|
ok: false;
|
|
22
35
|
retryable: boolean;
|
|
23
36
|
invalidated?: boolean;
|
|
37
|
+
selectionRestart?: false;
|
|
38
|
+
account: ManagedAccount;
|
|
39
|
+
accountManager: AccountManager;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
retryable: true;
|
|
43
|
+
selectionRestart: true;
|
|
44
|
+
accountManager: AccountManager;
|
|
24
45
|
}>;
|
|
46
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sanitizeEmail } from "../accounts.js";
|
|
1
2
|
import { queuedRefresh } from "../refresh-queue.js";
|
|
2
3
|
import { isTokenInvalidationError, isTokenRefreshRetryable, } from "../request/rate-limit-decision.js";
|
|
3
4
|
/** @internal */
|
|
@@ -24,49 +25,232 @@ function hasUsableAccessToken(account, now, skewMs) {
|
|
|
24
25
|
typeof account.expires === "number" &&
|
|
25
26
|
account.expires > now + Math.max(0, skewMs));
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
let runtimeRefreshCommitQueues = new WeakMap();
|
|
29
|
+
let runtimeRefreshManagerRedirects = new WeakMap();
|
|
30
|
+
function resolveRuntimeRefreshCommitManager(accountManager) {
|
|
31
|
+
let current = accountManager;
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
while (!seen.has(current)) {
|
|
34
|
+
seen.add(current);
|
|
35
|
+
const next = runtimeRefreshManagerRedirects.get(current);
|
|
36
|
+
if (!next)
|
|
37
|
+
return current;
|
|
38
|
+
current = next;
|
|
39
|
+
}
|
|
40
|
+
return current;
|
|
41
|
+
}
|
|
42
|
+
function uniqueMatch(accounts, predicate) {
|
|
43
|
+
const matches = accounts.filter(predicate);
|
|
44
|
+
return matches.length === 1 ? matches[0] ?? null : null;
|
|
45
|
+
}
|
|
46
|
+
function workspaceIds(account) {
|
|
47
|
+
return new Set([
|
|
48
|
+
account.accountId?.trim(),
|
|
49
|
+
...(account.workspaces ?? []).map((workspace) => workspace.id.trim()),
|
|
50
|
+
].filter((value) => Boolean(value)));
|
|
51
|
+
}
|
|
52
|
+
function hasWorkspaceConflict(source, candidate) {
|
|
53
|
+
const sourceIds = workspaceIds(source);
|
|
54
|
+
const candidateIds = workspaceIds(candidate);
|
|
55
|
+
return (sourceIds.size > 0 &&
|
|
56
|
+
candidateIds.size > 0 &&
|
|
57
|
+
![...sourceIds].some((id) => candidateIds.has(id)));
|
|
58
|
+
}
|
|
59
|
+
/** @internal Resolve an account onto the latest runtime manager replacement. */
|
|
60
|
+
export function resolveRuntimeRefreshTarget(accountManager, account) {
|
|
61
|
+
const targetManager = resolveRuntimeRefreshCommitManager(accountManager);
|
|
62
|
+
if (targetManager === accountManager)
|
|
63
|
+
return { accountManager, account };
|
|
64
|
+
const accounts = targetManager.getAccountsSnapshot();
|
|
65
|
+
// A persisted record id is the strongest row identity we have. If that row
|
|
66
|
+
// vanished in the replacement manager, never fall through to a same-email
|
|
67
|
+
// sibling workspace: the in-flight refresh belongs to the removed row.
|
|
68
|
+
// Derived in-memory ids hash the refresh token, so they are only strict
|
|
69
|
+
// when the row actually persisted one — otherwise rotation retires the id.
|
|
70
|
+
if (account.recordId && accountManager.hasPersistedRecordId(account)) {
|
|
71
|
+
const exact = uniqueMatch(accounts, (candidate) => candidate.recordId === account.recordId);
|
|
72
|
+
if (!exact)
|
|
73
|
+
return null;
|
|
74
|
+
const live = targetManager.getAccountByIndex(exact.index);
|
|
75
|
+
return live ? { accountManager: targetManager, account: live } : null;
|
|
76
|
+
}
|
|
77
|
+
const compatibleAccounts = accounts.filter((candidate) => !hasWorkspaceConflict(account, candidate));
|
|
78
|
+
const sourceEmail = sanitizeEmail(account.email);
|
|
79
|
+
const snapshot = uniqueMatch(compatibleAccounts, (candidate) => candidate.refreshToken === account.refreshToken) ??
|
|
80
|
+
(account.accountId && sourceEmail
|
|
81
|
+
? uniqueMatch(compatibleAccounts, (candidate) => candidate.accountId === account.accountId && sanitizeEmail(candidate.email) === sourceEmail)
|
|
82
|
+
: null) ??
|
|
83
|
+
// accountId alone cannot merge logins: two members of one workspace share
|
|
84
|
+
// it. When both rows carry known-but-different emails they are different
|
|
85
|
+
// logins, and the in-flight refresh belongs to the removed one — let the
|
|
86
|
+
// caller restart selection instead of adopting the sibling's credentials.
|
|
87
|
+
(account.accountId
|
|
88
|
+
? uniqueMatch(compatibleAccounts, (candidate) => candidate.accountId === account.accountId &&
|
|
89
|
+
(!sourceEmail ||
|
|
90
|
+
!sanitizeEmail(candidate.email) ||
|
|
91
|
+
sanitizeEmail(candidate.email) === sourceEmail))
|
|
92
|
+
: null) ??
|
|
93
|
+
(sourceEmail
|
|
94
|
+
? uniqueMatch(compatibleAccounts, (candidate) => sanitizeEmail(candidate.email) === sourceEmail)
|
|
95
|
+
: null);
|
|
96
|
+
if (!snapshot)
|
|
97
|
+
return null;
|
|
98
|
+
const live = targetManager.getAccountByIndex(snapshot.index);
|
|
99
|
+
return live ? { accountManager: targetManager, account: live } : null;
|
|
100
|
+
}
|
|
101
|
+
/** @internal Test-only reset for process-global refresh commit/redirect state. */
|
|
102
|
+
export function resetRuntimeRefreshStateForTests() {
|
|
103
|
+
runtimeRefreshCommitQueues = new WeakMap();
|
|
104
|
+
runtimeRefreshManagerRedirects = new WeakMap();
|
|
105
|
+
}
|
|
106
|
+
/** @internal Wait until every refresh-auth commit already targeting this manager settles. */
|
|
107
|
+
export async function waitForRuntimeRefreshCommits(accountManager) {
|
|
108
|
+
const target = resolveRuntimeRefreshCommitManager(accountManager);
|
|
109
|
+
while (true) {
|
|
110
|
+
const queue = runtimeRefreshCommitQueues.get(target);
|
|
111
|
+
const pending = queue ? [...queue.values()] : [];
|
|
112
|
+
if (pending.length === 0)
|
|
113
|
+
return;
|
|
114
|
+
await Promise.allSettled(pending);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** @internal Redirect late refresh state from requests that captured a superseded manager. */
|
|
118
|
+
export function redirectRuntimeRefreshCommits(previousManager, replacementManager) {
|
|
119
|
+
if (previousManager === replacementManager)
|
|
120
|
+
return;
|
|
121
|
+
runtimeRefreshManagerRedirects.set(previousManager, resolveRuntimeRefreshCommitManager(replacementManager));
|
|
122
|
+
}
|
|
28
123
|
async function commitRefreshedAuthOnce(accountManager, account, auth) {
|
|
124
|
+
const commitManager = resolveRuntimeRefreshCommitManager(accountManager);
|
|
29
125
|
const key = [
|
|
30
|
-
account.
|
|
126
|
+
account.recordId ?? "",
|
|
31
127
|
account.accountId ?? "",
|
|
32
128
|
account.email ?? "",
|
|
33
129
|
account.refreshToken,
|
|
34
130
|
].join("\0");
|
|
35
|
-
let queue = runtimeRefreshCommitQueues.get(
|
|
131
|
+
let queue = runtimeRefreshCommitQueues.get(commitManager);
|
|
36
132
|
if (!queue) {
|
|
37
133
|
queue = new Map();
|
|
38
|
-
runtimeRefreshCommitQueues.set(
|
|
134
|
+
runtimeRefreshCommitQueues.set(commitManager, queue);
|
|
39
135
|
}
|
|
40
136
|
const existing = queue.get(key);
|
|
41
137
|
if (existing)
|
|
42
138
|
return existing;
|
|
43
|
-
const pending =
|
|
139
|
+
const pending = commitManager
|
|
44
140
|
.commitRefreshedAuth(account, auth)
|
|
141
|
+
.then((updatedAccount) => ({ accountManager: commitManager, account: updatedAccount }))
|
|
45
142
|
.finally(() => queue?.delete(key));
|
|
46
143
|
queue.set(key, pending);
|
|
47
144
|
return pending;
|
|
48
145
|
}
|
|
49
146
|
/** @internal */
|
|
50
147
|
export async function ensureFreshAccessToken(params) {
|
|
51
|
-
const { accountManager, account, family, model, now, tokenRefreshSkewMs, tokenInvalidationCooldownMs } = params;
|
|
52
|
-
|
|
53
|
-
|
|
148
|
+
const { accountManager, account, family, model, now, tokenRefreshSkewMs, tokenInvalidationCooldownMs, } = params;
|
|
149
|
+
const redirectedInitialManager = resolveRuntimeRefreshCommitManager(accountManager);
|
|
150
|
+
const resolvedInitialTarget = resolveRuntimeRefreshTarget(accountManager, account);
|
|
151
|
+
if (redirectedInitialManager !== accountManager && !resolvedInitialTarget) {
|
|
152
|
+
// The request captured a manager that has since been replaced, and the
|
|
153
|
+
// selected row no longer exists there. Even a still-fresh old token must not
|
|
154
|
+
// bypass that removal; restart selection on the replacement pool.
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
retryable: true,
|
|
158
|
+
selectionRestart: true,
|
|
159
|
+
accountManager: redirectedInitialManager,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const initialTarget = resolvedInitialTarget ?? {
|
|
163
|
+
accountManager,
|
|
164
|
+
account,
|
|
165
|
+
};
|
|
166
|
+
if (initialTarget.account.enabled === false) {
|
|
167
|
+
return {
|
|
168
|
+
ok: false,
|
|
169
|
+
retryable: true,
|
|
170
|
+
selectionRestart: true,
|
|
171
|
+
accountManager: initialTarget.accountManager,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (hasUsableAccessToken(initialTarget.account, now, tokenRefreshSkewMs)) {
|
|
175
|
+
return {
|
|
176
|
+
ok: true,
|
|
177
|
+
accessToken: initialTarget.account.access ?? "",
|
|
178
|
+
account: initialTarget.account,
|
|
179
|
+
accountManager: initialTarget.accountManager,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const refreshCredential = {
|
|
183
|
+
access: initialTarget.account.access,
|
|
184
|
+
refreshToken: initialTarget.account.refreshToken,
|
|
185
|
+
expires: initialTarget.account.expires,
|
|
186
|
+
};
|
|
187
|
+
const refreshResult = await queuedRefresh(refreshCredential.refreshToken);
|
|
188
|
+
const redirectedManager = resolveRuntimeRefreshCommitManager(initialTarget.accountManager);
|
|
189
|
+
const resolvedLatestTarget = resolveRuntimeRefreshTarget(initialTarget.accountManager, initialTarget.account);
|
|
190
|
+
if (redirectedManager !== initialTarget.accountManager && !resolvedLatestTarget) {
|
|
191
|
+
// The row that initiated this refresh disappeared while OAuth was in flight.
|
|
192
|
+
// Ignore the stale result rather than guessing another same-email workspace,
|
|
193
|
+
// but hand the caller the replacement manager so it can restart selection and
|
|
194
|
+
// discover a different healthy login from the current pool.
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
retryable: true,
|
|
198
|
+
selectionRestart: true,
|
|
199
|
+
accountManager: redirectedManager,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const latestTarget = resolvedLatestTarget ?? initialTarget;
|
|
203
|
+
if (latestTarget.account.enabled === false) {
|
|
204
|
+
// An operator/runtime inventory change disabled this row while OAuth was in
|
|
205
|
+
// flight. Never let a successful refresh re-enable it in commitRefreshedAuth.
|
|
206
|
+
return {
|
|
207
|
+
ok: false,
|
|
208
|
+
retryable: true,
|
|
209
|
+
selectionRestart: true,
|
|
210
|
+
accountManager: latestTarget.accountManager,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const credentialChangedWhileRefreshing = latestTarget.account.access !== refreshCredential.access ||
|
|
214
|
+
latestTarget.account.refreshToken !== refreshCredential.refreshToken ||
|
|
215
|
+
latestTarget.account.expires !== refreshCredential.expires;
|
|
216
|
+
if (credentialChangedWhileRefreshing) {
|
|
217
|
+
// A concurrent refresh or external re-login repaired/replaced this credential.
|
|
218
|
+
// The result for the old OAuth tuple must never invalidate or overwrite it.
|
|
219
|
+
if (hasUsableAccessToken(latestTarget.account, now, tokenRefreshSkewMs)) {
|
|
220
|
+
return {
|
|
221
|
+
ok: true,
|
|
222
|
+
accessToken: latestTarget.account.access ?? "",
|
|
223
|
+
account: latestTarget.account,
|
|
224
|
+
accountManager: latestTarget.accountManager,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
ok: false,
|
|
229
|
+
retryable: true,
|
|
230
|
+
account: latestTarget.account,
|
|
231
|
+
accountManager: latestTarget.accountManager,
|
|
232
|
+
};
|
|
54
233
|
}
|
|
55
|
-
const refreshResult = await queuedRefresh(account.refreshToken);
|
|
56
234
|
if (refreshResult.type === "failed") {
|
|
57
|
-
accountManager.recordFailure(account, family, model);
|
|
58
|
-
accountManager.incrementAuthFailures(account);
|
|
235
|
+
latestTarget.accountManager.recordFailure(latestTarget.account, family, model);
|
|
236
|
+
latestTarget.accountManager.incrementAuthFailures(latestTarget.account);
|
|
59
237
|
// If the refresh endpoint itself returns an explicit invalidation message
|
|
60
238
|
// (e.g. Microsoft/Outlook SSO revokes the refresh token server-side), apply
|
|
61
239
|
// the long cooldown and signal to the caller to stop rotating rather than
|
|
62
240
|
// presenting other accounts' tokens from the same IP.
|
|
63
241
|
const invalidated = isTokenInvalidationError(refreshResult.message ?? "");
|
|
64
242
|
if (invalidated) {
|
|
65
|
-
accountManager.markAuthInvalidated(account);
|
|
243
|
+
latestTarget.accountManager.markAuthInvalidated(latestTarget.account);
|
|
66
244
|
}
|
|
67
|
-
applyMonotonicAuthCooldown(accountManager, account, invalidated ? tokenInvalidationCooldownMs : DEFAULT_AUTH_FAILURE_COOLDOWN_MS);
|
|
68
|
-
accountManager.saveToDiskDebounced();
|
|
69
|
-
return {
|
|
245
|
+
applyMonotonicAuthCooldown(latestTarget.accountManager, latestTarget.account, invalidated ? tokenInvalidationCooldownMs : DEFAULT_AUTH_FAILURE_COOLDOWN_MS);
|
|
246
|
+
latestTarget.accountManager.saveToDiskDebounced();
|
|
247
|
+
return {
|
|
248
|
+
ok: false,
|
|
249
|
+
retryable: isTokenRefreshRetryable(refreshResult),
|
|
250
|
+
invalidated,
|
|
251
|
+
account: latestTarget.account,
|
|
252
|
+
accountManager: latestTarget.accountManager,
|
|
253
|
+
};
|
|
70
254
|
}
|
|
71
255
|
const auth = {
|
|
72
256
|
type: "oauth",
|
|
@@ -75,28 +259,35 @@ export async function ensureFreshAccessToken(params) {
|
|
|
75
259
|
expires: refreshResult.expires,
|
|
76
260
|
};
|
|
77
261
|
try {
|
|
78
|
-
const
|
|
262
|
+
const committed = await commitRefreshedAuthOnce(latestTarget.accountManager, latestTarget.account, auth);
|
|
79
263
|
// If commit succeeded, use the stored access token from the committed
|
|
80
|
-
// account
|
|
264
|
+
// account ? this also handles the dedup case where two concurrent callers
|
|
81
265
|
// share one commit and both end up with the same committed token.
|
|
82
266
|
// If commit returned null (account missing from storage after persist),
|
|
83
|
-
// fall back to the
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const accessToken =
|
|
88
|
-
? (
|
|
267
|
+
// fall back to the account that initiated the commit but always use
|
|
268
|
+
// refreshResult.access; that account may still carry an expired token.
|
|
269
|
+
const resolvedAccount = committed.account ?? latestTarget.account;
|
|
270
|
+
const resolvedManager = committed.account ? committed.accountManager : latestTarget.accountManager;
|
|
271
|
+
const accessToken = committed.account !== null
|
|
272
|
+
? (committed.account.access ?? refreshResult.access)
|
|
89
273
|
: refreshResult.access;
|
|
90
274
|
return {
|
|
91
275
|
ok: true,
|
|
92
276
|
accessToken,
|
|
93
277
|
account: resolvedAccount,
|
|
278
|
+
accountManager: resolvedManager,
|
|
94
279
|
};
|
|
95
280
|
}
|
|
96
281
|
catch {
|
|
97
|
-
accountManager.
|
|
98
|
-
accountManager.
|
|
99
|
-
accountManager.
|
|
100
|
-
|
|
282
|
+
const failureTarget = resolveRuntimeRefreshTarget(latestTarget.accountManager, latestTarget.account) ?? latestTarget;
|
|
283
|
+
failureTarget.accountManager.recordFailure(failureTarget.account, family, model);
|
|
284
|
+
failureTarget.accountManager.markAccountCoolingDown(failureTarget.account, DEFAULT_AUTH_FAILURE_COOLDOWN_MS, "auth-failure");
|
|
285
|
+
failureTarget.accountManager.saveToDiskDebounced();
|
|
286
|
+
return {
|
|
287
|
+
ok: false,
|
|
288
|
+
retryable: true,
|
|
289
|
+
account: failureTarget.account,
|
|
290
|
+
accountManager: failureTarget.accountManager,
|
|
291
|
+
};
|
|
101
292
|
}
|
|
102
293
|
}
|