Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit78db0ad

Browse files
committed
Add error handling
1 parent796c9eb commit78db0ad

File tree

7 files changed

+410
-186
lines changed

7 files changed

+410
-186
lines changed

‎src/api/coderApi.ts‎

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
typeAxiosInstance,
44
typeAxiosHeaders,
55
typeAxiosResponseTransformer,
6+
isAxiosError,
67
}from"axios";
78
import{Api}from"coder/site/src/api/api";
89
import{
@@ -30,6 +31,12 @@ import {
3031
HttpClientLogLevel,
3132
}from"../logging/types";
3233
import{sizeOf}from"../logging/utils";
34+
import{
35+
parseOAuthError,
36+
requiresReAuthentication,
37+
isNetworkError,
38+
}from"../oauth/errors";
39+
import{typeOAuthSessionManager}from"../oauth/sessionManager";
3340
import{typeUnidirectionalStream}from"../websocket/eventStreamConnection";
3441
import{
3542
OneWayWebSocket,
@@ -58,14 +65,15 @@ export class CoderApi extends Api {
5865
baseUrl:string,
5966
token:string|undefined,
6067
output:Logger,
68+
oauthSessionManager?:OAuthSessionManager,
6169
):CoderApi{
6270
constclient=newCoderApi(output);
6371
client.setHost(baseUrl);
6472
if(token){
6573
client.setSessionToken(token);
6674
}
6775

68-
setupInterceptors(client,baseUrl,output);
76+
setupInterceptors(client,baseUrl,output,oauthSessionManager);
6977
returnclient;
7078
}
7179

@@ -302,6 +310,7 @@ function setupInterceptors(
302310
client:CoderApi,
303311
baseUrl:string,
304312
output:Logger,
313+
oauthSessionManager?:OAuthSessionManager,
305314
):void{
306315
addLoggingInterceptors(client.getAxiosInstance(),output);
307316

@@ -334,6 +343,11 @@ function setupInterceptors(
334343
throwawaitCertificateError.maybeWrap(err,baseUrl,output);
335344
},
336345
);
346+
347+
// OAuth token refresh interceptors
348+
if(oauthSessionManager){
349+
addOAuthInterceptors(client,output,oauthSessionManager);
350+
}
337351
}
338352

339353
functionaddLoggingInterceptors(client:AxiosInstance,logger:Logger){
@@ -363,7 +377,7 @@ function addLoggingInterceptors(client: AxiosInstance, logger: Logger) {
363377
},
364378
(error:unknown)=>{
365379
logError(logger,error,getLogLevel());
366-
returnPromise.reject(error);
380+
throwerror;
367381
},
368382
);
369383

@@ -374,7 +388,80 @@ function addLoggingInterceptors(client: AxiosInstance, logger: Logger) {
374388
},
375389
(error:unknown)=>{
376390
logError(logger,error,getLogLevel());
377-
returnPromise.reject(error);
391+
throwerror;
392+
},
393+
);
394+
}
395+
396+
/**
397+
* Add OAuth token refresh interceptors.
398+
* Success interceptor: proactively refreshes token when approaching expiry.
399+
* Error interceptor: reactively refreshes token on 401/403 responses.
400+
*/
401+
functionaddOAuthInterceptors(
402+
client:CoderApi,
403+
logger:Logger,
404+
oauthSessionManager:OAuthSessionManager,
405+
){
406+
client.getAxiosInstance().interceptors.response.use(
407+
// Success response interceptor: proactive token refresh
408+
(response)=>{
409+
if(oauthSessionManager.shouldRefreshToken()){
410+
logger.debug(
411+
"Token approaching expiry, triggering proactive refresh in background",
412+
);
413+
414+
// Fire-and-forget: don't await, don't block response
415+
oauthSessionManager.refreshToken().catch((error)=>{
416+
logger.warn("Background token refresh failed:",error);
417+
});
418+
}
419+
420+
returnresponse;
421+
},
422+
// Error response interceptor: reactive token refresh on 401/403
423+
async(error:unknown)=>{
424+
if(!isAxiosError(error)){
425+
throwerror;
426+
}
427+
428+
conststatus=error.response?.status;
429+
if(status!==401&&status!==403){
430+
throwerror;
431+
}
432+
433+
if(!oauthSessionManager.isLoggedInWithOAuth()){
434+
throwerror;
435+
}
436+
437+
logger.info(`Received${status} response, attempting token refresh`);
438+
439+
try{
440+
constnewTokens=awaitoauthSessionManager.refreshToken();
441+
client.setSessionToken(newTokens.access_token);
442+
443+
logger.info("Token refresh successful, updated session token");
444+
}catch(refreshError){
445+
logger.error("Token refresh failed:",refreshError);
446+
447+
constoauthError=parseOAuthError(refreshError);
448+
if(oauthError&&requiresReAuthentication(oauthError)){
449+
logger.error(
450+
`OAuth error requires re-authentication:${oauthError.errorCode}`,
451+
);
452+
453+
oauthSessionManager
454+
.showReAuthenticationModal(oauthError)
455+
.catch((err)=>{
456+
logger.error("Failed to show re-auth modal:",err);
457+
});
458+
}elseif(isNetworkError(refreshError)){
459+
logger.warn(
460+
"Token refresh failed due to network error, will retry later",
461+
);
462+
}
463+
}
464+
throwerror;
378465
},
379466
);
380467
}

