diff --git a/.changeset/shaggy-lies-go.md b/.changeset/shaggy-lies-go.md new file mode 100644 index 00000000..ebfc0251 --- /dev/null +++ b/.changeset/shaggy-lies-go.md @@ -0,0 +1,5 @@ +--- +'@hono/node-ws': patch +--- + +fix a bug if upgrading process uses async function diff --git a/packages/node-ws/src/index.test.ts b/packages/node-ws/src/index.test.ts index a64a879b..508785b3 100644 --- a/packages/node-ws/src/index.test.ts +++ b/packages/node-ws/src/index.test.ts @@ -283,4 +283,27 @@ describe('WebSocket helper', () => { expect(await mainPromise).toBe(true) }) + + it('Should not async processes to create events affect message handling', async () => { + const mainPromise = new Promise((resolve) => + app.get( + '/', + upgradeWebSocket(async () => { + await new Promise((resolve) => setTimeout(resolve, 100)) + return { + onMessage() { + resolve(true) + }, + } + }) + ) + ) + + const ws = new WebSocket('ws://localhost:3030/') + ws.onopen = () => { + ws.send('Hello') + } + + expect(await mainPromise).toBe(true) + }) }) diff --git a/packages/node-ws/src/index.ts b/packages/node-ws/src/index.ts index 8a87deb2..e880c9dd 100644 --- a/packages/node-ws/src/index.ts +++ b/packages/node-ws/src/index.ts @@ -106,6 +106,14 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => { c.env[CONNECTION_SYMBOL_KEY] = connectionSymbol ;(async () => { const ws = await nodeUpgradeWebSocket(c.env.incoming, connectionSymbol) + + // buffer messages to handle messages received before the events are set up + const messagesReceivedInStarting: [data: WebSocket.RawData, isBinary: boolean][] = [] + const bufferMessage = (data: WebSocket.RawData, isBinary: boolean) => { + messagesReceivedInStarting.push([data, isBinary]) + } + ws.on('message', bufferMessage) + let events: WSEvents try { events = await createEvents(c) @@ -137,7 +145,8 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => { } catch (e) { ;(options?.onError ?? console.error)(e) } - ws.on('message', (data, isBinary) => { + + const handleMessage = (data: WebSocket.RawData, isBinary: boolean) => { const datas = Array.isArray(data) ? data : [data] for (const data of datas) { try { @@ -155,6 +164,14 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => { ;(options?.onError ?? console.error)(e) } } + } + ws.off('message', bufferMessage) + for (const message of messagesReceivedInStarting) { + handleMessage(...message) + } + + ws.on('message', (data, isBinary) => { + handleMessage(data, isBinary) }) ws.on('close', (code, reason) => { try {