@@ -385,9 +385,29 @@ export class Client {
385
385
this . _client = new ThinClient ( baseUrl ? new URL ( baseUrl ) : undefined ) ;
386
386
this . _authChange = opts ?. onAuthChange ;
387
387
388
+ const tokens = opts ?. tokens ;
388
389
// Note: this is a double assignment to _tokenState to ensure the linter
389
390
// that it's really initialized in the constructor.
390
- this . _tokenState = this . setTokenState ( buildTokenState ( opts ?. tokens ) , true ) ;
391
+ this . _tokenState = this . setTokenState ( buildTokenState ( tokens ) , true ) ;
392
+
393
+ if ( tokens ?. refresh_token !== undefined ) {
394
+ // Validate session. This is currently async, which allows to initialize
395
+ // a Client synchronously from invalid tokens. We may want to consider
396
+ // offering a safer async initializer to avoid "racy" behavior. Especially,
397
+ // when the auth token is valid while the session has already been closed.
398
+ this . checkAuthStatus ( )
399
+ . then ( ( tokens ) => {
400
+ if ( tokens === undefined ) {
401
+ // In this case, the auth state has changed, so we should invoke the callback.
402
+ this . setTokenState ( buildTokenState ( undefined ) , false ) ;
403
+ } else {
404
+ // In this case, the auth state has remained the same, we're merely
405
+ // updating the reminted auth token.
406
+ this . setTokenState ( buildTokenState ( tokens ) , true ) ;
407
+ }
408
+ } )
409
+ . catch ( console . error ) ;
410
+ }
391
411
}
392
412
393
413
public static init ( site ?: URL | string , opts ?: ClientOptions ) : Client {
@@ -488,20 +508,31 @@ export class Client {
488
508
} ) ;
489
509
}
490
510
491
- public async checkCookies ( ) : Promise < Tokens | undefined > {
492
- const response = await this . fetch ( `${ authApiBasePath } /status` ) ;
493
- const status : LoginStatusResponse = await response . json ( ) ;
494
-
495
- const authToken = status ?. auth_token ;
496
- if ( authToken ) {
497
- const newState = buildTokenState ( {
498
- auth_token : authToken ,
499
- refresh_token : status . refresh_token ,
500
- csrf_token : status . csrf_token ,
501
- } ) ;
511
+ /// This will call the status endpoint, which validates any provided tokens
512
+ /// but also hoists any tokens provided as cookies into a JSON response.
513
+ private async checkAuthStatus ( ) : Promise < Tokens | undefined > {
514
+ const response = await this . fetch ( `${ authApiBasePath } /status` , {
515
+ throwOnError : false ,
516
+ } ) ;
517
+ if ( response . ok ) {
518
+ const status : LoginStatusResponse = await response . json ( ) ;
519
+ const auth_token = status . auth_token ;
520
+ if ( auth_token ) {
521
+ return {
522
+ auth_token,
523
+ refresh_token : status . refresh_token ,
524
+ csrf_token : status . csrf_token ,
525
+ } ;
526
+ }
527
+ }
528
+ return undefined ;
529
+ }
502
530
531
+ public async checkCookies ( ) : Promise < Tokens | undefined > {
532
+ const tokens = await this . checkAuthStatus ( ) ;
533
+ if ( tokens ) {
534
+ const newState = buildTokenState ( tokens ) ;
503
535
this . setTokenState ( newState ) ;
504
-
505
536
return newState . state ?. tokens ;
506
537
}
507
538
}
@@ -579,7 +610,7 @@ export class Client {
579
610
return response ;
580
611
} catch ( err ) {
581
612
if ( err instanceof TypeError ) {
582
- throw Error ( `Connection refused ${ err } . TrailBase down or CORS?` ) ;
613
+ console . debug ( `Connection refused ${ err } . TrailBase down or CORS?` ) ;
583
614
}
584
615
throw err ;
585
616
}
0 commit comments