@@ -88,39 +88,51 @@ export class GitHubAuthProvider implements vscode.AuthenticationProvider {
8888 }
8989 }
9090
91- try {
92- const token = await this . githubService . getToken ( ) ;
93- const tokenScopes = await this . githubService . getTokenScopes ( token ) ;
94- if ( tokenScopes . length === 0 ) {
95- this . logger . info ( 'GitHubAuthProvider: hydrate skipped, token has no scopes' ) ;
96- return ;
97- }
91+ await this . tryHydrate ( 3 , 500 ) ;
92+ }
9893
99- const githubUser = await this . githubService . getUser ( ) ;
100- const matchingBundles = getMatchingHydrationScopeBundles ( tokenScopes ) ;
101- if ( matchingBundles . length === 0 ) {
102- this . logger . info ( 'GitHubAuthProvider: hydrate skipped, token scopes match no known bundle' ) ;
103- return ;
104- }
94+ private async tryHydrate ( maxAttempts : number , delayMs : number ) : Promise < void > {
95+ for ( let attempt = 1 ; attempt <= maxAttempts ; attempt ++ ) {
96+ try {
97+ const token = await this . githubService . getToken ( ) ;
98+ const tokenScopes = await this . githubService . getTokenScopes ( token ) ;
99+ if ( tokenScopes . length === 0 ) {
100+ this . logger . info ( 'GitHubAuthProvider: hydrate skipped, token has no scopes' ) ;
101+ return ;
102+ }
105103
106- const isDeviceAuthToken = await this . githubService . isDeviceAuthToken ( ) ;
107- const account = { label : githubUser . login , id : githubUser . id . toString ( ) } ;
108- const hydratedSessions = matchingBundles . map ( scopes => ( {
109- id : v4 ( ) ,
110- accessToken : token ,
111- account,
112- scopes : isDeviceAuthToken ? scopes : [ ...scopes , WORKSPACE_PAT_SCOPE ] ,
113- } ) ) ;
114-
115- await this . storeSessions ( hydratedSessions ) ;
116- this . sessionChangeEmitter . fire ( { added : hydratedSessions , removed : [ ] , changed : [ ] } ) ;
117- const tokenSource = isDeviceAuthToken ? 'device authentication' : 'workspace PAT' ;
118- this . logger . info ( `GitHubAuthProvider: hydrated ${ hydratedSessions . length } session(s) from K8s ${ tokenSource } ` ) ;
119- } catch ( error ) {
120- if ( isUnauthorizedError ( error ) ) {
121- this . logger . warn ( 'GitHubAuthProvider: hydrate failed, token is not valid' ) ;
122- } else {
123- this . logger . warn ( `GitHubAuthProvider: hydrate failed: ${ ( error as Error ) . message } ` ) ;
104+ const githubUser = await this . githubService . getUser ( ) ;
105+ const matchingBundles = getMatchingHydrationScopeBundles ( tokenScopes ) ;
106+ if ( matchingBundles . length === 0 ) {
107+ this . logger . info ( 'GitHubAuthProvider: hydrate skipped, token scopes match no known bundle' ) ;
108+ return ;
109+ }
110+
111+ const isDeviceAuthToken = await this . githubService . isDeviceAuthToken ( ) ;
112+ const account = { label : githubUser . login , id : githubUser . id . toString ( ) } ;
113+ const hydratedSessions = matchingBundles . map ( scopes => ( {
114+ id : v4 ( ) ,
115+ accessToken : token ,
116+ account,
117+ scopes : isDeviceAuthToken ? scopes : [ ...scopes , WORKSPACE_PAT_SCOPE ] ,
118+ } ) ) ;
119+
120+ await this . storeSessions ( hydratedSessions ) ;
121+ this . sessionChangeEmitter . fire ( { added : hydratedSessions , removed : [ ] , changed : [ ] } ) ;
122+ const tokenSource = isDeviceAuthToken ? 'device authentication' : 'workspace PAT' ;
123+ this . logger . info ( `GitHubAuthProvider: hydrated ${ hydratedSessions . length } session(s) from K8s ${ tokenSource } ` ) ;
124+ return ;
125+ } catch ( error ) {
126+ if ( isUnauthorizedError ( error ) ) {
127+ this . logger . warn ( 'GitHubAuthProvider: hydrate failed, token is not valid' ) ;
128+ return ;
129+ }
130+ if ( attempt < maxAttempts ) {
131+ this . logger . info ( `GitHubAuthProvider: hydrate attempt ${ attempt } /${ maxAttempts } failed: ${ ( error as Error ) . message } , retrying in ${ delayMs } ms` ) ;
132+ await new Promise ( resolve => setTimeout ( resolve , delayMs ) ) ;
133+ } else {
134+ this . logger . warn ( `GitHubAuthProvider: hydrate failed after ${ maxAttempts } attempts: ${ ( error as Error ) . message } ` ) ;
135+ }
124136 }
125137 }
126138 }
0 commit comments