@orkestrel/websocket 0.0.10 → 0.0.11

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.
@@ -4,7 +4,7 @@ import { EmitterHooks } from '@orkestrel/emitter';
4
4
  import { EmitterInterface } from '@orkestrel/emitter';
5
5
 
6
6
  /**
7
- * Compute the `Sec-WebSocket-Accept` response value for an RFC 6455 upgrade.
7
+ * Computes the `Sec-WebSocket-Accept` response value for an RFC 6455 upgrade.
8
8
  *
9
9
  * @remarks
10
10
  * The base64-encoded SHA-1 of the client's `Sec-WebSocket-Key` concatenated with the
@@ -17,10 +17,10 @@ import { EmitterInterface } from '@orkestrel/emitter';
17
17
  export declare function computeWebSocketAccept(key: string): string;
18
18
 
19
19
  /**
20
- * Create a server-native WebSocket over a raw upgraded `node:stream` Duplex socket.
20
+ * Creates a server-native WebSocket over a raw upgraded `node:stream` Duplex socket.
21
21
  *
22
22
  * @remarks
23
- * The construction entry point for the {@link NodeWebSocketInterface} (AGENTS §8). Pass
23
+ * The construction entry point for the {@link NodeWebSocketInterface}. Pass
24
24
  * the upgraded `socket` plus the client's `Sec-WebSocket-Key` as `key` to run in SERVER
25
25
  * mode — the wrapper writes the `101 Switching Protocols` handshake and sends unmasked
26
26
  * frames; omit `key` for CLIENT mode (no handshake, masked frames). This is the
@@ -31,6 +31,7 @@ export declare function computeWebSocketAccept(key: string): string;
31
31
  * @param options - The {@link NodeWebSocketOptions} (`socket`, optional `key` / `head` /
32
32
  * `protocol` / `on`)
33
33
  * @returns A typed {@link NodeWebSocketInterface}
34
+ * @throws A `WebSocketError` coded `OPTION` when `payload`, `timeout`, `key`, or `protocol` is refused, thrown before the wrapper writes to or assumes ownership of the `socket`
34
35
  *
35
36
  * @example
36
37
  * ```ts
@@ -38,9 +39,14 @@ export declare function computeWebSocketAccept(key: string): string;
38
39
  *
39
40
  * // In a node:http 'upgrade' handler — server mode, identified by the client key:
40
41
  * server.on('upgrade', (request, socket, head) => {
42
+ * const key = request.headers['sec-websocket-key']
43
+ * if (typeof key !== 'string') {
44
+ * socket.destroy()
45
+ * return
46
+ * }
41
47
  * const ws = createNodeWebSocket({
42
48
  * socket,
43
- * key: request.headers['sec-websocket-key'],
49
+ * key, // present => server mode + 101 handshake
44
50
  * head,
45
51
  * on: { message: (text) => ws.send(`echo: ${text}`) },
46
52
  * })
@@ -50,28 +56,29 @@ export declare function computeWebSocketAccept(key: string): string;
50
56
  export declare function createNodeWebSocket(options: NodeWebSocketOptions): NodeWebSocketInterface;
51
57
 
52
58
  /**
53
- * Encode a single RFC 6455 frame to its wire bytes — the inverse of
54
- * {@link parseWebSocketFrame}.
59
+ * Encodes a single RFC 6455 frame to its wire bytes — the inverse of
60
+ * `parseWebSocketFrame`.
55
61
  *
56
62
  * @remarks
57
63
  * Builds a final (FIN-set) frame: byte 0 is `0x80 | opcode`; the payload length uses
58
64
  * the 7-bit form below 126, the `126` + 16-bit form below 65 536, or the `127` +
59
65
  * 64-bit form beyond; when `masked` is set the mask bit is set, a 4-byte key (supplied
60
- * via `options.mask`, else random) is written, and the payload is XOR-masked. Server→
66
+ * through `options.mask`, else random) is written, and the payload is XOR-masked. Server→
61
67
  * client frames are unmasked (the default); pass `masked: true` to encode a CLIENT
62
- * frame (e.g. to feed the parser in a test). A `string` payload is encoded as UTF-8.
63
- * Returns one contiguous `Buffer` (header + payload), so the wrapper writes it with a
64
- * single `socket.write`. Pure.
68
+ * frame (for example to feed the parser in a test). A `string` payload is encoded as
69
+ * UTF-8. Returns one contiguous `Buffer` (header + payload), so the wrapper writes it
70
+ * with a single `socket.write`. Pure.
65
71
  *
66
72
  * @param opcode - The frame opcode (a `WEBSOCKET_OPCODE_*` value)
67
73
  * @param payload - The payload, a `Buffer` or a UTF-8 `string`
68
74
  * @param options - Masking control ({@link WebSocketEncodeOptions}); defaults to unmasked
69
75
  * @returns The complete frame as wire bytes
76
+ * @throws A {@link WebSocketError} coded `FRAME` when `opcode` is outside the four-bit wire field, when `options.mask` is not 4 bytes, or when `options.mask` is supplied without `masked: true`
70
77
  */
