@rlanz/socket 0.0.1-6 → 0.0.1-8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +186 -147
- package/build/{types-DiYaFvgi.d.ts → base_channel-DPOnqned.d.ts} +185 -171
- package/build/chunk-6PJ4ALJD.js +115 -0
- package/build/chunk-6PJ4ALJD.js.map +1 -0
- package/build/chunk-E6ILCRL3.js +182 -0
- package/build/chunk-E6ILCRL3.js.map +1 -0
- package/build/{chunk-SHH6U4CI.js → chunk-G75J233Z.js} +1 -1
- package/build/chunk-G75J233Z.js.map +1 -0
- package/build/{chunk-B4Y3TNDI.js → chunk-IUQ3GYZZ.js} +5 -24
- package/build/chunk-IUQ3GYZZ.js.map +1 -0
- package/build/chunk-K243S3QP.js +131 -0
- package/build/chunk-K243S3QP.js.map +1 -0
- package/build/chunk-QNOOQXYY.js +899 -0
- package/build/chunk-QNOOQXYY.js.map +1 -0
- package/build/{chunk-FVPY6HZW.js → chunk-YVC7IMDN.js} +21 -5
- package/build/chunk-YVC7IMDN.js.map +1 -0
- package/build/framework-B8pJ4cCA.d.ts +13 -0
- package/build/index-DjBYUhFR.d.ts +150 -0
- package/build/index.d.ts +23 -12
- package/build/index.js +12 -14
- package/build/index.js.map +1 -1
- package/build/providers/socket_provider.d.ts +2 -2
- package/build/providers/socket_provider.js +478 -215
- package/build/providers/socket_provider.js.map +1 -1
- package/build/services/socket.d.ts +2 -2
- package/build/{socket_service-D3jKrleE.d.ts → socket_service-BcC9ASCE.d.ts} +8 -7
- package/build/src/assembler_hook.js +33 -59
- package/build/src/assembler_hook.js.map +1 -1
- package/build/src/client/index.d.ts +3 -147
- package/build/src/client/index.js +4 -837
- package/build/src/client/index.js.map +1 -1
- package/build/src/client/react.d.ts +13 -5
- package/build/src/client/react.js +27 -11
- package/build/src/client/react.js.map +1 -1
- package/build/src/client/types.d.ts +30 -36
- package/build/src/client/vue.d.ts +17 -6
- package/build/src/client/vue.js +31 -13
- package/build/src/client/vue.js.map +1 -1
- package/build/src/decorators.d.ts +3 -2
- package/build/src/decorators.js +1 -1
- package/build/src/health_check.d.ts +2 -2
- package/build/src/health_check.js +14 -3
- package/build/src/health_check.js.map +1 -1
- package/build/src/otel.js +0 -1
- package/build/src/otel.js.map +1 -1
- package/build/src/testing.d.ts +3 -12
- package/build/src/testing.js +1 -1
- package/build/src/types/tracing_channels.d.ts +1 -2
- package/build/src/types.d.ts +1 -1
- package/package.json +3 -9
- package/build/chunk-B4Y3TNDI.js.map +0 -1
- package/build/chunk-FVPY6HZW.js.map +0 -1
- package/build/chunk-HK7Z65DA.js +0 -19
- package/build/chunk-HK7Z65DA.js.map +0 -1
- package/build/chunk-SFAY2ZA4.js +0 -28
- package/build/chunk-SFAY2ZA4.js.map +0 -1
- package/build/chunk-SHH6U4CI.js.map +0 -1
- package/build/chunk-YAX5EHHB.js +0 -453
- package/build/chunk-YAX5EHHB.js.map +0 -1
- package/build/framework-DuW6zpPk.d.ts +0 -14
- package/build/src/client/svelte.d.ts +0 -23
- package/build/src/client/svelte.js +0 -82
- package/build/src/client/svelte.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../providers/socket_provider.ts","../../src/socket_service.ts","../../src/channel_subscription_storage.ts","../../src/channel_subscriptions.ts","../../src/protocol/reply.ts","../../src/protocol/message.ts","../../src/message_queue.ts","../../src/broadcasting.ts","../../src/socket_bus.ts","../../src/duration.ts","../../src/socket_upgrader.ts"],"sourcesContent":["import type { ApplicationService } from '@adonisjs/core/types'\nimport type { HttpContext, Server as AdonisServer } from '@adonisjs/core/http'\nimport type { Logger } from '@adonisjs/logger'\nimport type { MiddlewareAsClass } from '@adonisjs/core/types/http'\nimport { ServerResponse } from 'node:http'\nimport { SocketService } from '../src/socket_service.js'\nimport { ChannelRouter } from '../src/channel_router.js'\nimport { BaseChannel } from '../src/base_channel.js'\nimport { PresenceManager } from '../src/presence_manager.js'\nimport type { SocketUpgradeContextRunner } from '../src/socket_upgrader.js'\nimport type { SocketConfig, SocketHttpMiddleware } from '../src/types.js'\n\ndeclare module '@adonisjs/core/types' {\n interface ContainerBindings {\n 'socket': SocketService\n 'socket.router': ChannelRouter\n 'socket.presence': PresenceManager\n }\n}\n\nexport default class SocketProvider {\n constructor(protected app: ApplicationService) {}\n\n /**\n * Registers the bindings in the container.\n */\n register(): void {\n this.app.container.singleton('socket.router', () => {\n return new ChannelRouter()\n })\n\n this.app.container.singleton('socket.presence', () => {\n return new PresenceManager()\n })\n\n this.app.container.singleton('socket', () => {\n return new SocketService()\n })\n }\n\n /**\n * Boots the provider.\n */\n async boot(): Promise<void> {\n const router = await this.app.container.make('socket.router')\n\n // Discover and register channel classes.\n await this.#registerChannels(router)\n }\n\n /**\n * Called when the app is ready and the HTTP server is running.\n */\n async ready(): Promise<void> {\n const socket = await this.app.container.make('socket')\n const router = await this.app.container.make('socket.router')\n const presence = await this.app.container.make('socket.presence')\n const logger = await this.#resolveLogger()\n const config = this.app.config.get<SocketConfig>('socket', {})\n\n socket.setPresenceManager(presence)\n\n logger.info('router has %d channels registered', router.size)\n\n const server = await this.app.container.make('server')\n const httpServer = server.getNodeServer()\n\n if (!httpServer) {\n const error = new Error('HTTP server not available.')\n socket.markFailed(error)\n logger.warn('HTTP server not available; socket server was not started')\n return\n }\n\n try {\n await socket.boot(\n httpServer,\n config,\n router,\n logger,\n this.#createUpgradeContextRunner(config, server)\n )\n logger.info('server started')\n } catch (error) {\n socket.markFailed(error)\n throw error\n }\n }\n\n /**\n * Performs a clean shutdown.\n */\n async shutdown(): Promise<void> {\n const socket = await this.app.container.make('socket')\n await socket.close()\n }\n\n /**\n * Resolves the AdonisJS logger and creates a child logger for the socket context.\n */\n async #resolveLogger(): Promise<Logger> {\n const logger = await this.app.container.make('logger')\n return logger.child({ module: 'socket' })\n }\n\n /**\n * Creates an AdonisJS HTTP context for WebSocket upgrade requests.\n */\n #createUpgradeContextRunner(\n config: SocketConfig,\n server: AdonisServer\n ): SocketUpgradeContextRunner {\n const middleware = config.websocket?.middleware ?? []\n\n return async (request, handler) => {\n const response = new ServerResponse(request)\n const adonisRequest = server.createRequest(request, response)\n const adonisResponse = server.createResponse(request, response)\n const httpContext = server.createHttpContext(\n adonisRequest,\n adonisResponse,\n this.app.container.createResolver()\n )\n\n return this.#runUpgradeMiddleware(server, middleware, httpContext, handler)\n }\n }\n\n /**\n * Runs middleware attached to WebSocket upgrade requests.\n */\n async #runUpgradeMiddleware<Result>(\n server: AdonisServer,\n middleware: NonNullable<NonNullable<SocketConfig['websocket']>['middleware']>,\n httpContext: HttpContext,\n handler: (httpContext: HttpContext) => Promise<Result>\n ): Promise<Result> {\n if (middleware.length === 0) {\n return handler(httpContext)\n }\n\n const middlewareClasses: MiddlewareAsClass[] = await Promise.all(\n middleware.map(async (one): Promise<MiddlewareAsClass> => {\n if (one.prototype?.handle) {\n return one as MiddlewareAsClass\n }\n\n const moduleExports = await (one as Exclude<SocketHttpMiddleware, MiddlewareAsClass>)()\n return moduleExports.default\n })\n )\n\n let outcome: { value: Result } | undefined\n\n await server\n .pipeline(middlewareClasses)\n .errorHandler((error) => {\n throw error\n })\n .finalHandler(async () => {\n outcome = { value: await handler(httpContext) }\n })\n .run(httpContext)\n\n if (!outcome) {\n throw new Error('WebSocket upgrade middleware must call next()')\n }\n\n return outcome.value\n }\n\n /**\n * Scans and registers channel classes.\n */\n async #registerChannels(router: ChannelRouter): Promise<void> {\n const logger = await this.#resolveLogger()\n const config = this.app.config.get<SocketConfig>('socket', {})\n const legacyChannels = (config as SocketConfig & { channels?: { patterns?: string[] } })\n .channels\n if (legacyChannels?.patterns) {\n throw new Error(\n 'Socket channel patterns are managed by the Assembler hook and cannot be configured at runtime'\n )\n }\n\n let generated: { socketChannels?: unknown }\n try {\n generated = await this.app.import('#generated/socket_channels')\n } catch (error) {\n throw new Error('Failed to load generated socket channels', { cause: error })\n }\n\n if (!Array.isArray(generated.socketChannels)) {\n throw new Error('Generated socket channel manifest must export a socketChannels array')\n }\n\n for (const [index, channelClass] of generated.socketChannels.entries()) {\n const source = `generated channel at index ${index}`\n if (\n typeof channelClass !== 'function' ||\n !(channelClass.prototype instanceof BaseChannel) ||\n !channelClass.pattern\n ) {\n throw new Error(`Socket channel ${source} must default export a BaseChannel with a pattern`)\n }\n\n try {\n router.register(channelClass)\n } catch (error) {\n throw new Error(`Failed to register socket channel from ${source}`, { cause: error })\n }\n\n logger.info('registered channel: %s', channelClass.pattern)\n }\n\n logger.info('total channels registered: %d', router.size)\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IncomingMessage } from 'node:http'\nimport type { Server as HttpServer } from 'node:http'\nimport type { Logger } from '@adonisjs/logger'\nimport Emittery from 'emittery'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport type { RawData } from 'ws'\nimport type {\n AuthenticatedSocket,\n SocketConfig,\n SocketEvents,\n ChannelAck,\n RawSocket,\n SocketHealthSnapshot,\n SocketServiceStatus,\n} from './types.js'\nimport type { SocketUpgradeContextRunner } from './socket_upgrader.js'\nimport type { ChannelMessage, ServerProtocolMessage } from './shared_types.js'\nimport type { ChannelRouter } from './channel_router.js'\nimport { PRESENCE_DATA_KEY, type PresenceManager, type PresenceSocket } from './presence_manager.js'\nimport { ChannelSubscriptions, type ChannelSubscriptionLimits } from './channel_subscriptions.js'\nimport { Message, type TransportMessage } from './protocol/message.js'\nimport { MessageQueue } from './message_queue.js'\nimport { Reply } from './protocol/reply.js'\nimport { userRoom, type SocketEmission, type SocketEmissionSink } from './broadcasting.js'\nimport { SocketFake } from './fake_socket.js'\nimport { SocketBus, type SerializablePresenceSocket } from './socket_bus.js'\nimport {\n SocketUpgrader,\n type AcceptedUpgrade,\n type SocketUpgradeHandler,\n} from './socket_upgrader.js'\nimport { parseDuration, type Duration } from './duration.js'\nimport { SocketResponseError } from './base_channel.js'\nimport {\n broadcastChannel,\n channelMessageChannel,\n connectChannel,\n disconnectChannel,\n subscribeChannel,\n unsubscribeChannel,\n} from './tracing_channels.js'\nimport type {\n SocketBroadcastMessage,\n SocketChannelMessage,\n SocketSubscribeMessage,\n SocketUnsubscribeMessage,\n} from './types/tracing_channels.js'\n\nconst DEFAULT_PING_INTERVAL = 25_000\nconst DEFAULT_PING_TIMEOUT = 5_000\nconst DEFAULT_MAX_PAYLOAD = 1024 * 1024\nconst DEFAULT_MAX_QUEUED_MESSAGES = 100\nconst DEFAULT_MAX_MESSAGES_PER_INTERVAL = 1000\nconst DEFAULT_MESSAGE_RATE_INTERVAL = 1000\nconst DEFAULT_MAX_BUFFERED_AMOUNT = 16 * 1024 * 1024\nconst DEFAULT_MAX_OUTBOUND_PAYLOAD = 1024 * 1024\nconst DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET = 100\nconst DEFAULT_MAX_CHANNEL_NAME_LENGTH = 255\nconst CLOSE_POLICY_VIOLATION = 1008\nconst CLOSE_MESSAGE_TOO_BIG = 1009\nconst CLOSE_OUTBOUND_BUFFER_LIMIT = 'Socket outbound buffer limit exceeded'\nconst CLOSE_OUTBOUND_MESSAGE_TOO_BIG = 'Socket outbound message too big'\n\ninterface InboundMessageConfig {\n maxPayload: number\n maxQueuedMessages: number\n maxMessagesPerInterval: number\n messageRateInterval: number\n subscriptionLimits: ChannelSubscriptionLimits\n}\n\ninterface OutboundMessageConfig {\n maxBufferedAmount: number\n maxOutboundPayload: number\n}\n\ninterface SocketMessageRate {\n count: number\n intervalStartedAt: number\n}\n\nfunction serializeFrame(frame: ServerProtocolMessage): string {\n return JSON.stringify(frame)\n}\n\nfunction sendFrame(\n connection: WebSocket,\n frame: ServerProtocolMessage,\n config: OutboundMessageConfig\n): boolean {\n const serializedFrame = serializeFrame(frame)\n return sendSerializedFrameWithBackpressure(connection, serializedFrame, config)\n}\n\nfunction sendSerializedFrameWithBackpressure(\n connection: WebSocket,\n serializedFrame: string,\n config: OutboundMessageConfig\n): boolean {\n if (connection.readyState !== WebSocket.OPEN) {\n return false\n }\n\n const payloadSize = Buffer.byteLength(serializedFrame)\n if (payloadSize > config.maxOutboundPayload) {\n closeConnection(connection, CLOSE_MESSAGE_TOO_BIG, CLOSE_OUTBOUND_MESSAGE_TOO_BIG)\n return false\n }\n\n if (connection.bufferedAmount + payloadSize > config.maxBufferedAmount) {\n closeConnection(connection, CLOSE_POLICY_VIOLATION, CLOSE_OUTBOUND_BUFFER_LIMIT)\n return false\n }\n\n connection.send(serializedFrame)\n return true\n}\n\nfunction parsePositiveInteger(name: string, value: number | undefined, fallback: number): number {\n if (value === undefined) {\n return fallback\n }\n\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(`${name} must be a positive integer`)\n }\n\n return value\n}\n\nfunction resolveHeartbeatConfig(\n config: { pingInterval?: Duration; pingTimeout?: Duration } | undefined\n): { interval: number; timeout: number } | null {\n const pingInterval = parseDuration('websocket.pingInterval', config?.pingInterval)\n const pingTimeout = parseDuration('websocket.pingTimeout', config?.pingTimeout)\n\n if (pingInterval === undefined && pingTimeout === undefined) {\n return null\n }\n\n return {\n interval: pingInterval ?? DEFAULT_PING_INTERVAL,\n timeout: pingTimeout ?? DEFAULT_PING_TIMEOUT,\n }\n}\n\nfunction resolveInboundMessageConfig(\n config:\n | {\n maxPayload?: number\n maxQueuedMessages?: number\n maxMessagesPerInterval?: number\n messageRateInterval?: Duration\n maxSubscriptionsPerSocket?: number\n maxChannelNameLength?: number\n }\n | undefined\n): InboundMessageConfig {\n const messageRateInterval =\n parseDuration('websocket.messageRateInterval', config?.messageRateInterval) ??\n DEFAULT_MESSAGE_RATE_INTERVAL\n\n return {\n maxPayload: parsePositiveInteger(\n 'websocket.maxPayload',\n config?.maxPayload,\n DEFAULT_MAX_PAYLOAD\n ),\n maxQueuedMessages: parsePositiveInteger(\n 'websocket.maxQueuedMessages',\n config?.maxQueuedMessages,\n DEFAULT_MAX_QUEUED_MESSAGES\n ),\n maxMessagesPerInterval: parsePositiveInteger(\n 'websocket.maxMessagesPerInterval',\n config?.maxMessagesPerInterval,\n DEFAULT_MAX_MESSAGES_PER_INTERVAL\n ),\n messageRateInterval,\n subscriptionLimits: {\n maxSubscriptionsPerSocket: parsePositiveInteger(\n 'websocket.maxSubscriptionsPerSocket',\n config?.maxSubscriptionsPerSocket,\n DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET\n ),\n maxChannelNameLength: parsePositiveInteger(\n 'websocket.maxChannelNameLength',\n config?.maxChannelNameLength,\n DEFAULT_MAX_CHANNEL_NAME_LENGTH\n ),\n },\n }\n}\n\nfunction resolveOutboundMessageConfig(\n config:\n | {\n maxBufferedAmount?: number\n maxOutboundPayload?: number\n }\n | undefined\n): OutboundMessageConfig {\n return {\n maxBufferedAmount: parsePositiveInteger(\n 'websocket.maxBufferedAmount',\n config?.maxBufferedAmount,\n DEFAULT_MAX_BUFFERED_AMOUNT\n ),\n maxOutboundPayload: parsePositiveInteger(\n 'websocket.maxOutboundPayload',\n config?.maxOutboundPayload,\n DEFAULT_MAX_OUTBOUND_PAYLOAD\n ),\n }\n}\n\nfunction getRawDataByteLength(data: RawData): number {\n if (Array.isArray(data)) {\n return data.reduce((total, chunk) => total + chunk.byteLength, 0)\n }\n\n return data.byteLength\n}\n\nfunction closeConnection(connection: WebSocket, code: number, reason: string): void {\n if (connection.readyState === WebSocket.OPEN) {\n connection.close(code, reason)\n }\n}\n\n/**\n * Main service for managing WebSocket connections.\n */\nexport class SocketService<User = unknown> extends Emittery<SocketEvents<User>> {\n #server: WebSocketServer | null = null\n #httpServer: HttpServer | null = null\n #upgradeHandler: SocketUpgradeHandler | null = null\n #sockets = new Map<string, AuthenticatedSocket<User>>()\n #userRooms = new Map<string, Set<string>>()\n #socketUserRoom = new Map<string, string>()\n #channelSubscriptions: ChannelSubscriptions<User> | null = null\n #presenceManager: PresenceManager | null = null\n #bus: SocketBus | null = null\n #fake: SocketFake | null = null\n #deliverySink: SocketEmissionSink = {\n dispatch: (emission) => {\n this.#deliverBroadcast(emission)\n },\n }\n #broadcastSink: SocketEmissionSink = this.#deliverySink\n #status: SocketServiceStatus = 'stopped'\n #lastError: Error | null = null\n #heartbeatInterval: ReturnType<typeof setInterval> | null = null\n #heartbeatTimeouts = new Map<string, ReturnType<typeof setTimeout>>()\n #messageQueue = new MessageQueue()\n #messageRates = new Map<string, SocketMessageRate>()\n #socketFinalizations = new Map<string, Promise<void>>()\n #closePromise: Promise<void> | null = null\n #outboundMessageConfig = resolveOutboundMessageConfig(undefined)\n #logger: Logger | null = null\n\n /**\n * Accesses the underlying ws server.\n */\n get server(): WebSocketServer {\n if (!this.#server) {\n throw new Error('WebSocket server is not initialized. Call boot() first.')\n }\n\n return this.#server\n }\n\n setPresenceManager(presenceManager: PresenceManager): void {\n this.#presenceManager = presenceManager\n this.#channelSubscriptions?.setPresenceManager(presenceManager)\n this.#configurePresenceFetcher()\n }\n\n async boot(\n httpServer: HttpServer,\n config: SocketConfig<User>,\n channelRouter: ChannelRouter,\n logger: Logger,\n runWithHttpContext: SocketUpgradeContextRunner\n ): Promise<void> {\n this.#closePromise = null\n this.#status = 'starting'\n this.#lastError = null\n this.#logger = logger\n\n const websocketConfig = config.websocket\n const heartbeatConfig = resolveHeartbeatConfig(websocketConfig)\n const inboundMessageConfig = resolveInboundMessageConfig(websocketConfig)\n this.#outboundMessageConfig = resolveOutboundMessageConfig(websocketConfig)\n\n this.#channelSubscriptions = new ChannelSubscriptions(\n this,\n channelRouter,\n logger,\n this.#presenceManager ?? undefined,\n inboundMessageConfig.subscriptionLimits\n )\n\n try {\n if (config.transport) {\n this.#bus = new SocketBus(config.transport, {\n channel: (message) => {\n this.#traceBroadcast(\n {\n target: 'channel',\n channel: message.channel,\n event: message.event,\n via: 'bus',\n except: message.except,\n },\n () =>\n this.#emitToChannelLocally(\n message.channel,\n message.event,\n message.data,\n message.except\n )\n )\n },\n user: (message) => {\n this.#traceBroadcast(\n { target: 'user', room: message.room, event: message.event, via: 'bus' },\n () => this.#emitToUserRoomLocally(message.room, message.event, message.data)\n )\n },\n broadcast: (message) => {\n this.#traceBroadcast({ target: 'global', event: message.event, via: 'bus' }, () =>\n this.#broadcastLocally(message.event, message.data)\n )\n },\n presenceSockets: (channel) => {\n return this.#getLocalPresenceSockets(channel)\n },\n })\n\n await this.#bus.start()\n this.#configurePresenceFetcher()\n }\n\n const websocketServer = new WebSocketServer({\n noServer: true,\n maxPayload: inboundMessageConfig.maxPayload,\n })\n\n this.#server = websocketServer\n this.#httpServer = httpServer\n const upgrader = new SocketUpgrader<User>(\n websocketServer,\n websocketConfig,\n runWithHttpContext,\n (message, error) => this.#warn(message, error)\n )\n\n this.#upgradeHandler = (request, socket, head) => {\n upgrader\n .handle(request, socket, head, (connection, upgradeRequest, accepted) => {\n this.#handleConnection(connection, upgradeRequest, accepted, inboundMessageConfig)\n })\n .catch((error) => {\n this.#warn('failed to upgrade socket connection: %s', error)\n SocketUpgrader.reject(socket, 500, 'Internal Server Error')\n })\n }\n httpServer.on('upgrade', this.#upgradeHandler)\n\n this.#startHeartbeat(heartbeatConfig)\n this.#status = 'ready'\n } catch (error) {\n this.#lastError = error instanceof Error ? error : new Error('Socket service boot failed')\n this.#status = 'failed'\n await this.close()\n throw error\n }\n }\n\n #handleConnection(\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User>,\n inboundMessageConfig: InboundMessageConfig\n ): void {\n if (this.#status !== 'ready') {\n connection.terminate()\n return\n }\n\n const socket = this.#wrapSocket(connection, request, upgrade)\n\n connectChannel.traceSync(\n () => {\n this.#sockets.set(socket.id, socket)\n this.#emitLifecycleEvent('connect', { socket })\n },\n { socketId: socket.id }\n )\n\n connection.on('error', () => {})\n\n connection.on('message', (data) => {\n if (getRawDataByteLength(data) > inboundMessageConfig.maxPayload) {\n closeConnection(connection, CLOSE_MESSAGE_TOO_BIG, 'Message too big')\n return\n }\n\n if (!this.#acceptMessageRate(socket.id, inboundMessageConfig)) {\n closeConnection(connection, CLOSE_POLICY_VIOLATION, 'Socket message rate limit exceeded')\n return\n }\n\n const message = Message.fromTransport(data.toString())\n\n if (message.type === 'ping') {\n sendFrame(\n socket.raw.connection,\n { id: message.id, type: 'pong' },\n this.#outboundMessageConfig\n )\n return\n }\n\n const enqueued = this.#messageQueue.enqueue(\n socket.id,\n async () => {\n await this.#handleMessage(socket, message).catch((error) => {\n try {\n this.#logger?.warn('unexpected socket message failure: %s', error)\n } catch {\n // Logging must never prevent a protocol response.\n }\n\n sendFrame(\n connection,\n message.id === undefined\n ? { type: 'error', error: 'Unexpected socket error' }\n : Reply.error(message.id, 'Unexpected socket error').toFrame(),\n this.#outboundMessageConfig\n )\n })\n },\n { maxDepth: inboundMessageConfig.maxQueuedMessages }\n )\n\n if (!enqueued) {\n closeConnection(connection, CLOSE_POLICY_VIOLATION, 'Socket message queue limit exceeded')\n }\n })\n\n connection.on('pong', () => {\n this.#clearHeartbeatTimeout(socket.id)\n })\n\n connection.on('close', () => {\n void Promise.resolve()\n .then(() => this.#finalizeSocket(socket))\n .catch((error) => this.markFailed(error))\n })\n }\n\n #finalizeSocket(socket: AuthenticatedSocket<User>): Promise<void> {\n const pending = this.#socketFinalizations.get(socket.id)\n if (pending) {\n return pending\n }\n\n if (!this.#sockets.has(socket.id)) {\n return Promise.resolve()\n }\n\n const finalization = disconnectChannel\n .tracePromise(\n async () => {\n this.#clearHeartbeatTimeout(socket.id)\n this.#messageRates.delete(socket.id)\n await this.#messageQueue.drain(socket.id)\n this.#messageQueue.delete(socket.id)\n await this.#channelSubscriptions?.leaveAll(socket)\n this.#channelSubscriptions?.deleteSocket(socket.id)\n this.#sockets.delete(socket.id)\n this.#leaveUserRoom(socket.id)\n this.#emitLifecycleEvent('disconnect', { socket, reason: 'close' })\n },\n {\n socketId: socket.id,\n reason: 'close',\n subscriptions: this.#channelSubscriptions?.subscriptionCountFor(socket.id) ?? 0,\n }\n )\n .finally(() => {\n this.#socketFinalizations.delete(socket.id)\n })\n\n this.#socketFinalizations.set(socket.id, finalization)\n return finalization\n }\n\n async #handleMessage(\n socket: AuthenticatedSocket<User>,\n message: TransportMessage\n ): Promise<void> {\n if (!message.valid) {\n sendFrame(socket.raw.connection, message.toRejectionFrame(), this.#outboundMessageConfig)\n return\n }\n\n switch (message.type) {\n case 'ping':\n return\n case 'subscribe': {\n const traceMessage: SocketSubscribeMessage = {\n socketId: socket.id,\n channel: message.channel,\n }\n\n await subscribeChannel.tracePromise(async () => {\n const result = await this.#channelSubscriptions?.subscribe(socket, message.channel)\n\n traceMessage.created = result?.created ?? false\n traceMessage.ok = result?.ack.ok ?? false\n if (!result?.ack.ok) {\n traceMessage.error = result?.ack.error ?? 'Socket service is not initialized'\n }\n\n if (result?.created) {\n this.#emitLifecycleEvent('subscribe', { socket, channel: message.channel })\n }\n\n sendFrame(\n socket.raw.connection,\n Reply.fromSubscribeResult(message.id, result).toFrame(),\n this.#outboundMessageConfig\n )\n }, traceMessage)\n return\n }\n case 'unsubscribe': {\n const traceMessage: SocketUnsubscribeMessage = {\n socketId: socket.id,\n channel: message.channel,\n }\n\n await unsubscribeChannel.tracePromise(async () => {\n traceMessage.removed =\n (await this.#channelSubscriptions?.leave(socket, message.channel)) ?? false\n traceMessage.ok = true\n this.#emitLifecycleEvent('unsubscribe', { socket, channel: message.channel })\n sendFrame(\n socket.raw.connection,\n Reply.ok(message.id).toFrame(),\n this.#outboundMessageConfig\n )\n }, traceMessage)\n return\n }\n case 'message':\n case 'whisper': {\n await this.#handleChannelFrame(socket, message)\n return\n }\n }\n }\n\n async #handleChannelFrame(\n socket: AuthenticatedSocket<User>,\n message: Extract<TransportMessage, { type: 'message' | 'whisper' }>\n ): Promise<void> {\n const payload = message.toChannelMessage()\n const traceMessage: SocketChannelMessage = {\n socketId: socket.id,\n channel: payload.channel,\n event: payload.event,\n }\n\n await channelMessageChannel.tracePromise(async () => {\n const ack = await this.#handleChannelPayload(socket, message.type, payload)\n traceMessage.ok = ack.ok\n if (!ack.ok) {\n traceMessage.error = ack.error ?? 'Handler error'\n }\n\n sendFrame(\n socket.raw.connection,\n Reply.fromChannelAck(message.id, ack).toFrame(),\n this.#outboundMessageConfig\n )\n }, traceMessage)\n }\n\n async #handleChannelPayload(\n socket: AuthenticatedSocket<User>,\n type: 'message' | 'whisper',\n payload: ChannelMessage\n ): Promise<ChannelAck> {\n if (typeof payload.channel !== 'string' || typeof payload.event !== 'string') {\n return { ok: false, error: `Invalid channel ${type}` }\n }\n\n if (type === 'message') {\n return this.#channelSubscriptions!.handleMessage(socket, payload)\n }\n\n return this.#channelSubscriptions!.relayWhisper(socket, payload)\n }\n\n #wrapSocket(\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User>\n ): AuthenticatedSocket<User> {\n const raw: RawSocket = {\n id: randomUUID(),\n data: {},\n connection,\n request,\n httpContext: upgrade.httpContext,\n }\n\n return {\n id: raw.id,\n user: upgrade.user,\n\n getUserOrFail() {\n if (this.user === undefined) {\n throw new SocketResponseError('Unauthorized')\n }\n\n return this.user\n },\n\n emit: (event, data) => {\n this.#sendSerializedEventFrame(connection, serializeFrame({ type: 'event', event, data }))\n },\n\n joinUserRoom: (userId) => {\n this.#joinUserRoom(raw.id, userRoom(userId))\n return Promise.resolve()\n },\n\n leaveUserRoom: () => {\n this.#leaveUserRoom(raw.id)\n return Promise.resolve()\n },\n\n disconnect() {\n connection.close()\n },\n\n raw,\n }\n }\n\n #joinUserRoom(socketId: string, room: string): void {\n this.#leaveUserRoom(socketId)\n\n if (!this.#userRooms.has(room)) {\n this.#userRooms.set(room, new Set())\n }\n\n this.#userRooms.get(room)!.add(socketId)\n this.#socketUserRoom.set(socketId, room)\n }\n\n #leaveUserRoom(socketId: string): void {\n const room = this.#socketUserRoom.get(socketId)\n\n if (!room) {\n return\n }\n\n const sockets = this.#userRooms.get(room)\n sockets?.delete(socketId)\n if (sockets?.size === 0) {\n this.#userRooms.delete(room)\n }\n\n this.#socketUserRoom.delete(socketId)\n }\n\n to(channel: string) {\n return {\n emit: (event: string, data: unknown) => {\n this.#broadcastSink.dispatch({ target: 'channel', channel, event, data })\n },\n except: (socketId: string) => ({\n emit: (event: string, data: unknown) => {\n this.#broadcastSink.dispatch({\n target: 'channel',\n channel,\n event,\n data,\n except: [socketId],\n })\n },\n }),\n }\n }\n\n toUser(userId: string | number) {\n const room = userRoom(userId)\n\n return {\n emit: (event: string, data: unknown) => {\n this.#broadcastSink.dispatch({ target: 'user', userId, room, event, data })\n },\n }\n }\n\n broadcast(event: string, data: unknown): void {\n this.#broadcastSink.dispatch({ target: 'global', event, data })\n }\n\n #deliverBroadcast(emission: SocketEmission): void {\n switch (emission.target) {\n case 'channel': {\n const channel = emission.channel\n const serializedFrame = serializeFrame({\n type: 'event',\n channel,\n event: emission.event,\n data: emission.data,\n })\n this.#bus?.publishChannel(channel, emission.event, emission.data, emission.except)\n\n const traceMessage: SocketBroadcastMessage = {\n target: 'channel',\n channel,\n event: emission.event,\n via: 'local',\n }\n if (emission.except) {\n traceMessage.except = emission.except\n }\n\n this.#traceBroadcast(traceMessage, () =>\n this.#emitToChannelLocally(\n channel,\n emission.event,\n emission.data,\n emission.except,\n serializedFrame\n )\n )\n return\n }\n case 'user': {\n const room = emission.room\n const serializedFrame = serializeFrame({\n type: 'event',\n event: emission.event,\n data: emission.data,\n })\n this.#bus?.publishUser(room, emission.event, emission.data)\n this.#traceBroadcast({ target: 'user', room, event: emission.event, via: 'local' }, () =>\n this.#emitToUserRoomLocally(room, emission.event, emission.data, serializedFrame)\n )\n return\n }\n case 'global': {\n const serializedFrame = serializeFrame({\n type: 'event',\n event: emission.event,\n data: emission.data,\n })\n this.#bus?.publishBroadcast(emission.event, emission.data)\n this.#traceBroadcast({ target: 'global', event: emission.event, via: 'local' }, () =>\n this.#broadcastLocally(emission.event, emission.data, serializedFrame)\n )\n }\n }\n }\n\n #traceBroadcast(message: SocketBroadcastMessage, deliver: () => number): void {\n broadcastChannel.traceSync(() => {\n message.delivered = deliver()\n }, message)\n }\n\n #sendSerializedEventFrame(connection: WebSocket, serializedFrame: string): boolean {\n return sendSerializedFrameWithBackpressure(\n connection,\n serializedFrame,\n this.#outboundMessageConfig\n )\n }\n\n #emitToChannelLocally(\n channel: string,\n event: string,\n data: unknown,\n except: string[] = [],\n serializedFrame = serializeFrame({ type: 'event', channel, event, data })\n ): number {\n let delivered = 0\n\n for (const socketId of this.#channelSubscriptions?.getSocketIds(channel) ?? []) {\n if (except.includes(socketId)) {\n continue\n }\n\n const socket = this.#sockets.get(socketId)\n if (socket && this.#sendSerializedEventFrame(socket.raw.connection, serializedFrame)) {\n delivered += 1\n }\n }\n\n return delivered\n }\n\n #emitToUserRoomLocally(\n room: string,\n event: string,\n data: unknown,\n serializedFrame = serializeFrame({ type: 'event', event, data })\n ): number {\n let delivered = 0\n\n for (const socketId of this.#userRooms.get(room) ?? []) {\n const socket = this.#sockets.get(socketId)\n if (socket && this.#sendSerializedEventFrame(socket.raw.connection, serializedFrame)) {\n delivered += 1\n }\n }\n\n return delivered\n }\n\n #broadcastLocally(\n event: string,\n data: unknown,\n serializedFrame = serializeFrame({ type: 'event', event, data })\n ): number {\n let delivered = 0\n\n for (const socket of this.#sockets.values()) {\n if (this.#sendSerializedEventFrame(socket.raw.connection, serializedFrame)) {\n delivered += 1\n }\n }\n\n return delivered\n }\n\n #configurePresenceFetcher(): void {\n if (!this.#presenceManager || !this.#bus) {\n return\n }\n\n this.#presenceManager.setSocketFetcher(async (channel) => {\n return [\n ...this.#presenceManager!.getLocalSockets(channel),\n ...(await this.#bus!.fetchPresenceSockets(channel)),\n ]\n })\n }\n\n #getLocalPresenceSockets(channel: string): SerializablePresenceSocket[] {\n return (this.#presenceManager?.getLocalSockets(channel) ?? []).map((socket) => {\n return this.#serializePresenceSocket(channel, socket)\n })\n }\n\n #serializePresenceSocket(channel: string, socket: PresenceSocket): SerializablePresenceSocket {\n const user = socket.data[PRESENCE_DATA_KEY]![channel]\n\n return {\n id: socket.id,\n data: {\n [PRESENCE_DATA_KEY]: {\n [channel]: {\n ...user,\n joinedAt: user.joinedAt.toISOString(),\n },\n },\n },\n }\n }\n\n getSocket(socketId: string): AuthenticatedSocket<User> | undefined {\n return this.#sockets.get(socketId)\n }\n\n get connectionsCount(): number {\n return this.#sockets.size\n }\n\n get status(): SocketServiceStatus {\n return this.#status\n }\n\n get ready(): boolean {\n return this.#status === 'ready' && Boolean(this.#server)\n }\n\n fake(): SocketFake {\n const fake = new SocketFake(() => {\n if (this.#fake === fake) {\n this.restore()\n }\n })\n\n this.#fake = fake\n this.#broadcastSink = fake\n return fake\n }\n\n restore(): void {\n this.#fake = null\n this.#broadcastSink = this.#deliverySink\n }\n\n markFailed(error: unknown): void {\n this.#lastError = error instanceof Error ? error : new Error('Socket service failed')\n this.#status = 'failed'\n }\n\n #warn(message: string, error: unknown): void {\n try {\n this.#logger?.warn(message, error)\n } catch {\n // Logging must never change socket behavior.\n }\n }\n\n #emitLifecycleEvent<EventName extends keyof SocketEvents<User>>(\n eventName: EventName,\n event: SocketEvents<User>[EventName]\n ): void {\n void this.emit(eventName, event).catch((error) => {\n try {\n this.#logger?.warn('socket %s listener failed: %s', eventName, error)\n } catch {\n // Lifecycle observers and their reporting must not affect the socket service.\n }\n })\n }\n\n health(): SocketHealthSnapshot {\n return {\n status: this.#status,\n ready: this.ready,\n connections: this.#sockets.size,\n channels: this.#channelSubscriptions?.channelsCount ?? 0,\n ...(this.#lastError ? { lastError: this.#lastError.message } : {}),\n }\n }\n\n #startHeartbeat(config: { interval: number; timeout: number } | null): void {\n this.#stopHeartbeat()\n\n if (!config) {\n return\n }\n\n this.#heartbeatInterval = setInterval(() => {\n this.#pingSockets(config.timeout)\n }, config.interval)\n }\n\n #pingSockets(timeout: number): void {\n for (const socket of this.#sockets.values()) {\n const { connection } = socket.raw\n\n if (connection.readyState !== WebSocket.OPEN) {\n this.#clearHeartbeatTimeout(socket.id)\n continue\n }\n\n if (this.#heartbeatTimeouts.has(socket.id)) {\n continue\n }\n\n const timeoutId = setTimeout(() => {\n this.#heartbeatTimeouts.delete(socket.id)\n connection.terminate()\n }, timeout)\n\n this.#heartbeatTimeouts.set(socket.id, timeoutId)\n\n try {\n connection.ping()\n } catch {\n this.#clearHeartbeatTimeout(socket.id)\n connection.terminate()\n }\n }\n }\n\n #clearHeartbeatTimeout(socketId: string): void {\n const timeout = this.#heartbeatTimeouts.get(socketId)\n\n if (!timeout) {\n return\n }\n\n clearTimeout(timeout)\n this.#heartbeatTimeouts.delete(socketId)\n }\n\n #stopHeartbeat(): void {\n if (this.#heartbeatInterval) {\n clearInterval(this.#heartbeatInterval)\n this.#heartbeatInterval = null\n }\n\n for (const timeout of this.#heartbeatTimeouts.values()) {\n clearTimeout(timeout)\n }\n\n this.#heartbeatTimeouts.clear()\n }\n\n #acceptMessageRate(socketId: string, config: InboundMessageConfig): boolean {\n const now = Date.now()\n const rate = this.#messageRates.get(socketId)\n\n if (!rate || now - rate.intervalStartedAt >= config.messageRateInterval) {\n this.#messageRates.set(socketId, { count: 1, intervalStartedAt: now })\n return true\n }\n\n if (rate.count >= config.maxMessagesPerInterval) {\n return false\n }\n\n rate.count += 1\n return true\n }\n\n #cleanup(): void {\n this.#stopHeartbeat()\n this.#sockets.clear()\n this.#userRooms.clear()\n this.#socketUserRoom.clear()\n this.#messageQueue.clear()\n this.#messageRates.clear()\n this.#socketFinalizations.clear()\n this.#channelSubscriptions?.clear()\n }\n\n close(): Promise<void> {\n if (!this.#closePromise) {\n this.#closePromise = this.#close()\n }\n\n return this.#closePromise\n }\n\n async #close(): Promise<void> {\n const server = this.#server\n const bus = this.#bus\n const httpServer = this.#httpServer\n const upgradeHandler = this.#upgradeHandler\n if (this.#status !== 'failed') {\n this.#status = 'stopping'\n }\n\n this.#server = null\n this.#httpServer = null\n this.#upgradeHandler = null\n if (httpServer && upgradeHandler) {\n httpServer.off('upgrade', upgradeHandler)\n }\n\n const serverClose = server\n ? new Promise<unknown | null>((resolve) => {\n server.close((error) => resolve(error ?? null))\n })\n : Promise.resolve(null)\n\n this.#stopHeartbeat()\n const sockets = [...this.#sockets.values()]\n for (const socket of sockets) {\n socket.raw.connection.terminate()\n }\n\n const errors: unknown[] = []\n const finalizations = sockets.map((socket) => {\n return Promise.resolve().then(() => this.#finalizeSocket(socket))\n })\n const results = await Promise.allSettled(finalizations)\n for (const result of results) {\n if (result.status === 'rejected') {\n errors.push(result.reason)\n }\n }\n\n this.#cleanup()\n this.#presenceManager?.setSocketFetcher(null)\n this.#bus = null\n\n try {\n await bus?.close()\n } catch (error) {\n errors.push(error)\n }\n\n const serverCloseError = await serverClose\n if (serverCloseError) {\n errors.push(serverCloseError)\n }\n\n if (errors.length > 0) {\n const error =\n errors.length === 1 && errors[0] instanceof Error\n ? errors[0]\n : new AggregateError(errors, 'Socket service shutdown failed')\n this.markFailed(error)\n throw error\n }\n\n if (this.#status !== 'failed') {\n this.#status = 'stopped'\n }\n }\n}\n","import type { BaseChannel } from './base_channel.js'\n\nexport interface StoredChannelSubscription {\n channelName: string\n instance: BaseChannel<any, any>\n paramValues: string[]\n}\n\n/**\n * Stores durable Channel subscriptions and keeps Socket/Channel indexes in sync.\n */\nexport class ChannelSubscriptionStorage {\n #subscriptions = new Map<string, Map<string, StoredChannelSubscription>>()\n #subscribers = new Map<string, Set<string>>()\n\n has(socketId: string, channelName: string): boolean {\n return this.#subscriptions.get(socketId)?.has(channelName) ?? false\n }\n\n get(socketId: string, channelName: string): StoredChannelSubscription | undefined {\n return this.#subscriptions.get(socketId)?.get(channelName)\n }\n\n set(socketId: string, channelName: string, subscription: StoredChannelSubscription): void {\n if (!this.#subscriptions.has(socketId)) {\n this.#subscriptions.set(socketId, new Map())\n }\n\n this.#subscriptions.get(socketId)!.set(channelName, subscription)\n\n if (!this.#subscribers.has(channelName)) {\n this.#subscribers.set(channelName, new Set())\n }\n\n this.#subscribers.get(channelName)!.add(socketId)\n }\n\n delete(socketId: string, channelName: string): void {\n const subscriptions = this.#subscriptions.get(socketId)\n\n if (!subscriptions) {\n return\n }\n\n subscriptions.delete(channelName)\n if (subscriptions.size === 0) {\n this.#subscriptions.delete(socketId)\n }\n\n const subscribers = this.#subscribers.get(channelName)\n subscribers?.delete(socketId)\n if (subscribers?.size === 0) {\n this.#subscribers.delete(channelName)\n }\n }\n\n deleteSocket(socketId: string): void {\n for (const channelName of this.channelNamesFor(socketId)) {\n this.delete(socketId, channelName)\n }\n }\n\n channelNamesFor(socketId: string): string[] {\n return [...(this.#subscriptions.get(socketId)?.keys() ?? [])]\n }\n\n countForSocket(socketId: string): number {\n return this.#subscriptions.get(socketId)?.size ?? 0\n }\n\n socketIdsFor(channelName: string): string[] {\n return [...(this.#subscribers.get(channelName) ?? [])]\n }\n\n get channelsCount(): number {\n return this.#subscribers.size\n }\n\n clear(): void {\n this.#subscriptions.clear()\n this.#subscribers.clear()\n }\n}\n","import type { Logger } from '@adonisjs/logger'\nimport { SocketResponseError } from './base_channel.js'\nimport type { BaseChannel } from './base_channel.js'\nimport {\n ChannelSubscriptionStorage,\n type StoredChannelSubscription,\n} from './channel_subscription_storage.js'\nimport type { ChannelRouter } from './channel_router.js'\nimport type { PresenceData, PresenceManager } from './presence_manager.js'\nimport type { SocketService } from './socket_service.js'\nimport type { AuthenticatedSocket, ChannelAck, ChannelMessage } from './types.js'\n\ninterface AuthorizedChannel<User> {\n instance: BaseChannel<User>\n params: Record<string, string>\n paramValues: string[]\n presenceData: Record<string, unknown> | PresenceData | null\n}\n\nexport interface ChannelSubscribeAck {\n ok: boolean\n presenceData?: Record<string, unknown> | PresenceData | null\n error?: string\n}\n\nexport interface ChannelSubscribeResult {\n ack: ChannelSubscribeAck\n created: boolean\n}\n\nexport interface ChannelSubscriptionLimits {\n maxSubscriptionsPerSocket: number\n maxChannelNameLength: number\n}\n\n/**\n * Durable channel subscriptions for sockets.\n */\nexport class ChannelSubscriptions<User = unknown> {\n #storage = new ChannelSubscriptionStorage()\n #channelOperations = new Map<string, Promise<void>>()\n\n static #serializePresenceData(presenceData: PresenceData): Record<string, unknown> {\n return {\n ...presenceData,\n users: presenceData.users.map((user) => ({\n ...user,\n joinedAt: user.joinedAt.toISOString(),\n })),\n }\n }\n\n constructor(\n private socketService: SocketService<User>,\n private channelRouter: ChannelRouter,\n private logger: Logger,\n private presenceManager?: PresenceManager,\n private limits?: ChannelSubscriptionLimits\n ) {}\n\n setPresenceManager(presenceManager: PresenceManager): void {\n this.presenceManager = presenceManager\n }\n\n async subscribe(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<ChannelSubscribeResult> {\n return this.#subscribe(socket, channelName)\n }\n\n async #subscribe(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<ChannelSubscribeResult> {\n const existing = await this.#refreshExistingSubscription(socket, channelName)\n if (existing) {\n return existing\n }\n\n if (this.limits && channelName.length > this.limits.maxChannelNameLength) {\n return {\n ack: { ok: false, error: 'Channel name is too long' },\n created: false,\n }\n }\n\n if (\n this.limits &&\n this.#storage.channelNamesFor(socket.id).length >= this.limits.maxSubscriptionsPerSocket\n ) {\n return {\n ack: { ok: false, error: 'Socket subscription limit exceeded' },\n created: false,\n }\n }\n\n const result = await this.channelRouter.authorize(socket, channelName)\n\n if (!result.success) {\n if ('cause' in result && !(result.cause instanceof SocketResponseError)) {\n this.#warn(`failed to authorize channel \"${channelName}\": %s`, result.cause)\n }\n\n return {\n ack: { ok: false, error: result.error },\n created: false,\n }\n }\n\n if (this.#usesPresence(result.instance)) {\n return this.#withChannelOperation(channelName, async () => {\n const concurrentSubscription = await this.#refreshExistingSubscription(socket, channelName)\n if (concurrentSubscription) {\n return concurrentSubscription\n }\n\n return this.#completeSubscription(socket, channelName, result)\n })\n }\n\n return this.#completeSubscription(socket, channelName, result)\n }\n\n async #completeSubscription(\n socket: AuthenticatedSocket<User>,\n channelName: string,\n result: AuthorizedChannel<User>\n ): Promise<ChannelSubscribeResult> {\n result.instance.$setContext(\n this.socketService,\n channelName,\n result.params,\n this.presenceManager\n )\n\n let presenceData: Record<string, unknown> | PresenceData | null = result.presenceData\n let presenceSnapshot: PresenceData | null = null\n let presenceJoined = false\n let serializationError: unknown\n\n try {\n if (this.#usesPresence(result.instance)) {\n const presenceInfo = result.instance.$getPresenceInfo(socket)\n const wasPresent = (await this.presenceManager!.snapshot(channelName)).users.some(\n (user) => user.id === presenceInfo.id\n )\n\n const { joinedAt: _joinedAt, ...member } = this.presenceManager!.join(\n channelName,\n socket.raw,\n presenceInfo\n )\n presenceJoined = true\n\n presenceSnapshot = await this.presenceManager!.snapshot(channelName)\n presenceData = presenceSnapshot\n\n try {\n JSON.stringify(presenceData)\n } catch (error) {\n serializationError = error\n throw error\n }\n\n if (!wasPresent) {\n await result.instance.onMemberJoin?.(socket, member, ...result.paramValues)\n }\n await result.instance.onJoin?.(socket, ...result.paramValues)\n } else {\n try {\n JSON.stringify(presenceData)\n } catch (error) {\n serializationError = error\n throw error\n }\n\n await result.instance.onJoin?.(socket, ...result.paramValues)\n }\n\n this.#storage.set(socket.id, channelName, {\n channelName,\n instance: result.instance,\n paramValues: result.paramValues,\n })\n\n if (presenceSnapshot) {\n this.socketService\n .to(channelName)\n .except(socket.id)\n .emit('presence:update', ChannelSubscriptions.#serializePresenceData(presenceSnapshot))\n }\n } catch (error) {\n if (presenceJoined) {\n this.presenceManager!.leave(channelName, socket.raw)\n\n const rollbackData = await this.presenceManager!.snapshot(channelName).catch(() => null)\n if (rollbackData) {\n this.socketService\n .to(channelName)\n .emit('presence:update', ChannelSubscriptions.#serializePresenceData(rollbackData))\n }\n }\n\n this.#storage.delete(socket.id, channelName)\n\n if (serializationError) {\n this.#warn(\n `failed to serialize subscription response for channel \"${channelName}\": %s`,\n serializationError\n )\n } else if (!(error instanceof SocketResponseError)) {\n this.#warn(`failed to join channel \"${channelName}\": %s`, error)\n }\n\n return {\n ack: {\n ok: false,\n error: serializationError\n ? 'Subscription response is not serializable'\n : error instanceof SocketResponseError\n ? error.message\n : 'Join failed',\n },\n created: false,\n }\n }\n\n return {\n ack: { ok: true, presenceData },\n created: true,\n }\n }\n\n async leave(socket: AuthenticatedSocket<User>, channelName: string): Promise<boolean> {\n const subscription = this.#storage.get(socket.id, channelName)\n if (!subscription) {\n return false\n }\n\n this.#storage.delete(socket.id, channelName)\n\n if (this.#usesPresence(subscription.instance)) {\n await this.#withChannelOperation(channelName, () =>\n this.#cleanupAfterLeave(socket, channelName, subscription)\n )\n } else {\n await this.#cleanupAfterLeave(socket, channelName, subscription)\n }\n\n return true\n }\n\n async #cleanupAfterLeave(\n socket: AuthenticatedSocket<User>,\n channelName: string,\n subscription: StoredChannelSubscription\n ): Promise<void> {\n if (this.#usesPresence(subscription.instance)) {\n const presenceUser = this.presenceManager!.getLocalUser(channelName, socket.id)\n this.presenceManager!.leave(channelName, socket.raw)\n\n try {\n const presenceData = await this.presenceManager!.snapshot(channelName)\n\n this.socketService\n .to(channelName)\n .emit('presence:update', ChannelSubscriptions.#serializePresenceData(presenceData))\n\n if (presenceUser && !presenceData.users.some((user) => user.id === presenceUser.id)) {\n const { joinedAt: _joinedAt, ...member } = presenceUser\n await subscription.instance.onMemberLeave?.(socket, member, ...subscription.paramValues)\n }\n } catch (error) {\n this.#warn(`failed to update presence while leaving channel \"${channelName}\": %s`, error)\n }\n }\n\n try {\n await subscription.instance.onLeave?.(socket, ...subscription.paramValues)\n } catch (error) {\n this.#warn(`failed to leave channel \"${channelName}\": %s`, error)\n }\n }\n\n async leaveAll(socket: AuthenticatedSocket<User>): Promise<void> {\n for (const channelName of this.#storage.channelNamesFor(socket.id)) {\n await this.leave(socket, channelName)\n }\n }\n\n async handleMessage(\n socket: AuthenticatedSocket<User>,\n payload: ChannelMessage\n ): Promise<ChannelAck> {\n const subscription = this.#storage.get(socket.id, payload.channel)\n\n if (!subscription) {\n return { ok: false, error: 'Not subscribed' }\n }\n\n try {\n const result = await subscription.instance.$handleMessage(socket, payload.event, payload.data)\n\n try {\n JSON.stringify(result)\n } catch (error) {\n this.#warn(\n `failed to serialize handler response for channel \"${payload.channel}\": %s`,\n error\n )\n return { ok: false, error: 'Handler response is not serializable' }\n }\n\n return { ok: true, data: result }\n } catch (error) {\n if (!(error instanceof SocketResponseError)) {\n this.#warn(`channel handler failed for \"${payload.channel}\": %s`, error)\n }\n\n return {\n ok: false,\n error: error instanceof SocketResponseError ? error.message : 'Handler error',\n }\n }\n }\n\n relayWhisper(socket: AuthenticatedSocket<User>, payload: ChannelMessage): ChannelAck {\n if (!this.#storage.has(socket.id, payload.channel)) {\n return { ok: false, error: 'Not subscribed' }\n }\n\n this.socketService\n .to(payload.channel)\n .except(socket.id)\n .emit(`client:${payload.event}`, payload.data)\n\n return { ok: true }\n }\n\n deleteSocket(socketId: string): void {\n this.#storage.deleteSocket(socketId)\n }\n\n clear(): void {\n this.#storage.clear()\n this.#channelOperations.clear()\n }\n\n getSocketIds(channelName: string): string[] {\n return this.#storage.socketIdsFor(channelName)\n }\n\n subscriptionCountFor(socketId: string): number {\n return this.#storage.countForSocket(socketId)\n }\n\n get channelsCount(): number {\n return this.#storage.channelsCount\n }\n\n #warn(message: string, error: unknown): void {\n try {\n this.logger.warn(message, error)\n } catch {\n // Logging must never change the socket protocol outcome.\n }\n }\n\n async #withChannelOperation<Result>(\n channelName: string,\n operation: () => Promise<Result>\n ): Promise<Result> {\n const previous = this.#channelOperations.get(channelName) ?? Promise.resolve()\n const release = Promise.withResolvers<void>()\n const queued = previous.then(() => release.promise)\n this.#channelOperations.set(channelName, queued)\n\n await previous\n try {\n return await operation()\n } finally {\n release.resolve()\n if (this.#channelOperations.get(channelName) === queued) {\n this.#channelOperations.delete(channelName)\n }\n }\n }\n\n #usesPresence(instance: BaseChannel<any, any>): boolean {\n return Boolean(\n (instance.constructor as typeof BaseChannel).options?.presence && this.presenceManager\n )\n }\n\n async #refreshExistingSubscription(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<ChannelSubscribeResult | null> {\n if (!this.#storage.has(socket.id, channelName)) {\n return null\n }\n\n let presenceData: PresenceData | undefined\n\n try {\n presenceData = await this.#getPresenceData(socket, channelName)\n } catch (error) {\n this.#warn(`failed to refresh subscription for channel \"${channelName}\": %s`, error)\n return {\n ack: { ok: false, error: 'Subscribe failed' },\n created: false,\n }\n }\n\n try {\n JSON.stringify(presenceData)\n } catch (error) {\n this.#warn(\n `failed to serialize subscription response for channel \"${channelName}\": %s`,\n error\n )\n return {\n ack: { ok: false, error: 'Subscription response is not serializable' },\n created: false,\n }\n }\n\n return {\n ack: {\n ok: true,\n presenceData,\n },\n created: false,\n }\n }\n\n async #getPresenceData(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<PresenceData | undefined> {\n if (!this.presenceManager?.hasLocal(channelName, socket.id)) {\n return undefined\n }\n\n return this.presenceManager.snapshot(channelName)\n }\n}\n","import type { ChannelAck, ServerProtocolMessage } from '../shared_types.js'\nimport type { ChannelSubscribeResult } from '../channel_subscriptions.js'\n\nconst INVALID_SOCKET_MESSAGE = 'Invalid socket message'\n\nexport class Reply {\n private constructor(\n private id: string | undefined,\n private ok: boolean,\n private data: unknown | undefined,\n private error: string | undefined\n ) {}\n\n static ok(id: string | undefined, data?: unknown): Reply {\n return new Reply(id, true, data, undefined)\n }\n\n static error(id: string | undefined, error: string): Reply {\n return new Reply(id, false, undefined, error)\n }\n\n static invalidMessage(id: string | undefined): ServerProtocolMessage {\n if (id === undefined) {\n return { type: 'error', error: INVALID_SOCKET_MESSAGE }\n }\n\n return Reply.error(id, INVALID_SOCKET_MESSAGE).toFrame()\n }\n\n static fromSubscribeResult(\n id: string | undefined,\n result: ChannelSubscribeResult | undefined\n ): Reply {\n if (!result) {\n return Reply.error(id, 'Socket service is not initialized')\n }\n\n if (!result.ack.ok) {\n return Reply.error(id, result.ack.error ?? 'Subscribe failed')\n }\n\n const data = result.ack.presenceData\n ? {\n presenceData: result.ack.presenceData,\n }\n : undefined\n\n return Reply.ok(id, data)\n }\n\n static fromChannelAck(id: string | undefined, ack: ChannelAck): Reply {\n return ack.ok ? Reply.ok(id, ack.data) : Reply.error(id, ack.error ?? 'Handler error')\n }\n\n toFrame(): Extract<ServerProtocolMessage, { type: 'ack' }> {\n const frame: Extract<ServerProtocolMessage, { type: 'ack' }> = {\n id: this.id,\n type: 'ack',\n ok: this.ok,\n }\n\n if (this.data !== undefined) {\n frame.data = this.data\n }\n\n if (this.error !== undefined) {\n frame.error = this.error\n }\n\n return frame\n }\n}\n","import type {\n ChannelMessage,\n ClientProtocolMessage,\n ServerProtocolMessage,\n} from '../shared_types.js'\nimport { Reply } from './reply.js'\n\ntype ClientMessageType = ClientProtocolMessage['type']\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport abstract class Message {\n abstract readonly valid: boolean\n abstract readonly type: ClientMessageType | 'invalid'\n\n static fromTransport(raw: string): TransportMessage {\n try {\n return Message.fromParsedTransport(JSON.parse(raw))\n } catch {\n return new InvalidMessage(undefined)\n }\n }\n\n private static fromParsedTransport(value: unknown): TransportMessage {\n if (!isRecord(value)) {\n return new InvalidMessage(undefined)\n }\n\n const id = typeof value.id === 'string' ? value.id : undefined\n\n if ('id' in value && typeof value.id !== 'string') {\n return new InvalidMessage(undefined)\n }\n\n if (!isClientMessageType(value.type)) {\n return new InvalidMessage(id)\n }\n\n if (value.type === 'ping') {\n return new PingMessage(id)\n }\n\n if (value.type === 'subscribe' && typeof value.channel === 'string') {\n return new SubscribeMessage(id, value.channel)\n }\n\n if (value.type === 'unsubscribe' && typeof value.channel === 'string') {\n return new UnsubscribeMessage(id, value.channel)\n }\n\n if (\n (value.type === 'message' || value.type === 'whisper') &&\n typeof value.channel === 'string' &&\n typeof value.event === 'string'\n ) {\n return new ChannelProtocolMessage(id, value.type, value.channel, value.event, value.data)\n }\n\n return new InvalidMessage(id)\n }\n}\n\nexport class InvalidMessage extends Message {\n readonly valid = false\n readonly type = 'invalid'\n\n constructor(readonly id: string | undefined) {\n super()\n }\n\n toRejectionFrame(): ServerProtocolMessage {\n return Reply.invalidMessage(this.id)\n }\n}\n\nexport class PingMessage extends Message {\n readonly valid = true\n readonly type = 'ping'\n\n constructor(readonly id: string | undefined) {\n super()\n }\n}\n\nexport class SubscribeMessage extends Message {\n readonly valid = true\n readonly type = 'subscribe'\n\n constructor(\n readonly id: string | undefined,\n readonly channel: string\n ) {\n super()\n }\n}\n\nexport class UnsubscribeMessage extends Message {\n readonly valid = true\n readonly type = 'unsubscribe'\n\n constructor(\n readonly id: string | undefined,\n readonly channel: string\n ) {\n super()\n }\n}\n\nexport class ChannelProtocolMessage extends Message {\n readonly valid = true\n\n constructor(\n readonly id: string | undefined,\n readonly type: 'message' | 'whisper',\n readonly channel: string,\n readonly event: string,\n readonly data: unknown\n ) {\n super()\n }\n\n toChannelMessage(): ChannelMessage {\n return {\n channel: this.channel,\n event: this.event,\n data: this.data,\n }\n }\n}\n\nexport type TransportMessage =\n | InvalidMessage\n | PingMessage\n | SubscribeMessage\n | UnsubscribeMessage\n | ChannelProtocolMessage\n\nfunction isClientMessageType(value: unknown): value is ClientMessageType {\n return (\n value === 'ping' ||\n value === 'subscribe' ||\n value === 'unsubscribe' ||\n value === 'message' ||\n value === 'whisper'\n )\n}\n","export class MessageQueue<Key = string> {\n #queues = new Map<Key, Promise<void>>()\n #depths = new Map<Key, number>()\n\n enqueue(key: Key, task: () => Promise<void>, options: { maxDepth?: number } = {}): boolean {\n const depth = this.#depths.get(key) ?? 0\n\n if (options.maxDepth !== undefined && depth >= options.maxDepth) {\n return false\n }\n\n this.#depths.set(key, depth + 1)\n\n const previous = this.#queues.get(key) ?? Promise.resolve()\n const next = previous\n .catch(() => {})\n .then(task)\n .catch(() => {})\n .finally(() => {\n const nextDepth = (this.#depths.get(key) ?? 1) - 1\n\n if (nextDepth <= 0) {\n this.#depths.delete(key)\n } else {\n this.#depths.set(key, nextDepth)\n }\n\n if (this.#queues.get(key) === next) {\n this.#queues.delete(key)\n }\n })\n\n this.#queues.set(key, next)\n return true\n }\n\n drain(key: Key): Promise<void> {\n return this.#queues.get(key) ?? Promise.resolve()\n }\n\n delete(key: Key): void {\n this.#queues.delete(key)\n this.#depths.delete(key)\n }\n\n clear(): void {\n this.#queues.clear()\n this.#depths.clear()\n }\n}\n","export type SocketEmission =\n | {\n target: 'global'\n event: string\n data: unknown\n }\n | {\n target: 'channel'\n channel: string\n event: string\n data: unknown\n except?: string[]\n }\n | {\n target: 'user'\n userId: string | number\n room: string\n event: string\n data: unknown\n }\n\nexport type SocketEmissionTarget = SocketEmission['target']\n\nexport interface SocketEmissionSink {\n dispatch(emission: SocketEmission): void\n}\n\nexport function userRoom(userId: string | number): string {\n return `socket:user:${String(userId)}`\n}\n","import { randomUUID } from 'node:crypto'\nimport { Bus } from '@boringnode/bus'\nimport type { Serializable, TransportFactory } from '@boringnode/bus/types/main'\nimport { PRESENCE_DATA_KEY, type PresenceSocket, type PresenceUser } from './presence_manager.js'\nimport { parseDuration, type Duration } from './duration.js'\n\nconst DEFAULT_CHANNEL = 'socket::broadcast'\nconst DEFAULT_PRESENCE_TIMEOUT = 100\n\ntype SerializablePresenceUser = {\n [key: string]: Serializable\n id: string\n name: string\n joinedAt: string\n}\n\nexport interface SerializablePresenceSocket {\n [key: string]: Serializable\n id: string\n data: {\n [key: string]: Serializable\n }\n}\n\ntype ChannelEventMessage = {\n [key: string]: Serializable\n type: 'channel:event'\n origin: string\n channel: string\n event: string\n data: Serializable\n except: string[]\n}\n\ntype UserEventMessage = {\n [key: string]: Serializable\n type: 'user:event'\n origin: string\n room: string\n event: string\n data: Serializable\n}\n\ntype BroadcastEventMessage = {\n [key: string]: Serializable\n type: 'broadcast:event'\n origin: string\n event: string\n data: Serializable\n}\n\ntype PresenceSocketsRequestMessage = {\n [key: string]: Serializable\n type: 'presence:sockets:request'\n origin: string\n requestId: string\n channel: string\n}\n\ntype PresenceSocketsResponseMessage = {\n [key: string]: Serializable\n type: 'presence:sockets:response'\n origin: string\n target: string\n requestId: string\n sockets: SerializablePresenceSocket[]\n}\n\nexport type SocketBusMessage =\n | ChannelEventMessage\n | UserEventMessage\n | BroadcastEventMessage\n | PresenceSocketsRequestMessage\n | PresenceSocketsResponseMessage\n\nexport interface SocketTransportConfig {\n driver: TransportFactory\n channel?: string\n /**\n * How long to wait for other instances to answer a presence snapshot request.\n */\n presenceTimeout?: Duration\n}\n\ninterface SocketBusHandlers {\n channel(message: Extract<SocketBusMessage, { type: 'channel:event' }>): void\n user(message: Extract<SocketBusMessage, { type: 'user:event' }>): void\n broadcast(message: Extract<SocketBusMessage, { type: 'broadcast:event' }>): void\n presenceSockets(channel: string): SerializablePresenceSocket[]\n}\n\ninterface PendingPresenceRequest {\n sockets: SerializablePresenceSocket[]\n resolve(sockets: PresenceSocket[]): void\n timeout: ReturnType<typeof setTimeout>\n}\n\nfunction parsePresenceSocket(value: unknown): SerializablePresenceSocket | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null\n }\n\n const socket = value as Record<string, unknown>\n if (\n typeof socket.id !== 'string' ||\n !socket.data ||\n typeof socket.data !== 'object' ||\n Array.isArray(socket.data)\n ) {\n return null\n }\n\n const presence = (socket.data as Record<string, unknown>)[PRESENCE_DATA_KEY]\n if (presence === undefined) {\n return socket as SerializablePresenceSocket\n }\n\n if (!presence || typeof presence !== 'object' || Array.isArray(presence)) {\n return null\n }\n\n for (const user of Object.values(presence)) {\n if (\n !user ||\n typeof user !== 'object' ||\n typeof user.id !== 'string' ||\n typeof user.name !== 'string' ||\n typeof user.joinedAt !== 'string' ||\n Number.isNaN(Date.parse(user.joinedAt))\n ) {\n return null\n }\n }\n\n return socket as SerializablePresenceSocket\n}\n\nfunction parseBusMessage(payload: unknown): SocketBusMessage | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return null\n }\n\n const message = payload as Record<string, unknown>\n if (typeof message.origin !== 'string') {\n return null\n }\n\n switch (message.type) {\n case 'channel:event':\n return typeof message.channel === 'string' &&\n typeof message.event === 'string' &&\n Array.isArray(message.except) &&\n message.except.every((socketId) => typeof socketId === 'string')\n ? (message as ChannelEventMessage)\n : null\n case 'user:event':\n return typeof message.room === 'string' && typeof message.event === 'string'\n ? (message as UserEventMessage)\n : null\n case 'broadcast:event':\n return typeof message.event === 'string' ? (message as BroadcastEventMessage) : null\n case 'presence:sockets:request':\n return typeof message.requestId === 'string' && typeof message.channel === 'string'\n ? (message as PresenceSocketsRequestMessage)\n : null\n case 'presence:sockets:response':\n if (\n typeof message.target !== 'string' ||\n typeof message.requestId !== 'string' ||\n !Array.isArray(message.sockets)\n ) {\n return null\n }\n\n const sockets = Array.from(message.sockets, parsePresenceSocket)\n return sockets.every((socket) => socket !== null)\n ? ({ ...message, sockets } as PresenceSocketsResponseMessage)\n : null\n default:\n return null\n }\n}\n\nexport class SocketBus {\n #origin = randomUUID()\n #channel: string\n #bus: Bus\n #presenceTimeout: number\n #pendingPresenceRequests = new Map<string, PendingPresenceRequest>()\n\n constructor(\n transport: SocketTransportConfig,\n private handlers: SocketBusHandlers\n ) {\n this.#channel = transport.channel ?? DEFAULT_CHANNEL\n this.#presenceTimeout =\n parseDuration('transport.presenceTimeout', transport.presenceTimeout) ??\n DEFAULT_PRESENCE_TIMEOUT\n this.#bus = new Bus(transport.driver(), { retryQueue: { enabled: true } })\n }\n\n async start(): Promise<void> {\n await this.#bus.subscribe(this.#channel, (payload) => {\n try {\n const message = parseBusMessage(payload)\n if (!message || message.origin === this.#origin) {\n return\n }\n\n switch (message.type) {\n case 'channel:event':\n this.handlers.channel(message)\n return\n case 'user:event':\n this.handlers.user(message)\n return\n case 'broadcast:event':\n this.handlers.broadcast(message)\n return\n case 'presence:sockets:request':\n void this.#respondToPresenceRequest(message).catch(() => {})\n return\n case 'presence:sockets:response':\n this.#handlePresenceResponse(message)\n return\n }\n } catch {\n return\n }\n })\n }\n\n publishChannel(channel: string, event: string, data: unknown, except?: string[]): void {\n const message: SocketBusMessage = {\n type: 'channel:event',\n origin: this.#origin,\n channel,\n event,\n data: data as Serializable,\n except: except ?? [],\n }\n\n void this.#bus.publish(this.#channel, message)\n }\n\n publishUser(room: string, event: string, data: unknown): void {\n const message: UserEventMessage = {\n type: 'user:event',\n origin: this.#origin,\n room,\n event,\n data: data as Serializable,\n }\n void this.#bus.publish(this.#channel, message)\n }\n\n publishBroadcast(event: string, data: unknown): void {\n const message: BroadcastEventMessage = {\n type: 'broadcast:event',\n origin: this.#origin,\n event,\n data: data as Serializable,\n }\n void this.#bus.publish(this.#channel, message)\n }\n\n fetchPresenceSockets(channel: string): Promise<PresenceSocket[]> {\n const requestId = randomUUID()\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n const request = this.#pendingPresenceRequests.get(requestId)\n\n if (!request) {\n return\n }\n\n this.#pendingPresenceRequests.delete(requestId)\n resolve(request.sockets.map((socket) => this.#deserializePresenceSocket(socket)))\n }, this.#presenceTimeout)\n\n this.#pendingPresenceRequests.set(requestId, {\n sockets: [],\n resolve,\n timeout,\n })\n\n const message: PresenceSocketsRequestMessage = {\n type: 'presence:sockets:request',\n origin: this.#origin,\n requestId,\n channel,\n }\n void this.#bus.publish(this.#channel, message)\n })\n }\n\n async close(): Promise<void> {\n for (const [requestId, request] of this.#pendingPresenceRequests) {\n clearTimeout(request.timeout)\n request.resolve(request.sockets.map((socket) => this.#deserializePresenceSocket(socket)))\n this.#pendingPresenceRequests.delete(requestId)\n }\n\n await this.#bus.disconnect()\n }\n\n async #respondToPresenceRequest(\n message: Extract<SocketBusMessage, { type: 'presence:sockets:request' }>\n ): Promise<void> {\n const response: PresenceSocketsResponseMessage = {\n type: 'presence:sockets:response',\n origin: this.#origin,\n target: message.origin,\n requestId: message.requestId,\n sockets: this.handlers.presenceSockets(message.channel),\n }\n await this.#bus.publish(this.#channel, response as Serializable)\n }\n\n #handlePresenceResponse(\n message: Extract<SocketBusMessage, { type: 'presence:sockets:response' }>\n ): void {\n if (message.target !== this.#origin) {\n return\n }\n\n const request = this.#pendingPresenceRequests.get(message.requestId)\n\n if (!request) {\n return\n }\n\n request.sockets.push(...message.sockets)\n }\n\n #deserializePresenceSocket(socket: SerializablePresenceSocket): PresenceSocket {\n const presence = socket.data[PRESENCE_DATA_KEY] as\n | Record<string, SerializablePresenceUser>\n | undefined\n\n return {\n id: socket.id,\n data: {\n [PRESENCE_DATA_KEY]: presence\n ? Object.fromEntries(\n Object.entries(presence).map(([channel, user]) => [\n channel,\n {\n ...user,\n joinedAt: new Date(user.joinedAt),\n } as PresenceUser,\n ])\n )\n : undefined,\n },\n }\n }\n}\n","import { parse as parseDurationExpression } from '@lukeed/ms'\n\n/**\n * Duration can be specified as milliseconds or as a human-readable string.\n */\nexport type Duration = number | string\n\nexport function parseDuration(name: string, duration: Duration | undefined): number | undefined {\n if (duration === undefined) {\n return undefined\n }\n\n const milliseconds = typeof duration === 'number' ? duration : parseDurationExpression(duration)\n\n if (typeof milliseconds === 'undefined' || !Number.isFinite(milliseconds) || milliseconds <= 0) {\n throw new Error(`${name} must be a positive duration`)\n }\n\n return milliseconds\n}\n","import type { IncomingMessage } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport type { WebSocket, WebSocketServer } from 'ws'\nimport type { HttpContext } from '@adonisjs/core/http'\nimport type { SocketConfig, SocketUpgradeContext } from './types.js'\n\nexport const DEFAULT_WEBSOCKET_PATH = '/socket'\n\nexport interface AcceptedUpgrade<User> {\n httpContext: HttpContext\n user?: User\n}\n\nexport type SocketUpgradeHandler = (request: IncomingMessage, socket: Duplex, head: Buffer) => void\n\ntype AcceptUpgrade<User> = (\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User>\n) => void\n\nexport type SocketUpgradeContextRunner = <Result>(\n request: IncomingMessage,\n handler: (httpContext: HttpContext) => Promise<Result>\n) => Promise<Result>\n\nexport class SocketUpgrader<User = unknown> {\n #path: string\n #allowedOrigins: Set<string>\n\n constructor(\n private server: WebSocketServer,\n private config: SocketConfig<User>['websocket'] | undefined,\n private runWithHttpContext: SocketUpgradeContextRunner,\n private reportError: (message: string, error: unknown) => void = () => {}\n ) {\n this.#path = config?.path ?? DEFAULT_WEBSOCKET_PATH\n this.#allowedOrigins = new Set((config?.allowedOrigins ?? []).map(SocketUpgrader.#parseOrigin))\n }\n\n async handle(\n request: IncomingMessage,\n socket: Duplex,\n head: Buffer,\n accept: AcceptUpgrade<User>\n ): Promise<boolean> {\n if (!this.#matchesPath(request)) {\n return false\n }\n\n if (!this.#isOriginAllowed(request)) {\n SocketUpgrader.reject(socket, 403, 'Forbidden')\n return true\n }\n\n const accepted = await this.#authenticate(request)\n\n if (!accepted) {\n SocketUpgrader.reject(socket, 401, 'Unauthorized')\n return true\n }\n\n this.server.handleUpgrade(request, socket, head, (connection) => {\n accept(connection, request, accepted)\n })\n\n return true\n }\n\n static reject(socket: Duplex, statusCode: number, reason: string): void {\n if (!socket.writableEnded) {\n socket.write(`HTTP/1.1 ${statusCode} ${reason}\\r\\n\\r\\n`)\n }\n\n socket.destroy()\n }\n\n static #parseOrigin(value: string): string {\n let url: URL\n\n try {\n url = new URL(value)\n } catch {\n throw new Error(`websocket.allowedOrigins contains an invalid origin: ${value}`)\n }\n\n if (\n !['http:', 'https:'].includes(url.protocol) ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash\n ) {\n throw new Error(`websocket.allowedOrigins contains an invalid origin: ${value}`)\n }\n\n return url.origin\n }\n\n #matchesPath(request: IncomingMessage): boolean {\n const url = new URL(request.url ?? '/', 'ws://localhost')\n return url.pathname === this.#path\n }\n\n #isOriginAllowed(request: IncomingMessage): boolean {\n const origin = request.headers.origin\n if (!origin) {\n return true\n }\n\n let parsedOrigin: string\n try {\n parsedOrigin = SocketUpgrader.#parseOrigin(origin)\n } catch {\n return false\n }\n\n if (this.#allowedOrigins.has(parsedOrigin)) {\n return true\n }\n\n const host = request.headers.host\n if (!host) {\n return false\n }\n\n const forwardedHeader = request.headers['x-forwarded-proto']\n const forwardedProtocol = (\n Array.isArray(forwardedHeader) ? forwardedHeader[0] : forwardedHeader\n )\n ?.split(',')[0]\n ?.trim()\n const protocol =\n forwardedProtocol === 'http' || forwardedProtocol === 'https'\n ? forwardedProtocol\n : (request.socket as typeof request.socket & { encrypted?: boolean }).encrypted\n ? 'https'\n : 'http'\n\n try {\n return parsedOrigin === new URL(`${protocol}://${host}`).origin\n } catch {\n return false\n }\n }\n\n async #authenticate(request: IncomingMessage): Promise<AcceptedUpgrade<User> | null> {\n const config = this.config\n return this.runWithHttpContext(request, async (httpContext) => {\n if (!config?.authenticate) {\n return { httpContext }\n }\n\n try {\n const ctx: SocketUpgradeContext = {\n httpContext,\n }\n\n const result = await config.authenticate(ctx)\n\n if (result === false || result === null || result === undefined) {\n return null\n }\n\n return {\n httpContext,\n user: result,\n }\n } catch (error) {\n try {\n this.reportError('socket authentication failed: %s', error)\n } catch {\n // Error reporting must never change an authentication rejection.\n }\n return null\n }\n })\n }\n}\n"],"mappings":"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","names":["randomUUID","randomUUID"]}
|
|
1
|
+
{"version":3,"sources":["../../providers/socket_provider.ts","../../src/socket_service.ts","../../src/channel_subscription_storage.ts","../../src/channel_subscriptions.ts","../../src/protocol/reply.ts","../../src/protocol/message.ts","../../src/message_queue.ts","../../src/socket_bus.ts","../../src/presence_manager.ts","../../src/presence_socket_frame.ts","../../src/duration.ts","../../src/socket_upgrader.ts","../../src/channel_pattern.ts","../../src/channel_router.ts"],"sourcesContent":["import type { ApplicationService } from '@adonisjs/core/types'\nimport type { HttpContext, Server as AdonisServer } from '@adonisjs/core/http'\nimport type { Logger } from '@adonisjs/logger'\nimport type { MiddlewareAsClass } from '@adonisjs/core/types/http'\nimport { ServerResponse } from 'node:http'\nimport { SocketService } from '../src/socket_service.js'\nimport { ChannelRouter } from '../src/channel_router.js'\nimport { BaseChannel } from '../src/base_channel.js'\nimport { PresenceManager } from '../src/presence_manager.js'\nimport type { SocketUpgradeContextRunner } from '../src/socket_upgrader.js'\nimport type { SocketConfig, SocketHttpMiddleware } from '../src/types.js'\n\ndeclare module '@adonisjs/core/types' {\n interface ContainerBindings {\n 'socket': SocketService\n 'socket.router': ChannelRouter\n 'socket.presence': PresenceManager\n }\n}\n\nexport default class SocketProvider {\n constructor(protected app: ApplicationService) {}\n\n /**\n * Registers the bindings in the container.\n */\n register(): void {\n this.app.container.singleton('socket.router', () => {\n return new ChannelRouter(\n (channel) => this.app.container.make(channel),\n () => {\n const resolver = this.app.container.createResolver()\n\n return async (Middleware, ctx, next) => {\n const instance = await resolver.make(Middleware)\n await resolver.call(instance, 'handle', [ctx, next])\n }\n }\n )\n })\n\n this.app.container.singleton('socket.presence', () => {\n return new PresenceManager()\n })\n\n this.app.container.singleton('socket', () => {\n return new SocketService()\n })\n }\n\n /**\n * Boots the provider.\n */\n async boot(): Promise<void> {\n const router = await this.app.container.make('socket.router')\n\n // Discover and register channel classes.\n await this.#registerChannels(router)\n }\n\n /**\n * Called when the app is ready and the HTTP server is running.\n */\n async ready(): Promise<void> {\n const socket = await this.app.container.make('socket')\n const router = await this.app.container.make('socket.router')\n const presence = await this.app.container.make('socket.presence')\n const logger = await this.#resolveLogger()\n const config = this.app.config.get<SocketConfig>('socket', {})\n\n socket.setPresenceManager(presence)\n\n logger.info('router has %d channels registered', router.size)\n\n const server = await this.app.container.make('server')\n const httpServer = server.getNodeServer()\n\n if (!httpServer) {\n const error = new Error('HTTP server not available.')\n socket.markFailed(error)\n logger.warn('HTTP server not available; socket server was not started')\n return\n }\n\n try {\n await socket.boot(\n httpServer,\n config,\n router,\n logger,\n this.#createUpgradeContextRunner(config, server)\n )\n logger.info('server started')\n } catch (error) {\n socket.markFailed(error)\n throw error\n }\n }\n\n /**\n * Performs a clean shutdown.\n */\n async shutdown(): Promise<void> {\n const socket = await this.app.container.make('socket')\n await socket.close()\n }\n\n /**\n * Resolves the AdonisJS logger and creates a child logger for the socket context.\n */\n async #resolveLogger(): Promise<Logger> {\n const logger = await this.app.container.make('logger')\n return logger.child({ module: 'socket' })\n }\n\n /**\n * Creates an AdonisJS HTTP context for WebSocket upgrade requests.\n */\n #createUpgradeContextRunner(\n config: SocketConfig,\n server: AdonisServer\n ): SocketUpgradeContextRunner {\n const middleware = config.websocket?.middleware ?? []\n\n return async (request, handler, shortCircuitBeforeMiddleware) => {\n const response = new ServerResponse(request)\n const adonisRequest = server.createRequest(request, response)\n const adonisResponse = server.createResponse(request, response)\n const httpContext = server.createHttpContext(\n adonisRequest,\n adonisResponse,\n this.app.container.createResolver()\n )\n\n const earlyResult = await shortCircuitBeforeMiddleware?.(httpContext)\n if (earlyResult !== undefined) {\n return earlyResult\n }\n\n return this.#runUpgradeMiddleware(server, middleware, httpContext, handler)\n }\n }\n\n /**\n * Runs middleware attached to WebSocket upgrade requests.\n */\n async #runUpgradeMiddleware<Result>(\n server: AdonisServer,\n middleware: NonNullable<NonNullable<SocketConfig['websocket']>['middleware']>,\n httpContext: HttpContext,\n handler: (httpContext: HttpContext) => Promise<Result>\n ): Promise<Result> {\n if (middleware.length === 0) {\n return handler(httpContext)\n }\n\n const middlewareClasses: MiddlewareAsClass[] = await Promise.all(\n middleware.map(async (one): Promise<MiddlewareAsClass> => {\n if (one.prototype?.handle) {\n return one as MiddlewareAsClass\n }\n\n const moduleExports = await (one as Exclude<SocketHttpMiddleware, MiddlewareAsClass>)()\n return moduleExports.default\n })\n )\n\n let outcome: { value: Result } | undefined\n\n await server\n .pipeline(middlewareClasses)\n .errorHandler((error) => {\n throw error\n })\n .finalHandler(async () => {\n outcome = { value: await handler(httpContext) }\n })\n .run(httpContext)\n\n if (!outcome) {\n throw new Error('WebSocket upgrade middleware must call next()')\n }\n\n return outcome.value\n }\n\n /**\n * Scans and registers channel classes.\n */\n async #registerChannels(router: ChannelRouter): Promise<void> {\n const logger = await this.#resolveLogger()\n\n let generated: { socketChannels?: unknown }\n try {\n generated = await this.app.import('#generated/socket_channels')\n } catch (error) {\n throw new Error('Failed to load generated socket channels', { cause: error })\n }\n\n if (!Array.isArray(generated.socketChannels)) {\n throw new Error('Generated socket channel manifest must export a socketChannels array')\n }\n\n for (const [index, channelClass] of generated.socketChannels.entries()) {\n const source = `generated channel at index ${index}`\n if (\n typeof channelClass !== 'function' ||\n !(channelClass.prototype instanceof BaseChannel) ||\n !channelClass.pattern\n ) {\n throw new Error(`Socket channel ${source} must default export a BaseChannel with a pattern`)\n }\n\n try {\n router.register(channelClass)\n } catch (error) {\n throw new Error(`Failed to register socket channel from ${source}`, { cause: error })\n }\n\n logger.info('registered channel: %s', channelClass.pattern)\n }\n\n logger.info('total channels registered: %d', router.size)\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IncomingMessage } from 'node:http'\nimport type { Server as HttpServer } from 'node:http'\nimport type { Logger } from '@adonisjs/logger'\nimport Emittery from 'emittery'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport type { RawData } from 'ws'\nimport type {\n AuthenticatedSocket,\n SocketConfig,\n SocketEvents,\n ChannelAck,\n RawSocket,\n SocketHealthSnapshot,\n SocketServiceStatus,\n} from './types.js'\nimport type { SocketUpgradeContextRunner } from './socket_upgrader.js'\nimport type { ChannelMessage, ServerProtocolMessage } from './shared_types.js'\nimport type { ChannelRouter } from './channel_router.js'\nimport type { PresenceManager } from './presence_manager.js'\nimport { ChannelSubscriptions, type ChannelSubscriptionLimits } from './channel_subscriptions.js'\nimport { Message, type TransportMessage } from './protocol/message.js'\nimport { MessageQueue } from './message_queue.js'\nimport { Reply } from './protocol/reply.js'\nimport type { SocketEmission, SocketEmissionSink } from './broadcasting.js'\nimport { SocketFake } from './fake_socket.js'\nimport { SocketBus } from './socket_bus.js'\nimport { PresenceSocketFrame, type SerializablePresenceSocket } from './presence_socket_frame.js'\nimport {\n SocketUpgrader,\n type AcceptedUpgrade,\n type SocketUpgradeHandler,\n} from './socket_upgrader.js'\nimport { parseDuration, type Duration } from './duration.js'\nimport { SocketResponseError } from './base_channel.js'\nimport {\n broadcastChannel,\n channelMessageChannel,\n connectChannel,\n disconnectChannel,\n subscribeChannel,\n unsubscribeChannel,\n} from './tracing_channels.js'\nimport type {\n SocketBroadcastMessage,\n SocketChannelMessage,\n SocketSubscribeMessage,\n SocketUnsubscribeMessage,\n} from './types/tracing_channels.js'\n\nconst DEFAULT_PING_INTERVAL = 25_000\nconst DEFAULT_PING_TIMEOUT = 5_000\nconst DEFAULT_MAX_PAYLOAD = 1024 * 1024\nconst DEFAULT_MAX_QUEUED_MESSAGES = 100\nconst DEFAULT_MAX_MESSAGES_PER_INTERVAL = 1000\nconst DEFAULT_MESSAGE_RATE_INTERVAL = 1000\nconst DEFAULT_MAX_BUFFERED_AMOUNT = 16 * 1024 * 1024\nconst DEFAULT_MAX_OUTBOUND_PAYLOAD = 1024 * 1024\nconst DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET = 100\nconst DEFAULT_MAX_CHANNEL_NAME_LENGTH = 255\nconst CLOSE_POLICY_VIOLATION = 1008\nconst CLOSE_MESSAGE_TOO_BIG = 1009\nconst CLOSE_OUTBOUND_BUFFER_LIMIT = 'Socket outbound buffer limit exceeded'\nconst CLOSE_OUTBOUND_MESSAGE_TOO_BIG = 'Socket outbound message too big'\n\ninterface InboundMessageConfig {\n maxPayload: number\n maxQueuedMessages: number\n maxMessagesPerInterval: number\n messageRateInterval: number\n subscriptionLimits: ChannelSubscriptionLimits\n}\n\ninterface OutboundMessageConfig {\n maxBufferedAmount: number\n maxOutboundPayload: number\n}\n\ninterface SocketMessageRate {\n count: number\n intervalStartedAt: number\n}\n\nfunction serializeFrame(frame: ServerProtocolMessage): string {\n return JSON.stringify(frame)\n}\n\nfunction sendFrame(\n connection: WebSocket,\n frame: ServerProtocolMessage,\n config: OutboundMessageConfig\n): boolean {\n const serializedFrame = serializeFrame(frame)\n return sendSerializedFrameWithBackpressure(connection, serializedFrame, config)\n}\n\nfunction sendSerializedFrameWithBackpressure(\n connection: WebSocket,\n serializedFrame: string,\n config: OutboundMessageConfig\n): boolean {\n if (connection.readyState !== WebSocket.OPEN) {\n return false\n }\n\n const payloadSize = Buffer.byteLength(serializedFrame)\n if (payloadSize > config.maxOutboundPayload) {\n closeConnection(connection, CLOSE_MESSAGE_TOO_BIG, CLOSE_OUTBOUND_MESSAGE_TOO_BIG)\n return false\n }\n\n if (connection.bufferedAmount + payloadSize > config.maxBufferedAmount) {\n closeConnection(connection, CLOSE_POLICY_VIOLATION, CLOSE_OUTBOUND_BUFFER_LIMIT)\n return false\n }\n\n connection.send(serializedFrame)\n return true\n}\n\nfunction parsePositiveInteger(name: string, value: number | undefined, fallback: number): number {\n if (value === undefined) {\n return fallback\n }\n\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(`${name} must be a positive integer`)\n }\n\n return value\n}\n\nfunction resolveHeartbeatConfig(\n config: { pingInterval?: Duration; pingTimeout?: Duration } | undefined\n): { interval: number; timeout: number } | null {\n const pingInterval = parseDuration('websocket.pingInterval', config?.pingInterval)\n const pingTimeout = parseDuration('websocket.pingTimeout', config?.pingTimeout)\n\n if (pingInterval === undefined && pingTimeout === undefined) {\n return null\n }\n\n return {\n interval: pingInterval ?? DEFAULT_PING_INTERVAL,\n timeout: pingTimeout ?? DEFAULT_PING_TIMEOUT,\n }\n}\n\nfunction resolveInboundMessageConfig(\n config:\n | {\n maxPayload?: number\n maxQueuedMessages?: number\n maxMessagesPerInterval?: number\n messageRateInterval?: Duration\n maxSubscriptionsPerSocket?: number\n maxChannelNameLength?: number\n }\n | undefined\n): InboundMessageConfig {\n const messageRateInterval =\n parseDuration('websocket.messageRateInterval', config?.messageRateInterval) ??\n DEFAULT_MESSAGE_RATE_INTERVAL\n\n return {\n maxPayload: parsePositiveInteger(\n 'websocket.maxPayload',\n config?.maxPayload,\n DEFAULT_MAX_PAYLOAD\n ),\n maxQueuedMessages: parsePositiveInteger(\n 'websocket.maxQueuedMessages',\n config?.maxQueuedMessages,\n DEFAULT_MAX_QUEUED_MESSAGES\n ),\n maxMessagesPerInterval: parsePositiveInteger(\n 'websocket.maxMessagesPerInterval',\n config?.maxMessagesPerInterval,\n DEFAULT_MAX_MESSAGES_PER_INTERVAL\n ),\n messageRateInterval,\n subscriptionLimits: {\n maxSubscriptionsPerSocket: parsePositiveInteger(\n 'websocket.maxSubscriptionsPerSocket',\n config?.maxSubscriptionsPerSocket,\n DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET\n ),\n maxChannelNameLength: parsePositiveInteger(\n 'websocket.maxChannelNameLength',\n config?.maxChannelNameLength,\n DEFAULT_MAX_CHANNEL_NAME_LENGTH\n ),\n },\n }\n}\n\nfunction resolveOutboundMessageConfig(\n config:\n | {\n maxBufferedAmount?: number\n maxOutboundPayload?: number\n }\n | undefined\n): OutboundMessageConfig {\n return {\n maxBufferedAmount: parsePositiveInteger(\n 'websocket.maxBufferedAmount',\n config?.maxBufferedAmount,\n DEFAULT_MAX_BUFFERED_AMOUNT\n ),\n maxOutboundPayload: parsePositiveInteger(\n 'websocket.maxOutboundPayload',\n config?.maxOutboundPayload,\n DEFAULT_MAX_OUTBOUND_PAYLOAD\n ),\n }\n}\n\nfunction getRawDataByteLength(data: RawData): number {\n if (Array.isArray(data)) {\n return data.reduce((total, chunk) => total + chunk.byteLength, 0)\n }\n\n return data.byteLength\n}\n\nfunction closeConnection(connection: WebSocket, code: number, reason: string): void {\n if (connection.readyState === WebSocket.OPEN) {\n connection.close(code, reason)\n }\n}\n\n/**\n * Main service for managing WebSocket connections.\n */\nexport class SocketService<User = unknown> extends Emittery<SocketEvents<User>> {\n #server: WebSocketServer | null = null\n #httpServer: HttpServer | null = null\n #upgradeHandler: SocketUpgradeHandler | null = null\n #sockets = new Map<string, AuthenticatedSocket<User>>()\n #channelSubscriptions: ChannelSubscriptions<User> | null = null\n #presenceManager: PresenceManager | null = null\n #bus: SocketBus | null = null\n #fake: SocketFake | null = null\n #deliverySink: SocketEmissionSink = {\n dispatch: (emission) => {\n this.#deliverBroadcast(emission)\n },\n }\n #broadcastSink: SocketEmissionSink = this.#deliverySink\n #status: SocketServiceStatus = 'stopped'\n #lastError: Error | null = null\n #heartbeatInterval: ReturnType<typeof setInterval> | null = null\n #heartbeatTimeouts = new Map<string, ReturnType<typeof setTimeout>>()\n #messageQueue = new MessageQueue()\n #messageRates = new Map<string, SocketMessageRate>()\n #socketFinalizations = new Map<string, Promise<void>>()\n #closePromise: Promise<void> | null = null\n #outboundMessageConfig = resolveOutboundMessageConfig(undefined)\n #logger: Logger | null = null\n\n /**\n * Accesses the underlying ws server.\n */\n get server(): WebSocketServer {\n if (!this.#server) {\n throw new Error('WebSocket server is not initialized. Call boot() first.')\n }\n\n return this.#server\n }\n\n setPresenceManager(presenceManager: PresenceManager): void {\n this.#presenceManager = presenceManager\n this.#channelSubscriptions?.setPresenceManager(presenceManager)\n this.#configurePresenceFetcher()\n }\n\n async boot(\n httpServer: HttpServer,\n config: SocketConfig<User>,\n channelRouter: ChannelRouter,\n logger: Logger,\n runWithHttpContext: SocketUpgradeContextRunner\n ): Promise<void> {\n this.#closePromise = null\n this.#status = 'starting'\n this.#lastError = null\n this.#logger = logger\n\n const websocketConfig = config.websocket\n const heartbeatConfig = resolveHeartbeatConfig(websocketConfig)\n const inboundMessageConfig = resolveInboundMessageConfig(websocketConfig)\n this.#outboundMessageConfig = resolveOutboundMessageConfig(websocketConfig)\n\n this.#channelSubscriptions = new ChannelSubscriptions(\n this,\n channelRouter,\n logger,\n this.#presenceManager ?? undefined,\n inboundMessageConfig.subscriptionLimits\n )\n\n try {\n if (config.transport) {\n this.#bus = new SocketBus(config.transport, {\n channel: (message) => {\n this.#traceBroadcast(\n {\n target: 'channel',\n channel: message.channel,\n event: message.event,\n via: 'bus',\n except: message.except,\n },\n () =>\n this.#emitToChannelLocally(\n message.channel,\n message.event,\n message.data,\n message.except\n )\n )\n },\n broadcast: (message) => {\n this.#traceBroadcast({ target: 'global', event: message.event, via: 'bus' }, () =>\n this.#broadcastLocally(message.event, message.data)\n )\n },\n presenceSockets: (channel) => {\n return this.#getLocalPresenceSockets(channel)\n },\n })\n\n await this.#bus.start()\n this.#configurePresenceFetcher()\n }\n\n const websocketServer = new WebSocketServer({\n noServer: true,\n maxPayload: inboundMessageConfig.maxPayload,\n })\n\n this.#server = websocketServer\n this.#httpServer = httpServer\n const upgrader = new SocketUpgrader<User>(\n websocketServer,\n websocketConfig,\n runWithHttpContext,\n (message, error) => this.#warn(message, error)\n )\n\n this.#upgradeHandler = (request, socket, head) => {\n upgrader\n .handle(request, socket, head, (connection, upgradeRequest, accepted) => {\n this.#handleConnection(connection, upgradeRequest, accepted, inboundMessageConfig)\n })\n .catch((error) => {\n this.#warn('failed to upgrade socket connection: %s', error)\n SocketUpgrader.reject(socket, 500, 'Internal Server Error')\n })\n }\n httpServer.on('upgrade', this.#upgradeHandler)\n\n this.#startHeartbeat(heartbeatConfig)\n this.#status = 'ready'\n } catch (error) {\n this.#lastError = error instanceof Error ? error : new Error('Socket service boot failed')\n this.#status = 'failed'\n await this.close()\n throw error\n }\n }\n\n #handleConnection(\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User>,\n inboundMessageConfig: InboundMessageConfig\n ): void {\n if (this.#status !== 'ready') {\n connection.terminate()\n return\n }\n\n const socket = this.#wrapSocket(connection, request, upgrade)\n\n connectChannel.traceSync(\n () => {\n this.#sockets.set(socket.id, socket)\n this.#emitLifecycleEvent('connect', { socket })\n },\n { socketId: socket.id }\n )\n\n connection.on('error', () => {})\n\n connection.on('message', (data) => {\n if (getRawDataByteLength(data) > inboundMessageConfig.maxPayload) {\n closeConnection(connection, CLOSE_MESSAGE_TOO_BIG, 'Message too big')\n return\n }\n\n if (!this.#acceptMessageRate(socket.id, inboundMessageConfig)) {\n closeConnection(connection, CLOSE_POLICY_VIOLATION, 'Socket message rate limit exceeded')\n return\n }\n\n const message = Message.fromTransport(data.toString())\n\n if (message.type === 'ping') {\n sendFrame(\n socket.raw.connection,\n { id: message.id, type: 'pong' },\n this.#outboundMessageConfig\n )\n return\n }\n\n const enqueued = this.#messageQueue.enqueue(\n socket.id,\n async () => {\n await this.#handleMessage(socket, message).catch((error) => {\n try {\n this.#logger?.warn('unexpected socket message failure: %s', error)\n } catch {\n // Logging must never prevent a protocol response.\n }\n\n sendFrame(\n connection,\n message.id === undefined\n ? { type: 'error', error: 'Unexpected socket error' }\n : Reply.error(message.id, 'Unexpected socket error').toFrame(),\n this.#outboundMessageConfig\n )\n })\n },\n { maxDepth: inboundMessageConfig.maxQueuedMessages }\n )\n\n if (!enqueued) {\n closeConnection(connection, CLOSE_POLICY_VIOLATION, 'Socket message queue limit exceeded')\n }\n })\n\n connection.on('pong', () => {\n this.#clearHeartbeatTimeout(socket.id)\n })\n\n connection.on('close', () => {\n void Promise.resolve()\n .then(() => this.#finalizeSocket(socket))\n .catch((error) => this.markFailed(error))\n })\n }\n\n #finalizeSocket(socket: AuthenticatedSocket<User>): Promise<void> {\n const pending = this.#socketFinalizations.get(socket.id)\n if (pending) {\n return pending\n }\n\n if (!this.#sockets.has(socket.id)) {\n return Promise.resolve()\n }\n\n const finalization = disconnectChannel\n .tracePromise(\n async () => {\n this.#clearHeartbeatTimeout(socket.id)\n this.#messageRates.delete(socket.id)\n await this.#messageQueue.drain(socket.id)\n this.#messageQueue.delete(socket.id)\n await this.#channelSubscriptions?.leaveAll(socket)\n this.#channelSubscriptions?.deleteSocket(socket.id)\n this.#sockets.delete(socket.id)\n this.#emitLifecycleEvent('disconnect', { socket, reason: 'close' })\n },\n {\n socketId: socket.id,\n reason: 'close',\n subscriptions: this.#channelSubscriptions?.subscriptionCountFor(socket.id) ?? 0,\n }\n )\n .finally(() => {\n this.#socketFinalizations.delete(socket.id)\n })\n\n this.#socketFinalizations.set(socket.id, finalization)\n return finalization\n }\n\n async #handleMessage(\n socket: AuthenticatedSocket<User>,\n message: TransportMessage\n ): Promise<void> {\n if (!message.valid) {\n sendFrame(socket.raw.connection, message.toRejectionFrame(), this.#outboundMessageConfig)\n return\n }\n\n switch (message.type) {\n case 'ping':\n return\n case 'subscribe': {\n const traceMessage: SocketSubscribeMessage = {\n socketId: socket.id,\n channel: message.channel,\n }\n\n await subscribeChannel.tracePromise(async () => {\n const result = await this.#channelSubscriptions?.subscribe(socket, message.channel)\n\n traceMessage.created = result?.created ?? false\n traceMessage.ok = result?.ack.ok ?? false\n if (!result?.ack.ok) {\n traceMessage.error = result?.ack.error ?? 'Socket service is not initialized'\n }\n\n if (result?.created) {\n this.#emitLifecycleEvent('subscribe', { socket, channel: message.channel })\n }\n\n sendFrame(\n socket.raw.connection,\n Reply.fromSubscribeResult(message.id, result).toFrame(),\n this.#outboundMessageConfig\n )\n }, traceMessage)\n return\n }\n case 'unsubscribe': {\n const traceMessage: SocketUnsubscribeMessage = {\n socketId: socket.id,\n channel: message.channel,\n }\n\n await unsubscribeChannel.tracePromise(async () => {\n traceMessage.removed =\n (await this.#channelSubscriptions?.leave(socket, message.channel)) ?? false\n traceMessage.ok = true\n this.#emitLifecycleEvent('unsubscribe', { socket, channel: message.channel })\n sendFrame(\n socket.raw.connection,\n Reply.ok(message.id).toFrame(),\n this.#outboundMessageConfig\n )\n }, traceMessage)\n return\n }\n case 'message':\n case 'whisper': {\n await this.#handleChannelFrame(socket, message)\n return\n }\n }\n }\n\n async #handleChannelFrame(\n socket: AuthenticatedSocket<User>,\n message: Extract<TransportMessage, { type: 'message' | 'whisper' }>\n ): Promise<void> {\n const payload = message.toChannelMessage()\n const traceMessage: SocketChannelMessage = {\n socketId: socket.id,\n channel: payload.channel,\n event: payload.event,\n }\n\n await channelMessageChannel.tracePromise(async () => {\n const ack = await this.#handleChannelPayload(socket, message.type, payload)\n traceMessage.ok = ack.ok\n if (!ack.ok) {\n traceMessage.error = ack.error ?? 'Handler error'\n }\n\n sendFrame(\n socket.raw.connection,\n Reply.fromChannelAck(message.id, ack).toFrame(),\n this.#outboundMessageConfig\n )\n }, traceMessage)\n }\n\n async #handleChannelPayload(\n socket: AuthenticatedSocket<User>,\n type: 'message' | 'whisper',\n payload: ChannelMessage\n ): Promise<ChannelAck> {\n if (typeof payload.channel !== 'string' || typeof payload.event !== 'string') {\n return { ok: false, error: `Invalid channel ${type}` }\n }\n\n if (type === 'message') {\n return this.#channelSubscriptions!.handleMessage(socket, payload)\n }\n\n return this.#channelSubscriptions!.relayWhisper(socket, payload)\n }\n\n #wrapSocket(\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User>\n ): AuthenticatedSocket<User> {\n const raw: RawSocket = {\n id: randomUUID(),\n data: {},\n connection,\n request,\n httpContext: upgrade.httpContext,\n }\n\n return {\n id: raw.id,\n user: upgrade.user,\n\n getUserOrFail() {\n if (this.user === undefined) {\n throw new SocketResponseError('Unauthorized')\n }\n\n return this.user\n },\n\n emit: (event, data) => {\n this.#sendSerializedEventFrame(connection, serializeFrame({ type: 'event', event, data }))\n },\n\n disconnect() {\n connection.close()\n },\n\n raw,\n }\n }\n\n to(channel: string) {\n return {\n emit: (event: string, data: unknown) => {\n this.#broadcastSink.dispatch({ target: 'channel', channel, event, data })\n },\n except: (socketId: string) => ({\n emit: (event: string, data: unknown) => {\n this.#broadcastSink.dispatch({\n target: 'channel',\n channel,\n event,\n data,\n except: [socketId],\n })\n },\n }),\n }\n }\n\n broadcast(event: string, data: unknown): void {\n this.#broadcastSink.dispatch({ target: 'global', event, data })\n }\n\n #deliverBroadcast(emission: SocketEmission): void {\n switch (emission.target) {\n case 'channel': {\n const channel = emission.channel\n const serializedFrame = serializeFrame({\n type: 'event',\n channel,\n event: emission.event,\n data: emission.data,\n })\n this.#bus?.publishChannel(channel, emission.event, emission.data, emission.except)\n\n const traceMessage: SocketBroadcastMessage = {\n target: 'channel',\n channel,\n event: emission.event,\n via: 'local',\n }\n if (emission.except) {\n traceMessage.except = emission.except\n }\n\n this.#traceBroadcast(traceMessage, () =>\n this.#emitToChannelLocally(\n channel,\n emission.event,\n emission.data,\n emission.except,\n serializedFrame\n )\n )\n return\n }\n case 'global': {\n const serializedFrame = serializeFrame({\n type: 'event',\n event: emission.event,\n data: emission.data,\n })\n this.#bus?.publishBroadcast(emission.event, emission.data)\n this.#traceBroadcast({ target: 'global', event: emission.event, via: 'local' }, () =>\n this.#broadcastLocally(emission.event, emission.data, serializedFrame)\n )\n }\n }\n }\n\n #traceBroadcast(message: SocketBroadcastMessage, deliver: () => number): void {\n broadcastChannel.traceSync(() => {\n message.delivered = deliver()\n }, message)\n }\n\n #sendSerializedEventFrame(connection: WebSocket, serializedFrame: string): boolean {\n return sendSerializedFrameWithBackpressure(\n connection,\n serializedFrame,\n this.#outboundMessageConfig\n )\n }\n\n #emitToChannelLocally(\n channel: string,\n event: string,\n data: unknown,\n except: string[] = [],\n serializedFrame = serializeFrame({ type: 'event', channel, event, data })\n ): number {\n let delivered = 0\n\n for (const socketId of this.#channelSubscriptions?.getSocketIds(channel) ?? []) {\n if (except.includes(socketId)) {\n continue\n }\n\n const socket = this.#sockets.get(socketId)\n if (socket && this.#sendSerializedEventFrame(socket.raw.connection, serializedFrame)) {\n delivered += 1\n }\n }\n\n return delivered\n }\n\n #broadcastLocally(\n event: string,\n data: unknown,\n serializedFrame = serializeFrame({ type: 'event', event, data })\n ): number {\n let delivered = 0\n\n for (const socket of this.#sockets.values()) {\n if (this.#sendSerializedEventFrame(socket.raw.connection, serializedFrame)) {\n delivered += 1\n }\n }\n\n return delivered\n }\n\n #configurePresenceFetcher(): void {\n if (!this.#presenceManager || !this.#bus) {\n return\n }\n\n this.#presenceManager.setSocketFetcher(async (channel) => {\n return [\n ...this.#presenceManager!.getLocalSockets(channel),\n ...(await this.#bus!.fetchPresenceSockets(channel)),\n ]\n })\n }\n\n #getLocalPresenceSockets(channel: string): SerializablePresenceSocket[] {\n return (this.#presenceManager?.getLocalSockets(channel) ?? []).map((socket) => {\n return PresenceSocketFrame.fromSocket(channel, socket).toTransport()\n })\n }\n\n getSocket(socketId: string): AuthenticatedSocket<User> | undefined {\n return this.#sockets.get(socketId)\n }\n\n get connectionsCount(): number {\n return this.#sockets.size\n }\n\n get status(): SocketServiceStatus {\n return this.#status\n }\n\n get ready(): boolean {\n return this.#status === 'ready' && Boolean(this.#server)\n }\n\n fake(): SocketFake {\n const fake = new SocketFake(() => {\n if (this.#fake === fake) {\n this.restore()\n }\n })\n\n this.#fake = fake\n this.#broadcastSink = fake\n return fake\n }\n\n restore(): void {\n this.#fake = null\n this.#broadcastSink = this.#deliverySink\n }\n\n markFailed(error: unknown): void {\n this.#lastError = error instanceof Error ? error : new Error('Socket service failed')\n this.#status = 'failed'\n }\n\n #warn(message: string, error: unknown): void {\n try {\n this.#logger?.warn(message, error)\n } catch {\n // Logging must never change socket behavior.\n }\n }\n\n #emitLifecycleEvent<EventName extends keyof SocketEvents<User>>(\n eventName: EventName,\n event: SocketEvents<User>[EventName]\n ): void {\n void this.emit(eventName, event).catch((error) => {\n try {\n this.#logger?.warn('socket %s listener failed: %s', eventName, error)\n } catch {\n // Lifecycle observers and their reporting must not affect the socket service.\n }\n })\n }\n\n health(): SocketHealthSnapshot {\n return {\n status: this.#status,\n ready: this.ready,\n connections: this.#sockets.size,\n channels: this.#channelSubscriptions?.channelsCount ?? 0,\n ...(this.#lastError ? { lastError: this.#lastError.message } : {}),\n }\n }\n\n #startHeartbeat(config: { interval: number; timeout: number } | null): void {\n this.#stopHeartbeat()\n\n if (!config) {\n return\n }\n\n this.#heartbeatInterval = setInterval(() => {\n this.#pingSockets(config.timeout)\n }, config.interval)\n }\n\n #pingSockets(timeout: number): void {\n for (const socket of this.#sockets.values()) {\n const { connection } = socket.raw\n\n if (connection.readyState !== WebSocket.OPEN) {\n this.#clearHeartbeatTimeout(socket.id)\n continue\n }\n\n if (this.#heartbeatTimeouts.has(socket.id)) {\n continue\n }\n\n const timeoutId = setTimeout(() => {\n this.#heartbeatTimeouts.delete(socket.id)\n connection.terminate()\n }, timeout)\n\n this.#heartbeatTimeouts.set(socket.id, timeoutId)\n\n try {\n connection.ping()\n } catch {\n this.#clearHeartbeatTimeout(socket.id)\n connection.terminate()\n }\n }\n }\n\n #clearHeartbeatTimeout(socketId: string): void {\n const timeout = this.#heartbeatTimeouts.get(socketId)\n\n if (!timeout) {\n return\n }\n\n clearTimeout(timeout)\n this.#heartbeatTimeouts.delete(socketId)\n }\n\n #stopHeartbeat(): void {\n if (this.#heartbeatInterval) {\n clearInterval(this.#heartbeatInterval)\n this.#heartbeatInterval = null\n }\n\n for (const timeout of this.#heartbeatTimeouts.values()) {\n clearTimeout(timeout)\n }\n\n this.#heartbeatTimeouts.clear()\n }\n\n #acceptMessageRate(socketId: string, config: InboundMessageConfig): boolean {\n const now = Date.now()\n const rate = this.#messageRates.get(socketId)\n\n if (!rate || now - rate.intervalStartedAt >= config.messageRateInterval) {\n this.#messageRates.set(socketId, { count: 1, intervalStartedAt: now })\n return true\n }\n\n if (rate.count >= config.maxMessagesPerInterval) {\n return false\n }\n\n rate.count += 1\n return true\n }\n\n #cleanup(): void {\n this.#stopHeartbeat()\n this.#sockets.clear()\n this.#messageQueue.clear()\n this.#messageRates.clear()\n this.#socketFinalizations.clear()\n this.#channelSubscriptions?.clear()\n }\n\n close(): Promise<void> {\n if (!this.#closePromise) {\n this.#closePromise = this.#close()\n }\n\n return this.#closePromise\n }\n\n async #close(): Promise<void> {\n const server = this.#server\n const bus = this.#bus\n const httpServer = this.#httpServer\n const upgradeHandler = this.#upgradeHandler\n if (this.#status !== 'failed') {\n this.#status = 'stopping'\n }\n\n this.#server = null\n this.#httpServer = null\n this.#upgradeHandler = null\n if (httpServer && upgradeHandler) {\n httpServer.off('upgrade', upgradeHandler)\n }\n\n const serverClose = server\n ? new Promise<unknown | null>((resolve) => {\n server.close((error) => resolve(error ?? null))\n })\n : Promise.resolve(null)\n\n this.#stopHeartbeat()\n const sockets = [...this.#sockets.values()]\n for (const socket of sockets) {\n socket.raw.connection.terminate()\n }\n\n const errors: unknown[] = []\n const finalizations = sockets.map((socket) => {\n return Promise.resolve().then(() => this.#finalizeSocket(socket))\n })\n const results = await Promise.allSettled(finalizations)\n for (const result of results) {\n if (result.status === 'rejected') {\n errors.push(result.reason)\n }\n }\n\n this.#cleanup()\n this.#presenceManager?.setSocketFetcher(null)\n this.#bus = null\n\n try {\n await bus?.close()\n } catch (error) {\n errors.push(error)\n }\n\n const serverCloseError = await serverClose\n if (serverCloseError) {\n errors.push(serverCloseError)\n }\n\n if (errors.length > 0) {\n const error =\n errors.length === 1 && errors[0] instanceof Error\n ? errors[0]\n : new AggregateError(errors, 'Socket service shutdown failed')\n this.markFailed(error)\n throw error\n }\n\n if (this.#status !== 'failed') {\n this.#status = 'stopped'\n }\n }\n}\n","import type { BaseChannel } from './base_channel.js'\n\nexport interface StoredChannelSubscription {\n channelName: string\n instance: BaseChannel<any, any>\n paramValues: string[]\n}\n\n/**\n * Stores durable Channel subscriptions and keeps Socket/Channel indexes in sync.\n */\nexport class ChannelSubscriptionStorage {\n #subscriptions = new Map<string, Map<string, StoredChannelSubscription>>()\n #subscribers = new Map<string, Set<string>>()\n\n has(socketId: string, channelName: string): boolean {\n return this.#subscriptions.get(socketId)?.has(channelName) ?? false\n }\n\n get(socketId: string, channelName: string): StoredChannelSubscription | undefined {\n return this.#subscriptions.get(socketId)?.get(channelName)\n }\n\n set(socketId: string, channelName: string, subscription: StoredChannelSubscription): void {\n if (!this.#subscriptions.has(socketId)) {\n this.#subscriptions.set(socketId, new Map())\n }\n\n this.#subscriptions.get(socketId)!.set(channelName, subscription)\n\n if (!this.#subscribers.has(channelName)) {\n this.#subscribers.set(channelName, new Set())\n }\n\n this.#subscribers.get(channelName)!.add(socketId)\n }\n\n delete(socketId: string, channelName: string): void {\n const subscriptions = this.#subscriptions.get(socketId)\n\n if (!subscriptions) {\n return\n }\n\n subscriptions.delete(channelName)\n if (subscriptions.size === 0) {\n this.#subscriptions.delete(socketId)\n }\n\n const subscribers = this.#subscribers.get(channelName)\n subscribers?.delete(socketId)\n if (subscribers?.size === 0) {\n this.#subscribers.delete(channelName)\n }\n }\n\n deleteSocket(socketId: string): void {\n for (const channelName of this.channelNamesFor(socketId)) {\n this.delete(socketId, channelName)\n }\n }\n\n channelNamesFor(socketId: string): string[] {\n return [...(this.#subscriptions.get(socketId)?.keys() ?? [])]\n }\n\n countForSocket(socketId: string): number {\n return this.#subscriptions.get(socketId)?.size ?? 0\n }\n\n socketIdsFor(channelName: string): string[] {\n return [...(this.#subscribers.get(channelName) ?? [])]\n }\n\n get channelsCount(): number {\n return this.#subscribers.size\n }\n\n clear(): void {\n this.#subscriptions.clear()\n this.#subscribers.clear()\n }\n}\n","import type { Logger } from '@adonisjs/logger'\nimport { SocketResponseError } from './base_channel.js'\nimport type { BaseChannel } from './base_channel.js'\nimport {\n ChannelSubscriptionStorage,\n type StoredChannelSubscription,\n} from './channel_subscription_storage.js'\nimport type { ChannelRouter } from './channel_router.js'\nimport type { PresenceData, PresenceManager } from './presence_manager.js'\nimport type { SocketService } from './socket_service.js'\nimport type { AuthenticatedSocket, ChannelAck, ChannelMessage } from './types.js'\n\ninterface AuthorizedChannel<User> {\n instance: BaseChannel<User>\n params: Record<string, string>\n paramValues: string[]\n presenceData: Record<string, unknown> | PresenceData | null\n}\n\nexport interface ChannelSubscribeAck {\n ok: boolean\n presenceData?: Record<string, unknown> | PresenceData | null\n error?: string\n}\n\nexport interface ChannelSubscribeResult {\n ack: ChannelSubscribeAck\n created: boolean\n}\n\nexport interface ChannelSubscriptionLimits {\n maxSubscriptionsPerSocket: number\n maxChannelNameLength: number\n}\n\n/**\n * Durable channel subscriptions for sockets.\n */\nexport class ChannelSubscriptions<User = unknown> {\n #storage = new ChannelSubscriptionStorage()\n #channelOperations = new Map<string, Promise<void>>()\n\n static #serializePresenceData(presenceData: PresenceData): Record<string, unknown> {\n return {\n ...presenceData,\n users: presenceData.users.map((user) => ({\n ...user,\n joinedAt: user.joinedAt.toISOString(),\n })),\n }\n }\n\n constructor(\n private socketService: SocketService<User>,\n private channelRouter: ChannelRouter,\n private logger: Logger,\n private presenceManager?: PresenceManager,\n private limits?: ChannelSubscriptionLimits\n ) {}\n\n setPresenceManager(presenceManager: PresenceManager): void {\n this.presenceManager = presenceManager\n }\n\n async subscribe(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<ChannelSubscribeResult> {\n return this.#subscribe(socket, channelName)\n }\n\n async #subscribe(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<ChannelSubscribeResult> {\n const existing = await this.#refreshExistingSubscription(socket, channelName)\n if (existing) {\n return existing\n }\n\n if (this.limits && channelName.length > this.limits.maxChannelNameLength) {\n return {\n ack: { ok: false, error: 'Channel name is too long' },\n created: false,\n }\n }\n\n if (\n this.limits &&\n this.#storage.channelNamesFor(socket.id).length >= this.limits.maxSubscriptionsPerSocket\n ) {\n return {\n ack: { ok: false, error: 'Socket subscription limit exceeded' },\n created: false,\n }\n }\n\n const result = await this.channelRouter.authorize(socket, channelName)\n\n if (!result.success) {\n if ('cause' in result && !(result.cause instanceof SocketResponseError)) {\n this.#warn(`failed to authorize channel \"${channelName}\": %s`, result.cause)\n }\n\n return {\n ack: { ok: false, error: result.error },\n created: false,\n }\n }\n\n if (this.#usesPresence(result.instance)) {\n return this.#withChannelOperation(channelName, async () => {\n const concurrentSubscription = await this.#refreshExistingSubscription(socket, channelName)\n if (concurrentSubscription) {\n return concurrentSubscription\n }\n\n return this.#completeSubscription(socket, channelName, result)\n })\n }\n\n return this.#completeSubscription(socket, channelName, result)\n }\n\n async #completeSubscription(\n socket: AuthenticatedSocket<User>,\n channelName: string,\n result: AuthorizedChannel<User>\n ): Promise<ChannelSubscribeResult> {\n result.instance.$setContext(\n this.socketService,\n channelName,\n result.params,\n this.presenceManager\n )\n\n let presenceData: Record<string, unknown> | PresenceData | null = result.presenceData\n let presenceSnapshot: PresenceData | null = null\n let presenceJoined = false\n let serializationError: unknown\n\n try {\n if (this.#usesPresence(result.instance)) {\n const presenceInfo = result.instance.$getPresenceInfo(socket)\n const wasPresent = (await this.presenceManager!.snapshot(channelName)).users.some(\n (user) => user.id === presenceInfo.id\n )\n\n const { joinedAt: _joinedAt, ...member } = this.presenceManager!.join(\n channelName,\n socket.raw,\n presenceInfo\n )\n presenceJoined = true\n\n presenceSnapshot = await this.presenceManager!.snapshot(channelName)\n presenceData = presenceSnapshot\n\n try {\n JSON.stringify(presenceData)\n } catch (error) {\n serializationError = error\n throw error\n }\n\n if (!wasPresent) {\n await result.instance.onMemberJoin?.(socket, member, ...result.paramValues)\n }\n await result.instance.onJoin?.(socket, ...result.paramValues)\n } else {\n try {\n JSON.stringify(presenceData)\n } catch (error) {\n serializationError = error\n throw error\n }\n\n await result.instance.onJoin?.(socket, ...result.paramValues)\n }\n\n this.#storage.set(socket.id, channelName, {\n channelName,\n instance: result.instance,\n paramValues: result.paramValues,\n })\n\n if (presenceSnapshot) {\n this.socketService\n .to(channelName)\n .except(socket.id)\n .emit('presence:update', ChannelSubscriptions.#serializePresenceData(presenceSnapshot))\n }\n } catch (error) {\n if (presenceJoined) {\n this.presenceManager!.leave(channelName, socket.raw)\n\n const rollbackData = await this.presenceManager!.snapshot(channelName).catch(() => null)\n if (rollbackData) {\n this.socketService\n .to(channelName)\n .emit('presence:update', ChannelSubscriptions.#serializePresenceData(rollbackData))\n }\n }\n\n this.#storage.delete(socket.id, channelName)\n\n if (serializationError) {\n this.#warn(\n `failed to serialize subscription response for channel \"${channelName}\": %s`,\n serializationError\n )\n } else if (!(error instanceof SocketResponseError)) {\n this.#warn(`failed to join channel \"${channelName}\": %s`, error)\n }\n\n return {\n ack: {\n ok: false,\n error: serializationError\n ? 'Subscription response is not serializable'\n : error instanceof SocketResponseError\n ? error.message\n : 'Join failed',\n },\n created: false,\n }\n }\n\n return {\n ack: { ok: true, presenceData },\n created: true,\n }\n }\n\n async leave(socket: AuthenticatedSocket<User>, channelName: string): Promise<boolean> {\n const subscription = this.#storage.get(socket.id, channelName)\n if (!subscription) {\n return false\n }\n\n this.#storage.delete(socket.id, channelName)\n\n if (this.#usesPresence(subscription.instance)) {\n await this.#withChannelOperation(channelName, () =>\n this.#cleanupAfterLeave(socket, channelName, subscription)\n )\n } else {\n await this.#cleanupAfterLeave(socket, channelName, subscription)\n }\n\n return true\n }\n\n async #cleanupAfterLeave(\n socket: AuthenticatedSocket<User>,\n channelName: string,\n subscription: StoredChannelSubscription\n ): Promise<void> {\n if (this.#usesPresence(subscription.instance)) {\n const presenceUser = this.presenceManager!.getLocalUser(channelName, socket.id)\n this.presenceManager!.leave(channelName, socket.raw)\n\n try {\n const presenceData = await this.presenceManager!.snapshot(channelName)\n\n this.socketService\n .to(channelName)\n .emit('presence:update', ChannelSubscriptions.#serializePresenceData(presenceData))\n\n if (presenceUser && !presenceData.users.some((user) => user.id === presenceUser.id)) {\n const { joinedAt: _joinedAt, ...member } = presenceUser\n await subscription.instance.onMemberLeave?.(socket, member, ...subscription.paramValues)\n }\n } catch (error) {\n this.#warn(`failed to update presence while leaving channel \"${channelName}\": %s`, error)\n }\n }\n\n try {\n await subscription.instance.onLeave?.(socket, ...subscription.paramValues)\n } catch (error) {\n this.#warn(`failed to leave channel \"${channelName}\": %s`, error)\n }\n }\n\n async leaveAll(socket: AuthenticatedSocket<User>): Promise<void> {\n for (const channelName of this.#storage.channelNamesFor(socket.id)) {\n await this.leave(socket, channelName)\n }\n }\n\n async handleMessage(\n socket: AuthenticatedSocket<User>,\n payload: ChannelMessage\n ): Promise<ChannelAck> {\n const subscription = this.#storage.get(socket.id, payload.channel)\n\n if (!subscription) {\n return { ok: false, error: 'Not subscribed' }\n }\n\n try {\n const result = await subscription.instance.$handleMessage(socket, payload.event, payload.data)\n\n try {\n JSON.stringify(result)\n } catch (error) {\n this.#warn(\n `failed to serialize handler response for channel \"${payload.channel}\": %s`,\n error\n )\n return { ok: false, error: 'Handler response is not serializable' }\n }\n\n return { ok: true, data: result }\n } catch (error) {\n if (!(error instanceof SocketResponseError)) {\n this.#warn(`channel handler failed for \"${payload.channel}\": %s`, error)\n }\n\n return {\n ok: false,\n error: error instanceof SocketResponseError ? error.message : 'Handler error',\n }\n }\n }\n\n relayWhisper(socket: AuthenticatedSocket<User>, payload: ChannelMessage): ChannelAck {\n if (!this.#storage.has(socket.id, payload.channel)) {\n return { ok: false, error: 'Not subscribed' }\n }\n\n this.socketService\n .to(payload.channel)\n .except(socket.id)\n .emit(`client:${payload.event}`, payload.data)\n\n return { ok: true }\n }\n\n deleteSocket(socketId: string): void {\n this.#storage.deleteSocket(socketId)\n }\n\n clear(): void {\n this.#storage.clear()\n this.#channelOperations.clear()\n }\n\n getSocketIds(channelName: string): string[] {\n return this.#storage.socketIdsFor(channelName)\n }\n\n subscriptionCountFor(socketId: string): number {\n return this.#storage.countForSocket(socketId)\n }\n\n get channelsCount(): number {\n return this.#storage.channelsCount\n }\n\n #warn(message: string, error: unknown): void {\n try {\n this.logger.warn(message, error)\n } catch {\n // Logging must never change the socket protocol outcome.\n }\n }\n\n async #withChannelOperation<Result>(\n channelName: string,\n operation: () => Promise<Result>\n ): Promise<Result> {\n const previous = this.#channelOperations.get(channelName) ?? Promise.resolve()\n const release = Promise.withResolvers<void>()\n const queued = previous.then(() => release.promise)\n this.#channelOperations.set(channelName, queued)\n\n await previous\n try {\n return await operation()\n } finally {\n release.resolve()\n if (this.#channelOperations.get(channelName) === queued) {\n this.#channelOperations.delete(channelName)\n }\n }\n }\n\n #usesPresence(instance: BaseChannel<any, any>): boolean {\n return Boolean(\n (instance.constructor as typeof BaseChannel).options?.presence && this.presenceManager\n )\n }\n\n async #refreshExistingSubscription(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<ChannelSubscribeResult | null> {\n if (!this.#storage.has(socket.id, channelName)) {\n return null\n }\n\n let presenceData: PresenceData | undefined\n\n try {\n presenceData = await this.#getPresenceData(socket, channelName)\n } catch (error) {\n this.#warn(`failed to refresh subscription for channel \"${channelName}\": %s`, error)\n return {\n ack: { ok: false, error: 'Subscribe failed' },\n created: false,\n }\n }\n\n try {\n JSON.stringify(presenceData)\n } catch (error) {\n this.#warn(\n `failed to serialize subscription response for channel \"${channelName}\": %s`,\n error\n )\n return {\n ack: { ok: false, error: 'Subscription response is not serializable' },\n created: false,\n }\n }\n\n return {\n ack: {\n ok: true,\n presenceData,\n },\n created: false,\n }\n }\n\n async #getPresenceData(\n socket: AuthenticatedSocket<User>,\n channelName: string\n ): Promise<PresenceData | undefined> {\n if (!this.presenceManager?.hasLocal(channelName, socket.id)) {\n return undefined\n }\n\n return this.presenceManager.snapshot(channelName)\n }\n}\n","import type { ChannelAck, ServerProtocolMessage } from '../shared_types.js'\nimport type { ChannelSubscribeResult } from '../channel_subscriptions.js'\n\nconst INVALID_SOCKET_MESSAGE = 'Invalid socket message'\n\nexport class Reply {\n private constructor(\n private id: string | undefined,\n private ok: boolean,\n private data: unknown | undefined,\n private error: string | undefined\n ) {}\n\n static ok(id: string | undefined, data?: unknown): Reply {\n return new Reply(id, true, data, undefined)\n }\n\n static error(id: string | undefined, error: string): Reply {\n return new Reply(id, false, undefined, error)\n }\n\n static invalidMessage(id: string | undefined): ServerProtocolMessage {\n if (id === undefined) {\n return { type: 'error', error: INVALID_SOCKET_MESSAGE }\n }\n\n return Reply.error(id, INVALID_SOCKET_MESSAGE).toFrame()\n }\n\n static fromSubscribeResult(\n id: string | undefined,\n result: ChannelSubscribeResult | undefined\n ): Reply {\n if (!result) {\n return Reply.error(id, 'Socket service is not initialized')\n }\n\n if (!result.ack.ok) {\n return Reply.error(id, result.ack.error ?? 'Subscribe failed')\n }\n\n const data = result.ack.presenceData\n ? {\n presenceData: result.ack.presenceData,\n }\n : undefined\n\n return Reply.ok(id, data)\n }\n\n static fromChannelAck(id: string | undefined, ack: ChannelAck): Reply {\n return ack.ok ? Reply.ok(id, ack.data) : Reply.error(id, ack.error ?? 'Handler error')\n }\n\n toFrame(): Extract<ServerProtocolMessage, { type: 'ack' }> {\n const frame: Extract<ServerProtocolMessage, { type: 'ack' }> = {\n id: this.id,\n type: 'ack',\n ok: this.ok,\n }\n\n if (this.data !== undefined) {\n frame.data = this.data\n }\n\n if (this.error !== undefined) {\n frame.error = this.error\n }\n\n return frame\n }\n}\n","import type {\n ChannelMessage,\n ClientProtocolMessage,\n ServerProtocolMessage,\n} from '../shared_types.js'\nimport { Reply } from './reply.js'\n\ntype ClientMessageType = ClientProtocolMessage['type']\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport abstract class Message {\n abstract readonly valid: boolean\n abstract readonly type: ClientMessageType | 'invalid'\n\n static fromTransport(raw: string): TransportMessage {\n try {\n return Message.fromParsedTransport(JSON.parse(raw))\n } catch {\n return new InvalidMessage(undefined)\n }\n }\n\n private static fromParsedTransport(value: unknown): TransportMessage {\n if (!isRecord(value)) {\n return new InvalidMessage(undefined)\n }\n\n const id = typeof value.id === 'string' ? value.id : undefined\n\n if ('id' in value && typeof value.id !== 'string') {\n return new InvalidMessage(undefined)\n }\n\n if (!isClientMessageType(value.type)) {\n return new InvalidMessage(id)\n }\n\n if (value.type === 'ping') {\n return new PingMessage(id)\n }\n\n if (value.type === 'subscribe' && typeof value.channel === 'string') {\n return new SubscribeMessage(id, value.channel)\n }\n\n if (value.type === 'unsubscribe' && typeof value.channel === 'string') {\n return new UnsubscribeMessage(id, value.channel)\n }\n\n if (\n (value.type === 'message' || value.type === 'whisper') &&\n typeof value.channel === 'string' &&\n typeof value.event === 'string'\n ) {\n return new ChannelProtocolMessage(id, value.type, value.channel, value.event, value.data)\n }\n\n return new InvalidMessage(id)\n }\n}\n\nexport class InvalidMessage extends Message {\n readonly valid = false\n readonly type = 'invalid'\n\n constructor(readonly id: string | undefined) {\n super()\n }\n\n toRejectionFrame(): ServerProtocolMessage {\n return Reply.invalidMessage(this.id)\n }\n}\n\nexport class PingMessage extends Message {\n readonly valid = true\n readonly type = 'ping'\n\n constructor(readonly id: string | undefined) {\n super()\n }\n}\n\nexport class SubscribeMessage extends Message {\n readonly valid = true\n readonly type = 'subscribe'\n\n constructor(\n readonly id: string | undefined,\n readonly channel: string\n ) {\n super()\n }\n}\n\nexport class UnsubscribeMessage extends Message {\n readonly valid = true\n readonly type = 'unsubscribe'\n\n constructor(\n readonly id: string | undefined,\n readonly channel: string\n ) {\n super()\n }\n}\n\nexport class ChannelProtocolMessage extends Message {\n readonly valid = true\n\n constructor(\n readonly id: string | undefined,\n readonly type: 'message' | 'whisper',\n readonly channel: string,\n readonly event: string,\n readonly data: unknown\n ) {\n super()\n }\n\n toChannelMessage(): ChannelMessage {\n return {\n channel: this.channel,\n event: this.event,\n data: this.data,\n }\n }\n}\n\nexport type TransportMessage =\n | InvalidMessage\n | PingMessage\n | SubscribeMessage\n | UnsubscribeMessage\n | ChannelProtocolMessage\n\nfunction isClientMessageType(value: unknown): value is ClientMessageType {\n return (\n value === 'ping' ||\n value === 'subscribe' ||\n value === 'unsubscribe' ||\n value === 'message' ||\n value === 'whisper'\n )\n}\n","export class MessageQueue<Key = string> {\n #queues = new Map<Key, Promise<void>>()\n #depths = new Map<Key, number>()\n\n enqueue(key: Key, task: () => Promise<void>, options: { maxDepth?: number } = {}): boolean {\n const depth = this.#depths.get(key) ?? 0\n\n if (options.maxDepth !== undefined && depth >= options.maxDepth) {\n return false\n }\n\n this.#depths.set(key, depth + 1)\n\n const previous = this.#queues.get(key) ?? Promise.resolve()\n const next = previous\n .catch(() => {})\n .then(task)\n .catch(() => {})\n .finally(() => {\n const nextDepth = (this.#depths.get(key) ?? 1) - 1\n\n if (nextDepth <= 0) {\n this.#depths.delete(key)\n } else {\n this.#depths.set(key, nextDepth)\n }\n\n if (this.#queues.get(key) === next) {\n this.#queues.delete(key)\n }\n })\n\n this.#queues.set(key, next)\n return true\n }\n\n drain(key: Key): Promise<void> {\n return this.#queues.get(key) ?? Promise.resolve()\n }\n\n delete(key: Key): void {\n this.#queues.delete(key)\n this.#depths.delete(key)\n }\n\n clear(): void {\n this.#queues.clear()\n this.#depths.clear()\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { Bus } from '@boringnode/bus'\nimport type { Serializable, TransportFactory } from '@boringnode/bus/types/main'\nimport type { PresenceSocket } from './presence_manager.js'\nimport { PresenceSocketFrame, type SerializablePresenceSocket } from './presence_socket_frame.js'\nimport { parseDuration, type Duration } from './duration.js'\n\nexport type { SerializablePresenceSocket } from './presence_socket_frame.js'\n\nconst DEFAULT_CHANNEL = 'socket::broadcast'\nconst DEFAULT_PRESENCE_TIMEOUT = 100\nexport const DEFAULT_RETRY_QUEUE_MAX_SIZE = 1000\n\ntype ChannelEventMessage = {\n [key: string]: Serializable\n type: 'channel:event'\n origin: string\n channel: string\n event: string\n data: Serializable\n except: string[]\n}\n\ntype BroadcastEventMessage = {\n [key: string]: Serializable\n type: 'broadcast:event'\n origin: string\n event: string\n data: Serializable\n}\n\ntype PresenceSocketsRequestMessage = {\n [key: string]: Serializable\n type: 'presence:sockets:request'\n origin: string\n requestId: string\n channel: string\n}\n\ntype PresenceSocketsResponseMessage = {\n [key: string]: Serializable\n type: 'presence:sockets:response'\n origin: string\n target: string\n requestId: string\n sockets: SerializablePresenceSocket[]\n}\n\nexport type SocketBusMessage =\n | ChannelEventMessage\n | BroadcastEventMessage\n | PresenceSocketsRequestMessage\n | PresenceSocketsResponseMessage\n\nexport interface SocketTransportConfig {\n driver: TransportFactory\n channel?: string\n /**\n * How long to wait for other instances to answer a presence snapshot request.\n */\n presenceTimeout?: Duration\n /**\n * In-memory retry policy for transport publications that fail.\n *\n * The queue is enabled and limited to 1000 distinct messages by default.\n * Set maxSize to null only when an unbounded queue is explicitly desired.\n */\n retryQueue?: SocketRetryQueueConfig\n}\n\nexport interface SocketRetryQueueConfig {\n enabled?: boolean\n removeDuplicates?: boolean\n maxSize?: number | null\n retryInterval?: Duration | false\n}\n\nfunction resolveRetryQueueConfig(config: SocketRetryQueueConfig | undefined) {\n const maxSize = config?.maxSize === undefined ? DEFAULT_RETRY_QUEUE_MAX_SIZE : config.maxSize\n\n if (maxSize !== null && (!Number.isSafeInteger(maxSize) || maxSize <= 0)) {\n throw new Error('transport.retryQueue.maxSize must be a positive integer or null')\n }\n\n return {\n enabled: true,\n maxSize,\n ...config,\n }\n}\n\ninterface SocketBusHandlers {\n channel(message: Extract<SocketBusMessage, { type: 'channel:event' }>): void\n broadcast(message: Extract<SocketBusMessage, { type: 'broadcast:event' }>): void\n presenceSockets(channel: string): SerializablePresenceSocket[]\n}\n\ninterface PendingPresenceRequest {\n sockets: PresenceSocketFrame[]\n resolve(sockets: PresenceSocket[]): void\n timeout: ReturnType<typeof setTimeout>\n}\n\ntype ParsedPresenceSocketsResponseMessage = {\n type: 'presence:sockets:response'\n origin: string\n target: string\n requestId: string\n sockets: PresenceSocketFrame[]\n}\n\ntype ParsedSocketBusMessage =\n | Exclude<SocketBusMessage, PresenceSocketsResponseMessage>\n | ParsedPresenceSocketsResponseMessage\n\nfunction parseBusMessage(payload: unknown): ParsedSocketBusMessage | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return null\n }\n\n const message = payload as Record<string, unknown>\n if (typeof message.origin !== 'string') {\n return null\n }\n\n switch (message.type) {\n case 'channel:event':\n return typeof message.channel === 'string' &&\n typeof message.event === 'string' &&\n Array.isArray(message.except) &&\n message.except.every((socketId) => typeof socketId === 'string')\n ? (message as ChannelEventMessage)\n : null\n case 'broadcast:event':\n return typeof message.event === 'string' ? (message as BroadcastEventMessage) : null\n case 'presence:sockets:request':\n return typeof message.requestId === 'string' && typeof message.channel === 'string'\n ? (message as PresenceSocketsRequestMessage)\n : null\n case 'presence:sockets:response':\n if (\n typeof message.target !== 'string' ||\n typeof message.requestId !== 'string' ||\n !Array.isArray(message.sockets)\n ) {\n return null\n }\n\n const sockets = Array.from(message.sockets, PresenceSocketFrame.fromTransport)\n return sockets.every((socket) => socket !== null)\n ? ({ ...message, sockets } as ParsedPresenceSocketsResponseMessage)\n : null\n default:\n return null\n }\n}\n\nexport class SocketBus {\n #origin = randomUUID()\n #channel: string\n #bus: Bus\n #presenceTimeout: number\n #pendingPresenceRequests = new Map<string, PendingPresenceRequest>()\n\n constructor(\n transport: SocketTransportConfig,\n private handlers: SocketBusHandlers\n ) {\n this.#channel = transport.channel ?? DEFAULT_CHANNEL\n this.#presenceTimeout =\n parseDuration('transport.presenceTimeout', transport.presenceTimeout) ??\n DEFAULT_PRESENCE_TIMEOUT\n this.#bus = new Bus(transport.driver(), {\n retryQueue: resolveRetryQueueConfig(transport.retryQueue),\n })\n }\n\n async start(): Promise<void> {\n await this.#bus.subscribe(this.#channel, (payload) => {\n try {\n const message = parseBusMessage(payload)\n if (!message || message.origin === this.#origin) {\n return\n }\n\n switch (message.type) {\n case 'channel:event':\n this.handlers.channel(message)\n return\n case 'broadcast:event':\n this.handlers.broadcast(message)\n return\n case 'presence:sockets:request':\n void this.#respondToPresenceRequest(message).catch(() => {})\n return\n case 'presence:sockets:response':\n this.#handlePresenceResponse(message)\n return\n }\n } catch {\n return\n }\n })\n }\n\n publishChannel(channel: string, event: string, data: unknown, except?: string[]): void {\n const message: SocketBusMessage = {\n type: 'channel:event',\n origin: this.#origin,\n channel,\n event,\n data: data as Serializable,\n except: except ?? [],\n }\n\n void this.#bus.publish(this.#channel, message)\n }\n\n publishBroadcast(event: string, data: unknown): void {\n const message: BroadcastEventMessage = {\n type: 'broadcast:event',\n origin: this.#origin,\n event,\n data: data as Serializable,\n }\n void this.#bus.publish(this.#channel, message)\n }\n\n fetchPresenceSockets(channel: string): Promise<PresenceSocket[]> {\n const requestId = randomUUID()\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n const request = this.#pendingPresenceRequests.get(requestId)\n\n if (!request) {\n return\n }\n\n this.#pendingPresenceRequests.delete(requestId)\n resolve(request.sockets.map((socket) => socket.toSocket()))\n }, this.#presenceTimeout)\n\n this.#pendingPresenceRequests.set(requestId, {\n sockets: [],\n resolve,\n timeout,\n })\n\n const message: PresenceSocketsRequestMessage = {\n type: 'presence:sockets:request',\n origin: this.#origin,\n requestId,\n channel,\n }\n void this.#bus.publish(this.#channel, message)\n })\n }\n\n async close(): Promise<void> {\n for (const [requestId, request] of this.#pendingPresenceRequests) {\n clearTimeout(request.timeout)\n request.resolve(request.sockets.map((socket) => socket.toSocket()))\n this.#pendingPresenceRequests.delete(requestId)\n }\n\n await this.#bus.disconnect()\n }\n\n async #respondToPresenceRequest(\n message: Extract<SocketBusMessage, { type: 'presence:sockets:request' }>\n ): Promise<void> {\n const response: PresenceSocketsResponseMessage = {\n type: 'presence:sockets:response',\n origin: this.#origin,\n target: message.origin,\n requestId: message.requestId,\n sockets: this.handlers.presenceSockets(message.channel),\n }\n await this.#bus.publish(this.#channel, response as Serializable)\n }\n\n #handlePresenceResponse(message: ParsedPresenceSocketsResponseMessage): void {\n if (message.target !== this.#origin) {\n return\n }\n\n const request = this.#pendingPresenceRequests.get(message.requestId)\n\n if (!request) {\n return\n }\n\n request.sockets.push(...message.sockets)\n }\n}\n","import type { PresenceInfo } from './types.js'\n\nexport const PRESENCE_DATA_KEY = '__rlanzSocketPresence'\n\ntype PresenceSocketData = Record<string, unknown> & {\n [PRESENCE_DATA_KEY]?: Record<string, PresenceUser>\n}\n\nexport interface PresenceUser {\n id: string\n joinedAt: Date\n [key: string]: unknown\n}\n\nexport interface PresenceData {\n channel: string\n users: PresenceUser[]\n count: number\n}\n\nexport interface PresenceSocket {\n id: string\n data: PresenceSocketData\n}\n\n/**\n * Tracks user presence in channels.\n *\n * channel -> socketId -> PresenceUser\n */\nexport class PresenceManager {\n #presence = new Map<string, Map<string, PresenceUser>>()\n #fetchSockets: ((channel: string) => Promise<PresenceSocket[]>) | null = null\n\n /**\n * Sets the socket fetcher used to build distributed snapshots.\n */\n setSocketFetcher(fetchSockets: ((channel: string) => Promise<PresenceSocket[]>) | null): void {\n this.#fetchSockets = fetchSockets\n }\n\n /**\n * Adds a user to a channel.\n */\n join(channel: string, socket: PresenceSocket, member: PresenceInfo): PresenceUser {\n const user = {\n ...member.data,\n id: member.id,\n joinedAt: new Date(),\n }\n\n const users = this.#presence.get(channel) ?? new Map()\n users.set(socket.id, user)\n this.#presence.set(channel, users)\n this.#setSocketPresence(socket, channel, user)\n\n return user\n }\n\n /**\n * Removes a user from a channel.\n */\n leave(channel: string, socket: PresenceSocket): void {\n const channelPresence = this.#presence.get(channel)\n\n if (channelPresence) {\n channelPresence.delete(socket.id)\n\n if (channelPresence.size === 0) {\n this.#presence.delete(channel)\n }\n }\n\n this.#deleteSocketPresence(socket, channel)\n }\n\n /**\n * Removes a user from every channel.\n * Returns the list of channels the user left.\n */\n leaveAll(socket: PresenceSocket): string[] {\n const leftChannels: string[] = []\n\n for (const [channel, users] of this.#presence) {\n if (users.has(socket.id)) {\n users.delete(socket.id)\n leftChannels.push(channel)\n\n if (users.size === 0) {\n this.#presence.delete(channel)\n }\n\n this.#deleteSocketPresence(socket, channel)\n }\n }\n\n return leftChannels\n }\n\n /**\n * Gets presence data for a channel.\n */\n async snapshot(channel: string): Promise<PresenceData> {\n if (this.#fetchSockets) {\n return this.#getFromSockets(channel)\n }\n\n return this.#localSnapshot(channel)\n }\n\n /**\n * Gets the number of users in a channel.\n */\n async count(channel: string): Promise<number> {\n return (await this.snapshot(channel)).count\n }\n\n /**\n * Checks whether a socket is locally present in a channel.\n */\n hasLocal(channel: string, socketId: string): boolean {\n return this.#presence.get(channel)?.has(socketId) || false\n }\n\n /**\n * Gets the presence user retained for one local socket.\n */\n getLocalUser(channel: string, socketId: string): PresenceUser | undefined {\n return this.#presence.get(channel)?.get(socketId)\n }\n\n /**\n * Lists every local channel where a socket is present.\n */\n getLocalChannelsForSocket(socketId: string): string[] {\n const channels: string[] = []\n\n for (const [channel, users] of this.#presence) {\n if (users.has(socketId)) {\n channels.push(channel)\n }\n }\n\n return channels\n }\n\n /**\n * Lists sockets that are locally present in a channel.\n */\n getLocalSockets(channel: string): PresenceSocket[] {\n const users = this.#presence.get(channel)\n\n if (!users) {\n return []\n }\n\n return Array.from(users.entries()).map(([socketId, user]) => ({\n id: socketId,\n data: {\n [PRESENCE_DATA_KEY]: {\n [channel]: user,\n },\n },\n }))\n }\n\n #localSnapshot(channel: string): PresenceData {\n return this.#createSnapshot(channel, Array.from(this.#presence.get(channel)?.entries() ?? []))\n }\n\n async #getFromSockets(channel: string): Promise<PresenceData> {\n const sockets = await this.#fetchSockets!(channel)\n const users = sockets.flatMap((socket): Array<[string, PresenceUser]> => {\n const user = socket.data?.[PRESENCE_DATA_KEY]?.[channel]\n return user ? [[socket.id, user]] : []\n })\n\n return this.#createSnapshot(channel, users)\n }\n\n #createSnapshot(\n channel: string,\n connections: Array<[socketId: string, user: PresenceUser]>\n ): PresenceData {\n const usersById = new Map<string, [socketId: string, user: PresenceUser]>()\n\n for (const connection of connections) {\n const current = usersById.get(connection[1].id)\n if (!current || this.#compareConnections(connection, current) < 0) {\n usersById.set(connection[1].id, connection)\n }\n }\n\n const users = [...usersById.values()]\n .sort((left, right) => this.#compareConnections(left, right))\n .map(([, user]) => user)\n\n return {\n channel,\n users,\n count: users.length,\n }\n }\n\n #compareConnections(\n [leftSocketId, leftUser]: [string, PresenceUser],\n [rightSocketId, rightUser]: [string, PresenceUser]\n ): number {\n const joinedAtDifference = leftUser.joinedAt.getTime() - rightUser.joinedAt.getTime()\n return joinedAtDifference || leftSocketId.localeCompare(rightSocketId)\n }\n\n #setSocketPresence(socket: PresenceSocket, channel: string, user: PresenceUser): void {\n socket.data[PRESENCE_DATA_KEY] ??= {}\n socket.data[PRESENCE_DATA_KEY][channel] = user\n }\n\n #deleteSocketPresence(socket: PresenceSocket, channel: string): void {\n if (!socket.data[PRESENCE_DATA_KEY]) {\n return\n }\n\n delete socket.data[PRESENCE_DATA_KEY][channel]\n\n if (Object.keys(socket.data[PRESENCE_DATA_KEY]).length === 0) {\n delete socket.data[PRESENCE_DATA_KEY]\n }\n }\n}\n","import type { Serializable } from '@boringnode/bus/types/main'\nimport { PRESENCE_DATA_KEY, type PresenceSocket, type PresenceUser } from './presence_manager.js'\n\ntype SerializablePresenceUser = {\n [key: string]: Serializable\n id: string\n joinedAt: string\n}\n\nexport interface SerializablePresenceSocket {\n [key: string]: Serializable\n id: string\n data: {\n [key: string]: Serializable\n }\n}\n\n/**\n * Transport representation of one socket participating in distributed presence.\n */\nexport class PresenceSocketFrame {\n private constructor(\n private readonly transportValue: SerializablePresenceSocket,\n private readonly socketValue: PresenceSocket\n ) {}\n\n /**\n * Create one transport frame from a local socket presence entry.\n */\n static fromSocket(channel: string, socket: PresenceSocket): PresenceSocketFrame {\n const user = socket.data[PRESENCE_DATA_KEY]?.[channel]\n if (!user || Number.isNaN(user.joinedAt.getTime())) {\n throw new Error(`Socket \"${socket.id}\" has no valid presence for channel \"${channel}\"`)\n }\n\n const transport: SerializablePresenceSocket = {\n id: socket.id,\n data: {\n [PRESENCE_DATA_KEY]: {\n [channel]: {\n // Keep custom fields. Convert only the presence timestamp.\n ...user,\n joinedAt: user.joinedAt.toISOString(),\n } as SerializablePresenceUser,\n },\n },\n }\n\n return new PresenceSocketFrame(transport, socket)\n }\n\n /**\n * Validate one transport value and restore its presence timestamps.\n */\n static fromTransport(value: unknown): PresenceSocketFrame | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null\n }\n\n const transport = value as Record<string, unknown>\n\n // A valid frame needs a socket ID and one object for socket data.\n if (\n typeof transport.id !== 'string' ||\n !transport.data ||\n typeof transport.data !== 'object' ||\n Array.isArray(transport.data)\n ) {\n return null\n }\n\n const data = transport.data as Record<string, unknown>\n const presence = data[PRESENCE_DATA_KEY]\n\n // A socket can have no presence entries.\n if (presence === undefined) {\n return new PresenceSocketFrame(transport as SerializablePresenceSocket, {\n id: transport.id,\n data: { ...data },\n })\n }\n if (!presence || typeof presence !== 'object' || Array.isArray(presence)) {\n return null\n }\n\n // Validate all members before this frame becomes a PresenceSocket.\n const restoredPresence: Record<string, PresenceUser> = {}\n for (const [channel, candidate] of Object.entries(presence)) {\n if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {\n return null\n }\n\n const user = candidate as Record<string, unknown>\n if (\n typeof user.id !== 'string' ||\n typeof user.joinedAt !== 'string' ||\n Number.isNaN(Date.parse(user.joinedAt))\n ) {\n return null\n }\n\n // Keep custom fields. Restore only the presence timestamp.\n restoredPresence[channel] = {\n ...user,\n id: user.id,\n joinedAt: new Date(user.joinedAt),\n }\n }\n\n return new PresenceSocketFrame(transport as SerializablePresenceSocket, {\n id: transport.id,\n data: {\n ...data,\n [PRESENCE_DATA_KEY]: restoredPresence,\n },\n })\n }\n\n /**\n * Return the validated transport value.\n */\n toTransport(): SerializablePresenceSocket {\n return this.transportValue\n }\n\n /**\n * Return the socket value with restored presence timestamps.\n */\n toSocket(): PresenceSocket {\n return this.socketValue\n }\n}\n","import { parse as parseDurationExpression } from '@lukeed/ms'\n\n/**\n * Duration can be specified as milliseconds or as a human-readable string.\n */\nexport type Duration = number | string\n\nexport function parseDuration(name: string, duration: Duration | undefined): number | undefined {\n if (duration === undefined) {\n return undefined\n }\n\n const milliseconds = typeof duration === 'number' ? duration : parseDurationExpression(duration)\n\n if (typeof milliseconds === 'undefined' || !Number.isFinite(milliseconds) || milliseconds <= 0) {\n throw new Error(`${name} must be a positive duration`)\n }\n\n return milliseconds\n}\n","import type { IncomingMessage } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport type { WebSocket, WebSocketServer } from 'ws'\nimport type { HttpContext } from '@adonisjs/core/http'\nimport type { SocketConfig, SocketUpgradeContext } from './types.js'\n\nexport const DEFAULT_WEBSOCKET_PATH = '/socket'\n\nexport interface AcceptedUpgrade<User> {\n httpContext: HttpContext\n user?: User\n}\n\nexport type SocketUpgradeHandler = (request: IncomingMessage, socket: Duplex, head: Buffer) => void\n\ntype AcceptUpgrade<User> = (\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User>\n) => void\n\nexport type SocketUpgradeContextRunner = <Result>(\n request: IncomingMessage,\n handler: (httpContext: HttpContext) => Promise<Result>,\n shortCircuitBeforeMiddleware?: (\n httpContext: HttpContext\n ) => Result | undefined | Promise<Result | undefined>\n) => Promise<Result>\n\ntype UpgradeResult<User> =\n | { accepted: AcceptedUpgrade<User> }\n | { rejected: 'authentication' | 'origin' }\n\nexport class SocketUpgrader<User = unknown> {\n #path: string\n\n constructor(\n private server: WebSocketServer,\n private config: SocketConfig<User>['websocket'] | undefined,\n private runWithHttpContext: SocketUpgradeContextRunner,\n private reportError: (message: string, error: unknown) => void = () => {}\n ) {\n this.#path = config?.path ?? DEFAULT_WEBSOCKET_PATH\n }\n\n async handle(\n request: IncomingMessage,\n socket: Duplex,\n head: Buffer,\n accept: AcceptUpgrade<User>\n ): Promise<boolean> {\n if (!this.#matchesPath(request)) {\n return false\n }\n\n const result = await this.#prepareUpgrade(request)\n\n if ('rejected' in result) {\n if (result.rejected === 'origin') {\n SocketUpgrader.reject(socket, 403, 'Forbidden')\n return true\n }\n\n SocketUpgrader.reject(socket, 401, 'Unauthorized')\n return true\n }\n\n this.server.handleUpgrade(request, socket, head, (connection) => {\n accept(connection, request, result.accepted)\n })\n\n return true\n }\n\n static reject(socket: Duplex, statusCode: number, reason: string): void {\n if (!socket.writableEnded) {\n socket.write(`HTTP/1.1 ${statusCode} ${reason}\\r\\n\\r\\n`)\n }\n\n socket.destroy()\n }\n\n #matchesPath(request: IncomingMessage): boolean {\n const url = new URL(request.url ?? '/', 'ws://localhost')\n return url.pathname === this.#path\n }\n\n #isOriginAllowed(request: IncomingMessage, httpContext: HttpContext): boolean {\n const origin = request.headers.origin\n if (!origin) {\n return true\n }\n\n if (this.config?.origin !== undefined) {\n return this.#matchesOriginPolicy(origin, httpContext)\n }\n\n const host = request.headers.host\n if (!host) {\n return false\n }\n\n const forwardedHeader = request.headers['x-forwarded-proto']\n const forwardedProtocol = (\n Array.isArray(forwardedHeader) ? forwardedHeader[0] : forwardedHeader\n )\n ?.split(',')[0]\n ?.trim()\n const protocol =\n forwardedProtocol === 'http' || forwardedProtocol === 'https'\n ? forwardedProtocol\n : (request.socket as typeof request.socket & { encrypted?: boolean }).encrypted\n ? 'https'\n : 'http'\n\n try {\n return origin === new URL(`${protocol}://${host}`).origin\n } catch {\n return false\n }\n }\n\n #matchesOriginPolicy(origin: string, httpContext: HttpContext): boolean {\n let originPolicy = this.config?.origin ?? false\n\n if (typeof originPolicy === 'function') {\n originPolicy = originPolicy(origin, httpContext)\n }\n\n if (originPolicy === true || originPolicy === '*') {\n return true\n }\n\n if (originPolicy === false) {\n return false\n }\n\n if (Array.isArray(originPolicy)) {\n return originPolicy.includes(origin)\n }\n\n return originPolicy.split(',').includes(origin)\n }\n\n async #prepareUpgrade(request: IncomingMessage): Promise<UpgradeResult<User>> {\n return this.runWithHttpContext<UpgradeResult<User>>(\n request,\n async (httpContext) => {\n const accepted = await this.#authenticate(httpContext)\n return accepted ? { accepted } : { rejected: 'authentication' }\n },\n (httpContext) => {\n return this.#isOriginAllowed(request, httpContext) ? undefined : { rejected: 'origin' }\n }\n )\n }\n\n async #authenticate(httpContext: HttpContext): Promise<AcceptedUpgrade<User> | null> {\n const config = this.config\n if (!config?.authenticate) {\n return { httpContext }\n }\n\n try {\n const ctx: SocketUpgradeContext = {\n httpContext,\n }\n\n const result = await config.authenticate(ctx)\n\n if (result === false || result === null || result === undefined) {\n return null\n }\n\n return {\n httpContext,\n user: result,\n }\n } catch (error) {\n try {\n this.reportError('socket authentication failed: %s', error)\n } catch {\n // Error reporting must never change an authentication rejection.\n }\n return null\n }\n }\n}\n","import type { BaseChannelConstructor } from './base_channel.js'\nimport { ChannelPatternSyntax } from './channel_pattern_syntax.js'\n\ntype MatchParams = Record<string, string>\n\nexport interface ChannelPatternMatch {\n pattern: ChannelPattern\n channel: BaseChannelConstructor\n params: MatchParams\n}\n\ninterface MatchCandidate {\n pattern: ChannelPattern\n channel: BaseChannelConstructor\n}\n\nexport class ChannelPattern {\n private readonly syntax: ChannelPatternSyntax\n\n private constructor(readonly value: string) {\n this.syntax = ChannelPatternSyntax.from(value)\n }\n\n /**\n * Parse one runtime channel pattern.\n */\n static from(value: string): ChannelPattern {\n return new ChannelPattern(value)\n }\n\n /**\n * Match one concrete channel name.\n */\n match(channelName: string): MatchParams | null {\n return this.syntax.match(channelName)\n }\n\n /**\n * Return the most specific matching candidate. Static segments have the highest score.\n * Parameters score above optional parameters. Wildcards have the lowest score.\n * Insertion order is preserved for ties.\n */\n static firstMatch(\n channelName: string,\n candidates: Iterable<MatchCandidate>\n ): ChannelPatternMatch | null {\n const sorted = [...candidates].sort((left, right) => {\n return ChannelPattern.#compareSpecificity(left.pattern, right.pattern)\n })\n const matched = ChannelPatternSyntax.firstMatch(\n sorted.map(({ pattern }) => pattern.syntax),\n channelName\n )\n if (!matched) return null\n\n const { pattern, channel } = sorted[matched.index]\n return { pattern, channel, params: matched.params }\n }\n\n static #compareSpecificity(left: ChannelPattern, right: ChannelPattern): number {\n return left.syntax.compareSpecificity(right.syntax)\n }\n}\n","import {\n SocketResponseError,\n type BaseChannel,\n type BaseChannelConstructor,\n type ChannelMiddlewareRunnerFactory,\n} from './base_channel.js'\nimport { ChannelPattern } from './channel_pattern.js'\nimport type { AuthenticatedSocket, ChannelMatch, MiddlewareContext } from './types.js'\n\ninterface RegisteredChannel {\n pattern: ChannelPattern\n channel: BaseChannelConstructor\n}\n\nexport type ChannelFactory = (\n channel: BaseChannelConstructor\n) => BaseChannel<any> | Promise<BaseChannel<any>>\n\n/**\n * Matches channel names against registered patterns.\n *\n * Pattern: chat/:roomId\n * Channel: chat/general\n *\n * chat / :roomId\n * | |\n * chat / general => { roomId: \"general\" }\n */\nexport class ChannelRouter {\n /**\n * Registered channels keyed by their pattern.\n */\n #channels = new Map<string, RegisteredChannel>()\n\n constructor(\n private makeChannel: ChannelFactory = (channel) => new channel(),\n private createMiddlewareRunner?: ChannelMiddlewareRunnerFactory\n ) {}\n\n /**\n * Registers a channel.\n */\n register(channel: BaseChannelConstructor): void {\n const patternValue = channel.pattern\n\n if (!patternValue) {\n throw new Error(`Channel ${channel.name} must define a static pattern`)\n }\n\n if (this.#channels.has(patternValue)) {\n throw new Error(`Channel pattern \"${patternValue}\" is already registered`)\n }\n\n const pattern = ChannelPattern.from(patternValue)\n\n this.#channels.set(pattern.value, { pattern, channel })\n }\n\n /**\n * Matches a channel name against registered patterns.\n */\n match(channelName: string): ChannelMatch | null {\n const matched = ChannelPattern.firstMatch(channelName, this.#channels.values())\n\n if (!matched) {\n return null\n }\n\n return {\n channel: matched.channel,\n pattern: matched.pattern.value,\n params: matched.params,\n }\n }\n\n /**\n * Authorizes a socket before it joins a channel.\n */\n async authorize<User = unknown>(socket: AuthenticatedSocket<User>, channelName: string) {\n const matched = this.match(channelName)\n\n if (!matched) {\n return {\n success: false,\n error: 'Channel not found',\n } as const\n }\n\n const instance = (await this.makeChannel(matched.channel)) as BaseChannel<User>\n const paramValues = Object.values(matched.params)\n\n const ctx: MiddlewareContext<User> = {\n socket,\n channel: channelName,\n params: matched.params,\n presenceData: undefined,\n setPresenceData(data) {\n ctx.presenceData = data\n },\n }\n\n // Run authorization middlewares.\n try {\n await instance.$runMiddlewares(ctx, this.createMiddlewareRunner?.())\n } catch (error) {\n return {\n success: false,\n error: error instanceof SocketResponseError ? error.message : 'Authorization failed',\n cause: error,\n } as const\n }\n\n return {\n success: true,\n instance,\n params: matched.params,\n paramValues,\n presenceData: ctx.presenceData ?? null,\n } as const\n }\n\n /**\n * Lists all registered channels.\n */\n list() {\n return [...this.#channels.values()].map(({ pattern, channel }) => ({\n pattern: pattern.value,\n name: channel.name,\n options: channel.options,\n }))\n }\n\n /**\n * Number of registered channels.\n */\n get size(): number {\n return this.#channels.size\n }\n}\n"],"mappings":"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","names":["randomUUID","randomUUID","pattern"]}
|