@@ -99,8 +99,8 @@ describe("AuthService", () => {
9999 }
100100 vi . mocked ( RefreshTimer ) . mockImplementation ( ( ) => mockTimer as unknown as RefreshTimer )
101101
102- // Setup config mocks
103- vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( "https://clerk.test .com" )
102+ // Setup config mocks - use production URL by default to maintain existing test behavior
103+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( "https://clerk.roocode .com" )
104104 vi . mocked ( Config . getRooCodeApiUrl ) . mockReturnValue ( "https://api.test.com" )
105105
106106 // Setup utils mock
@@ -377,7 +377,7 @@ describe("AuthService", () => {
377377 expect ( mockContext . secrets . delete ) . toHaveBeenCalledWith ( "clerk-auth-credentials" )
378378 expect ( mockContext . globalState . update ) . toHaveBeenCalledWith ( "clerk-auth-state" , undefined )
379379 expect ( mockFetch ) . toHaveBeenCalledWith (
380- "https://clerk.test .com/v1/client/sessions/test-session/remove" ,
380+ "https://clerk.roocode .com/v1/client/sessions/test-session/remove" ,
381381 expect . objectContaining ( {
382382 method : "POST" ,
383383 headers : expect . objectContaining ( {
@@ -812,4 +812,141 @@ describe("AuthService", () => {
812812 expect ( mockTimer . start ) . toHaveBeenCalled ( )
813813 } )
814814 } )
815+
816+ describe ( "auth credentials key scoping" , ( ) => {
817+ it ( "should use default key when getClerkBaseUrl returns production URL" , async ( ) => {
818+ // Mock getClerkBaseUrl to return production URL
819+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( "https://clerk.roocode.com" )
820+
821+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
822+ const credentials = { clientToken : "test-token" , sessionId : "test-session" }
823+
824+ await service . initialize ( )
825+ await service [ "storeCredentials" ] ( credentials )
826+
827+ expect ( mockContext . secrets . store ) . toHaveBeenCalledWith (
828+ "clerk-auth-credentials" ,
829+ JSON . stringify ( credentials ) ,
830+ )
831+ } )
832+
833+ it ( "should use scoped key when getClerkBaseUrl returns custom URL" , async ( ) => {
834+ const customUrl = "https://custom.clerk.com"
835+ // Mock getClerkBaseUrl to return custom URL
836+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( customUrl )
837+
838+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
839+ const credentials = { clientToken : "test-token" , sessionId : "test-session" }
840+
841+ await service . initialize ( )
842+ await service [ "storeCredentials" ] ( credentials )
843+
844+ expect ( mockContext . secrets . store ) . toHaveBeenCalledWith (
845+ `clerk-auth-credentials-${ customUrl } ` ,
846+ JSON . stringify ( credentials ) ,
847+ )
848+ } )
849+
850+ it ( "should load credentials using scoped key" , async ( ) => {
851+ const customUrl = "https://custom.clerk.com"
852+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( customUrl )
853+
854+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
855+ const credentials = { clientToken : "test-token" , sessionId : "test-session" }
856+ mockContext . secrets . get . mockResolvedValue ( JSON . stringify ( credentials ) )
857+
858+ await service . initialize ( )
859+ const loadedCredentials = await service [ "loadCredentials" ] ( )
860+
861+ expect ( mockContext . secrets . get ) . toHaveBeenCalledWith ( `clerk-auth-credentials-${ customUrl } ` )
862+ expect ( loadedCredentials ) . toEqual ( credentials )
863+ } )
864+
865+ it ( "should clear credentials using scoped key" , async ( ) => {
866+ const customUrl = "https://custom.clerk.com"
867+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( customUrl )
868+
869+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
870+
871+ await service . initialize ( )
872+ await service [ "clearCredentials" ] ( )
873+
874+ expect ( mockContext . secrets . delete ) . toHaveBeenCalledWith ( `clerk-auth-credentials-${ customUrl } ` )
875+ } )
876+
877+ it ( "should listen for changes on scoped key" , async ( ) => {
878+ const customUrl = "https://custom.clerk.com"
879+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( customUrl )
880+
881+ let onDidChangeCallback : ( e : { key : string } ) => void
882+
883+ mockContext . secrets . onDidChange . mockImplementation ( ( callback : ( e : { key : string } ) => void ) => {
884+ onDidChangeCallback = callback
885+ return { dispose : vi . fn ( ) }
886+ } )
887+
888+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
889+ await service . initialize ( )
890+
891+ // Simulate credentials change event with scoped key
892+ const newCredentials = { clientToken : "new-token" , sessionId : "new-session" }
893+ mockContext . secrets . get . mockResolvedValue ( JSON . stringify ( newCredentials ) )
894+
895+ const inactiveSessionSpy = vi . fn ( )
896+ service . on ( "inactive-session" , inactiveSessionSpy )
897+
898+ onDidChangeCallback ! ( { key : `clerk-auth-credentials-${ customUrl } ` } )
899+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) // Wait for async handling
900+
901+ expect ( inactiveSessionSpy ) . toHaveBeenCalled ( )
902+ } )
903+
904+ it ( "should not respond to changes on different scoped keys" , async ( ) => {
905+ const customUrl = "https://custom.clerk.com"
906+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( customUrl )
907+
908+ let onDidChangeCallback : ( e : { key : string } ) => void
909+
910+ mockContext . secrets . onDidChange . mockImplementation ( ( callback : ( e : { key : string } ) => void ) => {
911+ onDidChangeCallback = callback
912+ return { dispose : vi . fn ( ) }
913+ } )
914+
915+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
916+ await service . initialize ( )
917+
918+ const inactiveSessionSpy = vi . fn ( )
919+ service . on ( "inactive-session" , inactiveSessionSpy )
920+
921+ // Simulate credentials change event with different scoped key
922+ onDidChangeCallback ! ( { key : "clerk-auth-credentials-https://other.clerk.com" } )
923+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) // Wait for async handling
924+
925+ expect ( inactiveSessionSpy ) . not . toHaveBeenCalled ( )
926+ } )
927+
928+ it ( "should not respond to changes on default key when using scoped key" , async ( ) => {
929+ const customUrl = "https://custom.clerk.com"
930+ vi . mocked ( Config . getClerkBaseUrl ) . mockReturnValue ( customUrl )
931+
932+ let onDidChangeCallback : ( e : { key : string } ) => void
933+
934+ mockContext . secrets . onDidChange . mockImplementation ( ( callback : ( e : { key : string } ) => void ) => {
935+ onDidChangeCallback = callback
936+ return { dispose : vi . fn ( ) }
937+ } )
938+
939+ const service = new AuthService ( mockContext as unknown as vscode . ExtensionContext , mockLog )
940+ await service . initialize ( )
941+
942+ const inactiveSessionSpy = vi . fn ( )
943+ service . on ( "inactive-session" , inactiveSessionSpy )
944+
945+ // Simulate credentials change event with default key
946+ onDidChangeCallback ! ( { key : "clerk-auth-credentials" } )
947+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) // Wait for async handling
948+
949+ expect ( inactiveSessionSpy ) . not . toHaveBeenCalled ( )
950+ } )
951+ } )
815952} )
0 commit comments