71
78
  export declare function encodeWebSocketFrame(opcode: number, payload: Buffer | string, options?: WebSocketEncodeOptions): Buffer;
72
79
 
73
80
  /**
74
- * Whether a numeric value is a valid RFC 6455 close status code to RECEIVE (§7.4.1).
81
+ * Checks whether a numeric value is a valid RFC 6455 close status code to RECEIVE (§7.4.1).
75
82
  *
76
83
  * @remarks
77
84
  * True for `1000`–`1003`, `1007`–`1014`, and the application range `3000`–`4999`; false
@@ -84,7 +91,7 @@ export declare function encodeWebSocketFrame(opcode: number, payload: Buffer | s
84
91
  * never throws.
85
92
  *
86
93
  * @param code - The close status code to validate
87
- * @returns `true` when `code` is a valid RFC 6455 close code
94
+ * @returns True if `code` is a valid RFC 6455 close code; false otherwise
88
95
  *
89
96
  * @example
90
97
  * ```ts
@@ -94,25 +101,26 @@ export declare function encodeWebSocketFrame(opcode: number, payload: Buffer | s
94
101
  export declare function isCloseCode(code: number): boolean;
95
102
 
96
103
  /**
97
- * Whether the next frame uses the shortest valid RFC 6455 payload-length encoding.
98
- *
99
- * @remarks
100
- * Returns `undefined` until the complete length prefix is buffered. The 16-bit form
101
- * is canonical only for lengths at least 126; the 64-bit form only for lengths at
102
- * least 65,536 and with its most-significant bit clear (RFC 6455 §5.2).
104
+ * Checks whether a value is a {@link WebSocketError}.
103
105
  *
104
- * @param buffer - The accumulation buffer containing the next frame header
105
- * @returns Its canonicality, or `undefined` while the length prefix is incomplete
106
+ * @param value - The value to test (typically a `catch` binding)
107
+ * @returns True if `value` is a `WebSocketError`; false otherwise
106
108
  *
107
109
  * @example
108
110
  * ```ts
109
- * if (isWebSocketFrameCanonical(buffer) === false) fail(WEBSOCKET_CLOSE_PROTOCOL)
111
+ * import { isWebSocketError } from '@src/server'
112
+ *
113
+ * try {
114
+ * ws.close(1000.5)
115
+ * } catch (error) {
116
+ * if (isWebSocketError(error) && error.code === 'CLOSE') ws.close()
117
+ * }
110
118
  * ```
111
119
  */
112
- export declare function isWebSocketFrameCanonical(buffer: Buffer): boolean | undefined;
120
+ export declare function isWebSocketError(value: unknown): value is WebSocketError;
113
121
 
114
122
  /**
115
- * Whether a value is a canonical RFC 6455 `Sec-WebSocket-Key`.
123
+ * Checks whether a value is a canonical RFC 6455 `Sec-WebSocket-Key`.
116
124
  *
117
125
  * @remarks
118
126
  * A valid key is exactly 16 random bytes encoded as 24 characters of base64, ending
@@ -120,7 +128,7 @@ export declare function isWebSocketFrameCanonical(buffer: Buffer): boolean | und
120
128
  * malformed or non-canonical encodings return `false`; nothing is thrown.
121
129
  *
122
130
  * @param key - The proposed `Sec-WebSocket-Key` header value
123
- * @returns `true` when `key` is the canonical base64 encoding of 16 bytes
131
+ * @returns True if `key` is the canonical base64 encoding of 16 bytes; false otherwise
124
132
  *
125
133
  * @example
126
134
  * ```ts
@@ -131,7 +139,7 @@ export declare function isWebSocketFrameCanonical(buffer: Buffer): boolean | und
131
139
  export declare function isWebSocketKey(key: string): boolean;
132
140
 
133
141
  /**
134
- * Whether a value is one valid WebSocket subprotocol token.
142
+ * Checks whether a value is one valid WebSocket subprotocol token.
135
143
  *
136
144
  * @remarks
137
145
  * Subprotocols use the HTTP `token` grammar. Whitespace, separators, commas, and
@@ -139,22 +147,42 @@ export declare function isWebSocketKey(key: string): boolean;
139
147
  * second handshake header.
140
148
  *
141
149
  * @param protocol - The negotiated subprotocol to validate
142
- * @returns `true` when `protocol` is one non-empty HTTP token
150
+ * @returns True if `protocol` is one non-empty HTTP token; false otherwise
143
151
  *
144
152
  * @example
145
153
  * ```ts
146
- * if (!isWebSocketProtocol(protocol)) throw new RangeError('invalid protocol')
154
+ * if (!isWebSocketProtocol(protocol)) socket.destroy()
147
155
  * ```
148
156
  */
