@rlanz/socket 0.0.1-2 → 0.0.1-4

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presence_manager.ts","../src/base_channel.ts","../src/fake_socket.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","../src/channel_pattern.ts","../src/channel_router.ts"],"sourcesContent":["import type { PresenceMember } 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 name: 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[]>): void {\n this.#fetchSockets = fetchSockets\n }\n\n /**\n * Adds a user to a channel.\n */\n join(channel: string, socket: PresenceSocket, member: string | PresenceMember): void {\n if (!this.#presence.has(channel)) {\n this.#presence.set(channel, new Map())\n }\n\n const presenceUser =\n typeof member === 'string'\n ? { id: socket.id, name: member }\n : {\n ...member,\n id: member.id || socket.id,\n }\n\n const user = {\n ...presenceUser,\n joinedAt: new Date(),\n }\n\n this.#presence.get(channel)!.set(socket.id, user)\n this.#setSocketPresence(socket, channel, 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 * 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 const users = this.#presence.get(channel)\n\n return {\n channel,\n users: users ? Array.from(users.values()) : [],\n count: users?.size || 0,\n }\n }\n\n async #getFromSockets(channel: string): Promise<PresenceData> {\n const sockets = await this.#fetchSockets!(channel)\n const users = sockets\n .map((socket) => socket.data?.[PRESENCE_DATA_KEY]?.[channel])\n .filter((user): user is PresenceUser => Boolean(user))\n\n return {\n channel,\n users,\n count: users.length,\n }\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 {\n AuthenticatedSocket,\n ChannelOptions,\n PresenceMember,\n Middleware,\n MiddlewareContext,\n ChannelEventMap,\n ChannelHandlerMap,\n} from './types.js'\nimport type { PresenceManager } from './presence_manager.js'\nimport { getDecoratedChannelHandlers } from './decorators.js'\n\ninterface ChannelBroadcaster {\n to(channel: string): {\n emit(event: string, data: unknown): void\n except(socketId: string): {\n emit(event: string, data: unknown): void\n }\n }\n}\n\nexport class MissingPresenceInfoError extends Error {\n constructor() {\n super('Presence channels must implement getPresenceInfo(socket)')\n }\n}\n\n/**\n * Abstract class used to define a channel.\n *\n * @example\n * ```ts\n * export default class ChatChannel extends BaseChannel {\n * static pattern = 'chat/:roomId'\n * static middlewares = [\n * async (ctx, next) => {\n * // Authorize access to the channel through middleware.\n * // if (!Room.isMember(ctx.params.roomId, ctx.socket.user.id)) throw new Error('Forbidden')\n * await next()\n * },\n * ]\n * }\n * ```\n *\n * @example With presence and decorated handlers\n * ```ts\n * import { onMessage } from '@rlanz/socket/decorators'\n *\n * export default class ChatChannel extends BaseChannel {\n * static pattern = 'chat/:roomId'\n * static options = { presence: true }\n *\n * static middlewares = [\n * async (ctx, next) => {\n * if (!ctx.socket.user.isVerified) throw new Error('Not verified')\n * await next()\n * }\n * ]\n *\n * @onMessage('chat:send')\n * async handleSend(socket: AuthenticatedSocket<User>, data: unknown) {\n * // Handle chat:send event\n * }\n *\n * @onMessage('chat:typing')\n * async handleTyping(socket: AuthenticatedSocket<User>, data: unknown) {\n * // Handle chat:typing event\n * }\n * }\n * ```\n */\nexport class BaseChannel<\n User = unknown,\n Events extends ChannelEventMap = ChannelEventMap,\n HttpContext = unknown,\n> {\n /**\n * URL-like channel pattern, for example: 'chat/:roomId'.\n */\n static pattern: string\n\n /**\n * Channel options.\n */\n static options?: ChannelOptions\n\n /**\n * Middlewares to run before subscription.\n */\n static middlewares?: Middleware<any, any>[]\n\n /**\n * Event handler map.\n * Ex: { 'chat:send': 'handleSend' }\n */\n protected handlers: ChannelHandlerMap<User, Events, HttpContext> = {}\n\n /**\n * Injected socket service.\n */\n protected socket!: ChannelBroadcaster\n\n /**\n * Full channel name, for example: 'chat/general'.\n */\n protected channelName!: string\n\n /**\n * Parameters extracted from the pattern, for example: { roomId: 'general' }.\n */\n protected params!: Record<string, string>\n\n /**\n * Injected presence manager when presence is enabled.\n */\n protected presence!: PresenceManager\n\n /**\n * Injects dependencies.\n */\n $setContext(\n socket: ChannelBroadcaster,\n channelName: string,\n params: Record<string, string>,\n presence?: PresenceManager\n ): void {\n this.socket = socket\n this.channelName = channelName\n this.params = params\n if (presence) {\n this.presence = presence\n }\n }\n\n /**\n * Emits to every channel member.\n */\n protected broadcast(event: string, data: unknown): void {\n this.socket.to(this.channelName).emit(event, data)\n }\n\n /**\n * Emits to every channel member except one socket.\n */\n protected broadcastExcept(socketId: string, event: string, data: unknown): void {\n this.socket.to(this.channelName).except(socketId).emit(event, data)\n }\n\n /**\n * Runs the middleware chain.\n *\n * middleware[0] -> middleware[1] -> ... -> subscribe\n */\n async $runMiddlewares(ctx: MiddlewareContext<User, HttpContext>): Promise<void> {\n const middlewares = (this.constructor as typeof BaseChannel).middlewares || []\n\n let index = 0\n\n const next = async (): Promise<void> => {\n if (index >= middlewares.length) return\n\n const middleware = middlewares[index++]\n\n if (typeof middleware === 'function') {\n await middleware(ctx, next)\n } else {\n await middleware.handle(ctx, next)\n }\n }\n\n await next()\n }\n\n /**\n * Returns member information for presence.\n * Implement when options.presence = true.\n */\n getPresenceInfo?(socket: AuthenticatedSocket<User, HttpContext>): PresenceMember\n\n /**\n * Hook called when a socket joins the channel.\n */\n onJoin?(socket: AuthenticatedSocket<User, HttpContext>, ...params: string[]): Promise<void>\n\n /**\n * Hook called when a socket leaves the channel.\n */\n onLeave?(socket: AuthenticatedSocket<User, HttpContext>, ...params: string[]): Promise<void>\n\n /**\n * Hook called when a message is received on the channel.\n * Used as fallback when no event handler matches.\n */\n onMessage?(\n socket: AuthenticatedSocket<User, HttpContext>,\n event: string,\n data: unknown\n ): Promise<void>\n\n /**\n * Hook called when a member joins a presence channel.\n */\n onMemberJoin?(\n socket: AuthenticatedSocket<User, HttpContext>,\n member: PresenceMember,\n ...params: string[]\n ): Promise<void>\n\n /**\n * Hook called when a member leaves a presence channel.\n */\n onMemberLeave?(\n socket: AuthenticatedSocket<User, HttpContext>,\n member: PresenceMember,\n ...params: string[]\n ): Promise<void>\n\n /**\n * Dispatches a message to the matching handler.\n * Called by SocketService. Do not override.\n */\n async $handleMessage(\n socket: AuthenticatedSocket<User, HttpContext>,\n event: string,\n data: unknown\n ): Promise<unknown> {\n const handlers = {\n ...(this.handlers as Record<string, unknown>),\n ...(getDecoratedChannelHandlers<User, Events, HttpContext>(this) as Record<string, unknown>),\n }\n const handler = handlers[event]\n\n if (typeof handler === 'function') {\n return (\n handler as (socket: AuthenticatedSocket<User, HttpContext>, data: unknown) => unknown\n ).call(this, socket, data)\n }\n\n // Fall back to onMessage when it is defined.\n return this.onMessage?.(socket, event, data)\n }\n\n /**\n * Runs the generic join hook. ChannelSubscriptions owns subscription lifecycle.\n */\n async $handleJoin(\n socket: AuthenticatedSocket<User, HttpContext>,\n ...params: string[]\n ): Promise<void> {\n await this.onJoin?.(socket, ...params)\n }\n\n /**\n * Runs the generic leave hook. ChannelSubscriptions owns subscription lifecycle.\n */\n async $handleLeave(\n socket: AuthenticatedSocket<User, HttpContext>,\n ...params: string[]\n ): Promise<void> {\n await this.onLeave?.(socket, ...params)\n }\n\n $getPresenceInfo(socket: AuthenticatedSocket<User, HttpContext>): PresenceMember {\n if (!this.getPresenceInfo) {\n throw new MissingPresenceInfoError()\n }\n\n return this.getPresenceInfo(socket)\n }\n}\n","import { AssertionError } from 'node:assert'\nimport { isDeepStrictEqual } from 'node:util'\nimport type { SocketEmission, SocketEmissionSink, SocketEmissionTarget } from './broadcasting.js'\n\nexport type SocketFakeTarget = SocketEmissionTarget\nexport type SocketFakeEmission = SocketEmission\n\nexport interface SocketFakeEmissionQuery {\n data?: unknown | ((data: unknown) => boolean)\n except?: string[] | ((except: string[] | undefined) => boolean)\n}\n\nexport interface SocketFakeCountQuery extends SocketFakeEmissionQuery {\n target?: SocketFakeTarget\n event?: string\n channel?: string\n userId?: string | number\n}\n\nexport class SocketFake implements SocketEmissionSink {\n #emissions: SocketFakeEmission[] = []\n #restore: () => void\n\n constructor(restore: () => void) {\n this.#restore = restore\n }\n\n get emissions(): SocketFakeEmission[] {\n return [...this.#emissions]\n }\n\n record(emission: SocketFakeEmission): void {\n this.#emissions.push({\n ...emission,\n ...('except' in emission && emission.except ? { except: [...emission.except] } : {}),\n })\n }\n\n dispatch(emission: SocketFakeEmission): void {\n this.record(emission)\n }\n\n clear(): void {\n this.#emissions = []\n }\n\n restore(): void {\n this.#restore()\n }\n\n [Symbol.dispose](): void {\n this.restore()\n }\n\n assertBroadcasted(event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertEmitted(\n (emission) => emission.target === 'global' && emission.event === event,\n query,\n `Expected socket event \"${event}\" to have been broadcasted`\n )\n }\n\n assertNotBroadcasted(event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertNotEmitted(\n (emission) => emission.target === 'global' && emission.event === event,\n query,\n `Expected socket event \"${event}\" not to have been broadcasted`\n )\n }\n\n assertEmittedTo(channel: string, event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertEmitted(\n (emission) =>\n emission.target === 'channel' && emission.channel === channel && emission.event === event,\n query,\n `Expected socket event \"${event}\" to have been emitted to channel \"${channel}\"`\n )\n }\n\n assertNotEmittedTo(channel: string, event: string, query?: SocketFakeEmissionQuery): void {\n this.#assertNotEmitted(\n (emission) =>\n emission.target === 'channel' && emission.channel === channel && emission.event === event,\n query,\n `Expected socket event \"${event}\" not to have been emitted to channel \"${channel}\"`\n )\n }\n\n assertEmittedToUser(\n userId: string | number,\n event: string,\n query?: SocketFakeEmissionQuery\n ): void {\n this.#assertEmitted(\n (emission) =>\n emission.target === 'user' && emission.userId === userId && emission.event === event,\n query,\n `Expected socket event \"${event}\" to have been emitted to user \"${String(userId)}\"`\n )\n }\n\n assertNotEmittedToUser(\n userId: string | number,\n event: string,\n query?: SocketFakeEmissionQuery\n ): void {\n this.#assertNotEmitted(\n (emission) =>\n emission.target === 'user' && emission.userId === userId && emission.event === event,\n query,\n `Expected socket event \"${event}\" not to have been emitted to user \"${String(userId)}\"`\n )\n }\n\n assertEmittedCount(count: number, query?: SocketFakeCountQuery): void {\n const actual = this.#matching(query).length\n\n if (actual !== count) {\n throw new AssertionError({\n message: `Expected ${count} socket event(s) to have been emitted, but found ${actual}`,\n actual,\n expected: count,\n operator: 'strictEqual',\n })\n }\n }\n\n assertNothingEmitted(): void {\n this.assertEmittedCount(0)\n }\n\n #assertEmitted(\n predicate: (emission: SocketFakeEmission) => boolean,\n query: SocketFakeEmissionQuery | undefined,\n message: string\n ): void {\n const matching = this.#emissions.filter((emission) => {\n return predicate(emission) && this.#matchesQuery(emission, query)\n })\n\n if (matching.length === 0) {\n throw new AssertionError({\n message,\n actual: this.#emissions,\n expected: query,\n operator: 'includes',\n })\n }\n }\n\n #assertNotEmitted(\n predicate: (emission: SocketFakeEmission) => boolean,\n query: SocketFakeEmissionQuery | undefined,\n message: string\n ): void {\n const matching = this.#emissions.filter((emission) => {\n return predicate(emission) && this.#matchesQuery(emission, query)\n })\n\n if (matching.length > 0) {\n throw new AssertionError({\n message,\n actual: matching,\n expected: [],\n operator: 'doesNotInclude',\n })\n }\n }\n\n #matching(query: SocketFakeCountQuery | undefined): SocketFakeEmission[] {\n return this.#emissions.filter((emission) => {\n if (query?.target && emission.target !== query.target) {\n return false\n }\n\n if (query?.event && emission.event !== query.event) {\n return false\n }\n\n if (query?.channel && (!('channel' in emission) || emission.channel !== query.channel)) {\n return false\n }\n\n if (\n query?.userId !== undefined &&\n (!('userId' in emission) || emission.userId !== query.userId)\n ) {\n return false\n }\n\n return this.#matchesQuery(emission, query)\n })\n }\n\n #matchesQuery(emission: SocketFakeEmission, query: SocketFakeEmissionQuery | undefined): boolean {\n if (!query) {\n return true\n }\n\n if ('data' in query) {\n if (typeof query.data === 'function') {\n if (!query.data(emission.data)) {\n return false\n }\n } else if (!isDeepStrictEqual(emission.data, query.data)) {\n return false\n }\n }\n\n if ('except' in query) {\n if (typeof query.except === 'function') {\n if (!query.except('except' in emission ? emission.except : undefined)) {\n return false\n }\n } else if (\n !isDeepStrictEqual(('except' in emission ? emission.except : undefined) ?? [], query.except)\n ) {\n return false\n }\n }\n\n return true\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 { 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 } 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 {\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 CLOSE_POLICY_VIOLATION = 1008\nconst CLOSE_MESSAGE_TOO_BIG = 1009\nconst CLOSE_OUTBOUND_BUFFER_LIMIT = 'Socket outbound buffer limit exceeded'\n\ninterface InboundMessageConfig {\n maxPayload: number\n maxQueuedMessages: number\n maxMessagesPerInterval: number\n messageRateInterval: number\n}\n\ninterface OutboundMessageConfig {\n maxBufferedAmount: 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 sendSerializedFrame(connection: WebSocket, serializedFrame: string): boolean {\n if (connection.readyState !== WebSocket.OPEN) {\n return false\n }\n\n connection.send(serializedFrame)\n return true\n}\n\nfunction sendFrame(connection: WebSocket, frame: ServerProtocolMessage): boolean {\n return sendSerializedFrame(connection, serializeFrame(frame))\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 if (connection.bufferedAmount > 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 }\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 }\n}\n\nfunction resolveOutboundMessageConfig(\n config:\n | {\n maxBufferedAmount?: number\n }\n | undefined\n): OutboundMessageConfig {\n return {\n maxBufferedAmount: parsePositiveInteger(\n 'websocket.maxBufferedAmount',\n config?.maxBufferedAmount,\n DEFAULT_MAX_BUFFERED_AMOUNT\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, HttpContext = unknown> extends Emittery<\n SocketEvents<User, HttpContext>\n> {\n #server: WebSocketServer | null = null\n #httpServer: HttpServer | null = null\n #upgradeHandler: SocketUpgradeHandler | null = null\n #sockets = new Map<string, AuthenticatedSocket<User, HttpContext>>()\n #userRooms = new Map<string, Set<string>>()\n #socketUserRoom = new Map<string, string>()\n #channelSubscriptions: ChannelSubscriptions<User, HttpContext> | 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 #outboundMessageConfig = resolveOutboundMessageConfig(undefined)\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, HttpContext>,\n channelRouter: ChannelRouter,\n logger: Logger\n ): Promise<void> {\n this.#status = 'starting'\n this.#lastError = null\n\n this.#channelSubscriptions = new ChannelSubscriptions(\n this,\n channelRouter,\n logger,\n this.#presenceManager ?? undefined\n )\n\n const websocketConfig = config.websocket\n const heartbeatConfig = resolveHeartbeatConfig(websocketConfig)\n const inboundMessageConfig = resolveInboundMessageConfig(websocketConfig)\n this.#outboundMessageConfig = resolveOutboundMessageConfig(websocketConfig)\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, HttpContext>(websocketServer, websocketConfig)\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 logger.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, HttpContext>,\n inboundMessageConfig: InboundMessageConfig\n ): void {\n const socket = this.#wrapSocket(connection, request, upgrade)\n\n connectChannel.traceSync(\n () => {\n this.#sockets.set(socket.id, socket)\n this.emit('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(socket.raw.connection, { id: message.id, type: 'pong' })\n return\n }\n\n const enqueued = this.#messageQueue.enqueue(\n socket.id,\n async () => {\n await this.#handleMessage(socket, message).catch((error) => {\n sendFrame(connection, {\n type: 'error',\n error: error instanceof Error ? error.message : 'Unexpected socket error',\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', async () => {\n const traceMessage = {\n socketId: socket.id,\n reason: 'close',\n subscriptions: socket.channels.size,\n }\n\n await disconnectChannel.tracePromise(async () => {\n this.#clearHeartbeatTimeout(socket.id)\n this.#messageQueue.delete(socket.id)\n this.#messageRates.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.emit('disconnect', { socket, reason: 'close' })\n }, traceMessage)\n })\n }\n\n async #handleMessage(\n socket: AuthenticatedSocket<User, HttpContext>,\n message: TransportMessage\n ): Promise<void> {\n if (!message.valid) {\n sendFrame(socket.raw.connection, message.toRejectionFrame())\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.emit('subscribe', { socket, channel: message.channel })\n }\n\n sendFrame(socket.raw.connection, Reply.fromSubscribeResult(message.id, result).toFrame())\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 = socket.channels.has(message.channel)\n await this.#channelSubscriptions?.leave(socket, message.channel)\n traceMessage.ok = true\n this.emit('unsubscribe', { socket, channel: message.channel })\n sendFrame(socket.raw.connection, Reply.ok(message.id).toFrame())\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, HttpContext>,\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(socket.raw.connection, Reply.fromChannelAck(message.id, ack).toFrame())\n }, traceMessage)\n }\n\n async #handleChannelPayload(\n socket: AuthenticatedSocket<User, HttpContext>,\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, HttpContext>\n ): AuthenticatedSocket<User, HttpContext> {\n const raw: RawSocket<HttpContext> = {\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 channels: new Set(),\n\n emit: (event, data) => {\n this.#sendEventFrame(connection, { 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 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(channel, emission.event, emission.data, emission.except)\n )\n return\n }\n case 'user': {\n const room = emission.room\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)\n )\n return\n }\n case 'global':\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)\n )\n }\n }\n\n #traceBroadcast(message: SocketBroadcastMessage, deliver: () => number): void {\n broadcastChannel.traceSync(() => {\n message.delivered = deliver()\n }, message)\n }\n\n #sendEventFrame(\n connection: WebSocket,\n frame: Extract<ServerProtocolMessage, { type: 'event' }>\n ): boolean {\n return this.#sendSerializedEventFrame(connection, serializeFrame(frame))\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 ): number {\n let delivered = 0\n const serializedFrame = serializeFrame({ type: 'event', channel, event, data })\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(room: string, event: string, data: unknown): number {\n let delivered = 0\n const serializedFrame = serializeFrame({ type: 'event', event, data })\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(event: string, data: unknown): number {\n let delivered = 0\n const serializedFrame = serializeFrame({ type: 'event', event, data })\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, HttpContext> | 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 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\n for (const socket of this.#sockets.values()) {\n socket.raw.connection.terminate()\n }\n\n this.#sockets.clear()\n this.#userRooms.clear()\n this.#socketUserRoom.clear()\n this.#messageQueue.clear()\n this.#messageRates.clear()\n this.#channelSubscriptions?.clear()\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.#bus = null\n this.#httpServer = null\n this.#upgradeHandler = null\n if (httpServer && upgradeHandler) {\n httpServer.off('upgrade', upgradeHandler)\n }\n this.#cleanup()\n\n try {\n await bus?.close()\n\n if (!server) {\n if (this.#status !== 'failed') {\n this.#status = 'stopped'\n }\n return\n }\n\n await new Promise<void>((resolve) => {\n server.close(() => {\n resolve()\n })\n })\n\n if (this.#status !== 'failed') {\n this.#status = 'stopped'\n }\n } catch (error) {\n this.markFailed(error)\n throw error\n }\n }\n}\n","import type { BaseChannel } from './base_channel.js'\n\nexport interface StoredChannelSubscription {\n channelName: string\n instance: BaseChannel<any, 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 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 { MissingPresenceInfoError } from './base_channel.js'\nimport type { BaseChannel } from './base_channel.js'\nimport { ChannelSubscriptionStorage } 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, PresenceMember } from './types.js'\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\n/**\n * Durable channel subscriptions for sockets.\n */\nexport class ChannelSubscriptions<User = unknown, HttpContext = unknown> {\n #storage = new ChannelSubscriptionStorage()\n\n constructor(\n private socketService: SocketService<User, HttpContext>,\n private channelRouter: ChannelRouter,\n private logger: Logger,\n private presenceManager?: PresenceManager\n ) {}\n\n setPresenceManager(presenceManager: PresenceManager): void {\n this.presenceManager = presenceManager\n }\n\n async subscribe(\n socket: AuthenticatedSocket<User, HttpContext>,\n channelName: string\n ): Promise<ChannelSubscribeResult> {\n if (this.#storage.has(socket.id, channelName)) {\n return {\n ack: {\n ok: true,\n presenceData: await this.#getPresenceData(socket, channelName),\n },\n created: false,\n }\n }\n\n const result = await this.channelRouter.authorize(socket, channelName)\n\n if (!result.success) {\n return {\n ack: { ok: false, error: result.error },\n created: false,\n }\n }\n\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 presenceJoined = false\n\n try {\n if (this.#usesPresence(result.instance)) {\n const member = this.#getPresenceMember(result.instance, socket)\n\n this.presenceManager!.join(channelName, socket.raw, member)\n presenceJoined = true\n\n await result.instance.onMemberJoin?.(socket, member, ...result.paramValues)\n await result.instance.onJoin?.(socket, ...result.paramValues)\n\n presenceData = await this.presenceManager!.snapshot(channelName)\n } else {\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 socket.channels.add(channelName)\n\n if (this.#usesPresence(result.instance) && presenceData) {\n this.socketService.to(channelName).except(socket.id).emit('presence:update', presenceData)\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.to(channelName).emit('presence:update', rollbackData)\n }\n }\n\n this.#storage.delete(socket.id, channelName)\n socket.channels.delete(channelName)\n\n return {\n ack: {\n ok: false,\n error: error instanceof MissingPresenceInfoError ? error.message : '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, HttpContext>, channelName: string): Promise<void> {\n const subscription = this.#storage.get(socket.id, channelName)\n\n if (subscription) {\n this.#storage.delete(socket.id, channelName)\n socket.channels.delete(channelName)\n\n try {\n if (this.#usesPresence(subscription.instance)) {\n const member = this.#getPresenceMember(subscription.instance, socket)\n\n this.presenceManager!.leave(channelName, socket.raw)\n const presenceData = await this.presenceManager!.snapshot(channelName)\n\n this.socketService.to(channelName).emit('presence:update', presenceData)\n\n await subscription.instance.onMemberLeave?.(socket, member, ...subscription.paramValues)\n await subscription.instance.onLeave?.(socket, ...subscription.paramValues)\n } else {\n await subscription.instance.onLeave?.(socket, ...subscription.paramValues)\n }\n } catch (error) {\n this.logger.warn(`failed to leave channel \"${channelName}\": %s`, error)\n }\n } else {\n socket.channels.delete(channelName)\n }\n }\n\n async leaveAll(socket: AuthenticatedSocket<User, HttpContext>): Promise<void> {\n for (const channelName of this.getChannelNames(socket.id)) {\n await this.leave(socket, channelName)\n }\n }\n\n async handleMessage(\n socket: AuthenticatedSocket<User, HttpContext>,\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 return { ok: true, data: result }\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Handler error',\n }\n }\n }\n\n relayWhisper(socket: AuthenticatedSocket<User, HttpContext>, 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 }\n\n getSocketIds(channelName: string): string[] {\n return this.#storage.socketIdsFor(channelName)\n }\n\n getChannelNames(socketId: string): string[] {\n return this.#storage.channelNamesFor(socketId)\n }\n\n get channelsCount(): number {\n return this.#storage.channelsCount\n }\n\n #usesPresence(instance: BaseChannel<any, any, any>): boolean {\n return Boolean(\n (instance.constructor as typeof BaseChannel).options?.presence && this.presenceManager\n )\n }\n\n #getPresenceMember(\n instance: BaseChannel<any, any, any>,\n socket: AuthenticatedSocket<User, HttpContext>\n ): PresenceMember {\n return instance.$getPresenceInfo(socket)\n }\n\n async #getPresenceData(\n socket: AuthenticatedSocket<User, HttpContext>,\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 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 = Omit<PresenceUser, 'joinedAt'> & {\n [key: string]: Serializable\n joinedAt: string\n}\n\nexport interface SerializablePresenceSocket {\n [key: string]: Serializable\n id: string\n data: {\n [key: string]: Serializable\n }\n}\n\nexport type SocketBusMessage =\n | {\n type: 'channel:event'\n origin: string\n channel: string\n event: string\n data: Serializable\n except?: string[]\n }\n | {\n type: 'user:event'\n origin: string\n room: string\n event: string\n data: Serializable\n }\n | {\n type: 'broadcast:event'\n origin: string\n event: string\n data: Serializable\n }\n | {\n type: 'presence:sockets:request'\n origin: string\n requestId: string\n channel: string\n }\n | {\n type: 'presence:sockets:response'\n origin: string\n target: string\n requestId: string\n sockets: SerializablePresenceSocket[]\n }\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\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, async (payload) => {\n const message = payload as SocketBusMessage\n\n if (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 await this.#respondToPresenceRequest(message)\n return\n case 'presence:sockets:response':\n this.#handlePresenceResponse(message)\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 }\n\n if (except) {\n message.except = except\n }\n\n void this.#bus.publish(this.#channel, message as Serializable)\n }\n\n publishUser(room: string, event: string, data: unknown): void {\n void this.#bus.publish(this.#channel, {\n type: 'user:event',\n origin: this.#origin,\n room,\n event,\n data: data as Serializable,\n } as Serializable)\n }\n\n publishBroadcast(event: string, data: unknown): void {\n void this.#bus.publish(this.#channel, {\n type: 'broadcast:event',\n origin: this.#origin,\n event,\n data: data as Serializable,\n } as Serializable)\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 void this.#bus.publish(this.#channel, {\n type: 'presence:sockets:request',\n origin: this.#origin,\n requestId,\n channel,\n } as Serializable)\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 await this.#bus.publish(this.#channel, {\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 } as unknown 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 { SocketConfig, SocketUpgradeContext } from './types.js'\n\nexport const DEFAULT_WEBSOCKET_PATH = '/socket'\n\nexport interface AcceptedUpgrade<User, HttpContext> {\n httpContext?: HttpContext\n user?: User\n}\n\nexport type SocketUpgradeHandler = (request: IncomingMessage, socket: Duplex, head: Buffer) => void\n\ntype AcceptUpgrade<User, HttpContext> = (\n connection: WebSocket,\n request: IncomingMessage,\n upgrade: AcceptedUpgrade<User, HttpContext>\n) => void\n\nexport class SocketUpgrader<User = unknown, HttpContext = unknown> {\n #path: string\n\n constructor(\n private server: WebSocketServer,\n private config: SocketConfig<User, HttpContext>['websocket'] | undefined\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, HttpContext>\n ): Promise<boolean> {\n if (!this.#matchesPath(request)) {\n return false\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 #matchesPath(request: IncomingMessage): boolean {\n const url = new URL(request.url ?? '/', 'ws://localhost')\n return url.pathname === this.#path\n }\n\n async #authenticate(\n request: IncomingMessage\n ): Promise<AcceptedUpgrade<User, HttpContext> | null> {\n const config = this.config\n\n if (!config) {\n return {}\n }\n\n if (!config.authenticate && !config.createContextOnUpgrade) {\n return {}\n }\n\n let httpContext: HttpContext | undefined\n try {\n httpContext = await config.createContext?.(request)\n\n if (!config.authenticate) {\n return { httpContext }\n }\n\n const ctx: SocketUpgradeContext<HttpContext> = {\n httpContext,\n }\n\n const result = await config.authenticate(ctx)\n\n if (result === false || result === null) {\n return null\n }\n\n return {\n httpContext,\n user: result,\n }\n } catch {\n return null\n }\n }\n}\n","import type { BaseChannel } from './base_channel.js'\nimport { exec, match, parse, type ParsedRoute } from '@poppinss/matchit'\n\ntype MatchParams = Record<string, string>\n\nexport interface ChannelPatternMatch {\n pattern: ChannelPattern\n channel: typeof BaseChannel\n params: MatchParams\n}\n\ninterface MatchCandidate {\n pattern: ChannelPattern\n channel: typeof BaseChannel\n}\n\nexport class ChannelPattern {\n readonly route: ParsedRoute\n readonly score: number[]\n\n private constructor(readonly value: string) {\n this.route = parse(value)\n this.score = this.route.map((segment) => {\n switch (segment.type) {\n case 0:\n return 40\n case 1:\n return 30\n case 3:\n return 20\n case 2:\n return 0\n }\n })\n }\n\n static from(value: string): ChannelPattern {\n return new ChannelPattern(value)\n }\n\n match(channelName: string): MatchParams | null {\n const matched = match(channelName, [this.route])\n if (matched.length === 0) {\n return null\n }\n\n return exec(channelName, matched, true) as MatchParams\n }\n\n /**\n * Returns the most specific matching candidate. Static segments outrank params,\n * params outrank optional params, and optional params outrank wildcards.\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 routes = sorted.map((candidate) => candidate.pattern.route)\n const matched = match(channelName, routes)\n\n if (matched.length === 0) {\n return null\n }\n\n for (const { pattern, channel } of sorted) {\n if (pattern.route !== matched) {\n continue\n }\n\n const params = pattern.match(channelName)\n if (params) {\n return { pattern, channel, params }\n }\n }\n\n return null\n }\n\n static #compareSpecificity(left: ChannelPattern, right: ChannelPattern): number {\n const length = Math.max(left.score.length, right.score.length)\n\n for (let index = 0; index < length; index++) {\n const scoreDifference = (right.score[index] ?? -1) - (left.score[index] ?? -1)\n if (scoreDifference !== 0) {\n return scoreDifference\n }\n }\n\n return right.score.length - left.score.length\n }\n}\n","import type { BaseChannel } from './base_channel.js'\nimport { ChannelPattern } from './channel_pattern.js'\nimport type {\n AuthenticatedSocket,\n ChannelEventMap,\n ChannelMatch,\n MiddlewareContext,\n} from './types.js'\n\ninterface RegisteredChannel {\n pattern: ChannelPattern\n channel: typeof BaseChannel\n}\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 /**\n * Registers a channel.\n */\n register(channel: typeof BaseChannel): 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, HttpContext = unknown>(\n socket: AuthenticatedSocket<User, HttpContext>,\n channelName: string\n ) {\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 = new matched.channel() as BaseChannel<User, ChannelEventMap, HttpContext>\n const paramValues = Object.values(matched.params)\n\n const ctx: MiddlewareContext<User, HttpContext> = {\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)\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Middleware rejected',\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"]}
package/build/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { C as ChannelRouter, a as SocketFake, b as SocketFakeCountQuery, c as SocketFakeEmission, d as SocketFakeEmissionQuery, e as SocketFakeTarget, S as SocketService } from './socket_service-BN1g3ENk.js';
2
- export { A as AuthenticatedSocket, B as BaseChannel, C as ChannelEventMap, h as ChannelHandlerFn, a as ChannelHandlerMap, b as ChannelMatch, d as ChannelOptions, M as Middleware, i as MiddlewareClass, j as MiddlewareContext, k as MiddlewareFn, P as PresenceManager, l as PresenceMember, R as RawSocket, m as SocketAuthenticationDetails, n as SocketAuthenticationHandler, o as SocketAuthenticationResult, e as SocketConfig, S as SocketEvents, g as SocketHealthSnapshot, p as SocketHttpContextFactory, q as SocketHttpMiddleware, f as SocketServiceStatus, r as SocketUpgradeContext } from './types-BnOi46bE.js';
1
+ export { C as ChannelRouter, S as SocketFake, a as SocketFakeCountQuery, b as SocketFakeEmission, c as SocketFakeEmissionQuery, d as SocketFakeTarget, e as SocketService } from './socket_service-CRmPa74K.js';
2
+ import { S as SocketConfig, a as SocketAuthenticationHandler } from './types-BBLNfcWk.js';
3
+ export { A as AuthenticatedSocket, B as BaseChannel, C as ChannelEventMap, b as ChannelHandlerFn, c as ChannelHandlerMap, d as ChannelMatch, e as ChannelOptions, D as Duration, M as Middleware, f as MiddlewareClass, g as MiddlewareContext, h as MiddlewareFn, P as PresenceManager, i as PresenceMember, R as RawSocket, j as SocketAuthenticationResult, k as SocketEvents, l as SocketHealthSnapshot, m as SocketHttpContextFactory, n as SocketHttpMiddleware, o as SocketServiceStatus, p as SocketUpgradeContext } from './types-BBLNfcWk.js';
3
4
  export { SocketHealthCheck } from './src/health_check.js';
4
5
  export { C as ChannelAck, a as ChannelMessage } from './shared_types-Dw9AphfO.js';
5
6
  import 'node:http';
@@ -9,3 +10,16 @@ import 'ws';
9
10
  import '@adonisjs/core/types/http';
10
11
  import '@boringnode/bus/types/main';
11
12
  import '@adonisjs/core/health';
13
+
14
+ declare function defineConfig<User = unknown, HttpContext = unknown, Config extends SocketConfig<User, HttpContext> = SocketConfig<User, HttpContext>>(config: Config): Config;
15
+
16
+ interface AdonisAuthenticator<User> {
17
+ authenticateUsing(): void | Promise<void>;
18
+ getUserOrFail(): User;
19
+ }
20
+ interface AdonisAuthHttpContext<User> {
21
+ auth: AdonisAuthenticator<User>;
22
+ }
23
+ declare function authenticateWithAdonisAuth<User = unknown, HttpContext extends AdonisAuthHttpContext<User> = AdonisAuthHttpContext<User>>(): SocketAuthenticationHandler<User, HttpContext>;
24
+
25
+ export { SocketAuthenticationHandler, SocketConfig, authenticateWithAdonisAuth, defineConfig };
package/build/index.js CHANGED
@@ -4,18 +4,36 @@ import {
4
4
  PresenceManager,
5
5
  SocketFake,
6
6
  SocketService
7
- } from "./chunk-NRWRLZAO.js";
7
+ } from "./chunk-ILDK672E.js";
8
8
  import "./chunk-XUDFDJME.js";
