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
pull/653/head
Quentin 2024-07-19 00:10:07 +02:00 committed by GitHub
parent 9467b7e54c
commit 139e34a907
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 55 additions and 2 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/node-ws': patch
---
Add a `CloseEvent` class to avoid exception "CloseEvent is not defined"

View File

@ -0,0 +1,32 @@
interface CloseEventInit extends EventInit {
code?: number;
reason?: string;
wasClean?: boolean;
}
/**
* @link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
*/
export const CloseEvent = globalThis.CloseEvent ?? class extends Event {
#eventInitDict
constructor(
type: string,
eventInitDict: CloseEventInit = {}
) {
super(type, eventInitDict)
this.#eventInitDict = eventInitDict
}
get wasClean(): boolean {
return this.#eventInitDict.wasClean ?? false
}
get code(): number {
return this.#eventInitDict.code ?? 0
}
get reason(): string {
return this.#eventInitDict.reason ?? ''
}
}

View File

@ -13,6 +13,7 @@ describe('WebSocket helper', () => {
beforeEach(async () => { beforeEach(async () => {
app = new Hono() app = new Hono()
;({ injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app })) ;({ injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app }))
server = await new Promise<ServerType>((resolve) => { server = await new Promise<ServerType>((resolve) => {
@ -108,6 +109,21 @@ describe('WebSocket helper', () => {
connections.forEach((ws) => ws.close()) connections.forEach((ws) => ws.close())
}) })
it('CloseEvent should be executed without crash', async () => {
app.get(
'/',
upgradeWebSocket(() => ({
onClose() {
// doing some stuff here
},
}))
)
const ws = new WebSocket('ws://localhost:3030/')
await new Promise<void>((resolve) => ws.on('open', resolve))
ws.close()
})
it('Should be able to send and receive binary content with good length', async () => { it('Should be able to send and receive binary content with good length', async () => {
const mainPromise = new Promise<WSMessageReceive>((resolve) => const mainPromise = new Promise<WSMessageReceive>((resolve) =>
app.get( app.get(
@ -126,7 +142,7 @@ describe('WebSocket helper', () => {
await new Promise<void>((resolve) => ws.on('open', resolve)) await new Promise<void>((resolve) => ws.on('open', resolve))
ws.send(binaryData) ws.send(binaryData)
const receivedMessage = await mainPromise; const receivedMessage = await mainPromise
expect(receivedMessage).toBeInstanceOf(Buffer) expect(receivedMessage).toBeInstanceOf(Buffer)
expect((receivedMessage as Buffer).byteLength).toBe(binaryData.length) expect((receivedMessage as Buffer).byteLength).toBe(binaryData.length)

View File

@ -1,4 +1,3 @@
import { Buffer } from 'buffer'
import type { Server } from 'node:http' import type { Server } from 'node:http'
import type { Http2SecureServer, Http2Server } from 'node:http2' import type { Http2SecureServer, Http2Server } from 'node:http2'
import type { Hono } from 'hono' import type { Hono } from 'hono'
@ -6,6 +5,7 @@ import type { UpgradeWebSocket, WSContext } from 'hono/ws'
import type { WebSocket } from 'ws' import type { WebSocket } from 'ws'
import { WebSocketServer } from 'ws' import { WebSocketServer } from 'ws'
import type { IncomingMessage } from 'http' import type { IncomingMessage } from 'http'
import { CloseEvent } from './events'
export interface NodeWebSocket { export interface NodeWebSocket {
upgradeWebSocket: UpgradeWebSocket upgradeWebSocket: UpgradeWebSocket