149
157
  export declare function isWebSocketProtocol(protocol: string): boolean;
150
158
 
151
159
  /**
152
- * Read the declared payload length off the front of a buffer, without buffering or
160
+ * Checks whether the next frame uses the shortest valid RFC 6455 payload-length encoding.
161
+ *
162
+ * @remarks
163
+ * Returns `undefined` until the complete length prefix is buffered. The 16-bit form
164
+ * is canonical only for lengths at least 126; the 64-bit form only for lengths at
165
+ * least 65,536 and with its most-significant bit clear (RFC 6455 §5.2). Reads the same
166
+ * length prefix as {@link measureWebSocketFrame}, under the same incomplete-buffer
167
+ * contract. Pure; never throws.
168
+ *
169
+ * @param buffer - The accumulation buffer containing the next frame header
170
+ * @returns Its canonicality, or `undefined` while the length prefix is incomplete
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * if (matchesWebSocketCanonical(buffer) === false) fail(WEBSOCKET_CLOSE_PROTOCOL)
175
+ * ```
176
+ */
177
+ export declare function matchesWebSocketCanonical(buffer: Buffer): boolean | undefined;
178
+
179
+ /**
180
+ * Reads the declared payload length off the front of a buffer, without buffering or
153
181
  * reading the payload itself.
154
182
  *
155
183
  * @remarks
156
184
  * Decodes only byte 1's 7-bit length field, extended by the 16-bit (`126`) or 64-bit
157
- * (`127`) form exactly like {@link parseWebSocketFrame} — but stops there, so a caller
185
+ * (`127`) form exactly like `parseWebSocketFrame` — but stops there, so a caller
158
186
  * can reject an over-cap frame the moment its length is known, before the payload
159
187
  * bytes have even arrived. Returns `undefined` until the length field itself is fully
160
188
  * buffered (mirrors the parser's incomplete-buffer contract). Pure; never throws.
@@ -165,13 +193,13 @@ export declare function isWebSocketProtocol(protocol: string): boolean;
165
193
  * @example
166
194
  * ```ts
167
195
  * const declared = measureWebSocketFrame(buffer)
168
- * if (declared !== undefined && declared > limit) fail(WEBSOCKET_CLOSE_TOOBIG)
196
+ * if (declared !== undefined && declared > limit) fail(WEBSOCKET_CLOSE_TOO_BIG)
169
197
  * ```
170
198
  */
171
199
  export declare function measureWebSocketFrame(buffer: Buffer): number | undefined;
172
200
 
173
201
  /**
174
- * A server-native WebSocket over a raw upgraded `node:stream` Duplex — the lean
202
+ * Represents a server-native WebSocket over a raw upgraded `node:stream` Duplex — the lean
175
203
  * wrapper around the RFC 6455 wire protocol.
176
204
  *
177
205
  * @remarks
@@ -184,34 +212,59 @@ export declare function measureWebSocketFrame(buffer: Buffer): number | undefine
184
212
  * `fin: false` frames — decodes to UTF-8 and emits `message`; a PING is auto-answered
185
213
  * with a PONG and emits `ping`; a PONG emits `pong`; a CLOSE is echoed and ends the
186
214
  * socket, emitting `close`. `send` writes a text frame, `ping` a ping, `close` a close
187
- * frame; `destroy` tears down immediately. It owns a typed `#emitter` (AGENTS §13) that
188
- * isolates a throwing listener and routes the error to its own `error` handler (the `error`
189
- * option) — the socket never crashes. An underlying socket error emits the domain
190
- * `error` event and terminates the wrapper. The untyped socket `data` is narrowed to a
191
- * `Buffer` with a guard, never an assertion (AGENTS §14).
215
+ * frame; `destroy` tears down immediately. It owns a typed `#emitter` by composition, and
216
+ * the emitter isolates a throwing listener and routes the error to its own `error` handler
217
+ * (the `error` option) — the socket never crashes. An underlying socket error emits the
218
+ * domain `error` event and terminates the wrapper. The untyped socket `data` is narrowed
219
+ * to a `Buffer` with a guard, never an assertion.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * import { NodeWebSocket } from '@src/server'
224
+ *
225
+ * // In a node:http 'upgrade' handler, over the socket the server already handed over:
226
+ * const key = request.headers['sec-websocket-key']
227
+ * if (typeof key !== 'string') {
228
+ * socket.destroy()
229
+ * return
230
+ * }
231
+ * const ws = new NodeWebSocket({ socket, key, head })
232
+ * ws.emitter.on('message', (text) => ws.send(`echo: ${text}`))
233
+ * ```
192
234
  */
