@@ -2,6 +2,7 @@ import { z } from "zod";
22
33import { DeploymentSchema , type Deployment } from "../deployment/types" ;
44import { toSafeHost } from "../util" ;
5+ import { WindowBroadcast } from "../windowBroadcast" ;
56
67import type { OAuth2ClientRegistrationResponse } from "coder/site/src/api/typesGenerated" ;
78import type { Memento , SecretStorage , Disposable } from "vscode" ;
@@ -57,14 +58,24 @@ const OAuthCallbackDataSchema = z.object({
5758 error : z . string ( ) . nullable ( ) ,
5859} ) ;
5960
60- type OAuthCallbackData = z . infer < typeof OAuthCallbackDataSchema > ;
61+ export type OAuthCallbackData = z . infer < typeof OAuthCallbackDataSchema > ;
6162
6263export class SecretsManager {
64+ public readonly oauthCallback : WindowBroadcast < OAuthCallbackData > ;
65+
6366 constructor (
6467 private readonly secrets : SecretStorage ,
6568 private readonly memento : Memento ,
6669 private readonly logger : Logger ,
67- ) { }
70+ ) {
71+ this . oauthCallback = new WindowBroadcast (
72+ secrets ,
73+ OAUTH_CALLBACK_KEY ,
74+ ( v : unknown ) : v is OAuthCallbackData =>
75+ OAuthCallbackDataSchema . safeParse ( v ) . success ,
76+ logger ,
77+ ) ;
78+ }
6879
6980 private buildKey ( prefix : SecretKeyPrefix , safeHostname : string ) : string {
7081 return `${ prefix } ${ safeHostname || "<legacy>" } ` ;
@@ -306,54 +317,6 @@ export class SecretsManager {
306317 return safeHostname ;
307318 }
308319
309- /**
310- * Write an OAuth callback result to secrets storage.
311- * Used for cross-window communication when OAuth callback arrives in a different window.
312- */
313- public async setOAuthCallback ( data : OAuthCallbackData ) : Promise < void > {
314- const parsed = OAuthCallbackDataSchema . parse ( data ) ;
315- await this . secrets . store ( OAUTH_CALLBACK_KEY , JSON . stringify ( parsed ) ) ;
316- }
317-
318- /**
319- * Listen for OAuth callback results from any VS Code window.
320- * The listener receives the state parameter, code (if success), and error (if failed).
321- */
322- public onDidChangeOAuthCallback (
323- listener : ( data : OAuthCallbackData ) => void ,
324- ) : Disposable {
325- return this . secrets . onDidChange ( async ( e ) => {
326- if ( e . key !== OAUTH_CALLBACK_KEY ) {
327- return ;
328- }
329-
330- const raw = await this . secrets . get ( OAUTH_CALLBACK_KEY ) ;
331- if ( ! raw ) {
332- return ;
333- }
334-
335- let parsed : unknown ;
336- try {
337- parsed = JSON . parse ( raw ) ;
338- } catch ( err ) {
339- this . logger . error ( "Failed to parse OAuth callback JSON" , err ) ;
340- return ;
341- }
342-
343- const result = OAuthCallbackDataSchema . safeParse ( parsed ) ;
344- if ( ! result . success ) {
345- this . logger . error ( "Invalid OAuth callback data shape" , result . error ) ;
346- return ;
347- }
348-
349- try {
350- listener ( result . data ) ;
351- } catch ( err ) {
352- this . logger . error ( "Error in onDidChangeOAuthCallback listener" , err ) ;
353- }
354- } ) ;
355- }
356-
357320 public getOAuthClientRegistration (
358321 safeHostname : string ,
359322 ) : Promise < OAuth2ClientRegistrationResponse | undefined > {
0 commit comments