























@@ -18,10 +18,12 @@ import {
1818} from "./state.js";
1919import type {
2020AuthProfileCredential,
21+AuthProfileFailureReason,
2122AuthProfileSecretsStore,
2223AuthProfileStore,
2324OAuthCredential,
2425OAuthCredentials,
26+ProfileUsageStats,
2527} from "./types.js";
26282729export type LegacyAuthStore = Record<string, AuthProfileCredential>;
@@ -213,6 +215,107 @@ function isNewerUsableOAuthCredential(
213215);
214216}
215217218+const AUTH_INVALIDATION_REASONS = new Set<AuthProfileFailureReason>([
219+"auth",
220+"auth_permanent",
221+"session_expired",
222+]);
223+224+function hasAuthInvalidationSignal(stats: ProfileUsageStats | undefined): boolean {
225+if (!stats) {
226+return false;
227+}
228+if (
229+(stats.cooldownReason && AUTH_INVALIDATION_REASONS.has(stats.cooldownReason)) ||
230+(stats.disabledReason && AUTH_INVALIDATION_REASONS.has(stats.disabledReason))
231+) {
232+return true;
233+}
234+return Object.entries(stats.failureCounts ?? {}).some(
235+([reason, count]) =>
236+AUTH_INVALIDATION_REASONS.has(reason as AuthProfileFailureReason) &&
237+typeof count === "number" &&
238+count > 0,
239+);
240+}
241+242+function isProfileReferencedByAuthState(store: AuthProfileStore, profileId: string): boolean {
243+if (Object.values(store.order ?? {}).some((profileIds) => profileIds.includes(profileId))) {
244+return true;
245+}
246+return Object.values(store.lastGood ?? {}).some((value) => value === profileId);
247+}
248+249+function resolveProviderAuthStateValue<T>(
250+values: Record<string, T> | undefined,
251+providerKey: string,
252+): T | undefined {
253+if (!values) {
254+return undefined;
255+}
256+for (const [key, value] of Object.entries(values)) {
257+if (normalizeProviderId(key) === providerKey) {
258+return value;
259+}
260+}
261+return undefined;
262+}
263+264+function findMainStoreOAuthReplacementForInvalidatedProfile(params: {
265+base: AuthProfileStore;
266+override: AuthProfileStore;
267+profileId: string;
268+credential: OAuthCredential;
269+}): string | undefined {
270+const providerKey = normalizeProviderId(params.credential.provider);
271+if (
272+providerKey !== "openai-codex" ||
273+!isProfileReferencedByAuthState(params.override, params.profileId) ||
274+!hasAuthInvalidationSignal(params.override.usageStats?.[params.profileId])
275+) {
276+return undefined;
277+}
278+279+const candidates = Object.entries(params.base.profiles)
280+.flatMap(([profileId, credential]): Array<[string, OAuthCredential]> => {
281+if (
282+profileId === params.profileId ||
283+credential.type !== "oauth" ||
284+normalizeProviderId(credential.provider) !== providerKey ||
285+!hasUsableOAuthCredential(credential)
286+) {
287+return [];
288+}
289+return [[profileId, credential]];
290+})
291+.toSorted(([leftId, leftCredential], [rightId, rightCredential]) => {
292+const leftExpires = Number.isFinite(leftCredential.expires) ? leftCredential.expires : 0;
293+const rightExpires = Number.isFinite(rightCredential.expires) ? rightCredential.expires : 0;
294+if (rightExpires !== leftExpires) {
295+return rightExpires - leftExpires;
296+}
297+return leftId.localeCompare(rightId);
298+});
299+if (candidates.length === 0) {
300+return undefined;
301+}
302+303+const candidateIds = new Set(candidates.map(([profileId]) => profileId));
304+const orderedProfileId = resolveProviderAuthStateValue(params.base.order, providerKey)?.find(
305+(profileId) => candidateIds.has(profileId),
306+);
307+if (orderedProfileId) {
308+return orderedProfileId;
309+}
310+311+const lastGoodProfileId = resolveProviderAuthStateValue(params.base.lastGood, providerKey);
312+if (lastGoodProfileId && candidateIds.has(lastGoodProfileId)) {
313+return lastGoodProfileId;
314+}
315+316+return candidates.length === 1 ? candidates[0]?.[0] : undefined;
317+}
318+216319function findMainStoreOAuthReplacement(params: {
217320base: AuthProfileStore;
218321legacyProfileId: string;
@@ -343,14 +446,21 @@ function reconcileMainStoreOAuthProfileDrift(params: {
343446}): AuthProfileStore {
344447const replacements = new Map<string, string>();
345448for (const [profileId, credential] of Object.entries(params.override.profiles)) {
346-if (credential.type !== "oauth" || !isLegacyDefaultOAuthProfile(profileId, credential)) {
449+if (credential.type !== "oauth") {
347450continue;
348451}
349-const replacementProfileId = findMainStoreOAuthReplacement({
350-base: params.base,
351-legacyProfileId: profileId,
352-legacyCredential: credential,
353-});
452+const replacementProfileId = isLegacyDefaultOAuthProfile(profileId, credential)
453+ ? findMainStoreOAuthReplacement({
454+base: params.base,
455+legacyProfileId: profileId,
456+legacyCredential: credential,
457+})
458+ : findMainStoreOAuthReplacementForInvalidatedProfile({
459+base: params.base,
460+override: params.override,
461+ profileId,
462+ credential,
463+});
354464if (replacementProfileId) {
355465replacements.set(profileId, replacementProfileId);
356466}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。