mates-fullstack 1.0.0-beta.1

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.
Files changed (202) hide show
  1. package/README.md +311 -0
  2. package/dist/arctic-auth.d.ts +101 -0
  3. package/dist/arctic-auth.d.ts.map +1 -0
  4. package/dist/arctic-auth.js +538 -0
  5. package/dist/arctic-auth.js.map +1 -0
  6. package/dist/asset-manifest.d.ts +14 -0
  7. package/dist/asset-manifest.d.ts.map +1 -0
  8. package/dist/asset-manifest.js +102 -0
  9. package/dist/asset-manifest.js.map +1 -0
  10. package/dist/browser.d.ts +18 -0
  11. package/dist/browser.d.ts.map +1 -0
  12. package/dist/browser.js +25 -0
  13. package/dist/browser.js.map +1 -0
  14. package/dist/build-esbuild.d.ts +29 -0
  15. package/dist/build-esbuild.d.ts.map +1 -0
  16. package/dist/build-esbuild.js +699 -0
  17. package/dist/build-esbuild.js.map +1 -0
  18. package/dist/build-prod.d.ts +126 -0
  19. package/dist/build-prod.d.ts.map +1 -0
  20. package/dist/build-prod.js +1014 -0
  21. package/dist/build-prod.js.map +1 -0
  22. package/dist/cli-new.d.ts +14 -0
  23. package/dist/cli-new.d.ts.map +1 -0
  24. package/dist/cli-new.js +637 -0
  25. package/dist/cli-new.js.map +1 -0
  26. package/dist/client.d.ts +43 -0
  27. package/dist/client.d.ts.map +1 -0
  28. package/dist/client.js +130 -0
  29. package/dist/client.js.map +1 -0
  30. package/dist/cors.d.ts +16 -0
  31. package/dist/cors.d.ts.map +1 -0
  32. package/dist/cors.js +60 -0
  33. package/dist/cors.js.map +1 -0
  34. package/dist/ctx.d.ts +78 -0
  35. package/dist/ctx.d.ts.map +1 -0
  36. package/dist/ctx.js +280 -0
  37. package/dist/ctx.js.map +1 -0
  38. package/dist/dev-watcher.d.ts +23 -0
  39. package/dist/dev-watcher.d.ts.map +1 -0
  40. package/dist/dev-watcher.js +136 -0
  41. package/dist/dev-watcher.js.map +1 -0
  42. package/dist/docs-generator.d.ts +69 -0
  43. package/dist/docs-generator.d.ts.map +1 -0
  44. package/dist/docs-generator.js +557 -0
  45. package/dist/docs-generator.js.map +1 -0
  46. package/dist/docs-page.d.ts +20 -0
  47. package/dist/docs-page.d.ts.map +1 -0
  48. package/dist/docs-page.js +1152 -0
  49. package/dist/docs-page.js.map +1 -0
  50. package/dist/download.d.ts +78 -0
  51. package/dist/download.d.ts.map +1 -0
  52. package/dist/download.js +202 -0
  53. package/dist/download.js.map +1 -0
  54. package/dist/env-loader.d.ts +76 -0
  55. package/dist/env-loader.d.ts.map +1 -0
  56. package/dist/env-loader.js +213 -0
  57. package/dist/env-loader.js.map +1 -0
  58. package/dist/errors.d.ts +146 -0
  59. package/dist/errors.d.ts.map +1 -0
  60. package/dist/errors.js +386 -0
  61. package/dist/errors.js.map +1 -0
  62. package/dist/head.d.ts +31 -0
  63. package/dist/head.d.ts.map +1 -0
  64. package/dist/head.js +245 -0
  65. package/dist/head.js.map +1 -0
  66. package/dist/index.d.ts +30 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +30 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/internal-prefixes.d.ts +16 -0
  71. package/dist/internal-prefixes.d.ts.map +1 -0
  72. package/dist/internal-prefixes.js +16 -0
  73. package/dist/internal-prefixes.js.map +1 -0
  74. package/dist/internal.d.ts +25 -0
  75. package/dist/internal.d.ts.map +1 -0
  76. package/dist/internal.js +25 -0
  77. package/dist/internal.js.map +1 -0
  78. package/dist/jwt.d.ts +166 -0
  79. package/dist/jwt.d.ts.map +1 -0
  80. package/dist/jwt.js +261 -0
  81. package/dist/jwt.js.map +1 -0
  82. package/dist/log.d.ts +44 -0
  83. package/dist/log.d.ts.map +1 -0
  84. package/dist/log.js +66 -0
  85. package/dist/log.js.map +1 -0
  86. package/dist/logger.d.ts +76 -0
  87. package/dist/logger.d.ts.map +1 -0
  88. package/dist/logger.js +138 -0
  89. package/dist/logger.js.map +1 -0
  90. package/dist/main-runner.d.ts +59 -0
  91. package/dist/main-runner.d.ts.map +1 -0
  92. package/dist/main-runner.js +157 -0
  93. package/dist/main-runner.js.map +1 -0
  94. package/dist/mates-auth.d.ts +82 -0
  95. package/dist/mates-auth.d.ts.map +1 -0
  96. package/dist/mates-auth.js +323 -0
  97. package/dist/mates-auth.js.map +1 -0
  98. package/dist/middleware.d.ts +30 -0
  99. package/dist/middleware.d.ts.map +1 -0
  100. package/dist/middleware.js +67 -0
  101. package/dist/middleware.js.map +1 -0
  102. package/dist/project-resolver.d.ts +102 -0
  103. package/dist/project-resolver.d.ts.map +1 -0
  104. package/dist/project-resolver.js +271 -0
  105. package/dist/project-resolver.js.map +1 -0
  106. package/dist/rate-limit.d.ts +37 -0
  107. package/dist/rate-limit.d.ts.map +1 -0
  108. package/dist/rate-limit.js +109 -0
  109. package/dist/rate-limit.js.map +1 -0
  110. package/dist/redirect.d.ts +84 -0
  111. package/dist/redirect.d.ts.map +1 -0
  112. package/dist/redirect.js +105 -0
  113. package/dist/redirect.js.map +1 -0
  114. package/dist/renderer.d.ts +91 -0
  115. package/dist/renderer.d.ts.map +1 -0
  116. package/dist/renderer.js +630 -0
  117. package/dist/renderer.js.map +1 -0
  118. package/dist/request-logger.d.ts +12 -0
  119. package/dist/request-logger.d.ts.map +1 -0
  120. package/dist/request-logger.js +55 -0
  121. package/dist/request-logger.js.map +1 -0
  122. package/dist/rest.d.ts +25 -0
  123. package/dist/rest.d.ts.map +1 -0
  124. package/dist/rest.js +93 -0
  125. package/dist/rest.js.map +1 -0
  126. package/dist/router.d.ts +71 -0
  127. package/dist/router.d.ts.map +1 -0
  128. package/dist/router.js +222 -0
  129. package/dist/router.js.map +1 -0
  130. package/dist/rpc-registry.d.ts +84 -0
  131. package/dist/rpc-registry.d.ts.map +1 -0
  132. package/dist/rpc-registry.js +271 -0
  133. package/dist/rpc-registry.js.map +1 -0
  134. package/dist/rpc-runner.d.ts +82 -0
  135. package/dist/rpc-runner.d.ts.map +1 -0
  136. package/dist/rpc-runner.js +564 -0
  137. package/dist/rpc-runner.js.map +1 -0
  138. package/dist/sanitize.d.ts +61 -0
  139. package/dist/sanitize.d.ts.map +1 -0
  140. package/dist/sanitize.js +193 -0
  141. package/dist/sanitize.js.map +1 -0
  142. package/dist/security-headers.d.ts +114 -0
  143. package/dist/security-headers.d.ts.map +1 -0
  144. package/dist/security-headers.js +121 -0
  145. package/dist/security-headers.js.map +1 -0
  146. package/dist/server-fn.d.ts +323 -0
  147. package/dist/server-fn.d.ts.map +1 -0
  148. package/dist/server-fn.js +373 -0
  149. package/dist/server-fn.js.map +1 -0
  150. package/dist/server-public.d.ts +13 -0
  151. package/dist/server-public.d.ts.map +1 -0
  152. package/dist/server-public.js +12 -0
  153. package/dist/server-public.js.map +1 -0
  154. package/dist/server-timeout.d.ts +38 -0
  155. package/dist/server-timeout.d.ts.map +1 -0
  156. package/dist/server-timeout.js +46 -0
  157. package/dist/server-timeout.js.map +1 -0
  158. package/dist/server.d.ts +100 -0
  159. package/dist/server.d.ts.map +1 -0
  160. package/dist/server.js +1218 -0
  161. package/dist/server.js.map +1 -0
  162. package/dist/socket-router.d.ts +153 -0
  163. package/dist/socket-router.d.ts.map +1 -0
  164. package/dist/socket-router.js +612 -0
  165. package/dist/socket-router.js.map +1 -0
  166. package/dist/sso.d.ts +90 -0
  167. package/dist/sso.d.ts.map +1 -0
  168. package/dist/sso.js +261 -0
  169. package/dist/sso.js.map +1 -0
  170. package/dist/ssr-context.d.ts +49 -0
  171. package/dist/ssr-context.d.ts.map +1 -0
  172. package/dist/ssr-context.js +85 -0
  173. package/dist/ssr-context.js.map +1 -0
  174. package/dist/ssr-globals.d.ts +32 -0
  175. package/dist/ssr-globals.d.ts.map +1 -0
  176. package/dist/ssr-globals.js +1010 -0
  177. package/dist/ssr-globals.js.map +1 -0
  178. package/dist/ssr-template.d.ts +73 -0
  179. package/dist/ssr-template.d.ts.map +1 -0
  180. package/dist/ssr-template.js +507 -0
  181. package/dist/ssr-template.js.map +1 -0
  182. package/dist/stack-mapper.d.ts +25 -0
  183. package/dist/stack-mapper.d.ts.map +1 -0
  184. package/dist/stack-mapper.js +139 -0
  185. package/dist/stack-mapper.js.map +1 -0
  186. package/dist/stream.d.ts +89 -0
  187. package/dist/stream.d.ts.map +1 -0
  188. package/dist/stream.js +299 -0
  189. package/dist/stream.js.map +1 -0
  190. package/dist/upload.d.ts +69 -0
  191. package/dist/upload.d.ts.map +1 -0
  192. package/dist/upload.js +110 -0
  193. package/dist/upload.js.map +1 -0
  194. package/dist/validate.d.ts +58 -0
  195. package/dist/validate.d.ts.map +1 -0
  196. package/dist/validate.js +89 -0
  197. package/dist/validate.js.map +1 -0
  198. package/dist/verify-package.d.ts +3 -0
  199. package/dist/verify-package.d.ts.map +1 -0
  200. package/dist/verify-package.js +128 -0
  201. package/dist/verify-package.js.map +1 -0
  202. package/package.json +79 -0
@@ -0,0 +1,612 @@
1
+ /**
2
+ * mates-fullstack — socket-router.ts
3
+ *
4
+ * WebSocket server for mates-fullstack using the `ws` npm package.
5
+ * Replaces the Bun-native WebSocket handler with a Node.js-compatible
6
+ * implementation.
7
+ *
8
+ * ─── File → route mapping ─────────────────────────────────────────────────────
9
+ *
10
+ * server/socket/chat.ts → ws://host/socket/chat
11
+ * server/socket/game/[id].ts → ws://host/socket/game/:id
12
+ * server/socket/index.ts → ws://host/socket
13
+ *
14
+ * ─── Handler exports ──────────────────────────────────────────────────────────
15
+ *
16
+ * export async function onConnect(ctx: SocketCtx): Promise<void>
17
+ * export async function onDisconnect(ctx: SocketCtx): Promise<void>
18
+ * // Any other exported async function → callable from client via WS RPC
19
+ * export async function sendMessage(payload: { text: string }, ctx: SocketCtx)
20
+ *
21
+ * ─── SocketCtx ────────────────────────────────────────────────────────────────
22
+ *
23
+ * Extends Context with:
24
+ * - id: string unique connection id
25
+ * - join(room): void join a room
26
+ * - leave(room): void leave a room
27
+ * - rooms: Set<string> rooms this connection is in
28
+ * - emit(event, data): void send to this client
29
+ * - to(room).emit(...) send to all in a room
30
+ * - broadcast(event, data) send to all except self
31
+ *
32
+ * ─── Security ──────────────────────────────────────────────────────────────────
33
+ *
34
+ * - Path traversal: resolved file paths are checked to stay inside socketDir
35
+ * - Private files (_*) and test files (*.test.*, *.spec.*) are skipped
36
+ * - Heartbeat: ping/pong every 30s to detect dead connections
37
+ * - Message size limit: 1MB per message
38
+ * - Max connections: configurable (default: unlimited)
39
+ */
40
+ import fs from "node:fs";
41
+ import path from "node:path";
42
+ import { devError, devWarn } from "./log.js";
43
+ import crypto from "node:crypto";
44
+ import { createContextFromHeaders } from "./ctx.js";
45
+ // ─── Room management ──────────────────────────────────────────────────────────
46
+ /** room name → Set of ws clients in that room */
47
+ const _rooms = new Map();
48
+ /** ws client → Set of room names it's in */
49
+ const _socketRooms = new Map();
50
+ /** connection id → ws client */
51
+ const _connections = new Map();
52
+ function _joinRoom(ws, room) {
53
+ if (!_rooms.has(room))
54
+ _rooms.set(room, new Set());
55
+ _rooms.get(room).add(ws);
56
+ if (!_socketRooms.has(ws))
57
+ _socketRooms.set(ws, new Set());
58
+ _socketRooms.get(ws).add(room);
59
+ }
60
+ function _leaveRoom(ws, room) {
61
+ _rooms.get(room)?.delete(ws);
62
+ if (_rooms.get(room)?.size === 0)
63
+ _rooms.delete(room);
64
+ _socketRooms.get(ws)?.delete(room);
65
+ }
66
+ function _leaveAllRooms(ws) {
67
+ const rooms = _socketRooms.get(ws);
68
+ if (!rooms)
69
+ return;
70
+ for (const room of rooms) {
71
+ _rooms.get(room)?.delete(ws);
72
+ if (_rooms.get(room)?.size === 0)
73
+ _rooms.delete(room);
74
+ }
75
+ _socketRooms.delete(ws);
76
+ }
77
+ function _emitToRoom(room, event, data, excludeWs) {
78
+ const clients = _rooms.get(room);
79
+ if (!clients)
80
+ return;
81
+ const msg = JSON.stringify({ event, data });
82
+ for (const client of clients) {
83
+ if (client === excludeWs)
84
+ continue;
85
+ // readyState 1 = OPEN
86
+ if (client.readyState === 1) {
87
+ try {
88
+ client.send(msg);
89
+ }
90
+ catch {
91
+ // Client disconnected between check and send — ignore
92
+ }
93
+ }
94
+ }
95
+ }
96
+ function _emitToAll(event, data, excludeWs) {
97
+ const msg = JSON.stringify({ event, data });
98
+ for (const client of _connections.values()) {
99
+ if (client === excludeWs)
100
+ continue;
101
+ if (client.readyState === 1) {
102
+ try {
103
+ client.send(msg);
104
+ }
105
+ catch {
106
+ /* ignore */
107
+ }
108
+ }
109
+ }
110
+ }
111
+ // ─── SocketCtx factory ────────────────────────────────────────────────────────
112
+ function _createSocketCtx(ws, id, incomingHeaders) {
113
+ const base = createContextFromHeaders(incomingHeaders);
114
+ const rooms = _socketRooms.get(ws) ?? new Set();
115
+ const ctx = {
116
+ ...base,
117
+ id,
118
+ rooms,
119
+ join(room) {
120
+ _joinRoom(ws, room);
121
+ },
122
+ leave(room) {
123
+ _leaveRoom(ws, room);
124
+ },
125
+ emit(event, data) {
126
+ if (ws.readyState === 1) {
127
+ try {
128
+ ws.send(JSON.stringify({ event, data }));
129
+ }
130
+ catch {
131
+ /* ignore */
132
+ }
133
+ }
134
+ },
135
+ to(room) {
136
+ return {
137
+ emit(event, data) {
138
+ _emitToRoom(room, event, data, undefined);
139
+ },
140
+ };
141
+ },
142
+ broadcast(event, data) {
143
+ _emitToAll(event, data, ws);
144
+ },
145
+ };
146
+ return ctx;
147
+ }
148
+ let _socketConnectHooks = [];
149
+ /**
150
+ * Register a global hook that runs on every WebSocket connection.
151
+ * Called before the route-specific onConnect handler.
152
+ * If a hook returns a Response, the connection is rejected.
153
+ * If a hook throws, the connection is rejected with a 1008 close code.
154
+ */
155
+ export function onSocketConnect(hook) {
156
+ _socketConnectHooks.push(hook);
157
+ }
158
+ /** Clear all registered socket connect hooks. */
159
+ export function clearSocketConnectHooks() {
160
+ _socketConnectHooks = [];
161
+ }
162
+ // ─── Registry ─────────────────────────────────────────────────────────────────
163
+ let _routes = [];
164
+ let _socketDir = null;
165
+ // ─── Scanner ──────────────────────────────────────────────────────────────────
166
+ /**
167
+ * Scan server/socket/ and register all socket handlers.
168
+ */
169
+ export async function scanSocketHandlers(socketDir, dev = false) {
170
+ if (!fs.existsSync(socketDir))
171
+ return;
172
+ _socketDir = socketDir;
173
+ _routes = [];
174
+ const files = _collectFiles(socketDir);
175
+ for (const filePath of files) {
176
+ const absSocket = path.resolve(socketDir);
177
+ const absFile = path.resolve(filePath);
178
+ if (!absFile.startsWith(absSocket + path.sep) && absFile !== absSocket) {
179
+ continue;
180
+ }
181
+ await _registerSocketFile(socketDir, filePath, dev);
182
+ }
183
+ _routes = _sortRoutes(_routes);
184
+ }
185
+ /**
186
+ * Look up a socket route by URL pathname.
187
+ */
188
+ export function matchSocketRoute(pathname) {
189
+ for (const entry of _routes) {
190
+ const params = _matchPattern(entry, pathname);
191
+ if (params !== null)
192
+ return { entry, params };
193
+ }
194
+ return null;
195
+ }
196
+ /**
197
+ * List all registered socket routes (for logging).
198
+ */
199
+ export function listSocketRoutes() {
200
+ return _routes.map((r) => ({ pattern: r.pattern }));
201
+ }
202
+ /**
203
+ * Clear the registry. Used before a rescan or in tests.
204
+ */
205
+ export function clearSocketRoutes() {
206
+ _routes = [];
207
+ _socketDir = null;
208
+ }
209
+ /**
210
+ * Watch server/socket/ for changes and trigger a rescan.
211
+ */
212
+ export function watchSocketRoutes(socketDir, onChange) {
213
+ if (!fs.existsSync(socketDir))
214
+ return () => { };
215
+ let debounce = null;
216
+ const watcher = fs.watch(socketDir, { recursive: true }, (event, filename) => {
217
+ if (!filename)
218
+ return;
219
+ if (!_isSocketFile(path.basename(filename)))
220
+ return;
221
+ if (debounce)
222
+ clearTimeout(debounce);
223
+ debounce = setTimeout(async () => {
224
+ await scanSocketHandlers(socketDir, true);
225
+ onChange();
226
+ }, 50);
227
+ });
228
+ return () => {
229
+ if (debounce)
230
+ clearTimeout(debounce);
231
+ watcher.close();
232
+ };
233
+ }
234
+ /**
235
+ * Attach a WebSocket server to the HTTP server.
236
+ * Handles upgrade events, routing, lifecycle, and RPC calls.
237
+ * Returns a cleanup function.
238
+ */
239
+ export async function attachSocketServer(options) {
240
+ const { server, dev, maxMessageBytes = 1 * 1024 * 1024, heartbeatIntervalMs = 30000, } = options;
241
+ // Lazy-import ws — not required if no WebSockets are used
242
+ let ws;
243
+ try {
244
+ ws = await import("ws");
245
+ }
246
+ catch {
247
+ devWarn("[mates-fullstack] WebSocket support requires the 'ws' package.\n" +
248
+ " Install it: npm install ws");
249
+ return () => { };
250
+ }
251
+ const { WebSocketServer } = ws;
252
+ const wss = new WebSocketServer({
253
+ noServer: true,
254
+ maxPayload: maxMessageBytes,
255
+ });
256
+ // ── Upgrade handler ────────────────────────────────────────────────────────
257
+ const _upgradeHandler = (req, socket, head) => {
258
+ // ── Origin validation (CSWSH prevention) ──────────────────────────────
259
+ const origin = req.headers.origin;
260
+ if (origin) {
261
+ const allowedOrigins = options.allowedOrigins;
262
+ if (allowedOrigins?.includes("*")) {
263
+ // Wildcard — allow all origins (explicit opt-in)
264
+ }
265
+ else if (allowedOrigins && allowedOrigins.length > 0) {
266
+ // Specific origins — must match exactly
267
+ let ok = false;
268
+ for (const allowed of allowedOrigins) {
269
+ if (allowed === origin) {
270
+ ok = true;
271
+ break;
272
+ }
273
+ }
274
+ if (!ok) {
275
+ socket.destroy();
276
+ return;
277
+ }
278
+ }
279
+ else {
280
+ // Default: same-origin only — origin must match request Host
281
+ const host = req.headers.host;
282
+ if (host) {
283
+ try {
284
+ const originUrl = new URL(origin);
285
+ if (originUrl.host !== host) {
286
+ socket.destroy();
287
+ return;
288
+ }
289
+ }
290
+ catch {
291
+ socket.destroy();
292
+ return;
293
+ }
294
+ }
295
+ }
296
+ }
297
+ // No Origin header — allow (non-browser clients like mobile apps)
298
+ let url;
299
+ try {
300
+ url = new URL(req.url ?? "/", "http://localhost");
301
+ }
302
+ catch {
303
+ socket.destroy();
304
+ return;
305
+ }
306
+ const pathname = url.pathname;
307
+ // Only handle /socket/** paths
308
+ if (!pathname.startsWith("/socket")) {
309
+ socket.destroy();
310
+ return;
311
+ }
312
+ const match = matchSocketRoute(pathname);
313
+ if (!match) {
314
+ // No handler registered for this path
315
+ socket.write("HTTP/1.1 404 Not Found\r\n" +
316
+ "Content-Type: text/plain\r\n\r\n" +
317
+ "WebSocket endpoint not found");
318
+ socket.destroy();
319
+ return;
320
+ }
321
+ wss.handleUpgrade(req, socket, head, (wsClient) => {
322
+ wss.emit("connection", wsClient, req, match);
323
+ });
324
+ };
325
+ server.on("upgrade", _upgradeHandler);
326
+ // ── Connection handler ─────────────────────────────────────────────────────
327
+ wss.on("connection", async (wsClient, req, match) => {
328
+ // Assign unique ID
329
+ const id = crypto.randomUUID();
330
+ wsClient._matesId = id;
331
+ wsClient.isAlive = true;
332
+ // Track connection
333
+ _connections.set(id, wsClient);
334
+ _socketRooms.set(wsClient, new Set());
335
+ // Normalize headers for ctx
336
+ const headers = {};
337
+ for (const [key, val] of Object.entries(req.headers)) {
338
+ if (typeof val === "string")
339
+ headers[key.toLowerCase()] = val;
340
+ else if (Array.isArray(val))
341
+ headers[key.toLowerCase()] = val.join(", ");
342
+ }
343
+ const ctx = _createSocketCtx(wsClient, id, headers);
344
+ // ── Global socket connect hooks ─────────────────────────────────────
345
+ // Run global hooks before the route-specific onConnect.
346
+ // Auth middleware registers here to process cookies and populate ctx.auth.
347
+ let hookRejected = false;
348
+ for (const hook of _socketConnectHooks) {
349
+ try {
350
+ const result = await hook(ctx, req);
351
+ if (result instanceof Response) {
352
+ wsClient.close(1008, "Connection rejected");
353
+ hookRejected = true;
354
+ return;
355
+ }
356
+ }
357
+ catch (err) {
358
+ devError("socket connect hook error:", err);
359
+ wsClient.close(1008, "Connection rejected");
360
+ hookRejected = true;
361
+ return;
362
+ }
363
+ }
364
+ if (hookRejected)
365
+ return;
366
+ // ── onConnect ───────────────────────────────────────────────────────
367
+ if (match.entry.handlers.onConnect) {
368
+ try {
369
+ await match.entry.handlers.onConnect(ctx);
370
+ }
371
+ catch (err) {
372
+ devError("socket onConnect error:", err);
373
+ // Close on auth errors etc.
374
+ wsClient.close(1008, "Connection rejected");
375
+ return;
376
+ }
377
+ }
378
+ // ── Message handler ─────────────────────────────────────────────────
379
+ wsClient.on("message", async (raw) => {
380
+ wsClient.isAlive = true; // reset heartbeat
381
+ // Parse message envelope: { fnName, payload }
382
+ let envelope;
383
+ try {
384
+ const str = typeof raw === "string" ? raw : raw.toString("utf-8");
385
+ envelope = JSON.parse(str);
386
+ }
387
+ catch {
388
+ wsClient.send(JSON.stringify({
389
+ event: "error",
390
+ data: { message: "Invalid JSON" },
391
+ }));
392
+ return;
393
+ }
394
+ const fnName = envelope.fnName;
395
+ const payload = envelope.payload ?? {};
396
+ if (!fnName || typeof fnName !== "string") {
397
+ wsClient.send(JSON.stringify({
398
+ event: "error",
399
+ data: { message: "Missing fnName in message envelope" },
400
+ }));
401
+ return;
402
+ }
403
+ // Reserved names — not callable as RPC
404
+ if (fnName === "onConnect" || fnName === "onDisconnect") {
405
+ wsClient.send(JSON.stringify({
406
+ event: "error",
407
+ data: { message: `"${fnName}" is not callable` },
408
+ }));
409
+ return;
410
+ }
411
+ const handler = match.entry.handlers[fnName];
412
+ if (typeof handler !== "function") {
413
+ wsClient.send(JSON.stringify({
414
+ event: "error",
415
+ data: { message: `No handler for "${fnName}"` },
416
+ }));
417
+ return;
418
+ }
419
+ try {
420
+ const result = await handler(payload, ctx);
421
+ // Send result back if the function returned something
422
+ if (result !== undefined) {
423
+ wsClient.send(JSON.stringify({ event: `${fnName}:result`, data: result }));
424
+ }
425
+ }
426
+ catch (err) {
427
+ devError(`socket "${fnName}" error:`, err);
428
+ wsClient.send(JSON.stringify({
429
+ event: "error",
430
+ data: {
431
+ message: err?.message ?? "Server error",
432
+ fnName,
433
+ },
434
+ }));
435
+ }
436
+ });
437
+ // ── Pong handler (heartbeat) ─────────────────────────────────────────
438
+ wsClient.on("pong", () => {
439
+ wsClient.isAlive = true;
440
+ });
441
+ // ── Close handler ───────────────────────────────────────────────────
442
+ wsClient.on("close", async () => {
443
+ _connections.delete(id);
444
+ _leaveAllRooms(wsClient);
445
+ if (match.entry.handlers.onDisconnect) {
446
+ try {
447
+ await match.entry.handlers.onDisconnect(ctx);
448
+ }
449
+ catch (err) {
450
+ devError("socket onDisconnect error:", err);
451
+ }
452
+ }
453
+ });
454
+ // ── Error handler ───────────────────────────────────────────────────
455
+ wsClient.on("error", (err) => {
456
+ devError("socket error:", err.message);
457
+ });
458
+ });
459
+ // ── Heartbeat interval ─────────────────────────────────────────────────────
460
+ const heartbeatInterval = setInterval(() => {
461
+ for (const client of wss.clients) {
462
+ if (client.isAlive === false) {
463
+ // No pong received — terminate dead connection
464
+ client.terminate();
465
+ continue;
466
+ }
467
+ client.isAlive = false;
468
+ client.ping();
469
+ }
470
+ }, heartbeatIntervalMs);
471
+ // Cleanup — properly detach all listeners
472
+ return () => {
473
+ clearInterval(heartbeatInterval);
474
+ server.removeListener("upgrade", _upgradeHandler);
475
+ wss.close();
476
+ _connections.clear();
477
+ _rooms.clear();
478
+ _socketRooms.clear();
479
+ };
480
+ }
481
+ // ─── URL derivation ───────────────────────────────────────────────────────────
482
+ /**
483
+ * Derive the URL pattern for a socket file.
484
+ *
485
+ * Examples (socketDir = /project/server/socket):
486
+ * /project/server/socket/chat.ts → /socket/chat
487
+ * /project/server/socket/game/[id].ts → /socket/game/:id
488
+ * /project/server/socket/index.ts → /socket
489
+ */
490
+ export function deriveSocketPattern(socketDir, filePath) {
491
+ const rel = path.relative(socketDir, filePath);
492
+ const withoutExt = rel.replace(/\.(ts|js|tsx|jsx)$/, "");
493
+ const rawSegs = withoutExt.split(path.sep);
494
+ const segs = rawSegs[rawSegs.length - 1] === "index" ? rawSegs.slice(0, -1) : rawSegs;
495
+ const paramNames = [];
496
+ const parts = ["socket"]; // always prefix with /socket
497
+ for (const seg of segs) {
498
+ if (seg.startsWith("[...") && seg.endsWith("]")) {
499
+ // Catch-all not typically needed for WS but support it
500
+ paramNames.push(seg.slice(4, -1));
501
+ parts.push("*");
502
+ }
503
+ else if (seg.startsWith("[") && seg.endsWith("]")) {
504
+ const name = seg.slice(1, -1);
505
+ paramNames.push(name);
506
+ parts.push(`:${name}`);
507
+ }
508
+ else {
509
+ parts.push(seg);
510
+ }
511
+ }
512
+ const pattern = "/" + parts.join("/");
513
+ return { pattern, paramNames };
514
+ }
515
+ // ─── Internal ─────────────────────────────────────────────────────────────────
516
+ async function _registerSocketFile(socketDir, filePath, dev) {
517
+ const importSpecifier = dev ? `${filePath}?t=${Date.now()}` : filePath;
518
+ let mod;
519
+ try {
520
+ mod = await import(importSpecifier);
521
+ }
522
+ catch (err) {
523
+ devError(`failed to import socket handler ` +
524
+ `${path.relative(socketDir, filePath)}: ${err?.message ?? err}`);
525
+ return;
526
+ }
527
+ const handlers = {};
528
+ let hasHandlers = false;
529
+ for (const [exportName, exportValue] of Object.entries(mod)) {
530
+ if (exportName === "default")
531
+ continue;
532
+ if (typeof exportValue !== "function")
533
+ continue;
534
+ handlers[exportName] = exportValue;
535
+ hasHandlers = true;
536
+ }
537
+ if (!hasHandlers) {
538
+ devWarn(`${path.relative(socketDir, filePath)} ` +
539
+ `has no exported functions — skipped.`);
540
+ return;
541
+ }
542
+ const { pattern, paramNames } = deriveSocketPattern(socketDir, filePath);
543
+ _routes.push({ pattern, paramNames, handlers, filePath });
544
+ }
545
+ function _matchPattern(entry, pathname) {
546
+ const normalizedPath = pathname.length > 1 && pathname.endsWith("/")
547
+ ? pathname.slice(0, -1)
548
+ : pathname;
549
+ const routeSegs = entry.pattern.split("/").filter(Boolean);
550
+ const pathSegs = normalizedPath.split("/").filter(Boolean);
551
+ if (routeSegs.length !== pathSegs.length)
552
+ return null;
553
+ const params = {};
554
+ for (let i = 0; i < routeSegs.length; i++) {
555
+ const rs = routeSegs[i];
556
+ const ps = pathSegs[i];
557
+ if (rs.startsWith(":")) {
558
+ try {
559
+ params[rs.slice(1)] = decodeURIComponent(ps);
560
+ }
561
+ catch {
562
+ params[rs.slice(1)] = ps;
563
+ }
564
+ }
565
+ else if (rs !== ps) {
566
+ return null;
567
+ }
568
+ }
569
+ return params;
570
+ }
571
+ function _sortRoutes(entries) {
572
+ return [...entries].sort((a, b) => {
573
+ const aSegs = a.pattern.split("/").filter(Boolean).length;
574
+ const bSegs = b.pattern.split("/").filter(Boolean).length;
575
+ if (aSegs !== bSegs)
576
+ return bSegs - aSegs;
577
+ return a.paramNames.length - b.paramNames.length;
578
+ });
579
+ }
580
+ function _collectFiles(dir) {
581
+ const results = [];
582
+ _walk(dir, results);
583
+ return results;
584
+ }
585
+ function _walk(dir, out) {
586
+ let entries;
587
+ try {
588
+ entries = fs.readdirSync(dir, { withFileTypes: true });
589
+ }
590
+ catch {
591
+ return;
592
+ }
593
+ for (const entry of entries) {
594
+ const full = path.join(dir, entry.name);
595
+ if (entry.isDirectory()) {
596
+ _walk(full, out);
597
+ }
598
+ else if (_isSocketFile(entry.name)) {
599
+ out.push(full);
600
+ }
601
+ }
602
+ }
603
+ function _isSocketFile(filename) {
604
+ if (filename.startsWith("_"))
605
+ return false;
606
+ if (filename.startsWith("."))
607
+ return false;
608
+ if (filename.includes(".test.") || filename.includes(".spec."))
609
+ return false;
610
+ return /\.(ts|js|tsx|jsx)$/.test(filename);
611
+ }
612
+ //# sourceMappingURL=socket-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-router.js","sourceRoot":"","sources":["../src/socket-router.ts"],"names":[],"mappings":"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"}