9
9
  import {
10
10
  SocketHealthCheck
11
11
  } from "./chunk-HK7Z65DA.js";
12
12
  import "./chunk-GKAD2UOA.js";
13
+
14
+ // src/define_config.ts
15
+ function defineConfig(config) {
16
+ return config;
17
+ }
18
+
19
+ // src/adonis_auth.ts
20
+ function authenticateWithAdonisAuth() {
21
+ return async (ctx) => {
22
+ if (!ctx.httpContext) {
23
+ throw new Error("Cannot authenticate socket without an AdonisJS HTTP context");
24
+ }
25
+ await ctx.httpContext.auth.authenticateUsing();
26
+ return ctx.httpContext.auth.getUserOrFail();
27
+ };
28
+ }
13
29
  export {
14
30
  BaseChannel,
15
31
  ChannelRouter,
16
32
  PresenceManager,
17
33
  SocketFake,
18
34
  SocketHealthCheck,
19
- SocketService
35
+ SocketService,
36
+ authenticateWithAdonisAuth,
37
+ defineConfig
20
38
  };
21
39
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/define_config.ts","../src/adonis_auth.ts"],"sourcesContent":["import type { SocketConfig } from './types.js'\n\nexport function defineConfig<\n User = unknown,\n HttpContext = unknown,\n Config extends SocketConfig<User, HttpContext> = SocketConfig<User, HttpContext>,\n>(config: Config): Config {\n return config\n}\n","import type { SocketAuthenticationHandler } from './types.js'\n\ninterface AdonisAuthenticator<User> {\n authenticateUsing(): void | Promise<void>\n getUserOrFail(): User\n}\n\ninterface AdonisAuthHttpContext<User> {\n auth: AdonisAuthenticator<User>\n}\n\nexport function authenticateWithAdonisAuth<\n User = unknown,\n HttpContext extends AdonisAuthHttpContext<User> = AdonisAuthHttpContext<User>,\n>(): SocketAuthenticationHandler<User, HttpContext> {\n return async (ctx) => {\n if (!ctx.httpContext) {\n throw new Error('Cannot authenticate socket without an AdonisJS HTTP context')\n }\n\n await ctx.httpContext.auth.authenticateUsing()\n\n return ctx.httpContext.auth.getUserOrFail()\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAEO,SAAS,aAId,QAAwB;AACxB,SAAO;AACT;;;ACGO,SAAS,6BAGoC;AAClD,SAAO,OAAO,QAAQ;AACpB,QAAI,CAAC,IAAI,aAAa;AACpB,YAAM,IAAI,MAAM,6DAA6D;AAAA,IAC/E;AAEA,UAAM,IAAI,YAAY,KAAK,kBAAkB;AAE7C,WAAO,IAAI,YAAY,KAAK,cAAc;AAAA,EAC5C;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { ApplicationService } from '@adonisjs/core/types';
2
- import { S as SocketService, C as ChannelRouter } from '../socket_service-BN1g3ENk.js';
3
- import { P as PresenceManager } from '../types-BnOi46bE.js';
2
+ import { e as SocketService, C as ChannelRouter } from '../socket_service-CRmPa74K.js';
3
+ import { P as PresenceManager } from '../types-BBLNfcWk.js';
4
4
  import 'node:http';
5
5
  import '@adonisjs/logger';
6
6
  import 'emittery';
@@ -2,14 +2,14 @@ import {
2
2
  ChannelRouter,
3
3
  PresenceManager,
4
4
  SocketService
5
- } from "../chunk-NRWRLZAO.js";
5
+ } from "../chunk-ILDK672E.js";
6
6
  import "../chunk-XUDFDJME.js";
7
7
  import "../chunk-GKAD2UOA.js";
8
8
 
9
9
  // providers/socket_provider.ts
10
10
  import { ServerResponse } from "http";
11
11
  function isMiddlewareClass(middleware) {
12
- return typeof middleware === "function" && "handle" in middleware.prototype;
12
+ return typeof middleware === "function" && middleware.prototype !== void 0 && "handle" in middleware.prototype;
13
13
  }
14
14
  var SocketProvider = class {
15
15
  constructor(app) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../providers/socket_provider.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 { PresenceManager } from '../src/presence_manager.js'\nimport type { SocketConfig, SocketHttpMiddleware } from '../src/types.js'\n\nfunction isMiddlewareClass(middleware: SocketHttpMiddleware): middleware is MiddlewareAsClass {\n return typeof middleware === 'function' && 'handle' in middleware.prototype\n}\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(httpServer, this.#withHttpContextFactory(config, server), router, logger)\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 #withHttpContextFactory(config: SocketConfig, server: AdonisServer): SocketConfig {\n const middleware = config.websocket?.middleware ?? []\n\n if (!config.websocket?.authenticate && middleware.length === 0) {\n return config\n }\n\n const createContext = config.websocket?.createContext\n\n return {\n ...config,\n websocket: {\n ...config.websocket,\n createContextOnUpgrade: middleware.length > 0,\n createContext: async (request) => {\n if (createContext) {\n const httpContext = await createContext(request)\n await this.#runUpgradeMiddleware(server, middleware, httpContext)\n return httpContext\n }\n\n const response = new ServerResponse(request)\n const adonisRequest = server.createRequest(request, response)\n const adonisResponse = server.createResponse(request, response)\n\n const httpContext = server.createHttpContext(\n adonisRequest,\n adonisResponse,\n this.app.container.createResolver()\n )\n\n await this.#runUpgradeMiddleware(server, middleware, httpContext)\n\n return httpContext\n },\n },\n }\n }\n\n /**\n * Runs middleware attached to WebSocket upgrade requests.\n */\n async #runUpgradeMiddleware(\n server: AdonisServer,\n middleware: NonNullable<NonNullable<SocketConfig['websocket']>['middleware']>,\n httpContext: unknown\n ): Promise<void> {\n if (middleware.length === 0) {\n return\n }\n\n const ctx = httpContext as HttpContext\n const middlewareClasses = await Promise.all(\n middleware.map(async (one) => {\n if (isMiddlewareClass(one)) {\n return one\n }\n\n const moduleExports = await one()\n return moduleExports.default\n })\n )\n\n await server\n .pipeline(middlewareClasses as MiddlewareAsClass[])\n .errorHandler((error) => {\n throw error\n })\n .finalHandler(async () => {})\n .run(ctx)\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 { glob } = await import('node:fs/promises')\n const { resolve } = await import('node:path')\n\n const config = this.app.config.get<SocketConfig>('socket', {})\n const patterns = config.channels?.patterns ?? ['app/channels/**/*_channel.{ts,js}']\n\n for (const channelPattern of patterns) {\n const pattern = this.app.makePath(channelPattern)\n\n for await (const file of glob(pattern)) {\n try {\n const absolutePath = resolve(file)\n const module = await import(`file://${absolutePath}`)\n const channelClass = module.default\n\n if (channelClass?.pattern) {\n router.register(channelClass)\n logger.info('registered channel: %s', channelClass.pattern)\n }\n } catch (error) {\n logger.warn('failed to load channel from %s: %s', file, error)\n }\n }\n }\n\n logger.info('total channels registered: %d', router.size)\n }\n}\n"],"mappings":"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","names":["httpContext"]}
1
+ {"version":3,"sources":["../../providers/socket_provider.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 { PresenceManager } from '../src/presence_manager.js'\nimport type { SocketConfig, SocketHttpMiddleware } from '../src/types.js'\n\nfunction isMiddlewareClass(middleware: SocketHttpMiddleware): middleware is MiddlewareAsClass {\n return (\n typeof middleware === 'function' &&\n middleware.prototype !== undefined &&\n 'handle' in middleware.prototype\n )\n}\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(httpServer, this.#withHttpContextFactory(config, server), router, logger)\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 #withHttpContextFactory(config: SocketConfig, server: AdonisServer): SocketConfig {\n const middleware = config.websocket?.middleware ?? []\n\n if (!config.websocket?.authenticate && middleware.length === 0) {\n return config\n }\n\n const createContext = config.websocket?.createContext\n\n return {\n ...config,\n websocket: {\n ...config.websocket,\n createContextOnUpgrade: middleware.length > 0,\n createContext: async (request) => {\n if (createContext) {\n const httpContext = await createContext(request)\n await this.#runUpgradeMiddleware(server, middleware, httpContext)\n return httpContext\n }\n\n const response = new ServerResponse(request)\n const adonisRequest = server.createRequest(request, response)\n const adonisResponse = server.createResponse(request, response)\n\n const httpContext = server.createHttpContext(\n adonisRequest,\n adonisResponse,\n this.app.container.createResolver()\n )\n\n await this.#runUpgradeMiddleware(server, middleware, httpContext)\n\n return httpContext\n },\n },\n }\n }\n\n /**\n * Runs middleware attached to WebSocket upgrade requests.\n */\n async #runUpgradeMiddleware(\n server: AdonisServer,\n middleware: NonNullable<NonNullable<SocketConfig['websocket']>['middleware']>,\n httpContext: unknown\n ): Promise<void> {\n if (middleware.length === 0) {\n return\n }\n\n const ctx = httpContext as HttpContext\n const middlewareClasses = await Promise.all(\n middleware.map(async (one) => {\n if (isMiddlewareClass(one)) {\n return one\n }\n\n const moduleExports = await one()\n return moduleExports.default\n })\n )\n\n await server\n .pipeline(middlewareClasses as MiddlewareAsClass[])\n .errorHandler((error) => {\n throw error\n })\n .finalHandler(async () => {})\n .run(ctx)\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 { glob } = await import('node:fs/promises')\n const { resolve } = await import('node:path')\n\n const config = this.app.config.get<SocketConfig>('socket', {})\n const patterns = config.channels?.patterns ?? ['app/channels/**/*_channel.{ts,js}']\n\n for (const channelPattern of patterns) {\n const pattern = this.app.makePath(channelPattern)\n\n for await (const file of glob(pattern)) {\n try {\n const absolutePath = resolve(file)\n const module = await import(`file://${absolutePath}`)\n const channelClass = module.default\n\n if (channelClass?.pattern) {\n router.register(channelClass)\n logger.info('registered channel: %s', channelClass.pattern)\n }\n } catch (error) {\n logger.warn('failed to load channel from %s: %s', file, error)\n }\n }\n }\n\n logger.info('total channels registered: %d', router.size)\n }\n}\n"],"mappings":"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","names":["httpContext"]}
@@ -1,9 +1,9 @@
1
- import { S as SocketService } from '../socket_service-BN1g3ENk.js';
1
+ import { e as SocketService } from '../socket_service-CRmPa74K.js';
2
2
  import 'node:http';
3
3
  import '@adonisjs/logger';
4
4
  import 'emittery';
5
5
  import 'ws';
6
- import '../types-BnOi46bE.js';
6
+ import '../types-BBLNfcWk.js';
7
7
  import '@adonisjs/core/types/http';
8
8
  import '@boringnode/bus/types/main';
9
9
  import '../shared_types-Dw9AphfO.js';
@@ -2,7 +2,7 @@ import { Server } from 'node:http';
2
2
  import { Logger } from '@adonisjs/logger';
3
3
  import Emittery from 'emittery';
4
4
  import { WebSocketServer } from 'ws';
5
- import { B as BaseChannel, b as ChannelMatch, A as AuthenticatedSocket, C as ChannelEventMap, c as PresenceData, d as ChannelOptions, S as SocketEvents, P as PresenceManager, e as SocketConfig, f as SocketServiceStatus, g as SocketHealthSnapshot } from './types-BnOi46bE.js';
5
+ import { B as BaseChannel, d as ChannelMatch, A as AuthenticatedSocket, C as ChannelEventMap, q as PresenceData, e as ChannelOptions, k as SocketEvents, P as PresenceManager, S as SocketConfig, o as SocketServiceStatus, l as SocketHealthSnapshot } from './types-BBLNfcWk.js';
6
6
 
7
7
  /**
8
8
  * Matches channel names against registered patterns.
@@ -141,4 +141,4 @@ declare class SocketService<User = unknown, HttpContext = unknown> extends Emitt
141
141
  close(): Promise<void>;
142
142
  }
143
143
 
144
- export { ChannelRouter as C, SocketService as S, SocketFake as a, type SocketFakeCountQuery as b, type SocketFakeEmission as c, type SocketFakeEmissionQuery as d, type SocketFakeTarget as e };
144
+ export { ChannelRouter as C, SocketFake as S, type SocketFakeCountQuery as a, type SocketFakeEmission as b, type SocketFakeEmissionQuery as c, type SocketFakeTarget as d, SocketService as e };
@@ -609,14 +609,12 @@ var Socket = class {
609
609
  #channels = /* @__PURE__ */ new Map();
610
610
  #url;
611
611
  #path;
612
- #auth;
613
612
  #session;
614
613
  constructor(options = {}) {
615
614
  const browserWindow = globalThis;
616
615
  const browserOrigin = typeof globalThis === "object" && browserWindow.window?.location?.origin ? browserWindow.window.location.origin : "";
617
616
  this.#url = options.url ?? browserOrigin;
618
617
  this.#path = options.path ?? "/socket";
619
- this.#auth = options.auth;
620
618
  this.#session = new ClientSocketSession({
621
619
  buildUrl: () => this.#buildUrl(),
622
620
  autoReconnect: options.autoReconnect,
@@ -680,9 +678,6 @@ var Socket = class {
680
678
  const url = new URL(this.#url || browserGlobal.location?.origin || "http://localhost");
681
679
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
682
680
  url.pathname = this.#path;
683
- if (this.#auth) {
684
- url.searchParams.set("auth", JSON.stringify(this.#auth));
685
- }
686
681
  return url.toString();
687
682
  }
688
683
  async #resubscribeChannels() {