Skip to content

Commit 139e34a

Browse files
authored
fix(node-ws): CloseEvent is not defined (#648)
* feat: add CloseEvent class as it doesn't exist for some versions of Node.js * chore(style): remove semicolon * test: add promise to check if "onClose" doesn't crashes * chore(style): apply eslint rules * ref: use `globalThis.CloseEvent` whenever possible or fallback to custom CloseEvent class * chore: add changeset
1 parent 9467b7e commit 139e34a

4 files changed

Lines changed: 55 additions & 2 deletions

File tree

.changeset/light-goats-teach.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hono/node-ws': patch
3+
---
4+
5+
Add a `CloseEvent` class to avoid exception "CloseEvent is not defined"

packages/node-ws/src/events.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
interface CloseEventInit extends EventInit {
2+
code?: number;
3+
reason?: string;
4+
wasClean?: boolean;
5+
}
6+
7+
/**
8+
* @link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
9+
*/
10+
export const CloseEvent = globalThis.CloseEvent ?? class extends Event {
11+
#eventInitDict
12+
13+
constructor(
14+
type: string,
15+
eventInitDict: CloseEventInit = {}
16+
) {
17+
super(type, eventInitDict)
18+
this.#eventInitDict = eventInitDict
19+
}
20+
21+
get wasClean(): boolean {
22+
return this.#eventInitDict.wasClean ?? false
23+
}
24+
25+
get code(): number {
26+
return this.#eventInitDict.code ?? 0
27+
}
28+
29+
get reason(): string {
30+
return this.#eventInitDict.reason ?? ''
31+
}
32+
}

packages/node-ws/src/index.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('WebSocket helper', () => {
1313

1414
beforeEach(async () => {
1515
app = new Hono()
16+
1617
;({ injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app }))
1718

1819
server = await new Promise<ServerType>((resolve) => {
@@ -108,6 +109,21 @@ describe('WebSocket helper', () => {
108109
connections.forEach((ws) => ws.close())
109110
})
110111

112+
it('CloseEvent should be executed without crash', async () => {
113+
app.get(
114+
'/',
115+
upgradeWebSocket(() => ({
116+
onClose() {
117+
// doing some stuff here
118+
},
119+
}))
120+
)
121+
122+
const ws = new WebSocket('ws://localhost:3030/')
123+
await new Promise<void>((resolve) => ws.on('open', resolve))
124+
ws.close()
125+
})
126+
111127
it('Should be able to send and receive binary content with good length', async () => {
112128
const mainPromise = new Promise<WSMessageReceive>((resolve) =>
113129
app.get(
@@ -126,7 +142,7 @@ describe('WebSocket helper', () => {
126142
await new Promise<void>((resolve) => ws.on('open', resolve))
127143
ws.send(binaryData)
128144

129-
const receivedMessage = await mainPromise;
145+
const receivedMessage = await mainPromise
130146
expect(receivedMessage).toBeInstanceOf(Buffer)
131147
expect((receivedMessage as Buffer).byteLength).toBe(binaryData.length)
132148

packages/node-ws/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { Buffer } from 'buffer'
21
import type { Server } from 'node:http'
32
import type { Http2SecureServer, Http2Server } from 'node:http2'
43
import type { Hono } from 'hono'
54
import type { UpgradeWebSocket, WSContext } from 'hono/ws'
65
import type { WebSocket } from 'ws'
76
import { WebSocketServer } from 'ws'
87
import type { IncomingMessage } from 'http'
8+
import { CloseEvent } from './events'
99

1010
export interface NodeWebSocket {
1111
upgradeWebSocket: UpgradeWebSocket

0 commit comments

Comments
 (0)