@@ -407,6 +407,78 @@ describe("createOAuthProvider", () => {
407407 ] ) ;
408408 } ) ;
409409
410+ test ( "idle tokens getter adopts a sibling's completed auth without rewriting matching DCR" , async ( ) => {
411+ const home = await tempHome ( ) ;
412+ const a = await createOAuthProvider ( {
413+ serverName : "linear" ,
414+ serverURL : linear . serverURL ,
415+ redirectUrl : "http://127.0.0.1:62000/callback" ,
416+ onAuthURL : ( ) => undefined ,
417+ home,
418+ } ) ;
419+ await saveClient ( a , clientInfo ( 62000 ) ) ;
420+ await a . saveTokens ( {
421+ access_token : "tok-a" ,
422+ token_type : "bearer" ,
423+ expires_in : 3600 ,
424+ refresh_token : "ref-a" ,
425+ } ) ;
426+
427+ const b = await createOAuthProvider ( {
428+ serverName : "linear" ,
429+ serverURL : linear . serverURL ,
430+ redirectUrl : "http://127.0.0.1:60435/callback" ,
431+ onAuthURL : ( ) => undefined ,
432+ home,
433+ } ) ;
434+ await saveClient ( b , clientInfo ( 60435 ) ) ;
435+ await b . saveTokens ( {
436+ access_token : "tok-b" ,
437+ token_type : "bearer" ,
438+ expires_in : 3600 ,
439+ refresh_token : "ref-b" ,
440+ } ) ;
441+
442+ expect ( ( await syncValue ( a . tokens ( ) ) ) ?. access_token ) . toBe ( "tok-b" ) ;
443+ const disk = await loadAuthState ( linear , home ) ;
444+ expect ( disk . tokens ?. access_token ) . toBe ( "tok-b" ) ;
445+ expect ( disk . clientInformation ?. client_id ) . toBe ( "client-on-60435" ) ;
446+ expect ( disk . clientInformation ?. redirect_uris ) . toEqual ( [ "http://127.0.0.1:60435/callback" ] ) ;
447+ } ) ;
448+
449+ test ( "same-port DCR rotation after a different-port sibling saveClient keeps the new client" , async ( ) => {
450+ const home = await tempHome ( ) ;
451+ const v1 = { ...clientInfo ( 62000 ) , client_id : "client-on-62000-v1" } ;
452+ const v2 = { ...clientInfo ( 62000 ) , client_id : "client-on-62000-v2" } ;
453+ const a = await createOAuthProvider ( {
454+ serverName : "linear" ,
455+ serverURL : linear . serverURL ,
456+ redirectUrl : "http://127.0.0.1:62000/callback" ,
457+ onAuthURL : ( ) => undefined ,
458+ home,
459+ } ) ;
460+ await saveClient ( a , v1 ) ;
461+
462+ const b = await createOAuthProvider ( {
463+ serverName : "linear" ,
464+ serverURL : linear . serverURL ,
465+ redirectUrl : "http://127.0.0.1:60435/callback" ,
466+ onAuthURL : ( ) => undefined ,
467+ home,
468+ } ) ;
469+ await saveClient ( b , clientInfo ( 60435 ) ) ;
470+ await saveClient ( a , v2 ) ;
471+
472+ const info = await syncValue ( a . clientInformation ( ) ) ;
473+ expect ( info ?. client_id ) . toBe ( "client-on-62000-v2" ) ;
474+ expect ( info && "redirect_uris" in info ? info . redirect_uris : undefined ) . toEqual ( [
475+ "http://127.0.0.1:62000/callback" ,
476+ ] ) ;
477+ const disk = await loadAuthState ( linear , home ) ;
478+ expect ( disk . clientInformation ?. client_id ) . toBe ( "client-on-62000-v2" ) ;
479+ expect ( disk . clientInformation ?. redirect_uris ) . toEqual ( [ "http://127.0.0.1:62000/callback" ] ) ;
480+ } ) ;
481+
410482 test ( "sync getters fall back to the in-memory mirror when the auth file disappears" , async ( ) => {
411483 const home = await tempHome ( ) ;
412484 const provider = await createOAuthProvider ( {
0 commit comments