11import { afterAll , beforeAll , describe , expect , test } from "bun:test" ;
2- import { serve } from "@blink.so/api/test " ;
2+ import Client from "@blink.so/api" ;
33import { createDevhookSupport } from "./devhook" ;
4+ import { serve } from "./test" ;
45
56describe ( "devhook integration tests" , ( ) => {
67 let server : Awaited < ReturnType < typeof serve > > ;
@@ -18,8 +19,8 @@ describe("devhook integration tests", () => {
1819 } ) ;
1920 } ) ;
2021
21- afterAll ( ( ) => {
22- server . stop ( ) ;
22+ afterAll ( async ( ) => {
23+ await server [ Symbol . asyncDispose ] ( ) ;
2324 } ) ;
2425
2526 describe ( "UUID validation" , ( ) => {
@@ -82,6 +83,54 @@ describe("devhook integration tests", () => {
8283 } ) ;
8384 } ) ;
8485
86+ describe ( "authentication" , ( ) => {
87+ test ( "requires auth for devhook listen" , async ( ) => {
88+ const id = crypto . randomUUID ( ) ;
89+ const client = new Client ( { baseURL : server . url . toString ( ) } ) ;
90+ let connected = false ;
91+ let errorEvent : unknown ;
92+
93+ const outcome = await new Promise < "error" | "disconnect" > (
94+ ( resolve , reject ) => {
95+ const timer = setTimeout ( ( ) => {
96+ reject ( new Error ( "Timed out waiting for devhook auth failure" ) ) ;
97+ } , 5000 ) ;
98+
99+ let disposable : { dispose : ( ) => void } | undefined ;
100+ disposable = client . devhook . listen ( {
101+ id,
102+ onRequest : async ( ) => new Response ( "ok" ) ,
103+ onConnect : ( ) => {
104+ connected = true ;
105+ } ,
106+ onDisconnect : ( ) => {
107+ clearTimeout ( timer ) ;
108+ disposable ?. dispose ( ) ;
109+ resolve ( "disconnect" ) ;
110+ } ,
111+ onError : ( err ) => {
112+ errorEvent = err ;
113+ clearTimeout ( timer ) ;
114+ disposable ?. dispose ( ) ;
115+ resolve ( "error" ) ;
116+ } ,
117+ } ) ;
118+ }
119+ ) ;
120+
121+ expect ( outcome ) . toBe ( "error" ) ;
122+ expect ( connected ) . toBe ( false ) ;
123+ expect ( errorEvent ) . toBeDefined ( ) ;
124+
125+ // Assert the actual auth error message via HTTP since WebSocket errors
126+ // do not expose the handshake response body.
127+ const response = await client . request ( "GET" , `/api/devhook/${ id } /url` ) ;
128+ expect ( response . status ) . toBe ( 401 ) ;
129+ const body = await response . json ( ) ;
130+ expect ( body . message ) . toBe ( "Unauthorized" ) ;
131+ } ) ;
132+ } ) ;
133+
85134 describe ( "devhook proxy flow" , ( ) => {
86135 test ( "proxies requests through connected devhook" , async ( ) => {
87136 const { helpers, bindings, url } = server ;
0 commit comments