@znight/websocket 0.0.0-stage → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +226 -2
- package/dist/bun.d.mts +4 -0
- package/dist/bun.mjs +112 -0
- package/dist/bun.mjs.map +1 -0
- package/dist/compiler.d.mts +90 -0
- package/dist/compiler.mjs +864 -0
- package/dist/compiler.mjs.map +1 -0
- package/dist/index.d.mts +501 -0
- package/dist/index.mjs +2088 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server-CI_Bh9o1.d.mts +331 -0
- package/dist/server-D40_bC88.mjs +72 -0
- package/dist/server-D40_bC88.mjs.map +1 -0
- package/dist/testing.d.mts +60 -0
- package/dist/testing.mjs +189 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/transport-xnJqvB93.d.mts +63 -0
- package/dist/ws.d.mts +9 -0
- package/dist/ws.mjs +143 -0
- package/dist/ws.mjs.map +1 -0
- package/package.json +100 -4
- package/src/client.ts +246 -0
- package/src/compiler/analyze.ts +850 -0
- package/src/compiler/constants.ts +102 -0
- package/src/compiler/data.ts +78 -0
- package/src/compiler/generate.ts +262 -0
- package/src/compiler/index.ts +53 -0
- package/src/compiler/validate.ts +81 -0
- package/src/connection.ts +455 -0
- package/src/context.ts +43 -0
- package/src/decorators.ts +83 -0
- package/src/dispatcher.ts +343 -0
- package/src/envelope.ts +136 -0
- package/src/exceptions.ts +91 -0
- package/src/index.ts +89 -0
- package/src/metadata.ts +74 -0
- package/src/options.ts +343 -0
- package/src/plugin.ts +820 -0
- package/src/rate-limit.ts +27 -0
- package/src/rooms.ts +185 -0
- package/src/server.ts +125 -0
- package/src/testing/index.ts +279 -0
- package/src/tokens.ts +23 -0
- package/src/transport.ts +72 -0
- package/src/transports/bun.ts +163 -0
- package/src/transports/memory.ts +174 -0
- package/src/transports/ws.ts +237 -0
- package/src/validate.ts +31 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/client.ts","../src/exceptions.ts","../src/connection.ts","../src/decorators.ts","../src/envelope.ts","../src/dispatcher.ts","../src/options.ts","../src/rate-limit.ts","../src/rooms.ts","../src/tokens.ts","../src/transports/memory.ts","../src/plugin.ts","../src/validate.ts"],"sourcesContent":["/**\n * The client of `WebSocketPlugin.connect()` (RFC 0003 §5.10): an in-memory connection that speaks\n * the `events` protocol (requests, replies, server events) or sends raw frames, with every received\n * frame buffered from the start so that tests never race the server.\n */\nimport type { InjectResponse } from '@znight/http'\nimport type { MemoryClient, MemoryCloseInfo } from './transports/memory.ts'\n\n/** Options of `WebSocketPlugin.connect()`. */\nexport interface WsConnectOptions {\n /** Query parameters appended to the path. */\n readonly query?: Readonly<Record<string, string | readonly string[]>>\n /** Request headers of the handshake. */\n readonly headers?: Readonly<Record<string, string>>\n /** Offered subprotocols (`sec-websocket-protocol`), in preference order. */\n readonly protocols?: readonly string[]\n /** The `origin` header (a browser's). Default: none, like a non-browser client. */\n readonly origin?: string\n /** Cookies of the handshake. */\n readonly cookies?: Readonly<Record<string, string>>\n}\n\n/** Options of the waiting methods of {@link WsClient}. */\nexport interface WsWaitOptions {\n /** Default: 1 000 ms (`request()`: 5 000 ms). */\n readonly timeoutMs?: number\n}\n\n/** A refused handshake: the HTTP response the server answered. */\nexport class WsHandshakeError extends Error {\n readonly status: number\n readonly headers: Readonly<Record<string, string | string[]>>\n readonly body: string\n readonly #response: InjectResponse\n\n constructor(response: InjectResponse) {\n super(`The WebSocket handshake was refused with ${response.status}: ${response.body}`)\n this.name = 'WsHandshakeError'\n this.status = response.status\n this.headers = response.headers\n this.body = response.body\n this.#response = response\n }\n\n /** The body parsed as JSON. */\n json<T = unknown>(): T {\n return this.#response.json<T>()\n }\n}\n\n/** The failure reply of a request (`{ id, error }`). */\nexport class WsRequestError extends Error {\n readonly code: string\n readonly details: unknown\n\n constructor(\n event: string,\n error: { readonly code?: unknown; readonly message?: unknown; readonly details?: unknown },\n ) {\n super(typeof error.message === 'string' ? error.message : `The request \"${event}\" failed`)\n this.name = 'WsRequestError'\n this.code = typeof error.code === 'string' ? error.code : 'INTERNAL'\n this.details = error.details\n }\n}\n\ninterface Entry {\n readonly frame: string | Uint8Array\n /** The decoded envelope, `undefined` for a binary or non-JSON frame. */\n readonly envelope: Readonly<Record<string, unknown>> | undefined\n /** Taken by `next()` or a request. */\n consumed: boolean\n /** Taken by `nextRaw()`. */\n rawConsumed: boolean\n}\n\ninterface Waiter {\n readonly match: (entry: Entry) => boolean\n readonly take: (entry: Entry) => void\n}\n\nfunction decode(frame: string | Uint8Array): Readonly<Record<string, unknown>> | undefined {\n if (typeof frame !== 'string') return undefined\n try {\n const value: unknown = JSON.parse(frame)\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n } catch {\n return undefined\n }\n}\n\n/** An in-memory WebSocket client (`WebSocketPlugin.connect()`, `TestApp.connect()`). */\nexport class WsClient implements AsyncDisposable {\n readonly #peer: MemoryClient\n readonly #entries: Entry[] = []\n readonly #waiters = new Set<Waiter>()\n readonly #closed: PromiseWithResolvers<MemoryCloseInfo> = Promise.withResolvers()\n #nextId = 1\n\n /** @internal Created by `WebSocketPlugin.connect()` once the handshake succeeded. */\n constructor(peer: MemoryClient) {\n this.#peer = peer\n for (const frame of peer.received) this.#receive(frame)\n peer.onmessage = frame => this.#receive(frame)\n const ended = peer.closed\n if (ended === undefined) {\n peer.onclose = info => this.#closed.resolve(info)\n } else {\n this.#closed.resolve(ended)\n }\n }\n\n /** The negotiated subprotocol, `''` when none. */\n get protocol(): string {\n return this.#peer.protocol\n }\n\n /** Every frame received, in order: JSON objects decoded, other text frames as strings, binary frames as bytes. */\n get frames(): readonly unknown[] {\n return this.#entries.map(entry => entry.envelope ?? entry.frame)\n }\n\n /** Resolves once the connection closed (by either side). */\n get closed(): Promise<MemoryCloseInfo> {\n return this.#closed.promise\n }\n\n /** Sends an event without id (fire and forget). */\n send(event: string, data?: unknown): void {\n this.#peer.send(JSON.stringify(data === undefined ? { event } : { event, data }))\n }\n\n /** Sends a request and resolves with the `data` of its reply; rejects with {@link WsRequestError}. */\n request<T = unknown>(event: string, data?: unknown, options: WsWaitOptions = {}): Promise<T> {\n const id = this.#nextId++\n const reply = this.#wait<T>(\n entry => !entry.consumed && entry.envelope?.['id'] === id && entry.envelope['event'] === undefined,\n (entry, resolve, reject) => {\n entry.consumed = true\n const envelope = entry.envelope as Record<string, unknown>\n if (envelope['error'] === undefined) {\n resolve(envelope['data'] as T)\n } else {\n reject(new WsRequestError(event, envelope['error'] as object))\n }\n },\n options.timeoutMs ?? 5_000,\n `the reply to \"${event}\" (id ${id})`,\n )\n this.#peer.send(JSON.stringify(data === undefined ? { event, id } : { event, data, id }))\n return reply\n }\n\n /** The `data` of the oldest server event (matching `event`) not taken yet. */\n next<T = unknown>(event?: string, options: WsWaitOptions = {}): Promise<T> {\n return this.#wait<T>(\n entry =>\n !entry.consumed &&\n typeof entry.envelope?.['event'] === 'string' &&\n (event === undefined || entry.envelope['event'] === event),\n (entry, resolve) => {\n entry.consumed = true\n resolve((entry.envelope as Record<string, unknown>)['data'] as T)\n },\n options.timeoutMs ?? 1_000,\n event === undefined ? 'a server event' : `the event \"${event}\"`,\n )\n }\n\n /** Sends a frame as is (a string is a text frame). */\n sendRaw(frame: string | Uint8Array): void {\n this.#peer.send(frame)\n }\n\n /** The oldest frame not taken by `nextRaw()` yet, as received. */\n nextRaw(options: WsWaitOptions = {}): Promise<string | Uint8Array> {\n return this.#wait<string | Uint8Array>(\n entry => !entry.rawConsumed,\n (entry, resolve) => {\n entry.rawConsumed = true\n resolve(entry.frame)\n },\n options.timeoutMs ?? 1_000,\n 'a frame',\n )\n }\n\n /** Closes the connection and resolves with how it closed. */\n close(code = 1000, reason = ''): Promise<MemoryCloseInfo> {\n this.#peer.close(code, reason)\n return this.#closed.promise\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close()\n }\n\n #wait<T>(\n match: (entry: Entry) => boolean,\n take: (entry: Entry, resolve: (value: T) => void, reject: (error: Error) => void) => void,\n timeoutMs: number,\n what: string,\n ): Promise<T> {\n const { promise, resolve, reject } = Promise.withResolvers<T>()\n const found = this.#entries.find(match)\n if (found !== undefined) {\n take(found, resolve, reject)\n return promise\n }\n if (this.#peer.closed !== undefined) {\n reject(new Error(`The WebSocket connection is closed: no ${what} will arrive`))\n return promise\n }\n const timer = setTimeout(() => {\n this.#waiters.delete(waiter)\n reject(new Error(`Timed out after ${timeoutMs} ms waiting for ${what}`))\n }, timeoutMs)\n const waiter: Waiter = {\n match,\n take: entry => {\n clearTimeout(timer)\n take(entry, resolve, reject)\n },\n }\n this.#waiters.add(waiter)\n void this.#closed.promise.then(() => {\n if (!this.#waiters.delete(waiter)) return\n clearTimeout(timer)\n reject(new Error(`The WebSocket connection closed while waiting for ${what}`))\n })\n return promise\n }\n\n #receive(frame: string | Uint8Array): void {\n const entry: Entry = { frame, envelope: decode(frame), consumed: false, rawConsumed: false }\n this.#entries.push(entry)\n // waiters in arrival order; each re-checks the entry, which an earlier waiter may have taken\n for (const waiter of this.#waiters) {\n if (!waiter.match(entry)) continue\n this.#waiters.delete(waiter)\n waiter.take(entry)\n }\n }\n}\n","/** Exceptions of WebSocket handlers and their wire codes (RFC 0003 §5.3, §5.8). */\n\n/** Built-in error codes of the wire protocol. */\nexport const WsErrorCode = {\n BadFrame: 'BAD_FRAME',\n UnsupportedFrame: 'UNSUPPORTED_FRAME',\n BadRequest: 'BAD_REQUEST',\n Unauthorized: 'UNAUTHORIZED',\n Forbidden: 'FORBIDDEN',\n NotFound: 'NOT_FOUND',\n Conflict: 'CONFLICT',\n Unprocessable: 'UNPROCESSABLE',\n RateLimited: 'RATE_LIMITED',\n UnknownEvent: 'UNKNOWN_EVENT',\n Timeout: 'TIMEOUT',\n Internal: 'INTERNAL',\n} as const\n\n/** Close codes used by the runtime (RFC 0003 §5.8, normative). */\nexport const WsCloseCode = {\n Normal: 1000,\n GoingAway: 1001,\n PolicyViolation: 1008,\n MessageTooBig: 1009,\n InternalError: 1011,\n TryAgainLater: 1013,\n} as const\n\n/** Options of {@link WsException}. */\nexport interface WsExceptionOptions {\n /** Close the connection with this code after replying. */\n readonly close?: number\n readonly cause?: unknown\n}\n\n/**\n * An error a handler or a message guard throws to answer the client: a reply with an `id`, an\n * `$error` event otherwise, then a close when `close` is set.\n *\n * ```ts\n * throw new WsException('FORBIDDEN', 'Join the room first')\n * ```\n */\nexport class WsException extends Error {\n readonly code: string\n readonly details: unknown\n readonly close: number | undefined\n\n constructor(code: string, message?: string, details?: unknown, options: WsExceptionOptions = {}) {\n super(message ?? code, options.cause === undefined ? undefined : { cause: options.cause })\n this.name = 'WsException'\n this.code = code\n this.details = details\n this.close = options.close\n }\n}\n\n/** One issue of a {@link WsValidationException}. */\nexport interface WsValidationIssue {\n readonly path: string\n readonly message: string\n}\n\n/** A payload failed its schema: `BAD_REQUEST` with `details: [{ path, message }]`. */\nexport class WsValidationException extends WsException {\n readonly issues: readonly WsValidationIssue[]\n\n constructor(issues: readonly WsValidationIssue[], message = 'Invalid payload') {\n super(WsErrorCode.BadRequest, message, issues)\n this.name = 'WsValidationException'\n this.issues = issues\n }\n}\n\nconst BY_STATUS: Readonly<Record<number, string>> = {\n 400: WsErrorCode.BadRequest,\n 401: WsErrorCode.Unauthorized,\n 403: WsErrorCode.Forbidden,\n 404: WsErrorCode.NotFound,\n 409: WsErrorCode.Conflict,\n 422: WsErrorCode.Unprocessable,\n 429: WsErrorCode.RateLimited,\n}\n\n/**\n * The wire code of an HTTP status thrown by a service (`HttpException`): the table of RFC 0003\n * §5.8, `INTERNAL` for 5xx and unknown statuses.\n */\nexport function codeOfStatus(status: number): string {\n return BY_STATUS[status] ?? (status >= 400 && status < 500 ? WsErrorCode.BadRequest : WsErrorCode.Internal)\n}\n","/**\n * A WebSocket connection (RFC 0003 §5.4, §8.4, §8.5): the inbound queue with its concurrency and\n * read pausing, the outbound backpressure policy, rooms, and the close sequence. What a message\n * means (decoding, handlers, guards, replies) is given by the plugin through {@link ConnectionDriver}.\n */\nimport type { HttpContext } from '@znight/http'\nimport type { TokenBucket } from './rate-limit.ts'\nimport type { Broadcast, ChannelMember, RoomRegistry } from './rooms.ts'\nimport type { SendStatus, SocketEvents, TransportSocket } from './transport.ts'\n\nimport { WsCloseCode } from './exceptions.ts'\n\n/** Who closed a connection. */\nexport type WsCloseInitiator = 'client' | 'server' | 'shutdown' | 'heartbeat' | 'backpressure' | 'error'\n\n/** How a connection closed. */\nexport interface WsCloseInfo {\n readonly code: number\n readonly reason: string\n readonly initiator: WsCloseInitiator\n}\n\n/** The result of a send: written, buffered by the transport, or dropped. */\nexport type WsSendResult = SendStatus\n\n/** How often a pending `conn.drained()` re-reads the outbound buffer (ms). */\nconst DRAIN_POLL_MS = 10\n\n/** `conn.drained()` rejects with it once the connection is closed. */\nexport class WsClosedError extends Error {\n constructor(message = 'The WebSocket connection is closed') {\n super(message)\n this.name = 'WsClosedError'\n }\n}\n\n/** A WebSocket connection, as handlers and services see it. */\nexport interface WsConnection<\n TData extends object = Record<string, unknown>,\n E extends object = Record<string, unknown>,\n> {\n readonly id: string\n /** Path pattern of the gateway, prefix included (`/api/chat`). */\n readonly gateway: string\n /** The request id of the handshake. */\n readonly requestId: string\n /** The handshake, detached from its socket. */\n readonly handshake: HttpContext\n readonly params: Readonly<Record<string, string>>\n /** The negotiated subprotocol, `''` when none. */\n readonly protocol: string\n /** Per-connection state, an empty object at first. */\n readonly data: TData\n readonly rooms: ReadonlySet<string>\n readonly readyState: 'open' | 'closing' | 'closed'\n readonly bufferedAmount: number\n /** Aborted when the connection starts closing. */\n readonly signal: AbortSignal\n /** How the connection closed: set once the socket closed, before `@OnDisconnect`. */\n readonly closeInfo: WsCloseInfo | undefined\n emit<K extends keyof E & string>(event: K, data: E[K]): WsSendResult\n send(frame: string | Uint8Array): WsSendResult\n join(room: string | readonly string[]): void\n leave(room: string): void\n /** The other members of `room`. */\n to(room: string | readonly string[]): Broadcast<E>\n /** Resolves once the outbound buffer is below `limit / 4`; rejects with {@link WsClosedError} once closed. */\n drained(): Promise<void>\n close(code?: number, reason?: string): void\n terminate(): void\n}\n\n/** Limits of one connection, resolved from the gateway and the plugin options. */\nexport interface ConnectionLimits {\n readonly maxPayload: number\n readonly maxPendingMessages: number\n readonly concurrency: number\n readonly backpressureLimit: number\n readonly onBackpressure: 'close' | 'drop'\n readonly closeTimeoutMs: number\n readonly rateLimit?: { readonly bucket: TokenBucket; readonly onLimit: 'reject' | 'close' }\n}\n\n/** What the plugin does with a connection (the gateway semantics). */\nexport interface ConnectionDriver {\n /** Runs `@OnConnect`; a rejection closes the connection with the code it returns. */\n connect(conn: WsConnectionImpl): Promise<void>\n /** Handles one inbound message (decode, guards, handler, reply). Never rejects. */\n dispatch(conn: WsConnectionImpl, frame: string | Uint8Array, binary: boolean): Promise<void>\n /** A message refused by the rate limit with `onLimit: 'reject'`. */\n rateLimited(conn: WsConnectionImpl, frame: string | Uint8Array, binary: boolean): void\n /** The close code of an `@OnConnect` failure. */\n connectFailure(error: unknown): { readonly code: number; readonly reason: string }\n /** Runs `@OnDisconnect` (errors handled by the driver). */\n disconnect(conn: WsConnectionImpl): Promise<void>\n /** Once fully closed (rooms left): hooks, stats, scope release. */\n closed(conn: WsConnectionImpl, info: WsCloseInfo): void\n}\n\n/** Totals of the plugin (`WebSocketPlugin.stats()`), updated by the connections. */\nexport interface WsStats {\n /** Open connections. */\n readonly connections: number\n readonly opened: number\n readonly closed: number\n readonly messagesIn: number\n readonly messagesOut: number\n readonly bytesIn: number\n readonly bytesOut: number\n /** Outbound frames dropped by a `drop` backpressure policy or refused by the transport. */\n readonly dropped: number\n /** Connections closed with `1013` (slow consumer). */\n readonly slowConsumerCloses: number\n}\n\n/** The mutable counters behind {@link WsStats} (internal). */\nexport class StatsCounter {\n opened = 0\n closed = 0\n messagesIn = 0\n messagesOut = 0\n bytesIn = 0\n bytesOut = 0\n dropped = 0\n slowConsumerCloses = 0\n\n /** A frozen snapshot, with the number of open connections. */\n snapshot(connections: number): WsStats {\n return Object.freeze({\n connections,\n opened: this.opened,\n closed: this.closed,\n messagesIn: this.messagesIn,\n messagesOut: this.messagesOut,\n bytesIn: this.bytesIn,\n bytesOut: this.bytesOut,\n dropped: this.dropped,\n slowConsumerCloses: this.slowConsumerCloses,\n })\n }\n}\n\n/** What a connection is created with. */\nexport interface ConnectionInit {\n readonly id: string\n readonly gateway: string\n readonly handshake: HttpContext\n readonly protocol: string\n readonly limits: ConnectionLimits\n readonly rooms: RoomRegistry<WsConnectionImpl>\n readonly driver: ConnectionDriver\n /** Counters shared by the connections of a plugin. */\n readonly stats?: StatsCounter\n}\n\nfunction sizeOf(frame: string | Uint8Array): number {\n return typeof frame === 'string' ? Buffer.byteLength(frame) : frame.byteLength\n}\n\n/** The implementation of {@link WsConnection} (internal to the package). */\nexport class WsConnectionImpl implements WsConnection, ChannelMember {\n readonly id: string\n readonly gateway: string\n readonly handshake: HttpContext\n readonly protocol: string\n readonly data: Record<string, unknown> = {}\n readonly roomSet: Set<string> = new Set()\n readonly #limits: ConnectionLimits\n readonly #registry: RoomRegistry<WsConnectionImpl>\n readonly #driver: ConnectionDriver\n readonly #stats: StatsCounter | undefined\n readonly #abort = new AbortController()\n readonly #queue: { readonly frame: string | Uint8Array; readonly binary: boolean }[] = []\n readonly #running = new Set<Promise<void>>()\n readonly #drainWaiters: { resolve(): void; reject(error: Error): void }[] = []\n readonly #finished: PromiseWithResolvers<WsCloseInfo> = Promise.withResolvers()\n #socket: TransportSocket | undefined\n /** Polls the buffer while `drained()` waits: a transport may only report a drain at its own limit. */\n #drainPoll: ReturnType<typeof setInterval> | undefined\n #state: 'open' | 'closing' | 'closed' = 'open'\n #connecting = true\n #connected = false\n #paused = false\n #closing: WsCloseInfo | undefined\n #closeInfo: WsCloseInfo | undefined\n #closeTimer: ReturnType<typeof setTimeout> | undefined\n /** Seen alive (a frame or a pong) since the last heartbeat tick. */\n #alive = true\n\n constructor(init: ConnectionInit) {\n this.id = init.id\n this.gateway = init.gateway\n this.handshake = init.handshake\n this.protocol = init.protocol\n this.#limits = init.limits\n this.#registry = init.rooms\n this.#driver = init.driver\n this.#stats = init.stats\n }\n\n get requestId(): string {\n return this.handshake.requestId\n }\n\n get params(): Readonly<Record<string, string>> {\n return this.handshake.params\n }\n\n get rooms(): ReadonlySet<string> {\n return this.roomSet\n }\n\n get readyState(): 'open' | 'closing' | 'closed' {\n return this.#state\n }\n\n get bufferedAmount(): number {\n return this.#socket?.bufferedAmount ?? 0\n }\n\n get signal(): AbortSignal {\n return this.#abort.signal\n }\n\n get closeInfo(): WsCloseInfo | undefined {\n return this.#closeInfo\n }\n\n /** Resolves once the connection is fully closed. */\n get finished(): Promise<WsCloseInfo> {\n return this.#finished.promise\n }\n\n /** The socket events to give to the transport. */\n socketEvents(): SocketEvents {\n return {\n message: (frame, binary) => this.#receive(frame, binary),\n pong: () => {\n this.#alive = true\n },\n drain: () => this.#drain(),\n close: (code, reason) => this.#socketClosed(code, reason),\n }\n }\n\n /** Binds the accepted socket, joins the gateway and runs `@OnConnect` as the first task. */\n start(socket: TransportSocket): void {\n this.#socket = socket\n this.#registry.add(this)\n const task = this.#driver.connect(this).then(\n () => {\n this.#connected = true\n this.#connecting = false\n this.#pump()\n },\n (error: unknown) => {\n this.#connecting = false\n const { code, reason } = this.#driver.connectFailure(error)\n this.#beginClose(code, reason, 'server', true)\n },\n )\n this.#track(task)\n }\n\n emit(event: string, data: unknown): WsSendResult {\n return this.sendFrame(this.#registry.codec.encode({ kind: 'event', event, data }))\n }\n\n send(frame: string | Uint8Array): WsSendResult {\n return this.sendFrame(frame)\n }\n\n /** Sends an encoded frame through the backpressure policy. */\n sendFrame(frame: string | Uint8Array): WsSendResult {\n const socket = this.#socket\n if (this.#state !== 'open' || socket === undefined) return 'dropped'\n const size = sizeOf(frame)\n const stats = this.#stats\n if (socket.bufferedAmount + size > this.#limits.backpressureLimit) {\n if (stats !== undefined) stats.dropped++\n if (this.#limits.onBackpressure === 'drop') return 'dropped'\n if (stats !== undefined) stats.slowConsumerCloses++\n this.#beginClose(WsCloseCode.TryAgainLater, 'Slow consumer', 'backpressure', true)\n return 'dropped'\n }\n const status = socket.send(frame, typeof frame !== 'string')\n if (stats !== undefined) {\n if (status === 'dropped') stats.dropped++\n else {\n stats.messagesOut++\n stats.bytesOut += size\n }\n }\n return status\n }\n\n join(room: string | readonly string[]): void {\n for (const name of typeof room === 'string' ? [room] : room) this.#registry.join(this, name)\n }\n\n leave(room: string): void {\n this.#registry.leave(this, room)\n }\n\n to(room: string | readonly string[]): Broadcast {\n return this.#registry.select(room, [this.id])\n }\n\n drained(): Promise<void> {\n if (this.#state !== 'open') return Promise.reject(new WsClosedError())\n if (this.bufferedAmount <= this.#limits.backpressureLimit / 4) return Promise.resolve()\n const { promise, resolve, reject } = Promise.withResolvers<void>()\n this.#drainWaiters.push({ resolve, reject })\n if (this.#drainPoll === undefined) {\n this.#drainPoll = setInterval(() => this.#drain(), DRAIN_POLL_MS)\n this.#drainPoll.unref?.()\n }\n return promise\n }\n\n close(code: number = WsCloseCode.Normal, reason = ''): void {\n this.#beginClose(code, reason, 'server', true)\n }\n\n /** Closes with an initiator (shutdown, heartbeat...). */\n closeWith(code: number, reason: string, initiator: WsCloseInitiator): void {\n this.#beginClose(code, reason, initiator, true)\n }\n\n terminate(): void {\n this.terminateWith('server')\n }\n\n /** Terminates without close frame (heartbeat timeout, shutdown deadline...): local code `1006`. */\n terminateWith(initiator: WsCloseInitiator): void {\n this.#beginClose(1006, '', initiator, false)\n this.#socket?.terminate()\n }\n\n /**\n * One heartbeat tick (RFC 0003 §8.7): a connection not seen alive since the previous tick is\n * terminated, the others are marked and pinged.\n */\n heartbeat(): void {\n if (this.#state !== 'open' || this.#socket === undefined) return\n if (!this.#alive) {\n this.terminateWith('heartbeat')\n return\n }\n this.#alive = false\n this.#socket.ping()\n }\n\n #receive(frame: string | Uint8Array, binary: boolean): void {\n if (this.#state !== 'open') return\n this.#alive = true\n const size = sizeOf(frame)\n const stats = this.#stats\n if (stats !== undefined) {\n stats.messagesIn++\n stats.bytesIn += size\n }\n if (size > this.#limits.maxPayload) {\n this.#beginClose(WsCloseCode.MessageTooBig, 'Message too big', 'server', true)\n return\n }\n const rate = this.#limits.rateLimit\n if (rate !== undefined && !rate.bucket.take()) {\n if (rate.onLimit === 'close') this.#beginClose(4429, 'Rate limited', 'server', true)\n else this.#driver.rateLimited(this, frame, binary)\n return\n }\n this.#queue.push({ frame, binary })\n const max = this.#limits.maxPendingMessages\n if (this.#queue.length >= max && !this.#paused) {\n this.#paused = this.#socket?.pause() ?? false\n if (!this.#paused && this.#queue.length >= max * 2) {\n this.#beginClose(WsCloseCode.PolicyViolation, 'Too many pending messages', 'server', true)\n return\n }\n }\n this.#pump()\n }\n\n #pump(): void {\n while (\n this.#state === 'open' &&\n !this.#connecting &&\n this.#running.size < this.#limits.concurrency &&\n this.#queue.length > 0\n ) {\n const next = this.#queue.shift() as { readonly frame: string | Uint8Array; readonly binary: boolean }\n this.#track(this.#driver.dispatch(this, next.frame, next.binary))\n }\n if (this.#paused && this.#queue.length <= this.#limits.maxPendingMessages / 2) {\n this.#paused = false\n this.#socket?.resume()\n }\n }\n\n /** Counts a running task until it settles, then dispatches the next messages. */\n #track(task: Promise<void>): void {\n const tracked: Promise<void> = task\n .catch(() => undefined)\n .then(() => {\n this.#running.delete(tracked)\n this.#pump()\n })\n this.#running.add(tracked)\n }\n\n #drain(): void {\n if (this.bufferedAmount > this.#limits.backpressureLimit / 4) return\n this.#stopDrainPoll()\n for (const waiter of this.#drainWaiters.splice(0)) waiter.resolve()\n }\n\n #stopDrainPoll(): void {\n if (this.#drainPoll !== undefined) clearInterval(this.#drainPoll)\n this.#drainPoll = undefined\n }\n\n #beginClose(code: number, reason: string, initiator: WsCloseInitiator, frame: boolean): void {\n if (this.#state !== 'open') return\n this.#state = 'closing'\n this.#closing = { code, reason, initiator }\n this.#abort.abort(new WsClosedError())\n this.#queue.length = 0\n if (!frame) return\n this.#socket?.close(code, reason)\n this.#closeTimer = setTimeout(() => this.#socket?.terminate(), this.#limits.closeTimeoutMs)\n this.#closeTimer.unref?.()\n }\n\n #socketClosed(code: number, reason: string): void {\n if (this.#state === 'closed') return\n if (this.#state === 'open') this.#beginClose(code, reason, 'client', false)\n if (this.#closeTimer !== undefined) clearTimeout(this.#closeTimer)\n void this.#finish()\n }\n\n async #finish(): Promise<void> {\n // known from now on: @OnDisconnect reads it\n const info = this.#closing ?? { code: 1006, reason: '', initiator: 'error' as const }\n this.#closeInfo = info\n while (this.#running.size > 0) await Promise.all([...this.#running])\n if (this.#connected) await this.#driver.disconnect(this).catch(() => undefined)\n this.#registry.remove(this)\n this.#state = 'closed'\n this.#stopDrainPoll()\n for (const waiter of this.#drainWaiters.splice(0)) waiter.reject(new WsClosedError())\n this.#driver.closed(this, info)\n this.#finished.resolve(info)\n }\n}\n","/**\n * Marker decorators of `@znight/websocket` (RFC 0003 §5.2). Like every Znight decorator they do\n * nothing at runtime: the compiler extension reads them from the source code, validates them and\n * generates `metadata.extensions.websocket`. Every argument is _static_ (literals, `const`\n * references, simple expressions), except the schemas and guards, which are values.\n */\nimport type { GatewayOptions } from './options.ts'\n\n/** A class decorator marker. */\nexport type GatewayClassMarker = (target: abstract new (...args: never[]) => unknown) => void\n\n/** A method decorator marker. */\nexport type GatewayMethodMarker = (\n target: object,\n propertyKey: string | symbol,\n descriptor?: PropertyDescriptor,\n) => void\n\n/** A parameter decorator marker. */\nexport type GatewayParameterMarker = (target: object, propertyKey: string | symbol | undefined, index: number) => void\n\n/** A class or method decorator marker. */\nexport type GatewayClassOrMethodMarker = (target: object, propertyKey?: string | symbol, descriptor?: unknown) => void\n\nfunction marker(): void {\n // intentionally empty: decorators are compile-time markers\n}\n\n/**\n * A provider whose methods handle the WebSocket connections of `path` (default `/`), joined to the\n * `HttpPlugin` prefix.\n *\n * ```ts\n * @Gateway({ path: '/chat', protocols: ['chat.v1'] })\n * export class ChatGateway {}\n * ```\n */\nexport function Gateway(_pathOrOptions?: string | GatewayOptions): GatewayClassMarker {\n return marker\n}\n\n/** Runs once the handshake succeeded, before any message. Throwing closes the connection. */\nexport function OnConnect(): GatewayMethodMarker {\n return marker\n}\n\n/**\n * Handles an event (`events` protocol). Without `event`: the default handler (unknown events, every\n * message of a `raw` gateway). Repeatable.\n */\nexport function OnMessage(_event?: string): GatewayMethodMarker {\n return marker\n}\n\n/** Runs once per connection whose `@OnConnect` completed, before rooms are left and the scope closes. */\nexport function OnDisconnect(): GatewayMethodMarker {\n return marker\n}\n\n/** The message `data` (`events`) or the raw frame (`raw`), validated by `schema` (a Standard Schema). */\nexport function Payload(_schema?: unknown): GatewayParameterMarker {\n return marker\n}\n\n/** The `WsConnection` of the message or of the lifecycle method. */\nexport function Conn(): GatewayParameterMarker {\n return marker\n}\n\n/** The `WsMessageContext` (`@OnMessage` handlers only). */\nexport function Ctx(): GatewayParameterMarker {\n return marker\n}\n\n/** Extra HTTP guards (`CanActivate`) of the handshake, after the `HttpPlugin` global guards. */\nexport function UseHandshakeGuard(..._guards: readonly unknown[]): GatewayClassMarker {\n return marker\n}\n\n/** Message guards (`WsGuard`) run before each handler: global, then class, then method. */\nexport function UseMessageGuard(..._guards: readonly unknown[]): GatewayClassOrMethodMarker {\n return marker\n}\n","/** The envelope of `events` gateways (RFC 0003 §5.3): decoding inbound frames, encoding outbound ones. */\nimport { WsErrorCode } from './exceptions.ts'\n\n/** Event names: `^[A-Za-z][\\w.:/-]{0,127}$`; names starting with `$` are reserved. */\nexport const EVENT_NAME: RegExp = /^[A-Za-z][\\w.:/-]{0,127}$/\n\n/** A message id: a string of at most 64 characters or a safe integer, chosen by the client. */\nexport type MessageId = string | number\n\n/** A decoded inbound message. */\nexport interface InboundMessage {\n readonly event: string\n readonly data: unknown\n /** Present when the client expects exactly one reply. */\n readonly id: MessageId | undefined\n}\n\n/** A frame that could not be decoded: answered with `$error` (or a reply when the id was readable). */\nexport interface InboundFailure {\n readonly error: string\n readonly message: string\n readonly id: MessageId | undefined\n}\n\n/** The wire error of a reply or of an `$error` event. */\nexport interface WireError {\n readonly code: string\n readonly message: string\n readonly details?: unknown\n}\n\n/** Whether `value` is a valid message id. */\nexport function isMessageId(value: unknown): value is MessageId {\n return (typeof value === 'string' && value.length <= 64) || Number.isSafeInteger(value)\n}\n\n/**\n * Decodes an inbound frame of an `events` gateway with the JSON codec: a binary frame is\n * `UNSUPPORTED_FRAME`, anything but a JSON object with a string `event` is `BAD_FRAME`. Unknown\n * fields are ignored.\n */\nexport function decodeFrame(frame: string | Uint8Array): InboundMessage | InboundFailure {\n if (typeof frame !== 'string') {\n return { error: WsErrorCode.UnsupportedFrame, message: 'Binary frames are not supported', id: undefined }\n }\n let value: unknown\n try {\n value = JSON.parse(frame)\n } catch {\n return { error: WsErrorCode.BadFrame, message: 'The frame is not valid JSON', id: undefined }\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return { error: WsErrorCode.BadFrame, message: 'The frame must be a JSON object', id: undefined }\n }\n const record = value as Record<string, unknown>\n const rawId = record['id']\n const id = isMessageId(rawId) ? rawId : undefined\n if (rawId !== undefined && id === undefined) {\n return { error: WsErrorCode.BadFrame, message: 'Invalid message id', id: undefined }\n }\n const event = record['event']\n if (typeof event !== 'string') return { error: WsErrorCode.BadFrame, message: 'Missing event name', id }\n return { event, data: record['data'], id }\n}\n\n/** Whether a decoded frame is a failure. */\nexport function isFailure(decoded: InboundMessage | InboundFailure): decoded is InboundFailure {\n return 'error' in decoded\n}\n\n/** A success reply: `{ id, data }`, `data` omitted when `undefined`. */\nexport function encodeReply(id: MessageId, data: unknown): string {\n return data === undefined ? JSON.stringify({ id }) : JSON.stringify({ id, data })\n}\n\n/** A failure reply: `{ id, error }`. */\nexport function encodeErrorReply(id: MessageId, error: WireError): string {\n return JSON.stringify({ id, error: wireError(error) })\n}\n\n/** A server event: `{ event, data }`. */\nexport function encodeEvent(event: string, data: unknown): string {\n return data === undefined ? JSON.stringify({ event }) : JSON.stringify({ event, data })\n}\n\n/** The failure of a message without id: `{ event: '$error', data: { event, code, message, details? } }`. */\nexport function encodeErrorEvent(event: string | undefined, error: WireError): string {\n return JSON.stringify({ event: '$error', data: { ...(event === undefined ? {} : { event }), ...wireError(error) } })\n}\n\nfunction wireError(error: WireError): WireError {\n return error.details === undefined\n ? { code: error.code, message: error.message }\n : { code: error.code, message: error.message, details: error.details }\n}\n\n/** An outbound frame of an `events` gateway, before encoding. */\nexport type OutboundMessage =\n | { readonly kind: 'event'; readonly event: string; readonly data: unknown }\n | { readonly kind: 'reply'; readonly id: MessageId; readonly data: unknown }\n /** A failure: a reply when `id` is set, an `$error` event otherwise (`event`: the failed message's). */\n | {\n readonly kind: 'error'\n readonly id: MessageId | undefined\n readonly event: string | undefined\n readonly error: WireError\n }\n\n/**\n * The codec of `events` gateways (`WebSocketPlugin` option `codec`): how frames are decoded into\n * `{ event, data, id }` and how outbound messages are encoded. The default is {@link jsonCodec};\n * a custom codec may carry MessagePack over binary frames, for instance.\n */\nexport interface WsCodec {\n /** Decodes an inbound frame; a failure is answered with its code (`BAD_FRAME`...). */\n decode(frame: string | Uint8Array, binary: boolean): InboundMessage | InboundFailure\n /** Encodes an outbound message: a string is a text frame, bytes a binary frame. */\n encode(message: OutboundMessage): string | Uint8Array\n}\n\n/** The default codec: UTF-8 JSON text frames (RFC 0003 §5.3); binary frames are `UNSUPPORTED_FRAME`. */\nexport const jsonCodec: WsCodec = Object.freeze({\n decode: (frame: string | Uint8Array): InboundMessage | InboundFailure => decodeFrame(frame),\n encode(message: OutboundMessage): string {\n switch (message.kind) {\n case 'event':\n return encodeEvent(message.event, message.data)\n case 'reply':\n return encodeReply(message.id, message.data)\n case 'error':\n return message.id === undefined\n ? encodeErrorEvent(message.event, message.error)\n : encodeErrorReply(message.id, message.error)\n }\n },\n})\n","/**\n * The gateway semantics of a connection (RFC 0003 §8.4 step 3, §5.8): decoding, `$ping`, handler\n * selection, message guards, `invoke` bounded by the handler timeout, replies and error mapping.\n * The plugin builds one {@link GatewayDispatcher} per gateway and gives it to its connections.\n */\nimport type { Hooks, WebSocketMessageEvent, WebSocketMessageOutcome } from '@znight/core'\nimport type { ConnectionDriver, WsCloseInfo, WsConnectionImpl } from './connection.ts'\nimport type { WsExceptionMapper, WsGuard, WsMessageContext } from './context.ts'\nimport type { MessageId, WireError, WsCodec } from './envelope.ts'\nimport type { GatewayDefinition, WsHandlerDefinition } from './metadata.ts'\n\nimport { HttpException } from '@znight/http'\n\nimport { isFailure, jsonCodec } from './envelope.ts'\nimport { codeOfStatus, WsCloseCode, WsErrorCode, WsException, WsValidationException } from './exceptions.ts'\n\n/** A handler with its resolved guards and effective metadata. */\nexport interface HandlerPlan {\n readonly definition: WsHandlerDefinition\n /** Plugin, gateway, then method guards. */\n readonly guards: readonly WsGuard[]\n /** Gateway meta merged with the method's (nearest wins). */\n readonly meta: Readonly<Record<string, unknown>>\n}\n\n/** What a dispatcher needs from the plugin. */\nexport interface DispatcherOptions {\n readonly definition: GatewayDefinition\n /** Gateway path, prefix included. */\n readonly path: string\n readonly handlers: readonly HandlerPlan[]\n /** The gateway instance of a connection (singleton, or the request-scoped one of its handshake). */\n readonly instance: (conn: WsConnectionImpl) => object | Promise<object>\n readonly handlerTimeoutMs: number\n readonly exposeErrors: boolean\n /** Logs an unexpected error (handler, guard, lifecycle). */\n readonly logError: (message: string, error: unknown, conn: WsConnectionImpl) => void\n /** Once a connection is fully closed. */\n readonly closed: (conn: WsConnectionImpl, info: WsCloseInfo) => void\n /** The `websocket:message` hook: run when it has wrappers, emitted when it has listeners. */\n readonly hooks?: Hooks\n /** Display name of the gateway (hook events). */\n readonly name?: string\n /** Plugin `exceptionMappers`, in order. */\n readonly mappers?: readonly WsExceptionMapper[]\n /** The codec of `events` gateways. Default: {@link jsonCodec}. */\n readonly codec?: WsCodec\n /**\n * Development aid: called once per handler whose result was ignored (a message without `id`\n * answered by a value). Omitted in production.\n */\n readonly ignoredResult?: (handler: string, event: string | undefined) => void\n}\n\nconst MESSAGE_HOOK = 'websocket:message'\n\n/** How a message ended (the `websocket:message` outcome and error). */\ninterface Settled {\n readonly outcome: WebSocketMessageOutcome\n readonly error?: unknown\n}\n\nconst OK: Settled = Object.freeze({ outcome: 'ok' })\n\nclass TimeoutError extends Error {}\n\n/** Converts what a handler or a guard threw to a wire error. */\nexport function toWireError(error: unknown, exposeErrors: boolean): WireError {\n if (error instanceof WsException) {\n return {\n code: error.code,\n message: error.message,\n ...(error.details === undefined ? {} : { details: error.details }),\n }\n }\n if (error instanceof HttpException) {\n const code = codeOfStatus(error.status)\n const message = code === WsErrorCode.Internal && !exposeErrors ? 'Internal error' : error.message\n return { code, message, ...(error.details === undefined ? {} : { details: error.details }) }\n }\n if (error instanceof TimeoutError) return { code: WsErrorCode.Timeout, message: 'The handler timed out' }\n const message = exposeErrors && error instanceof Error ? error.message : 'Internal error'\n return { code: WsErrorCode.Internal, message }\n}\n\nfunction isForbidden(error: unknown): boolean {\n if (error instanceof WsException)\n return error.code === WsErrorCode.Forbidden || error.code === WsErrorCode.Unauthorized\n return error instanceof HttpException && (error.status === 401 || error.status === 403)\n}\n\nfunction isExpected(error: unknown): boolean {\n if (error instanceof WsException || error instanceof TimeoutError) return true\n return error instanceof HttpException && error.status < 500\n}\n\n/** The close code of an `@OnConnect` failure (§5.8). */\nexport function connectFailureCode(error: unknown): { readonly code: number; readonly reason: string } {\n if (error instanceof WsValidationException) return { code: 4400, reason: error.message }\n if (error instanceof WsException) return { code: error.close ?? WsCloseCode.PolicyViolation, reason: error.message }\n if (error instanceof HttpException) return { code: 4000 + error.status, reason: error.message }\n return { code: WsCloseCode.InternalError, reason: 'Internal error' }\n}\n\n/** One gateway's message pipeline, shared by its connections. */\nexport class GatewayDispatcher implements ConnectionDriver {\n readonly #options: DispatcherOptions\n readonly #byEvent = new Map<string, HandlerPlan>()\n readonly #fallback: HandlerPlan | undefined\n readonly #codec: WsCodec\n readonly #ignored = new Set<string>()\n\n constructor(options: DispatcherOptions) {\n this.#options = options\n this.#codec = options.codec ?? jsonCodec\n let fallback: HandlerPlan | undefined\n for (const plan of options.handlers) {\n if (plan.definition.event === undefined) fallback = plan\n else this.#byEvent.set(plan.definition.event, plan)\n }\n this.#fallback = fallback\n }\n\n get raw(): boolean {\n return this.#options.definition.protocol === 'raw'\n }\n\n async connect(conn: WsConnectionImpl): Promise<void> {\n const lifecycle = this.#options.definition.onConnect\n if (lifecycle === undefined) return\n const gateway = await this.#options.instance(conn)\n await this.#bounded(Promise.resolve(lifecycle.invoke(gateway, conn)), undefined)\n }\n\n connectFailure(error: unknown): { readonly code: number; readonly reason: string } {\n return connectFailureCode(error)\n }\n\n async disconnect(conn: WsConnectionImpl): Promise<void> {\n const lifecycle = this.#options.definition.onDisconnect\n if (lifecycle === undefined) return\n try {\n await lifecycle.invoke(await this.#options.instance(conn), conn)\n } catch (error) {\n this.#options.logError(`@OnDisconnect ${lifecycle.method} failed`, error, conn)\n }\n }\n\n closed(conn: WsConnectionImpl, info: WsCloseInfo): void {\n this.#options.closed(conn, info)\n }\n\n rateLimited(conn: WsConnectionImpl, frame: string | Uint8Array, binary: boolean): void {\n if (this.raw) return\n const decoded = this.#codec.decode(frame, binary)\n const id = decoded.id\n const event = isFailure(decoded) ? undefined : decoded.event\n this.#fail(conn, id, event, { code: WsErrorCode.RateLimited, message: 'Too many messages' })\n }\n\n async dispatch(conn: WsConnectionImpl, frame: string | Uint8Array, binary: boolean): Promise<void> {\n const receivedAt = performance.now()\n let event: string | undefined\n let id: MessageId | undefined\n let data: unknown = frame\n let failure: WireError | undefined\n if (!this.raw) {\n const decoded = this.#codec.decode(frame, binary)\n if (isFailure(decoded)) {\n id = decoded.id\n failure = { code: decoded.error, message: decoded.message }\n } else {\n ;({ event, id, data } = decoded)\n if (event === '$ping') {\n if (id !== undefined) conn.sendFrame(this.#codec.encode({ kind: 'reply', id, data: { t: Date.now() } }))\n return\n }\n }\n }\n const plan =\n failure === undefined\n ? ((event === undefined ? undefined : this.#byEvent.get(event)) ?? this.#fallback)\n : undefined\n const abort = new AbortController()\n const onClose = () => abort.abort(conn.signal.reason)\n conn.signal.addEventListener('abort', onClose, { once: true })\n const ctx: WsMessageContext = {\n connection: conn,\n event,\n id,\n data,\n binary,\n bytes: typeof frame === 'string' ? frame.length : frame.byteLength,\n receivedAt,\n signal: abort.signal,\n state: new Map(),\n route: {\n path: this.#options.path,\n gateway: this.#options.definition.token,\n handler: plan?.definition.method,\n event,\n meta: plan?.meta ?? this.#options.definition.meta,\n },\n }\n try {\n const hooks = this.#options.hooks\n if (hooks === undefined || (!hooks.hasWrappers(MESSAGE_HOOK) && !hooks.hasListeners(MESSAGE_HOOK))) {\n await this.#handle(plan, conn, ctx, failure, abort)\n return\n }\n const hookEvent: WebSocketMessageEvent = {\n gateway: this.#options.name ?? String(this.#options.definition.token),\n path: this.#options.path,\n event,\n handler: plan?.definition.method,\n connectionId: conn.id,\n requestId: conn.requestId,\n bytes: ctx.bytes,\n context: ctx,\n startTime: receivedAt,\n }\n try {\n await hooks.run(MESSAGE_HOOK, hookEvent, async () => {\n const settled = await this.#handle(plan, conn, ctx, failure, abort)\n hookEvent.outcome = settled.outcome\n if (settled.error !== undefined) hookEvent.error = settled.error\n })\n } catch (error) {\n this.#options.logError('A \"websocket:message\" hook wrapper failed', error, conn)\n }\n if (hooks.hasListeners(MESSAGE_HOOK)) hooks.emit(MESSAGE_HOOK, hookEvent)\n } finally {\n conn.signal.removeEventListener('abort', onClose)\n }\n }\n\n /** Guards, handler, reply and error mapping of one message. Never rejects. */\n async #handle(\n plan: HandlerPlan | undefined,\n conn: WsConnectionImpl,\n ctx: WsMessageContext,\n failure: WireError | undefined,\n abort: AbortController,\n ): Promise<Settled> {\n if (failure !== undefined) {\n this.#fail(conn, ctx.id, undefined, failure)\n return { outcome: 'error', error: new WsException(failure.code, failure.message) }\n }\n if (plan === undefined) {\n this.#fail(conn, ctx.id, ctx.event, {\n code: WsErrorCode.UnknownEvent,\n message: `Unknown event \"${ctx.event}\"`,\n })\n return { outcome: 'unhandled' }\n }\n let rejected = false\n try {\n const result = await this.#bounded(\n this.#run(plan, conn, ctx, () => {\n rejected = true\n }),\n abort,\n )\n if (ctx.id !== undefined && conn.readyState === 'open') {\n conn.sendFrame(this.#codec.encode({ kind: 'reply', id: ctx.id, data: result }))\n } else if (ctx.id === undefined && result !== undefined && !this.raw) {\n this.#ignoredResult(plan.definition.method, ctx.event)\n }\n return OK\n } catch (thrown) {\n const error = await this.#map(thrown, ctx, conn)\n if (!isExpected(error)) this.#options.logError(`Handler ${plan.definition.method} failed`, error, conn)\n if (!this.raw) this.#fail(conn, ctx.id, ctx.event, toWireError(error, this.#options.exposeErrors))\n if (error instanceof WsException && error.close !== undefined) conn.close(error.close, error.message)\n let outcome: WebSocketMessageOutcome = 'error'\n if (thrown instanceof TimeoutError) outcome = 'timeout'\n else if (rejected && isForbidden(error)) outcome = 'rejected'\n return { outcome, error: thrown }\n }\n }\n\n #ignoredResult(method: string, event: string | undefined): void {\n const report = this.#options.ignoredResult\n if (report === undefined || this.#ignored.has(method)) return\n this.#ignored.add(method)\n report(method, event)\n }\n\n /** Runs the plugin exception mappers, in order: the first `WsException` wins. */\n async #map(error: unknown, ctx: WsMessageContext, conn: WsConnectionImpl): Promise<unknown> {\n const mappers = this.#options.mappers\n if (mappers === undefined || mappers.length === 0 || error instanceof TimeoutError) return error\n for (const mapper of mappers) {\n try {\n const mapped = await mapper.map(error, ctx)\n if (mapped !== undefined) return mapped\n } catch (failure) {\n this.#options.logError('A WebSocket exception mapper failed', failure, conn)\n return failure\n }\n }\n return error\n }\n\n async #run(plan: HandlerPlan, conn: WsConnectionImpl, ctx: WsMessageContext, refused: () => void): Promise<unknown> {\n for (const guard of plan.guards) {\n let allowed: boolean\n try {\n allowed = (await guard.canHandle(ctx)) === true\n } catch (error) {\n refused()\n throw error\n }\n if (!allowed) {\n refused()\n throw new WsException(WsErrorCode.Forbidden, 'Forbidden')\n }\n }\n const gateway = await this.#options.instance(conn)\n return await plan.definition.invoke(gateway, ctx)\n }\n\n /** Races a task with the handler timeout; aborts `abort` on timeout. */\n #bounded<T>(task: Promise<T>, abort: AbortController | undefined): Promise<T> {\n const ms = this.#options.handlerTimeoutMs\n if (!Number.isFinite(ms)) return task\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n const error = new TimeoutError('The handler timed out')\n abort?.abort(error)\n reject(error)\n }, ms)\n })\n task.catch(() => undefined)\n return Promise.race([task, timeout]).finally(() => clearTimeout(timer))\n }\n\n #fail(conn: WsConnectionImpl, id: MessageId | undefined, event: string | undefined, error: WireError): void {\n if (this.raw || conn.readyState !== 'open') return\n conn.sendFrame(this.#codec.encode({ kind: 'error', id, event, error }))\n }\n}\n","/** Options of `@Gateway` and of `WebSocketPlugin` (RFC 0003 §5.2, §5.9). */\nimport type { ByteSize, HttpContext } from '@znight/http'\nimport type { WsExceptionMapper, WsGuard } from './context.ts'\nimport type { WsCodec } from './envelope.ts'\nimport type { WebSocketTransport } from './transport.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\nimport { parseByteSize } from '@znight/http'\n\nimport { jsonCodec } from './envelope.ts'\n\n/** Options of `@Gateway` (RFC 0003 §5.2), all static: the compiler reads them. */\nexport interface GatewayOptions {\n /** HTTP path grammar (`/chat`, `/docs/:docId`, `/feeds/*`). Default: `'/'`. */\n readonly path?: string\n /** `'request'`: one gateway instance per connection. Default: `'singleton'`. */\n readonly scope?: 'singleton' | 'request'\n /** `'events'` (envelope, routing by event) or `'raw'` (one default handler). Default: `'events'`. */\n readonly protocol?: 'events' | 'raw'\n /** Accepted subprotocols, in preference order: a client offering none of them is refused (400). */\n readonly protocols?: readonly string[]\n /** Largest inbound message (`'64kb'` or bytes). Default: the plugin `maxPayload`. */\n readonly maxPayload?: string | number\n /** Messages of one connection handled in parallel. Default: `1` (keeps the order). */\n readonly concurrency?: number\n /** A token bucket per connection. */\n readonly rateLimit?: RateLimitOptions\n /** Outbound buffer limit and what to do above it. Default: the plugin `backpressure`. */\n readonly backpressure?: BackpressureOptions\n}\n\n/** `@Gateway({ rateLimit })`. */\nexport interface RateLimitOptions {\n readonly messages: number\n readonly intervalMs: number\n /** `'reject'` answers `RATE_LIMITED` (default), `'close'` closes with `4429`. */\n readonly onLimit?: 'reject' | 'close'\n}\n\n/** `@Gateway({ backpressure })` and the plugin option. */\nexport interface BackpressureOptions {\n /** Buffered outbound bytes above which `onLimit` applies (`'1mb'` or bytes). */\n readonly limit?: string | number\n /** `'close'` closes with `1013` (default), `'drop'` drops the message. */\n readonly onLimit?: 'close' | 'drop'\n}\n\n// -------------------------------------------------------------------------------------------------\n// WebSocketPlugin options (RFC 0003 §5.9)\n// -------------------------------------------------------------------------------------------------\n\n/** `'same-origin'`, `'*'`, exact origins and anchored `RegExp`s, or a function (RFC 0003 §5.6). */\nexport type WsOrigins =\n | 'same-origin'\n | '*'\n | string\n | RegExp\n | readonly (string | RegExp)[]\n | ((origin: string, ctx: HttpContext) => boolean | Promise<boolean>)\n\n/** A message guard or an exception mapper: a provider class or an instance. */\nexport type WsProviderRef<T> = (abstract new (...args: never[]) => T) | T\n\n/** Options of `WebSocketPlugin.configure()`. */\nexport interface WebSocketPluginOptions {\n /** `'auto'` (default): Bun's native transport with `honoAdapter()` on Bun, `ws` otherwise. */\n readonly transport?: 'auto' | WebSocketTransport\n /** Allowed `Origin`s of handshakes. Default: `'same-origin'` (and requests without `Origin`). */\n readonly origins?: WsOrigins\n /** Largest inbound message (`'1mb'` or bytes). Default: `'1mb'`. Gateways may lower it. */\n readonly maxPayload?: ByteSize\n /** Open connections per process; above, handshakes get `503`. Default: `Infinity`. */\n readonly maxConnections?: number\n /** Inbound queue per connection before reading pauses. Default: `32`. */\n readonly maxPendingMessages?: number\n /** Outbound buffer per connection. Default: `{ limit: '1mb', onLimit: 'close' }`. */\n readonly backpressure?: BackpressureOptions\n /** Ping interval; `false` disables heartbeats. Default: `{ intervalMs: 30_000 }`. */\n readonly heartbeat?: { readonly intervalMs: number } | false\n /** Handshakes whose guards have not answered by then get `408`. Default: `10_000`. */\n readonly handshakeTimeoutMs?: number\n /** Per message and per `@OnConnect`: `TIMEOUT`. `Infinity` disables. Default: `30_000`. */\n readonly handlerTimeoutMs?: number\n /** Wait for the client's close frame before terminating. Default: `2_000`. */\n readonly closeTimeoutMs?: number\n /** The codec of `events` gateways. Default: `jsonCodec` (JSON text frames). */\n readonly codec?: WsCodec\n /** Global message guards, run before the gateway's and the handler's. */\n readonly messageGuards?: readonly WsProviderRef<WsGuard>[]\n /** Exception mappers of message handlers and guards, in order. */\n readonly exceptionMappers?: readonly WsProviderRef<WsExceptionMapper>[]\n /** Send the message of unexpected errors (`INTERNAL`). Default: `false`. */\n readonly exposeErrors?: boolean\n /** Graceful shutdown. Default: `{ code: 1001, reason: 'Server shutting down', timeoutMs: 3_000 }`. */\n readonly shutdown?: { readonly code?: number; readonly reason?: string; readonly timeoutMs?: number }\n}\n\n/** Validated plugin options (internal). */\nexport interface ResolvedWebSocketOptions {\n readonly transport: 'auto' | WebSocketTransport\n readonly origins: OriginPolicy\n readonly maxPayload: number\n readonly maxConnections: number\n readonly maxPendingMessages: number\n readonly backpressure: { readonly limit: number; readonly onLimit: 'close' | 'drop' }\n readonly heartbeatMs: number\n readonly handshakeTimeoutMs: number\n readonly handlerTimeoutMs: number\n readonly closeTimeoutMs: number\n readonly codec: WsCodec\n readonly messageGuards: readonly unknown[]\n readonly exceptionMappers: readonly unknown[]\n readonly exposeErrors: boolean\n readonly shutdown: { readonly code: number; readonly reason: string; readonly timeoutMs: number }\n}\n\n/** How origins are checked (internal). */\nexport interface OriginPolicy {\n /** `'same-origin'`: the request's own origin only. */\n readonly sameOrigin: boolean\n allows(origin: string, ctx: HttpContext): boolean | Promise<boolean>\n}\n\nconst OPTION_KEYS: ReadonlySet<string> = new Set([\n 'transport',\n 'origins',\n 'maxPayload',\n 'maxConnections',\n 'maxPendingMessages',\n 'backpressure',\n 'heartbeat',\n 'handshakeTimeoutMs',\n 'handlerTimeoutMs',\n 'closeTimeoutMs',\n 'codec',\n 'messageGuards',\n 'exceptionMappers',\n 'exposeErrors',\n 'shutdown',\n])\n\n/** `ZNIGHT050: WebSocketPlugin: option \"<name>\" must be <expected> (received <value>)`. */\nexport function invalidOption(name: string, expected: string, value: unknown, hints?: readonly string[]): ZnightError {\n return new ZnightError(\n ErrorCode.InvalidGateway,\n `WebSocketPlugin: option \"${name}\" must be ${expected} (received ${describe(value)})`,\n hints === undefined ? {} : { hints },\n )\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'function') return 'a function'\n if (value instanceof RegExp) return String(value)\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return typeof value\n }\n}\n\nfunction positiveInteger(name: string, value: unknown, fallback: number, infinite = false): number {\n if (value === undefined) return fallback\n if (infinite && value === Number.POSITIVE_INFINITY) return value\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {\n throw invalidOption(name, `a positive integer${infinite ? ' or Infinity' : ''}`, value)\n }\n return value\n}\n\nfunction byteSize(name: string, value: unknown, fallback: number): number {\n if (value === undefined) return fallback\n const bytes = parseByteSize(value)\n if (bytes === undefined || bytes === 0 || bytes === Number.POSITIVE_INFINITY) {\n throw invalidOption(name, \"a positive byte size ('64kb', 65536)\", value)\n }\n return bytes\n}\n\n/** Validates the options of `WebSocketPlugin.configure()` (ZNIGHT050). */\nexport function resolveWebSocketOptions(options: unknown): ResolvedWebSocketOptions {\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n throw invalidOption('options', 'an object', options)\n }\n for (const key of Object.keys(options)) {\n if (!OPTION_KEYS.has(key)) {\n throw new ZnightError(ErrorCode.InvalidGateway, `WebSocketPlugin: unknown option \"${key}\"`, {\n hints: [`Known options: ${[...OPTION_KEYS].join(', ')}`],\n })\n }\n }\n const o = options as WebSocketPluginOptions\n const transport = o.transport ?? 'auto'\n if (\n transport !== 'auto' &&\n (transport === null || typeof transport !== 'object' || typeof transport.accept !== 'function')\n ) {\n throw invalidOption('transport', \"'auto', wsTransport() or bunTransport()\", transport)\n }\n const backpressure = o.backpressure ?? {}\n if (backpressure === null || typeof backpressure !== 'object') {\n throw invalidOption('backpressure', \"{ limit?, onLimit?: 'close' | 'drop' }\", backpressure)\n }\n const onLimit = backpressure.onLimit ?? 'close'\n if (onLimit !== 'close' && onLimit !== 'drop')\n throw invalidOption('backpressure.onLimit', \"'close' or 'drop'\", onLimit)\n const heartbeat = o.heartbeat ?? { intervalMs: 30_000 }\n let heartbeatMs = 0\n if (heartbeat !== false) {\n if (heartbeat === null || typeof heartbeat !== 'object') {\n throw invalidOption('heartbeat', '{ intervalMs } or false', heartbeat)\n }\n heartbeatMs = positiveInteger('heartbeat.intervalMs', heartbeat.intervalMs, 30_000)\n }\n const shutdown = o.shutdown ?? {}\n if (shutdown === null || typeof shutdown !== 'object') {\n throw invalidOption('shutdown', '{ code?, reason?, timeoutMs? }', shutdown)\n }\n const code = shutdown.code ?? 1001\n if (!isCloseCode(code)) throw invalidOption('shutdown.code', 'a close code (1000, 1001, 1012, 3000-4999)', code)\n const reason = shutdown.reason ?? 'Server shutting down'\n if (typeof reason !== 'string' || Buffer.byteLength(reason) > 123) {\n throw invalidOption('shutdown.reason', 'a string of at most 123 bytes', reason)\n }\n const codec = o.codec ?? jsonCodec\n if (\n codec === null ||\n typeof codec !== 'object' ||\n typeof codec.decode !== 'function' ||\n typeof codec.encode !== 'function'\n ) {\n throw invalidOption('codec', '{ decode(frame, binary), encode(message) }', codec)\n }\n if (o.exposeErrors !== undefined && typeof o.exposeErrors !== 'boolean') {\n throw invalidOption('exposeErrors', 'a boolean', o.exposeErrors)\n }\n return Object.freeze({\n transport,\n origins: resolveOrigins(o.origins ?? 'same-origin'),\n maxPayload: byteSize('maxPayload', o.maxPayload, 1024 * 1024),\n maxConnections: positiveInteger('maxConnections', o.maxConnections, Number.POSITIVE_INFINITY, true),\n maxPendingMessages: positiveInteger('maxPendingMessages', o.maxPendingMessages, 32),\n backpressure: Object.freeze({ limit: byteSize('backpressure.limit', backpressure.limit, 1024 * 1024), onLimit }),\n heartbeatMs,\n handshakeTimeoutMs: positiveInteger('handshakeTimeoutMs', o.handshakeTimeoutMs, 10_000, true),\n handlerTimeoutMs: positiveInteger('handlerTimeoutMs', o.handlerTimeoutMs, 30_000, true),\n closeTimeoutMs: positiveInteger('closeTimeoutMs', o.closeTimeoutMs, 2_000),\n codec,\n messageGuards: refs('messageGuards', o.messageGuards, 'canHandle'),\n exceptionMappers: refs('exceptionMappers', o.exceptionMappers, 'map'),\n exposeErrors: o.exposeErrors ?? false,\n shutdown: Object.freeze({\n code,\n reason,\n timeoutMs: positiveInteger('shutdown.timeoutMs', shutdown.timeoutMs, 3_000),\n }),\n })\n}\n\n/** Whether a close code may be sent by a server (RFC 6455 §7.4). */\nexport function isCloseCode(code: unknown): code is number {\n if (typeof code !== 'number' || !Number.isInteger(code)) return false\n if (code >= 3000 && code <= 4999) return true\n return code >= 1000 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006\n}\n\nfunction refs(name: string, value: unknown, method: string): readonly unknown[] {\n if (value === undefined) return []\n if (!Array.isArray(value)) throw invalidOption(name, `an array of classes or instances with ${method}()`, value)\n for (const ref of value as unknown[]) {\n const ok =\n typeof ref === 'function'\n ? typeof (ref.prototype as Record<string, unknown> | undefined)?.[method] === 'function'\n : ref !== null && typeof ref === 'object' && typeof (ref as Record<string, unknown>)[method] === 'function'\n if (!ok) throw invalidOption(name, `an array of classes or instances with ${method}()`, ref)\n }\n return Object.freeze([...(value as unknown[])])\n}\n\n/** Validates the `origins` option (RFC 0003 §5.6), with the rules of the `cors.origin` option of `HttpPlugin`. */\nexport function resolveOrigins(value: unknown): OriginPolicy {\n if (value === 'same-origin') {\n return { sameOrigin: true, allows: (origin, ctx) => origin === ownOrigin(ctx) }\n }\n if (typeof value === 'function') {\n return { sameOrigin: false, allows: value as OriginPolicy['allows'] }\n }\n const items: readonly unknown[] = Array.isArray(value) ? value : [value]\n const exact = new Set<string>()\n const patterns: RegExp[] = []\n for (const item of items) {\n if (item === '*') return { sameOrigin: false, allows: () => true }\n if (typeof item === 'string') exact.add(checkOrigin(item))\n else if (item instanceof RegExp) patterns.push(checkPattern(item))\n else throw invalidOption('origins', ORIGINS, value)\n }\n return {\n sameOrigin: false,\n allows: origin => exact.has(origin) || patterns.some(pattern => pattern.test(origin)),\n }\n}\n\nconst ORIGINS = \"'same-origin', '*', an origin, an anchored RegExp, a list of them or a function\"\n\n/** The origin of the request itself (`trustProxy` applies to `ctx.protocol`). */\nfunction ownOrigin(ctx: HttpContext): string {\n return `${ctx.protocol}://${ctx.header('host') ?? ''}`\n}\n\nfunction checkOrigin(value: string): string {\n if (value === 'null') {\n throw invalidOption('origins', 'a real origin', value, [\n 'The \"null\" origin is shared by sandboxed iframes, local files and redirects: never trust it',\n ])\n }\n let url: URL | undefined\n try {\n url = new URL(value)\n } catch {\n url = undefined\n }\n if (url === undefined || (url.protocol !== 'http:' && url.protocol !== 'https:')) {\n throw invalidOption('origins', 'an http(s) origin such as \"https://app.example.com\"', value)\n }\n if (url.origin !== value) {\n throw invalidOption('origins', `an origin without path, trailing slash or default port (\"${url.origin}\")`, value)\n }\n return value\n}\n\nfunction checkPattern(pattern: RegExp): RegExp {\n const source = pattern.source\n const trailingBackslashes = /\\\\*\\$$/.exec(source)?.[0].length ?? 0\n const anchoredEnd = source.endsWith('$') && (trailingBackslashes - 1) % 2 === 0\n if (!source.startsWith('^') || !anchoredEnd || /(^|[^\\\\])\\|/.test(source.replace(/\\([^)]*\\)|\\[[^\\]]*\\]/g, ''))) {\n throw invalidOption('origins', 'a RegExp anchored with ^ and $ (around every alternative)', pattern, [\n 'Without anchors, /example\\\\.com/ also allows https://example.com.evil.net',\n ])\n }\n if (pattern.global || pattern.sticky) {\n throw invalidOption('origins', 'a RegExp without the g or y flag (test() would be stateful)', pattern)\n }\n return pattern\n}\n","/** The token bucket of `@Gateway({ rateLimit })` (RFC 0003 §8.6), one per connection. */\nexport class TokenBucket {\n readonly #capacity: number\n readonly #perMs: number\n #tokens: number\n #updatedAt: number\n\n /** `messages` per `intervalMs`, refilled continuously; full at first. */\n constructor(messages: number, intervalMs: number, now: number = performance.now()) {\n this.#capacity = messages\n this.#perMs = messages / intervalMs\n this.#tokens = messages\n this.#updatedAt = now\n }\n\n /** Takes one token: `false` when the bucket is empty. */\n take(now: number = performance.now()): boolean {\n const elapsed = now - this.#updatedAt\n if (elapsed > 0) {\n this.#tokens = Math.min(this.#capacity, this.#tokens + elapsed * this.#perMs)\n this.#updatedAt = now\n }\n if (this.#tokens < 1) return false\n this.#tokens -= 1\n return true\n }\n}\n","/**\n * Rooms and broadcasts of one gateway (RFC 0003 §5.4): rooms are strings scoped per gateway,\n * created on first join and deleted when empty; a broadcast encodes its frame once, then sends it\n * to each selected member, which applies its own backpressure policy.\n */\nimport type { WsCodec } from './envelope.ts'\n\nimport { jsonCodec } from './envelope.ts'\n\n/** What a room holds: a connection, seen through the operations rooms need. */\nexport interface ChannelMember {\n readonly id: string\n /** The rooms of the member, kept in sync by the channel. */\n readonly roomSet: Set<string>\n /** Sends an already encoded frame (`string`: text, `Uint8Array`: binary). */\n sendFrame(frame: string | Uint8Array): unknown\n close(code?: number, reason?: string): void\n}\n\n/** A target of `except()`: a member or its id. */\nexport type MemberRef<M extends ChannelMember = ChannelMember> = M | string\n\n/** A selection of members of a gateway (RFC 0003 §5.4). */\nexport interface Broadcast<E extends object = Record<string, unknown>, M extends ChannelMember = ChannelMember> {\n to(room: string | readonly string[]): Broadcast<E, M>\n except(target: MemberRef<M> | readonly MemberRef<M>[]): Broadcast<E, M>\n exceptRoom(room: string | readonly string[]): Broadcast<E, M>\n emit<K extends keyof E & string>(event: K, data: E[K]): void\n send(frame: string | Uint8Array): void\n join(room: string): void\n leave(room: string): void\n close(code?: number, reason?: string): void\n}\n\ninterface Selection {\n /** `undefined`: every member of the gateway. */\n readonly rooms: readonly string[] | undefined\n readonly except: ReadonlySet<string>\n readonly exceptRooms: readonly string[]\n}\n\nfunction list(value: string | readonly string[]): readonly string[] {\n return typeof value === 'string' ? [value] : value\n}\n\n/** The members and rooms of one gateway. */\nexport class RoomRegistry<M extends ChannelMember = ChannelMember> {\n readonly #members = new Map<string, M>()\n readonly #rooms = new Map<string, Set<M>>()\n /** Encodes the events of broadcasts (once per broadcast). */\n readonly codec: WsCodec\n\n constructor(codec: WsCodec = jsonCodec) {\n this.codec = codec\n }\n\n /** Open members. */\n get size(): number {\n return this.#members.size\n }\n\n add(member: M): void {\n this.#members.set(member.id, member)\n }\n\n /** Removes the member and leaves its rooms. */\n remove(member: M): void {\n for (const room of [...member.roomSet]) this.leave(member, room)\n this.#members.delete(member.id)\n }\n\n get(id: string): M | undefined {\n return this.#members.get(id)\n }\n\n members(): IterableIterator<M> {\n return this.#members.values()\n }\n\n join(member: M, room: string): void {\n if (!this.#members.has(member.id)) return\n let set = this.#rooms.get(room)\n if (set === undefined) {\n set = new Set()\n this.#rooms.set(room, set)\n }\n set.add(member)\n member.roomSet.add(room)\n }\n\n leave(member: M, room: string): void {\n const set = this.#rooms.get(room)\n member.roomSet.delete(room)\n if (set === undefined) return\n set.delete(member)\n if (set.size === 0) this.#rooms.delete(room)\n }\n\n /** The members of `room` (a read-only view). */\n room(room: string): ReadonlySet<M> {\n return this.#rooms.get(room) ?? new Set()\n }\n\n /** Room → size. */\n rooms(): ReadonlyMap<string, number> {\n const sizes = new Map<string, number>()\n for (const [name, set] of this.#rooms) sizes.set(name, set.size)\n return sizes\n }\n\n /** A broadcast over every member, or over the members of `rooms`. */\n select<E extends object>(rooms?: string | readonly string[], except: readonly string[] = []): Broadcast<E, M> {\n return new BroadcastImpl<E, M>(this, {\n rooms: rooms === undefined ? undefined : list(rooms),\n except: new Set(except),\n exceptRooms: [],\n })\n }\n\n /** @internal The members a selection designates, each once. */\n resolve(selection: Selection): M[] {\n const excluded = new Set(selection.except)\n for (const room of selection.exceptRooms) for (const member of this.room(room)) excluded.add(member.id)\n const result: M[] = []\n const seen = new Set<string>()\n const sources = selection.rooms === undefined ? [this.#members.values()] : selection.rooms.map(r => this.room(r))\n for (const source of sources) {\n for (const member of source) {\n if (seen.has(member.id) || excluded.has(member.id)) continue\n seen.add(member.id)\n result.push(member)\n }\n }\n return result\n }\n}\n\nclass BroadcastImpl<E extends object, M extends ChannelMember> implements Broadcast<E, M> {\n readonly #registry: RoomRegistry<M>\n readonly #selection: Selection\n\n constructor(registry: RoomRegistry<M>, selection: Selection) {\n this.#registry = registry\n this.#selection = selection\n }\n\n to(room: string | readonly string[]): Broadcast<E, M> {\n const rooms = [...(this.#selection.rooms ?? []), ...list(room)]\n return new BroadcastImpl(this.#registry, { ...this.#selection, rooms })\n }\n\n except(target: MemberRef<M> | readonly MemberRef<M>[]): Broadcast<E, M> {\n const refs: readonly MemberRef<M>[] = Array.isArray(target) ? target : [target as MemberRef<M>]\n const except = new Set(this.#selection.except)\n for (const ref of refs) except.add(typeof ref === 'string' ? ref : ref.id)\n return new BroadcastImpl(this.#registry, { ...this.#selection, except })\n }\n\n exceptRoom(room: string | readonly string[]): Broadcast<E, M> {\n return new BroadcastImpl(this.#registry, {\n ...this.#selection,\n exceptRooms: [...this.#selection.exceptRooms, ...list(room)],\n })\n }\n\n emit<K extends keyof E & string>(event: K, data: E[K]): void {\n this.send(this.#registry.codec.encode({ kind: 'event', event, data }))\n }\n\n send(frame: string | Uint8Array): void {\n for (const member of this.#registry.resolve(this.#selection)) member.sendFrame(frame)\n }\n\n join(room: string): void {\n for (const member of this.#registry.resolve(this.#selection)) this.#registry.join(member, room)\n }\n\n leave(room: string): void {\n for (const member of this.#registry.resolve(this.#selection)) this.#registry.leave(member, room)\n }\n\n close(code?: number, reason?: string): void {\n for (const member of this.#registry.resolve(this.#selection)) member.close(code, reason)\n }\n}\n","import type { TypedToken } from '@znight/core'\nimport type { WsConnection } from './connection.ts'\nimport type { WebSocketPlugin } from './plugin.ts'\nimport type { WsServer } from './server.ts'\n\n/**\n * Tokens of the values `@znight/websocket` supplies to the container. `WsConnection` is a\n * request-scoped external: the request scope of a WebSocket handshake lasts as long as its\n * connection. Inject it in request-scoped providers (`@Gateway({ scope: 'request' })`) or through\n * `Lazy<WsConnection>`.\n */\nexport const WsTokens: {\n /** The {@link WsServer} of the application (singleton). */\n readonly Server: TypedToken<WsServer>\n /** The {@link WebSocketPlugin} instance (singleton). */\n readonly Plugin: TypedToken<WebSocketPlugin>\n /** The {@link WsConnection} of the current connection (request scope). */\n readonly Connection: TypedToken<WsConnection>\n} = Object.freeze({\n Server: '@znight/websocket#WsServer',\n Plugin: '@znight/websocket#WebSocketPlugin',\n Connection: '@znight/websocket#WsConnection',\n})\n","/**\n * The in-memory transport (RFC 0003 §8.3): an in-process pair used by `WebSocketPlugin.connect()`\n * and the tests. Frames are delivered synchronously, nothing is buffered, reading pauses with a\n * queue, and there is no heartbeat.\n */\nimport type { BunUpgrade, MemoryUpgrade, NodeUpgrade } from '@znight/http'\nimport type { AcceptInit, SendStatus, SocketEvents, TransportSocket, WebSocketTransport } from '../transport.ts'\n\n/** How a memory connection closed. */\nexport interface MemoryCloseInfo {\n readonly code: number\n readonly reason: string\n}\n\n/**\n * The client side of an in-memory connection: pass it as the `peer` of a memory upgrade\n * (`{ kind: 'memory', peer: client }`), then read `received` and send frames.\n */\nexport class MemoryClient {\n /** Frames received from the server, in order. */\n readonly received: (string | Uint8Array)[] = []\n /** Called for each frame received from the server. */\n onmessage: ((frame: string | Uint8Array) => void) | undefined\n /** Called once when the connection closes. */\n onclose: ((info: MemoryCloseInfo) => void) | undefined\n #protocol = ''\n #closed: MemoryCloseInfo | undefined\n #server: MemorySocket | undefined\n\n /** The subprotocol the server selected, `''` when none. */\n get protocol(): string {\n return this.#protocol\n }\n\n /** How the connection closed, `undefined` while open. */\n get closed(): MemoryCloseInfo | undefined {\n return this.#closed\n }\n\n /** Whether the server accepted the connection. */\n get open(): boolean {\n return this.#server !== undefined && this.#closed === undefined\n }\n\n /** Sends a frame to the server (a string is a text frame). */\n send(frame: string | Uint8Array): void {\n if (this.#server === undefined || this.#closed !== undefined) throw new Error('The connection is not open')\n this.#server.receive(frame)\n }\n\n /** Closes the connection from the client side. */\n close(code = 1000, reason = ''): void {\n if (this.#server === undefined || this.#closed !== undefined) return\n this.#server.closeFromPeer(code, reason)\n }\n\n /** @internal Bound by the memory transport. */\n attach(server: MemorySocket, protocol: string): void {\n if (this.#server !== undefined) throw new Error('This MemoryClient is already connected')\n this.#server = server\n this.#protocol = protocol\n }\n\n /** @internal */\n deliver(frame: string | Uint8Array): void {\n this.received.push(frame)\n this.onmessage?.(frame)\n }\n\n /** @internal */\n closedWith(info: MemoryCloseInfo): void {\n if (this.#closed !== undefined) return\n this.#closed = info\n this.onclose?.(info)\n }\n}\n\n/** The server side of an in-memory connection. */\nclass MemorySocket implements TransportSocket {\n readonly bufferedAmount = 0\n readonly extensions = ''\n readonly #client: MemoryClient\n readonly #events: SocketEvents\n readonly #queue: (string | Uint8Array)[] = []\n #paused = false\n #closed = false\n\n constructor(client: MemoryClient, events: SocketEvents) {\n this.#client = client\n this.#events = events\n }\n\n send(frame: string | Uint8Array, _binary: boolean): SendStatus {\n if (this.#closed) return 'dropped'\n this.#client.deliver(frame)\n return 'sent'\n }\n\n ping(): void {\n if (!this.#closed) this.#events.pong()\n }\n\n pause(): boolean {\n this.#paused = true\n return true\n }\n\n resume(): void {\n this.#paused = false\n while (!this.#paused && !this.#closed && this.#queue.length > 0) this.#dispatch(this.#queue.shift() as string)\n }\n\n close(code: number, reason: string): void {\n this.#finish(code, reason)\n }\n\n terminate(): void {\n this.#finish(1006, '')\n }\n\n receive(frame: string | Uint8Array): void {\n if (this.#closed) return\n if (this.#paused) this.#queue.push(frame)\n else this.#dispatch(frame)\n }\n\n closeFromPeer(code: number, reason: string): void {\n this.#finish(code, reason)\n }\n\n #dispatch(frame: string | Uint8Array): void {\n this.#events.message(frame, typeof frame !== 'string')\n }\n\n #finish(code: number, reason: string): void {\n if (this.#closed) return\n this.#closed = true\n this.#queue.length = 0\n this.#client.closedWith({ code, reason })\n this.#events.close(code, reason)\n }\n}\n\n/** The in-memory transport: completes `{ kind: 'memory', peer }` upgrades whose peer is a {@link MemoryClient}. */\nexport function memoryTransport(): WebSocketTransport {\n const sockets = new Set<MemorySocket>()\n return {\n name: 'memory',\n accepts: 'memory',\n configure: () => undefined,\n accept(native: NodeUpgrade | BunUpgrade | MemoryUpgrade, init: AcceptInit, events: SocketEvents): TransportSocket {\n if (native.kind !== 'memory' || !(native.peer instanceof MemoryClient)) {\n throw new Error('The memory transport only completes memory upgrades whose peer is a MemoryClient')\n }\n const tracked: SocketEvents = {\n message: (frame, binary) => events.message(frame, binary),\n pong: () => events.pong(),\n drain: () => events.drain(),\n close: (code, reason) => {\n sockets.delete(socket)\n events.close(code, reason)\n },\n }\n const socket = new MemorySocket(native.peer, tracked)\n sockets.add(socket)\n native.peer.attach(socket, init.protocol)\n return socket\n },\n close(): Promise<void> {\n for (const socket of [...sockets]) socket.terminate()\n return Promise.resolve()\n },\n }\n}\n","/**\n * `WebSocketPlugin` (RFC 0003 §5.9, §8.9): serves the gateways of `metadata.extensions.websocket`\n * through the upgrade routes of `HttpPlugin`. The handshake runs through the HTTP pipeline (request\n * scope, hooks, guards); the plugin adds the origin, subprotocol and capacity checks, completes the\n * upgrade with a transport, and keeps the request scope open for the lifetime of the connection.\n */\nimport type {\n Container,\n Plugin,\n PluginContext,\n PluginOptions,\n PluginRootsContext,\n ProviderKey,\n Token,\n WebSocketConnectionEvent,\n ZnightMetadata,\n} from '@znight/core'\nimport type {\n HttpContext,\n HttpMetadata,\n HttpPlugin,\n PendingUpgrade,\n PluginHttpUpgrades,\n PluginHttpUpgradesContext,\n PluginUpgradeRoute,\n PluginUpgrades,\n RouteMetaEntry,\n} from '@znight/http'\nimport type { WsConnectOptions } from './client.ts'\nimport type { ConnectionLimits, WsCloseInfo, WsStats } from './connection.ts'\nimport type { WsExceptionMapper, WsGuard } from './context.ts'\nimport type { HandlerPlan } from './dispatcher.ts'\nimport type { GatewayDefinition, WebSocketMetadata } from './metadata.ts'\nimport type { ResolvedWebSocketOptions, WebSocketPluginOptions } from './options.ts'\nimport type { SocketEvents, TransportSocket, WebSocketTransport } from './transport.ts'\n\nimport { AsyncLocalStorage } from 'node:async_hooks'\nimport { displayName, ErrorCode, resolveOptions, ZnightError } from '@znight/core'\nimport { BadRequestException, ForbiddenException, HttpException } from '@znight/http'\n\nimport { WsClient, WsHandshakeError } from './client.ts'\nimport { StatsCounter, WsConnectionImpl } from './connection.ts'\nimport { GatewayDispatcher } from './dispatcher.ts'\nimport { resolveWebSocketOptions } from './options.ts'\nimport { TokenBucket } from './rate-limit.ts'\nimport { RoomRegistry } from './rooms.ts'\nimport { WsServer } from './server.ts'\nimport { WsTokens } from './tokens.ts'\nimport { bunTransport } from './transports/bun.ts'\nimport { MemoryClient, memoryTransport } from './transports/memory.ts'\nimport { wsTransport } from './transports/ws.ts'\n\n/** A served gateway, as listed by {@link WebSocketPlugin.gateways}. */\nexport interface WsGatewaySummary {\n /** The path, HTTP prefix included. */\n readonly path: string\n /** Display name of the gateway class. */\n readonly gateway: string\n readonly protocol: 'events' | 'raw'\n /** Handled events (`events` gateways), in declaration order. */\n readonly events: readonly string[]\n}\n\n/** One gateway, ready to accept connections (internal). */\ninterface GatewayPlan {\n readonly definition: GatewayDefinition\n readonly name: string\n /** Path, HTTP prefix included. */\n readonly path: string\n readonly rooms: RoomRegistry<WsConnectionImpl>\n readonly dispatcher: GatewayDispatcher\n readonly maxPayload: number\n readonly limits: ConnectionLimits\n readonly rateLimit: GatewayDefinition['rateLimit']\n readonly instance: (conn: WsConnectionImpl) => object | Promise<object>\n readonly requestScoped: boolean\n}\n\ntype ContextRunner = <R>(fn: () => R) => R\n\n/** The current async context (the handshake's request scope), to run the socket events in it. */\nfunction captureContext(): ContextRunner {\n const snapshot = (AsyncLocalStorage as { snapshot?: () => ContextRunner }).snapshot\n return typeof snapshot === 'function' ? snapshot() : run => run()\n}\n\nconst CONNECTION_HOOK = 'websocket:connection'\n\n/**\n * The WebSocket plugin: `WebSocketPlugin.configure(options)` (name `websocket`). Requires\n * `HttpPlugin`: gateways are served on its server and port, whatever the plugin order.\n *\n * ```ts\n * await Application.create({\n * metadata: __ZNIGHT_METADATA__,\n * plugins: [HttpPlugin.configure({ port: 3000 }), WebSocketPlugin.configure({ maxPayload: '64kb' })],\n * })\n * ```\n */\nexport class WebSocketPlugin implements Plugin, PluginHttpUpgrades {\n readonly name = 'websocket'\n /** The `WsServer` of the application (also injectable). */\n readonly server: WsServer = new WsServer()\n readonly #options: PluginOptions<WebSocketPluginOptions>\n readonly #connections = new Map<WsConnectionImpl, number>()\n /** Connections whose heartbeat the plugin drives (the `ws` transport). */\n readonly #beating = new Set<WsConnectionImpl>()\n #stats = new StatsCounter()\n #ctx: PluginContext | undefined\n #resolved: ResolvedWebSocketOptions | undefined\n #plans: readonly GatewayPlan[] | undefined\n #transport: WebSocketTransport | undefined\n #memory: WebSocketTransport | undefined\n #heartbeat: ReturnType<typeof setInterval> | undefined\n #draining = false\n /** Handshakes past their guards and not yet registered: they count against `maxConnections`. */\n #accepting = 0\n #drain: Promise<void> | undefined\n #active = false\n\n private constructor(options: PluginOptions<WebSocketPluginOptions>) {\n this.#options = options\n }\n\n /**\n * Creates the plugin. `options` may be a function of the container, evaluated once the container\n * is initialised: `WebSocketPlugin.configure(c => ({ origins: c.get(ServerConfig).webOrigins }))`.\n */\n static configure(options: PluginOptions<WebSocketPluginOptions> = {}): WebSocketPlugin {\n return new WebSocketPlugin(options)\n }\n\n /** Name of the transport (`ws`, `bun`), `undefined` before `HttpPlugin` collected the upgrade routes. */\n get transport(): string | undefined {\n return this.#transport?.name\n }\n\n /** The served gateways (after bootstrap). */\n get gateways(): readonly WsGatewaySummary[] {\n return (this.#plans ?? []).map(plan =>\n Object.freeze({\n path: plan.path,\n gateway: plan.name,\n protocol: plan.definition.protocol,\n events: Object.freeze(plan.definition.handlers.flatMap(handler => handler.event ?? [])),\n }),\n )\n }\n\n /** Open connections of every gateway. */\n get connections(): number {\n return this.#connections.size\n }\n\n /** Totals since the application started. */\n stats(): WsStats {\n return this.#stats.snapshot(this.#connections.size)\n }\n\n /**\n * Providers `TestApp` creates at boot: the classes of the `messageGuards` and `exceptionMappers`\n * options, and the gateways of the metadata with their guards.\n */\n initRoots(context?: PluginRootsContext): readonly ProviderKey[] {\n const roots = new Set<ProviderKey>()\n try {\n const options: unknown = this.#options\n if (options !== null && typeof options === 'object') {\n for (const key of ['messageGuards', 'exceptionMappers'] as const) {\n const refs: unknown = (options as WebSocketPluginOptions)[key]\n if (Array.isArray(refs)) for (const ref of refs) if (typeof ref === 'function') roots.add(ref as ProviderKey)\n }\n }\n const gateways: unknown = (context?.metadata.extensions?.websocket as { gateways?: unknown } | undefined)\n ?.gateways\n if (Array.isArray(gateways)) {\n for (const gateway of gateways as Partial<GatewayDefinition>[]) {\n if (typeof gateway?.token !== 'string') continue\n roots.add(gateway.token)\n const handlers = Array.isArray(gateway.handlers) ? gateway.handlers : []\n const tokens = [\n ...(gateway.handshakeGuards ?? []),\n ...(gateway.messageGuards ?? []),\n ...handlers.flatMap(handler => handler?.guards ?? []),\n ]\n for (const token of tokens) if (typeof token === 'string') roots.add(token)\n }\n }\n } catch {\n // initRoots never throws: onBootstrap reports malformed options and metadata\n }\n return [...roots]\n }\n\n register(ctx: PluginContext): void {\n if (this.#active) {\n throw new ZnightError(\n ErrorCode.DuplicateProvider,\n 'This WebSocketPlugin is already used by another application',\n {\n hints: ['Call WebSocketPlugin.configure() once per application'],\n },\n )\n }\n if (ctx.getPlugin('http') === undefined) {\n throw new ZnightError(\n ErrorCode.WebSocketTransportUnavailable,\n 'WebSocketPlugin needs HttpPlugin: gateways are served by the HTTP server',\n { hints: ['Add HttpPlugin.configure() to the plugins (without controllers for a WebSocket-only service)'] },\n )\n }\n this.#active = true\n this.#ctx = ctx\n this.#resolved = undefined\n this.#plans = undefined\n this.#transport = undefined\n this.#memory = undefined\n this.#draining = false\n this.#drain = undefined\n this.#stats = new StatsCounter()\n this.server.reset()\n ctx.container.registerExternal({ token: WsTokens.Connection, scope: 'request', providedBy: 'WebSocketPlugin' })\n ctx.container.registerValue(WsTokens.Server, this.server)\n ctx.container.registerValue(WsTokens.Plugin, this)\n }\n\n onBootstrap(ctx: PluginContext): void {\n this.#ctx = ctx\n this.#resolve()\n gatewaysOf(ctx.metadata)\n }\n\n /**\n * The `PluginHttpUpgrades` contract of `@znight/http`: one upgrade route per gateway, and the\n * `Bun.serve()` settings of the Bun transport. Called once by `HttpPlugin.onBootstrap`. No route\n * (and no transport) without gateways.\n */\n httpUpgrades(context: PluginHttpUpgradesContext): PluginUpgrades {\n const plans = this.#prepare(context)\n if (plans.length === 0) return { routes: [] }\n const extensions = this.#context().metadata.extensions\n const groups = {\n ...(extensions?.http as HttpMetadata | undefined)?.groups,\n ...(extensions?.websocket as WebSocketMetadata | undefined)?.groups,\n }\n const options = this.#resolve()\n const routes = plans.map(\n (plan): PluginUpgradeRoute => ({\n path: plan.definition.path,\n name: plan.name,\n owner: plan.definition.token,\n meta: metaEntries(plan.definition.meta, groups),\n guards: plan.definition.handshakeGuards,\n timeoutMs: options.handshakeTimeoutMs,\n precheck: ctx => this.#precheck(plan, ctx),\n accept: (ctx, upgrade) => this.#accept(plan, ctx, upgrade),\n }),\n )\n const bunWebSocket = this.#transport?.bunWebSocket?.()\n return bunWebSocket === undefined ? { routes } : { routes, bunWebSocket }\n }\n\n async onStart(): Promise<void> {\n const transport = this.#transport\n if (transport === undefined) return\n await transport.ready?.()\n const intervalMs = this.#resolve().heartbeatMs\n if (intervalMs > 0 && transport.accepts === 'node') {\n this.#heartbeat = setInterval(() => {\n for (const conn of this.#beating) conn.heartbeat()\n }, intervalMs)\n this.#heartbeat.unref?.()\n }\n }\n\n /**\n * The `PluginHttpRoutes` contract: `HttpPlugin` starts draining, whatever the plugin order.\n * Refuses new handshakes and closes every connection gracefully (see {@link onStop}).\n */\n onHttpDrain(): Promise<void> {\n return this.#shutdown()\n }\n\n /**\n * Refuses handshakes (`503`), closes every connection with `shutdown.code`, waits for close\n * frames, running handlers and `@OnDisconnect` up to `shutdown.timeoutMs`, then terminates the\n * rest. Idempotent: the same drain as {@link onHttpDrain}.\n */\n onStop(): Promise<void> {\n return this.#shutdown()\n }\n\n async onDispose(): Promise<void> {\n this.#stopHeartbeat()\n try {\n // an application that never started (in-memory tests) still closes its connections gracefully\n await this.#shutdown()\n await Promise.all([this.#transport?.close(), this.#memory?.close()])\n } finally {\n this.#active = false\n this.#beating.clear()\n this.#connections.clear()\n this.#plans = undefined\n }\n }\n\n /**\n * Opens an in-memory connection (tests): the real handshake through the HTTP pipeline (guards,\n * hooks, origin and subprotocol checks) with an in-memory request, then the in-memory transport.\n * `path` is the URL path, HTTP prefix included. Rejects with {@link WsHandshakeError} when the\n * handshake is refused.\n *\n * ```ts\n * await using alice = await plugin.connect('/chat', { protocols: ['chat.v1'] })\n * expect(await alice.request('room.join', { room: 'general' })).toEqual({ members: 1 })\n * ```\n */\n async connect(path: string, options: WsConnectOptions = {}): Promise<WsClient> {\n const http = this.#ctx?.getPlugin<HttpPlugin>('http')\n if (http === undefined || this.#plans === undefined) {\n throw new ZnightError(ErrorCode.LifecycleFailed, 'WebSocketPlugin is not bootstrapped yet', {\n hints: ['connect() is available once Application.create() resolved'],\n })\n }\n const headers: Record<string, string> = { ...options.headers }\n if (options.protocols !== undefined && options.protocols.length > 0) {\n headers['sec-websocket-protocol'] = options.protocols.join(', ')\n }\n if (options.origin !== undefined) headers['origin'] = options.origin\n const peer = new MemoryClient()\n const refused = await http.upgradeInMemory(\n {\n method: 'GET',\n url: path,\n headers,\n ...(options.query === undefined ? {} : { query: options.query }),\n ...(options.cookies === undefined ? {} : { cookies: options.cookies }),\n },\n { kind: 'memory', peer },\n )\n if (refused !== undefined) throw new WsHandshakeError(refused)\n return new WsClient(peer)\n }\n\n // ------------------------------------------------------------------------------------------------\n\n #context(): PluginContext {\n const ctx = this.#ctx\n if (ctx === undefined) {\n throw new ZnightError(ErrorCode.LifecycleFailed, 'WebSocketPlugin is not registered in an application')\n }\n return ctx\n }\n\n #resolve(): ResolvedWebSocketOptions {\n if (this.#resolved !== undefined) return this.#resolved\n const container: Container = this.#context().container\n this.#resolved = resolveWebSocketOptions(resolveOptions(this.#options, container))\n return this.#resolved\n }\n\n /** Builds the gateway plans and selects the transport, once. */\n #prepare(context: PluginHttpUpgradesContext): readonly GatewayPlan[] {\n if (this.#plans !== undefined) return this.#plans\n const ctx = this.#context()\n const options = this.#resolve()\n const definitions = gatewaysOf(ctx.metadata)\n if (definitions.length === 0) {\n this.#plans = []\n return this.#plans\n }\n const transport = selectTransport(options, context)\n let maxPayload = options.maxPayload\n let backpressureLimit = options.backpressure.limit\n for (const definition of definitions) {\n maxPayload = Math.max(maxPayload, definition.maxPayload ?? 0)\n backpressureLimit = Math.max(backpressureLimit, definition.backpressure?.limit ?? 0)\n }\n transport.configure({ maxPayload, backpressureLimit, heartbeatMs: options.heartbeatMs })\n this.#transport = transport\n const refs = new Refs(ctx.container, ctx.metadata)\n const globalGuards = options.messageGuards.map(ref => refs.guard(ref, 'global message guard'))\n const mappers = options.exceptionMappers.map(ref => refs.mapper(ref))\n const plans = definitions.map(definition => {\n const name = displayName(definition.token)\n const path = joinPath(context.prefix, definition.path)\n const classGuards = definition.messageGuards.map(token => refs.guard(token, `message guard of ${name}`))\n const handlers: HandlerPlan[] = definition.handlers.map(handler => ({\n definition: handler,\n guards: [\n ...globalGuards,\n ...classGuards,\n ...handler.guards.map(token => refs.guard(token, `message guard of ${name}.${handler.method}`)),\n ],\n meta: Object.freeze({ ...definition.meta, ...handler.meta }),\n }))\n const requestScoped = ctx.metadata.providers[definition.token]?.scope === 'request'\n const instance = gatewayInstance(ctx.container, definition.token, requestScoped)\n const rooms = new RoomRegistry<WsConnectionImpl>(options.codec)\n const backpressure = definition.backpressure\n const gatewayMaxPayload = definition.maxPayload ?? options.maxPayload\n const plan: GatewayPlan = {\n definition,\n name,\n path,\n rooms,\n maxPayload: gatewayMaxPayload,\n limits: {\n maxPayload: gatewayMaxPayload,\n maxPendingMessages: options.maxPendingMessages,\n concurrency: definition.concurrency ?? 1,\n backpressureLimit: backpressure?.limit ?? options.backpressure.limit,\n onBackpressure: backpressure?.onLimit ?? options.backpressure.onLimit,\n closeTimeoutMs: options.closeTimeoutMs,\n },\n rateLimit: definition.rateLimit,\n instance,\n requestScoped,\n dispatcher: new GatewayDispatcher({\n definition,\n path,\n handlers,\n instance,\n handlerTimeoutMs: options.handlerTimeoutMs,\n exposeErrors: options.exposeErrors,\n hooks: ctx.hooks,\n name,\n mappers,\n codec: options.codec,\n ...(process.env['NODE_ENV'] === 'production'\n ? {}\n : {\n ignoredResult: (handler: string, event: string | undefined) =>\n ctx.logger.debug(\n `WebSocketPlugin: the result of ${name}.${handler} is ignored: \"${event}\" was sent without id (fire and forget)`,\n { gateway: name, handler, event },\n ),\n }),\n logError: (message, error, conn) => {\n ctx.logger.error(`WebSocketPlugin: ${message}`, {\n err: error,\n gateway: name,\n path,\n connectionId: conn.id,\n requestId: conn.requestId,\n })\n },\n closed: (conn, info) => this.#closed(plan, conn, info),\n }),\n }\n this.server.register({\n type: classOf(ctx.metadata, definition.token),\n declaredPath: definition.path,\n path,\n rooms,\n })\n return plan\n })\n this.#plans = plans\n ctx.logger.debug('WebSocket gateways ready', { gateways: plans.length, transport: transport.name })\n return plans\n }\n\n /** Origin, subprotocol and capacity checks, before the guards. */\n async #precheck(plan: GatewayPlan, ctx: HttpContext): Promise<void> {\n if (this.#draining) throw unavailable('The server is shutting down')\n const options = this.#resolve()\n const origin = ctx.header('origin')\n if (origin !== undefined) {\n let allowed = false\n try {\n allowed = (await options.origins.allows(origin, ctx)) === true\n } catch {\n allowed = false\n }\n if (!allowed) throw new ForbiddenException('Origin not allowed')\n }\n selectProtocol(plan, ctx)\n if (this.#full(options)) throw unavailable('Too many WebSocket connections')\n }\n\n #full(options: ResolvedWebSocketOptions): boolean {\n return this.#connections.size + this.#accepting >= options.maxConnections\n }\n\n /** After the guards: completes the upgrade and starts the connection in the handshake's scope. */\n async #accept(plan: GatewayPlan, ctx: HttpContext, upgrade: PendingUpgrade): Promise<void> {\n if (this.#draining) throw unavailable('The server is shutting down')\n const options = this.#resolve()\n // checked again and reserved synchronously: concurrent handshakes all passed the precheck\n if (this.#full(options)) throw unavailable('Too many WebSocket connections')\n this.#accepting++\n let opened: { conn: WsConnectionImpl; socket: TransportSocket }\n try {\n opened = await this.#open(plan, ctx, upgrade)\n } finally {\n this.#accepting--\n }\n const { conn, socket } = opened\n const ws = this.#context()\n const openedAt = performance.now()\n this.#connections.set(conn, openedAt)\n if (upgrade.native.kind !== 'memory' && this.#transport?.accepts === 'node') this.#beating.add(conn)\n this.#stats.opened++\n if (ws.hooks.hasListeners(CONNECTION_HOOK)) {\n ws.hooks.emit(CONNECTION_HOOK, connectionEvent('open', plan, conn, openedAt, undefined))\n }\n conn.start(socket)\n upgrade.hold(conn.finished)\n // the drain began while the handshake completed: it did not see this connection\n if (this.#draining) conn.closeWith(options.shutdown.code, options.shutdown.reason, 'shutdown')\n }\n\n /** Creates the connection (and a request-scoped gateway) and completes the handshake. */\n async #open(\n plan: GatewayPlan,\n ctx: HttpContext,\n upgrade: PendingUpgrade,\n ): Promise<{ conn: WsConnectionImpl; socket: TransportSocket }> {\n const ws = this.#context()\n const protocol = selectProtocol(plan, ctx)\n const rate = plan.rateLimit\n const conn = new WsConnectionImpl({\n id: crypto.randomUUID(),\n gateway: plan.path,\n handshake: ctx,\n protocol,\n limits:\n rate === undefined\n ? plan.limits\n : {\n ...plan.limits,\n rateLimit: { bucket: new TokenBucket(rate.messages, rate.intervalMs), onLimit: rate.onLimit },\n },\n rooms: plan.rooms,\n driver: plan.dispatcher,\n stats: this.#stats,\n })\n ws.container.currentScope()?.set(WsTokens.Connection, conn)\n // a request-scoped gateway is created at the handshake: a factory error answers 500\n if (plan.requestScoped) await plan.instance(conn)\n const memory = upgrade.native.kind === 'memory'\n let transport = this.#transport as WebSocketTransport\n if (memory) {\n this.#memory ??= memoryTransport()\n transport = this.#memory\n }\n const run = captureContext()\n const events = conn.socketEvents()\n // socket events arrive outside of any async context: dispatch them in the connection's scope\n const scoped: SocketEvents = {\n message: (frame, binary) => run(() => events.message(frame, binary)),\n pong: () => events.pong(),\n drain: () => events.drain(),\n close: (code, reason) => run(() => events.close(code, reason)),\n }\n // after every await: a handshake answered 408, or refused by a drain, is not completed\n if (upgrade.expired) throw new HttpException(408, 'WebSocket handshake timed out')\n if (this.#draining) throw unavailable('The server is shutting down')\n const socket = await transport.accept(\n upgrade.native,\n { protocol, headers: upgrade.headers, maxPayload: plan.maxPayload },\n scoped,\n )\n return { conn, socket }\n }\n\n /** A connection fully closed (after `@OnDisconnect`, rooms left). */\n #closed(plan: GatewayPlan, conn: WsConnectionImpl, info: WsCloseInfo): void {\n const openedAt = this.#connections.get(conn) ?? performance.now()\n this.#connections.delete(conn)\n this.#beating.delete(conn)\n this.#stats.closed++\n const hooks = this.#ctx?.hooks\n if (hooks?.hasListeners(CONNECTION_HOOK)) {\n hooks.emit(CONNECTION_HOOK, connectionEvent('close', plan, conn, openedAt, info))\n }\n }\n\n #shutdown(): Promise<void> {\n this.#drain ??= this.#closeAll()\n return this.#drain\n }\n\n async #closeAll(): Promise<void> {\n this.#draining = true\n this.#stopHeartbeat()\n const options = this.#resolved\n const connections = [...this.#connections.keys()]\n if (options === undefined || connections.length === 0) return\n const { code, reason, timeoutMs } = options.shutdown\n for (const conn of connections) conn.closeWith(code, reason, 'shutdown')\n const all = Promise.all(connections.map(conn => conn.finished))\n if (await within(all, timeoutMs)) return\n for (const conn of connections) if (conn.readyState !== 'closed') conn.terminateWith('shutdown')\n await within(all, options.closeTimeoutMs)\n }\n\n #stopHeartbeat(): void {\n if (this.#heartbeat !== undefined) clearInterval(this.#heartbeat)\n this.#heartbeat = undefined\n }\n}\n\n/** Resolves when `task` settles (`true`) or after `ms` (`false`). */\nasync function within(task: Promise<unknown>, ms: number): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<boolean>(resolve => {\n timer = setTimeout(() => resolve(false), ms)\n })\n try {\n return await Promise.race([task.then(() => true), timeout])\n } finally {\n clearTimeout(timer)\n }\n}\n\nfunction unavailable(message: string): HttpException {\n return new HttpException(503, message, undefined, { headers: { 'retry-after': '1' } })\n}\n\nfunction connectionEvent(\n type: 'open' | 'close',\n plan: GatewayPlan,\n conn: WsConnectionImpl,\n openedAt: number,\n info: WsCloseInfo | undefined,\n): WebSocketConnectionEvent {\n return {\n type,\n gateway: plan.name,\n path: plan.path,\n connectionId: conn.id,\n requestId: conn.requestId,\n connection: conn,\n openedAt,\n ...(info === undefined ? {} : { code: info.code, reason: info.reason, initiator: info.initiator }),\n }\n}\n\n/** The subprotocol of a handshake: the first of the gateway's `protocols` the client offers (400 otherwise). */\nfunction selectProtocol(plan: GatewayPlan, ctx: HttpContext): string {\n const accepted = plan.definition.protocols\n if (accepted === undefined || accepted.length === 0) return ''\n const offered = (ctx.header('sec-websocket-protocol') ?? '')\n .split(',')\n .map(item => item.trim())\n .filter(item => item !== '')\n const selected = accepted.find(protocol => offered.includes(protocol))\n if (selected === undefined) throw new BadRequestException('Unsupported WebSocket subprotocol')\n return selected\n}\n\n/** The transport of the `transport` option for the native upgrades of the adapter (ZNIGHT051). */\nfunction selectTransport(options: ResolvedWebSocketOptions, context: PluginHttpUpgradesContext): WebSocketTransport {\n const kind = context.upgrades\n if (kind === undefined) {\n throw new ZnightError(\n ErrorCode.WebSocketTransportUnavailable,\n `WebSocketPlugin: the ${context.adapter} adapter cannot serve WebSocket upgrades`,\n { hints: ['Use a built-in adapter (node, fastify, express, hono) on a server Znight starts'] },\n )\n }\n let transport = options.transport\n if (transport === 'auto') transport = kind === 'bun' ? bunTransport() : wsTransport()\n if (transport.accepts !== kind) {\n throw new ZnightError(\n ErrorCode.WebSocketTransportUnavailable,\n `WebSocketPlugin: the ${transport.name} transport completes ${transport.accepts} upgrades, but the ${context.adapter} adapter produces ${kind} upgrades`,\n {\n hints:\n kind === 'bun'\n ? [\"Use bunTransport() (or transport: 'auto') with honoAdapter() on Bun\"]\n : [\"Use wsTransport() (or transport: 'auto') with the node:http adapters\"],\n },\n )\n }\n return transport\n}\n\n/** `prefix` (`''`, `/api`) joined with a normalized gateway path (`/chat`, `/`). */\nfunction joinPath(prefix: string, path: string): string {\n if (prefix === '' || prefix === '/') return path\n const base = prefix.endsWith('/') ? prefix.slice(0, -1) : prefix\n return path === '/' ? base : `${base}${path}`\n}\n\n/** Route decorator metadata as upgrade route entries, with the groups of `metadata.extensions.http`. */\nfunction metaEntries(\n meta: Readonly<Record<string, unknown>>,\n groups: NonNullable<HttpMetadata['groups']>,\n): RouteMetaEntry[] {\n return Object.keys(meta)\n .sort()\n .map(key => {\n for (const [group, definition] of Object.entries(groups)) {\n if (definition.keys.includes(key)) return { key, value: meta[key], group, required: definition.required }\n }\n return { key, value: meta[key] }\n })\n}\n\nfunction classOf(metadata: ZnightMetadata, token: Token): abstract new (...args: never[]) => object {\n return metadata.providers[token]?.class as abstract new (\n ...args: never[]\n ) => object\n}\n\n/** The gateway instance of a connection: the singleton, or the request-scoped one of its handshake. */\nfunction gatewayInstance(\n container: Container,\n token: Token,\n requestScoped: boolean,\n): (conn: WsConnectionImpl) => object | Promise<object> {\n if (requestScoped) return () => container.get(token) as object | Promise<object>\n let instance: object | undefined\n return () => {\n instance ??= container.get(token) as object\n return instance\n }\n}\n\n/** `metadata.extensions.websocket`, checked (ZNIGHT050): `[]` without gateways. */\nfunction gatewaysOf(metadata: ZnightMetadata): readonly GatewayDefinition[] {\n const section: unknown = metadata.extensions?.websocket\n if (section === undefined) return []\n const gateways = (section as Partial<WebSocketMetadata> | null)?.gateways\n if (!Array.isArray(gateways)) throw malformed('\"gateways\" must be an array')\n for (const gateway of gateways as Partial<GatewayDefinition>[]) {\n const where = typeof gateway?.token === 'string' ? gateway.token : JSON.stringify(gateway)\n if (gateway === null || typeof gateway !== 'object' || typeof gateway.token !== 'string') {\n throw malformed(`invalid gateway ${where}`)\n }\n if (!Object.hasOwn(metadata.providers, gateway.token)) {\n throw malformed(`the gateway ${where} is not a provider of the metadata`)\n }\n if (typeof gateway.path !== 'string' || !gateway.path.startsWith('/')) throw malformed(`invalid path of ${where}`)\n if (gateway.protocol !== 'events' && gateway.protocol !== 'raw') throw malformed(`invalid protocol of ${where}`)\n if (\n !Array.isArray(gateway.handlers) ||\n !Array.isArray(gateway.handshakeGuards) ||\n !Array.isArray(gateway.messageGuards)\n ) {\n throw malformed(`handlers, handshakeGuards and messageGuards of ${where} must be arrays`)\n }\n for (const lifecycle of [gateway.onConnect, gateway.onDisconnect]) {\n if (lifecycle !== undefined && typeof lifecycle?.invoke !== 'function') {\n throw malformed(`invalid lifecycle handler of ${where}`)\n }\n }\n for (const handler of gateway.handlers) {\n if (\n handler === null ||\n typeof handler !== 'object' ||\n typeof handler.invoke !== 'function' ||\n !Array.isArray(handler.guards)\n ) {\n throw malformed(`invalid handler of ${where}`)\n }\n }\n }\n return gateways as GatewayDefinition[]\n}\n\nfunction malformed(reason: string): ZnightError {\n return new ZnightError(\n ErrorCode.InvalidGateway,\n `WebSocketPlugin: malformed metadata.extensions.websocket: ${reason}`,\n {\n hints: ['Regenerate the container module (znight generate) with the same @znight/websocket version'],\n },\n )\n}\n\n/**\n * Message guards and exception mappers resolved once at bootstrap: singletons to their instance,\n * request-scoped and transient providers per call, in the connection's scope.\n */\nclass Refs {\n readonly #container: Container\n readonly #metadata: ZnightMetadata\n\n constructor(container: Container, metadata: ZnightMetadata) {\n this.#container = container\n this.#metadata = metadata\n }\n\n guard(ref: unknown, what: string): WsGuard {\n const resolve = this.#resolve<WsGuard>(ref, what, 'canHandle')\n return typeof resolve === 'function' ? { canHandle: ctx => resolve().canHandle(ctx) } : resolve\n }\n\n mapper(ref: unknown): WsExceptionMapper {\n const resolve = this.#resolve<WsExceptionMapper>(ref, 'exception mapper', 'map')\n return typeof resolve === 'function' ? { map: (error, ctx) => resolve().map(error, ctx) } : resolve\n }\n\n /** The instance, or a function resolving it per call (request-scoped and transient providers). */\n #resolve<T extends object>(ref: unknown, what: string, method: string): T | (() => T) {\n if (typeof ref !== 'function' && typeof ref !== 'string') return ref as T\n const token = typeof ref === 'string' ? ref : this.#container.tokenOf(ref as ProviderKey)\n if (token === undefined || !this.#container.has(token)) {\n const name = typeof ref === 'string' ? displayName(ref) : (ref as { name?: string }).name || '<anonymous>'\n throw new ZnightError(ErrorCode.MissingProvider, `WebSocketPlugin: the ${what} ${name} is not a provider`, {\n hints: ['Add @Injectable() to the class, or pass an instance'],\n })\n }\n const definition = Object.hasOwn(this.#metadata.providers, token) ? this.#metadata.providers[token] : undefined\n const cls: unknown = definition?.class\n if (typeof cls === 'function' && typeof (cls.prototype as Record<string, unknown>)?.[method] !== 'function') {\n throw new ZnightError(\n ErrorCode.InvalidGateway,\n `WebSocketPlugin: the ${what} ${displayName(token)} has no ${method}() method`,\n )\n }\n const scope = definition?.scope\n if (scope === 'request' || scope === 'transient') return () => this.#container.get(token) as T\n return this.#container.get(token) as T\n }\n}\n","/** Payload validation called by the generated `invoke` functions (RFC 0003 §7.3, \"Compiler contract\"). */\nimport type { InferSchemaOutput, StandardSchemaV1 } from '@znight/http'\n\nimport { ValidationException, validate } from '@znight/http'\n\nimport { WsValidationException } from './exceptions.ts'\n\n/**\n * Validates a message payload with a Standard Schema and returns the schema output, synchronously\n * when the schema is synchronous.\n *\n * @throws WsValidationException (`BAD_REQUEST`, `details: [{ path, message }]`) when the payload is invalid.\n */\nexport function validatePayload<S extends StandardSchemaV1>(\n schema: S,\n value: unknown,\n): InferSchemaOutput<S> | Promise<InferSchemaOutput<S>> {\n try {\n const result = validate(schema, value, 'payload')\n return result instanceof Promise ? result.catch(rethrow) : result\n } catch (error) {\n return rethrow(error)\n }\n}\n\nfunction rethrow(error: unknown): never {\n if (error instanceof ValidationException) {\n throw new WsValidationException(error.details as readonly { path: string; message: string }[])\n }\n throw error\n}\n"],"mappings":"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"}
|