tina4-nodejs 3.13.92 → 3.13.95
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/CLAUDE.md +170 -28
- package/README.md +2 -2
- package/package.json +13 -9
- package/packages/cli/dist/bin.js +33126 -30055
- package/packages/cli/src/commands/metrics.ts +17 -11
- package/packages/cli/src/commands/serve.ts +10 -9
- package/packages/core/dist/index.js +33062 -29908
- package/packages/core/src/ai.ts +7 -1
- package/packages/core/src/auth.ts +191 -39
- package/packages/core/src/background.ts +19 -19
- package/packages/core/src/cache.ts +492 -49
- package/packages/core/src/devAdmin.ts +79 -32
- package/packages/core/src/devMailbox.ts +20 -44
- package/packages/core/src/dispatchPipeline.ts +285 -0
- package/packages/core/src/dotenv.ts +185 -40
- package/packages/core/src/index.ts +7 -6
- package/packages/core/src/logger.ts +257 -36
- package/packages/core/src/mcp.ts +1 -1
- package/packages/core/src/messenger.ts +81 -13
- package/packages/core/src/metrics.ts +199 -961
- package/packages/core/src/middleware.ts +390 -123
- package/packages/core/src/queue.ts +188 -32
- package/packages/core/src/queueBackends/kafkaBackend.ts +109 -13
- package/packages/core/src/queueBackends/liteBackend.ts +13 -0
- package/packages/core/src/queueBackends/mongoBackend.ts +101 -9
- package/packages/core/src/queueBackends/rabbitmqBackend.ts +22 -4
- package/packages/core/src/rateLimiter.ts +10 -5
- package/packages/core/src/request.ts +6 -9
- package/packages/core/src/response.ts +46 -1
- package/packages/core/src/router.ts +29 -4
- package/packages/core/src/server.ts +751 -414
- package/packages/core/src/session.ts +244 -27
- package/packages/core/src/sessionHandlers/childError.ts +72 -0
- package/packages/core/src/sessionHandlers/databaseHandler.ts +338 -48
- package/packages/core/src/sessionHandlers/memcachedHandler.ts +181 -0
- package/packages/core/src/sessionHandlers/mongoClient.ts +293 -202
- package/packages/core/src/sessionHandlers/mongoHandler.ts +88 -8
- package/packages/core/src/sessionHandlers/respClient.ts +16 -143
- package/packages/core/src/sessionHandlers/sqlClient.ts +290 -0
- package/packages/core/src/sessionHandlers/syncBridge.ts +190 -0
- package/packages/core/src/sessionHandlers/syncSocket.ts +236 -0
- package/packages/core/src/testClient.ts +18 -5
- package/packages/core/src/trustedProxy.ts +249 -0
- package/packages/core/src/types.ts +29 -5
- package/packages/core/src/websocket.ts +66 -0
- package/packages/frond/dist/index.js +74 -31
- package/packages/frond/src/engine.ts +99 -33
- package/packages/orm/dist/index.js +26554 -23400
- package/packages/orm/src/adapters/firebird.ts +183 -56
- package/packages/orm/src/adapters/mongodb.ts +25 -4
- package/packages/orm/src/adapters/mssql.ts +114 -29
- package/packages/orm/src/adapters/mysql.ts +103 -40
- package/packages/orm/src/adapters/odbc.ts +44 -21
- package/packages/orm/src/adapters/postgres.ts +118 -26
- package/packages/orm/src/adapters/sqlDialect.ts +120 -0
- package/packages/orm/src/adapters/sqlite.ts +64 -25
- package/packages/orm/src/baseModel.ts +135 -40
- package/packages/orm/src/cachedDatabase.ts +43 -19
- package/packages/orm/src/connectTimeout.ts +265 -0
- package/packages/orm/src/database.ts +338 -198
- package/packages/orm/src/databaseResult.ts +65 -13
- package/packages/orm/src/databaseUrl.ts +484 -0
- package/packages/orm/src/docstore.ts +386 -145
- package/packages/orm/src/index.ts +13 -3
- package/packages/orm/src/migration.ts +18 -3
- package/packages/orm/src/queryBuilder.ts +38 -4
- package/packages/orm/src/sqlTranslator.ts +310 -4
- package/packages/orm/src/types.ts +15 -4
- package/types/cli/src/bin.d.ts +92 -0
- package/types/cli/src/commands/build.d.ts +2 -0
- package/types/cli/src/commands/generate.d.ts +47 -0
- package/types/cli/src/commands/init.d.ts +1 -0
- package/types/cli/src/commands/metrics.d.ts +6 -0
- package/types/cli/src/commands/migrate.d.ts +1 -0
- package/types/cli/src/commands/migrateCreate.d.ts +1 -0
- package/types/cli/src/commands/migrateRollback.d.ts +1 -0
- package/types/cli/src/commands/migrateStatus.d.ts +1 -0
- package/types/cli/src/commands/queue.d.ts +20 -0
- package/types/cli/src/commands/routes.d.ts +1 -0
- package/types/cli/src/commands/seed.d.ts +1 -0
- package/types/cli/src/commands/serve.d.ts +6 -0
- package/types/cli/src/commands/test.d.ts +1 -0
- package/types/core/src/ai.d.ts +64 -0
- package/types/core/src/api.d.ts +262 -0
- package/types/core/src/auth.d.ts +177 -0
- package/types/core/src/authGate.d.ts +20 -0
- package/types/core/src/background.d.ts +34 -0
- package/types/core/src/cache.d.ts +163 -0
- package/types/core/src/constants.d.ts +38 -0
- package/types/core/src/container.d.ts +44 -0
- package/types/core/src/context/chunker.d.ts +31 -0
- package/types/core/src/context/index.d.ts +93 -0
- package/types/core/src/devAdmin.d.ts +179 -0
- package/types/core/src/devMailbox.d.ts +54 -0
- package/types/core/src/dispatchPipeline.d.ts +117 -0
- package/types/core/src/docs.d.ts +141 -0
- package/types/core/src/docsAutoDiscovery.d.ts +6 -0
- package/types/core/src/dotenv.d.ts +87 -0
- package/types/core/src/env.d.ts +28 -0
- package/types/core/src/errorOverlay.d.ts +36 -0
- package/types/core/src/events.d.ts +75 -0
- package/types/core/src/fakeData.d.ts +55 -0
- package/types/core/src/feedback.d.ts +90 -0
- package/types/core/src/graphql.d.ts +207 -0
- package/types/core/src/health.d.ts +22 -0
- package/types/core/src/htmlElement.d.ts +75 -0
- package/types/core/src/i18n.d.ts +37 -0
- package/types/core/src/index.d.ts +92 -0
- package/types/core/src/job.d.ts +39 -0
- package/types/core/src/logger.d.ts +200 -0
- package/types/core/src/mcp.d.ts +248 -0
- package/types/core/src/messenger.d.ts +191 -0
- package/types/core/src/metrics.d.ts +41 -0
- package/types/core/src/middleware.d.ts +330 -0
- package/types/core/src/mqtt.d.ts +257 -0
- package/types/core/src/mqttMessage.d.ts +67 -0
- package/types/core/src/plan.d.ts +96 -0
- package/types/core/src/projectIndex.d.ts +56 -0
- package/types/core/src/queue.d.ts +268 -0
- package/types/core/src/queueBackends/kafkaBackend.d.ts +117 -0
- package/types/core/src/queueBackends/liteBackend.d.ts +128 -0
- package/types/core/src/queueBackends/mongoBackend.d.ts +119 -0
- package/types/core/src/queueBackends/rabbitmqBackend.d.ts +55 -0
- package/types/core/src/rateLimiter.d.ts +49 -0
- package/types/core/src/request.d.ts +25 -0
- package/types/core/src/response.d.ts +28 -0
- package/types/core/src/routeDiscovery.d.ts +12 -0
- package/types/core/src/router.d.ts +366 -0
- package/types/core/src/scss.d.ts +19 -0
- package/types/core/src/server.d.ts +146 -0
- package/types/core/src/service.d.ts +115 -0
- package/types/core/src/session.d.ts +341 -0
- package/types/core/src/sessionHandlers/childError.d.ts +34 -0
- package/types/core/src/sessionHandlers/databaseHandler.d.ts +97 -0
- package/types/core/src/sessionHandlers/memcachedHandler.d.ts +60 -0
- package/types/core/src/sessionHandlers/mongoClient.d.ts +35 -0
- package/types/core/src/sessionHandlers/mongoHandler.d.ts +109 -0
- package/types/core/src/sessionHandlers/respClient.d.ts +22 -0
- package/types/core/src/sessionHandlers/sqlClient.d.ts +39 -0
- package/types/core/src/sessionHandlers/syncBridge.d.ts +91 -0
- package/types/core/src/sessionHandlers/syncSocket.d.ts +49 -0
- package/types/core/src/sessionHandlers/valkeyHandler.d.ts +65 -0
- package/types/core/src/static.d.ts +2 -0
- package/types/core/src/test.d.ts +94 -0
- package/types/core/src/testClient.d.ts +36 -0
- package/types/core/src/testing.d.ts +58 -0
- package/types/core/src/trustedProxy.d.ts +44 -0
- package/types/core/src/types.d.ts +242 -0
- package/types/core/src/validator.d.ts +52 -0
- package/types/core/src/websocket.d.ts +402 -0
- package/types/core/src/websocketBackplane.d.ts +166 -0
- package/types/core/src/websocketConnection.d.ts +54 -0
- package/types/core/src/wsdl.d.ts +101 -0
- package/types/frond/src/engine.d.ts +263 -0
- package/types/frond/src/index.d.ts +2 -0
- package/types/orm/src/adapters/firebird.d.ts +183 -0
- package/types/orm/src/adapters/mongodb.d.ts +81 -0
- package/types/orm/src/adapters/mssql.d.ts +77 -0
- package/types/orm/src/adapters/mysql.d.ts +67 -0
- package/types/orm/src/adapters/odbc.d.ts +94 -0
- package/types/orm/src/adapters/postgres.d.ts +86 -0
- package/types/orm/src/adapters/sqlDialect.d.ts +71 -0
- package/types/orm/src/adapters/sqlite.d.ts +68 -0
- package/types/orm/src/autoCrud.d.ts +73 -0
- package/types/orm/src/baseModel.d.ts +427 -0
- package/types/orm/src/cachedDatabase.d.ts +190 -0
- package/types/orm/src/connectTimeout.d.ts +100 -0
- package/types/orm/src/database.d.ts +655 -0
- package/types/orm/src/databaseResult.d.ts +109 -0
- package/types/orm/src/databaseUrl.d.ts +125 -0
- package/types/orm/src/docstore.d.ts +241 -0
- package/types/orm/src/fakeData.d.ts +22 -0
- package/types/orm/src/index.d.ts +43 -0
- package/types/orm/src/migration.d.ts +275 -0
- package/types/orm/src/model.d.ts +7 -0
- package/types/orm/src/query.d.ts +14 -0
- package/types/orm/src/queryBuilder.d.ts +193 -0
- package/types/orm/src/realtime/index.d.ts +7 -0
- package/types/orm/src/realtime/models/attachment.d.ts +43 -0
- package/types/orm/src/realtime/models/channel.d.ts +32 -0
- package/types/orm/src/realtime/models/channelMember.d.ts +32 -0
- package/types/orm/src/realtime/models/message.d.ts +36 -0
- package/types/orm/src/realtime/models/workspace.d.ts +26 -0
- package/types/orm/src/realtime/realtime.d.ts +24 -0
- package/types/orm/src/realtime/storage.d.ts +61 -0
- package/types/orm/src/seeder.d.ts +118 -0
- package/types/orm/src/sqlTranslator.d.ts +258 -0
- package/types/orm/src/types.d.ts +148 -0
- package/types/orm/src/validation.d.ts +6 -0
- package/types/swagger/src/generator.d.ts +46 -0
- package/types/swagger/src/index.d.ts +2 -0
- package/types/swagger/src/ui.d.ts +11 -0
- package/packages/core/src/sessionHandlers/redisHandler.ts +0 -206
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tina4 WebSocket — Zero-dependency RFC 6455 implementation.
|
|
3
|
+
*
|
|
4
|
+
* Native WebSocket server using Node.js built-in `http` module.
|
|
5
|
+
*
|
|
6
|
+
* import { WebSocketServer } from "@tina4/core";
|
|
7
|
+
*
|
|
8
|
+
* const wss = new WebSocketServer({ port: 8080 });
|
|
9
|
+
* wss.on("open", (client) => {
|
|
10
|
+
* console.log("Connected:", client.id);
|
|
11
|
+
* });
|
|
12
|
+
* wss.on("message", (client, message) => {
|
|
13
|
+
* wss.broadcast(message);
|
|
14
|
+
* });
|
|
15
|
+
* await wss.start();
|
|
16
|
+
*
|
|
17
|
+
* Supported:
|
|
18
|
+
* - HTTP Upgrade handshake (RFC 6455 Sec-WebSocket-Accept)
|
|
19
|
+
* - Frame protocol: text, binary, close, ping, pong
|
|
20
|
+
* - Masking / unmasking (client->server)
|
|
21
|
+
* - Extended payload lengths (7-bit, 16-bit, 64-bit)
|
|
22
|
+
* - Connection manager with broadcast
|
|
23
|
+
*/
|
|
24
|
+
import { IncomingMessage } from "node:http";
|
|
25
|
+
import type { Socket } from "node:net";
|
|
26
|
+
import type { WebSocketConnection } from "./websocketConnection.js";
|
|
27
|
+
export declare const OP_CONTINUATION = 0;
|
|
28
|
+
export declare const OP_TEXT = 1;
|
|
29
|
+
export declare const OP_BINARY = 2;
|
|
30
|
+
export declare const OP_CLOSE = 8;
|
|
31
|
+
export declare const OP_PING = 9;
|
|
32
|
+
export declare const OP_PONG = 10;
|
|
33
|
+
export declare const CLOSE_NORMAL = 1000;
|
|
34
|
+
export declare const CLOSE_GOING_AWAY = 1001;
|
|
35
|
+
export declare const CLOSE_PROTOCOL_ERROR = 1002;
|
|
36
|
+
export declare const CLOSE_POLICY_VIOLATION = 1008;
|
|
37
|
+
export interface WebSocketClient {
|
|
38
|
+
id: string;
|
|
39
|
+
socket: Socket;
|
|
40
|
+
ip: string;
|
|
41
|
+
connectedAt: number;
|
|
42
|
+
closed: boolean;
|
|
43
|
+
/** The URL path this client connected on (e.g. "/chat", "/notifications"). */
|
|
44
|
+
path: string;
|
|
45
|
+
/**
|
|
46
|
+
* Epoch ms of the last inbound frame. Updated on every frame; the idle
|
|
47
|
+
* reaper closes connections silent longer than `TINA4_WS_IDLE_TIMEOUT`
|
|
48
|
+
* (opt-in). Optional so externally-injected/legacy client objects still fit.
|
|
49
|
+
*/
|
|
50
|
+
lastActivity?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Verified JWT payload when this client connected on a secured WS route, or
|
|
53
|
+
* `null` on a public route. Mirrors Python's `connection.auth`. Optional so
|
|
54
|
+
* externally-injected/legacy client objects still fit.
|
|
55
|
+
*/
|
|
56
|
+
auth?: Record<string, unknown> | null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Compute Sec-WebSocket-Accept from Sec-WebSocket-Key per RFC 6455.
|
|
60
|
+
*/
|
|
61
|
+
/**
|
|
62
|
+
* Build an RFC 6455 close frame carrying a status code and optional reason.
|
|
63
|
+
*
|
|
64
|
+
* The code is a big-endian uint16 in the first two payload bytes (s5.5.1), so
|
|
65
|
+
* a peer that only reads the code still gets a valid one.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildCloseFrame(code: number, reason?: string): Buffer;
|
|
68
|
+
export declare function computeAcceptKey(key: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Return true if the upgrade request's `Origin` is permitted.
|
|
71
|
+
*
|
|
72
|
+
* Controlled by `TINA4_WS_ALLOWED_ORIGINS` (comma-separated list of exact
|
|
73
|
+
* origins, e.g. `https://app.example.com,https://admin.example.com`).
|
|
74
|
+
*
|
|
75
|
+
* Empty/unset = allow ALL origins (current behaviour, non-breaking). When set,
|
|
76
|
+
* only requests whose `Origin` header exactly matches a listed value are
|
|
77
|
+
* allowed; a missing `Origin` header is rejected once the allow-list is active.
|
|
78
|
+
* Header lookup is case-insensitive on the key (Node lowercases header keys,
|
|
79
|
+
* but the helper also checks an exact `Origin` so it works with raw maps too).
|
|
80
|
+
*/
|
|
81
|
+
export declare function originAllowed(headers: Record<string, string | string[] | undefined>): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Extract a bearer token from a WebSocket upgrade handshake.
|
|
84
|
+
*
|
|
85
|
+
* Order (mirrors Python's `ws_token`): the `Authorization: Bearer` header (set
|
|
86
|
+
* by server/CLI/mobile clients), then the `Sec-WebSocket-Protocol` subprotocol
|
|
87
|
+
* in the form `"bearer, <token>"` (the only way a *browser* can pass a token,
|
|
88
|
+
* since `new WebSocket()` cannot set headers), then a `?token=` query param.
|
|
89
|
+
* Returns the token string or `null`.
|
|
90
|
+
*
|
|
91
|
+
* @param headers - Upgrade-request headers (case-insensitive lookup).
|
|
92
|
+
* @param queryString - Raw query string (without the leading `?`), e.g. `token=abc`.
|
|
93
|
+
* @param subprotocol - The offered `Sec-WebSocket-Protocol` value, if already parsed out.
|
|
94
|
+
*/
|
|
95
|
+
export declare function wsToken(headers: Record<string, string | string[] | undefined>, queryString?: string, subprotocol?: string): string | null;
|
|
96
|
+
/**
|
|
97
|
+
* Per-route WebSocket authentication, checked on the upgrade.
|
|
98
|
+
*
|
|
99
|
+
* A route is secured when `authRequired` is truthy (set by `.secure()` /
|
|
100
|
+
* `{ secured: true }` on the WS route, or a `_secured` flag on the handler).
|
|
101
|
+
* Public routes (the default) always pass. A secured route needs a valid JWT
|
|
102
|
+
* via the Authorization header, the `bearer` subprotocol, or `?token=`.
|
|
103
|
+
*
|
|
104
|
+
* Returns `[payload, ok]` — the verified token payload (or `null`) and whether
|
|
105
|
+
* the upgrade may proceed. Mirrors Python's `ws_authorized`.
|
|
106
|
+
*/
|
|
107
|
+
export declare function wsAuthorized(route: {
|
|
108
|
+
authRequired?: boolean;
|
|
109
|
+
} | null | undefined, headers: Record<string, string | string[] | undefined>, queryString?: string, subprotocol?: string): [Record<string, unknown> | null, boolean];
|
|
110
|
+
/**
|
|
111
|
+
* Whether the client offered the `bearer` subprotocol — if so, the server MUST
|
|
112
|
+
* echo `bearer` back as the accepted `Sec-WebSocket-Protocol` in the handshake
|
|
113
|
+
* (RFC 6455 §1.3; browsers send the token as the second subprotocol token).
|
|
114
|
+
*/
|
|
115
|
+
export declare function offeredBearerSubprotocol(subprotocol: string): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Parse HTTP headers from raw upgrade request data.
|
|
118
|
+
*/
|
|
119
|
+
export declare function parseUpgradeHeaders(raw: string): Record<string, string>;
|
|
120
|
+
/**
|
|
121
|
+
* Build a WebSocket frame (server->client, never masked).
|
|
122
|
+
*/
|
|
123
|
+
export declare function buildFrame(opcode: number, payload: Buffer, fin?: boolean): Buffer;
|
|
124
|
+
/**
|
|
125
|
+
* Parse a WebSocket frame from a buffer.
|
|
126
|
+
* Returns { fin, opcode, payload, bytesConsumed } or null if not enough data.
|
|
127
|
+
*/
|
|
128
|
+
export declare function parseFrame(data: Buffer): {
|
|
129
|
+
fin: boolean;
|
|
130
|
+
opcode: number;
|
|
131
|
+
payload: Buffer;
|
|
132
|
+
bytesConsumed: number;
|
|
133
|
+
} | null;
|
|
134
|
+
export declare class WebSocketServer {
|
|
135
|
+
private port;
|
|
136
|
+
private server;
|
|
137
|
+
private clients;
|
|
138
|
+
private handlers;
|
|
139
|
+
/** rooms[roomName] = Set of clientIds */
|
|
140
|
+
private rooms;
|
|
141
|
+
/** clientRooms[clientId] = Set of roomNames */
|
|
142
|
+
private clientRooms;
|
|
143
|
+
/** Route-style handlers registered via route(), keyed by path */
|
|
144
|
+
private _routeHandlers;
|
|
145
|
+
/**
|
|
146
|
+
* Backplane (multi-instance scaling). Lazily wired on the first broadcast
|
|
147
|
+
* via {@link ensureBackplane}. Each instance owns a stable id so it can
|
|
148
|
+
* ignore its own echoes coming back over the shared pub/sub channel.
|
|
149
|
+
*/
|
|
150
|
+
private backplane;
|
|
151
|
+
/** Set once ensureBackplane() has fired so we only attempt the wiring once. */
|
|
152
|
+
private backplaneStarted;
|
|
153
|
+
/** Idle-connection reaper timer (opt-in via TINA4_WS_IDLE_TIMEOUT). */
|
|
154
|
+
private reaperTimer;
|
|
155
|
+
constructor(options?: {
|
|
156
|
+
port?: number;
|
|
157
|
+
});
|
|
158
|
+
/** Test/diagnostic helper: this instance's stable backplane id. */
|
|
159
|
+
get instanceId(): string;
|
|
160
|
+
/**
|
|
161
|
+
* Register an event handler.
|
|
162
|
+
*/
|
|
163
|
+
on(event: string, handler: Function): WebSocketServer;
|
|
164
|
+
/**
|
|
165
|
+
* Register a WebSocket handler for a path (decorator style, matches Python).
|
|
166
|
+
*
|
|
167
|
+
* The handler receives a WebSocketConnection and sets up callbacks via
|
|
168
|
+
* `conn.onMessage(handler)` and `conn.onClose(handler)`.
|
|
169
|
+
*
|
|
170
|
+
* Internally this creates an adapter that converts from the decorator style
|
|
171
|
+
* to the Router's `(conn, event, data)` style and registers it via
|
|
172
|
+
* `Router.websocket()`.
|
|
173
|
+
*/
|
|
174
|
+
route(path: string, handler: (conn: WebSocketConnection) => void | Promise<void>, options?: {
|
|
175
|
+
secured?: boolean;
|
|
176
|
+
}): void;
|
|
177
|
+
/**
|
|
178
|
+
* Broadcast a message to all connected clients.
|
|
179
|
+
*
|
|
180
|
+
* When `path` is provided, only clients connected on that specific path
|
|
181
|
+
* receive the message (matching PHP's WebSocket::broadcast behaviour).
|
|
182
|
+
* When `path` is omitted/undefined, all clients receive the message
|
|
183
|
+
* (backward compatible).
|
|
184
|
+
*/
|
|
185
|
+
broadcast(message: string | Buffer, excludeIds?: string[], path?: string): void;
|
|
186
|
+
/**
|
|
187
|
+
* Send a message to a specific client by ID.
|
|
188
|
+
*
|
|
189
|
+
* Local-only: a connection lives on exactly one instance, so there is
|
|
190
|
+
* nothing to fan out over the backplane.
|
|
191
|
+
*/
|
|
192
|
+
sendTo(clientId: string, message: string | Buffer): void;
|
|
193
|
+
/**
|
|
194
|
+
* Start the WebSocket server.
|
|
195
|
+
*/
|
|
196
|
+
start(): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* Stop the server and disconnect all clients.
|
|
199
|
+
*/
|
|
200
|
+
stop(): void;
|
|
201
|
+
/**
|
|
202
|
+
* Get all connected clients.
|
|
203
|
+
*/
|
|
204
|
+
getClients(): Map<string, WebSocketClient>;
|
|
205
|
+
/**
|
|
206
|
+
* Close a specific client connection with an optional code and reason.
|
|
207
|
+
*/
|
|
208
|
+
close(clientId: string, code?: number, reason?: string): void;
|
|
209
|
+
/**
|
|
210
|
+
* Add a client to a named room.
|
|
211
|
+
*/
|
|
212
|
+
joinRoom(clientId: string, roomName: string): void;
|
|
213
|
+
/**
|
|
214
|
+
* Remove a client from a named room.
|
|
215
|
+
*/
|
|
216
|
+
leaveRoom(clientId: string, roomName: string): void;
|
|
217
|
+
/**
|
|
218
|
+
* Return the list of client IDs in a room.
|
|
219
|
+
*/
|
|
220
|
+
getRoomConnections(roomName: string): string[];
|
|
221
|
+
/**
|
|
222
|
+
* Return the number of clients in a room.
|
|
223
|
+
*/
|
|
224
|
+
roomCount(roomName: string): number;
|
|
225
|
+
/**
|
|
226
|
+
* Return the names of all rooms a client has joined.
|
|
227
|
+
*/
|
|
228
|
+
getClientRooms(clientId: string): string[];
|
|
229
|
+
/**
|
|
230
|
+
* Broadcast a message to all clients in a room.
|
|
231
|
+
*
|
|
232
|
+
* Resilient to dead clients (a failed send prunes the client, never aborts
|
|
233
|
+
* the loop) and fans out to sibling instances over the backplane when
|
|
234
|
+
* configured — a room can span instances, so each one delivers to its own
|
|
235
|
+
* members.
|
|
236
|
+
*/
|
|
237
|
+
broadcastToRoom(roomName: string, message: string | Buffer, excludeIds?: string[]): void;
|
|
238
|
+
private emit;
|
|
239
|
+
/** Lazily wire the backplane on the first broadcast. Idempotent. */
|
|
240
|
+
private ensureBackplane;
|
|
241
|
+
/**
|
|
242
|
+
* Deliver a remote-originated envelope to LOCAL connections only. NEVER
|
|
243
|
+
* re-publishes (that would loop the message around the cluster). Dispatches
|
|
244
|
+
* by `kind`: room / path / all.
|
|
245
|
+
*/
|
|
246
|
+
private relayLocal;
|
|
247
|
+
/**
|
|
248
|
+
* Send to ONE client without letting a single dead/slow client abort a
|
|
249
|
+
* broadcast loop. A write failure (or an already-closed client) is logged
|
|
250
|
+
* and the client is pruned. Returns true if the frame was handed to the
|
|
251
|
+
* socket.
|
|
252
|
+
*
|
|
253
|
+
* Slow-client backpressure: `socket.write()` returns false when the kernel
|
|
254
|
+
* send buffer is full. We don't unboundedly buffer — a client whose backlog
|
|
255
|
+
* has blown past TINA4_WS_MAX_BACKLOG bytes is hopelessly behind, so we drop
|
|
256
|
+
* and close it rather than let it grow the process heap without bound.
|
|
257
|
+
*/
|
|
258
|
+
private safeSend;
|
|
259
|
+
/** Remove a client from the manager, rooms, and close its socket. */
|
|
260
|
+
private pruneClient;
|
|
261
|
+
/**
|
|
262
|
+
* Close connections whose last inbound frame is older than `timeoutSeconds`.
|
|
263
|
+
* Returns the number reaped. `timeoutSeconds <= 0` is a no-op (the reaper is
|
|
264
|
+
* opt-in via TINA4_WS_IDLE_TIMEOUT).
|
|
265
|
+
*/
|
|
266
|
+
reapIdle(timeoutSeconds: number): number;
|
|
267
|
+
/**
|
|
268
|
+
* Spin up the idle-connection reaper when TINA4_WS_IDLE_TIMEOUT is a
|
|
269
|
+
* positive number of seconds. Opt-in and non-breaking — unset/0 means no
|
|
270
|
+
* timer is created at all (current behaviour). Called from start().
|
|
271
|
+
*/
|
|
272
|
+
private startIdleReaper;
|
|
273
|
+
private handleUpgrade;
|
|
274
|
+
private processBuffer;
|
|
275
|
+
private removeClientFromAllRooms;
|
|
276
|
+
}
|
|
277
|
+
/** A live route connection in the integrated server. */
|
|
278
|
+
interface RouteConnState {
|
|
279
|
+
conn: WebSocketConnection;
|
|
280
|
+
socket: Socket;
|
|
281
|
+
path: string;
|
|
282
|
+
rooms: Set<string>;
|
|
283
|
+
closed: boolean;
|
|
284
|
+
/** Optional dev-admin tracker id so the connection shows in the websockets list. */
|
|
285
|
+
trackerId?: string;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Process-wide manager for user WebSocket route connections served by the
|
|
289
|
+
* integrated server. Path-scoped broadcast + rooms mirror the standalone
|
|
290
|
+
* WebSocketServer semantics so a route handler behaves the same either way.
|
|
291
|
+
*/
|
|
292
|
+
declare class WsRouteManager {
|
|
293
|
+
private connections;
|
|
294
|
+
private rooms;
|
|
295
|
+
private onAdd?;
|
|
296
|
+
private onRemove?;
|
|
297
|
+
/** Wire dev-admin tracking callbacks (WsTracker.add / WsTracker.remove). */
|
|
298
|
+
setTracker(onAdd: (remoteAddress: string, path: string) => string, onRemove: (id: string) => void): void;
|
|
299
|
+
/** Currently-open route connections (test/diagnostic helper). */
|
|
300
|
+
get size(): number;
|
|
301
|
+
add(state: RouteConnState): void;
|
|
302
|
+
remove(id: string): void;
|
|
303
|
+
/**
|
|
304
|
+
* Close every open route connection with an RFC 6455 status code.
|
|
305
|
+
*
|
|
306
|
+
* Used by graceful shutdown with 1001 "going away", which is the code RFC
|
|
307
|
+
* 6455 s7.4.1 defines for exactly this case ("a server going down"). A
|
|
308
|
+
* client that is told 1001 can reconnect on a schedule; a socket that just
|
|
309
|
+
* vanishes looks like a network fault and produces an error instead.
|
|
310
|
+
*
|
|
311
|
+
* Best-effort per connection: a dead socket is skipped, never aborting the
|
|
312
|
+
* rest. Returns how many were signalled.
|
|
313
|
+
*/
|
|
314
|
+
closeAll(code?: number, reason?: string): number;
|
|
315
|
+
/** Send a text frame to one connection (best-effort). */
|
|
316
|
+
sendTo(id: string, message: string): void;
|
|
317
|
+
/** Broadcast a text frame to every connection on the same path. */
|
|
318
|
+
broadcastPath(path: string, message: string): void;
|
|
319
|
+
joinRoom(id: string, room: string): void;
|
|
320
|
+
leaveRoom(id: string, room: string): void;
|
|
321
|
+
/**
|
|
322
|
+
* The live connections currently in a room (open only). Returns the
|
|
323
|
+
* WebSocketConnection objects so callers can read each `.auth` (presence
|
|
324
|
+
* rosters). Mirrors Python's mgr.get_room_connections / PHP getRoomConnections.
|
|
325
|
+
*/
|
|
326
|
+
getRoomConnections(room: string): WebSocketConnection[];
|
|
327
|
+
/**
|
|
328
|
+
* Broadcast a text frame to every connection in a room, optionally skipping
|
|
329
|
+
* one connection id (self-exclusion). A dead/slow socket is skipped, never
|
|
330
|
+
* aborting the rest.
|
|
331
|
+
*/
|
|
332
|
+
broadcastToRoom(room: string, message: string, excludeId?: string): void;
|
|
333
|
+
}
|
|
334
|
+
/** Process-wide manager for integrated-server user WS route connections. */
|
|
335
|
+
export declare const wsRouteManager: WsRouteManager;
|
|
336
|
+
/**
|
|
337
|
+
* Serve a user WebSocket route on the integrated server's `upgrade` event.
|
|
338
|
+
*
|
|
339
|
+
* This is the second half of per-route WS auth in Node: it's the entry point
|
|
340
|
+
* that wires a user-registered WS route (the WS route table) into the integrated
|
|
341
|
+
* server so the route actually gets a live open/message/close lifecycle on a
|
|
342
|
+
* real connection — parity with Python/PHP/Ruby — AND enforces per-route auth.
|
|
343
|
+
*
|
|
344
|
+
* Order mirrors Python's `_handle_dev_websocket` / `_handle_asgi_websocket`:
|
|
345
|
+
* 1. require a Sec-WebSocket-Key (else 400);
|
|
346
|
+
* 2. origin allow-list (else 403) — TINA4_WS_ALLOWED_ORIGINS, unset = allow all;
|
|
347
|
+
* 3. per-route auth (else 401) — public by default, secured needs a valid JWT;
|
|
348
|
+
* 4. accept the handshake, echoing `bearer` when offered;
|
|
349
|
+
* 5. build the connection (conn.auth = payload), fire "open", then pump
|
|
350
|
+
* frames into "message" / "close".
|
|
351
|
+
*
|
|
352
|
+
* Returns true if a matching route was found and handled (accepted OR rejected),
|
|
353
|
+
* false if no WS route matched this path (caller falls through to its 404).
|
|
354
|
+
*/
|
|
355
|
+
export declare function serveWebSocketRoute(req: IncomingMessage, socket: Socket, head: Buffer): boolean;
|
|
356
|
+
/**
|
|
357
|
+
* Connection manager for the dev-reload channel (`/__dev_reload`).
|
|
358
|
+
*
|
|
359
|
+
* Mirrors Python's `_ws_manager` scoped to `/__dev_reload`: it accepts the
|
|
360
|
+
* RFC 6455 handshake on the *main* dev server's HTTP `upgrade` event, holds the
|
|
361
|
+
* raw sockets open, and lets `POST /__dev/api/reload` push an instant reload to
|
|
362
|
+
* every connected browser via {@link broadcast}. The framework never reads from
|
|
363
|
+
* the client — the open socket is the whole point. This restores the documented
|
|
364
|
+
* WebSocket-primary DevReload design (the dev toolbar and dev-admin dashboard
|
|
365
|
+
* both connect here). Registered only when `TINA4_DEBUG` is on, and never on the
|
|
366
|
+
* stable AI port.
|
|
367
|
+
*/
|
|
368
|
+
declare class DevReloadWsManager {
|
|
369
|
+
private clients;
|
|
370
|
+
/** Optional hooks (add/remove) so the dev-admin connection list stays in sync. */
|
|
371
|
+
private onAdd?;
|
|
372
|
+
private onRemove?;
|
|
373
|
+
/** Wire dev-admin tracking callbacks (WsTracker.add / WsTracker.remove). */
|
|
374
|
+
setTracker(onAdd: (remoteAddress: string, path: string) => string, onRemove: (id: string) => void): void;
|
|
375
|
+
/** Number of currently-open dev-reload sockets (test/diagnostic helper). */
|
|
376
|
+
get size(): number;
|
|
377
|
+
/**
|
|
378
|
+
* Close every open dev-reload socket with an RFC 6455 status code (1001
|
|
379
|
+
* "going away" on shutdown). The browser client reconnects on a schedule
|
|
380
|
+
* when it is told the server went away, rather than reporting an error.
|
|
381
|
+
* Best-effort per socket. Returns how many were signalled.
|
|
382
|
+
*/
|
|
383
|
+
closeAll(code?: number, reason?: string): number;
|
|
384
|
+
/**
|
|
385
|
+
* Accept a WebSocket upgrade on `/__dev_reload` and hold the socket open.
|
|
386
|
+
*
|
|
387
|
+
* Completes the RFC 6455 handshake, registers the connection, and drains
|
|
388
|
+
* inbound frames — responding to pings and cleaning up on close — without
|
|
389
|
+
* ever interpreting client data. Returns true if the handshake was accepted.
|
|
390
|
+
*/
|
|
391
|
+
handleUpgrade(req: IncomingMessage, socket: Socket, head: Buffer): boolean;
|
|
392
|
+
/**
|
|
393
|
+
* Broadcast a text frame to every connected dev-reload client.
|
|
394
|
+
*
|
|
395
|
+
* Best-effort: a dead socket is dropped silently. Never throws — the caller
|
|
396
|
+
* (`POST /__dev/api/reload`) must not 500 because a browser tab went away.
|
|
397
|
+
*/
|
|
398
|
+
broadcast(message: string): void;
|
|
399
|
+
}
|
|
400
|
+
/** Process-wide dev-reload manager (one channel: `/__dev_reload`). */
|
|
401
|
+
export declare const devReloadWs: DevReloadWsManager;
|
|
402
|
+
export {};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base interface for scaling WebSocket broadcast across instances.
|
|
3
|
+
*
|
|
4
|
+
* Implementations relay messages over a shared bus so every server instance
|
|
5
|
+
* receives every broadcast, not just the originator.
|
|
6
|
+
*/
|
|
7
|
+
export interface WebSocketBackplane {
|
|
8
|
+
/** Publish a message to all instances listening on `channel`. */
|
|
9
|
+
publish(channel: string, message: string): Promise<void>;
|
|
10
|
+
/** Subscribe to `channel`. `callback` is invoked with each incoming message. */
|
|
11
|
+
subscribe(channel: string, callback: (message: string) => void): Promise<void>;
|
|
12
|
+
/** Stop listening on `channel`. */
|
|
13
|
+
unsubscribe(channel: string): Promise<void>;
|
|
14
|
+
/** Tear down connections. */
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Redis pub/sub backplane.
|
|
19
|
+
*
|
|
20
|
+
* Requires the `redis` package (`npm install redis`). The import is deferred
|
|
21
|
+
* so the rest of Tina4 works fine without it installed — an error is thrown
|
|
22
|
+
* only when this class is actually instantiated.
|
|
23
|
+
*/
|
|
24
|
+
export declare class RedisBackplane implements WebSocketBackplane {
|
|
25
|
+
private publisher;
|
|
26
|
+
private subscriber;
|
|
27
|
+
private url;
|
|
28
|
+
private ready;
|
|
29
|
+
constructor(url?: string);
|
|
30
|
+
publish(channel: string, message: string): Promise<void>;
|
|
31
|
+
subscribe(channel: string, callback: (message: string) => void): Promise<void>;
|
|
32
|
+
unsubscribe(channel: string): Promise<void>;
|
|
33
|
+
close(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* NATS pub/sub backplane.
|
|
37
|
+
*
|
|
38
|
+
* Requires the `nats` package (`npm install nats`). The import is deferred
|
|
39
|
+
* so the rest of Tina4 works fine without it installed — an error is thrown
|
|
40
|
+
* only when this class is actually instantiated.
|
|
41
|
+
*
|
|
42
|
+
* NATS is async-native. The subscription listener runs via the NATS client's
|
|
43
|
+
* built-in async iteration.
|
|
44
|
+
*/
|
|
45
|
+
export declare class NATSBackplane implements WebSocketBackplane {
|
|
46
|
+
private nc;
|
|
47
|
+
private url;
|
|
48
|
+
private subs;
|
|
49
|
+
private ready;
|
|
50
|
+
constructor(url?: string);
|
|
51
|
+
publish(channel: string, message: string): Promise<void>;
|
|
52
|
+
subscribe(channel: string, callback: (message: string) => void): Promise<void>;
|
|
53
|
+
unsubscribe(channel: string): Promise<void>;
|
|
54
|
+
close(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Factory that reads TINA4_WS_BACKPLANE and returns the appropriate
|
|
58
|
+
* backplane instance, or `null` if no backplane is configured.
|
|
59
|
+
*
|
|
60
|
+
* This keeps backplane usage entirely optional — callers simply check
|
|
61
|
+
* `if (backplane)` before publishing.
|
|
62
|
+
*/
|
|
63
|
+
export declare function createBackplane(url?: string): WebSocketBackplane | null;
|
|
64
|
+
/**
|
|
65
|
+
* The shared pub/sub channel name. Identical across all four Tina4 frameworks
|
|
66
|
+
* (cross-framework constant parity) so a Python, PHP, Ruby and Node instance
|
|
67
|
+
* can all relay each other's broadcasts over the same bus.
|
|
68
|
+
*/
|
|
69
|
+
export declare const WS_BACKPLANE_CHANNEL = "tina4:ws";
|
|
70
|
+
/** What `kind` a broadcast envelope carries — mirrors the master design. */
|
|
71
|
+
export type WsEnvelopeKind = "all" | "path" | "room";
|
|
72
|
+
/**
|
|
73
|
+
* The JSON envelope published to the backplane channel. The wire shape is
|
|
74
|
+
* identical across all four frameworks. JSON can't carry bytes, so a string
|
|
75
|
+
* message rides under `text` and a binary message rides under `b64`
|
|
76
|
+
* (base64 of the bytes).
|
|
77
|
+
*/
|
|
78
|
+
export interface WsEnvelope {
|
|
79
|
+
/** Stable per-process instance id of the publisher (for the origin guard). */
|
|
80
|
+
src: string;
|
|
81
|
+
/** Delivery kind: every local conn / a path / a room. */
|
|
82
|
+
kind: WsEnvelopeKind;
|
|
83
|
+
/** Optional connection id to skip on delivery. */
|
|
84
|
+
exclude?: string | null;
|
|
85
|
+
/** Room name (only when kind === "room"). */
|
|
86
|
+
room?: string | null;
|
|
87
|
+
/** Path (only when kind === "path"). */
|
|
88
|
+
path?: string | null;
|
|
89
|
+
/** Text payload (str messages). */
|
|
90
|
+
text?: string;
|
|
91
|
+
/** Base64 payload (binary messages). */
|
|
92
|
+
b64?: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Wires a {@link WebSocketBackplane} into a local connection manager so a
|
|
96
|
+
* broadcast on one server instance reaches the local connections of every
|
|
97
|
+
* sibling instance.
|
|
98
|
+
*
|
|
99
|
+
* Node is single-threaded async, so — unlike Python's bg-thread →
|
|
100
|
+
* `run_coroutine_threadsafe` bridge — the subscribe callback can relay
|
|
101
|
+
* directly on the event loop. We still apply the two invariants that keep a
|
|
102
|
+
* cluster correct:
|
|
103
|
+
*
|
|
104
|
+
* 1. **Origin guard** — drop any envelope whose `src` is *this* instance's
|
|
105
|
+
* id. We already delivered it locally on broadcast; relaying it again
|
|
106
|
+
* would double-send.
|
|
107
|
+
* 2. **No re-publish** — the relay path only delivers to LOCAL connections;
|
|
108
|
+
* it never publishes, so a message can't loop around the cluster.
|
|
109
|
+
*
|
|
110
|
+
* The manager is generic over the local-delivery callback (`relay`) so it can
|
|
111
|
+
* sit beside the WebSocketServer without importing it (no module cycle).
|
|
112
|
+
*/
|
|
113
|
+
export declare class WsBackplaneManager {
|
|
114
|
+
/** Stable per-process id so we can ignore our own echoes. */
|
|
115
|
+
readonly instanceId: string;
|
|
116
|
+
readonly channel: string;
|
|
117
|
+
private backplane;
|
|
118
|
+
private started;
|
|
119
|
+
/** Local-delivery callback, installed by the owner (WebSocketServer). */
|
|
120
|
+
private relay;
|
|
121
|
+
constructor(channel?: string);
|
|
122
|
+
/** True once a backplane is actually attached (a network bus is configured). */
|
|
123
|
+
get active(): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Lazily wire the configured backplane and subscribe. Idempotent and
|
|
126
|
+
* best-effort — a failure here logs and leaves the manager in local-only
|
|
127
|
+
* mode; it must NEVER crash a broadcast. The `relay` callback is invoked
|
|
128
|
+
* (on this same event loop) for every *remote* envelope that survives the
|
|
129
|
+
* origin guard.
|
|
130
|
+
*/
|
|
131
|
+
ensure(relay: (env: WsEnvelope) => void, log?: WsBackplaneLogger): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Handle a raw envelope arriving on the channel. Applies the origin guard
|
|
134
|
+
* then hands a *remote* envelope to the local relay. Never throws (a
|
|
135
|
+
* malformed envelope is dropped silently).
|
|
136
|
+
*/
|
|
137
|
+
onMessage(raw: string): void;
|
|
138
|
+
/**
|
|
139
|
+
* Publish a broadcast to the shared channel for sibling instances. No-op
|
|
140
|
+
* when no backplane is configured. Best-effort — a publish failure logs and
|
|
141
|
+
* is swallowed so the local broadcast that already happened is never undone
|
|
142
|
+
* by a flaky message bus.
|
|
143
|
+
*/
|
|
144
|
+
publish(kind: WsEnvelopeKind, message: string | Buffer, opts?: {
|
|
145
|
+
room?: string | null;
|
|
146
|
+
path?: string | null;
|
|
147
|
+
exclude?: string | null;
|
|
148
|
+
}, log?: WsBackplaneLogger): void;
|
|
149
|
+
/**
|
|
150
|
+
* Reconstruct the original str/Buffer message from an envelope. JSON can't
|
|
151
|
+
* carry bytes, so `text` → string and `b64` → Buffer.
|
|
152
|
+
*/
|
|
153
|
+
static decodeMessage(env: WsEnvelope): string | Buffer | null;
|
|
154
|
+
}
|
|
155
|
+
/** Minimal logger shape so the manager doesn't import the logger module. */
|
|
156
|
+
export interface WsBackplaneLogger {
|
|
157
|
+
info(message: string): void;
|
|
158
|
+
warn(message: string): void;
|
|
159
|
+
error(message: string): void;
|
|
160
|
+
}
|
|
161
|
+
/** Build the cross-framework envelope. Exported for tests. */
|
|
162
|
+
export declare function buildEnvelope(src: string, kind: WsEnvelopeKind, message: string | Buffer, opts?: {
|
|
163
|
+
room?: string | null;
|
|
164
|
+
path?: string | null;
|
|
165
|
+
exclude?: string | null;
|
|
166
|
+
}): WsEnvelope;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a WebSocket connection with send/broadcast/close capabilities.
|
|
3
|
+
* Used by Router.websocket() route handlers.
|
|
4
|
+
*/
|
|
5
|
+
export interface WebSocketConnection {
|
|
6
|
+
/** Unique connection identifier */
|
|
7
|
+
id: string;
|
|
8
|
+
/** The WebSocket route path this connection is on */
|
|
9
|
+
path: string;
|
|
10
|
+
/** Client IP address */
|
|
11
|
+
ip: string;
|
|
12
|
+
/** HTTP headers from the upgrade request */
|
|
13
|
+
headers: Record<string, string>;
|
|
14
|
+
/** Route parameters extracted from `{param}` segments in the path */
|
|
15
|
+
params: Record<string, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Verified JWT payload on a `@secured` / `.secure()` WebSocket route, or
|
|
18
|
+
* `null` on a public route (the default). Set on the upgrade after the token
|
|
19
|
+
* is validated — mirrors Python's `connection.auth`.
|
|
20
|
+
*/
|
|
21
|
+
auth: Record<string, unknown> | null;
|
|
22
|
+
/** Send a message to this connection only */
|
|
23
|
+
send(message: string): void;
|
|
24
|
+
/** Serialize an object to JSON and send it to this connection. Parity with Python/PHP. */
|
|
25
|
+
sendJson(data: unknown): void;
|
|
26
|
+
/** Broadcast a message to all connections on the same path (path-scoped) */
|
|
27
|
+
broadcast(message: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Broadcast a message to every connection in a room. Pass `excludeSelf: true`
|
|
30
|
+
* to skip this connection (the common signalling/chat relay case). Mirrors
|
|
31
|
+
* Python `connection.broadcast_to_room(room, msg, exclude_self=...)`.
|
|
32
|
+
*/
|
|
33
|
+
broadcastToRoom(roomName: string, message: string, excludeSelf?: boolean): void;
|
|
34
|
+
/**
|
|
35
|
+
* The live connections currently in a room (for presence rosters — read each
|
|
36
|
+
* returned connection's `.auth`). Mirrors the manager room enumeration used
|
|
37
|
+
* by the Python/PHP/Ruby realtime rosters.
|
|
38
|
+
*/
|
|
39
|
+
getRoomConnections(roomName: string): WebSocketConnection[];
|
|
40
|
+
/** Join a room */
|
|
41
|
+
joinRoom(roomName: string): void;
|
|
42
|
+
/** Leave a room */
|
|
43
|
+
leaveRoom(roomName: string): void;
|
|
44
|
+
/** Close this connection */
|
|
45
|
+
close(): void;
|
|
46
|
+
/** Internal message callback, set via onMessage(). */
|
|
47
|
+
_onMessage: ((data: string) => void | Promise<void>) | null;
|
|
48
|
+
/** Internal close callback, set via onClose(). */
|
|
49
|
+
_onClose: (() => void | Promise<void>) | null;
|
|
50
|
+
/** Register a message handler (decorator style, matches Python). */
|
|
51
|
+
onMessage(handler: (data: string) => void | Promise<void>): void;
|
|
52
|
+
/** Register a close handler (decorator style, matches Python). */
|
|
53
|
+
onClose(handler: () => void | Promise<void>): void;
|
|
54
|
+
}
|