193
235
  export declare class NodeWebSocket implements NodeWebSocketInterface {
194
236
  #private;
237
+ /**
238
+ * Creates a WebSocket wrapper over an already-upgraded Duplex socket.
239
+ *
240
+ * @remarks
241
+ * `key` selects the mode: present runs SERVER mode and writes the `101 Switching
242
+ * Protocols` handshake, omitted runs CLIENT mode and masks every outgoing frame.
243
+ * {@link NodeWebSocketOptions} describes every member.
244
+ *
245
+ * @param options - The {@link NodeWebSocketOptions} the wrapper is built from
246
+ * @throws A {@link WebSocketError} coded `OPTION` when `payload`, `timeout`, `key`, or `protocol` is refused, or when `protocol` is supplied without a server `key`, thrown before the wrapper writes to or assumes ownership of the `socket`
247
+ */
195
248
  constructor(options: NodeWebSocketOptions);
196
249
  get emitter(): EmitterInterface<NodeWebSocketEventMap>;
197
250
  get readyState(): WebSocketReadyState;
198
- send(data: string): void;
199
- ping(data?: string): void;
251
+ send(message: string): void;
252
+ ping(payload?: string): void;
200
253
  close(code?: number, reason?: string): void;
201
254
  destroy(): void;
202
255
  }
203
256
 
204
257
  /**
205
- * The event map of a {@link NodeWebSocketInterface} (AGENTS §13).
258
+ * Represents the event map of a {@link NodeWebSocketInterface}.
206
259
  *
207
260
  * @remarks
208
261
  * `open` — the handshake completed and the socket is ready. `message` — a text frame
209
- * arrived (its decoded UTF-8 string). `close` — the connection ended (its
210
- * {@link WebSocketClose} metadata). `error` the underlying socket faulted (a DOMAIN
211
- * event and then terminates the wrapper). `ping` / `pong` — a control frame arrived
212
- * (a ping is auto-answered with a pong).
213
- * Listener isolation is the emitter's (AGENTS §13): a listener throw is routed to the
214
- * emitter's `error` handler (the `error` option), never onto this map, so a buggy observer
262
+ * arrived (its decoded UTF-8 string). `close` — the connection ended, carrying the
263
+ * labeled `[code, reason]` tuple (each `undefined` when the peer sent none). `error`
264
+ * the underlying socket faulted (a DOMAIN event and then terminates the wrapper).
265
+ * `ping` / `pong` — a control frame arrived (a ping is auto-answered with a pong).
266
+ * Listener isolation is the emitter's: a listener throw is routed to the emitter's
267
+ * `error` handler (the `error` option), never onto this map, so a buggy observer
215
268
  * never breaks the socket.
216
269
  */
