@@ -184,6 +184,17 @@ function upsertAccount(store: AccountStore, auth: OAuthStored, now = Date.now())
184184 store . activeIndex = index ;
185185}
186186
187+ function replaceAccount ( store : AccountStore , previous : OAuthStored , next : OAuthStored , now = Date . now ( ) ) {
188+ const index = store . accounts . findIndex ( ( account ) => account . refresh === previous . refresh || account . access === previous . access || account . refresh === next . refresh || account . access === next . access ) ;
189+ if ( index < 0 ) {
190+ upsertAccount ( store , next , now ) ;
191+ return ;
192+ }
193+ const existing = store . accounts [ index ] ;
194+ store . accounts [ index ] = { ...next , addedAt : existing ?. addedAt ?? now , lastUsed : now } ;
195+ store . activeIndex = index ;
196+ }
197+
187198async function rememberAnthropicOAuth ( auth : OAuthStored ) {
188199 const store = await loadAccountStore ( ) ;
189200 upsertAccount ( store , auth ) ;
@@ -611,7 +622,7 @@ async function getFreshOAuth(getAuth: () => Promise<OAuthStored | { type: string
611622 try {
612623 const refreshed = await refreshAnthropicToken ( candidate . refresh ) ;
613624 await writeAnthropicAuth ( refreshed ) ;
614- upsertAccount ( store , refreshed ) ;
625+ replaceAccount ( store , candidate , refreshed ) ;
615626 await saveAccountStore ( store ) ;
616627 return refreshed ;
617628 } catch ( error ) {
@@ -628,13 +639,37 @@ async function getFreshOAuth(getAuth: () => Promise<OAuthStored | { type: string
628639 } ) ;
629640}
630641
642+ async function refreshOAuthAfterAuthFailure ( auth : OAuthStored ) {
643+ return withRefreshLock ( async ( ) => {
644+ const latest = await readAnthropicAuth ( ) ;
645+ if ( latest && ! sameOAuth ( latest , auth ) && usableAccessToken ( latest ) ) return latest ;
646+
647+ const store = await loadAccountStore ( ) ;
648+ const refreshed = await refreshAnthropicToken ( auth . refresh ) ;
649+ await writeAnthropicAuth ( refreshed ) ;
650+ replaceAccount ( store , auth , refreshed ) ;
651+ await saveAccountStore ( store ) ;
652+ return refreshed ;
653+ } ) ;
654+ }
655+
656+ async function rotateAndRefreshAnthropicAccount ( auth : OAuthStored ) {
657+ const rotated = await rotateAnthropicAccount ( auth ) ;
658+ if ( ! rotated || sameOAuth ( rotated , auth ) ) return undefined ;
659+ try {
660+ return await refreshOAuthAfterAuthFailure ( rotated ) ;
661+ } catch {
662+ return undefined ;
663+ }
664+ }
665+
631666async function getFreshOAuthOrRotate ( getAuth : ( ) => Promise < OAuthStored | { type : string } > ) {
632667 try {
633668 return await getFreshOAuth ( getAuth ) ;
634669 } catch ( error ) {
635670 const auth = await readAnthropicAuth ( ) ;
636671 if ( auth ) {
637- const rotated = await rotateAnthropicAccount ( auth ) ;
672+ const rotated = await rotateAndRefreshAnthropicAccount ( auth ) ;
638673 if ( rotated && ! sameOAuth ( rotated , auth ) ) return rotated ;
639674 }
640675 throw error ;
@@ -670,7 +705,17 @@ const claudeCodeAuthPlugin: Plugin = async () => ({
670705 if ( ! response . ok ) {
671706 const bodyText = await response . clone ( ) . text ( ) . catch ( ( ) => "" ) ;
672707 if ( shouldRotateAuth ( response . status , bodyText ) ) {
673- const rotated = await rotateAnthropicAccount ( freshAuth ) ;
708+ const refreshed = await refreshOAuthAfterAuthFailure ( freshAuth ) . catch ( ( ) => undefined ) ;
709+ if ( refreshed ) {
710+ headers . set ( "authorization" , `Bearer ${ refreshed . access } ` ) ;
711+ response = await fetch ( input , { ...( init ?? { } ) , body : rewritten . body , headers } ) ;
712+ }
713+ }
714+ }
715+ if ( ! response . ok ) {
716+ const bodyText = await response . clone ( ) . text ( ) . catch ( ( ) => "" ) ;
717+ if ( shouldRotateAuth ( response . status , bodyText ) ) {
718+ const rotated = await rotateAndRefreshAnthropicAccount ( await readAnthropicAuth ( ) ?? freshAuth ) ;
674719 if ( rotated ) {
675720 headers . set ( "authorization" , `Bearer ${ rotated . access } ` ) ;
676721 response = await fetch ( input , { ...( init ?? { } ) , body : rewritten . body , headers } ) ;
0 commit comments