1- import * as vscode from "vscode" ;
2-
31import { CoderApi } from "../api/coderApi" ;
42import {
53 CONFIG_CHANGE_DEBOUNCE_MS ,
@@ -14,32 +12,21 @@ import { type OAuthSessionManager } from "../oauth/sessionManager";
1412import { getAuthConfigWatchSettings } from "../settings/authConfig" ;
1513import { type TelemetryService } from "../telemetry/service" ;
1614
15+ import { SessionStore , type SessionData } from "./sessionStore" ;
1716import {
1817 DeploymentSchema ,
1918 type Deployment ,
2019 type DeploymentWithAuth ,
2120} from "./types" ;
2221
2322import type { User } from "coder/site/src/api/typesGenerated" ;
23+ import type * as vscode from "vscode" ;
2424
2525import type {
2626 WorkspaceSessionSnapshot ,
2727 WorkspaceSessionState ,
2828} from "../workspace/session" ;
2929
30- type DeploymentSessionSnapshot =
31- | {
32- readonly kind : "signedOut" ;
33- readonly revision : number ;
34- readonly deployment : Deployment | null ;
35- }
36- | {
37- readonly kind : "signedIn" ;
38- readonly revision : number ;
39- readonly deployment : Deployment ;
40- readonly user : User ;
41- } ;
42-
4330/**
4431 * Manages deployment state for the extension.
4532 *
@@ -60,14 +47,8 @@ export class DeploymentManager
6047 private readonly logger : Logger ;
6148 private readonly telemetryService : TelemetryService ;
6249
63- #session: DeploymentSessionSnapshot = {
64- kind : "signedOut" ,
65- revision : 0 ,
66- deployment : null ,
67- } ;
68- readonly #onDidChangeWorkspaceSession =
69- new vscode . EventEmitter < WorkspaceSessionSnapshot > ( ) ;
70- public readonly onDidChange = this . #onDidChangeWorkspaceSession. event ;
50+ readonly #sessionStore = new SessionStore ( ) ;
51+ public readonly onDidChange = this . #sessionStore. onDidChange ;
7152 #disposed = false ;
7253 #authListenerDisposable: vscode . Disposable | undefined ;
7354 #authConfigDisposable: vscode . Disposable | undefined ;
@@ -106,31 +87,18 @@ export class DeploymentManager
10687 * Get the current deployment state.
10788 */
10889 public getCurrentDeployment ( ) : Deployment | null {
109- return this . #session. deployment ;
110- }
111-
112- public getCurrentUserId ( ) : string | undefined {
113- return this . #session. kind === "signedIn"
114- ? this . #session. user . id
115- : undefined ;
90+ return this . #sessionStore. current . deployment ;
11691 }
11792
11893 public getSnapshot ( ) : WorkspaceSessionSnapshot {
119- if ( this . #session. kind === "signedIn" ) {
120- return {
121- kind : "signedIn" ,
122- revision : this . #session. revision ,
123- userId : this . #session. user . id ,
124- } ;
125- }
126- return { kind : "signedOut" , revision : this . #session. revision } ;
94+ return this . #sessionStore. getSnapshot ( ) ;
12795 }
12896
12997 /**
13098 * Check if we have an authenticated deployment (does not guarantee that the current auth data is valid).
13199 */
132100 public isAuthenticated ( ) : boolean {
133- return this . #session . kind === "signedIn" ;
101+ return this . #sessionStore . current . kind === "signedIn" ;
134102 }
135103
136104 /**
@@ -139,10 +107,10 @@ export class DeploymentManager
139107 * a token become valid again. Bails if state moved during the verify
140108 * (logout, another login, dispose), so callers don't need a race guard.
141109 */
142- public async verifyAndApplyDeployment (
110+ public async verifyAndApply (
143111 deployment : Deployment & { token ?: string } ,
144112 ) : Promise < boolean > {
145- const sessionBefore = this . #session ;
113+ const sessionBefore = this . #sessionStore . current ;
146114 const token =
147115 deployment . token ??
148116 ( await this . secretsManager . getSessionAuth ( deployment . safeHostname ) )
@@ -165,11 +133,11 @@ export class DeploymentManager
165133 }
166134
167135 /** True if disposal, login, or a deployment switch raced our await. */
168- #hasStateChangedSince( sessionBefore : DeploymentSessionSnapshot ) : boolean {
136+ #hasStateChangedSince( sessionBefore : SessionData ) : boolean {
169137 return (
170138 this . #disposed ||
171139 this . isAuthenticated ( ) ||
172- this . #session !== sessionBefore
140+ this . #sessionStore . current !== sessionBefore
173141 ) ;
174142 }
175143
@@ -192,14 +160,17 @@ export class DeploymentManager
192160 this . client . setCredentials ( deployment . url , deployment . token ) ;
193161 }
194162
195- const ourRef = this . setSignedIn ( deploymentWithoutAuth , deployment . user ) ;
163+ const ourRef = this . #sessionStore. signIn (
164+ deploymentWithoutAuth ,
165+ deployment . user ,
166+ ) ;
196167 // Register before OAuth setup so background token refresh can update client credentials.
197168 this . registerAuthListener ( ) ;
198169 this . updateAuthContexts ( deployment . user ) ;
199170
200171 await this . oauthSessionManager . setDeployment ( deploymentWithoutAuth ) ;
201172 // Bail if a concurrent write took over during the await.
202- if ( this . #session !== ourRef ) {
173+ if ( this . #sessionStore . current !== ourRef ) {
203174 return ;
204175 }
205176 await this . persistDeployment ( deploymentWithoutAuth ) ;
@@ -211,12 +182,12 @@ export class DeploymentManager
211182 public async clearDeployment ( ) : Promise < void > {
212183 this . logger . debug (
213184 "Clearing deployment" ,
214- this . #session . deployment ?. safeHostname ,
185+ this . #sessionStore . current . deployment ?. safeHostname ,
215186 ) ;
216187 this . #authListenerDisposable?. dispose ( ) ;
217188 this . #authListenerDisposable = undefined ;
218- this . setSignedOut ( null ) ;
219- this . clearSessionSideEffects ( ) ;
189+ this . #sessionStore . signOut ( null ) ;
190+ this . clearSideEffects ( ) ;
220191 this . telemetryService . setDeploymentUrl ( "" ) ;
221192
222193 await this . secretsManager . setCurrentDeployment ( undefined ) ;
@@ -227,11 +198,11 @@ export class DeploymentManager
227198 * Auth listener remains active so recovery can happen automatically if tokens update.
228199 */
229200 public suspendSession ( ) : void {
230- this . setSignedOut ( this . #session . deployment ) ;
231- this . clearSessionSideEffects ( ) ;
201+ this . #sessionStore . signOut ( this . #sessionStore . current . deployment ) ;
202+ this . clearSideEffects ( ) ;
232203 }
233204
234- private clearSessionSideEffects ( ) : void {
205+ private clearSideEffects ( ) : void {
235206 this . oauthSessionManager . clearDeployment ( ) ;
236207 this . client . setCredentials ( undefined , undefined ) ;
237208 this . updateAuthContexts ( undefined ) ;
@@ -242,7 +213,7 @@ export class DeploymentManager
242213 this . #authListenerDisposable?. dispose ( ) ;
243214 this . #authConfigDisposable?. dispose ( ) ;
244215 this . #crossWindowSyncDisposable?. dispose ( ) ;
245- this . #onDidChangeWorkspaceSession . dispose ( ) ;
216+ this . #sessionStore . dispose ( ) ;
246217 }
247218
248219 /**
@@ -251,25 +222,28 @@ export class DeploymentManager
251222 * Also handles recovery from suspended session state.
252223 */
253224 private registerAuthListener ( ) : void {
254- if ( ! this . #session. deployment ) {
225+ const deployment = this . #sessionStore. current . deployment ;
226+ if ( ! deployment ) {
255227 return ;
256228 }
257229
258230 // Capture hostname at registration time for the guard clause
259- const safeHostname = this . #session . deployment . safeHostname ;
231+ const safeHostname = deployment . safeHostname ;
260232
261233 this . #authListenerDisposable?. dispose ( ) ;
262234 this . logger . debug ( "Registering auth listener for hostname" , safeHostname ) ;
263235 this . #authListenerDisposable = this . secretsManager . onDidChangeSessionAuth (
264236 safeHostname ,
265237 async ( auth ) => {
266- if ( this . #session. deployment ?. safeHostname !== safeHostname ) {
238+ if (
239+ this . #sessionStore. current . deployment ?. safeHostname !== safeHostname
240+ ) {
267241 return ;
268242 }
269243
270244 if ( auth ) {
271245 if ( this . isAuthenticated ( ) ) {
272- await this . verifyAndUpdateAuthenticatedSession ( {
246+ await this . verifyAndUpdateSession ( {
273247 url : auth . url ,
274248 safeHostname,
275249 token : auth . token ,
@@ -278,7 +252,7 @@ export class DeploymentManager
278252 this . logger . debug (
279253 "Token updated after session suspended, recovering" ,
280254 ) ;
281- await this . verifyAndApplyDeployment ( {
255+ await this . verifyAndApply ( {
282256 url : auth . url ,
283257 safeHostname,
284258 token : auth . token ,
@@ -291,10 +265,10 @@ export class DeploymentManager
291265 ) ;
292266 }
293267
294- private async verifyAndUpdateAuthenticatedSession (
268+ private async verifyAndUpdateSession (
295269 deployment : Deployment & { token : string } ,
296270 ) : Promise < void > {
297- const sessionBefore = this . #session ;
271+ const sessionBefore = this . #sessionStore . current ;
298272 const tempClient = CoderApi . create (
299273 deployment . url ,
300274 deployment . token ,
@@ -303,7 +277,7 @@ export class DeploymentManager
303277
304278 try {
305279 const user = await tempClient . getAuthenticatedUser ( ) ;
306- if ( this . #disposed || this . #session !== sessionBefore ) {
280+ if ( this . #disposed || this . #sessionStore . current !== sessionBefore ) {
307281 return ;
308282 }
309283 await this . setDeployment ( { ...deployment , user } ) ;
@@ -314,32 +288,6 @@ export class DeploymentManager
314288 }
315289 }
316290
317- private setSignedIn (
318- deployment : Deployment ,
319- user : User ,
320- ) : DeploymentSessionSnapshot {
321- this . #session = {
322- kind : "signedIn" ,
323- revision : this . #session. revision + 1 ,
324- deployment,
325- user,
326- } ;
327- this . #onDidChangeWorkspaceSession. fire ( this . getSnapshot ( ) ) ;
328- return this . #session;
329- }
330-
331- private setSignedOut (
332- deployment : Deployment | null ,
333- ) : DeploymentSessionSnapshot {
334- this . #session = {
335- kind : "signedOut" ,
336- revision : this . #session. revision + 1 ,
337- deployment,
338- } ;
339- this . #onDidChangeWorkspaceSession. fire ( this . getSnapshot ( ) ) ;
340- return this . #session;
341- }
342-
343291 private subscribeToAuthConfigChanges ( ) : void {
344292 this . #authConfigDisposable = watchConfigurationChanges (
345293 getAuthConfigWatchSettings ( ) ,
@@ -363,14 +311,14 @@ export class DeploymentManager
363311 try {
364312 do {
365313 this . #recoveryPending = false ;
366- const snapshot = this . #session . deployment ;
367- if ( this . #disposed || ! snapshot || this . isAuthenticated ( ) ) {
314+ const deployment = this . #sessionStore . current . deployment ;
315+ if ( this . #disposed || ! deployment || this . isAuthenticated ( ) ) {
368316 return ;
369317 }
370318 this . logger . debug (
371319 "Authentication settings changed after session suspended, recovering" ,
372320 ) ;
373- await this . verifyAndApplyDeployment ( snapshot ) ;
321+ await this . verifyAndApply ( deployment ) ;
374322 } while ( this . #recoveryPending) ;
375323 } catch ( err ) {
376324 this . logger . warn (
@@ -392,7 +340,7 @@ export class DeploymentManager
392340
393341 if ( deployment ) {
394342 this . logger . info ( "Deployment changed from another window" ) ;
395- await this . verifyAndApplyDeployment ( deployment ) ;
343+ await this . verifyAndApply ( deployment ) ;
396344 }
397345 } ,
398346 ) ;
0 commit comments