Skip to content

Commit

Permalink
fix(helper/websocket): allow custom events to be passed to generics (#…
Browse files Browse the repository at this point in the history
…3616)

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

* chore: disable any

* add tests

* patch

* test patch
  • Loading branch information
EdamAme-x authored Nov 3, 2024
1 parent ae6165b commit 6b9fb24
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 49 deletions.
7 changes: 3 additions & 4 deletions src/adapter/cloudflare-workers/websocket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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()
Expand Down
88 changes: 45 additions & 43 deletions src/adapter/cloudflare-workers/websocket.ts
Original file line number Diff line number Diff line change
@@ -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
}
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]
// @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),
})
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))
}
// note: cloudflare workers doesn't support 'open' event

// @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,
})
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,
})
})
4 changes: 2 additions & 2 deletions src/helper/websocket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 6b9fb24

Please sign in to comment.