@morojs/moro 1.8.16 → 1.8.17

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.
@@ -264,6 +264,11 @@ class EngineConnectionWrapper {
264
264
  _headers = undefined;
265
265
  _query = undefined;
266
266
  _queryString;
267
+ // The engine upgraded this socket itself (wsAutoUpgrade): the handshake is
268
+ // fetched from the engine the first time ip, headers or query is read. It
269
+ // stays readable through the disconnect handler; a read after that gets
270
+ // the empty values.
271
+ _lazy;
267
272
  rooms = new Set();
268
273
  eventHandlers = new Map();
269
274
  anyHandlers = [];
@@ -279,17 +284,35 @@ class EngineConnectionWrapper {
279
284
  // Handshake snapshot (captured before the upgrade invalidated the reqId):
280
285
  // real values for IP-based rate limiting and header/token connection
281
286
  // auth. The header object and the parsed query are built on first read.
287
+ // Without a snapshot the engine performed the upgrade and holds the
288
+ // handshake: it is fetched on first read (see _lazy).
289
+ this._lazy = handshake === undefined;
282
290
  this._ip = handshake?.ip ?? '';
283
291
  this._flat = handshake?.flat;
284
292
  this._queryString = handshake?.query ?? '';
285
293
  }
294
+ materialize() {
295
+ this._lazy = false;
296
+ const hs = typeof this.server.wsHandshake === 'function'
297
+ ? this.server.wsHandshake(this.wsId)
298
+ : undefined;
299
+ if (hs) {
300
+ this._ip = hs.ip;
301
+ this._flat = hs.flat;
302
+ this._queryString = hs.query;
303
+ }
304
+ }
286
305
  get ip() {
306
+ if (this._lazy)
307
+ this.materialize();
287
308
  return this._ip;
288
309
  }
289
310
  /** The handshake request's headers, keys lowercased, duplicates joined. */
290
311
  get headers() {
291
312
  let h = this._headers;
292
313
  if (h === undefined) {
314
+ if (this._lazy)
315
+ this.materialize();
293
316
  h = headersFromFlat(this._flat);
294
317
  this._flat = undefined;
295
318
  this._headers = h;
@@ -300,6 +323,8 @@ class EngineConnectionWrapper {
300
323
  get query() {
301
324
  let q = this._query;
302
325
  if (q === undefined) {
326
+ if (this._lazy)
327
+ this.materialize();
303
328
  q = parseQueryString(this._queryString);
304
329
  this._query = q;
305
330
  }
@@ -309,7 +334,7 @@ class EngineConnectionWrapper {
309
334
  // handlers (e.g. reading an `orgId` query param) work against the engine
310
335
  // adapter unchanged.
311
336
  get handshake() {
312
- return { query: this.query, headers: this.headers, address: this._ip };
337
+ return { query: this.query, headers: this.headers, address: this.ip };
313
338
  }
314
339
  on(event, handler) {
315
340
  if (event === 'disconnect') {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-adapter.js","sourceRoot":"","sources":["../../../../src/core/networking/adapters/engine-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["// @morojs/engine WebSocket adapter.\n// Bridges the native engine's RFC 6455 WebSocket callbacks (onWsOpen/Message/\n// Close, wsSend/wsClose on MoroEngineServer) to Moro's WebSocketAdapter model.\n// Message framing mirrors the uWS adapter: JSON { event, data } envelopes with\n// a default namespace, so app.websocket() handlers work identically.\n\nimport crypto from 'crypto';\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// One logger per role for the whole process, not one per namespace or per\n// connection: a child logger was being built on every upgrade.\nconst nsLogger = createFrameworkLogger('ENGINE_WS_NS');\nconst connLogger = createFrameworkLogger('ENGINE_WS_CONN');\n\n// Random bytes for connection ids, drawn from a pool refilled in one call:\n// crypto.randomBytes(4) per upgrade was a CSPRNG call and a Buffer each.\nconst ID_POOL = Buffer.allocUnsafe(4096);\nlet idPoolOffset = ID_POOL.length;\nfunction randomIdSuffix(): string {\n if (idPoolOffset + 4 > ID_POOL.length) {\n crypto.randomFillSync(ID_POOL);\n idPoolOffset = 0;\n }\n const hex = ID_POOL.toString('hex', idPoolOffset, idPoolOffset + 4);\n idPoolOffset += 4;\n return hex;\n}\n\n// The handshake headers as the EngineRequest.headers getter builds them:\n// keys already lowercased, duplicate lines joined ('; ' for cookie, ', '\n// otherwise) - last-wins would let a client send two X-Forwarded-For lines\n// and hide the earlier one from IP-based WS auth / rate-limiting.\nfunction headersFromFlat(flat: string[] | undefined): Record<string, string> {\n const headers: Record<string, string> = {};\n if (!flat) return headers;\n for (let i = 0; i + 1 < flat.length; i += 2) {\n const key = flat[i];\n const val = flat[i + 1];\n if (key === undefined || val === undefined) continue;\n const existing = headers[key];\n headers[key] = existing === undefined ? val : existing + (key === 'cookie' ? '; ' : ', ') + val;\n }\n return headers;\n}\n\n// Parse a raw upgrade query string (`orgId=1&x=y`, with or without a leading\n// `?`) into a flat object for `socket.handshake.query`. Last value wins on\n// duplicate keys, matching URLSearchParams / Socket.IO.\nfunction parseQueryString(qs: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!qs) return out;\n const params = new URLSearchParams(qs.startsWith('?') ? qs.slice(1) : qs);\n for (const [key, value] of params) out[key] = value;\n return out;\n}\n\nexport class EngineWebSocketAdapter implements WebSocketAdapter {\n private server: any; // MoroEngineServer\n private namespaces = new Map<string, EngineNamespaceWrapper>();\n private connections = new Map<string, EngineConnectionWrapper>();\n private byWsId = new Map<number, EngineConnectionWrapper>();\n private logger = createFrameworkLogger('ENGINE_WS');\n private customIdGenerator?: () => string;\n private connectionCounter = 0;\n\n async initialize(httpServer: any, _options: WebSocketAdapterOptions = {}): Promise<void> {\n if (!httpServer || typeof httpServer.enableWebSocket !== 'function') {\n throw new Error(\n 'EngineWebSocketAdapter requires the @morojs/engine HTTP server (MoroEngineServer)'\n );\n }\n this.server = httpServer;\n\n // Register the native WS bridge: the engine drives these on the event loop.\n this.server.enableWebSocket({\n onOpen: (\n wsId: number,\n path: string,\n info?: { ip: string; flat?: string[] | undefined; query?: string }\n ) => this.handleOpen(wsId, path, info),\n onMessage: (wsId: number, data: any, isBinary: boolean) =>\n this.handleMessage(wsId, data, isBinary),\n onClose: (wsId: number, code: number) => this.handleClose(wsId, code),\n });\n\n this.createNamespace('/');\n this.logger.info('Engine WebSocket adapter initialized', 'Init');\n }\n\n private handleOpen(\n wsId: number,\n path: string,\n info?: { ip: string; flat?: string[] | undefined; query?: string }\n ): void {\n const id = this.customIdGenerator ? this.customIdGenerator() : this.generateId();\n const connection = new EngineConnectionWrapper(\n this.server,\n wsId,\n id,\n path,\n this.namespaces,\n info\n );\n this.connections.set(id, connection);\n this.byWsId.set(wsId, connection);\n // Route to the namespace whose registered path matches the upgrade URL\n // (Socket.IO parity for `app.websocket('/name', ...)`), falling back to the\n // default namespace when nothing matches. Query/hash are stripped so a\n // client connecting to `/name?token=…` still resolves to the `/name`\n // namespace.\n const nsPath = (path || '/').split(/[?#]/)[0] || '/';\n const ns =\n (this.namespaces.get(nsPath) as EngineNamespaceWrapper | undefined) ??\n this.getDefaultNamespaceImpl();\n connection.raw = ns.raw;\n ns.handleConnection(connection);\n }\n\n private handleMessage(wsId: number, data: any, isBinary: boolean): void {\n const connection = this.byWsId.get(wsId);\n if (!connection) return;\n if (connection.raw) {\n // Raw namespace: no envelope, no parse - the frame is the message\n if (isBinary) connection.handleBinary(Buffer.isBuffer(data) ? data : Buffer.from(data));\n else\n connection.handleRawText(\n typeof data === 'string' ? data : Buffer.from(data).toString('utf-8')\n );\n return;\n }\n if (isBinary) {\n connection.handleBinary(data);\n return;\n }\n // Text frames carry JSON { event, data } envelopes (uWS-adapter parity)\n const text = typeof data === 'string' ? data : Buffer.from(data).toString('utf-8');\n let parsed: any;\n try {\n parsed = JSON.parse(text);\n } catch {\n this.logger.warn(`Non-JSON message from ${connection.id}`, 'Message');\n return;\n }\n connection.handleMessage(parsed);\n }\n\n private handleClose(wsId: number, code: number): void {\n const connection = this.byWsId.get(wsId);\n if (!connection) return;\n connection.connected = false;\n connection.handleDisconnect(code);\n this.byWsId.delete(wsId);\n this.connections.delete(connection.id);\n }\n\n private generateId(): string {\n return `${Date.now().toString(36)}-${(++this.connectionCounter).toString(36)}-${randomIdSuffix()}`;\n }\n\n private getDefaultNamespaceImpl(): EngineNamespaceWrapper {\n return this.createNamespace('/') as EngineNamespaceWrapper;\n }\n\n createNamespace(namespace: string, options?: WebSocketNamespaceOptions): WebSocketNamespace {\n let ns = this.namespaces.get(namespace);\n if (!ns) {\n ns = new EngineNamespaceWrapper(namespace, this.connections);\n this.namespaces.set(namespace, ns);\n }\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 for (const conn of this.connections.values()) {\n conn.disconnect();\n }\n this.connections.clear();\n this.byWsId.clear();\n }\n\n setCompression(_enabled: boolean, _options?: any): void {\n // Compression (permessage-deflate) is negotiated natively; no-op for now.\n }\n\n setCustomIdGenerator(generator: () => string): void {\n this.customIdGenerator = generator;\n }\n\n getAdapterName(): string {\n return '@morojs/engine';\n }\n\n getConnectionCount(): number {\n let count = 0;\n for (const conn of this.connections.values()) {\n if (conn.connected) count++;\n }\n return count;\n }\n}\n\nclass EngineNamespaceWrapper 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 logger = nsLogger;\n\n constructor(\n private namespace: string,\n private connections: Map<string, EngineConnectionWrapper>\n ) {}\n\n on(event: 'connection', handler: (socket: WebSocketConnection) => void): void {\n if (event === 'connection') this.connectionHandlers.push(handler);\n }\n\n handleConnection(connection: EngineConnectionWrapper): void {\n this.runMiddlewares(connection, err => {\n if (err) {\n connection.disconnect(true);\n return;\n }\n // A throwing connection handler must not take down the socket/loop.\n for (const handler of this.connectionHandlers) {\n try {\n handler(connection);\n } catch (error) {\n this.logger.error(\n `WebSocket connection handler threw: ${error instanceof Error ? error.message : String(error)}`,\n 'Connection'\n );\n }\n }\n });\n }\n\n private runMiddlewares(\n connection: EngineConnectionWrapper,\n finalCallback: (err?: Error) => void\n ): void {\n let index = 0;\n const next = (err?: Error) => {\n if (err) return finalCallback(err);\n if (index >= this.middlewares.length) return finalCallback();\n const middleware = this.middlewares[index++];\n middleware?.(connection, next);\n };\n next();\n }\n\n emit(event: string, data: any): void {\n for (const connection of this.connections.values()) {\n if (connection.connected) connection.emit(event, data);\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new EngineEmitterWrapper(this.connections, {\n rooms: Array.isArray(room) ? room : [room],\n });\n }\n\n except(room: string | string[]): WebSocketEmitter {\n return new EngineEmitterWrapper(this.connections, {\n exceptRooms: Array.isArray(room) ? room : [room],\n });\n }\n\n getSockets(): WebSocketConnection[] {\n const result: WebSocketConnection[] = [];\n for (const conn of this.connections.values()) if (conn.connected) result.push(conn);\n return result;\n }\n\n getConnectionCount(): number {\n let count = 0;\n for (const conn of this.connections.values()) if (conn.connected) count++;\n return count;\n }\n\n use(middleware: WebSocketMiddleware): void {\n this.middlewares.push(middleware);\n }\n}\n\nclass EngineConnectionWrapper implements WebSocketConnection {\n public data: Record<string, any> = {};\n public connected = true;\n /** Raw framing (set from the namespace at open) */\n public raw = false;\n private _flat: string[] | undefined;\n private _headers: Record<string, string> | undefined = undefined;\n private _query: Record<string, string> | undefined = undefined;\n private readonly _queryString: string;\n private rooms = new Set<string>();\n private eventHandlers = new Map<\n string,\n Array<(data: any, callback?: (response?: any) => void) => void>\n >();\n private anyHandlers: Array<(event: string, ...args: any[]) => void> = [];\n private disconnectHandlers: Array<(reason?: any) => void> = [];\n private logger = connLogger;\n private readonly _ip: string;\n\n constructor(\n private server: any,\n private wsId: number,\n public readonly id: string,\n public readonly path: string,\n private namespaces: Map<string, EngineNamespaceWrapper>,\n handshake?: { ip: string; flat?: string[] | undefined; query?: string }\n ) {\n // Handshake snapshot (captured before the upgrade invalidated the reqId):\n // real values for IP-based rate limiting and header/token connection\n // auth. The header object and the parsed query are built on first read.\n this._ip = handshake?.ip ?? '';\n this._flat = handshake?.flat;\n this._queryString = handshake?.query ?? '';\n }\n\n get ip(): string {\n return this._ip;\n }\n\n /** The handshake request's headers, keys lowercased, duplicates joined. */\n get headers(): Record<string, string> {\n let h = this._headers;\n if (h === undefined) {\n h = headersFromFlat(this._flat);\n this._flat = undefined;\n this._headers = h;\n }\n return h;\n }\n\n /** The handshake request's query parameters. */\n get query(): Record<string, string> {\n let q = this._query;\n if (q === undefined) {\n q = parseQueryString(this._queryString);\n this._query = q;\n }\n return q;\n }\n\n // Socket.IO-parity handshake view so `socket.handshake.query`/`.headers`\n // handlers (e.g. reading an `orgId` query param) work against the engine\n // adapter unchanged.\n get handshake(): {\n query: Record<string, string>;\n headers: Record<string, string>;\n address: string;\n } {\n return { query: this.query, headers: this.headers, address: this._ip };\n }\n\n on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void {\n if (event === 'disconnect') {\n this.disconnectHandlers.push(handler as any);\n return;\n }\n let handlers = this.eventHandlers.get(event);\n if (!handlers) {\n handlers = [];\n this.eventHandlers.set(event, handlers);\n }\n handlers.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 (!this.connected) return;\n try {\n const sent = this.server.wsSend(this.wsId, JSON.stringify({ event, data }), false);\n if (!sent) this.logger.warn(`Backpressure for connection ${this.id}`, 'Backpressure');\n } catch (error) {\n this.logger.error(\n `Failed to emit ${event}: ${error instanceof Error ? error.message : String(error)}`,\n 'Emit'\n );\n }\n }\n\n compressedEmit(event: string, data: any): void {\n this.emit(event, data);\n }\n\n send(data: string | Buffer | ArrayBuffer | Uint8Array, isBinary?: boolean): void {\n if (!this.connected) return;\n try {\n const binary = isBinary ?? typeof data !== 'string';\n const sent = this.server.wsSend(this.wsId, data, binary);\n if (!sent) this.logger.warn(`Backpressure for connection ${this.id}`, 'Backpressure');\n } catch (error) {\n this.logger.error(\n `Failed to send frame: ${error instanceof Error ? error.message : String(error)}`,\n 'Send'\n );\n }\n }\n\n /** Raw namespace: a text frame reaches the 'message' handlers verbatim */\n handleRawText(text: string): void {\n if (!this.connected) return;\n for (const handler of this.anyHandlers) this.runHandler(handler, 'message', text);\n const handlers = this.eventHandlers.get('message');\n if (handlers) for (const handler of handlers) this.runHandler(handler, text);\n }\n\n // A user handler throwing must not kill the connection, skip sibling\n // handlers, or (via the native callback) get swallowed silently.\n private runHandler(fn: (...args: any[]) => void, ...args: any[]): void {\n try {\n fn(...args);\n } catch (error) {\n this.logger.error(\n `WebSocket handler threw: ${error instanceof Error ? error.message : String(error)}`,\n 'Handler'\n );\n }\n }\n\n handleMessage(data: any): void {\n // A frame delivered after the socket was closed (e.g. a second frame in the\n // same TCP read whose first frame's handler called disconnect()) must not\n // reach app handlers on a dead socket.\n if (!this.connected) return;\n if (!data || typeof data !== 'object') return;\n const { event, data: eventData, callback: hasCallback } = data;\n if (!event) return;\n\n const callback = hasCallback\n ? (response?: any) => this.emit(`${event}:response`, response)\n : undefined;\n\n for (const handler of this.anyHandlers) this.runHandler(handler, event, eventData);\n const handlers = this.eventHandlers.get(event);\n if (handlers) for (const handler of handlers) this.runHandler(handler, eventData, callback);\n }\n\n handleBinary(data: any): void {\n if (!this.connected) return;\n const handlers = this.eventHandlers.get('binary');\n if (handlers) for (const handler of handlers) this.runHandler(handler, data);\n }\n\n handleDisconnect(reason?: any): void {\n for (const handler of this.disconnectHandlers) this.runHandler(handler, reason);\n }\n\n join(room: string | string[]): void {\n for (const r of Array.isArray(room) ? room : [room]) this.rooms.add(r);\n }\n\n leave(room: string | string[]): void {\n for (const r of Array.isArray(room) ? room : [room]) this.rooms.delete(r);\n }\n\n getRooms(): Set<string> {\n return new Set(this.rooms);\n }\n\n isInRoom(room: string): boolean {\n return this.rooms.has(room);\n }\n\n disconnect(_close?: boolean): void {\n if (!this.connected) return;\n this.connected = false;\n try {\n this.server.wsClose(this.wsId, 1000, '');\n } catch {\n // already gone\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new EngineEmitterWrapper(this.allConnections(), {\n rooms: Array.isArray(room) ? room : [room],\n });\n }\n\n // Emit to everyone in the default namespace except this socket\n get broadcast(): WebSocketEmitter {\n return new EngineEmitterWrapper(this.allConnections(), { exceptId: this.id });\n }\n\n private allConnections(): Map<string, EngineConnectionWrapper> {\n return (this.namespaces.get('/') as any)?.['connections'] ?? new Map();\n }\n}\n\nclass EngineEmitterWrapper implements WebSocketEmitter {\n constructor(\n private connections: Map<string, EngineConnectionWrapper>,\n private filter: { rooms?: string[]; exceptRooms?: string[]; exceptId?: string }\n ) {}\n\n emit(event: string, data: any): void {\n for (const conn of this.connections.values()) {\n if (!conn.connected) continue;\n if (this.filter.exceptId && conn.id === this.filter.exceptId) continue;\n if (this.filter.rooms && !this.filter.rooms.some(r => conn.isInRoom(r))) continue;\n if (this.filter.exceptRooms && this.filter.exceptRooms.some(r => conn.isInRoom(r))) continue;\n conn.emit(event, data);\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n const rooms = Array.isArray(room) ? room : [room];\n return new EngineEmitterWrapper(this.connections, {\n ...this.filter,\n rooms: [...(this.filter.rooms ?? []), ...rooms],\n });\n }\n\n except(room: string | string[]): WebSocketEmitter {\n const rooms = Array.isArray(room) ? room : [room];\n return new EngineEmitterWrapper(this.connections, {\n ...this.filter,\n exceptRooms: [...(this.filter.exceptRooms ?? []), ...rooms],\n });\n }\n\n compress(_compress: boolean): WebSocketEmitter {\n return this; // native negotiation; chaining preserved\n }\n}\n"]}
1
+ {"version":3,"file":"engine-adapter.js","sourceRoot":"","sources":["../../../../src/core/networking/adapters/engine-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["// @morojs/engine WebSocket adapter.\n// Bridges the native engine's RFC 6455 WebSocket callbacks (onWsOpen/Message/\n// Close, wsSend/wsClose on MoroEngineServer) to Moro's WebSocketAdapter model.\n// Message framing mirrors the uWS adapter: JSON { event, data } envelopes with\n// a default namespace, so app.websocket() handlers work identically.\n\nimport crypto from 'crypto';\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// One logger per role for the whole process, not one per namespace or per\n// connection: a child logger was being built on every upgrade.\nconst nsLogger = createFrameworkLogger('ENGINE_WS_NS');\nconst connLogger = createFrameworkLogger('ENGINE_WS_CONN');\n\n// Random bytes for connection ids, drawn from a pool refilled in one call:\n// crypto.randomBytes(4) per upgrade was a CSPRNG call and a Buffer each.\nconst ID_POOL = Buffer.allocUnsafe(4096);\nlet idPoolOffset = ID_POOL.length;\nfunction randomIdSuffix(): string {\n if (idPoolOffset + 4 > ID_POOL.length) {\n crypto.randomFillSync(ID_POOL);\n idPoolOffset = 0;\n }\n const hex = ID_POOL.toString('hex', idPoolOffset, idPoolOffset + 4);\n idPoolOffset += 4;\n return hex;\n}\n\n// The handshake headers as the EngineRequest.headers getter builds them:\n// keys already lowercased, duplicate lines joined ('; ' for cookie, ', '\n// otherwise) - last-wins would let a client send two X-Forwarded-For lines\n// and hide the earlier one from IP-based WS auth / rate-limiting.\nfunction headersFromFlat(flat: string[] | undefined): Record<string, string> {\n const headers: Record<string, string> = {};\n if (!flat) return headers;\n for (let i = 0; i + 1 < flat.length; i += 2) {\n const key = flat[i];\n const val = flat[i + 1];\n if (key === undefined || val === undefined) continue;\n const existing = headers[key];\n headers[key] = existing === undefined ? val : existing + (key === 'cookie' ? '; ' : ', ') + val;\n }\n return headers;\n}\n\n// Parse a raw upgrade query string (`orgId=1&x=y`, with or without a leading\n// `?`) into a flat object for `socket.handshake.query`. Last value wins on\n// duplicate keys, matching URLSearchParams / Socket.IO.\nfunction parseQueryString(qs: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!qs) return out;\n const params = new URLSearchParams(qs.startsWith('?') ? qs.slice(1) : qs);\n for (const [key, value] of params) out[key] = value;\n return out;\n}\n\nexport class EngineWebSocketAdapter implements WebSocketAdapter {\n private server: any; // MoroEngineServer\n private namespaces = new Map<string, EngineNamespaceWrapper>();\n private connections = new Map<string, EngineConnectionWrapper>();\n private byWsId = new Map<number, EngineConnectionWrapper>();\n private logger = createFrameworkLogger('ENGINE_WS');\n private customIdGenerator?: () => string;\n private connectionCounter = 0;\n\n async initialize(httpServer: any, _options: WebSocketAdapterOptions = {}): Promise<void> {\n if (!httpServer || typeof httpServer.enableWebSocket !== 'function') {\n throw new Error(\n 'EngineWebSocketAdapter requires the @morojs/engine HTTP server (MoroEngineServer)'\n );\n }\n this.server = httpServer;\n\n // Register the native WS bridge: the engine drives these on the event loop.\n this.server.enableWebSocket({\n onOpen: (\n wsId: number,\n path: string,\n info?: { ip: string; flat?: string[] | undefined; query?: string }\n ) => this.handleOpen(wsId, path, info),\n onMessage: (wsId: number, data: any, isBinary: boolean) =>\n this.handleMessage(wsId, data, isBinary),\n onClose: (wsId: number, code: number) => this.handleClose(wsId, code),\n });\n\n this.createNamespace('/');\n this.logger.info('Engine WebSocket adapter initialized', 'Init');\n }\n\n private handleOpen(\n wsId: number,\n path: string,\n info?: { ip: string; flat?: string[] | undefined; query?: string }\n ): void {\n const id = this.customIdGenerator ? this.customIdGenerator() : this.generateId();\n const connection = new EngineConnectionWrapper(\n this.server,\n wsId,\n id,\n path,\n this.namespaces,\n info\n );\n this.connections.set(id, connection);\n this.byWsId.set(wsId, connection);\n // Route to the namespace whose registered path matches the upgrade URL\n // (Socket.IO parity for `app.websocket('/name', ...)`), falling back to the\n // default namespace when nothing matches. Query/hash are stripped so a\n // client connecting to `/name?token=…` still resolves to the `/name`\n // namespace.\n const nsPath = (path || '/').split(/[?#]/)[0] || '/';\n const ns =\n (this.namespaces.get(nsPath) as EngineNamespaceWrapper | undefined) ??\n this.getDefaultNamespaceImpl();\n connection.raw = ns.raw;\n ns.handleConnection(connection);\n }\n\n private handleMessage(wsId: number, data: any, isBinary: boolean): void {\n const connection = this.byWsId.get(wsId);\n if (!connection) return;\n if (connection.raw) {\n // Raw namespace: no envelope, no parse - the frame is the message\n if (isBinary) connection.handleBinary(Buffer.isBuffer(data) ? data : Buffer.from(data));\n else\n connection.handleRawText(\n typeof data === 'string' ? data : Buffer.from(data).toString('utf-8')\n );\n return;\n }\n if (isBinary) {\n connection.handleBinary(data);\n return;\n }\n // Text frames carry JSON { event, data } envelopes (uWS-adapter parity)\n const text = typeof data === 'string' ? data : Buffer.from(data).toString('utf-8');\n let parsed: any;\n try {\n parsed = JSON.parse(text);\n } catch {\n this.logger.warn(`Non-JSON message from ${connection.id}`, 'Message');\n return;\n }\n connection.handleMessage(parsed);\n }\n\n private handleClose(wsId: number, code: number): void {\n const connection = this.byWsId.get(wsId);\n if (!connection) return;\n connection.connected = false;\n connection.handleDisconnect(code);\n this.byWsId.delete(wsId);\n this.connections.delete(connection.id);\n }\n\n private generateId(): string {\n return `${Date.now().toString(36)}-${(++this.connectionCounter).toString(36)}-${randomIdSuffix()}`;\n }\n\n private getDefaultNamespaceImpl(): EngineNamespaceWrapper {\n return this.createNamespace('/') as EngineNamespaceWrapper;\n }\n\n createNamespace(namespace: string, options?: WebSocketNamespaceOptions): WebSocketNamespace {\n let ns = this.namespaces.get(namespace);\n if (!ns) {\n ns = new EngineNamespaceWrapper(namespace, this.connections);\n this.namespaces.set(namespace, ns);\n }\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 for (const conn of this.connections.values()) {\n conn.disconnect();\n }\n this.connections.clear();\n this.byWsId.clear();\n }\n\n setCompression(_enabled: boolean, _options?: any): void {\n // Compression (permessage-deflate) is negotiated natively; no-op for now.\n }\n\n setCustomIdGenerator(generator: () => string): void {\n this.customIdGenerator = generator;\n }\n\n getAdapterName(): string {\n return '@morojs/engine';\n }\n\n getConnectionCount(): number {\n let count = 0;\n for (const conn of this.connections.values()) {\n if (conn.connected) count++;\n }\n return count;\n }\n}\n\nclass EngineNamespaceWrapper 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 logger = nsLogger;\n\n constructor(\n private namespace: string,\n private connections: Map<string, EngineConnectionWrapper>\n ) {}\n\n on(event: 'connection', handler: (socket: WebSocketConnection) => void): void {\n if (event === 'connection') this.connectionHandlers.push(handler);\n }\n\n handleConnection(connection: EngineConnectionWrapper): void {\n this.runMiddlewares(connection, err => {\n if (err) {\n connection.disconnect(true);\n return;\n }\n // A throwing connection handler must not take down the socket/loop.\n for (const handler of this.connectionHandlers) {\n try {\n handler(connection);\n } catch (error) {\n this.logger.error(\n `WebSocket connection handler threw: ${error instanceof Error ? error.message : String(error)}`,\n 'Connection'\n );\n }\n }\n });\n }\n\n private runMiddlewares(\n connection: EngineConnectionWrapper,\n finalCallback: (err?: Error) => void\n ): void {\n let index = 0;\n const next = (err?: Error) => {\n if (err) return finalCallback(err);\n if (index >= this.middlewares.length) return finalCallback();\n const middleware = this.middlewares[index++];\n middleware?.(connection, next);\n };\n next();\n }\n\n emit(event: string, data: any): void {\n for (const connection of this.connections.values()) {\n if (connection.connected) connection.emit(event, data);\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new EngineEmitterWrapper(this.connections, {\n rooms: Array.isArray(room) ? room : [room],\n });\n }\n\n except(room: string | string[]): WebSocketEmitter {\n return new EngineEmitterWrapper(this.connections, {\n exceptRooms: Array.isArray(room) ? room : [room],\n });\n }\n\n getSockets(): WebSocketConnection[] {\n const result: WebSocketConnection[] = [];\n for (const conn of this.connections.values()) if (conn.connected) result.push(conn);\n return result;\n }\n\n getConnectionCount(): number {\n let count = 0;\n for (const conn of this.connections.values()) if (conn.connected) count++;\n return count;\n }\n\n use(middleware: WebSocketMiddleware): void {\n this.middlewares.push(middleware);\n }\n}\n\nclass EngineConnectionWrapper implements WebSocketConnection {\n public data: Record<string, any> = {};\n public connected = true;\n /** Raw framing (set from the namespace at open) */\n public raw = false;\n private _flat: string[] | undefined;\n private _headers: Record<string, string> | undefined = undefined;\n private _query: Record<string, string> | undefined = undefined;\n private _queryString: string;\n // The engine upgraded this socket itself (wsAutoUpgrade): the handshake is\n // fetched from the engine the first time ip, headers or query is read. It\n // stays readable through the disconnect handler; a read after that gets\n // the empty values.\n private _lazy: boolean;\n private rooms = new Set<string>();\n private eventHandlers = new Map<\n string,\n Array<(data: any, callback?: (response?: any) => void) => void>\n >();\n private anyHandlers: Array<(event: string, ...args: any[]) => void> = [];\n private disconnectHandlers: Array<(reason?: any) => void> = [];\n private logger = connLogger;\n private _ip: string;\n\n constructor(\n private server: any,\n private wsId: number,\n public readonly id: string,\n public readonly path: string,\n private namespaces: Map<string, EngineNamespaceWrapper>,\n handshake?: { ip: string; flat?: string[] | undefined; query?: string }\n ) {\n // Handshake snapshot (captured before the upgrade invalidated the reqId):\n // real values for IP-based rate limiting and header/token connection\n // auth. The header object and the parsed query are built on first read.\n // Without a snapshot the engine performed the upgrade and holds the\n // handshake: it is fetched on first read (see _lazy).\n this._lazy = handshake === undefined;\n this._ip = handshake?.ip ?? '';\n this._flat = handshake?.flat;\n this._queryString = handshake?.query ?? '';\n }\n\n private materialize(): void {\n this._lazy = false;\n const hs =\n typeof this.server.wsHandshake === 'function'\n ? this.server.wsHandshake(this.wsId)\n : undefined;\n if (hs) {\n this._ip = hs.ip;\n this._flat = hs.flat;\n this._queryString = hs.query;\n }\n }\n\n get ip(): string {\n if (this._lazy) this.materialize();\n return this._ip;\n }\n\n /** The handshake request's headers, keys lowercased, duplicates joined. */\n get headers(): Record<string, string> {\n let h = this._headers;\n if (h === undefined) {\n if (this._lazy) this.materialize();\n h = headersFromFlat(this._flat);\n this._flat = undefined;\n this._headers = h;\n }\n return h;\n }\n\n /** The handshake request's query parameters. */\n get query(): Record<string, string> {\n let q = this._query;\n if (q === undefined) {\n if (this._lazy) this.materialize();\n q = parseQueryString(this._queryString);\n this._query = q;\n }\n return q;\n }\n\n // Socket.IO-parity handshake view so `socket.handshake.query`/`.headers`\n // handlers (e.g. reading an `orgId` query param) work against the engine\n // adapter unchanged.\n get handshake(): {\n query: Record<string, string>;\n headers: Record<string, string>;\n address: string;\n } {\n return { query: this.query, headers: this.headers, address: this.ip };\n }\n\n on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void {\n if (event === 'disconnect') {\n this.disconnectHandlers.push(handler as any);\n return;\n }\n let handlers = this.eventHandlers.get(event);\n if (!handlers) {\n handlers = [];\n this.eventHandlers.set(event, handlers);\n }\n handlers.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 (!this.connected) return;\n try {\n const sent = this.server.wsSend(this.wsId, JSON.stringify({ event, data }), false);\n if (!sent) this.logger.warn(`Backpressure for connection ${this.id}`, 'Backpressure');\n } catch (error) {\n this.logger.error(\n `Failed to emit ${event}: ${error instanceof Error ? error.message : String(error)}`,\n 'Emit'\n );\n }\n }\n\n compressedEmit(event: string, data: any): void {\n this.emit(event, data);\n }\n\n send(data: string | Buffer | ArrayBuffer | Uint8Array, isBinary?: boolean): void {\n if (!this.connected) return;\n try {\n const binary = isBinary ?? typeof data !== 'string';\n const sent = this.server.wsSend(this.wsId, data, binary);\n if (!sent) this.logger.warn(`Backpressure for connection ${this.id}`, 'Backpressure');\n } catch (error) {\n this.logger.error(\n `Failed to send frame: ${error instanceof Error ? error.message : String(error)}`,\n 'Send'\n );\n }\n }\n\n /** Raw namespace: a text frame reaches the 'message' handlers verbatim */\n handleRawText(text: string): void {\n if (!this.connected) return;\n for (const handler of this.anyHandlers) this.runHandler(handler, 'message', text);\n const handlers = this.eventHandlers.get('message');\n if (handlers) for (const handler of handlers) this.runHandler(handler, text);\n }\n\n // A user handler throwing must not kill the connection, skip sibling\n // handlers, or (via the native callback) get swallowed silently.\n private runHandler(fn: (...args: any[]) => void, ...args: any[]): void {\n try {\n fn(...args);\n } catch (error) {\n this.logger.error(\n `WebSocket handler threw: ${error instanceof Error ? error.message : String(error)}`,\n 'Handler'\n );\n }\n }\n\n handleMessage(data: any): void {\n // A frame delivered after the socket was closed (e.g. a second frame in the\n // same TCP read whose first frame's handler called disconnect()) must not\n // reach app handlers on a dead socket.\n if (!this.connected) return;\n if (!data || typeof data !== 'object') return;\n const { event, data: eventData, callback: hasCallback } = data;\n if (!event) return;\n\n const callback = hasCallback\n ? (response?: any) => this.emit(`${event}:response`, response)\n : undefined;\n\n for (const handler of this.anyHandlers) this.runHandler(handler, event, eventData);\n const handlers = this.eventHandlers.get(event);\n if (handlers) for (const handler of handlers) this.runHandler(handler, eventData, callback);\n }\n\n handleBinary(data: any): void {\n if (!this.connected) return;\n const handlers = this.eventHandlers.get('binary');\n if (handlers) for (const handler of handlers) this.runHandler(handler, data);\n }\n\n handleDisconnect(reason?: any): void {\n for (const handler of this.disconnectHandlers) this.runHandler(handler, reason);\n }\n\n join(room: string | string[]): void {\n for (const r of Array.isArray(room) ? room : [room]) this.rooms.add(r);\n }\n\n leave(room: string | string[]): void {\n for (const r of Array.isArray(room) ? room : [room]) this.rooms.delete(r);\n }\n\n getRooms(): Set<string> {\n return new Set(this.rooms);\n }\n\n isInRoom(room: string): boolean {\n return this.rooms.has(room);\n }\n\n disconnect(_close?: boolean): void {\n if (!this.connected) return;\n this.connected = false;\n try {\n this.server.wsClose(this.wsId, 1000, '');\n } catch {\n // already gone\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n return new EngineEmitterWrapper(this.allConnections(), {\n rooms: Array.isArray(room) ? room : [room],\n });\n }\n\n // Emit to everyone in the default namespace except this socket\n get broadcast(): WebSocketEmitter {\n return new EngineEmitterWrapper(this.allConnections(), { exceptId: this.id });\n }\n\n private allConnections(): Map<string, EngineConnectionWrapper> {\n return (this.namespaces.get('/') as any)?.['connections'] ?? new Map();\n }\n}\n\nclass EngineEmitterWrapper implements WebSocketEmitter {\n constructor(\n private connections: Map<string, EngineConnectionWrapper>,\n private filter: { rooms?: string[]; exceptRooms?: string[]; exceptId?: string }\n ) {}\n\n emit(event: string, data: any): void {\n for (const conn of this.connections.values()) {\n if (!conn.connected) continue;\n if (this.filter.exceptId && conn.id === this.filter.exceptId) continue;\n if (this.filter.rooms && !this.filter.rooms.some(r => conn.isInRoom(r))) continue;\n if (this.filter.exceptRooms && this.filter.exceptRooms.some(r => conn.isInRoom(r))) continue;\n conn.emit(event, data);\n }\n }\n\n to(room: string | string[]): WebSocketEmitter {\n const rooms = Array.isArray(room) ? room : [room];\n return new EngineEmitterWrapper(this.connections, {\n ...this.filter,\n rooms: [...(this.filter.rooms ?? []), ...rooms],\n });\n }\n\n except(room: string | string[]): WebSocketEmitter {\n const rooms = Array.isArray(room) ? room : [room];\n return new EngineEmitterWrapper(this.connections, {\n ...this.filter,\n exceptRooms: [...(this.filter.exceptRooms ?? []), ...rooms],\n });\n }\n\n compress(_compress: boolean): WebSocketEmitter {\n return this; // native negotiation; chaining preserved\n }\n}\n"]}
@@ -89,6 +89,11 @@ export interface EngineCapabilities {
89
89
  * with one variable path segment, echoed as the body, answered inside the
90
90
  * engine. Used for param(name) handlers on bare routes. */
91
91
  paramRoutes: boolean;
92
+ /** setWsAutoUpgrade()/wsGetHeaders()/wsGetQuery()/wsGetRemoteAddress()
93
+ * exist (engine >= 1.1.15): the engine answers a valid WebSocket
94
+ * handshake itself and fires onWsOpen, so an upgrade never round-trips
95
+ * through onRequest; the handshake stays readable on the socket. */
96
+ wsAutoUpgrade: boolean;
92
97
  /** I/O transport in use ('epoll', 'uv', 'uring'), when the engine reports it. */
93
98
  transport?: string;
94
99
  }
@@ -86,6 +86,7 @@ const CAP_KEYS = [
86
86
  'callbackScope',
87
87
  'batchDispatch',
88
88
  'paramRoutes',
89
+ 'wsAutoUpgrade',
89
90
  ];
90
91
  const NO_CAPABILITIES = Object.freeze(Object.fromEntries(CAP_KEYS.map(k => [k, false])));
91
92
  const capabilitiesCache = new WeakMap();
@@ -1 +1 @@
1
- {"version":3,"file":"package-utils.js","sourceRoot":"","sources":["../../../src/core/utilities/package-utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Package and Module Resolution Utilities\n// ESM-compatible helpers for detecting and resolving optional dependencies\n\nimport { createRequire } from 'module';\nimport { dirname, join } from 'path';\nimport { existsSync, realpathSync } from 'fs';\nimport { pathToFileURL } from 'url';\nimport { selfRequire } from './self-require.js';\n\n/**\n * Check if a package is available in the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to check (e.g., 'socket.io', 'zod')\n * @returns true if the package is installed, false otherwise\n *\n * @example\n * if (isPackageAvailable('socket.io')) {\n * // socket.io is installed, safe to import\n * const { Server } = await import('socket.io');\n * }\n */\nexport function isPackageAvailable(packageName: string): boolean {\n try {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n userRequire.resolve(packageName);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve a package path from the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to resolve\n * @returns The resolved package path\n * @throws Error if the package is not found\n *\n * @example\n * const socketIOPath = resolveUserPackage('socket.io');\n * const { Server } = await import(socketIOPath);\n */\nexport function resolveUserPackage(packageName: string): string {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n return userRequire.resolve(packageName);\n}\n\n/**\n * Create a require function for the user's working directory\n * Useful for resolving packages installed by the user, not in Moro's dependencies\n *\n * @returns A require function scoped to the user's working directory\n *\n * @example\n * const userRequire = createUserRequire();\n * const packagePath = userRequire.resolve('some-package');\n */\nexport function createUserRequire() {\n return createRequire(join(process.cwd(), 'package.json'));\n}\n\n// ---------------------------------------------------------------------------\n// Native HTTP engine loading\n// ---------------------------------------------------------------------------\n\n/**\n * Package names probed for the native HTTP engine, in priority order.\n * '@morojs/engine' is Moro's own engine (installed as an optionalDependency of\n * the framework); 'uWebSockets.js' is honored as a legacy user-installed peer.\n */\nexport const NATIVE_ENGINE_PACKAGES = ['@morojs/engine', 'uWebSockets.js'] as const;\n\nconst FRAMEWORK_PACKAGE_NAME = '@morojs/moro';\n\n/** Feature flags the framework gates option-passing on, so it never hands a\n * serve() option to an engine build that predates it. Everything defaults\n * false, so an older engine behaves exactly as it did before these existed. */\nexport interface EngineCapabilities {\n /** The full serve() limit surface is parsed (engine >= 1.1.0). */\n limits: boolean;\n /** In-process TLS termination via options.ssl (engine >= 1.1.x). */\n tls: boolean;\n /** ALPN HTTP/2 via options.http2 (reserved). */\n http2: boolean;\n /** WebSocket permessage-deflate via options.wsDeflate. */\n wsDeflate: boolean;\n /** responseTimeoutMs / responseBackpressureLimit / maxUriSize are parsed. */\n responseLimits: boolean;\n /** ssl.ciphers / ssl.ciphersuites / ssl.ecdhCurve are parsed. */\n tlsPolicy: boolean;\n /** updateSsl(serverId, ssl) exists: certificate rotation without a restart\n * (engine >= 1.1.8). Gates app.reloadTLS() on the engine. */\n tlsReload: boolean;\n /** setStaticRoute()/clearStaticRoutes() exist. Used for a literal body\n * given to the route builder's .handler() when the route has nothing\n * else configured, because a static route bypasses middleware, hooks,\n * auth and validation by design. */\n staticRoutes: boolean;\n /** prepareResponse()/respondPrepared()/respondPreparedEmpty()/endWith()\n * exist (engine >= 1.1.6): the adapter replays prepared header blocks for\n * the responses it emits itself. */\n responseTemplates: boolean;\n /** onAborted/onWritable are delivered on a later loop turn, never from\n * inside respond()/write()/end() (engine >= 1.1.6). */\n asyncNotify: boolean;\n /** A server left open at environment teardown is closed by the engine's\n * cleanup hook, so the engine may run inside worker threads that can be\n * terminate()d (engine >= 1.1.6). Gates thread-based clustering. */\n workerThreads: boolean;\n /** V8 fast API calls are installed on the hot entry points (informational). */\n fastCalls: boolean;\n /** Batched pipelined dispatch (onRequestBatch / getBatchBuffers / getPath). */\n batchDispatch: boolean;\n /** Every callback into JS runs inside a Node callback scope, so nextTicks\n * and microtasks queued during dispatch run when the callback returns;\n * the adapter then needs no drain of its own (engine > 1.1.6). */\n callbackScope: boolean;\n /** setParamRoute()/clearParamRoutes() exist (engine >= 1.1.9): a route\n * with one variable path segment, echoed as the body, answered inside the\n * engine. Used for param(name) handlers on bare routes. */\n paramRoutes: boolean;\n /** I/O transport in use ('epoll', 'uv', 'uring'), when the engine reports it. */\n transport?: string;\n}\n\n// One place to name every boolean flag: getEngineCapabilities coerces each\n// with `=== true`, and NO_CAPABILITIES is derived from the same list, so a\n// flag added here can never be read on one path and forgotten on the other.\nconst CAP_KEYS = [\n 'limits',\n 'tls',\n 'http2',\n 'wsDeflate',\n 'responseLimits',\n 'tlsPolicy',\n 'tlsReload',\n 'staticRoutes',\n 'responseTemplates',\n 'asyncNotify',\n 'workerThreads',\n 'fastCalls',\n 'callbackScope',\n 'batchDispatch',\n 'paramRoutes',\n] as const;\n\nexport interface NativeEngineLoadResult {\n /** The loaded engine module (CJS namespace: App, SSLApp, ...) */\n module: any;\n /** Which package satisfied the load */\n source: string;\n /** The engine package's version, when its package.json is resolvable */\n version?: string;\n /** Feature flags (Moro-shaped engine only; all-false for uWS or an\n * engine too old to advertise them). */\n capabilities?: EngineCapabilities;\n}\n\nconst NO_CAPABILITIES: EngineCapabilities = Object.freeze(\n Object.fromEntries(CAP_KEYS.map(k => [k, false]))\n) as unknown as EngineCapabilities;\n\nconst capabilitiesCache = new WeakMap<object, EngineCapabilities>();\n\n/**\n * Feature-detect a loaded engine module. Reads probe().capabilities when the\n * engine exposes it (>= 1.1.0); otherwise everything is false so the framework\n * passes only the options an older engine understood. uWS-style modules (no\n * probe/serve) report all-false — their SSL/limits go through the uWS-specific\n * paths, not these flags.\n */\nexport function getEngineCapabilities(module: any): EngineCapabilities {\n const surface = module?.default || module;\n if (!surface || typeof surface !== 'object') return NO_CAPABILITIES;\n const cached = capabilitiesCache.get(surface);\n if (cached) return cached;\n\n let caps: EngineCapabilities = NO_CAPABILITIES;\n try {\n if (typeof surface.probe === 'function') {\n const probe = surface.probe();\n const c = probe?.capabilities;\n if (c && typeof c === 'object') {\n const next: Record<string, boolean | string> = {};\n for (const key of CAP_KEYS) next[key] = c[key] === true;\n if (typeof probe.transport === 'string') next.transport = probe.transport;\n caps = next as unknown as EngineCapabilities;\n }\n }\n } catch {\n caps = NO_CAPABILITIES;\n }\n capabilitiesCache.set(surface, caps);\n return caps;\n}\n\n// undefined = never attempted, null = attempted and failed\nlet cachedEngine: NativeEngineLoadResult | null | undefined;\nlet engineLoadErrors: string[] = [];\n\n/**\n * Locate the installed framework package directory so the engine (a dependency\n * of moro, not of the user's app) resolves under strict layouts like pnpm's.\n * Walks up from cwd looking for node_modules/@morojs/moro, resolving symlinks\n * so pnpm's store-linked layout anchors requires next to moro's own deps.\n * Inside the framework repo itself (tests, examples) cwd is the framework dir.\n */\nfunction findFrameworkAnchor(): ReturnType<typeof createRequire> | null {\n // Primary: anchor to moro's OWN compiled location, so moro's `@morojs/engine`\n // dependency resolves relative to where moro is installed regardless of\n // `process.cwd()` (Docker WORKDIR, supervisord, pm2, a subdirectory, …). The\n // cwd-based walk below is a defensive fallback for exotic layouts.\n if (selfRequire) return selfRequire;\n\n try {\n const cwdPackageJson = join(process.cwd(), 'package.json');\n if (existsSync(cwdPackageJson)) {\n const require = createRequire(cwdPackageJson);\n const name = require(cwdPackageJson)?.name;\n if (name === FRAMEWORK_PACKAGE_NAME) {\n return require;\n }\n }\n } catch {\n // fall through to the node_modules walk\n }\n\n let dir = process.cwd();\n for (;;) {\n const packageJson = join(dir, 'node_modules', '@morojs', 'moro', 'package.json');\n try {\n if (existsSync(packageJson)) {\n return createRequire(join(realpathSync(dirname(packageJson)), 'package.json'));\n }\n } catch {\n // unreadable/broken link - keep walking up\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * Synchronously load the native HTTP engine, trying '@morojs/engine' first and\n * falling back to a user-installed 'uWebSockets.js'. Loading is require-based\n * (both packages are CJS at their core - .node addon loading is require-based),\n * so the instance is shared with any later import() via the CJS module cache.\n *\n * The default call is memoized: the engine either loads once per process or it\n * doesn't. Failure details are retained for logging via\n * getNativeEngineLoadErrors().\n *\n * @param options.candidates - Override the probed package names (testing).\n * When provided, the call bypasses the cache.\n * @returns The loaded engine and its source package, or null if none loads\n */\nexport function loadNativeEngine(options?: {\n candidates?: readonly string[];\n /** When provided, every per-attempt failure message is appended here, so a\n * candidate-override caller (which bypasses the memoized diagnostics) can\n * still report exactly WHY the engine didn't load — not just \"not installed\". */\n collectErrors?: string[];\n}): NativeEngineLoadResult | null {\n const useCache = !options?.candidates;\n if (useCache && cachedEngine !== undefined) {\n if (options?.collectErrors && !cachedEngine) {\n options.collectErrors.push(...engineLoadErrors);\n }\n return cachedEngine;\n }\n\n const candidates = options?.candidates ?? NATIVE_ENGINE_PACKAGES;\n const errors: string[] = [];\n let result: NativeEngineLoadResult | null = null;\n\n const frameworkRequire = findFrameworkAnchor();\n const userRequire = createUserRequire();\n\n for (const candidate of candidates) {\n // Moro's own engine lives in moro's dependencies (framework anchor first);\n // the legacy uWS peer dep lives in the user's node_modules (cwd first).\n const anchors =\n candidate === 'uWebSockets.js'\n ? [userRequire, frameworkRequire]\n : [frameworkRequire, userRequire];\n\n for (const anchor of anchors) {\n if (!anchor) continue;\n try {\n const module = anchor(candidate);\n // Capability check: the HTTP server needs either a uWS-style App()\n // factory or the Moro-shaped engine surface (serve()/respond()).\n // A package that loads but can't serve (e.g. a pre-M1 @morojs/engine\n // that only exposes probe()) must not shadow a usable alternative.\n const surface = module?.default || module;\n const uwsStyle = typeof surface?.App === 'function';\n const moroStyle =\n !uwsStyle &&\n typeof surface?.serve === 'function' &&\n typeof surface?.respond === 'function';\n if (!uwsStyle && !moroStyle) {\n errors.push(\n `${candidate}: loaded but provides neither App() nor serve()/respond() - not a usable HTTP engine`\n );\n continue;\n }\n let version: string | undefined;\n try {\n // May be blocked by the package's exports map - version is optional\n version = anchor(`${candidate}/package.json`)?.version;\n } catch {\n version = undefined;\n }\n result = {\n module,\n source: candidate,\n ...(version !== undefined ? { version } : {}),\n capabilities: moroStyle ? getEngineCapabilities(module) : NO_CAPABILITIES,\n };\n break;\n } catch (error) {\n const message = error instanceof Error ? error.message.split('\\n')[0] : String(error);\n errors.push(`${candidate}: ${message}`);\n }\n }\n if (result) break;\n }\n\n // Candidate-override probes (e.g. the clustering worker's uWS-only check)\n // must not clobber the diagnostics of the real default load, which\n // framework startup logging reads via getNativeEngineLoadErrors().\n if (useCache) {\n engineLoadErrors = result ? [] : [...new Set(errors)];\n cachedEngine = result;\n }\n // Hand this specific call's failure detail back to a caller that asked for it,\n // regardless of caching (so 'moro'/'uws' fallback reasons are precise).\n if (options?.collectErrors && !result) {\n options.collectErrors.push(...new Set(errors));\n }\n return result;\n}\n\n/**\n * Failure details from the most recent unsuccessful loadNativeEngine() call,\n * one entry per package/anchor attempt. Empty after a successful load.\n */\nexport function getNativeEngineLoadErrors(): readonly string[] {\n return engineLoadErrors;\n}\n\n/**\n * Clear the memoized engine load result. Testing only.\n */\nexport function resetNativeEngineLoaderForTesting(): void {\n cachedEngine = undefined;\n engineLoadErrors = [];\n}\n\n/**\n * Convert a file path to a file URL for ESM dynamic imports\n * This is required on Windows where absolute paths like C:\\path\\to\\module\n * need to be converted to file:/// URLs for dynamic import() to work\n *\n * @param filePath - The file path to convert (absolute or relative)\n * @returns A proper URL string for ESM import() that works cross-platform\n *\n * @example\n * const modulePath = 'C:\\\\Users\\\\project\\\\module.js';\n * const module = await import(filePathToImportURL(modulePath));\n */\nexport function filePathToImportURL(filePath: string): string {\n if (!filePath) {\n return filePath;\n }\n\n // If it's already a URL (starts with file:// or http(s)://), return as-is\n if (\n filePath.startsWith('file://') ||\n filePath.startsWith('http://') ||\n filePath.startsWith('https://')\n ) {\n return filePath;\n }\n\n // Check if it's a Windows absolute path (C:\\ or C:/)\n const windowsAbsolutePathRegex = /^[A-Za-z]:[\\\\//]/;\n const isWindowsAbsolute = windowsAbsolutePathRegex.test(filePath);\n\n // Check if it's a Unix absolute path (starts with /)\n const isUnixAbsolute = filePath.startsWith('/');\n\n // Check if it's a Windows UNC path (\\\\server\\share)\n const isWindowsUNC = filePath.startsWith('\\\\\\\\');\n\n // Convert absolute paths to file URLs\n if (isWindowsAbsolute || isUnixAbsolute || isWindowsUNC) {\n return pathToFileURL(filePath).href;\n }\n\n // For relative paths, return as-is (they work in import())\n return filePath;\n}\n"]}
1
+ {"version":3,"file":"package-utils.js","sourceRoot":"","sources":["../../../src/core/utilities/package-utils.ts"],"names":[],"mappings":"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","sourcesContent":["// Package and Module Resolution Utilities\n// ESM-compatible helpers for detecting and resolving optional dependencies\n\nimport { createRequire } from 'module';\nimport { dirname, join } from 'path';\nimport { existsSync, realpathSync } from 'fs';\nimport { pathToFileURL } from 'url';\nimport { selfRequire } from './self-require.js';\n\n/**\n * Check if a package is available in the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to check (e.g., 'socket.io', 'zod')\n * @returns true if the package is installed, false otherwise\n *\n * @example\n * if (isPackageAvailable('socket.io')) {\n * // socket.io is installed, safe to import\n * const { Server } = await import('socket.io');\n * }\n */\nexport function isPackageAvailable(packageName: string): boolean {\n try {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n userRequire.resolve(packageName);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve a package path from the user's node_modules\n * Uses ESM-compatible module resolution from the user's working directory\n *\n * @param packageName - The name of the package to resolve\n * @returns The resolved package path\n * @throws Error if the package is not found\n *\n * @example\n * const socketIOPath = resolveUserPackage('socket.io');\n * const { Server } = await import(socketIOPath);\n */\nexport function resolveUserPackage(packageName: string): string {\n const userRequire = createRequire(join(process.cwd(), 'package.json'));\n return userRequire.resolve(packageName);\n}\n\n/**\n * Create a require function for the user's working directory\n * Useful for resolving packages installed by the user, not in Moro's dependencies\n *\n * @returns A require function scoped to the user's working directory\n *\n * @example\n * const userRequire = createUserRequire();\n * const packagePath = userRequire.resolve('some-package');\n */\nexport function createUserRequire() {\n return createRequire(join(process.cwd(), 'package.json'));\n}\n\n// ---------------------------------------------------------------------------\n// Native HTTP engine loading\n// ---------------------------------------------------------------------------\n\n/**\n * Package names probed for the native HTTP engine, in priority order.\n * '@morojs/engine' is Moro's own engine (installed as an optionalDependency of\n * the framework); 'uWebSockets.js' is honored as a legacy user-installed peer.\n */\nexport const NATIVE_ENGINE_PACKAGES = ['@morojs/engine', 'uWebSockets.js'] as const;\n\nconst FRAMEWORK_PACKAGE_NAME = '@morojs/moro';\n\n/** Feature flags the framework gates option-passing on, so it never hands a\n * serve() option to an engine build that predates it. Everything defaults\n * false, so an older engine behaves exactly as it did before these existed. */\nexport interface EngineCapabilities {\n /** The full serve() limit surface is parsed (engine >= 1.1.0). */\n limits: boolean;\n /** In-process TLS termination via options.ssl (engine >= 1.1.x). */\n tls: boolean;\n /** ALPN HTTP/2 via options.http2 (reserved). */\n http2: boolean;\n /** WebSocket permessage-deflate via options.wsDeflate. */\n wsDeflate: boolean;\n /** responseTimeoutMs / responseBackpressureLimit / maxUriSize are parsed. */\n responseLimits: boolean;\n /** ssl.ciphers / ssl.ciphersuites / ssl.ecdhCurve are parsed. */\n tlsPolicy: boolean;\n /** updateSsl(serverId, ssl) exists: certificate rotation without a restart\n * (engine >= 1.1.8). Gates app.reloadTLS() on the engine. */\n tlsReload: boolean;\n /** setStaticRoute()/clearStaticRoutes() exist. Used for a literal body\n * given to the route builder's .handler() when the route has nothing\n * else configured, because a static route bypasses middleware, hooks,\n * auth and validation by design. */\n staticRoutes: boolean;\n /** prepareResponse()/respondPrepared()/respondPreparedEmpty()/endWith()\n * exist (engine >= 1.1.6): the adapter replays prepared header blocks for\n * the responses it emits itself. */\n responseTemplates: boolean;\n /** onAborted/onWritable are delivered on a later loop turn, never from\n * inside respond()/write()/end() (engine >= 1.1.6). */\n asyncNotify: boolean;\n /** A server left open at environment teardown is closed by the engine's\n * cleanup hook, so the engine may run inside worker threads that can be\n * terminate()d (engine >= 1.1.6). Gates thread-based clustering. */\n workerThreads: boolean;\n /** V8 fast API calls are installed on the hot entry points (informational). */\n fastCalls: boolean;\n /** Batched pipelined dispatch (onRequestBatch / getBatchBuffers / getPath). */\n batchDispatch: boolean;\n /** Every callback into JS runs inside a Node callback scope, so nextTicks\n * and microtasks queued during dispatch run when the callback returns;\n * the adapter then needs no drain of its own (engine > 1.1.6). */\n callbackScope: boolean;\n /** setParamRoute()/clearParamRoutes() exist (engine >= 1.1.9): a route\n * with one variable path segment, echoed as the body, answered inside the\n * engine. Used for param(name) handlers on bare routes. */\n paramRoutes: boolean;\n /** setWsAutoUpgrade()/wsGetHeaders()/wsGetQuery()/wsGetRemoteAddress()\n * exist (engine >= 1.1.15): the engine answers a valid WebSocket\n * handshake itself and fires onWsOpen, so an upgrade never round-trips\n * through onRequest; the handshake stays readable on the socket. */\n wsAutoUpgrade: boolean;\n /** I/O transport in use ('epoll', 'uv', 'uring'), when the engine reports it. */\n transport?: string;\n}\n\n// One place to name every boolean flag: getEngineCapabilities coerces each\n// with `=== true`, and NO_CAPABILITIES is derived from the same list, so a\n// flag added here can never be read on one path and forgotten on the other.\nconst CAP_KEYS = [\n 'limits',\n 'tls',\n 'http2',\n 'wsDeflate',\n 'responseLimits',\n 'tlsPolicy',\n 'tlsReload',\n 'staticRoutes',\n 'responseTemplates',\n 'asyncNotify',\n 'workerThreads',\n 'fastCalls',\n 'callbackScope',\n 'batchDispatch',\n 'paramRoutes',\n 'wsAutoUpgrade',\n] as const;\n\nexport interface NativeEngineLoadResult {\n /** The loaded engine module (CJS namespace: App, SSLApp, ...) */\n module: any;\n /** Which package satisfied the load */\n source: string;\n /** The engine package's version, when its package.json is resolvable */\n version?: string;\n /** Feature flags (Moro-shaped engine only; all-false for uWS or an\n * engine too old to advertise them). */\n capabilities?: EngineCapabilities;\n}\n\nconst NO_CAPABILITIES: EngineCapabilities = Object.freeze(\n Object.fromEntries(CAP_KEYS.map(k => [k, false]))\n) as unknown as EngineCapabilities;\n\nconst capabilitiesCache = new WeakMap<object, EngineCapabilities>();\n\n/**\n * Feature-detect a loaded engine module. Reads probe().capabilities when the\n * engine exposes it (>= 1.1.0); otherwise everything is false so the framework\n * passes only the options an older engine understood. uWS-style modules (no\n * probe/serve) report all-false — their SSL/limits go through the uWS-specific\n * paths, not these flags.\n */\nexport function getEngineCapabilities(module: any): EngineCapabilities {\n const surface = module?.default || module;\n if (!surface || typeof surface !== 'object') return NO_CAPABILITIES;\n const cached = capabilitiesCache.get(surface);\n if (cached) return cached;\n\n let caps: EngineCapabilities = NO_CAPABILITIES;\n try {\n if (typeof surface.probe === 'function') {\n const probe = surface.probe();\n const c = probe?.capabilities;\n if (c && typeof c === 'object') {\n const next: Record<string, boolean | string> = {};\n for (const key of CAP_KEYS) next[key] = c[key] === true;\n if (typeof probe.transport === 'string') next.transport = probe.transport;\n caps = next as unknown as EngineCapabilities;\n }\n }\n } catch {\n caps = NO_CAPABILITIES;\n }\n capabilitiesCache.set(surface, caps);\n return caps;\n}\n\n// undefined = never attempted, null = attempted and failed\nlet cachedEngine: NativeEngineLoadResult | null | undefined;\nlet engineLoadErrors: string[] = [];\n\n/**\n * Locate the installed framework package directory so the engine (a dependency\n * of moro, not of the user's app) resolves under strict layouts like pnpm's.\n * Walks up from cwd looking for node_modules/@morojs/moro, resolving symlinks\n * so pnpm's store-linked layout anchors requires next to moro's own deps.\n * Inside the framework repo itself (tests, examples) cwd is the framework dir.\n */\nfunction findFrameworkAnchor(): ReturnType<typeof createRequire> | null {\n // Primary: anchor to moro's OWN compiled location, so moro's `@morojs/engine`\n // dependency resolves relative to where moro is installed regardless of\n // `process.cwd()` (Docker WORKDIR, supervisord, pm2, a subdirectory, …). The\n // cwd-based walk below is a defensive fallback for exotic layouts.\n if (selfRequire) return selfRequire;\n\n try {\n const cwdPackageJson = join(process.cwd(), 'package.json');\n if (existsSync(cwdPackageJson)) {\n const require = createRequire(cwdPackageJson);\n const name = require(cwdPackageJson)?.name;\n if (name === FRAMEWORK_PACKAGE_NAME) {\n return require;\n }\n }\n } catch {\n // fall through to the node_modules walk\n }\n\n let dir = process.cwd();\n for (;;) {\n const packageJson = join(dir, 'node_modules', '@morojs', 'moro', 'package.json');\n try {\n if (existsSync(packageJson)) {\n return createRequire(join(realpathSync(dirname(packageJson)), 'package.json'));\n }\n } catch {\n // unreadable/broken link - keep walking up\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\n/**\n * Synchronously load the native HTTP engine, trying '@morojs/engine' first and\n * falling back to a user-installed 'uWebSockets.js'. Loading is require-based\n * (both packages are CJS at their core - .node addon loading is require-based),\n * so the instance is shared with any later import() via the CJS module cache.\n *\n * The default call is memoized: the engine either loads once per process or it\n * doesn't. Failure details are retained for logging via\n * getNativeEngineLoadErrors().\n *\n * @param options.candidates - Override the probed package names (testing).\n * When provided, the call bypasses the cache.\n * @returns The loaded engine and its source package, or null if none loads\n */\nexport function loadNativeEngine(options?: {\n candidates?: readonly string[];\n /** When provided, every per-attempt failure message is appended here, so a\n * candidate-override caller (which bypasses the memoized diagnostics) can\n * still report exactly WHY the engine didn't load — not just \"not installed\". */\n collectErrors?: string[];\n}): NativeEngineLoadResult | null {\n const useCache = !options?.candidates;\n if (useCache && cachedEngine !== undefined) {\n if (options?.collectErrors && !cachedEngine) {\n options.collectErrors.push(...engineLoadErrors);\n }\n return cachedEngine;\n }\n\n const candidates = options?.candidates ?? NATIVE_ENGINE_PACKAGES;\n const errors: string[] = [];\n let result: NativeEngineLoadResult | null = null;\n\n const frameworkRequire = findFrameworkAnchor();\n const userRequire = createUserRequire();\n\n for (const candidate of candidates) {\n // Moro's own engine lives in moro's dependencies (framework anchor first);\n // the legacy uWS peer dep lives in the user's node_modules (cwd first).\n const anchors =\n candidate === 'uWebSockets.js'\n ? [userRequire, frameworkRequire]\n : [frameworkRequire, userRequire];\n\n for (const anchor of anchors) {\n if (!anchor) continue;\n try {\n const module = anchor(candidate);\n // Capability check: the HTTP server needs either a uWS-style App()\n // factory or the Moro-shaped engine surface (serve()/respond()).\n // A package that loads but can't serve (e.g. a pre-M1 @morojs/engine\n // that only exposes probe()) must not shadow a usable alternative.\n const surface = module?.default || module;\n const uwsStyle = typeof surface?.App === 'function';\n const moroStyle =\n !uwsStyle &&\n typeof surface?.serve === 'function' &&\n typeof surface?.respond === 'function';\n if (!uwsStyle && !moroStyle) {\n errors.push(\n `${candidate}: loaded but provides neither App() nor serve()/respond() - not a usable HTTP engine`\n );\n continue;\n }\n let version: string | undefined;\n try {\n // May be blocked by the package's exports map - version is optional\n version = anchor(`${candidate}/package.json`)?.version;\n } catch {\n version = undefined;\n }\n result = {\n module,\n source: candidate,\n ...(version !== undefined ? { version } : {}),\n capabilities: moroStyle ? getEngineCapabilities(module) : NO_CAPABILITIES,\n };\n break;\n } catch (error) {\n const message = error instanceof Error ? error.message.split('\\n')[0] : String(error);\n errors.push(`${candidate}: ${message}`);\n }\n }\n if (result) break;\n }\n\n // Candidate-override probes (e.g. the clustering worker's uWS-only check)\n // must not clobber the diagnostics of the real default load, which\n // framework startup logging reads via getNativeEngineLoadErrors().\n if (useCache) {\n engineLoadErrors = result ? [] : [...new Set(errors)];\n cachedEngine = result;\n }\n // Hand this specific call's failure detail back to a caller that asked for it,\n // regardless of caching (so 'moro'/'uws' fallback reasons are precise).\n if (options?.collectErrors && !result) {\n options.collectErrors.push(...new Set(errors));\n }\n return result;\n}\n\n/**\n * Failure details from the most recent unsuccessful loadNativeEngine() call,\n * one entry per package/anchor attempt. Empty after a successful load.\n */\nexport function getNativeEngineLoadErrors(): readonly string[] {\n return engineLoadErrors;\n}\n\n/**\n * Clear the memoized engine load result. Testing only.\n */\nexport function resetNativeEngineLoaderForTesting(): void {\n cachedEngine = undefined;\n engineLoadErrors = [];\n}\n\n/**\n * Convert a file path to a file URL for ESM dynamic imports\n * This is required on Windows where absolute paths like C:\\path\\to\\module\n * need to be converted to file:/// URLs for dynamic import() to work\n *\n * @param filePath - The file path to convert (absolute or relative)\n * @returns A proper URL string for ESM import() that works cross-platform\n *\n * @example\n * const modulePath = 'C:\\\\Users\\\\project\\\\module.js';\n * const module = await import(filePathToImportURL(modulePath));\n */\nexport function filePathToImportURL(filePath: string): string {\n if (!filePath) {\n return filePath;\n }\n\n // If it's already a URL (starts with file:// or http(s)://), return as-is\n if (\n filePath.startsWith('file://') ||\n filePath.startsWith('http://') ||\n filePath.startsWith('https://')\n ) {\n return filePath;\n }\n\n // Check if it's a Windows absolute path (C:\\ or C:/)\n const windowsAbsolutePathRegex = /^[A-Za-z]:[\\\\//]/;\n const isWindowsAbsolute = windowsAbsolutePathRegex.test(filePath);\n\n // Check if it's a Unix absolute path (starts with /)\n const isUnixAbsolute = filePath.startsWith('/');\n\n // Check if it's a Windows UNC path (\\\\server\\share)\n const isWindowsUNC = filePath.startsWith('\\\\\\\\');\n\n // Convert absolute paths to file URLs\n if (isWindowsAbsolute || isUnixAbsolute || isWindowsUNC) {\n return pathToFileURL(filePath).href;\n }\n\n // For relative paths, return as-is (they work in import())\n return filePath;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morojs/moro",
3
- "version": "1.8.16",
3
+ "version": "1.8.17",
4
4
  "description": "High-performance Node.js framework with intelligent routing, automatic middleware ordering, enterprise authentication (Better Auth), type-safe validation, and functional architecture",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",