217
270
  export declare type NodeWebSocketEventMap = {
@@ -224,7 +277,7 @@ export declare type NodeWebSocketEventMap = {
224
277
  };
225
278
 
226
279
  /**
227
- * A server-native WebSocket over a raw upgraded socket — the behavioral contract.
280
+ * Represents a server-native WebSocket over a raw upgraded socket — the behavioral contract.
228
281
  *
229
282
  * @remarks
230
283
  * Created by `createNodeWebSocket`. In server mode it writes the RFC 6455 handshake
@@ -234,20 +287,24 @@ export declare type NodeWebSocketEventMap = {
234
287
  * frame is echoed and ends the socket, emitting `close`. `send` writes a text frame;
235
288
  * `ping` writes a ping; `close` writes a close frame (the 2-byte code + optional
236
289
  * reason); `destroy` tears the socket down immediately. `readyState` tracks the
237
- * lifecycle. It owns a typed `emitter` (AGENTS §13) and never throws on a faulty
290
+ * lifecycle. It owns a typed `emitter` by composition and never throws on a faulty
238
291
  * listener — the emitter routes it to its `error` handler (the `error` option).
292
+ * `ping` throws a `LIMIT`-coded `WebSocketError` when its UTF-8 payload exceeds
293
+ * `WEBSOCKET_CONTROL_MAX_LENGTH`; `close` throws a `CLOSE`-coded one for a status code
294
+ * `isCloseCode` refuses and a `LIMIT`-coded one for a reason past
295
+ * `WEBSOCKET_CLOSE_REASON_MAX_LENGTH`, in each case without changing `readyState`.
239
296
  */
240
297
  export declare interface NodeWebSocketInterface {
241
298
  readonly emitter: EmitterInterface<NodeWebSocketEventMap>;
242
299
  readonly readyState: WebSocketReadyState;
243
- send(data: string): void;
244
- ping(data?: string): void;
300
+ send(message: string): void;
301
+ ping(payload?: string): void;
245
302
  close(code?: number, reason?: string): void;
246
303
  destroy(): void;
247
304
  }
248
305
 
249
306
  /**
250
- * Options for `createNodeWebSocket`.
307
+ * Represents the options for `createNodeWebSocket`.
251
308
  *
252
309
  * @remarks
253
310
  * `socket` is the upgraded `node:stream` Duplex (the raw TCP stream after the HTTP
@@ -256,8 +313,8 @@ export declare interface NodeWebSocketInterface {
256
313
  * frames; omit it for CLIENT mode — no handshake is written and frames are MASKED (RFC
257
314
  * 6455 §5.3). `head` is any bytes buffered after the upgrade headers (replayed through
258
315
  * the parser). `protocol` is a negotiated subprotocol to echo in the handshake. `on`
259
- * wires initial listeners at construction (AGENTS §8 reserved option); `error` is the
260
- * emitter's listener-error handler (§13 a listener throw routes here). `payload` caps
316
+ * wires initial listeners at construction the reserved `on` option; `error` is the
317
+ * emitter's listener-error handler, where a listener throw routes. `payload` caps
261
318
  * both a single inbound frame's declared length AND the total bytes of a reassembled
262
319
  * fragmented message (default `WEBSOCKET_MAX_PAYLOAD`) — a breach closes 1009. `timeout`
263
320
  * is how long the wrapper waits, after sending a close frame, for the peer's echo before
@@ -265,7 +322,8 @@ export declare interface NodeWebSocketInterface {
265
322
  * is the external cancellation seam — on abort the socket destroys; composes with the
266
323
  * line's `@orkestrel/abort` and `@orkestrel/timeout` primitives, which expose native
267
324
  * `AbortSignal`s. An already-aborted signal tears the socket down immediately after
268
- * construction.
325
+ * construction. A refused member throws an `OPTION`-coded `WebSocketError` before the
326
+ * wrapper writes to or assumes ownership of the `socket`.
269
327
  */
270
328
  export declare interface NodeWebSocketOptions {
271
329
  readonly socket: Duplex;
@@ -273,7 +331,7 @@ export declare interface NodeWebSocketOptions {
273
331
  readonly head?: Buffer;
274
332
  readonly protocol?: string;
275
333
  readonly on?: EmitterHooks<NodeWebSocketEventMap>;
276
- /** The emitter's listener-error handler (AGENTS §13) — a listener throw routes here, not to a domain event. */
334
+ /** Holds the emitter's listener-error handler — a listener throw routes here, not to a domain event. */
277
335
  readonly error?: EmitterErrorHandler;
278
336
  readonly payload?: number;
279
337
  readonly timeout?: number;
@@ -281,12 +339,12 @@ export declare interface NodeWebSocketOptions {
281
339
  }
282
340
 
283
341
  /**
284
- * Decode a byte sequence as strict UTF-8, or signal it is malformed.
342
+ * Decodes a byte sequence as strict UTF-8, or signals it is malformed.
285
343
  *
286
344
  * @remarks
287
345
  * Wraps `TextDecoder('utf-8', { fatal: true })` in a try/catch so a malformed sequence
288
- * returns `undefined` instead of throwing (AGENTS §14 — a guard-adjacent coercer never
289
- * throws on bad input). Pure.
346
+ * returns `undefined` instead of throwing — a guard-adjacent coercer never throws on bad
347
+ * input. Pure.
290
348
  *
291
349
  * @param bytes - The raw bytes to decode
292
350
  * @returns The decoded string, or `undefined` when `bytes` is not valid UTF-8
@@ -300,7 +358,7 @@ export declare interface NodeWebSocketOptions {
300
358
  export declare function parseUTF8(bytes: Buffer): string | undefined;
301
359
 
302
360
  /**
303
- * Decode a single RFC 6455 frame from the front of a buffer.
361
+ * Decodes a single RFC 6455 frame from the front of a buffer.
304
362
  *
305
363
  * @remarks
306
364
  * Reads the FIN bit and opcode (byte 0), the mask bit and 7-bit payload length (byte
@@ -310,44 +368,49 @@ export declare function parseUTF8(bytes: Buffer): string | undefined;
310
368
  * 6455 §5.3; an unmasked frame still decodes, leaving the payload as-is, so the caller
311
369
  * can enforce policy). Returns `undefined` the moment the buffer is too short for the
312
370
  * part it is up to (the length prefix, the mask, or the full payload) — the signal to
313
- * the caller to read more bytes and retry, exactly like {@link SSEParser} on a partial
314
- * line. `consumed` is the total bytes the frame occupied, so the caller slices the
315
- * remainder. Pure; never throws on a short buffer.
371
+ * the caller to read more bytes and retry. `consumed` is the total bytes the frame
372
+ * occupied, so the caller slices the remainder. Pure; never throws on a short buffer.
316
373
  *
317
374
  * @param buffer - The accumulation buffer to decode the next frame from
318
375
  * @returns The parsed {@link WebSocketFrame}, or `undefined` when the buffer is incomplete
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * const frame = parseWebSocketFrame(buffer)
380
+ * if (frame === undefined) return // incomplete — wait for more bytes
381
+ * ```
319
382
  */
320
383
  export declare function parseWebSocketFrame(buffer: Buffer): WebSocketFrame | undefined;
321
384
 
322
- /** Invalid-frame-payload-data status code (RFC 6455 §7.4.1) — e.g. non-UTF-8 text or an unparseable close reason. */
385
+ /** Names the invalid-frame-payload-data status code (RFC 6455 §7.4.1) — for example non-UTF-8 text or an unparseable close reason. */
323
386
  export declare const WEBSOCKET_CLOSE_INVALID = 1007;
324
387
 
325
- /** Normal-closure status code (RFC 6455 §7.4.1) — the default `close` code. */
388
+ /** Names the normal-closure status code (RFC 6455 §7.4.1) — the default `close` code. */
326
389
  export declare const WEBSOCKET_CLOSE_NORMAL = 1000;
327
390
 
328
- /** Protocol-error status code (RFC 6455 §7.4.1) — a framing/state rule was violated. */
391
+ /** Names the protocol-error status code (RFC 6455 §7.4.1) — a framing/state rule was violated. */
329
392
  export declare const WEBSOCKET_CLOSE_PROTOCOL = 1002;
330
393
 
331
- /** The maximum UTF-8 close-reason length after the two-byte status code. */
332
- export declare const WEBSOCKET_CLOSE_REASON_MAXLEN: number;
394
+ /** Names the maximum UTF-8 close-reason length after the two-byte status code. */
395
+ export declare const WEBSOCKET_CLOSE_REASON_MAX_LENGTH: number;
333
396
 
334
- /** The default close-handshake timeout in milliseconds — how long `close()` waits for the peer's echo before tearing the socket down. */
397
+ /** Names the default close-handshake timeout in milliseconds — how long `close()` waits for the peer's echo before tearing the socket down. */
335
398
  export declare const WEBSOCKET_CLOSE_TIMEOUT_MS = 30000;
336
399
 
337
- /** Message-too-big status code (RFC 6455 §7.4.1) — a reassembled message exceeded the payload cap. */
338
- export declare const WEBSOCKET_CLOSE_TOOBIG = 1009;
400
+ /** Names the message-too-big status code (RFC 6455 §7.4.1) — a reassembled message exceeded the payload cap. */
401
+ export declare const WEBSOCKET_CLOSE_TOO_BIG = 1009;
339
402
 
340
- /** Unsupported-data status code (RFC 6455 §7.4.1) — the endpoint received a data type it cannot accept (e.g. binary on a text-only endpoint). */
403
+ /** Names the unsupported-data status code (RFC 6455 §7.4.1) — the endpoint received a data type it cannot accept, for example binary on a text-only endpoint. */
341
404
  export declare const WEBSOCKET_CLOSE_UNSUPPORTED = 1003;
342
405
 
343
- /** The maximum control-frame payload length in bytes (RFC 6455 §5.5). */
344
- export declare const WEBSOCKET_CONTROL_MAXLEN = 125;
406
+ /** Names the maximum control-frame payload length in bytes (RFC 6455 §5.5). */
407
+ export declare const WEBSOCKET_CONTROL_MAX_LENGTH = 125;
345
408
 
346
- /** The post-`#fail` flush grace in milliseconds — how long a validation-breach close frame is given to flush through the socket's write buffer before the hard `destroy()` fallback fires (the normal path destroys sooner, on the `end()` flush callback). */
409
+ /** Names the post-`#fail` flush grace in milliseconds — how long a validation-breach close frame is given to flush through the socket's write buffer before the hard `destroy()` fallback fires (the normal path destroys sooner, on the `end()` flush callback). */
347
410
  export declare const WEBSOCKET_FAIL_TIMEOUT_MS = 1000;
348
411
 
349
412
  /**
350
- * The RFC 6455 GUID concatenated to a client's `Sec-WebSocket-Key` before the SHA-1
413
+ * Names the RFC 6455 GUID concatenated to a client's `Sec-WebSocket-Key` before the SHA-1
351
414
  * hash that yields the `Sec-WebSocket-Accept` response value.
352
415
  *
353
416
  * @remarks
@@ -356,59 +419,44 @@ export declare const WEBSOCKET_FAIL_TIMEOUT_MS = 1000;
356
419
  */
357
420
  export declare const WEBSOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
358
421
 
359
- /** The default maximum inbound single-frame length AND reassembled-message total byte count (100 MiB — the `ws` package default). */
422
+ /** Names the default maximum inbound single-frame length AND reassembled-message total byte count (100 MiB — the `ws` package default). */
360
423
  export declare const WEBSOCKET_MAX_PAYLOAD = 104857600;
361
424
 
362
- /** Binary frame opcode — a raw byte payload (RFC 6455 §5.6). */
425
+ /** Names the binary frame opcode — a raw byte payload (RFC 6455 §5.6). */
363
426
  export declare const WEBSOCKET_OPCODE_BINARY = 2;
364
427
 
365
- /** Close frame opcode — a control frame ending the connection (RFC 6455 §5.5.1). */
428
+ /** Names the close frame opcode — a control frame ending the connection (RFC 6455 §5.5.1). */
366
429
  export declare const WEBSOCKET_OPCODE_CLOSE = 8;
367
430
 
368
- /** Continuation frame opcode — the next fragment of an open data message (RFC 6455 §5.4). */
431
+ /** Names the continuation frame opcode — the next fragment of an open data message (RFC 6455 §5.4). */
369
432
  export declare const WEBSOCKET_OPCODE_CONTINUATION = 0;
370
433
 
371
- /** Ping frame opcode — a control frame the peer must answer with a pong (RFC 6455 §5.5.2). */
434
+ /** Names the ping frame opcode — a control frame the peer must answer with a pong (RFC 6455 §5.5.2). */
372
435
  export declare const WEBSOCKET_OPCODE_PING = 9;
373
436
 
374
- /** Pong frame opcode — a control frame answering a ping (RFC 6455 §5.5.3). */
437
+ /** Names the pong frame opcode — a control frame answering a ping (RFC 6455 §5.5.3). */
375
438
  export declare const WEBSOCKET_OPCODE_PONG = 10;
376
439
 
377
- /** Text frame opcode — a UTF-8 payload (RFC 6455 §5.6). */
440
+ /** Names the text frame opcode — a UTF-8 payload (RFC 6455 §5.6). */
378
441
  export declare const WEBSOCKET_OPCODE_TEXT = 1;
379
442
 
380
- /** Ready state for a closed WebSocket (the socket ended). */
443
+ /** Names the ready state for a closed WebSocket (the socket ended). */
381
444
  export declare const WEBSOCKET_READY_CLOSED: WebSocketReadyState;
382
445
 
383
- /** Ready state for a closing WebSocket (a close frame was sent or received). */
446
+ /** Names the ready state for a closing WebSocket (a close frame was sent or received). */
384
447
  export declare const WEBSOCKET_READY_CLOSING: WebSocketReadyState;
385
448
 
386
- /** Ready state for a connecting WebSocket (before the handshake completes). */
449
+ /** Names the ready state for a connecting WebSocket (before the handshake completes). */
387
450
  export declare const WEBSOCKET_READY_CONNECTING: WebSocketReadyState;
388
451
 
389
- /** Ready state for an open WebSocket (the handshake completed; frames flow). */
452
+ /** Names the ready state for an open WebSocket (the handshake completed; frames flow). */
390
453
  export declare const WEBSOCKET_READY_OPEN: WebSocketReadyState;
391
454
 
392
- /** The WebSocket protocol version this wrapper speaks (`Sec-WebSocket-Version: 13`). */
455
+ /** Names the WebSocket protocol version this wrapper speaks (`Sec-WebSocket-Version: 13`). */
393
456
  export declare const WEBSOCKET_VERSION = "13";
394
457
 
395
458
  /**
396
- * The metadata of a closed WebSocketwhy the connection ended.
397
- *
398
- * @remarks
399
- * `code` is the RFC 6455 close status code (undefined when the peer closed with no
400
- * payload); `reason` is the optional UTF-8 reason text (undefined when empty).
401
- */
402
- export declare interface WebSocketClose {
403
- readonly code: number | undefined;
404
- readonly reason: string | undefined;
405
- }
406
-
407
- /** A WebSocket close status code (RFC 6455 §7.4) — e.g. `WEBSOCKET_CLOSE_NORMAL` (1000). */
408
- export declare type WebSocketCloseCode = number;
409
-
410
- /**
411
- * Options for {@link encodeWebSocketFrame} — how a frame is masked on the wire.
459
+ * Represents the options for {@link encodeWebSocketFrame}how a frame is masked on the wire.
412
460
  *
413
461
  * @remarks
414
462
  * `masked` toggles the mask bit (server→client frames are NOT masked, the default;
@@ -422,7 +470,57 @@ export declare interface WebSocketEncodeOptions {
422
470
  }
423
471
 
424
472
  /**
425
- * A parsed RFC 6455 frame the structured result of decoding one frame off the wire.
473
+ * Represents an error thrown by the WebSocket wrapper for a refused caller-supplied value.
474
+ *
475
+ * @remarks
476
+ * Carries a {@link WebSocketErrorCode} and an optional `context` record holding the
477
+ * refused value under a key naming it: an `'OPTION'` carries the offending option
478
+ * (`payload`, `timeout`, `key`, or `protocol`), a `'LIMIT'` carries `size` and the
479
+ * `limit` it exceeded, a `'CLOSE'` carries the refused close `code`, and a `'FRAME'`
480
+ * carries `opcode` or the mask's `size`. Narrow a caught value with
481
+ * {@link isWebSocketError}.
482
+ *
483
+ * @example
484
+ * ```ts
485
+ * import { createNodeWebSocket, isWebSocketError } from '@src/server'
486
+ *
487
+ * try {
488
+ * createNodeWebSocket({ socket, key: 'not-base64' })
489
+ * } catch (error) {
490
+ * if (isWebSocketError(error) && error.code === 'OPTION') socket.destroy()
491
+ * }
492
+ * ```
493
+ */
494
+ export declare class WebSocketError extends Error {
495
+ readonly code: WebSocketErrorCode;
496
+ readonly context?: Readonly<Record<string, unknown>>;
497
+ /**
498
+ * Creates a WebSocket error carrying a machine-readable code.
499
+ *
500
+ * @param code - The machine-readable {@link WebSocketErrorCode} a `catch` branches on
501
+ * @param message - The human-readable description, carried as the `Error` message
502
+ * @param context - The refused value keyed by name; omitted leaves `context` `undefined`
503
+ */
504
+ constructor(code: WebSocketErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
505
+ }
506
+
507
+ /**
508
+ * Represents the subject an {@link import('./errors.js').WebSocketError} names as refused.
509
+ *
510
+ * @remarks
511
+ * `OPTION` — a {@link NodeWebSocketOptions} member was refused at construction
512
+ * (`payload`, `timeout`, `key`, `protocol`, or a `protocol` given without a server
513
+ * `key`). `LIMIT` — an outbound control-frame payload exceeded its RFC 6455 §5.5 cap
514
+ * (a `ping` payload past `WEBSOCKET_CONTROL_MAX_LENGTH`, a `close` reason past
515
+ * `WEBSOCKET_CLOSE_REASON_MAX_LENGTH`). `CLOSE` — a close status code `isCloseCode` refuses
516
+ * was passed to `close`. `FRAME` — an `encodeWebSocketFrame` frame-header argument was
517
+ * refused (an opcode outside the four-bit wire field, a mask that is not 4 bytes, or a
518
+ * mask supplied without `masked: true`).
519
+ */
520
+ export declare type WebSocketErrorCode = 'OPTION' | 'LIMIT' | 'CLOSE' | 'FRAME';
521
+
522
+ /**
523
+ * Represents a parsed RFC 6455 frame — the structured result of decoding one frame off the wire.
426
524
  *
427
525
  * @remarks
428
526
  * `fin` is the final-fragment bit (false for a continued fragment); `opcode`
@@ -444,13 +542,8 @@ export declare interface WebSocketFrame {
444
542
  readonly rsv: number;
445
543
  }
446
544
 
447
- /** A decoded text message received from, or to send to, a WebSocket peer. */
448
- export declare interface WebSocketMessage {
449
- readonly data: string;
450
- }
451
-
452
545
  /**
453
- * A WebSocket ready state — the four browser-compatible lifecycle values.
546
+ * Represents a WebSocket ready state — the four browser-compatible lifecycle values.
454
547
  *
455
548
  * @remarks
456
549
  * `0` connecting, `1` open, `2` closing, `3` closed — the same numbering the DOM