room-kit 1.0.1 → 1.0.5

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 CHANGED
@@ -201,11 +201,12 @@ Runtime presence mode is configured in the `defineRoomType` options:
201
201
 
202
202
  `serveRoomType(socket, roomType, handlers, adapter?)` accepts:
203
203
 
204
- - `onAuth(socket)`: optional unless you type a non-`unknown` auth context. Return `false` to reject the socket before room initialization.
204
+ - `onAuth(socket)`: optional. Return `false` to reject the socket before room initialization.
205
205
  - `onConnect(socket, auth)`: optional transport-connect hook attempted once when the socket handler is attached (after auth resolution).
206
206
  - `revalidateAuth(socket, auth)`: optional per-request auth validation hook; return `{ kind: "ok", auth? }` to continue or `{ kind: "reject" }` to deny.
207
207
  - `initState(joinRequest)`: initializes room server state on first join for a given room instance.
208
- - `admit(joinRequest, ctx)`: required admission gate; returns `roomId`, `memberId`, `memberProfile`, and `roomProfile`.
208
+ - `admit(joinRequest, ctx)`: optional admission gate. Return only the fields you want to override. Missing `roomId`, `memberId`, `memberProfile`, and `roomProfile` values are filled in by the server.
209
+ - `admit` is still validated: any returned `roomId` must match the join request room id, and any returned `roomProfile.roomId` must match the resolved room id.
209
210
  - `onJoin(memberProfile, ctx)`: called after a successful join.
210
211
  - `onLeave(memberProfile, ctx)`: called on leave and during socket disconnect cleanup for joined rooms when auth is available for cleanup.
211
212
  - `onDisconnect(socket, auth)`: optional transport-disconnect hook.
package/changelog.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.5
4
+
5
+ - Made `onAuth` optional in server configs.
6
+ - Made `admit` optional and allowed it to return partial admission data.
7
+ - Added runtime defaults for missing admission fields and validation for room identity.
8
+ - Updated docs and tests for the new auth and admission behavior.
9
+
10
+ ## 1.0.4
11
+
12
+ - Added `serveRoomType(...).cleanup()` as the explicit server-handle teardown API.
13
+ - Added `JoinedRoom.listen({ events, presence })` for batched subscription setup.
14
+ - Improved reconnect replay for joined rooms and transport state tracking.
15
+
16
+ ## 1.0.3
17
+
18
+ - Hardened client and server event handling with payload validation and safe handler-name checks.
19
+ - Added acknowledgement timeouts and listener error isolation on the client.
20
+ - Added server-side request limits and safer wire-frame parsing.
21
+
22
+ ## 1.0.2
23
+
24
+ - Hardened room-key comparison in the example server with timing-safe equality.
25
+ - Tightened server join validation and static file handling.
26
+ - Cleaned up the example server routing and path resolution.
27
+
28
+ ## 1.0.1
29
+
30
+ - Updated package metadata for ESM publishing.
31
+ - Cleaned up the README packaging docs.
32
+ - Simplified the package and JSR metadata layout.
33
+
3
34
  ## 1.0.0
4
35
 
5
36
  - Initial release of `room-kit`.
@@ -10,4 +41,4 @@
10
41
  - Added reconnect replay for active stream subscriptions and room memberships.
11
42
  - Added Socket.IO client and server adapters for room-aware sends and membership mutation.
12
43
  - Added a JSR-ready package entrypoint via `jsr.json`.
13
- - Expanded the README with current client, server, and JSR examples.
44
+ - Expanded the README with current client, server, and JSR examples.
@@ -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,EAKjB,MAAM,SAAS,CAAC;AAsCjB;;;;;;;;;;;;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"}
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
- const handlers = state.eventListeners.get(key) ?? new Set();
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.presenceListeners.add(handler);
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
- handler(frame.payload, meta);
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
- handler(state.presenceCurrent);
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
- listener(next);
376
+ try {
377
+ listener(next);
378
+ }
379
+ catch {
380
+ // Swallow per-listener errors
381
+ }
315
382
  }
