0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-21 10:08:58 +01:00

fix(helper/websocket): allow custom events to be passed to generics (#3616)

* fix(helper/websocket): allow custom events to be passed to generics

* chore: disable any

* add tests

* patch

* test patch
This commit is contained in:
EdamAmex 2024-11-03 16:14:03 +09:00 committed by GitHub
parent ae6165b994
commit 6b9fb24874
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 53 deletions

View File

@ -21,14 +21,13 @@ describe('upgradeWebSocket middleware', () => {
app.get(
'/ws',
upgradeWebSocket(() => ({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
onMessage(evt, ws) {
resolve(evt.data)
resolve([evt.data, ws.readyState || 1])
},
}))
)
)
it('Should receive message is valid', async () => {
it('Should receive message and readyState is valid', async () => {
const sendingData = Math.random().toString()
await app.request('/ws', {
headers: {
@ -41,7 +40,7 @@ describe('upgradeWebSocket middleware', () => {
})
)
expect(sendingData).toBe(await wsPromise)
expect([sendingData, 1]).toStrictEqual(await wsPromise)
})
it('Should call next() when header does not have upgrade', async () => {
const next = vi.fn()

View File

@ -1,51 +1,53 @@
import { WSContext, defineWebSocketHelper } from '../../helper/websocket'
import type { UpgradeWebSocket, WSReadyState } from '../../helper/websocket'
import type { UpgradeWebSocket, WSEvents, WSReadyState } from '../../helper/websocket'
// Based on https://github.com/honojs/hono/issues/1153#issuecomment-1767321332
export const upgradeWebSocket: UpgradeWebSocket<WebSocket> = defineWebSocketHelper(
async (c, events) => {
const upgradeHeader = c.req.header('Upgrade')
if (upgradeHeader !== 'websocket') {
return
}
// @ts-expect-error WebSocketPair is not typed
const webSocketPair = new WebSocketPair()
const client: WebSocket = webSocketPair[0]
const server: WebSocket = webSocketPair[1]
const wsContext = new WSContext<WebSocket>({
close: (code, reason) => server.close(code, reason),
get protocol() {
return server.protocol
},
raw: server,
get readyState() {
return server.readyState as WSReadyState
},
url: server.url ? new URL(server.url) : null,
send: (source) => server.send(source),
})
if (events.onOpen) {
server.addEventListener('open', (evt: Event) => events.onOpen?.(evt, wsContext))
}
if (events.onClose) {
server.addEventListener('close', (evt: CloseEvent) => events.onClose?.(evt, wsContext))
}
if (events.onMessage) {
server.addEventListener('message', (evt: MessageEvent) => events.onMessage?.(evt, wsContext))
}
if (events.onError) {
server.addEventListener('error', (evt: Event) => events.onError?.(evt, wsContext))
}
// @ts-expect-error - server.accept is not typed
server.accept?.()
return new Response(null, {
status: 101,
// @ts-expect-error - webSocket is not typed
webSocket: client,
})
export const upgradeWebSocket: UpgradeWebSocket<
WebSocket,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
any,
Omit<WSEvents<WebSocket>, 'onOpen'>
> = defineWebSocketHelper(async (c, events) => {
const upgradeHeader = c.req.header('Upgrade')
if (upgradeHeader !== 'websocket') {
return
}
)
// @ts-expect-error WebSocketPair is not typed
const webSocketPair = new WebSocketPair()
const client: WebSocket = webSocketPair[0]
const server: WebSocket = webSocketPair[1]
const wsContext = new WSContext<WebSocket>({
close: (code, reason) => server.close(code, reason),
get protocol() {
return server.protocol
},
raw: server,
get readyState() {
return server.readyState as WSReadyState
},
url: server.url ? new URL(server.url) : null,
send: (source) => server.send(source),
})
// note: cloudflare workers doesn't support 'open' event
if (events.onClose) {
server.addEventListener('close', (evt: CloseEvent) => events.onClose?.(evt, wsContext))
}
if (events.onMessage) {
server.addEventListener('message', (evt: MessageEvent) => events.onMessage?.(evt, wsContext))
}
if (events.onError) {
server.addEventListener('error', (evt: Event) => events.onError?.(evt, wsContext))
}
// @ts-expect-error - server.accept is not typed
server.accept?.()
return new Response(null, {
status: 101,
// @ts-expect-error - webSocket is not typed
webSocket: client,
})
})

View File

@ -20,8 +20,8 @@ export interface WSEvents<T = unknown> {
/**
* Upgrade WebSocket Type
*/
export type UpgradeWebSocket<T = unknown, U = any> = (
createEvents: (c: Context) => WSEvents<T> | Promise<WSEvents<T>>,
export type UpgradeWebSocket<T = unknown, U = any, _WSEvents = WSEvents<T>> = (
createEvents: (c: Context) => _WSEvents | Promise<_WSEvents>,
options?: U
) => MiddlewareHandler<
any,