@@ -79,31 +79,29 @@ export function controlPlugin(
7979 // Static asset reverse proxy + WebSocket upgrade on /control path.
8080 // The control UI derives its WebSocket URL from location.pathname,
8181 // so upgrade requests arrive at /ops/control rather than /ops/ws.
82- opsRouter . all (
83- "/control/*" ,
84- cloakedAuth ,
85- userOneGuard ,
86- ipAllowlist ,
87- async ( ctx , next ) => {
88- const env = ctx . env as ControlBindings ;
89- if ( ! env . GATEWAY_URL ) {
90- return ctx . notFound ( ) ;
91- }
92-
93- // WebSocket upgrade → transparent proxy (same handler as /ws cookie path)
94- if ( ctx . req . header ( "upgrade" ) ?. toLowerCase ( ) === "websocket" ) {
95- if ( ! env . GATEWAY_TOKEN ) return ctx . notFound ( ) ;
96- return proxyUpgrade ( ctx , next ) ;
97- }
98-
99- deps . obsEmitEvent ?.( ctx , {
100- type : "control.proxy" ,
101- detail : { path : ctx . req . path , method : ctx . req . method } ,
102- } ) ;
103-
104- return proxyToGateway ( ctx , env . GATEWAY_URL ) ;
105- } ,
106- ) ;
82+ const controlHandler : MiddlewareHandler = async ( ctx , next ) => {
83+ const env = ctx . env as ControlBindings ;
84+ if ( ! env . GATEWAY_URL ) {
85+ return ctx . notFound ( ) ;
86+ }
87+
88+ // WebSocket upgrade → transparent proxy (same handler as /ws cookie path)
89+ if ( ctx . req . header ( "upgrade" ) ?. toLowerCase ( ) === "websocket" ) {
90+ if ( ! env . GATEWAY_TOKEN ) return ctx . notFound ( ) ;
91+ return proxyUpgrade ( ctx , next ) ;
92+ }
93+
94+ deps . obsEmitEvent ?.( ctx , {
95+ type : "control.proxy" ,
96+ detail : { path : ctx . req . path , method : ctx . req . method } ,
97+ } ) ;
98+
99+ return proxyToGateway ( ctx , env . GATEWAY_URL ) ;
100+ } ;
101+
102+ // Both /control and /control/* are needed — Hono's wildcard doesn't match the bare path.
103+ opsRouter . all ( "/control" , cloakedAuth , userOneGuard , ipAllowlist , controlHandler ) ;
104+ opsRouter . all ( "/control/*" , cloakedAuth , userOneGuard , ipAllowlist , controlHandler ) ;
107105
108106 // WebSocket proxy multiplexer (ADR-010 §WebSocket Multiplexing)
109107 // Intercepts cookie-based connections on /ws for the proxy handler.
0 commit comments