316
383
  }
317
384
  //# sourceMappingURL=client.js.map
@@ -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/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export { ClientSafeError } from "./types";
2
2
  export { createRoomClient } from "./client";
3
3
  export { defineRoomType } from "./room";
4
4
  export { serveRoomType } from "./server";
5
- export type { ClientConnectionState, ClientSocketLike, EventMetaFor, JoinRequest, JoinedRoom, MemberProfileFor, PresenceListQuery, PresenceFor, PresencePageFor, PresencePolicy, RoomMemberSnapshot, RoomClient, RoomDefinition, RoomEvents, RoomProfileFor, RoomRpc, RoomSchema, ServerStateFor, RoomServerAdapter, RoomServerBroadcastApi, RoomServerHandle, RoomServerContext, RoomServerHandlers, RoomSnapshot, ServerAdmission, ServerSocketLike, VisibleMemberFor, } from "./types";
5
+ export type { ClientConnectionState, ClientSocketLike, EventMetaFor, JoinRequest, JoinedRoom, MemberProfileFor, PresenceListQuery, PresenceFor, PresencePageFor, PresencePolicy, RoomMemberSnapshot, RoomClient, RoomDefinition, RoomEvents, RoomProfileFor, RoomRpc, RoomSchema, ServerStateFor, RoomServerAdapter, RoomServerBroadcastApi, RoomServerHandle, RoomServerContext, RoomServerHandlers, RoomSnapshot, ServerAdmission, ServerAdmissionInput, ServerSocketLike, VisibleMemberFor, } from "./types";
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,YAAY,EACR,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,UAAU,EACV,cAAc,EACd,OAAO,EACP,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,YAAY,EACR,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,UAAU,EACV,cAAc,EACd,OAAO,EACP,UAAU,EACV,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,SAAS,CAAC"}
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 callable handle that unregisters all listeners for the bound
6
- * socket, and exposes room introspection helpers.
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 stop = serveRoomType(socket, chatRoomType, {
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
- * // stop();
22
+ * // handle.cleanup();
23
23
  * });
