@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
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { a as TransportSocket, i as TransportSettings, n as SendStatus, o as WebSocketTransport, r as SocketEvents, t as AcceptInit } from "./transport-xnJqvB93.mjs";
|
|
2
|
+
import { A as TokenBucket, C as encodeErrorEvent, D as isFailure, E as encodeReply, O as isMessageId, S as decodeFrame, T as encodeEvent, _ as InboundMessage, a as WsCloseInfo, b as WireError, c as WsConnection, d as Broadcast, f as ChannelMember, g as InboundFailure, h as EVENT_NAME, i as WsServer, k as jsonCodec, l as WsSendResult, m as RoomRegistry, n as GatewayRef, o as WsCloseInitiator, p as MemberRef, r as ServedGateway, s as WsClosedError, t as GatewayChannel, u as WsStats, v as MessageId, w as encodeErrorReply, x as WsCodec, y as OutboundMessage } from "./server-CI_Bh9o1.mjs";
|
|
3
|
+
import { Plugin, PluginContext, PluginOptions, PluginRootsContext, ProviderKey, Token, TypedToken, ZnightError } from "@znight/core";
|
|
4
|
+
import { ByteSize, HttpContext, InferSchemaOutput, InjectResponse, PluginHttpUpgrades, PluginHttpUpgradesContext, PluginUpgrades, StandardSchemaV1 } from "@znight/http";
|
|
5
|
+
/** How a memory connection closed. */
|
|
6
|
+
interface MemoryCloseInfo {
|
|
7
|
+
readonly code: number;
|
|
8
|
+
readonly reason: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The client side of an in-memory connection: pass it as the `peer` of a memory upgrade
|
|
12
|
+
* (`{ kind: 'memory', peer: client }`), then read `received` and send frames.
|
|
13
|
+
*/
|
|
14
|
+
export declare class MemoryClient {
|
|
15
|
+
#private;
|
|
16
|
+
/** Frames received from the server, in order. */
|
|
17
|
+
readonly received: (string | Uint8Array)[];
|
|
18
|
+
/** Called for each frame received from the server. */
|
|
19
|
+
onmessage: ((frame: string | Uint8Array) => void) | undefined;
|
|
20
|
+
/** Called once when the connection closes. */
|
|
21
|
+
onclose: ((info: MemoryCloseInfo) => void) | undefined;
|
|
22
|
+
/** The subprotocol the server selected, `''` when none. */
|
|
23
|
+
get protocol(): string;
|
|
24
|
+
/** How the connection closed, `undefined` while open. */
|
|
25
|
+
get closed(): MemoryCloseInfo | undefined;
|
|
26
|
+
/** Whether the server accepted the connection. */
|
|
27
|
+
get open(): boolean;
|
|
28
|
+
/** Sends a frame to the server (a string is a text frame). */
|
|
29
|
+
send(frame: string | Uint8Array): void;
|
|
30
|
+
/** Closes the connection from the client side. */
|
|
31
|
+
close(code?: number, reason?: string): void;
|
|
32
|
+
/** @internal Bound by the memory transport. */
|
|
33
|
+
attach(server: MemorySocket, protocol: string): void;
|
|
34
|
+
/** @internal */
|
|
35
|
+
deliver(frame: string | Uint8Array): void;
|
|
36
|
+
/** @internal */
|
|
37
|
+
closedWith(info: MemoryCloseInfo): void;
|
|
38
|
+
}
|
|
39
|
+
/** The server side of an in-memory connection. */
|
|
40
|
+
declare class MemorySocket implements TransportSocket {
|
|
41
|
+
#private;
|
|
42
|
+
readonly bufferedAmount = 0;
|
|
43
|
+
readonly extensions = "";
|
|
44
|
+
constructor(client: MemoryClient, events: SocketEvents);
|
|
45
|
+
send(frame: string | Uint8Array, _binary: boolean): SendStatus;
|
|
46
|
+
ping(): void;
|
|
47
|
+
pause(): boolean;
|
|
48
|
+
resume(): void;
|
|
49
|
+
close(code: number, reason: string): void;
|
|
50
|
+
terminate(): void;
|
|
51
|
+
receive(frame: string | Uint8Array): void;
|
|
52
|
+
closeFromPeer(code: number, reason: string): void;
|
|
53
|
+
}
|
|
54
|
+
/** The in-memory transport: completes `{ kind: 'memory', peer }` upgrades whose peer is a {@link MemoryClient}. */
|
|
55
|
+
export declare function memoryTransport(): WebSocketTransport;
|
|
56
|
+
/** Options of `WebSocketPlugin.connect()`. */
|
|
57
|
+
interface WsConnectOptions {
|
|
58
|
+
/** Query parameters appended to the path. */
|
|
59
|
+
readonly query?: Readonly<Record<string, string | readonly string[]>>;
|
|
60
|
+
/** Request headers of the handshake. */
|
|
61
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
62
|
+
/** Offered subprotocols (`sec-websocket-protocol`), in preference order. */
|
|
63
|
+
readonly protocols?: readonly string[];
|
|
64
|
+
/** The `origin` header (a browser's). Default: none, like a non-browser client. */
|
|
65
|
+
readonly origin?: string;
|
|
66
|
+
/** Cookies of the handshake. */
|
|
67
|
+
readonly cookies?: Readonly<Record<string, string>>;
|
|
68
|
+
}
|
|
69
|
+
/** Options of the waiting methods of {@link WsClient}. */
|
|
70
|
+
interface WsWaitOptions {
|
|
71
|
+
/** Default: 1 000 ms (`request()`: 5 000 ms). */
|
|
72
|
+
readonly timeoutMs?: number;
|
|
73
|
+
}
|
|
74
|
+
/** A refused handshake: the HTTP response the server answered. */
|
|
75
|
+
export declare class WsHandshakeError extends Error {
|
|
76
|
+
#private;
|
|
77
|
+
readonly status: number;
|
|
78
|
+
readonly headers: Readonly<Record<string, string | string[]>>;
|
|
79
|
+
readonly body: string;
|
|
80
|
+
constructor(response: InjectResponse);
|
|
81
|
+
/** The body parsed as JSON. */
|
|
82
|
+
json<T = unknown>(): T;
|
|
83
|
+
}
|
|
84
|
+
/** The failure reply of a request (`{ id, error }`). */
|
|
85
|
+
export declare class WsRequestError extends Error {
|
|
86
|
+
readonly code: string;
|
|
87
|
+
readonly details: unknown;
|
|
88
|
+
constructor(event: string, error: {
|
|
89
|
+
readonly code?: unknown;
|
|
90
|
+
readonly message?: unknown;
|
|
91
|
+
readonly details?: unknown;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** An in-memory WebSocket client (`WebSocketPlugin.connect()`, `TestApp.connect()`). */
|
|
95
|
+
export declare class WsClient implements AsyncDisposable {
|
|
96
|
+
#private;
|
|
97
|
+
/** @internal Created by `WebSocketPlugin.connect()` once the handshake succeeded. */
|
|
98
|
+
constructor(peer: MemoryClient);
|
|
99
|
+
/** The negotiated subprotocol, `''` when none. */
|
|
100
|
+
get protocol(): string;
|
|
101
|
+
/** Every frame received, in order: JSON objects decoded, other text frames as strings, binary frames as bytes. */
|
|
102
|
+
get frames(): readonly unknown[];
|
|
103
|
+
/** Resolves once the connection closed (by either side). */
|
|
104
|
+
get closed(): Promise<MemoryCloseInfo>;
|
|
105
|
+
/** Sends an event without id (fire and forget). */
|
|
106
|
+
send(event: string, data?: unknown): void;
|
|
107
|
+
/** Sends a request and resolves with the `data` of its reply; rejects with {@link WsRequestError}. */
|
|
108
|
+
request<T = unknown>(event: string, data?: unknown, options?: WsWaitOptions): Promise<T>;
|
|
109
|
+
/** The `data` of the oldest server event (matching `event`) not taken yet. */
|
|
110
|
+
next<T = unknown>(event?: string, options?: WsWaitOptions): Promise<T>;
|
|
111
|
+
/** Sends a frame as is (a string is a text frame). */
|
|
112
|
+
sendRaw(frame: string | Uint8Array): void;
|
|
113
|
+
/** The oldest frame not taken by `nextRaw()` yet, as received. */
|
|
114
|
+
nextRaw(options?: WsWaitOptions): Promise<string | Uint8Array>;
|
|
115
|
+
/** Closes the connection and resolves with how it closed. */
|
|
116
|
+
close(code?: number, reason?: string): Promise<MemoryCloseInfo>;
|
|
117
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
/** Exceptions of WebSocket handlers and their wire codes (RFC 0003 §5.3, §5.8). */
|
|
120
|
+
/** Built-in error codes of the wire protocol. */
|
|
121
|
+
export declare const WsErrorCode: {
|
|
122
|
+
readonly BadFrame: "BAD_FRAME";
|
|
123
|
+
readonly UnsupportedFrame: "UNSUPPORTED_FRAME";
|
|
124
|
+
readonly BadRequest: "BAD_REQUEST";
|
|
125
|
+
readonly Unauthorized: "UNAUTHORIZED";
|
|
126
|
+
readonly Forbidden: "FORBIDDEN";
|
|
127
|
+
readonly NotFound: "NOT_FOUND";
|
|
128
|
+
readonly Conflict: "CONFLICT";
|
|
129
|
+
readonly Unprocessable: "UNPROCESSABLE";
|
|
130
|
+
readonly RateLimited: "RATE_LIMITED";
|
|
131
|
+
readonly UnknownEvent: "UNKNOWN_EVENT";
|
|
132
|
+
readonly Timeout: "TIMEOUT";
|
|
133
|
+
readonly Internal: "INTERNAL";
|
|
134
|
+
};
|
|
135
|
+
/** Close codes used by the runtime (RFC 0003 §5.8, normative). */
|
|
136
|
+
export declare const WsCloseCode: {
|
|
137
|
+
readonly Normal: 1000;
|
|
138
|
+
readonly GoingAway: 1001;
|
|
139
|
+
readonly PolicyViolation: 1008;
|
|
140
|
+
readonly MessageTooBig: 1009;
|
|
141
|
+
readonly InternalError: 1011;
|
|
142
|
+
readonly TryAgainLater: 1013;
|
|
143
|
+
};
|
|
144
|
+
/** Options of {@link WsException}. */
|
|
145
|
+
interface WsExceptionOptions {
|
|
146
|
+
/** Close the connection with this code after replying. */
|
|
147
|
+
readonly close?: number;
|
|
148
|
+
readonly cause?: unknown;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* An error a handler or a message guard throws to answer the client: a reply with an `id`, an
|
|
152
|
+
* `$error` event otherwise, then a close when `close` is set.
|
|
153
|
+
*
|
|
154
|
+
* ```ts
|
|
155
|
+
* throw new WsException('FORBIDDEN', 'Join the room first')
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export declare class WsException extends Error {
|
|
159
|
+
readonly code: string;
|
|
160
|
+
readonly details: unknown;
|
|
161
|
+
readonly close: number | undefined;
|
|
162
|
+
constructor(code: string, message?: string, details?: unknown, options?: WsExceptionOptions);
|
|
163
|
+
}
|
|
164
|
+
/** One issue of a {@link WsValidationException}. */
|
|
165
|
+
interface WsValidationIssue {
|
|
166
|
+
readonly path: string;
|
|
167
|
+
readonly message: string;
|
|
168
|
+
}
|
|
169
|
+
/** A payload failed its schema: `BAD_REQUEST` with `details: [{ path, message }]`. */
|
|
170
|
+
export declare class WsValidationException extends WsException {
|
|
171
|
+
readonly issues: readonly WsValidationIssue[];
|
|
172
|
+
constructor(issues: readonly WsValidationIssue[], message?: string);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The wire code of an HTTP status thrown by a service (`HttpException`): the table of RFC 0003
|
|
176
|
+
* §5.8, `INTERNAL` for 5xx and unknown statuses.
|
|
177
|
+
*/
|
|
178
|
+
export declare function codeOfStatus(status: number): string;
|
|
179
|
+
/** What handlers (`@Ctx()`) and message guards see of one message. */
|
|
180
|
+
interface WsMessageContext {
|
|
181
|
+
readonly connection: WsConnection;
|
|
182
|
+
/** `undefined` on raw gateways. */
|
|
183
|
+
readonly event: string | undefined;
|
|
184
|
+
readonly id: string | number | undefined;
|
|
185
|
+
/** The decoded `data` (events) or the frame (raw). */
|
|
186
|
+
readonly data: unknown;
|
|
187
|
+
readonly binary: boolean;
|
|
188
|
+
readonly bytes: number;
|
|
189
|
+
/** `performance.now()` when the message was received. */
|
|
190
|
+
readonly receivedAt: number;
|
|
191
|
+
/** Aborted on timeout or when the connection closes. */
|
|
192
|
+
readonly signal: AbortSignal;
|
|
193
|
+
/** Per message: guards to handler. */
|
|
194
|
+
readonly state: Map<string | symbol, unknown>;
|
|
195
|
+
readonly route: {
|
|
196
|
+
readonly path: string;
|
|
197
|
+
readonly gateway: Token;
|
|
198
|
+
readonly handler: string | undefined;
|
|
199
|
+
readonly event: string | undefined;
|
|
200
|
+
readonly meta: Readonly<Record<string, unknown>>;
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/** A guard run before each message handler: `false` answers `FORBIDDEN`. */
|
|
204
|
+
interface WsGuard {
|
|
205
|
+
canHandle(ctx: WsMessageContext): boolean | Promise<boolean>;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Maps an error thrown by a message handler or guard to the {@link WsException} answered to the
|
|
209
|
+
* client (plugin option `exceptionMappers`, run in order before the built-in mapping). `undefined`:
|
|
210
|
+
* not handled, the next mapper or the built-in mapping applies.
|
|
211
|
+
*/
|
|
212
|
+
interface WsExceptionMapper {
|
|
213
|
+
map(error: unknown, ctx: WsMessageContext): WsException | undefined | Promise<WsException | undefined>;
|
|
214
|
+
}
|
|
215
|
+
/** The gateways of the application, sorted by token. */
|
|
216
|
+
interface WebSocketMetadata {
|
|
217
|
+
readonly gateways: readonly GatewayDefinition[];
|
|
218
|
+
/**
|
|
219
|
+
* Route decorator groups the runtime needs (required, holding several keys, or named differently
|
|
220
|
+
* from their key), as `metadata.extensions.http.groups`. Absent when no group needs it.
|
|
221
|
+
*/
|
|
222
|
+
readonly groups?: Readonly<Record<string, {
|
|
223
|
+
readonly keys: readonly string[];
|
|
224
|
+
readonly required: boolean;
|
|
225
|
+
}>>;
|
|
226
|
+
}
|
|
227
|
+
/** One `@Gateway` class. Optional fields are omitted when absent. */
|
|
228
|
+
interface GatewayDefinition {
|
|
229
|
+
readonly token: Token;
|
|
230
|
+
/** The normalized `@Gateway` path, without the `HttpPlugin` prefix. */
|
|
231
|
+
readonly path: string;
|
|
232
|
+
readonly protocol: "events" | "raw";
|
|
233
|
+
readonly protocols?: readonly string[];
|
|
234
|
+
/** Bytes. */
|
|
235
|
+
readonly maxPayload?: number;
|
|
236
|
+
readonly concurrency?: number;
|
|
237
|
+
readonly rateLimit?: {
|
|
238
|
+
readonly messages: number;
|
|
239
|
+
readonly intervalMs: number;
|
|
240
|
+
readonly onLimit: "reject" | "close";
|
|
241
|
+
};
|
|
242
|
+
/** `limit` in bytes. */
|
|
243
|
+
readonly backpressure?: {
|
|
244
|
+
readonly limit?: number;
|
|
245
|
+
readonly onLimit?: "close" | "drop";
|
|
246
|
+
};
|
|
247
|
+
/** Route decorators of the class: handshake and messages. */
|
|
248
|
+
readonly meta: Readonly<Record<string, unknown>>;
|
|
249
|
+
/** `@UseHandshakeGuard`, in order. */
|
|
250
|
+
readonly handshakeGuards: readonly Token[];
|
|
251
|
+
/** `@UseMessageGuard` on the class, in order. */
|
|
252
|
+
readonly messageGuards: readonly Token[];
|
|
253
|
+
readonly onConnect?: WsLifecycleDefinition;
|
|
254
|
+
readonly onDisconnect?: WsLifecycleDefinition;
|
|
255
|
+
/** Declaration order, bases first. */
|
|
256
|
+
readonly handlers: readonly WsHandlerDefinition[];
|
|
257
|
+
}
|
|
258
|
+
/** `@OnConnect` or `@OnDisconnect`. */
|
|
259
|
+
interface WsLifecycleDefinition {
|
|
260
|
+
readonly method: string;
|
|
261
|
+
readonly invoke: (gateway: any, connection: WsConnection) => unknown;
|
|
262
|
+
}
|
|
263
|
+
/** A parameter of a handler (informational). */
|
|
264
|
+
interface WsParamDefinition {
|
|
265
|
+
readonly index: number;
|
|
266
|
+
readonly source: "payload" | "connection" | "context";
|
|
267
|
+
readonly schema?: boolean;
|
|
268
|
+
readonly optional?: boolean;
|
|
269
|
+
}
|
|
270
|
+
/** One `@OnMessage` handler. */
|
|
271
|
+
interface WsHandlerDefinition {
|
|
272
|
+
readonly method: string;
|
|
273
|
+
/** Absent: the default handler. */
|
|
274
|
+
readonly event?: string;
|
|
275
|
+
/** Route decorators of the method, merged over the gateway's at boot (nearest wins). */
|
|
276
|
+
readonly meta: Readonly<Record<string, unknown>>;
|
|
277
|
+
/** `@UseMessageGuard` on the method. */
|
|
278
|
+
readonly guards: readonly Token[];
|
|
279
|
+
readonly params: readonly WsParamDefinition[];
|
|
280
|
+
readonly invoke: (gateway: any, ctx: WsMessageContext) => unknown;
|
|
281
|
+
}
|
|
282
|
+
declare module "@znight/core" {
|
|
283
|
+
interface ZnightExtensionsMetadata {
|
|
284
|
+
readonly websocket?: WebSocketMetadata;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/** Options of `@Gateway` (RFC 0003 §5.2), all static: the compiler reads them. */
|
|
288
|
+
interface GatewayOptions {
|
|
289
|
+
/** HTTP path grammar (`/chat`, `/docs/:docId`, `/feeds/*`). Default: `'/'`. */
|
|
290
|
+
readonly path?: string;
|
|
291
|
+
/** `'request'`: one gateway instance per connection. Default: `'singleton'`. */
|
|
292
|
+
readonly scope?: "singleton" | "request";
|
|
293
|
+
/** `'events'` (envelope, routing by event) or `'raw'` (one default handler). Default: `'events'`. */
|
|
294
|
+
readonly protocol?: "events" | "raw";
|
|
295
|
+
/** Accepted subprotocols, in preference order: a client offering none of them is refused (400). */
|
|
296
|
+
readonly protocols?: readonly string[];
|
|
297
|
+
/** Largest inbound message (`'64kb'` or bytes). Default: the plugin `maxPayload`. */
|
|
298
|
+
readonly maxPayload?: string | number;
|
|
299
|
+
/** Messages of one connection handled in parallel. Default: `1` (keeps the order). */
|
|
300
|
+
readonly concurrency?: number;
|
|
301
|
+
/** A token bucket per connection. */
|
|
302
|
+
readonly rateLimit?: RateLimitOptions;
|
|
303
|
+
/** Outbound buffer limit and what to do above it. Default: the plugin `backpressure`. */
|
|
304
|
+
readonly backpressure?: BackpressureOptions;
|
|
305
|
+
}
|
|
306
|
+
/** `@Gateway({ rateLimit })`. */
|
|
307
|
+
interface RateLimitOptions {
|
|
308
|
+
readonly messages: number;
|
|
309
|
+
readonly intervalMs: number;
|
|
310
|
+
/** `'reject'` answers `RATE_LIMITED` (default), `'close'` closes with `4429`. */
|
|
311
|
+
readonly onLimit?: "reject" | "close";
|
|
312
|
+
}
|
|
313
|
+
/** `@Gateway({ backpressure })` and the plugin option. */
|
|
314
|
+
interface BackpressureOptions {
|
|
315
|
+
/** Buffered outbound bytes above which `onLimit` applies (`'1mb'` or bytes). */
|
|
316
|
+
readonly limit?: string | number;
|
|
317
|
+
/** `'close'` closes with `1013` (default), `'drop'` drops the message. */
|
|
318
|
+
readonly onLimit?: "close" | "drop";
|
|
319
|
+
}
|
|
320
|
+
/** `'same-origin'`, `'*'`, exact origins and anchored `RegExp`s, or a function (RFC 0003 §5.6). */
|
|
321
|
+
type WsOrigins = "same-origin" | "*" | string | RegExp | readonly (string | RegExp)[] | ((origin: string, ctx: HttpContext) => boolean | Promise<boolean>);
|
|
322
|
+
/** A message guard or an exception mapper: a provider class or an instance. */
|
|
323
|
+
type WsProviderRef<T> = (abstract new (...args: never[]) => T) | T;
|
|
324
|
+
/** Options of `WebSocketPlugin.configure()`. */
|
|
325
|
+
interface WebSocketPluginOptions {
|
|
326
|
+
/** `'auto'` (default): Bun's native transport with `honoAdapter()` on Bun, `ws` otherwise. */
|
|
327
|
+
readonly transport?: "auto" | WebSocketTransport;
|
|
328
|
+
/** Allowed `Origin`s of handshakes. Default: `'same-origin'` (and requests without `Origin`). */
|
|
329
|
+
readonly origins?: WsOrigins;
|
|
330
|
+
/** Largest inbound message (`'1mb'` or bytes). Default: `'1mb'`. Gateways may lower it. */
|
|
331
|
+
readonly maxPayload?: ByteSize;
|
|
332
|
+
/** Open connections per process; above, handshakes get `503`. Default: `Infinity`. */
|
|
333
|
+
readonly maxConnections?: number;
|
|
334
|
+
/** Inbound queue per connection before reading pauses. Default: `32`. */
|
|
335
|
+
readonly maxPendingMessages?: number;
|
|
336
|
+
/** Outbound buffer per connection. Default: `{ limit: '1mb', onLimit: 'close' }`. */
|
|
337
|
+
readonly backpressure?: BackpressureOptions;
|
|
338
|
+
/** Ping interval; `false` disables heartbeats. Default: `{ intervalMs: 30_000 }`. */
|
|
339
|
+
readonly heartbeat?: {
|
|
340
|
+
readonly intervalMs: number;
|
|
341
|
+
} | false;
|
|
342
|
+
/** Handshakes whose guards have not answered by then get `408`. Default: `10_000`. */
|
|
343
|
+
readonly handshakeTimeoutMs?: number;
|
|
344
|
+
/** Per message and per `@OnConnect`: `TIMEOUT`. `Infinity` disables. Default: `30_000`. */
|
|
345
|
+
readonly handlerTimeoutMs?: number;
|
|
346
|
+
/** Wait for the client's close frame before terminating. Default: `2_000`. */
|
|
347
|
+
readonly closeTimeoutMs?: number;
|
|
348
|
+
/** The codec of `events` gateways. Default: `jsonCodec` (JSON text frames). */
|
|
349
|
+
readonly codec?: WsCodec;
|
|
350
|
+
/** Global message guards, run before the gateway's and the handler's. */
|
|
351
|
+
readonly messageGuards?: readonly WsProviderRef<WsGuard>[];
|
|
352
|
+
/** Exception mappers of message handlers and guards, in order. */
|
|
353
|
+
readonly exceptionMappers?: readonly WsProviderRef<WsExceptionMapper>[];
|
|
354
|
+
/** Send the message of unexpected errors (`INTERNAL`). Default: `false`. */
|
|
355
|
+
readonly exposeErrors?: boolean;
|
|
356
|
+
/** Graceful shutdown. Default: `{ code: 1001, reason: 'Server shutting down', timeoutMs: 3_000 }`. */
|
|
357
|
+
readonly shutdown?: {
|
|
358
|
+
readonly code?: number;
|
|
359
|
+
readonly reason?: string;
|
|
360
|
+
readonly timeoutMs?: number;
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
/** A class decorator marker. */
|
|
364
|
+
type GatewayClassMarker = (target: abstract new (...args: never[]) => unknown) => void;
|
|
365
|
+
/** A method decorator marker. */
|
|
366
|
+
type GatewayMethodMarker = (target: object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
367
|
+
/** A parameter decorator marker. */
|
|
368
|
+
type GatewayParameterMarker = (target: object, propertyKey: string | symbol | undefined, index: number) => void;
|
|
369
|
+
/** A class or method decorator marker. */
|
|
370
|
+
type GatewayClassOrMethodMarker = (target: object, propertyKey?: string | symbol, descriptor?: unknown) => void;
|
|
371
|
+
/**
|
|
372
|
+
* A provider whose methods handle the WebSocket connections of `path` (default `/`), joined to the
|
|
373
|
+
* `HttpPlugin` prefix.
|
|
374
|
+
*
|
|
375
|
+
* ```ts
|
|
376
|
+
* @Gateway({ path: '/chat', protocols: ['chat.v1'] })
|
|
377
|
+
* export class ChatGateway {}
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
export declare function Gateway(_pathOrOptions?: string | GatewayOptions): GatewayClassMarker;
|
|
381
|
+
/** Runs once the handshake succeeded, before any message. Throwing closes the connection. */
|
|
382
|
+
export declare function OnConnect(): GatewayMethodMarker;
|
|
383
|
+
/**
|
|
384
|
+
* Handles an event (`events` protocol). Without `event`: the default handler (unknown events, every
|
|
385
|
+
* message of a `raw` gateway). Repeatable.
|
|
386
|
+
*/
|
|
387
|
+
export declare function OnMessage(_event?: string): GatewayMethodMarker;
|
|
388
|
+
/** Runs once per connection whose `@OnConnect` completed, before rooms are left and the scope closes. */
|
|
389
|
+
export declare function OnDisconnect(): GatewayMethodMarker;
|
|
390
|
+
/** The message `data` (`events`) or the raw frame (`raw`), validated by `schema` (a Standard Schema). */
|
|
391
|
+
export declare function Payload(_schema?: unknown): GatewayParameterMarker;
|
|
392
|
+
/** The `WsConnection` of the message or of the lifecycle method. */
|
|
393
|
+
export declare function Conn(): GatewayParameterMarker;
|
|
394
|
+
/** The `WsMessageContext` (`@OnMessage` handlers only). */
|
|
395
|
+
export declare function Ctx(): GatewayParameterMarker;
|
|
396
|
+
/** Extra HTTP guards (`CanActivate`) of the handshake, after the `HttpPlugin` global guards. */
|
|
397
|
+
export declare function UseHandshakeGuard(..._guards: readonly unknown[]): GatewayClassMarker;
|
|
398
|
+
/** Message guards (`WsGuard`) run before each handler: global, then class, then method. */
|
|
399
|
+
export declare function UseMessageGuard(..._guards: readonly unknown[]): GatewayClassOrMethodMarker;
|
|
400
|
+
/** A served gateway, as listed by {@link WebSocketPlugin.gateways}. */
|
|
401
|
+
interface WsGatewaySummary {
|
|
402
|
+
/** The path, HTTP prefix included. */
|
|
403
|
+
readonly path: string;
|
|
404
|
+
/** Display name of the gateway class. */
|
|
405
|
+
readonly gateway: string;
|
|
406
|
+
readonly protocol: "events" | "raw";
|
|
407
|
+
/** Handled events (`events` gateways), in declaration order. */
|
|
408
|
+
readonly events: readonly string[];
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* The WebSocket plugin: `WebSocketPlugin.configure(options)` (name `websocket`). Requires
|
|
412
|
+
* `HttpPlugin`: gateways are served on its server and port, whatever the plugin order.
|
|
413
|
+
*
|
|
414
|
+
* ```ts
|
|
415
|
+
* await Application.create({
|
|
416
|
+
* metadata: __ZNIGHT_METADATA__,
|
|
417
|
+
* plugins: [HttpPlugin.configure({ port: 3000 }), WebSocketPlugin.configure({ maxPayload: '64kb' })],
|
|
418
|
+
* })
|
|
419
|
+
* ```
|
|
420
|
+
*/
|
|
421
|
+
export declare class WebSocketPlugin implements Plugin, PluginHttpUpgrades {
|
|
422
|
+
#private;
|
|
423
|
+
readonly name = "websocket";
|
|
424
|
+
/** The `WsServer` of the application (also injectable). */
|
|
425
|
+
readonly server: WsServer;
|
|
426
|
+
private constructor();
|
|
427
|
+
/**
|
|
428
|
+
* Creates the plugin. `options` may be a function of the container, evaluated once the container
|
|
429
|
+
* is initialised: `WebSocketPlugin.configure(c => ({ origins: c.get(ServerConfig).webOrigins }))`.
|
|
430
|
+
*/
|
|
431
|
+
static configure(options?: PluginOptions<WebSocketPluginOptions>): WebSocketPlugin;
|
|
432
|
+
/** Name of the transport (`ws`, `bun`), `undefined` before `HttpPlugin` collected the upgrade routes. */
|
|
433
|
+
get transport(): string | undefined;
|
|
434
|
+
/** The served gateways (after bootstrap). */
|
|
435
|
+
get gateways(): readonly WsGatewaySummary[];
|
|
436
|
+
/** Open connections of every gateway. */
|
|
437
|
+
get connections(): number;
|
|
438
|
+
/** Totals since the application started. */
|
|
439
|
+
stats(): WsStats;
|
|
440
|
+
/**
|
|
441
|
+
* Providers `TestApp` creates at boot: the classes of the `messageGuards` and `exceptionMappers`
|
|
442
|
+
* options, and the gateways of the metadata with their guards.
|
|
443
|
+
*/
|
|
444
|
+
initRoots(context?: PluginRootsContext): readonly ProviderKey[];
|
|
445
|
+
register(ctx: PluginContext): void;
|
|
446
|
+
onBootstrap(ctx: PluginContext): void;
|
|
447
|
+
/**
|
|
448
|
+
* The `PluginHttpUpgrades` contract of `@znight/http`: one upgrade route per gateway, and the
|
|
449
|
+
* `Bun.serve()` settings of the Bun transport. Called once by `HttpPlugin.onBootstrap`. No route
|
|
450
|
+
* (and no transport) without gateways.
|
|
451
|
+
*/
|
|
452
|
+
httpUpgrades(context: PluginHttpUpgradesContext): PluginUpgrades;
|
|
453
|
+
onStart(): Promise<void>;
|
|
454
|
+
/**
|
|
455
|
+
* The `PluginHttpRoutes` contract: `HttpPlugin` starts draining, whatever the plugin order.
|
|
456
|
+
* Refuses new handshakes and closes every connection gracefully (see {@link onStop}).
|
|
457
|
+
*/
|
|
458
|
+
onHttpDrain(): Promise<void>;
|
|
459
|
+
/**
|
|
460
|
+
* Refuses handshakes (`503`), closes every connection with `shutdown.code`, waits for close
|
|
461
|
+
* frames, running handlers and `@OnDisconnect` up to `shutdown.timeoutMs`, then terminates the
|
|
462
|
+
* rest. Idempotent: the same drain as {@link onHttpDrain}.
|
|
463
|
+
*/
|
|
464
|
+
onStop(): Promise<void>;
|
|
465
|
+
onDispose(): Promise<void>;
|
|
466
|
+
/**
|
|
467
|
+
* Opens an in-memory connection (tests): the real handshake through the HTTP pipeline (guards,
|
|
468
|
+
* hooks, origin and subprotocol checks) with an in-memory request, then the in-memory transport.
|
|
469
|
+
* `path` is the URL path, HTTP prefix included. Rejects with {@link WsHandshakeError} when the
|
|
470
|
+
* handshake is refused.
|
|
471
|
+
*
|
|
472
|
+
* ```ts
|
|
473
|
+
* await using alice = await plugin.connect('/chat', { protocols: ['chat.v1'] })
|
|
474
|
+
* expect(await alice.request('room.join', { room: 'general' })).toEqual({ members: 1 })
|
|
475
|
+
* ```
|
|
476
|
+
*/
|
|
477
|
+
connect(path: string, options?: WsConnectOptions): Promise<WsClient>;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Tokens of the values `@znight/websocket` supplies to the container. `WsConnection` is a
|
|
481
|
+
* request-scoped external: the request scope of a WebSocket handshake lasts as long as its
|
|
482
|
+
* connection. Inject it in request-scoped providers (`@Gateway({ scope: 'request' })`) or through
|
|
483
|
+
* `Lazy<WsConnection>`.
|
|
484
|
+
*/
|
|
485
|
+
export declare const WsTokens: {
|
|
486
|
+
/** The {@link WsServer} of the application (singleton). */
|
|
487
|
+
readonly Server: TypedToken<WsServer>;
|
|
488
|
+
/** The {@link WebSocketPlugin} instance (singleton). */
|
|
489
|
+
readonly Plugin: TypedToken<WebSocketPlugin>;
|
|
490
|
+
/** The {@link WsConnection} of the current connection (request scope). */
|
|
491
|
+
readonly Connection: TypedToken<WsConnection>;
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* Validates a message payload with a Standard Schema and returns the schema output, synchronously
|
|
495
|
+
* when the schema is synchronous.
|
|
496
|
+
*
|
|
497
|
+
* @throws WsValidationException (`BAD_REQUEST`, `details: [{ path, message }]`) when the payload is invalid.
|
|
498
|
+
*/
|
|
499
|
+
export declare function validatePayload<S extends StandardSchemaV1>(schema: S, value: unknown): InferSchemaOutput<S> | Promise<InferSchemaOutput<S>>;
|
|
500
|
+
export { type AcceptInit, type BackpressureOptions, type Broadcast, type ChannelMember, EVENT_NAME, type GatewayChannel, type GatewayClassMarker, type GatewayClassOrMethodMarker, type GatewayDefinition, type GatewayMethodMarker, type GatewayOptions, type GatewayParameterMarker, type GatewayRef, type InboundFailure, type InboundMessage, type MemberRef, type MemoryCloseInfo, type MessageId, type OutboundMessage, type RateLimitOptions, RoomRegistry, type SendStatus, type ServedGateway, type SocketEvents, TokenBucket, type TransportSettings, type TransportSocket, type WebSocketMetadata, type WebSocketPluginOptions, type WebSocketTransport, type WireError, type WsCloseInfo, type WsCloseInitiator, WsClosedError, type WsCodec, type WsConnectOptions, type WsConnection, type WsExceptionMapper, type WsExceptionOptions, type WsGatewaySummary, type WsGuard, type WsHandlerDefinition, type WsLifecycleDefinition, type WsMessageContext, type WsOrigins, type WsParamDefinition, type WsProviderRef, type WsSendResult, WsServer, type WsStats, type WsValidationIssue, type WsWaitOptions, decodeFrame, encodeErrorEvent, encodeErrorReply, encodeEvent, encodeReply, isFailure, isMessageId, jsonCodec };
|
|
501
|
+
//# sourceMappingURL=index.d.mts.map
|