@@ -5,6 +5,7 @@ import type { DevframeRpcConnection, WsOriginRegistry, WsRpcTransport } from 'de
55import type { H3 , H3Event } from 'h3'
66import type { Buffer } from 'node:buffer'
77import type { IncomingMessage , Server as NodeHttpServer , ServerResponse } from 'node:http'
8+ import type { AddressInfo } from 'node:net'
89import type { Duplex } from 'node:stream'
910import type { ConnectionMeta , DevframeNodeContext , DevframeNodeRpcSession , DevframeNodeRpcSessionMeta , DevframeRpcClientFunctions , DevframeRpcServerFunctions } from '../types'
1011import type { DevframeSseOptions , DevframeWsOptions } from '../types/devframe'
@@ -144,14 +145,16 @@ async function bindHttpAndWs(options: BindHttpAndWsOptions): Promise<StartedServ
144145
145146 const address = httpServer . address ( )
146147 const resolvedPort = typeof address === 'object' && address ? address . port : port
147- const secure = httpServer instanceof TlsServer
148- const origin = secure
148+ const origin = httpServer instanceof TlsServer
149149 ? `https://${ formatHostForUrl ( bindHost ) } :${ resolvedPort } `
150150 : normalizeHttpServerUrl ( bindHost , resolvedPort )
151- const internal = getInternalContext ( context )
152- const wsUrl = `${ secure ? 'wss' : 'ws' } ://${ formatHostForUrl ( bindHost ) } :${ resolvedPort } ${ options . path ?? '' } `
153- if ( websocket )
154- internal . setWsEndpoint ( { url : wsUrl } )
151+ let wsUrl : string | undefined
152+ const cancelPublish = websocket
153+ ? whenListening ( httpServer , ( boundPort ) => {
154+ wsUrl = `${ wsScheme ( httpServer ) } ://${ formatHostForUrl ( bindHost ) } :${ boundPort } ${ options . path ?? '' } `
155+ getInternalContext ( context ) . setWsEndpoint ( { url : wsUrl } )
156+ } )
157+ : ( ) => { }
155158
156159 return {
157160 origin,
@@ -161,15 +164,34 @@ async function bindHttpAndWs(options: BindHttpAndWsOptions): Promise<StartedServ
161164 rpcGroup : core . rpcGroup ,
162165 connectionMeta : ( ) => websocketConnectionMeta ( rpcHost , options . path ) ,
163166 async close ( ) {
167+ cancelPublish ( )
164168 await closeWs ( )
165169 if ( ownsHttpServer )
166170 await new Promise < void > ( r => httpServer . close ( ( ) => r ( ) ) )
167- if ( websocket && getInternalContext ( context ) . wsEndpoint ?. url === wsUrl )
171+ if ( wsUrl && getInternalContext ( context ) . wsEndpoint ?. url === wsUrl )
168172 getInternalContext ( context ) . setWsEndpoint ( undefined )
169173 } ,
170174 }
171175}
172176
177+ function wsScheme ( server : NodeHttpServer ) : 'ws' | 'wss' {
178+ return server instanceof TlsServer ? 'wss' : 'ws'
179+ }
180+
181+ function whenListening ( server : NodeHttpServer , fn : ( port : number , address : AddressInfo ) => void ) : ( ) => void {
182+ const run = ( ) : void => {
183+ const address = server . address ( )
184+ if ( typeof address === 'object' && address )
185+ fn ( address . port , address )
186+ }
187+ if ( server . listening ) {
188+ run ( )
189+ return ( ) => { }
190+ }
191+ server . once ( 'listening' , run )
192+ return ( ) => server . off ( 'listening' , run )
193+ }
194+
173195/**
174196 * Structural view of `Bun.serve`, typed loosely so devframe carries no
175197 * dependency on Bun's own types (`tsc` runs with Node lib only).
@@ -943,19 +965,12 @@ export function createInstanceShell<TContext extends DevframeNodeContext>(
943965 * {@link bindHttpAndWs} does the same for the tiers it owns.
944966 */
945967 function publishWsEndpoint ( server : NodeHttpServer ) : void {
946- const record = ( ) : void => {
947- const address = server . address ( )
948- if ( typeof address !== 'object' || ! address )
949- return
968+ whenListening ( server , ( boundPort , address ) => {
950969 const host = options . host ?? ( address . address === '::' || address . address === '0.0.0.0' ? 'localhost' : address . address )
951970 getInternalContext ( ctx ) . setWsEndpoint ( {
952- url : `ws ://${ formatHostForUrl ( host ) } :${ address . port } ${ routePath } ` ,
971+ url : `${ wsScheme ( server ) } ://${ formatHostForUrl ( host ) } :${ boundPort } ${ routePath } ` ,
953972 } )
954- }
955- if ( server . listening )
956- record ( )
957- else
958- server . once ( 'listening' , record )
973+ } )
959974 }
960975
961976 function handleUpgrade ( req : IncomingMessage , socket : Duplex , head : Buffer ) : void {
0 commit comments