24
24
  * ```
25
25
  */
@@ -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;AAoCjB;;;;;;;;;;;;;;;;;;;;;;;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,CAyVzB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAWR,cAAc,EAGd,iBAAiB,EAEjB,gBAAgB,EAEhB,kBAAkB,EAElB,gBAAgB,EAKnB,MAAM,SAAS,CAAC;AAmKjB;;;;;;;;;;;;;;;;;;;;;;;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,CAsXzB"}
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 callable handle that unregisters all listeners for the bound
14
- * socket, and exposes room introspection helpers.
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 stop = serveRoomType(socket, chatRoomType, {
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
- * // stop();
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 (frame, ack) => {
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,
@@ -53,8 +149,7 @@ export function serveRoomType(socket, _room, handlers, adapter) {
53
149
  roomProfile: undefined,
54
150
  serverState: initialState,
55
151
  });
56
- const admission = await handlers.admit(frame.payload, provisional);
57
- assertMatchingRoomIds(requestedRoomId, admission.roomId, admission.roomProfile.roomId);
152
+ const admission = await resolveAdmission(socket, handlers, requestedRoomId, frame.payload, provisional);
58
153
  const roomState = roomCollection.get(admission.roomId) ?? {
59
154
  presence: _room.presence,
60
155
  roomProfile: admission.roomProfile,
@@ -62,6 +157,9 @@ export function serveRoomType(socket, _room, handlers, adapter) {
62
157
  membersBySocketId: new Map(),
63
158
  socketIdsByMemberId: new Map(),
64
159
  };
160
+ if (!roomState.membersBySocketId.has(socket.id) && roomState.membersBySocketId.size >= MAX_MEMBERS_PER_ROOM) {
161
+ throw new ClientSafeError("Room is full");
162
+ }
65
163
  roomState.roomProfile = roomState.roomProfile ?? admission.roomProfile;
66
164
  roomState.serverState = roomState.serverState ?? provisional.serverState;
67
165
  roomState.membersBySocketId.set(socket.id, {
@@ -97,8 +195,12 @@ export function serveRoomType(socket, _room, handlers, adapter) {
97
195
  ack?.({ ok: false, error: toErrorMessage(error) });
98
196
  }
99
197
  };
100
- const onLeave = async (payload, ack) => {
198
+ const onLeave = async (raw, ack) => {
101
199
  try {
200
+ if (ack !== undefined && typeof ack !== "function") {
201
+ return;
202
+ }
203
+ const payload = validateLeaveFrame(raw);
102
204
  assertMatchingRoomName(_room, payload.roomType);
103
205
  const stored = getStoredMembership(namespaceState, payload.roomType, payload.roomId, socket.id);
104
206
  if (!stored) {
@@ -125,9 +227,14 @@ export function serveRoomType(socket, _room, handlers, adapter) {
125
227
  ack?.({ ok: false, error: toErrorMessage(error) });
126
228
  }
127
229
  };
128
- const onRpc = async (frame, ack) => {
230
+ const onRpc = async (raw, ack) => {
129
231
  try {
232
+ if (ack !== undefined && typeof ack !== "function") {
233
+ return;
234
+ }
235
+ const frame = validateRpcFrame(raw);
130
236
  assertMatchingRoomName(_room, frame.roomType);
237
+ assertSafeHandlerName(frame.name);
131
238
  if (!handlers.rpc || !Object.hasOwn(handlers.rpc, frame.name)) {
132
239
  throw new ClientSafeError(`Unknown RPC '${frame.name}'`);
133
240
  }
@@ -150,6 +257,9 @@ export function serveRoomType(socket, _room, handlers, adapter) {
150
257
  roomProfile: getRoomState(namespaceState, frame.roomType, frame.roomId).roomProfile,
151
258
  serverState: getRoomState(namespaceState, frame.roomType, frame.roomId).serverState,
152
259
  });
260
+ if (frame.args.length > 64) {
261
+ throw new ClientSafeError("Too many RPC arguments");
262
+ }
153
263
  const result = await handler(...frame.args, ctx);
154
264
  ack?.({ ok: true, value: result });
155
265
  }
@@ -157,9 +267,14 @@ export function serveRoomType(socket, _room, handlers, adapter) {
157
267
  ack?.({ ok: false, error: toErrorMessage(error) });
158
268
  }
159
269
  };
160
- const onClientEvent = async (frame, ack) => {
270
+ const onClientEvent = async (raw, ack) => {
161
271
  try {
272
+ if (ack !== undefined && typeof ack !== "function") {
273
+ return;
274
+ }
275
+ const frame = validateClientEventFrame(raw);
162
276
  assertMatchingRoomName(_room, frame.roomType);
277
+ assertSafeHandlerName(frame.name);
163
278
  const stored = getStoredMembership(namespaceState, frame.roomType, frame.roomId, socket.id);
164
279
  if (!stored) {
165
280
  throw new ClientSafeError("Socket is not joined to that room");
@@ -194,8 +309,12 @@ export function serveRoomType(socket, _room, handlers, adapter) {
194
309
  ack?.({ ok: false, error: toErrorMessage(error) });
195
310
  }
196
311
  };
197
- const onPresenceQuery = async (frame, ack) => {
312
+ const onPresenceQuery = async (raw, ack) => {
198
313
  try {
314
+ if (ack !== undefined && typeof ack !== "function") {
315
+ return;
316
+ }
317
+ const frame = validatePresenceQueryFrame(raw);
199
318
  assertMatchingRoomName(_room, frame.roomType);
200
319
  const stored = getStoredMembership(namespaceState, frame.roomType, frame.roomId, socket.id);
201
320
  if (!stored) {
@@ -297,7 +416,7 @@ export function serveRoomType(socket, _room, handlers, adapter) {
297
416
  })
298
417
  .catch(() => undefined);
299
418
  }
300
- const stop = () => {
419
+ const cleanup = () => {
301
420
  socket.off(JOIN_EVENT, onJoin);
302
421
  socket.off(LEAVE_EVENT, onLeave);
303
422
  socket.off(RPC_EVENT, onRpc);
@@ -305,12 +424,13 @@ export function serveRoomType(socket, _room, handlers, adapter) {
305
424
  socket.off(PRESENCE_QUERY_EVENT, onPresenceQuery);
306
425
  socket.off("disconnect", onDisconnect);
307
426
  };
308
- return Object.assign(stop, {
427
+ return {
428
+ cleanup,
309
429
  rooms: () => listRoomSnapshots(namespaceState, _room.name),
310
430
  room: (roomId) => getRoomSnapshot(namespaceState, _room.name, roomId),
311
431
  members: (roomId, query) => getPresenceMembersPage(namespaceState, _room.name, roomId, query),
312
432
  count: (roomId) => getPresenceCount(namespaceState, _room.name, roomId),
313
- });
433
+ };
314
434
  }
315
435
  function createContext(socket, namespaceState, ctxState) {
316
436
  const emit = createEventEmitApi((eventName, payload) => {
@@ -353,11 +473,16 @@ async function resolveSocketAuth(socket, handlers, authCache, revalidate) {
353
473
  if (entry.pending) {
354
474
  return entry.pending;
355
475
  }
356
- if (entry.value === undefined) {
476
+ if (!entry.hasValue) {
357
477
  const pending = Promise.resolve(handlers.onAuth?.(socket))
358
478
  .then((auth) => {
479
+ if (auth === false) {
480
+ authCache.delete(socket);
481
+ throw new ClientSafeError("Unauthorized");
482
+ }
359
483
  const current = authCache.get(socket) ?? {};
360
484
  current.value = auth;
485
+ current.hasValue = true;
361
486
  current.pending = undefined;
362
487
  authCache.set(socket, current);
363
488
  return auth;
@@ -386,6 +511,18 @@ async function resolveSocketAuth(socket, handlers, authCache, revalidate) {
386
511
  }
387
512
  handleRejectedAuth(authCache, socket, decision);
388
513
  }
514
+ async function resolveAdmission(socket, handlers, joinRoomId, join, ctx) {
515
+ const admission = handlers.admit ? await Promise.resolve(handlers.admit(join, ctx)) : {};
516
+ const roomId = admission.roomId ?? joinRoomId;
517
+ const roomProfile = admission.roomProfile ?? { roomId };
518
+ assertMatchingRoomIds(joinRoomId, roomId, roomProfile.roomId);
519
+ return {
520
+ roomId,
521
+ memberId: admission.memberId ?? socket.id,
522
+ memberProfile: admission.memberProfile ?? {},
523
+ roomProfile,
524
+ };
525
+ }
389
526
  function handleRejectedAuth(authCache, socket, decision) {
390
527
  authCache.delete(socket);
391
528
  throw new ClientSafeError(decision.message ?? "Unauthorized");
@@ -737,7 +874,11 @@ function extractRoomId(payload) {
737
874
  if (!payload || typeof payload !== "object" || typeof payload.roomId !== "string") {
738
875
  throw new ClientSafeError("Join request must include a string roomId");
739
876
  }
740
- return payload.roomId;
877
+ const roomId = payload.roomId;
878
+ if (roomId.length === 0 || roomId.length > 256) {
879
+ throw new ClientSafeError("roomId must be between 1 and 256 characters");
880
+ }
881
+ return roomId;
741
882
  }
742
883
  function toErrorMessage(error) {
743
884
  return error instanceof ClientSafeError ? error.message : "An internal server error occurred.";