@@ -25,28 +25,78 @@ export interface RefreshGuardianStats {
2525
2626const DEFAULT_INTERVAL_MS = 60_000 ;
2727
28+ function findMatchingLiveAccountIndexes (
29+ liveAccounts : ManagedAccount [ ] ,
30+ predicate : ( candidate : ManagedAccount ) => boolean ,
31+ ) : number [ ] {
32+ const matches : number [ ] = [ ] ;
33+ for ( const [ index , candidate ] of liveAccounts . entries ( ) ) {
34+ if ( predicate ( candidate ) ) {
35+ matches . push ( index ) ;
36+ }
37+ }
38+ return matches ;
39+ }
40+
2841function resolveLiveAccountIndex (
2942 liveAccounts : ManagedAccount [ ] ,
3043 sourceAccount : ManagedAccount ,
3144) : number {
3245 if ( sourceAccount . accountId ) {
33- const byAccountId = liveAccounts . findIndex (
46+ const accountIdMatches = findMatchingLiveAccountIndexes (
47+ liveAccounts ,
3448 ( candidate ) => candidate . accountId === sourceAccount . accountId ,
3549 ) ;
36- if ( byAccountId >= 0 ) return byAccountId ;
50+ const resolvedIndex = accountIdMatches [ 0 ] ;
51+ if ( resolvedIndex !== undefined ) {
52+ log . debug ( "Resolved refreshed account by accountId" , {
53+ sourceIndex : sourceAccount . index ,
54+ resolvedIndex,
55+ matchCount : accountIdMatches . length ,
56+ } ) ;
57+ if ( accountIdMatches . length > 1 ) {
58+ log . warn ( "Duplicate live accountId matches during refresh reconciliation" , {
59+ sourceIndex : sourceAccount . index ,
60+ resolvedIndex,
61+ matchCount : accountIdMatches . length ,
62+ } ) ;
63+ }
64+ return resolvedIndex ;
65+ }
3766 }
3867
3968 const sourceEmail = sanitizeEmail ( sourceAccount . email ) ;
4069 if ( sourceEmail ) {
41- const byEmail = liveAccounts . findIndex (
70+ const emailMatches = findMatchingLiveAccountIndexes (
71+ liveAccounts ,
4272 ( candidate ) => sanitizeEmail ( candidate . email ) === sourceEmail ,
4373 ) ;
44- if ( byEmail >= 0 ) return byEmail ;
74+ const resolvedIndex = emailMatches [ 0 ] ;
75+ if ( resolvedIndex !== undefined ) {
76+ log . debug ( "Resolved refreshed account by email" , {
77+ sourceIndex : sourceAccount . index ,
78+ resolvedIndex,
79+ matchCount : emailMatches . length ,
80+ } ) ;
81+ if ( emailMatches . length > 1 ) {
82+ log . warn ( "Duplicate live email matches during refresh reconciliation" , {
83+ sourceIndex : sourceAccount . index ,
84+ resolvedIndex,
85+ matchCount : emailMatches . length ,
86+ } ) ;
87+ }
88+ return resolvedIndex ;
89+ }
4590 }
4691
47- return liveAccounts . findIndex (
92+ const byToken = liveAccounts . findIndex (
4893 ( candidate ) => candidate . refreshToken === sourceAccount . refreshToken ,
4994 ) ;
95+ log . debug ( "Resolved refreshed account by refresh token fallback" , {
96+ sourceIndex : sourceAccount . index ,
97+ resolvedIndex : byToken ,
98+ } ) ;
99+ return byToken ;
50100}
51101
52102export class RefreshGuardian {
@@ -141,11 +191,11 @@ export class RefreshGuardian {
141191 for ( const candidate of snapshot ) {
142192 snapshotByIndex . set ( candidate . index , candidate ) ;
143193 }
194+ const liveAccounts = manager . getAccountsSnapshot ( ) ;
144195
145196 for ( const [ accountIndex , result ] of refreshResults . entries ( ) ) {
146197 const sourceAccount = snapshotByIndex . get ( accountIndex ) ;
147198 if ( ! sourceAccount ) continue ;
148- const liveAccounts = manager . getAccountsSnapshot ( ) ;
149199 const resolvedIndex = resolveLiveAccountIndex ( liveAccounts , sourceAccount ) ;
150200 const account = resolvedIndex >= 0 ? manager . getAccountByIndex ( resolvedIndex ) : null ;
151201 if ( ! account ) continue ;
0 commit comments