room-kit 1.0.0 → 1.0.2
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/README.md +25 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +83 -16
- package/dist/client.js.map +1 -1
- package/dist/server.d.ts +4 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +143 -14
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +24 -4
- package/dist/types.d.ts.map +1 -1
- package/example/public/app.ts +184 -187
- package/example/server.ts +173 -146
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/client.ts +105 -16
- package/src/server.ts +189 -25
- package/src/types.ts +28 -4
- package/test/room.spec.ts +241 -78
package/README.md
CHANGED
|
@@ -61,7 +61,10 @@ export const chatRoom = defineRoomType<{
|
|
|
61
61
|
rpc: {
|
|
62
62
|
sendMessage: (input: { text: string }): Promise<{ id: string }>;
|
|
63
63
|
};
|
|
64
|
-
}>({
|
|
64
|
+
}>({
|
|
65
|
+
name: "chat", // namespace
|
|
66
|
+
presence: "list" // allow clients to list room members
|
|
67
|
+
});
|
|
65
68
|
```
|
|
66
69
|
|
|
67
70
|
```ts
|
|
@@ -155,13 +158,23 @@ const joined = await chatClient.join({
|
|
|
155
158
|
});
|
|
156
159
|
|
|
157
160
|
// Event payload and metadata are both inferred from the room schema.
|
|
158
|
-
joined.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
const cleanup = joined.listen({
|
|
162
|
+
events: {
|
|
163
|
+
message: (payload, meta) => {
|
|
164
|
+
// meta.source.kind is "server" or "member".
|
|
165
|
+
console.log(payload.text, meta.source.kind);
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
presence: {
|
|
169
|
+
onChange: (presence) => {
|
|
170
|
+
console.log(`${presence.count} members online`);
|
|
171
|
+
},
|
|
172
|
+
},
|
|
161
173
|
});
|
|
162
174
|
|
|
163
175
|
// Fully typed request/response based on your room definition.
|
|
164
176
|
await joined.rpc.sendMessage({ text: "hello" });
|
|
177
|
+
cleanup();
|
|
165
178
|
// Cleanly leave the room when you're done.
|
|
166
179
|
await joined.leave();
|
|
167
180
|
```
|
|
@@ -188,7 +201,7 @@ Runtime presence mode is configured in the `defineRoomType` options:
|
|
|
188
201
|
|
|
189
202
|
`serveRoomType(socket, roomType, handlers, adapter?)` accepts:
|
|
190
203
|
|
|
191
|
-
- `onAuth(socket)`: optional unless you type a non-`unknown` auth context.
|
|
204
|
+
- `onAuth(socket)`: optional unless you type a non-`unknown` auth context. Return `false` to reject the socket before room initialization.
|
|
192
205
|
- `onConnect(socket, auth)`: optional transport-connect hook attempted once when the socket handler is attached (after auth resolution).
|
|
193
206
|
- `revalidateAuth(socket, auth)`: optional per-request auth validation hook; return `{ kind: "ok", auth? }` to continue or `{ kind: "reject" }` to deny.
|
|
194
207
|
- `initState(joinRequest)`: initializes room server state on first join for a given room instance.
|
|
@@ -212,11 +225,11 @@ Server context (`ctx`) includes:
|
|
|
212
225
|
|
|
213
226
|
`serveRoomType` returns a handle:
|
|
214
227
|
|
|
215
|
-
- `
|
|
216
|
-
- `
|
|
217
|
-
- `
|
|
218
|
-
- `
|
|
219
|
-
- `
|
|
228
|
+
- `handle.cleanup()` unregisters listeners for that socket
|
|
229
|
+
- `handle.rooms()` returns snapshots for all rooms on the namespace
|
|
230
|
+
- `handle.room(roomId)` returns one room snapshot or `undefined`
|
|
231
|
+
- `handle.count(roomId)` returns the current member count for a room (`0` when the room does not exist; throws when room presence mode is `"none"`)
|
|
232
|
+
- `handle.members(roomId, query)` returns a paginated presence listing (`{ count: 0, offset: 0, limit: 0, members: [] }` when the room does not exist; throws when room presence mode is not `"list"`)
|
|
220
233
|
|
|
221
234
|
## Client API
|
|
222
235
|
|
|
@@ -233,6 +246,7 @@ Server context (`ctx`) includes:
|
|
|
233
246
|
- `joinedRoom.rpc.<name>(...args)` for typed RPC calls
|
|
234
247
|
- `joinedRoom.emit.<event>(payload)` for client-emitted room events
|
|
235
248
|
- `joinedRoom.on.<event>((payload, meta) => {})` for room event subscriptions
|
|
249
|
+
- `joinedRoom.listen({ events, presence })` batches event and presence subscriptions and returns one cleanup function
|
|
236
250
|
- `joinedRoom.leave()` to leave the room and unregister the joined-room handle
|
|
237
251
|
- `joinedRoom.presence` is part of the typed API when room presence mode is `"count"` or `"list"`; it exposes `current`, `onChange(handler)`, `count()`, and `list({ offset, limit })` when presence mode is `"list"`.
|
|
238
252
|
|
|
@@ -240,6 +254,7 @@ Server context (`ctx`) includes:
|
|
|
240
254
|
|
|
241
255
|
- Throw `ClientSafeError` for messages you want sent to clients.
|
|
242
256
|
- Non-`ClientSafeError` exceptions are sanitized to: `"An internal server error occurred."`
|
|
257
|
+
- `onAuth` may return `false` to reject the socket before any room state is initialized.
|
|
243
258
|
- RPC and event dispatch only allow own properties (`Object.hasOwn`) to prevent prototype-based handler access.
|
|
244
259
|
- Client event names are default-deny unless explicitly declared in `handlers.events`.
|
|
245
260
|
- Do not trust client payloads for authorization; derive identity in `onAuth`.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAER,gBAAgB,EAUhB,UAAU,EACV,cAAc,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAER,gBAAgB,EAUhB,UAAU,EACV,cAAc,EAMjB,MAAM,SAAS,CAAC;AAwCjB;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,cAAc,CAAC,GAAG,CAAC,EAC9D,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,KAAK,GACZ,UAAU,CAAC,KAAK,CAAC,CA6CnB"}
|
package/dist/client.js
CHANGED
|
@@ -5,6 +5,7 @@ const CLIENT_EVENT = "room-kit:client-event";
|
|
|
5
5
|
const SERVER_EVENT = "room-kit:server-event";
|
|
6
6
|
const PRESENCE_EVENT = "room-kit:presence";
|
|
7
7
|
const PRESENCE_QUERY_EVENT = "room-kit:presence-query";
|
|
8
|
+
const DEFAULT_ACK_TIMEOUT_MS = 30_000;
|
|
8
9
|
const clientRegistries = new WeakMap();
|
|
9
10
|
/**
|
|
10
11
|
* Binds a client socket to a room type and returns a typed room client.
|
|
@@ -95,18 +96,34 @@ function createJoinedRoom(socket, state) {
|
|
|
95
96
|
return undefined;
|
|
96
97
|
}
|
|
97
98
|
return (handler) => {
|
|
98
|
-
|
|
99
|
-
handlers.add(handler);
|
|
100
|
-
state.eventListeners.set(key, handlers);
|
|
101
|
-
return () => {
|
|
102
|
-
handlers.delete(handler);
|
|
103
|
-
if (handlers.size === 0) {
|
|
104
|
-
state.eventListeners.delete(key);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
99
|
+
return registerEventListener(state, key, handler);
|
|
107
100
|
};
|
|
108
101
|
},
|
|
109
102
|
});
|
|
103
|
+
const listen = (options) => {
|
|
104
|
+
const cleanups = [];
|
|
105
|
+
if (options.events) {
|
|
106
|
+
for (const [key, handler] of Object.entries(options.events)) {
|
|
107
|
+
if (typeof handler !== "function") {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
cleanups.push(registerEventListener(state, key, handler));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if ("presence" in options && options.presence?.onChange) {
|
|
114
|
+
cleanups.push(registerPresenceListener(state, options.presence.onChange));
|
|
115
|
+
}
|
|
116
|
+
let cleaned = false;
|
|
117
|
+
return () => {
|
|
118
|
+
if (cleaned) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
cleaned = true;
|
|
122
|
+
for (const cleanup of cleanups) {
|
|
123
|
+
cleanup();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
};
|
|
110
127
|
const base = {
|
|
111
128
|
name: state.name,
|
|
112
129
|
roomId: state.roomId,
|
|
@@ -115,6 +132,7 @@ function createJoinedRoom(socket, state) {
|
|
|
115
132
|
rpc,
|
|
116
133
|
emit,
|
|
117
134
|
on,
|
|
135
|
+
listen,
|
|
118
136
|
async leave() {
|
|
119
137
|
await emitAck(socket, LEAVE_EVENT, {
|
|
120
138
|
roomType: state.name,
|
|
@@ -132,10 +150,7 @@ function createJoinedRoom(socket, state) {
|
|
|
132
150
|
return state.presenceCurrent;
|
|
133
151
|
},
|
|
134
152
|
onChange(handler) {
|
|
135
|
-
state
|
|
136
|
-
return () => {
|
|
137
|
-
state.presenceListeners.delete(handler);
|
|
138
|
-
};
|
|
153
|
+
return registerPresenceListener(state, handler);
|
|
139
154
|
},
|
|
140
155
|
count() {
|
|
141
156
|
return emitAck(socket, PRESENCE_QUERY_EVENT, {
|
|
@@ -158,6 +173,23 @@ function createJoinedRoom(socket, state) {
|
|
|
158
173
|
},
|
|
159
174
|
});
|
|
160
175
|
}
|
|
176
|
+
function registerEventListener(state, key, handler) {
|
|
177
|
+
const handlers = state.eventListeners.get(key) ?? new Set();
|
|
178
|
+
handlers.add(handler);
|
|
179
|
+
state.eventListeners.set(key, handlers);
|
|
180
|
+
return () => {
|
|
181
|
+
handlers.delete(handler);
|
|
182
|
+
if (handlers.size === 0) {
|
|
183
|
+
state.eventListeners.delete(key);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function registerPresenceListener(state, handler) {
|
|
188
|
+
state.presenceListeners.add(handler);
|
|
189
|
+
return () => {
|
|
190
|
+
state.presenceListeners.delete(handler);
|
|
191
|
+
};
|
|
192
|
+
}
|
|
161
193
|
function getClientRegistry(socket) {
|
|
162
194
|
const existing = clientRegistries.get(socket);
|
|
163
195
|
if (existing) {
|
|
@@ -184,6 +216,16 @@ function getClientRegistry(socket) {
|
|
|
184
216
|
function installClientHandlers(socket, registry) {
|
|
185
217
|
if (!registry.serverHandlerInstalled) {
|
|
186
218
|
const onServerEvent = (frame) => {
|
|
219
|
+
if (!frame ||
|
|
220
|
+
typeof frame !== "object" ||
|
|
221
|
+
typeof frame.roomType !== "string" ||
|
|
222
|
+
typeof frame.roomId !== "string" ||
|
|
223
|
+
typeof frame.name !== "string" ||
|
|
224
|
+
!frame.meta ||
|
|
225
|
+
typeof frame.meta !== "object" ||
|
|
226
|
+
typeof frame.meta.sentAt !== "string") {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
187
229
|
const state = registry.joinedRooms.get(makeJoinedRoomKey(frame.roomType, frame.roomId));
|
|
188
230
|
if (!state) {
|
|
189
231
|
return;
|
|
@@ -197,7 +239,12 @@ function installClientHandlers(socket, registry) {
|
|
|
197
239
|
sentAt: new Date(frame.meta.sentAt),
|
|
198
240
|
};
|
|
199
241
|
for (const handler of handlers) {
|
|
200
|
-
|
|
242
|
+
try {
|
|
243
|
+
handler(frame.payload, meta);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Swallow per-listener errors to avoid breaking the event loop
|
|
247
|
+
}
|
|
201
248
|
}
|
|
202
249
|
};
|
|
203
250
|
socket.on(SERVER_EVENT, onServerEvent);
|
|
@@ -205,6 +252,12 @@ function installClientHandlers(socket, registry) {
|
|
|
205
252
|
}
|
|
206
253
|
if (!registry.presenceHandlerInstalled) {
|
|
207
254
|
const onPresence = (frame) => {
|
|
255
|
+
if (!frame ||
|
|
256
|
+
typeof frame !== "object" ||
|
|
257
|
+
typeof frame.roomType !== "string" ||
|
|
258
|
+
typeof frame.roomId !== "string") {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
208
261
|
const state = registry.joinedRooms.get(makeJoinedRoomKey(frame.roomType, frame.roomId));
|
|
209
262
|
if (!state) {
|
|
210
263
|
return;
|
|
@@ -214,7 +267,12 @@ function installClientHandlers(socket, registry) {
|
|
|
214
267
|
return;
|
|
215
268
|
}
|
|
216
269
|
for (const handler of state.presenceListeners) {
|
|
217
|
-
|
|
270
|
+
try {
|
|
271
|
+
handler(state.presenceCurrent);
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
// Swallow per-listener errors
|
|
275
|
+
}
|
|
218
276
|
}
|
|
219
277
|
};
|
|
220
278
|
socket.on(PRESENCE_EVENT, onPresence);
|
|
@@ -292,7 +350,11 @@ function makeJoinedRoomKey(name, roomId) {
|
|
|
292
350
|
}
|
|
293
351
|
function emitAck(socket, eventName, payload) {
|
|
294
352
|
return new Promise((resolve, reject) => {
|
|
353
|
+
const timer = setTimeout(() => {
|
|
354
|
+
reject(new Error(`Acknowledgement timeout for '${eventName}'`));
|
|
355
|
+
}, DEFAULT_ACK_TIMEOUT_MS);
|
|
295
356
|
socket.emit(eventName, payload, (result) => {
|
|
357
|
+
clearTimeout(timer);
|
|
296
358
|
if (!result || typeof result !== "object") {
|
|
297
359
|
reject(new Error("Invalid acknowledgement payload"));
|
|
298
360
|
return;
|
|
@@ -311,7 +373,12 @@ function setConnectionState(registry, next) {
|
|
|
311
373
|
}
|
|
312
374
|
registry.connectionState = next;
|
|
313
375
|
for (const listener of registry.connectionListeners) {
|
|
314
|
-
|
|
376
|
+
try {
|
|
377
|
+
listener(next);
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
// Swallow per-listener errors
|
|
381
|
+
}
|
|
315
382
|
}
|
|
316
383
|
}
|
|
317
384
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -2,13 +2,13 @@ import type { RoomDefinition, RoomServerAdapter, RoomServerHandle, RoomServerHan
|
|
|
2
2
|
/**
|
|
3
3
|
* Attaches room runtime handlers to a connected server socket.
|
|
4
4
|
*
|
|
5
|
-
* Returns a
|
|
6
|
-
*
|
|
5
|
+
* Returns a handle that unregisters all listeners for the bound socket via
|
|
6
|
+
* `cleanup()`, and exposes room introspection helpers.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
10
|
* io.on("connection", (socket) => {
|
|
11
|
-
* const
|
|
11
|
+
* const handle = serveRoomType(socket, chatRoomType, {
|
|
12
12
|
* onAuth: async () => ({ userId: socket.id }),
|
|
13
13
|
* admit: async (join, ctx) => ({
|
|
14
14
|
* roomId: join.roomId,
|
|
@@ -19,7 +19,7 @@ import type { RoomDefinition, RoomServerAdapter, RoomServerHandle, RoomServerHan
|
|
|
19
19
|
* });
|
|
20
20
|
*
|
|
21
21
|
* // Later if needed:
|
|
22
|
-
* //
|
|
22
|
+
* // handle.cleanup();
|
|
23
23
|
* });
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAUR,cAAc,EAEd,iBAAiB,EAEjB,gBAAgB,EAEhB,kBAAkB,EAElB,gBAAgB,EAInB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAUR,cAAc,EAEd,iBAAiB,EAEjB,gBAAgB,EAEhB,kBAAkB,EAElB,gBAAgB,EAInB,MAAM,SAAS,CAAC;AAkKjB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAAC,KAAK,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,EAC5E,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,EAC1C,OAAO,CAAC,EAAE,iBAAiB,GAC5B,gBAAgB,CAAC,KAAK,CAAC,CAqXzB"}
|
package/dist/server.js
CHANGED
|
@@ -6,17 +6,106 @@ const CLIENT_EVENT = "room-kit:client-event";
|
|
|
6
6
|
const SERVER_EVENT = "room-kit:server-event";
|
|
7
7
|
const PRESENCE_EVENT = "room-kit:presence";
|
|
8
8
|
const PRESENCE_QUERY_EVENT = "room-kit:presence-query";
|
|
9
|
+
function assertNonEmptyString(value, label) {
|
|
10
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
11
|
+
throw new ClientSafeError(`${label} must be a non-empty string`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function assertObject(value, label) {
|
|
15
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
16
|
+
throw new ClientSafeError(`${label} must be an object`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function assertArray(value, label) {
|
|
20
|
+
if (!Array.isArray(value)) {
|
|
21
|
+
throw new ClientSafeError(`${label} must be an array`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Validates and narrows a join frame from the wire. */
|
|
25
|
+
function validateJoinFrame(raw) {
|
|
26
|
+
assertObject(raw, "Join frame");
|
|
27
|
+
assertNonEmptyString(raw.roomType, "roomType");
|
|
28
|
+
assertObject(raw.payload, "payload");
|
|
29
|
+
return { roomType: raw.roomType, payload: raw.payload };
|
|
30
|
+
}
|
|
31
|
+
/** Validates and narrows a leave frame from the wire. */
|
|
32
|
+
function validateLeaveFrame(raw) {
|
|
33
|
+
assertObject(raw, "Leave frame");
|
|
34
|
+
assertNonEmptyString(raw.roomType, "roomType");
|
|
35
|
+
assertNonEmptyString(raw.roomId, "roomId");
|
|
36
|
+
return { roomType: raw.roomType, roomId: raw.roomId };
|
|
37
|
+
}
|
|
38
|
+
/** Validates and narrows an RPC frame from the wire. */
|
|
39
|
+
function validateRpcFrame(raw) {
|
|
40
|
+
assertObject(raw, "RPC frame");
|
|
41
|
+
assertNonEmptyString(raw.roomType, "roomType");
|
|
42
|
+
assertNonEmptyString(raw.roomId, "roomId");
|
|
43
|
+
assertNonEmptyString(raw.name, "name");
|
|
44
|
+
assertArray(raw.args, "args");
|
|
45
|
+
return { roomType: raw.roomType, roomId: raw.roomId, name: raw.name, args: raw.args };
|
|
46
|
+
}
|
|
47
|
+
/** Validates and narrows a client-event frame from the wire. */
|
|
48
|
+
function validateClientEventFrame(raw) {
|
|
49
|
+
assertObject(raw, "Client-event frame");
|
|
50
|
+
assertNonEmptyString(raw.roomType, "roomType");
|
|
51
|
+
assertNonEmptyString(raw.roomId, "roomId");
|
|
52
|
+
assertNonEmptyString(raw.name, "name");
|
|
53
|
+
return { roomType: raw.roomType, roomId: raw.roomId, name: raw.name, payload: raw.payload };
|
|
54
|
+
}
|
|
55
|
+
/** Validates and narrows a presence-query frame from the wire. */
|
|
56
|
+
function validatePresenceQueryFrame(raw) {
|
|
57
|
+
assertObject(raw, "Presence-query frame");
|
|
58
|
+
assertNonEmptyString(raw.roomType, "roomType");
|
|
59
|
+
assertNonEmptyString(raw.roomId, "roomId");
|
|
60
|
+
if (raw.kind !== "count" && raw.kind !== "list") {
|
|
61
|
+
throw new ClientSafeError("Presence query kind must be 'count' or 'list'");
|
|
62
|
+
}
|
|
63
|
+
const result = { roomType: raw.roomType, roomId: raw.roomId, kind: raw.kind };
|
|
64
|
+
if (raw.offset !== undefined) {
|
|
65
|
+
if (typeof raw.offset !== "number" || !Number.isFinite(raw.offset)) {
|
|
66
|
+
throw new ClientSafeError("offset must be a finite number");
|
|
67
|
+
}
|
|
68
|
+
result.offset = raw.offset;
|
|
69
|
+
}
|
|
70
|
+
if (raw.limit !== undefined) {
|
|
71
|
+
if (typeof raw.limit !== "number" || !Number.isFinite(raw.limit)) {
|
|
72
|
+
throw new ClientSafeError("limit must be a finite number");
|
|
73
|
+
}
|
|
74
|
+
result.limit = raw.limit;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
const DANGEROUS_PROPERTY_NAMES = new Set([
|
|
79
|
+
"__proto__",
|
|
80
|
+
"constructor",
|
|
81
|
+
"prototype",
|
|
82
|
+
"toString",
|
|
83
|
+
"valueOf",
|
|
84
|
+
"hasOwnProperty",
|
|
85
|
+
"isPrototypeOf",
|
|
86
|
+
"propertyIsEnumerable",
|
|
87
|
+
"toLocaleString",
|
|
88
|
+
]);
|
|
89
|
+
function assertSafeHandlerName(name) {
|
|
90
|
+
if (DANGEROUS_PROPERTY_NAMES.has(name)) {
|
|
91
|
+
throw new ClientSafeError(`Disallowed handler name '${name}'`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Maximum number of rooms that can exist within a single namespace. */
|
|
95
|
+
const MAX_ROOMS_PER_NAMESPACE = 10_000;
|
|
96
|
+
/** Maximum number of socket connections tracked per room. */
|
|
97
|
+
const MAX_MEMBERS_PER_ROOM = 10_000;
|
|
9
98
|
const namespaceStates = new WeakMap();
|
|
10
99
|
/**
|
|
11
100
|
* Attaches room runtime handlers to a connected server socket.
|
|
12
101
|
*
|
|
13
|
-
* Returns a
|
|
14
|
-
*
|
|
102
|
+
* Returns a handle that unregisters all listeners for the bound socket via
|
|
103
|
+
* `cleanup()`, and exposes room introspection helpers.
|
|
15
104
|
*
|
|
16
105
|
* @example
|
|
17
106
|
* ```ts
|
|
18
107
|
* io.on("connection", (socket) => {
|
|
19
|
-
* const
|
|
108
|
+
* const handle = serveRoomType(socket, chatRoomType, {
|
|
20
109
|
* onAuth: async () => ({ userId: socket.id }),
|
|
21
110
|
* admit: async (join, ctx) => ({
|
|
22
111
|
* roomId: join.roomId,
|
|
@@ -27,22 +116,29 @@ const namespaceStates = new WeakMap();
|
|
|
27
116
|
* });
|
|
28
117
|
*
|
|
29
118
|
* // Later if needed:
|
|
30
|
-
* //
|
|
119
|
+
* // handle.cleanup();
|
|
31
120
|
* });
|
|
32
121
|
* ```
|
|
33
122
|
*/
|
|
34
123
|
export function serveRoomType(socket, _room, handlers, adapter) {
|
|
35
124
|
const namespaceState = getNamespaceState(socket);
|
|
36
125
|
const authCache = new WeakMap();
|
|
37
|
-
const onJoin = async (
|
|
126
|
+
const onJoin = async (raw, ack) => {
|
|
38
127
|
try {
|
|
128
|
+
if (ack !== undefined && typeof ack !== "function") {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const frame = validateJoinFrame(raw);
|
|
39
132
|
assertMatchingRoomName(_room, frame.roomType);
|
|
40
133
|
const requestedRoomId = extractRoomId(frame.payload);
|
|
41
134
|
const roomCollection = getOrCreateRoomCollection(namespaceState, frame.roomType);
|
|
135
|
+
if (!roomCollection.has(requestedRoomId) && roomCollection.size >= MAX_ROOMS_PER_NAMESPACE) {
|
|
136
|
+
throw new ClientSafeError("Maximum room limit reached for this namespace");
|
|
137
|
+
}
|
|
42
138
|
const existingRoomState = roomCollection.get(requestedRoomId);
|
|
139
|
+
const auth = await resolveSocketAuth(socket, handlers, authCache, true);
|
|
43
140
|
const initialState = (existingRoomState?.serverState ??
|
|
44
141
|
await Promise.resolve(handlers.initState?.(frame.payload) ?? {}));
|
|
45
|
-
const auth = await resolveSocketAuth(socket, handlers, authCache, true);
|
|
46
142
|
const provisional = createContext(socket, namespaceState, {
|
|
47
143
|
adapter,
|
|
48
144
|
name: frame.roomType,
|
|
@@ -62,6 +158,9 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
62
158
|
membersBySocketId: new Map(),
|
|
63
159
|
socketIdsByMemberId: new Map(),
|
|
64
160
|
};
|
|
161
|
+
if (!roomState.membersBySocketId.has(socket.id) && roomState.membersBySocketId.size >= MAX_MEMBERS_PER_ROOM) {
|
|
162
|
+
throw new ClientSafeError("Room is full");
|
|
163
|
+
}
|
|
65
164
|
roomState.roomProfile = roomState.roomProfile ?? admission.roomProfile;
|
|
66
165
|
roomState.serverState = roomState.serverState ?? provisional.serverState;
|
|
67
166
|
roomState.membersBySocketId.set(socket.id, {
|
|
@@ -97,8 +196,12 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
97
196
|
ack?.({ ok: false, error: toErrorMessage(error) });
|
|
98
197
|
}
|
|
99
198
|
};
|
|
100
|
-
const onLeave = async (
|
|
199
|
+
const onLeave = async (raw, ack) => {
|
|
101
200
|
try {
|
|
201
|
+
if (ack !== undefined && typeof ack !== "function") {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const payload = validateLeaveFrame(raw);
|
|
102
205
|
assertMatchingRoomName(_room, payload.roomType);
|
|
103
206
|
const stored = getStoredMembership(namespaceState, payload.roomType, payload.roomId, socket.id);
|
|
104
207
|
if (!stored) {
|
|
@@ -125,9 +228,14 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
125
228
|
ack?.({ ok: false, error: toErrorMessage(error) });
|
|
126
229
|
}
|
|
127
230
|
};
|
|
128
|
-
const onRpc = async (
|
|
231
|
+
const onRpc = async (raw, ack) => {
|
|
129
232
|
try {
|
|
233
|
+
if (ack !== undefined && typeof ack !== "function") {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const frame = validateRpcFrame(raw);
|
|
130
237
|
assertMatchingRoomName(_room, frame.roomType);
|
|
238
|
+
assertSafeHandlerName(frame.name);
|
|
131
239
|
if (!handlers.rpc || !Object.hasOwn(handlers.rpc, frame.name)) {
|
|
132
240
|
throw new ClientSafeError(`Unknown RPC '${frame.name}'`);
|
|
133
241
|
}
|
|
@@ -150,6 +258,9 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
150
258
|
roomProfile: getRoomState(namespaceState, frame.roomType, frame.roomId).roomProfile,
|
|
151
259
|
serverState: getRoomState(namespaceState, frame.roomType, frame.roomId).serverState,
|
|
152
260
|
});
|
|
261
|
+
if (frame.args.length > 64) {
|
|
262
|
+
throw new ClientSafeError("Too many RPC arguments");
|
|
263
|
+
}
|
|
153
264
|
const result = await handler(...frame.args, ctx);
|
|
154
265
|
ack?.({ ok: true, value: result });
|
|
155
266
|
}
|
|
@@ -157,9 +268,14 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
157
268
|
ack?.({ ok: false, error: toErrorMessage(error) });
|
|
158
269
|
}
|
|
159
270
|
};
|
|
160
|
-
const onClientEvent = async (
|
|
271
|
+
const onClientEvent = async (raw, ack) => {
|
|
161
272
|
try {
|
|
273
|
+
if (ack !== undefined && typeof ack !== "function") {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const frame = validateClientEventFrame(raw);
|
|
162
277
|
assertMatchingRoomName(_room, frame.roomType);
|
|
278
|
+
assertSafeHandlerName(frame.name);
|
|
163
279
|
const stored = getStoredMembership(namespaceState, frame.roomType, frame.roomId, socket.id);
|
|
164
280
|
if (!stored) {
|
|
165
281
|
throw new ClientSafeError("Socket is not joined to that room");
|
|
@@ -194,8 +310,12 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
194
310
|
ack?.({ ok: false, error: toErrorMessage(error) });
|
|
195
311
|
}
|
|
196
312
|
};
|
|
197
|
-
const onPresenceQuery = async (
|
|
313
|
+
const onPresenceQuery = async (raw, ack) => {
|
|
198
314
|
try {
|
|
315
|
+
if (ack !== undefined && typeof ack !== "function") {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const frame = validatePresenceQueryFrame(raw);
|
|
199
319
|
assertMatchingRoomName(_room, frame.roomType);
|
|
200
320
|
const stored = getStoredMembership(namespaceState, frame.roomType, frame.roomId, socket.id);
|
|
201
321
|
if (!stored) {
|
|
@@ -297,7 +417,7 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
297
417
|
})
|
|
298
418
|
.catch(() => undefined);
|
|
299
419
|
}
|
|
300
|
-
const
|
|
420
|
+
const cleanup = () => {
|
|
301
421
|
socket.off(JOIN_EVENT, onJoin);
|
|
302
422
|
socket.off(LEAVE_EVENT, onLeave);
|
|
303
423
|
socket.off(RPC_EVENT, onRpc);
|
|
@@ -305,12 +425,13 @@ export function serveRoomType(socket, _room, handlers, adapter) {
|
|
|
305
425
|
socket.off(PRESENCE_QUERY_EVENT, onPresenceQuery);
|
|
306
426
|
socket.off("disconnect", onDisconnect);
|
|
307
427
|
};
|
|
308
|
-
return
|
|
428
|
+
return {
|
|
429
|
+
cleanup,
|
|
309
430
|
rooms: () => listRoomSnapshots(namespaceState, _room.name),
|
|
310
431
|
room: (roomId) => getRoomSnapshot(namespaceState, _room.name, roomId),
|
|
311
432
|
members: (roomId, query) => getPresenceMembersPage(namespaceState, _room.name, roomId, query),
|
|
312
433
|
count: (roomId) => getPresenceCount(namespaceState, _room.name, roomId),
|
|
313
|
-
}
|
|
434
|
+
};
|
|
314
435
|
}
|
|
315
436
|
function createContext(socket, namespaceState, ctxState) {
|
|
316
437
|
const emit = createEventEmitApi((eventName, payload) => {
|
|
@@ -356,6 +477,10 @@ async function resolveSocketAuth(socket, handlers, authCache, revalidate) {
|
|
|
356
477
|
if (entry.value === undefined) {
|
|
357
478
|
const pending = Promise.resolve(handlers.onAuth?.(socket))
|
|
358
479
|
.then((auth) => {
|
|
480
|
+
if (auth === false) {
|
|
481
|
+
authCache.delete(socket);
|
|
482
|
+
throw new ClientSafeError("Unauthorized");
|
|
483
|
+
}
|
|
359
484
|
const current = authCache.get(socket) ?? {};
|
|
360
485
|
current.value = auth;
|
|
361
486
|
current.pending = undefined;
|
|
@@ -737,7 +862,11 @@ function extractRoomId(payload) {
|
|
|
737
862
|
if (!payload || typeof payload !== "object" || typeof payload.roomId !== "string") {
|
|
738
863
|
throw new ClientSafeError("Join request must include a string roomId");
|
|
739
864
|
}
|
|
740
|
-
|
|
865
|
+
const roomId = payload.roomId;
|
|
866
|
+
if (roomId.length === 0 || roomId.length > 256) {
|
|
867
|
+
throw new ClientSafeError("roomId must be between 1 and 256 characters");
|
|
868
|
+
}
|
|
869
|
+
return roomId;
|
|
741
870
|
}
|
|
742
871
|
function toErrorMessage(error) {
|
|
743
872
|
return error instanceof ClientSafeError ? error.message : "An internal server error occurred.";
|