fix(node-ws): use buffering to fix #1129 (#1183)

* fix: use buffering to fix #1129

* chore: changeset

* chore: fmt
pull/1184/head
Shotaro Nakamura 2025-06-01 11:12:23 +09:00 committed by GitHub
parent 2fccb8b764
commit ccc49dd508
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 1 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/node-ws': patch
---
fix a bug if upgrading process uses async function

View File

@ -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<boolean>((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)
})
})

View File

@ -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<WebSocket>
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 {