‎src/commands.ts‎

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -482,20 +482,10 @@ export class Commands {
482482
}
483483
this.logger.info("Logging out");
484484

485-
// Check if using OAuth
486-
constisOAuthLoggedIn=
487-
awaitthis.oauthSessionManager.isLoggedInWithOAuth();
488-
if(isOAuthLoggedIn){
489-
this.logger.info("Logging out via OAuth");
490-
try{
491-
awaitthis.oauthSessionManager.logout();
492-
}catch(error){
493-
this.logger.warn(
494-
"OAuth logout failed, continuing with cleanup:",
495-
error,
496-
);
497-
}
498-
}
485+
// Fire and forget
486+
this.oauthSessionManager.logout().catch((error)=>{
487+
this.logger.warn("OAuth logout failed, continuing with cleanup:",error);
488+
});
499489

500490
// Clear from the REST client. An empty url will indicate to other parts of
501491
// the code that we are logged out.
@@ -667,19 +657,6 @@ export class Commands {
667657
},
668658
);
669659
}
670-
// Check if app has a URL to open
671-
if(app.url){
672-
returnvscode.window.withProgress(
673-
{
674-
location:vscode.ProgressLocation.Notification,
675-
title:`Opening${app.name||"application"} in browser...`,
676-
cancellable:false,
677-
},
678-
async()=>{
679-
awaitvscode.env.openExternal(vscode.Uri.parse(app.url!));
680-
},
681-
);
682-
}
683660

684661
// If no URL or command, show information about the app status
685662
vscode.window.showInformationMessage(`${app.name}`,{

‎src/extension.ts‎

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,24 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
7070
// Try to clear this flag ASAP
7171
constisFirstConnect=awaitmementoManager.getAndClearFirstConnect();
7272

73+
consturl=mementoManager.getUrl();
74+
75+
// Create OAuth session manager before the main client
76+
constoauthSessionManager=awaitOAuthSessionManager.create(
77+
url||"",
78+
serviceContainer,
79+
ctx,
80+
);
81+
ctx.subscriptions.push(oauthSessionManager);
82+
7383
// This client tracks the current login and will be used through the life of
7484
// the plugin to poll workspaces for the current login, as well as being used
7585
// in commands that operate on the current login.
76-
consturl=mementoManager.getUrl();
7786
constclient=CoderApi.create(
7887
url||"",
7988
awaitsecretsManager.getSessionToken(),
8089
output,
90+
oauthSessionManager,
8191
);
8292

8393
constmyWorkspacesProvider=newWorkspaceProvider(
@@ -123,14 +133,6 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
123133
ctx.subscriptions,
124134
);
125135

126-
constoauthSessionManager=awaitOAuthSessionManager.create(
127-
url||"",
128-
secretsManager,
129-
output,
130-
ctx,
131-
);
132-
ctx.subscriptions.push(oauthSessionManager);
133-
134136
// Listen for session token changes and sync state across all components
135137
ctx.subscriptions.push(
136138
secretsManager.onDidChangeSessionToken(async(token)=>{
@@ -409,6 +411,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
409411
isFirstConnect,
410412
);
411413
if(details){
414+
// TODO if the URL is different then we need to update the OAuth session!!! (Centralize this logic)
412415
ctx.subscriptions.push(details);
413416
// Authenticate the plugin client which is used in the sidebar to display
414417
// workspaces belonging to this deployment.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp