@morojs/moro 1.8.12 → 1.8.13

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 (84) hide show
  1. package/README.md +4 -2
  2. package/dist/core/cluster/thread-cluster.d.ts +25 -0
  3. package/dist/core/cluster/thread-cluster.js +95 -3
  4. package/dist/core/cluster/thread-cluster.js.map +1 -1
  5. package/dist/core/config/config-validator.js +15 -0
  6. package/dist/core/config/config-validator.js.map +1 -1
  7. package/dist/core/config/index.js +19 -2
  8. package/dist/core/config/index.js.map +1 -1
  9. package/dist/core/framework.d.ts +26 -0
  10. package/dist/core/framework.js +195 -6
  11. package/dist/core/framework.js.map +1 -1
  12. package/dist/core/http/http-server.d.ts +17 -0
  13. package/dist/core/http/http-server.js +21 -1
  14. package/dist/core/http/http-server.js.map +1 -1
  15. package/dist/core/http/http2-server.d.ts +13 -0
  16. package/dist/core/http/http2-server.js +11 -0
  17. package/dist/core/http/http2-server.js.map +1 -1
  18. package/dist/core/http/moro-engine-server.d.ts +28 -0
  19. package/dist/core/http/moro-engine-server.js +115 -11
  20. package/dist/core/http/moro-engine-server.js.map +1 -1
  21. package/dist/core/http/utils/body-type.d.ts +12 -0
  22. package/dist/core/http/utils/body-type.js +70 -0
  23. package/dist/core/http/utils/body-type.js.map +1 -0
  24. package/dist/core/http/utils/ssl-config.d.ts +11 -0
  25. package/dist/core/http/utils/ssl-config.js +3 -0
  26. package/dist/core/http/utils/ssl-config.js.map +1 -1
  27. package/dist/core/http/utils/uws-worker-clustering.js +5 -4
  28. package/dist/core/http/utils/uws-worker-clustering.js.map +1 -1
  29. package/dist/core/http/uws-http-server.d.ts +3 -0
  30. package/dist/core/http/uws-http-server.js +22 -1
  31. package/dist/core/http/uws-http-server.js.map +1 -1
  32. package/dist/core/middleware/built-in/body-parsers/index.d.ts +18 -0
  33. package/dist/core/middleware/built-in/body-parsers/index.js +41 -0
  34. package/dist/core/middleware/built-in/body-parsers/index.js.map +1 -1
  35. package/dist/core/middleware/built-in/cache/adapters/cache/redis.d.ts +32 -8
  36. package/dist/core/middleware/built-in/cache/adapters/cache/redis.js +117 -25
  37. package/dist/core/middleware/built-in/cache/adapters/cache/redis.js.map +1 -1
  38. package/dist/core/middleware/built-in/compression/core.js +5 -0
  39. package/dist/core/middleware/built-in/compression/core.js.map +1 -1
  40. package/dist/core/middleware/built-in/session/core.d.ts +1 -0
  41. package/dist/core/middleware/built-in/session/core.js.map +1 -1
  42. package/dist/core/middleware/built-in/static/core.d.ts +18 -0
  43. package/dist/core/middleware/built-in/static/core.js +128 -7
  44. package/dist/core/middleware/built-in/static/core.js.map +1 -1
  45. package/dist/core/networking/adapters/engine-adapter.d.ts +2 -2
  46. package/dist/core/networking/adapters/engine-adapter.js +40 -1
  47. package/dist/core/networking/adapters/engine-adapter.js.map +1 -1
  48. package/dist/core/networking/adapters/socketio-adapter.d.ts +2 -2
  49. package/dist/core/networking/adapters/socketio-adapter.js +10 -1
  50. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
  51. package/dist/core/networking/adapters/uws-adapter.d.ts +2 -2
  52. package/dist/core/networking/adapters/uws-adapter.js +54 -3
  53. package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
  54. package/dist/core/networking/adapters/ws-adapter.d.ts +9 -2
  55. package/dist/core/networking/adapters/ws-adapter.js +97 -12
  56. package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
  57. package/dist/core/networking/websocket-adapter.d.ts +19 -1
  58. package/dist/core/networking/websocket-adapter.js.map +1 -1
  59. package/dist/core/routing/index.d.ts +12 -8
  60. package/dist/core/routing/index.js +7 -2
  61. package/dist/core/routing/index.js.map +1 -1
  62. package/dist/core/routing/unified-router.d.ts +46 -8
  63. package/dist/core/routing/unified-router.js +108 -32
  64. package/dist/core/routing/unified-router.js.map +1 -1
  65. package/dist/core/utilities/package-utils.d.ts +7 -0
  66. package/dist/core/utilities/package-utils.js +2 -0
  67. package/dist/core/utilities/package-utils.js.map +1 -1
  68. package/dist/core/workers/worker-manager.js +2 -2
  69. package/dist/core/workers/worker-manager.js.map +1 -1
  70. package/dist/index.d.ts +4 -3
  71. package/dist/index.js +2 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/moro.d.ts +12 -1
  74. package/dist/moro.js +63 -7
  75. package/dist/moro.js.map +1 -1
  76. package/dist/types/cache.d.ts +2 -0
  77. package/dist/types/cache.js.map +1 -1
  78. package/dist/types/config.d.ts +9 -0
  79. package/dist/types/config.js.map +1 -1
  80. package/dist/types/http.d.ts +6 -0
  81. package/dist/types/http.js.map +1 -1
  82. package/dist/types/session.d.ts +1 -0
  83. package/dist/types/session.js.map +1 -1
  84. package/package.json +1 -1
@@ -14,14 +14,24 @@ export class WSAdapter {
14
14
  customIdGenerator;
15
15
  connectionCounter = 0;
16
16
  heartbeatTimer;
17
+ /** Upgrade path prefix (options.path, default '/ws'): namespaces live below it */
18
+ basePath = '/ws';
19
+ httpServer;
20
+ upgradeHandler;
17
21
  async initialize(httpServer, options = {}) {
18
22
  try {
19
23
  // Dynamic import from user's context to find their installed ws library
20
24
  const wsPath = resolveUserPackage('ws');
21
25
  const { WebSocketServer } = await import(wsPath);
26
+ // `ws` matches its `path` option EXACTLY, which would confine every
27
+ // namespace to the one base path. Namespaces are routed by URL
28
+ // (`/ws/chat` -> '/chat'), so the adapter owns the upgrade step itself
29
+ // and accepts the base path and anything below it. handleUpgrade()
30
+ // still applies verifyClient and maxPayload exactly as server mode did.
31
+ const base = (options.path || '/ws').replace(/\/+$/, '') || '/';
32
+ this.basePath = base.startsWith('/') ? base : `/${base}`;
22
33
  this.wss = new WebSocketServer({
23
- server: httpServer,
24
- path: options.path || '/ws',
34
+ noServer: true,
25
35
  // Matches the ws library's own default (100 MiB) so behavior is
26
36
  // unchanged; apps concerned about per-message buffering can lower it
27
37
  // via maxPayloadLength.
@@ -33,6 +43,26 @@ export class WSAdapter {
33
43
  // Note: ws doesn't have built-in compression like socket.io
34
44
  // but browsers handle compression at the transport level
35
45
  });
46
+ this.httpServer = httpServer;
47
+ this.upgradeHandler = (req, socket, head) => {
48
+ const pathname = String(req.url || '/').split('?')[0] ?? '/';
49
+ const ours = this.basePath === '/' ||
50
+ pathname === this.basePath ||
51
+ pathname.startsWith(`${this.basePath}/`);
52
+ if (!ours) {
53
+ // Not this adapter's path. Another 'upgrade' listener may claim the
54
+ // socket; with none, Node would leave it hanging, so answer and close.
55
+ if (httpServer.listenerCount('upgrade') <= 1) {
56
+ socket.write('HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Length: 0\r\n\r\n');
57
+ socket.destroy();
58
+ }
59
+ return;
60
+ }
61
+ this.wss.handleUpgrade(req, socket, head, (ws) => {
62
+ this.wss.emit('connection', ws, req);
63
+ });
64
+ };
65
+ httpServer.on('upgrade', this.upgradeHandler);
36
66
  // Setup connection handling
37
67
  this.wss.on('connection', (ws, request) => {
38
68
  this.handleConnection(ws, request);
@@ -140,11 +170,20 @@ export class WSAdapter {
140
170
  ws.isAlive = true;
141
171
  });
142
172
  this.connections.set(id, connection);
143
- // Parse namespace from URL path or default to '/'
144
- const url = new URL(request.url || '/', `http://${request.headers.host}`);
145
- const namespacePath = url.pathname === '/ws' ? '/' : url.pathname.replace('/ws', '') || '/';
146
- const namespace = this.namespaces.get(namespacePath);
173
+ // Namespace = the URL path below the base path ('/ws/chat' -> '/chat');
174
+ // the base path itself, and any path without a registered namespace,
175
+ // land on the default namespace (engine-adapter parity).
176
+ const url = new URL(request.url || '/', `http://${request.headers.host || 'localhost'}`);
177
+ let namespacePath = '/';
178
+ if (this.basePath === '/') {
179
+ namespacePath = url.pathname || '/';
180
+ }
181
+ else if (url.pathname.startsWith(`${this.basePath}/`)) {
182
+ namespacePath = url.pathname.slice(this.basePath.length) || '/';
183
+ }
184
+ const namespace = this.namespaces.get(namespacePath) ?? this.namespaces.get('/');
147
185
  if (namespace) {
186
+ connection.raw = namespace.raw;
148
187
  namespace.handleConnection(connection);
149
188
  }
150
189
  // Clean up on disconnect
@@ -152,13 +191,16 @@ export class WSAdapter {
152
191
  this.connections.delete(id);
153
192
  });
154
193
  }
155
- createNamespace(namespace) {
194
+ createNamespace(namespace, options) {
156
195
  if (!this.namespaces.has(namespace)) {
157
196
  const ns = new WSNamespaceWrapper(namespace, this);
158
197
  this.namespaces.set(namespace, ns);
159
198
  }
160
199
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
161
- return this.namespaces.get(namespace);
200
+ const ns = this.namespaces.get(namespace);
201
+ if (options?.raw)
202
+ ns.raw = true;
203
+ return ns;
162
204
  }
163
205
  getDefaultNamespace() {
164
206
  return this.createNamespace('/');
@@ -168,6 +210,10 @@ export class WSAdapter {
168
210
  clearInterval(this.heartbeatTimer);
169
211
  this.heartbeatTimer = undefined;
170
212
  }
213
+ if (this.httpServer && this.upgradeHandler) {
214
+ this.httpServer.off?.('upgrade', this.upgradeHandler);
215
+ this.upgradeHandler = undefined;
216
+ }
171
217
  if (this.wss) {
172
218
  // Terminate live clients first: wss.close() only stops accepting new
173
219
  // connections and does not resolve while sockets remain open, which would
@@ -227,6 +273,8 @@ export class WSAdapter {
227
273
  class WSNamespaceWrapper {
228
274
  namespacePath;
229
275
  adapter;
276
+ /** Raw framing for connections routed here (see WebSocketNamespaceOptions) */
277
+ raw = false;
230
278
  connectionHandlers = [];
231
279
  middlewares = [];
232
280
  connections = new Map();
@@ -298,6 +346,8 @@ class WSConnectionWrapper {
298
346
  ws;
299
347
  request;
300
348
  data = {};
349
+ /** Raw framing (set from the namespace at connection) */
350
+ raw = false;
301
351
  eventHandlers = new Map();
302
352
  anyHandlers = [];
303
353
  rooms = new Set();
@@ -307,12 +357,21 @@ class WSConnectionWrapper {
307
357
  this.ws = ws;
308
358
  this.request = request;
309
359
  // Setup message handling
310
- this.ws.on('message', (data) => {
311
- this.handleMessage(data);
360
+ this.ws.on('message', (data, isBinary) => {
361
+ this.handleMessage(data, isBinary === true);
312
362
  });
313
- this.ws.on('close', () => {
363
+ this.ws.on('close', (code, reason) => {
314
364
  this._connected = false;
315
365
  this.emit('close');
366
+ // The documented `disconnect` hook (app.websocket({ disconnect })) - a
367
+ // client-facing frame makes no sense on a closed socket, so it is
368
+ // dispatched locally with the close code, like the engine adapter.
369
+ const handlers = this.eventHandlers.get('disconnect');
370
+ if (handlers) {
371
+ const detail = { code, reason: reason ? reason.toString() : '' };
372
+ for (let i = 0; i < handlers.length; i++)
373
+ handlers[i]?.(detail);
374
+ }
316
375
  });
317
376
  this.ws.on('error', (error) => {
318
377
  this.emit('error', error);
@@ -408,7 +467,33 @@ class WSConnectionWrapper {
408
467
  }
409
468
  this._connected = false;
410
469
  }
411
- handleMessage(data) {
470
+ send(data, isBinary) {
471
+ if (!this._connected || this.ws.readyState !== 1)
472
+ return;
473
+ this.ws.send(data, { binary: isBinary ?? typeof data !== 'string' });
474
+ }
475
+ handleMessage(data, isBinary = false) {
476
+ if (this.raw) {
477
+ // Raw namespace: no envelope. Text -> 'message' (string), binary ->
478
+ // 'binary' (Buffer; ws may hand over a Buffer[] for fragmented frames).
479
+ const event = isBinary ? 'binary' : 'message';
480
+ const payload = isBinary
481
+ ? Array.isArray(data)
482
+ ? Buffer.concat(data)
483
+ : Buffer.isBuffer(data)
484
+ ? data
485
+ : Buffer.from(data)
486
+ : Array.isArray(data)
487
+ ? Buffer.concat(data).toString('utf8')
488
+ : data.toString();
489
+ for (const any of this.anyHandlers)
490
+ any(event, payload);
491
+ const handlers = this.eventHandlers.get(event);
492
+ if (handlers)
493
+ for (const handler of handlers)
494
+ handler(payload);
495
+ return;
496
+ }
412
497
  try {
413
498
  const text = data.toString();
414
499
  const parsed = JSON.parse(text);
@@ -1 +1 @@
1
- {"version":3,"file":"ws-adapter.js","sourceRoot":"","sources":["../../../../src/core/networking/adapters/ws-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["// Native WebSocket Adapter for Moro Framework\n// Implements the WebSocket adapter interface using the 'ws' library\n\nimport { resolveUserPackage } from '../../utilities/package-utils.js';\nimport {\n WebSocketAdapter,\n WebSocketAdapterOptions,\n WebSocketNamespace,\n WebSocketConnection,\n WebSocketEmitter,\n WebSocketMiddleware,\n} from '../websocket-adapter.js';\nimport { createFrameworkLogger } from '../../logger/index.js';\n\n/**\n * Native WebSocket adapter using the 'ws' library\n * Provides a lightweight, standards-compliant WebSocket implementation\n */\nexport class WSAdapter implements WebSocketAdapter {\n private wss: any; // WebSocket server instance\n private namespaces = new Map<string, WSNamespaceWrapper>();\n private connections = new Map<string, WSConnectionWrapper>();\n private wsLogger = createFrameworkLogger('WEBSOCKET_ADAPTER');\n private customIdGenerator?: () => string;\n private connectionCounter = 0;\n private heartbeatTimer?: ReturnType<typeof setInterval> | undefined;\n\n async initialize(httpServer: any, options: WebSocketAdapterOptions = {}): Promise<void> {\n try {\n // Dynamic import from user's context to find their installed ws library\n const wsPath = resolveUserPackage('ws');\n const { WebSocketServer } = await import(wsPath);\n\n this.wss = new WebSocketServer({\n server: httpServer,\n path: options.path || '/ws',\n // Matches the ws library's own default (100 MiB) so behavior is\n // unchanged; apps concerned about per-message buffering can lower it\n // via maxPayloadLength.\n maxPayload: options.maxPayloadLength || 100 * 1024 * 1024,\n // Origin allowlist + optional custom upgrade-auth hook. Without this a\n // cookie-authenticated app is open to cross-site WebSocket hijacking:\n // the browser sends auth cookies on a ws:// upgrade from any page.\n verifyClient: this.buildVerifyClient(options),\n // Note: ws doesn't have built-in compression like socket.io\n // but browsers handle compression at the transport level\n });\n\n // Setup connection handling\n this.wss.on('connection', (ws: any, request: any) => {\n this.handleConnection(ws, request);\n });\n\n // Protocol-level ping/pong dead-peer detection: terminate half-open\n // sockets that stop answering so they neither leak nor block close().\n const heartbeatMs =\n options.idleTimeout && options.idleTimeout > 0 ? options.idleTimeout : 30000;\n this.heartbeatTimer = setInterval(() => {\n for (const ws of this.wss.clients) {\n if (ws.isAlive === false) {\n ws.terminate();\n continue;\n }\n ws.isAlive = false;\n try {\n ws.ping();\n } catch {\n // socket already going away\n }\n }\n }, heartbeatMs);\n this.heartbeatTimer.unref?.();\n\n // Setup default namespace\n this.createNamespace('/');\n } catch {\n throw new Error(\n 'ws library not found. Install it with: npm install ws @types/ws\\n' +\n 'Or use a different WebSocket adapter.'\n );\n }\n }\n\n /**\n * Build a `ws` verifyClient callback enforcing the configured CORS origin\n * allowlist and any user-supplied upgrade-auth hook (`options.verifyClient`).\n *\n * `cors.origin` accepts:\n * - undefined / true / '*' -> allow any origin (permissive, back-compat)\n * - false -> same-origin only\n * - string -> that exact origin\n * - string[] -> any origin in the list\n * - (requestOrigin) => ... -> dynamic: return true (allow), false (deny),\n * '*' (allow), or the allowed origin string\n * (allowed when it equals the request origin).\n */\n private buildVerifyClient(\n options: WebSocketAdapterOptions\n ): ((info: { origin?: string; req: any; secure: boolean }) => boolean) | undefined {\n const corsOrigin = options.cors?.origin;\n const userVerify =\n typeof (options as any).verifyClient === 'function'\n ? ((options as any).verifyClient as (info: any) => boolean)\n : undefined;\n\n // Allow-all cases need no enforcement at all.\n const allowAll = corsOrigin === undefined || corsOrigin === true || corsOrigin === '*';\n if (allowAll && !userVerify) {\n return undefined;\n }\n\n return (info: { origin?: string; req: any; secure: boolean }): boolean => {\n // allowAll (undefined/true/'*') is handled above; here corsOrigin is a\n // specific rule to enforce.\n if (!allowAll) {\n const origin = info.origin;\n let ok = false;\n if (corsOrigin === false) {\n // Same-origin only: no Origin header (non-browser client) or the\n // Origin host equals the request Host.\n if (!origin) {\n ok = true;\n } else {\n try {\n const host = info.req?.headers?.host;\n ok = !!host && new URL(origin).host === host;\n } catch {\n ok = false;\n }\n }\n } else if (typeof corsOrigin === 'function') {\n // Dynamic: allow based on the function's decision for this origin.\n const decision = (corsOrigin as (o: string | undefined) => boolean | string)(origin);\n ok = decision === true || decision === '*' || (!!origin && decision === origin);\n } else if (corsOrigin instanceof RegExp) {\n ok = !!origin && corsOrigin.test(origin);\n } else if (typeof corsOrigin === 'string') {\n ok = origin === corsOrigin;\n } else if (Array.isArray(corsOrigin)) {\n ok = !!origin && corsOrigin.includes(origin);\n }\n if (!ok) {\n this.wsLogger.warn(\n `Rejected WebSocket upgrade from disallowed origin: ${origin ?? '(none)'}`\n );\n return false;\n }\n }\n return userVerify ? userVerify(info) : true;\n };\n }\n\n private handleConnection(ws: any, request: any): void {\n const id = this.generateId();\n const connection = new WSConnectionWrapper(id, ws, request);\n\n // Liveness tracking for the heartbeat sweep (see initialize()).\n ws.isAlive = true;\n ws.on('pong', () => {\n ws.isAlive = true;\n });\n\n this.connections.set(id, connection);\n\n // Parse namespace from URL path or default to '/'\n const url = new URL(request.url || '/', `http://${request.headers.host}`);\n const namespacePath = url.pathname === '/ws' ? '/' : url.pathname.replace('/ws', '') || '/';\n\n const namespace = this.namespaces.get(namespacePath);\n if (namespace) {\n namespace.handleConnection(connection);\n }\n\n // Clean up on disconnect\n ws.on('close', () => {\n this.connections.delete(id);\n });\n }\n\n createNamespace(namespace: string): WebSocketNamespace {\n if (!this.namespaces.has(namespace)) {\n const ns = new WSNamespaceWrapper(namespace, this);\n this.namespaces.set(namespace, ns);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.namespaces.get(namespace)!;\n }\n\n getDefaultNamespace(): WebSocketNamespace {\n return this.createNamespace('/');\n }\n\n async close(): Promise<void> {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n if (this.wss) {\n // Terminate live clients first: wss.close() only stops accepting new\n // connections and does not resolve while sockets remain open, which would\n // otherwise stall the app's graceful shutdown until its timeout.\n for (const ws of this.wss.clients) {\n try {\n ws.terminate();\n } catch {\n // socket already going away\n }\n }\n return new Promise(resolve => {\n this.wss.close(() => {\n this.connections.clear();\n this.namespaces.clear();\n resolve();\n });\n });\n }\n }\n\n setCompression(enabled: boolean, _options: any = {}): void {\n // ws library handles compression at the browser level\n // This is a no-op but kept for interface compatibility\n if (enabled) {\n this.wsLogger.warn('Compression is handled automatically by the ws library and browsers');\n }\n }\n\n setCustomIdGenerator(generator: () => string): void {\n this.customIdGenerator = generator;\n }\n\n getAdapterName(): string {\n return 'ws';\n }\n\n getConnectionCount(): number {\n return this.connections.size;\n }\n\n generateId(): string {\n if (this.customIdGenerator) {\n return this.customIdGenerator();\n }\n return `ws_${++this.connectionCounter}_${Date.now()}`;\n }\n\n addConnection(id: string, connection: WSConnectionWrapper): void {\n this.connections.set(id, connection);\n }\n\n removeConnection(id: string): void {\n this.connections.delete(id);\n }\n\n getAllConnections(): Map<string, WSConnectionWrapper> {\n return this.connections;\n }\n}\n\n/**\n * WebSocket namespace wrapper\n */\nclass WSNamespaceWrapper implements WebSocketNamespace {\n private connectionHandlers: ((socket: WebSocketConnection) => void)[] = [];\n private middlewares: WebSocketMiddleware[] = [];\n private connections = new Map<string, WSConnectionWrapper>();\n\n constructor(\n private namespacePath: string,\n private adapter: WSAdapter\n ) {}\n\n handleConnection(connection: WSConnectionWrapper): void {\n this.connections.set(connection.id, connection);\n\n // Run middlewares\n this.runMiddlewares(connection, () => {\n // Notify connection handlers - optimized with for loop\n const handlers = this.connectionHandlers;\n const len = handlers.length;\n for (let i = 0; i < len; i++) {\n handlers[i]?.(connection);\n }\n });\n\n // Clean up on disconnect\n connection.on('close', () => {\n this.connections.delete(connection.id);\n });\n }\n\n private runMiddlewares(connection: WSConnectionWrapper, callback: () => void): void {\n let index = 0;\n\n const next = (err?: Error) => {\n if (err || index >= this.middlewares.length) {\n if (!err) callback();\n return;\n }\n\n const middleware = this.middlewares[index++];\n middleware?.(connection, next);\n };\n\n next();\n }\n\n on(event: 'connection', handler: (socket: WebSocketConnection) => void): void {\n this.connectionHandlers.push(handler);\n }\n\n emit(event: string, data: any): void {\n const message = JSON.stringify({ event, data });\n for (const connection of this.connections.values()) {\n if (connection.connected) {\n connection.ws.send(message);\n }\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, room);\n }\n\n except(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, undefined, room);\n }\n\n getSockets(): WebSocketConnection[] {\n return Array.from(this.connections.values());\n }\n\n getConnectionCount(): number {\n return this.connections.size;\n }\n\n use(middleware: WebSocketMiddleware): void {\n this.middlewares.push(middleware);\n }\n}\n\n/**\n * WebSocket connection wrapper\n */\nclass WSConnectionWrapper implements WebSocketConnection {\n public data: Record<string, any> = {};\n private eventHandlers = new Map<string, CallableFunction[]>();\n private anyHandlers: CallableFunction[] = [];\n private rooms = new Set<string>();\n private _connected = true;\n\n constructor(\n public readonly id: string,\n public readonly ws: any,\n private request: any\n ) {\n // Setup message handling\n this.ws.on('message', (data: Buffer) => {\n this.handleMessage(data);\n });\n\n this.ws.on('close', () => {\n this._connected = false;\n this.emit('close');\n });\n\n this.ws.on('error', (error: Error) => {\n this.emit('error', error);\n });\n }\n\n get ip(): string | undefined {\n return (\n this.request.socket?.remoteAddress || this.request.headers['x-forwarded-for']?.split(',')[0]\n );\n }\n\n get headers(): Record<string, string> | undefined {\n return this.request.headers;\n }\n\n get connected(): boolean {\n return this._connected && this.ws.readyState === 1; // WebSocket.OPEN\n }\n\n get broadcast(): WebSocketEmitter {\n // Get all connections except this one\n const allConnections = new Map();\n // This would need access to adapter's connections\n return new WSEmitterWrapper(allConnections, undefined, undefined, this.id);\n }\n\n on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void {\n if (event === 'close' || event === 'error') {\n // Special internal events\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, []);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.eventHandlers.get(event)!.push(handler);\n return;\n }\n\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, []);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.eventHandlers.get(event)!.push(handler);\n }\n\n onAny(handler: (event: string, ...args: any[]) => void): void {\n this.anyHandlers.push(handler);\n }\n\n emit(event: string, data?: any): void {\n if (event === 'close' || event === 'error') {\n // Internal events\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n const len = handlers.length;\n for (let i = 0; i < len; i++) {\n handlers[i]?.(data);\n }\n }\n return;\n }\n\n if (this.connected) {\n const message = JSON.stringify({ event, data });\n this.ws.send(message);\n }\n }\n\n compressedEmit(event: string, data: any): void {\n // ws library handles compression automatically\n this.emit(event, data);\n }\n\n join(room: string | string[]): void {\n if (Array.isArray(room)) {\n const len = room.length;\n for (let i = 0; i < len; i++) {\n this.rooms.add(room[i] as string);\n }\n } else {\n this.rooms.add(room);\n }\n }\n\n leave(room: string | string[]): void {\n if (Array.isArray(room)) {\n const len = room.length;\n for (let i = 0; i < len; i++) {\n this.rooms.delete(room[i] as string);\n }\n } else {\n this.rooms.delete(room);\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n const connections = new Map([[this.id, this]]);\n return new WSEmitterWrapper(connections, room);\n }\n\n getRooms(): Set<string> {\n return new Set(this.rooms);\n }\n\n disconnect(close?: boolean): void {\n if (close !== false && this.ws.readyState === 1) {\n this.ws.close();\n }\n this._connected = false;\n }\n\n private handleMessage(data: Buffer): void {\n try {\n const text = data.toString();\n const parsed = JSON.parse(text);\n const { event, data: messageData, callback: callbackId } = parsed;\n\n // Create callback function if callback ID is provided\n const callback = callbackId\n ? (response: any) => {\n this.emit('callback', { id: callbackId, data: response });\n }\n : undefined;\n\n // Call any handlers - optimized with for loop\n const anyHandlers = this.anyHandlers;\n const anyLen = anyHandlers.length;\n for (let i = 0; i < anyLen; i++) {\n anyHandlers[i]?.(event, messageData);\n }\n\n // Call specific event handlers - optimized with for loop\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n const len = handlers.length;\n for (let i = 0; i < len; i++) {\n handlers[i]?.(messageData, callback);\n }\n }\n } catch {\n // Invalid message format - ignore\n }\n }\n}\n\n/**\n * WebSocket emitter wrapper\n */\nclass WSEmitterWrapper implements WebSocketEmitter {\n constructor(\n private connections: Map<string, WSConnectionWrapper>,\n private targetRooms?: string | string[],\n private excludeRooms?: string | string[],\n private excludeId?: string\n ) {}\n\n emit(event: string, data: any): void {\n const message = JSON.stringify({ event, data });\n\n for (const connection of this.connections.values()) {\n if (this.excludeId && connection.id === this.excludeId) {\n continue;\n }\n\n if (this.shouldIncludeConnection(connection) && connection.connected) {\n connection.ws.send(message);\n }\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, room, this.excludeRooms, this.excludeId);\n }\n\n except(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, this.targetRooms, room, this.excludeId);\n }\n\n compress(_compress: boolean): WebSocketEmitter {\n // ws library handles compression automatically\n return this;\n }\n\n private shouldIncludeConnection(connection: WSConnectionWrapper): boolean {\n const rooms = connection.getRooms();\n\n // Check target rooms - avoid array wrapping and use efficient iteration\n if (this.targetRooms) {\n if (Array.isArray(this.targetRooms)) {\n let hasTargetRoom = false;\n const len = this.targetRooms.length;\n for (let i = 0; i < len; i++) {\n if (rooms.has(this.targetRooms[i] as string)) {\n hasTargetRoom = true;\n break;\n }\n }\n if (!hasTargetRoom) return false;\n } else {\n if (!rooms.has(this.targetRooms)) return false;\n }\n }\n\n // Check exclude rooms - avoid array wrapping and use efficient iteration\n if (this.excludeRooms) {\n if (Array.isArray(this.excludeRooms)) {\n const len = this.excludeRooms.length;\n for (let i = 0; i < len; i++) {\n if (rooms.has(this.excludeRooms[i] as string)) return false;\n }\n } else {\n if (rooms.has(this.excludeRooms)) return false;\n }\n }\n\n return true;\n }\n}\n"]}
1
+ {"version":3,"file":"ws-adapter.js","sourceRoot":"","sources":["../../../../src/core/networking/adapters/ws-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["// Native WebSocket Adapter for Moro Framework\n// Implements the WebSocket adapter interface using the 'ws' library\n\nimport { resolveUserPackage } from '../../utilities/package-utils.js';\nimport {\n WebSocketAdapter,\n WebSocketAdapterOptions,\n WebSocketNamespace,\n WebSocketNamespaceOptions,\n WebSocketConnection,\n WebSocketEmitter,\n WebSocketMiddleware,\n} from '../websocket-adapter.js';\nimport { createFrameworkLogger } from '../../logger/index.js';\n\n/**\n * Native WebSocket adapter using the 'ws' library\n * Provides a lightweight, standards-compliant WebSocket implementation\n */\nexport class WSAdapter implements WebSocketAdapter {\n private wss: any; // WebSocket server instance\n private namespaces = new Map<string, WSNamespaceWrapper>();\n private connections = new Map<string, WSConnectionWrapper>();\n private wsLogger = createFrameworkLogger('WEBSOCKET_ADAPTER');\n private customIdGenerator?: () => string;\n private connectionCounter = 0;\n private heartbeatTimer?: ReturnType<typeof setInterval> | undefined;\n /** Upgrade path prefix (options.path, default '/ws'): namespaces live below it */\n private basePath = '/ws';\n private httpServer: any;\n private upgradeHandler: ((req: any, socket: any, head: Buffer) => void) | undefined;\n\n async initialize(httpServer: any, options: WebSocketAdapterOptions = {}): Promise<void> {\n try {\n // Dynamic import from user's context to find their installed ws library\n const wsPath = resolveUserPackage('ws');\n const { WebSocketServer } = await import(wsPath);\n\n // `ws` matches its `path` option EXACTLY, which would confine every\n // namespace to the one base path. Namespaces are routed by URL\n // (`/ws/chat` -> '/chat'), so the adapter owns the upgrade step itself\n // and accepts the base path and anything below it. handleUpgrade()\n // still applies verifyClient and maxPayload exactly as server mode did.\n const base = (options.path || '/ws').replace(/\\/+$/, '') || '/';\n this.basePath = base.startsWith('/') ? base : `/${base}`;\n this.wss = new WebSocketServer({\n noServer: true,\n // Matches the ws library's own default (100 MiB) so behavior is\n // unchanged; apps concerned about per-message buffering can lower it\n // via maxPayloadLength.\n maxPayload: options.maxPayloadLength || 100 * 1024 * 1024,\n // Origin allowlist + optional custom upgrade-auth hook. Without this a\n // cookie-authenticated app is open to cross-site WebSocket hijacking:\n // the browser sends auth cookies on a ws:// upgrade from any page.\n verifyClient: this.buildVerifyClient(options),\n // Note: ws doesn't have built-in compression like socket.io\n // but browsers handle compression at the transport level\n });\n\n this.httpServer = httpServer;\n this.upgradeHandler = (req: any, socket: any, head: Buffer) => {\n const pathname = String(req.url || '/').split('?')[0] ?? '/';\n const ours =\n this.basePath === '/' ||\n pathname === this.basePath ||\n pathname.startsWith(`${this.basePath}/`);\n if (!ours) {\n // Not this adapter's path. Another 'upgrade' listener may claim the\n // socket; with none, Node would leave it hanging, so answer and close.\n if (httpServer.listenerCount('upgrade') <= 1) {\n socket.write(\n 'HTTP/1.1 404 Not Found\\r\\nConnection: close\\r\\nContent-Length: 0\\r\\n\\r\\n'\n );\n socket.destroy();\n }\n return;\n }\n this.wss.handleUpgrade(req, socket, head, (ws: any) => {\n this.wss.emit('connection', ws, req);\n });\n };\n httpServer.on('upgrade', this.upgradeHandler);\n\n // Setup connection handling\n this.wss.on('connection', (ws: any, request: any) => {\n this.handleConnection(ws, request);\n });\n\n // Protocol-level ping/pong dead-peer detection: terminate half-open\n // sockets that stop answering so they neither leak nor block close().\n const heartbeatMs =\n options.idleTimeout && options.idleTimeout > 0 ? options.idleTimeout : 30000;\n this.heartbeatTimer = setInterval(() => {\n for (const ws of this.wss.clients) {\n if (ws.isAlive === false) {\n ws.terminate();\n continue;\n }\n ws.isAlive = false;\n try {\n ws.ping();\n } catch {\n // socket already going away\n }\n }\n }, heartbeatMs);\n this.heartbeatTimer.unref?.();\n\n // Setup default namespace\n this.createNamespace('/');\n } catch {\n throw new Error(\n 'ws library not found. Install it with: npm install ws @types/ws\\n' +\n 'Or use a different WebSocket adapter.'\n );\n }\n }\n\n /**\n * Build a `ws` verifyClient callback enforcing the configured CORS origin\n * allowlist and any user-supplied upgrade-auth hook (`options.verifyClient`).\n *\n * `cors.origin` accepts:\n * - undefined / true / '*' -> allow any origin (permissive, back-compat)\n * - false -> same-origin only\n * - string -> that exact origin\n * - string[] -> any origin in the list\n * - (requestOrigin) => ... -> dynamic: return true (allow), false (deny),\n * '*' (allow), or the allowed origin string\n * (allowed when it equals the request origin).\n */\n private buildVerifyClient(\n options: WebSocketAdapterOptions\n ): ((info: { origin?: string; req: any; secure: boolean }) => boolean) | undefined {\n const corsOrigin = options.cors?.origin;\n const userVerify =\n typeof (options as any).verifyClient === 'function'\n ? ((options as any).verifyClient as (info: any) => boolean)\n : undefined;\n\n // Allow-all cases need no enforcement at all.\n const allowAll = corsOrigin === undefined || corsOrigin === true || corsOrigin === '*';\n if (allowAll && !userVerify) {\n return undefined;\n }\n\n return (info: { origin?: string; req: any; secure: boolean }): boolean => {\n // allowAll (undefined/true/'*') is handled above; here corsOrigin is a\n // specific rule to enforce.\n if (!allowAll) {\n const origin = info.origin;\n let ok = false;\n if (corsOrigin === false) {\n // Same-origin only: no Origin header (non-browser client) or the\n // Origin host equals the request Host.\n if (!origin) {\n ok = true;\n } else {\n try {\n const host = info.req?.headers?.host;\n ok = !!host && new URL(origin).host === host;\n } catch {\n ok = false;\n }\n }\n } else if (typeof corsOrigin === 'function') {\n // Dynamic: allow based on the function's decision for this origin.\n const decision = (corsOrigin as (o: string | undefined) => boolean | string)(origin);\n ok = decision === true || decision === '*' || (!!origin && decision === origin);\n } else if (corsOrigin instanceof RegExp) {\n ok = !!origin && corsOrigin.test(origin);\n } else if (typeof corsOrigin === 'string') {\n ok = origin === corsOrigin;\n } else if (Array.isArray(corsOrigin)) {\n ok = !!origin && corsOrigin.includes(origin);\n }\n if (!ok) {\n this.wsLogger.warn(\n `Rejected WebSocket upgrade from disallowed origin: ${origin ?? '(none)'}`\n );\n return false;\n }\n }\n return userVerify ? userVerify(info) : true;\n };\n }\n\n private handleConnection(ws: any, request: any): void {\n const id = this.generateId();\n const connection = new WSConnectionWrapper(id, ws, request);\n\n // Liveness tracking for the heartbeat sweep (see initialize()).\n ws.isAlive = true;\n ws.on('pong', () => {\n ws.isAlive = true;\n });\n\n this.connections.set(id, connection);\n\n // Namespace = the URL path below the base path ('/ws/chat' -> '/chat');\n // the base path itself, and any path without a registered namespace,\n // land on the default namespace (engine-adapter parity).\n const url = new URL(request.url || '/', `http://${request.headers.host || 'localhost'}`);\n let namespacePath = '/';\n if (this.basePath === '/') {\n namespacePath = url.pathname || '/';\n } else if (url.pathname.startsWith(`${this.basePath}/`)) {\n namespacePath = url.pathname.slice(this.basePath.length) || '/';\n }\n\n const namespace = this.namespaces.get(namespacePath) ?? this.namespaces.get('/');\n if (namespace) {\n connection.raw = namespace.raw;\n namespace.handleConnection(connection);\n }\n\n // Clean up on disconnect\n ws.on('close', () => {\n this.connections.delete(id);\n });\n }\n\n createNamespace(namespace: string, options?: WebSocketNamespaceOptions): WebSocketNamespace {\n if (!this.namespaces.has(namespace)) {\n const ns = new WSNamespaceWrapper(namespace, this);\n this.namespaces.set(namespace, ns);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const ns = this.namespaces.get(namespace)!;\n if (options?.raw) ns.raw = true;\n return ns;\n }\n\n getDefaultNamespace(): WebSocketNamespace {\n return this.createNamespace('/');\n }\n\n async close(): Promise<void> {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n if (this.httpServer && this.upgradeHandler) {\n this.httpServer.off?.('upgrade', this.upgradeHandler);\n this.upgradeHandler = undefined;\n }\n if (this.wss) {\n // Terminate live clients first: wss.close() only stops accepting new\n // connections and does not resolve while sockets remain open, which would\n // otherwise stall the app's graceful shutdown until its timeout.\n for (const ws of this.wss.clients) {\n try {\n ws.terminate();\n } catch {\n // socket already going away\n }\n }\n return new Promise(resolve => {\n this.wss.close(() => {\n this.connections.clear();\n this.namespaces.clear();\n resolve();\n });\n });\n }\n }\n\n setCompression(enabled: boolean, _options: any = {}): void {\n // ws library handles compression at the browser level\n // This is a no-op but kept for interface compatibility\n if (enabled) {\n this.wsLogger.warn('Compression is handled automatically by the ws library and browsers');\n }\n }\n\n setCustomIdGenerator(generator: () => string): void {\n this.customIdGenerator = generator;\n }\n\n getAdapterName(): string {\n return 'ws';\n }\n\n getConnectionCount(): number {\n return this.connections.size;\n }\n\n generateId(): string {\n if (this.customIdGenerator) {\n return this.customIdGenerator();\n }\n return `ws_${++this.connectionCounter}_${Date.now()}`;\n }\n\n addConnection(id: string, connection: WSConnectionWrapper): void {\n this.connections.set(id, connection);\n }\n\n removeConnection(id: string): void {\n this.connections.delete(id);\n }\n\n getAllConnections(): Map<string, WSConnectionWrapper> {\n return this.connections;\n }\n}\n\n/**\n * WebSocket namespace wrapper\n */\nclass WSNamespaceWrapper implements WebSocketNamespace {\n /** Raw framing for connections routed here (see WebSocketNamespaceOptions) */\n raw = false;\n private connectionHandlers: ((socket: WebSocketConnection) => void)[] = [];\n private middlewares: WebSocketMiddleware[] = [];\n private connections = new Map<string, WSConnectionWrapper>();\n\n constructor(\n private namespacePath: string,\n private adapter: WSAdapter\n ) {}\n\n handleConnection(connection: WSConnectionWrapper): void {\n this.connections.set(connection.id, connection);\n\n // Run middlewares\n this.runMiddlewares(connection, () => {\n // Notify connection handlers - optimized with for loop\n const handlers = this.connectionHandlers;\n const len = handlers.length;\n for (let i = 0; i < len; i++) {\n handlers[i]?.(connection);\n }\n });\n\n // Clean up on disconnect\n connection.on('close', () => {\n this.connections.delete(connection.id);\n });\n }\n\n private runMiddlewares(connection: WSConnectionWrapper, callback: () => void): void {\n let index = 0;\n\n const next = (err?: Error) => {\n if (err || index >= this.middlewares.length) {\n if (!err) callback();\n return;\n }\n\n const middleware = this.middlewares[index++];\n middleware?.(connection, next);\n };\n\n next();\n }\n\n on(event: 'connection', handler: (socket: WebSocketConnection) => void): void {\n this.connectionHandlers.push(handler);\n }\n\n emit(event: string, data: any): void {\n const message = JSON.stringify({ event, data });\n for (const connection of this.connections.values()) {\n if (connection.connected) {\n connection.ws.send(message);\n }\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, room);\n }\n\n except(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, undefined, room);\n }\n\n getSockets(): WebSocketConnection[] {\n return Array.from(this.connections.values());\n }\n\n getConnectionCount(): number {\n return this.connections.size;\n }\n\n use(middleware: WebSocketMiddleware): void {\n this.middlewares.push(middleware);\n }\n}\n\n/**\n * WebSocket connection wrapper\n */\nclass WSConnectionWrapper implements WebSocketConnection {\n public data: Record<string, any> = {};\n /** Raw framing (set from the namespace at connection) */\n public raw = false;\n private eventHandlers = new Map<string, CallableFunction[]>();\n private anyHandlers: CallableFunction[] = [];\n private rooms = new Set<string>();\n private _connected = true;\n\n constructor(\n public readonly id: string,\n public readonly ws: any,\n private request: any\n ) {\n // Setup message handling\n this.ws.on('message', (data: Buffer, isBinary?: boolean) => {\n this.handleMessage(data, isBinary === true);\n });\n\n this.ws.on('close', (code?: number, reason?: Buffer) => {\n this._connected = false;\n this.emit('close');\n // The documented `disconnect` hook (app.websocket({ disconnect })) - a\n // client-facing frame makes no sense on a closed socket, so it is\n // dispatched locally with the close code, like the engine adapter.\n const handlers = this.eventHandlers.get('disconnect');\n if (handlers) {\n const detail = { code, reason: reason ? reason.toString() : '' };\n for (let i = 0; i < handlers.length; i++) handlers[i]?.(detail);\n }\n });\n\n this.ws.on('error', (error: Error) => {\n this.emit('error', error);\n });\n }\n\n get ip(): string | undefined {\n return (\n this.request.socket?.remoteAddress || this.request.headers['x-forwarded-for']?.split(',')[0]\n );\n }\n\n get headers(): Record<string, string> | undefined {\n return this.request.headers;\n }\n\n get connected(): boolean {\n return this._connected && this.ws.readyState === 1; // WebSocket.OPEN\n }\n\n get broadcast(): WebSocketEmitter {\n // Get all connections except this one\n const allConnections = new Map();\n // This would need access to adapter's connections\n return new WSEmitterWrapper(allConnections, undefined, undefined, this.id);\n }\n\n on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void {\n if (event === 'close' || event === 'error') {\n // Special internal events\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, []);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.eventHandlers.get(event)!.push(handler);\n return;\n }\n\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, []);\n }\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n this.eventHandlers.get(event)!.push(handler);\n }\n\n onAny(handler: (event: string, ...args: any[]) => void): void {\n this.anyHandlers.push(handler);\n }\n\n emit(event: string, data?: any): void {\n if (event === 'close' || event === 'error') {\n // Internal events\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n const len = handlers.length;\n for (let i = 0; i < len; i++) {\n handlers[i]?.(data);\n }\n }\n return;\n }\n\n if (this.connected) {\n const message = JSON.stringify({ event, data });\n this.ws.send(message);\n }\n }\n\n compressedEmit(event: string, data: any): void {\n // ws library handles compression automatically\n this.emit(event, data);\n }\n\n join(room: string | string[]): void {\n if (Array.isArray(room)) {\n const len = room.length;\n for (let i = 0; i < len; i++) {\n this.rooms.add(room[i] as string);\n }\n } else {\n this.rooms.add(room);\n }\n }\n\n leave(room: string | string[]): void {\n if (Array.isArray(room)) {\n const len = room.length;\n for (let i = 0; i < len; i++) {\n this.rooms.delete(room[i] as string);\n }\n } else {\n this.rooms.delete(room);\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n const connections = new Map([[this.id, this]]);\n return new WSEmitterWrapper(connections, room);\n }\n\n getRooms(): Set<string> {\n return new Set(this.rooms);\n }\n\n disconnect(close?: boolean): void {\n if (close !== false && this.ws.readyState === 1) {\n this.ws.close();\n }\n this._connected = false;\n }\n\n send(data: string | Buffer | ArrayBuffer | Uint8Array, isBinary?: boolean): void {\n if (!this._connected || this.ws.readyState !== 1) return;\n this.ws.send(data, { binary: isBinary ?? typeof data !== 'string' });\n }\n\n private handleMessage(data: Buffer, isBinary = false): void {\n if (this.raw) {\n // Raw namespace: no envelope. Text -> 'message' (string), binary ->\n // 'binary' (Buffer; ws may hand over a Buffer[] for fragmented frames).\n const event = isBinary ? 'binary' : 'message';\n const payload = isBinary\n ? Array.isArray(data)\n ? Buffer.concat(data)\n : Buffer.isBuffer(data)\n ? data\n : Buffer.from(data as any)\n : Array.isArray(data)\n ? Buffer.concat(data).toString('utf8')\n : data.toString();\n for (const any of this.anyHandlers) any(event, payload);\n const handlers = this.eventHandlers.get(event);\n if (handlers) for (const handler of handlers) handler(payload);\n return;\n }\n try {\n const text = data.toString();\n const parsed = JSON.parse(text);\n const { event, data: messageData, callback: callbackId } = parsed;\n\n // Create callback function if callback ID is provided\n const callback = callbackId\n ? (response: any) => {\n this.emit('callback', { id: callbackId, data: response });\n }\n : undefined;\n\n // Call any handlers - optimized with for loop\n const anyHandlers = this.anyHandlers;\n const anyLen = anyHandlers.length;\n for (let i = 0; i < anyLen; i++) {\n anyHandlers[i]?.(event, messageData);\n }\n\n // Call specific event handlers - optimized with for loop\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n const len = handlers.length;\n for (let i = 0; i < len; i++) {\n handlers[i]?.(messageData, callback);\n }\n }\n } catch {\n // Invalid message format - ignore\n }\n }\n}\n\n/**\n * WebSocket emitter wrapper\n */\nclass WSEmitterWrapper implements WebSocketEmitter {\n constructor(\n private connections: Map<string, WSConnectionWrapper>,\n private targetRooms?: string | string[],\n private excludeRooms?: string | string[],\n private excludeId?: string\n ) {}\n\n emit(event: string, data: any): void {\n const message = JSON.stringify({ event, data });\n\n for (const connection of this.connections.values()) {\n if (this.excludeId && connection.id === this.excludeId) {\n continue;\n }\n\n if (this.shouldIncludeConnection(connection) && connection.connected) {\n connection.ws.send(message);\n }\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, room, this.excludeRooms, this.excludeId);\n }\n\n except(room: string | string[]): WebSocketEmitter {\n return new WSEmitterWrapper(this.connections, this.targetRooms, room, this.excludeId);\n }\n\n compress(_compress: boolean): WebSocketEmitter {\n // ws library handles compression automatically\n return this;\n }\n\n private shouldIncludeConnection(connection: WSConnectionWrapper): boolean {\n const rooms = connection.getRooms();\n\n // Check target rooms - avoid array wrapping and use efficient iteration\n if (this.targetRooms) {\n if (Array.isArray(this.targetRooms)) {\n let hasTargetRoom = false;\n const len = this.targetRooms.length;\n for (let i = 0; i < len; i++) {\n if (rooms.has(this.targetRooms[i] as string)) {\n hasTargetRoom = true;\n break;\n }\n }\n if (!hasTargetRoom) return false;\n } else {\n if (!rooms.has(this.targetRooms)) return false;\n }\n }\n\n // Check exclude rooms - avoid array wrapping and use efficient iteration\n if (this.excludeRooms) {\n if (Array.isArray(this.excludeRooms)) {\n const len = this.excludeRooms.length;\n for (let i = 0; i < len; i++) {\n if (rooms.has(this.excludeRooms[i] as string)) return false;\n }\n } else {\n if (rooms.has(this.excludeRooms)) return false;\n }\n }\n\n return true;\n }\n}\n"]}
@@ -29,6 +29,17 @@ export interface WebSocketAdapterOptions {
29
29
  }) => boolean;
30
30
  [key: string]: any;
31
31
  }
32
+ /** Per-namespace options for createNamespace() / app.websocket(). */
33
+ export interface WebSocketNamespaceOptions {
34
+ /**
35
+ * Raw framing: frames on this namespace are NOT `{ event, data }` JSON
36
+ * envelopes. Every text frame reaches the `message` handler as a string and
37
+ * every binary frame reaches `binary` as a Buffer; replies go out through
38
+ * `socket.send()`. Supported by the engine, uWS and ws adapters (Socket.IO
39
+ * speaks its own protocol and ignores it).
40
+ */
41
+ raw?: boolean;
42
+ }
32
43
  /**
33
44
  * Abstract WebSocket adapter interface
34
45
  * Allows the framework to work with different WebSocket implementations
@@ -41,7 +52,7 @@ export interface WebSocketAdapter {
41
52
  /**
42
53
  * Create a namespace for organizing WebSocket connections
43
54
  */
44
- createNamespace(namespace: string): WebSocketNamespace;
55
+ createNamespace(namespace: string, options?: WebSocketNamespaceOptions): WebSocketNamespace;
45
56
  /**
46
57
  * Get the default namespace (usually '/')
47
58
  */
@@ -130,6 +141,13 @@ export interface WebSocketConnection {
130
141
  * Emit with compression
131
142
  */
132
143
  compressedEmit?(event: string, data: any): void;
144
+ /**
145
+ * Send one frame as-is, with no `{ event, data }` envelope: a string goes
146
+ * out as a text frame, a Buffer/ArrayBuffer/Uint8Array as a binary frame
147
+ * (`isBinary` overrides the guess). The reply side of a raw namespace; every
148
+ * built-in adapter implements it.
149
+ */
150
+ send?(data: string | Buffer | ArrayBuffer | Uint8Array, isBinary?: boolean): void;
133
151
  /**
134
152
  * Join a room
135
153
  */
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-adapter.js","sourceRoot":"","sources":["../../../src/core/networking/websocket-adapter.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,sEAAsE;AAgPtE;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAQ,EAAE,IAAS;IACtD,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;IACpB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;IAC9B,OAAO;QACL,GAAG,CAAC;QACJ,GAAG,CAAC;QACJ,OAAO,EAAE;YACP,GAAG,KAAK;YACR,GAAG,KAAK;YACR,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;SACvD;KACF,CAAC;AACJ,CAAC","sourcesContent":["// WebSocket Adapter Interface for Moro Framework\n// Provides a common interface for different WebSocket implementations\n\nexport interface WebSocketAdapterOptions {\n compression?: boolean;\n cors?: {\n /**\n * Allowed origin(s) for cross-origin WebSocket upgrades.\n * - `undefined` / `true` / `'*'` — allow any origin\n * - `false` — same-origin only\n * - `string` / `string[]` — exact origin(s)\n * - `RegExp` — matched origin (Socket.IO)\n * - function — dynamic: the `ws` adapter calls it `(requestOrigin) => boolean | string`\n * (return `true`/`'*'` to allow, `false` to deny, or the allowed origin string);\n * the Socket.IO adapter passes it through to Socket.IO (express-cors `(origin, callback)`).\n */\n origin?:\n | string\n | string[]\n | boolean\n | RegExp\n | ((\n requestOrigin: string | undefined,\n callback?: (err: Error | null, allow?: boolean) => void\n ) => boolean | string | void);\n methods?: string[];\n credentials?: boolean;\n };\n path?: string;\n maxPayloadLength?: number;\n idleTimeout?: number;\n /**\n * Optional upgrade-time authentication hook (ws adapter). Return false to\n * reject the handshake. Runs after the CORS origin check passes.\n */\n verifyClient?: (info: { origin?: string; req: any; secure: boolean }) => boolean;\n [key: string]: any; // Allow adapter-specific options\n}\n\n/**\n * Abstract WebSocket adapter interface\n * Allows the framework to work with different WebSocket implementations\n */\nexport interface WebSocketAdapter {\n /**\n * Initialize the WebSocket server with the given HTTP server\n */\n initialize(httpServer: any, options?: WebSocketAdapterOptions): Promise<void>;\n\n /**\n * Create a namespace for organizing WebSocket connections\n */\n createNamespace(namespace: string): WebSocketNamespace;\n\n /**\n * Get the default namespace (usually '/')\n */\n getDefaultNamespace(): WebSocketNamespace;\n\n /**\n * Close the WebSocket server and all connections\n */\n close(): Promise<void>;\n\n /**\n * Set compression configuration\n */\n setCompression(enabled: boolean, options?: any): void;\n\n /**\n * Set custom ID generator for connections\n */\n setCustomIdGenerator(generator: () => string): void;\n\n /**\n * Get adapter name/type\n */\n getAdapterName(): string;\n\n /**\n * Get connection count across all namespaces\n */\n getConnectionCount(): number;\n}\n\n/**\n * WebSocket namespace interface\n * Represents a logical grouping of WebSocket connections\n */\nexport interface WebSocketNamespace {\n /**\n * Listen for connection events\n */\n on(event: 'connection', handler: (socket: WebSocketConnection) => void): void;\n\n /**\n * Emit event to all connected sockets in this namespace\n */\n emit(event: string, data: any): void;\n\n /**\n * Emit to specific room(s)\n */\n to(room: string | string[]): WebSocketEmitter;\n\n /**\n * Emit to sockets except those in specified room(s)\n */\n except(room: string | string[]): WebSocketEmitter;\n\n /**\n * Get all connected sockets\n */\n getSockets(): WebSocketConnection[];\n\n /**\n * Get connection count for this namespace\n */\n getConnectionCount(): number;\n\n /**\n * Use middleware for this namespace\n */\n use(middleware: (socket: WebSocketConnection, next: (err?: Error) => void) => void): void;\n}\n\n/**\n * WebSocket connection interface\n * Represents an individual client connection\n */\nexport interface WebSocketConnection {\n /** Unique connection ID */\n id: string;\n\n /** Client IP address */\n ip?: string | undefined;\n\n /** Connection headers */\n headers?: Record<string, string> | undefined;\n\n /** Custom data storage */\n data: Record<string, any>;\n\n /**\n * Listen for events from this socket\n */\n on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void;\n\n /**\n * Listen for any event from this socket\n */\n onAny(handler: (event: string, ...args: any[]) => void): void;\n\n /**\n * Emit event to this socket\n */\n emit(event: string, data: any): void;\n\n /**\n * Emit with compression\n */\n compressedEmit?(event: string, data: any): void;\n\n /**\n * Join a room\n */\n join(room: string | string[]): void;\n\n /**\n * Leave a room\n */\n leave(room: string | string[]): void;\n\n /**\n * Emit to specific room(s)\n */\n to(room: string | string[]): WebSocketEmitter;\n\n /**\n * Emit to all sockets except this one\n */\n broadcast: WebSocketEmitter;\n\n /**\n * Get rooms this socket has joined\n */\n getRooms(): Set<string>;\n\n /**\n * Disconnect this socket\n */\n disconnect(close?: boolean): void;\n\n /**\n * Check if socket is connected\n */\n connected: boolean;\n}\n\n/**\n * WebSocket emitter interface for chaining operations\n */\nexport interface WebSocketEmitter {\n /**\n * Emit to target sockets\n */\n emit(event: string, data: any): void;\n\n /**\n * Target specific room(s)\n */\n to(room: string | string[]): WebSocketEmitter;\n\n /**\n * Exclude specific room(s)\n */\n except(room: string | string[]): WebSocketEmitter;\n\n /**\n * Use compression for this emit\n */\n compress(compress: boolean): WebSocketEmitter;\n}\n\n/**\n * WebSocket middleware function type\n */\nexport type WebSocketMiddleware = (\n socket: WebSocketConnection,\n next: (err?: Error) => void\n) => void;\n\n/**\n * WebSocket event handler type\n */\nexport type WebSocketEventHandler = (\n socket: WebSocketConnection,\n data: any,\n callback?: (response?: any) => void\n) => void | Promise<void>;\n\n/**\n * Merge WebSocket config from moro.config.ts with per-call createApp() options.\n * createApp() options take precedence over config for top-level and nested keys,\n * so `options.path` overrides `config.options.path` and same for cors fields.\n * @internal\n */\nexport function mergeWebSocketConfig(cfg: any, opts: any): any {\n const c = cfg || {};\n const o = opts || {};\n const cOpts = c.options || {};\n const oOpts = o.options || {};\n return {\n ...c,\n ...o,\n options: {\n ...cOpts,\n ...oOpts,\n cors: { ...(cOpts.cors || {}), ...(oOpts.cors || {}) },\n },\n };\n}\n"]}
1
+ {"version":3,"file":"websocket-adapter.js","sourceRoot":"","sources":["../../../src/core/networking/websocket-adapter.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,sEAAsE;AAoQtE;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAQ,EAAE,IAAS;IACtD,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;IACpB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;IAC9B,OAAO;QACL,GAAG,CAAC;QACJ,GAAG,CAAC;QACJ,OAAO,EAAE;YACP,GAAG,KAAK;YACR,GAAG,KAAK;YACR,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;SACvD;KACF,CAAC;AACJ,CAAC","sourcesContent":["// WebSocket Adapter Interface for Moro Framework\n// Provides a common interface for different WebSocket implementations\n\nexport interface WebSocketAdapterOptions {\n compression?: boolean;\n cors?: {\n /**\n * Allowed origin(s) for cross-origin WebSocket upgrades.\n * - `undefined` / `true` / `'*'` — allow any origin\n * - `false` — same-origin only\n * - `string` / `string[]` — exact origin(s)\n * - `RegExp` — matched origin (Socket.IO)\n * - function — dynamic: the `ws` adapter calls it `(requestOrigin) => boolean | string`\n * (return `true`/`'*'` to allow, `false` to deny, or the allowed origin string);\n * the Socket.IO adapter passes it through to Socket.IO (express-cors `(origin, callback)`).\n */\n origin?:\n | string\n | string[]\n | boolean\n | RegExp\n | ((\n requestOrigin: string | undefined,\n callback?: (err: Error | null, allow?: boolean) => void\n ) => boolean | string | void);\n methods?: string[];\n credentials?: boolean;\n };\n path?: string;\n maxPayloadLength?: number;\n idleTimeout?: number;\n /**\n * Optional upgrade-time authentication hook (ws adapter). Return false to\n * reject the handshake. Runs after the CORS origin check passes.\n */\n verifyClient?: (info: { origin?: string; req: any; secure: boolean }) => boolean;\n [key: string]: any; // Allow adapter-specific options\n}\n\n/** Per-namespace options for createNamespace() / app.websocket(). */\nexport interface WebSocketNamespaceOptions {\n /**\n * Raw framing: frames on this namespace are NOT `{ event, data }` JSON\n * envelopes. Every text frame reaches the `message` handler as a string and\n * every binary frame reaches `binary` as a Buffer; replies go out through\n * `socket.send()`. Supported by the engine, uWS and ws adapters (Socket.IO\n * speaks its own protocol and ignores it).\n */\n raw?: boolean;\n}\n\n/**\n * Abstract WebSocket adapter interface\n * Allows the framework to work with different WebSocket implementations\n */\nexport interface WebSocketAdapter {\n /**\n * Initialize the WebSocket server with the given HTTP server\n */\n initialize(httpServer: any, options?: WebSocketAdapterOptions): Promise<void>;\n\n /**\n * Create a namespace for organizing WebSocket connections\n */\n createNamespace(namespace: string, options?: WebSocketNamespaceOptions): WebSocketNamespace;\n\n /**\n * Get the default namespace (usually '/')\n */\n getDefaultNamespace(): WebSocketNamespace;\n\n /**\n * Close the WebSocket server and all connections\n */\n close(): Promise<void>;\n\n /**\n * Set compression configuration\n */\n setCompression(enabled: boolean, options?: any): void;\n\n /**\n * Set custom ID generator for connections\n */\n setCustomIdGenerator(generator: () => string): void;\n\n /**\n * Get adapter name/type\n */\n getAdapterName(): string;\n\n /**\n * Get connection count across all namespaces\n */\n getConnectionCount(): number;\n}\n\n/**\n * WebSocket namespace interface\n * Represents a logical grouping of WebSocket connections\n */\nexport interface WebSocketNamespace {\n /**\n * Listen for connection events\n */\n on(event: 'connection', handler: (socket: WebSocketConnection) => void): void;\n\n /**\n * Emit event to all connected sockets in this namespace\n */\n emit(event: string, data: any): void;\n\n /**\n * Emit to specific room(s)\n */\n to(room: string | string[]): WebSocketEmitter;\n\n /**\n * Emit to sockets except those in specified room(s)\n */\n except(room: string | string[]): WebSocketEmitter;\n\n /**\n * Get all connected sockets\n */\n getSockets(): WebSocketConnection[];\n\n /**\n * Get connection count for this namespace\n */\n getConnectionCount(): number;\n\n /**\n * Use middleware for this namespace\n */\n use(middleware: (socket: WebSocketConnection, next: (err?: Error) => void) => void): void;\n}\n\n/**\n * WebSocket connection interface\n * Represents an individual client connection\n */\nexport interface WebSocketConnection {\n /** Unique connection ID */\n id: string;\n\n /** Client IP address */\n ip?: string | undefined;\n\n /** Connection headers */\n headers?: Record<string, string> | undefined;\n\n /** Custom data storage */\n data: Record<string, any>;\n\n /**\n * Listen for events from this socket\n */\n on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void;\n\n /**\n * Listen for any event from this socket\n */\n onAny(handler: (event: string, ...args: any[]) => void): void;\n\n /**\n * Emit event to this socket\n */\n emit(event: string, data: any): void;\n\n /**\n * Emit with compression\n */\n compressedEmit?(event: string, data: any): void;\n\n /**\n * Send one frame as-is, with no `{ event, data }` envelope: a string goes\n * out as a text frame, a Buffer/ArrayBuffer/Uint8Array as a binary frame\n * (`isBinary` overrides the guess). The reply side of a raw namespace; every\n * built-in adapter implements it.\n */\n send?(data: string | Buffer | ArrayBuffer | Uint8Array, isBinary?: boolean): void;\n\n /**\n * Join a room\n */\n join(room: string | string[]): void;\n\n /**\n * Leave a room\n */\n leave(room: string | string[]): void;\n\n /**\n * Emit to specific room(s)\n */\n to(room: string | string[]): WebSocketEmitter;\n\n /**\n * Emit to all sockets except this one\n */\n broadcast: WebSocketEmitter;\n\n /**\n * Get rooms this socket has joined\n */\n getRooms(): Set<string>;\n\n /**\n * Disconnect this socket\n */\n disconnect(close?: boolean): void;\n\n /**\n * Check if socket is connected\n */\n connected: boolean;\n}\n\n/**\n * WebSocket emitter interface for chaining operations\n */\nexport interface WebSocketEmitter {\n /**\n * Emit to target sockets\n */\n emit(event: string, data: any): void;\n\n /**\n * Target specific room(s)\n */\n to(room: string | string[]): WebSocketEmitter;\n\n /**\n * Exclude specific room(s)\n */\n except(room: string | string[]): WebSocketEmitter;\n\n /**\n * Use compression for this emit\n */\n compress(compress: boolean): WebSocketEmitter;\n}\n\n/**\n * WebSocket middleware function type\n */\nexport type WebSocketMiddleware = (\n socket: WebSocketConnection,\n next: (err?: Error) => void\n) => void;\n\n/**\n * WebSocket event handler type\n */\nexport type WebSocketEventHandler = (\n socket: WebSocketConnection,\n data: any,\n callback?: (response?: any) => void\n) => void | Promise<void>;\n\n/**\n * Merge WebSocket config from moro.config.ts with per-call createApp() options.\n * createApp() options take precedence over config for top-level and nested keys,\n * so `options.path` overrides `config.options.path` and same for cors fields.\n * @internal\n */\nexport function mergeWebSocketConfig(cfg: any, opts: any): any {\n const c = cfg || {};\n const o = opts || {};\n const cOpts = c.options || {};\n const oOpts = o.options || {};\n return {\n ...c,\n ...o,\n options: {\n ...cOpts,\n ...oOpts,\n cors: { ...(cOpts.cors || {}), ...(oOpts.cors || {}) },\n },\n };\n}\n"]}
@@ -1,7 +1,8 @@
1
1
  import { ValidationSchema } from '../validation/schema-interface.js';
2
2
  import { HttpRequest, HttpResponse } from '../http/index.js';
3
- import { type StaticBody, type StaticResponse } from './unified-router.js';
4
- export type { StaticBody, StaticResponse };
3
+ import { param, type StaticBody, type StaticResponse, type ParamEcho, type ParamRouteReply } from './unified-router.js';
4
+ export type { StaticBody, StaticResponse, ParamEcho, ParamRouteReply };
5
+ export { param };
5
6
  export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
6
7
  export type RouteHandler<T = any> = (req: HttpRequest, res: HttpResponse) => T | Promise<T>;
7
8
  export type Middleware = (req: HttpRequest, res: HttpResponse, next: () => void) => void | Promise<void>;
@@ -35,8 +36,8 @@ export interface MiddlewarePhases {
35
36
  export interface RouteSchema {
36
37
  method: HttpMethod;
37
38
  path: string;
38
- /** A function, or the response body itself (see StaticBody / .handler()) */
39
- handler: RouteHandler | StaticBody;
39
+ /** A function, the response body itself (StaticBody), or param(name) */
40
+ handler: RouteHandler | StaticBody | ParamEcho;
40
41
  validation?: ValidationConfig;
41
42
  auth?: AuthConfig;
42
43
  rateLimit?: RateLimitConfig;
@@ -46,6 +47,8 @@ export interface RouteSchema {
46
47
  tags?: string[];
47
48
  /** Fixed reply of a literal handler; see StaticResponse */
48
49
  static?: StaticResponse;
50
+ /** Engine shape of a param(name) handler; see ParamRouteReply */
51
+ paramEcho?: ParamRouteReply;
49
52
  }
50
53
  export declare const EXECUTION_PHASES: readonly ["security", "parsing", "rateLimit", "before", "auth", "validation", "transform", "cache", "after", "handler"];
51
54
  export type ExecutionPhase = (typeof EXECUTION_PHASES)[number];
@@ -72,9 +75,10 @@ export interface RouteBuilder {
72
75
  describe(description: string): RouteBuilder;
73
76
  tag(...tags: string[]): RouteBuilder;
74
77
  /** Terminal. A function handles the request; a string or Buffer IS the
75
- * response body (as res.send would send it), and on a route with nothing
76
- * else configured Moro's native engine answers it without calling JS. */
77
- handler<T>(handler: RouteHandler<T> | StaticBody): void;
78
+ * response body (as res.send would send it); param(name) echoes that path
79
+ * parameter as the body. On a route with nothing else configured Moro's
80
+ * native engine answers the last two without calling JS. */
81
+ handler<T>(handler: RouteHandler<T> | StaticBody | ParamEcho): void;
78
82
  }
79
83
  export interface CompiledRoute {
80
84
  schema: RouteSchema;
@@ -102,7 +106,7 @@ export declare class IntelligentRouteBuilder implements RouteBuilder {
102
106
  use(...middleware: Middleware[]): RouteBuilder;
103
107
  describe(description: string): RouteBuilder;
104
108
  tag(...tags: string[]): RouteBuilder;
105
- handler<T>(handler: RouteHandler<T> | StaticBody): void;
109
+ handler<T>(handler: RouteHandler<T> | StaticBody | ParamEcho): void;
106
110
  }
107
111
  /**
108
112
  * Thin facade implementing CompiledRoute interface
@@ -3,7 +3,8 @@
3
3
  //
4
4
  // NOTE: This file exports types and thin facades to UnifiedRouter
5
5
  // All routing logic has been consolidated in unified-router.ts
6
- import { UnifiedRouter, compileStaticRoute, } from './unified-router.js';
6
+ import { UnifiedRouter, compileStaticRoute, compileParamRoute, isParamEcho, param, } from './unified-router.js';
7
+ export { param };
7
8
  export const EXECUTION_PHASES = [
8
9
  'security',
9
10
  'parsing',
@@ -148,7 +149,11 @@ export class IntelligentRouteBuilder {
148
149
  this.router.registerRoute(compileStaticRoute(this.schema, handler));
149
150
  return;
150
151
  }
151
- throw new Error('Handler is required: a function, or the response body as a string or Buffer');
152
+ if (isParamEcho(handler)) {
153
+ this.router.registerRoute(compileParamRoute(this.schema, handler));
154
+ return;
155
+ }
156
+ throw new Error('Handler is required: a function, the response body as a string or Buffer, or param(name)');
152
157
  }
153
158
  }
154
159
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/routing/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Intelligent Routing System for Moro Framework\n// Schema-first with automatic middleware ordering and chainable API\n//\n// NOTE: This file exports types and thin facades to UnifiedRouter\n// All routing logic has been consolidated in unified-router.ts\n\nimport { ValidationSchema } from '../validation/schema-interface.js';\nimport { HttpRequest, HttpResponse } from '../http/index.js';\nimport {\n UnifiedRouter,\n compileStaticRoute,\n type RouteSchema as UnifiedRouteSchema,\n type StaticBody,\n type StaticResponse,\n} from './unified-router.js';\n\nexport type { StaticBody, StaticResponse };\n\n// ===== TYPE EXPORTS (Keep all - used by app code) =====\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\nexport type RouteHandler<T = any> = (req: HttpRequest, res: HttpResponse) => T | Promise<T>;\nexport type Middleware = (\n req: HttpRequest,\n res: HttpResponse,\n next: () => void\n) => void | Promise<void>;\n\nexport interface ValidationConfig {\n body?: ValidationSchema;\n query?: ValidationSchema;\n params?: ValidationSchema;\n headers?: ValidationSchema;\n}\n\nexport interface AuthConfig {\n roles?: string[];\n permissions?: string[];\n optional?: boolean;\n}\n\nexport interface RateLimitConfig {\n requests: number;\n window: number;\n skipSuccessfulRequests?: boolean;\n skipFailedRequests?: boolean;\n}\n\nexport interface CacheConfig {\n ttl: number;\n key?: string;\n tags?: string[];\n}\n\nexport interface MiddlewarePhases {\n before?: Middleware[];\n after?: Middleware[];\n transform?: Middleware[];\n}\n\nexport interface RouteSchema {\n method: HttpMethod;\n path: string;\n /** A function, or the response body itself (see StaticBody / .handler()) */\n handler: RouteHandler | StaticBody;\n validation?: ValidationConfig;\n auth?: AuthConfig;\n rateLimit?: RateLimitConfig;\n cache?: CacheConfig;\n middleware?: MiddlewarePhases;\n description?: string;\n tags?: string[];\n /** Fixed reply of a literal handler; see StaticResponse */\n static?: StaticResponse;\n}\n\nexport const EXECUTION_PHASES = [\n 'security',\n 'parsing',\n 'rateLimit',\n 'before',\n 'auth',\n 'validation',\n 'transform',\n 'cache',\n 'after',\n 'handler',\n] as const;\n\nexport type ExecutionPhase = (typeof EXECUTION_PHASES)[number];\n\nexport interface ValidatedRequest<T = any> extends HttpRequest {\n validatedBody?: T;\n validatedQuery?: any;\n validatedParams?: any;\n validatedHeaders?: any;\n user?: any;\n}\n\n// ===== ROUTE BUILDER INTERFACE (Public API) =====\n\nexport interface RouteBuilder {\n validate(config: ValidationConfig): RouteBuilder;\n body<T>(schema: ValidationSchema<T>): RouteBuilder;\n query<T>(schema: ValidationSchema<T>): RouteBuilder;\n params<T>(schema: ValidationSchema<T>): RouteBuilder;\n headers<T>(schema: ValidationSchema<T>): RouteBuilder;\n auth(config: AuthConfig): RouteBuilder;\n rateLimit(config: RateLimitConfig): RouteBuilder;\n cache(config: CacheConfig): RouteBuilder;\n before(...middleware: Middleware[]): RouteBuilder;\n after(...middleware: Middleware[]): RouteBuilder;\n transform(...middleware: Middleware[]): RouteBuilder;\n use(...middleware: Middleware[]): RouteBuilder;\n describe(description: string): RouteBuilder;\n tag(...tags: string[]): RouteBuilder;\n /** Terminal. A function handles the request; a string or Buffer IS the\n * response body (as res.send would send it), and on a route with nothing\n * else configured Moro's native engine answers it without calling JS. */\n handler<T>(handler: RouteHandler<T> | StaticBody): void;\n}\n\n// ===== COMPILED ROUTE INTERFACE (Public API) =====\n\nexport interface CompiledRoute {\n schema: RouteSchema;\n execute(req: HttpRequest, res: HttpResponse): Promise<void>;\n}\n\n// ===== FACADE IMPLEMENTATIONS (Delegate to UnifiedRouter) =====\n\n/**\n * Thin facade to UnifiedRouter.RouteBuilder\n * Maintains backward compatibility while using optimized implementation\n */\nexport class IntelligentRouteBuilder implements RouteBuilder {\n private schema: Partial<RouteSchema>;\n private router = UnifiedRouter.getInstance();\n\n constructor(method: HttpMethod, path: string) {\n this.schema = {\n method,\n path,\n middleware: {} as MiddlewarePhases,\n };\n }\n\n validate(config: ValidationConfig): RouteBuilder {\n // Avoid spread operator - manually merge properties\n if (!this.schema.validation) {\n this.schema.validation = config;\n } else {\n if (config.body !== undefined) this.schema.validation.body = config.body;\n if (config.query !== undefined) this.schema.validation.query = config.query;\n if (config.params !== undefined) this.schema.validation.params = config.params;\n if (config.headers !== undefined) this.schema.validation.headers = config.headers;\n }\n return this;\n }\n\n body<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.body = schema;\n return this;\n }\n\n query<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.query = schema;\n return this;\n }\n\n params<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.params = schema;\n return this;\n }\n\n headers<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.headers = schema;\n return this;\n }\n\n auth(config: AuthConfig): RouteBuilder {\n this.schema.auth = config;\n return this;\n }\n\n rateLimit(config: RateLimitConfig): RouteBuilder {\n this.schema.rateLimit = config;\n return this;\n }\n\n cache(config: CacheConfig): RouteBuilder {\n this.schema.cache = config;\n return this;\n }\n\n before(...middleware: Middleware[]): RouteBuilder {\n if (!this.schema.middleware) this.schema.middleware = {};\n const phases = this.schema.middleware as MiddlewarePhases;\n // Avoid spread, use push for better performance\n if (!phases.before) phases.before = [];\n for (let i = 0; i < middleware.length; i++) {\n phases.before.push(middleware[i] as Middleware);\n }\n return this;\n }\n\n after(...middleware: Middleware[]): RouteBuilder {\n if (!this.schema.middleware) this.schema.middleware = {};\n const phases = this.schema.middleware as MiddlewarePhases;\n // Avoid spread, use push for better performance\n if (!phases.after) phases.after = [];\n for (let i = 0; i < middleware.length; i++) {\n phases.after.push(middleware[i] as Middleware);\n }\n return this;\n }\n\n transform(...middleware: Middleware[]): RouteBuilder {\n if (!this.schema.middleware) this.schema.middleware = {};\n const phases = this.schema.middleware as MiddlewarePhases;\n // Avoid spread, use push for better performance\n if (!phases.transform) phases.transform = [];\n for (let i = 0; i < middleware.length; i++) {\n phases.transform.push(middleware[i] as Middleware);\n }\n return this;\n }\n\n use(...middleware: Middleware[]): RouteBuilder {\n return this.after(...middleware);\n }\n\n describe(description: string): RouteBuilder {\n this.schema.description = description;\n return this;\n }\n\n tag(...tags: string[]): RouteBuilder {\n // Avoid spread, use push for better performance\n if (!this.schema.tags) this.schema.tags = [];\n for (let i = 0; i < tags.length; i++) {\n this.schema.tags.push(tags[i] as string);\n }\n return this;\n }\n\n handler<T>(handler: RouteHandler<T> | StaticBody): void {\n if (typeof handler === 'function') {\n // Avoid spread operator - add handler directly\n this.schema.handler = handler;\n\n // Delegate to UnifiedRouter\n this.router.registerRoute(this.schema as RouteSchema);\n return;\n }\n if (typeof handler === 'string' || Buffer.isBuffer(handler)) {\n this.router.registerRoute(\n compileStaticRoute(this.schema as Partial<UnifiedRouteSchema>, handler)\n );\n return;\n }\n throw new Error('Handler is required: a function, or the response body as a string or Buffer');\n }\n}\n\n/**\n * Thin facade implementing CompiledRoute interface\n * Just stores schema for documentation purposes\n */\nexport class ExecutableRoute implements CompiledRoute {\n constructor(public readonly schema: RouteSchema) {\n // Register with UnifiedRouter\n UnifiedRouter.getInstance().registerRoute(schema);\n }\n\n async execute(_req: HttpRequest, _res: HttpResponse): Promise<void> {\n // This is never called - UnifiedRouter handles execution\n // But we implement it for interface compatibility\n throw new Error(\n 'ExecutableRoute.execute() should not be called directly - routing handled by UnifiedRouter'\n );\n }\n}\n\n// ===== FACTORY FUNCTIONS (Backward Compatibility) =====\n\nexport function createRoute(method: HttpMethod, path: string): RouteBuilder {\n return new IntelligentRouteBuilder(method, path);\n}\n\nexport function defineRoute(schema: RouteSchema): CompiledRoute {\n return new ExecutableRoute(schema);\n}\n\n// ===== RE-EXPORTS FROM UNIFIED ROUTER =====\n\nexport { UnifiedRouter } from './unified-router.js';\nexport { RouteBuilder as UnifiedRouteBuilder } from './unified-router.js';\nexport { PathMatcher, type CompiledPath, type MatchResult } from './path-matcher.js';\nexport { ObjectPoolManager, getPoolManager } from '../pooling/object-pool-manager.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/routing/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Intelligent Routing System for Moro Framework\n// Schema-first with automatic middleware ordering and chainable API\n//\n// NOTE: This file exports types and thin facades to UnifiedRouter\n// All routing logic has been consolidated in unified-router.ts\n\nimport { ValidationSchema } from '../validation/schema-interface.js';\nimport { HttpRequest, HttpResponse } from '../http/index.js';\nimport {\n UnifiedRouter,\n compileStaticRoute,\n compileParamRoute,\n isParamEcho,\n param,\n type RouteSchema as UnifiedRouteSchema,\n type StaticBody,\n type StaticResponse,\n type ParamEcho,\n type ParamRouteReply,\n} from './unified-router.js';\n\nexport type { StaticBody, StaticResponse, ParamEcho, ParamRouteReply };\nexport { param };\n\n// ===== TYPE EXPORTS (Keep all - used by app code) =====\n\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';\nexport type RouteHandler<T = any> = (req: HttpRequest, res: HttpResponse) => T | Promise<T>;\nexport type Middleware = (\n req: HttpRequest,\n res: HttpResponse,\n next: () => void\n) => void | Promise<void>;\n\nexport interface ValidationConfig {\n body?: ValidationSchema;\n query?: ValidationSchema;\n params?: ValidationSchema;\n headers?: ValidationSchema;\n}\n\nexport interface AuthConfig {\n roles?: string[];\n permissions?: string[];\n optional?: boolean;\n}\n\nexport interface RateLimitConfig {\n requests: number;\n window: number;\n skipSuccessfulRequests?: boolean;\n skipFailedRequests?: boolean;\n}\n\nexport interface CacheConfig {\n ttl: number;\n key?: string;\n tags?: string[];\n}\n\nexport interface MiddlewarePhases {\n before?: Middleware[];\n after?: Middleware[];\n transform?: Middleware[];\n}\n\nexport interface RouteSchema {\n method: HttpMethod;\n path: string;\n /** A function, the response body itself (StaticBody), or param(name) */\n handler: RouteHandler | StaticBody | ParamEcho;\n validation?: ValidationConfig;\n auth?: AuthConfig;\n rateLimit?: RateLimitConfig;\n cache?: CacheConfig;\n middleware?: MiddlewarePhases;\n description?: string;\n tags?: string[];\n /** Fixed reply of a literal handler; see StaticResponse */\n static?: StaticResponse;\n /** Engine shape of a param(name) handler; see ParamRouteReply */\n paramEcho?: ParamRouteReply;\n}\n\nexport const EXECUTION_PHASES = [\n 'security',\n 'parsing',\n 'rateLimit',\n 'before',\n 'auth',\n 'validation',\n 'transform',\n 'cache',\n 'after',\n 'handler',\n] as const;\n\nexport type ExecutionPhase = (typeof EXECUTION_PHASES)[number];\n\nexport interface ValidatedRequest<T = any> extends HttpRequest {\n validatedBody?: T;\n validatedQuery?: any;\n validatedParams?: any;\n validatedHeaders?: any;\n user?: any;\n}\n\n// ===== ROUTE BUILDER INTERFACE (Public API) =====\n\nexport interface RouteBuilder {\n validate(config: ValidationConfig): RouteBuilder;\n body<T>(schema: ValidationSchema<T>): RouteBuilder;\n query<T>(schema: ValidationSchema<T>): RouteBuilder;\n params<T>(schema: ValidationSchema<T>): RouteBuilder;\n headers<T>(schema: ValidationSchema<T>): RouteBuilder;\n auth(config: AuthConfig): RouteBuilder;\n rateLimit(config: RateLimitConfig): RouteBuilder;\n cache(config: CacheConfig): RouteBuilder;\n before(...middleware: Middleware[]): RouteBuilder;\n after(...middleware: Middleware[]): RouteBuilder;\n transform(...middleware: Middleware[]): RouteBuilder;\n use(...middleware: Middleware[]): RouteBuilder;\n describe(description: string): RouteBuilder;\n tag(...tags: string[]): RouteBuilder;\n /** Terminal. A function handles the request; a string or Buffer IS the\n * response body (as res.send would send it); param(name) echoes that path\n * parameter as the body. On a route with nothing else configured Moro's\n * native engine answers the last two without calling JS. */\n handler<T>(handler: RouteHandler<T> | StaticBody | ParamEcho): void;\n}\n\n// ===== COMPILED ROUTE INTERFACE (Public API) =====\n\nexport interface CompiledRoute {\n schema: RouteSchema;\n execute(req: HttpRequest, res: HttpResponse): Promise<void>;\n}\n\n// ===== FACADE IMPLEMENTATIONS (Delegate to UnifiedRouter) =====\n\n/**\n * Thin facade to UnifiedRouter.RouteBuilder\n * Maintains backward compatibility while using optimized implementation\n */\nexport class IntelligentRouteBuilder implements RouteBuilder {\n private schema: Partial<RouteSchema>;\n private router = UnifiedRouter.getInstance();\n\n constructor(method: HttpMethod, path: string) {\n this.schema = {\n method,\n path,\n middleware: {} as MiddlewarePhases,\n };\n }\n\n validate(config: ValidationConfig): RouteBuilder {\n // Avoid spread operator - manually merge properties\n if (!this.schema.validation) {\n this.schema.validation = config;\n } else {\n if (config.body !== undefined) this.schema.validation.body = config.body;\n if (config.query !== undefined) this.schema.validation.query = config.query;\n if (config.params !== undefined) this.schema.validation.params = config.params;\n if (config.headers !== undefined) this.schema.validation.headers = config.headers;\n }\n return this;\n }\n\n body<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.body = schema;\n return this;\n }\n\n query<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.query = schema;\n return this;\n }\n\n params<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.params = schema;\n return this;\n }\n\n headers<T>(schema: ValidationSchema<T>): RouteBuilder {\n if (!this.schema.validation) this.schema.validation = {};\n this.schema.validation.headers = schema;\n return this;\n }\n\n auth(config: AuthConfig): RouteBuilder {\n this.schema.auth = config;\n return this;\n }\n\n rateLimit(config: RateLimitConfig): RouteBuilder {\n this.schema.rateLimit = config;\n return this;\n }\n\n cache(config: CacheConfig): RouteBuilder {\n this.schema.cache = config;\n return this;\n }\n\n before(...middleware: Middleware[]): RouteBuilder {\n if (!this.schema.middleware) this.schema.middleware = {};\n const phases = this.schema.middleware as MiddlewarePhases;\n // Avoid spread, use push for better performance\n if (!phases.before) phases.before = [];\n for (let i = 0; i < middleware.length; i++) {\n phases.before.push(middleware[i] as Middleware);\n }\n return this;\n }\n\n after(...middleware: Middleware[]): RouteBuilder {\n if (!this.schema.middleware) this.schema.middleware = {};\n const phases = this.schema.middleware as MiddlewarePhases;\n // Avoid spread, use push for better performance\n if (!phases.after) phases.after = [];\n for (let i = 0; i < middleware.length; i++) {\n phases.after.push(middleware[i] as Middleware);\n }\n return this;\n }\n\n transform(...middleware: Middleware[]): RouteBuilder {\n if (!this.schema.middleware) this.schema.middleware = {};\n const phases = this.schema.middleware as MiddlewarePhases;\n // Avoid spread, use push for better performance\n if (!phases.transform) phases.transform = [];\n for (let i = 0; i < middleware.length; i++) {\n phases.transform.push(middleware[i] as Middleware);\n }\n return this;\n }\n\n use(...middleware: Middleware[]): RouteBuilder {\n return this.after(...middleware);\n }\n\n describe(description: string): RouteBuilder {\n this.schema.description = description;\n return this;\n }\n\n tag(...tags: string[]): RouteBuilder {\n // Avoid spread, use push for better performance\n if (!this.schema.tags) this.schema.tags = [];\n for (let i = 0; i < tags.length; i++) {\n this.schema.tags.push(tags[i] as string);\n }\n return this;\n }\n\n handler<T>(handler: RouteHandler<T> | StaticBody | ParamEcho): void {\n if (typeof handler === 'function') {\n // Avoid spread operator - add handler directly\n this.schema.handler = handler;\n\n // Delegate to UnifiedRouter\n this.router.registerRoute(this.schema as RouteSchema);\n return;\n }\n if (typeof handler === 'string' || Buffer.isBuffer(handler)) {\n this.router.registerRoute(\n compileStaticRoute(this.schema as Partial<UnifiedRouteSchema>, handler)\n );\n return;\n }\n if (isParamEcho(handler)) {\n this.router.registerRoute(\n compileParamRoute(this.schema as Partial<UnifiedRouteSchema>, handler)\n );\n return;\n }\n throw new Error(\n 'Handler is required: a function, the response body as a string or Buffer, or param(name)'\n );\n }\n}\n\n/**\n * Thin facade implementing CompiledRoute interface\n * Just stores schema for documentation purposes\n */\nexport class ExecutableRoute implements CompiledRoute {\n constructor(public readonly schema: RouteSchema) {\n // Register with UnifiedRouter\n UnifiedRouter.getInstance().registerRoute(schema);\n }\n\n async execute(_req: HttpRequest, _res: HttpResponse): Promise<void> {\n // This is never called - UnifiedRouter handles execution\n // But we implement it for interface compatibility\n throw new Error(\n 'ExecutableRoute.execute() should not be called directly - routing handled by UnifiedRouter'\n );\n }\n}\n\n// ===== FACTORY FUNCTIONS (Backward Compatibility) =====\n\nexport function createRoute(method: HttpMethod, path: string): RouteBuilder {\n return new IntelligentRouteBuilder(method, path);\n}\n\nexport function defineRoute(schema: RouteSchema): CompiledRoute {\n return new ExecutableRoute(schema);\n}\n\n// ===== RE-EXPORTS FROM UNIFIED ROUTER =====\n\nexport { UnifiedRouter } from './unified-router.js';\nexport { RouteBuilder as UnifiedRouteBuilder } from './unified-router.js';\nexport { PathMatcher, type CompiledPath, type MatchResult } from './path-matcher.js';\nexport { ObjectPoolManager, getPoolManager } from '../pooling/object-pool-manager.js';\n"]}