@rlanz/socket 0.0.1-4 → 0.0.1-6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +430 -26
  2. package/build/chunk-B4Y3TNDI.js +159 -0
  3. package/build/chunk-B4Y3TNDI.js.map +1 -0
  4. package/build/{chunk-GKAD2UOA.js → chunk-D3HUBCBW.js} +1 -1
  5. package/build/chunk-D3HUBCBW.js.map +1 -0
  6. package/build/chunk-FVPY6HZW.js +136 -0
  7. package/build/chunk-FVPY6HZW.js.map +1 -0
  8. package/build/chunk-SFAY2ZA4.js +28 -0
  9. package/build/chunk-SFAY2ZA4.js.map +1 -0
  10. package/build/{chunk-XUDFDJME.js → chunk-SHH6U4CI.js} +12 -9
  11. package/build/chunk-SHH6U4CI.js.map +1 -0
  12. package/build/chunk-YAX5EHHB.js +453 -0
  13. package/build/chunk-YAX5EHHB.js.map +1 -0
  14. package/build/framework-DuW6zpPk.d.ts +14 -0
  15. package/build/index.d.ts +7 -13
  16. package/build/index.js +18 -10
  17. package/build/index.js.map +1 -1
  18. package/build/providers/socket_provider.d.ts +4 -3
  19. package/build/providers/socket_provider.js +1780 -57
  20. package/build/providers/socket_provider.js.map +1 -1
  21. package/build/services/socket.d.ts +4 -3
  22. package/build/socket_service-D3jKrleE.d.ts +105 -0
  23. package/build/src/assembler_hook.d.ts +15 -0
  24. package/build/src/assembler_hook.js +261 -0
  25. package/build/src/assembler_hook.js.map +1 -0
  26. package/build/src/client/index.d.ts +46 -12
  27. package/build/src/client/index.js +223 -76
  28. package/build/src/client/index.js.map +1 -1
  29. package/build/src/client/react.d.ts +27 -0
  30. package/build/src/client/react.js +69 -0
  31. package/build/src/client/react.js.map +1 -0
  32. package/build/src/client/svelte.d.ts +23 -0
  33. package/build/src/client/svelte.js +82 -0
  34. package/build/src/client/svelte.js.map +1 -0
  35. package/build/src/client/types.d.ts +69 -5
  36. package/build/src/client/vue.d.ts +26 -0
  37. package/build/src/client/vue.js +81 -0
  38. package/build/src/client/vue.js.map +1 -0
  39. package/build/src/decorators.d.ts +4 -4
  40. package/build/src/decorators.js +1 -1
  41. package/build/src/health_check.d.ts +4 -3
  42. package/build/src/otel.js +4 -5
  43. package/build/src/otel.js.map +1 -1
  44. package/build/src/testing.d.ts +54 -0
  45. package/build/src/testing.js +7 -0
  46. package/build/src/testing.js.map +1 -0
  47. package/build/src/types.d.ts +2 -2
  48. package/build/{types-BBLNfcWk.d.ts → types-DiYaFvgi.d.ts} +112 -63
  49. package/package.json +41 -6
  50. package/build/chunk-GKAD2UOA.js.map +0 -1
  51. package/build/chunk-ILDK672E.js +0 -1921
  52. package/build/chunk-ILDK672E.js.map +0 -1
  53. package/build/chunk-XUDFDJME.js.map +0 -1
  54. package/build/shared_types-Dw9AphfO.d.ts +0 -21
  55. package/build/socket_service-CRmPa74K.d.ts +0 -144
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/client/channel.ts","../../../src/client/socket_session.ts","../../../src/client/socket.ts"],"sourcesContent":["import type {\n SocketClientTransport,\n SubscribeOptions,\n SubscribeResult,\n UnsubscribeOptions,\n PresenceData,\n PresenceUser,\n EventHandler,\n ChannelMessage,\n ChannelAck,\n} from './types.js'\n\nconst CLIENT_EVENT_PREFIX = 'client:'\n\ninterface PendingSubscribe {\n promise: Promise<Channel>\n resolve: (channel: Channel) => void\n reject: (error: Error) => void\n token: number\n}\n\n/**\n * Represents a subscribed channel.\n * Chainable API inspired by Laravel Echo.\n *\n * @example\n * ```ts\n * socket.channel('chat/general')\n * .here((users) => setOnlineUsers(users))\n * .joining((user) => console.log(`${user.name} joined`))\n * .leaving((user) => console.log(`${user.name} left`))\n * .listen('chat:message', (msg) => addMessage(msg))\n * .subscribe()\n * ```\n */\nexport class Channel {\n /**\n * Channel name.\n */\n readonly name: string\n\n /**\n * Socket client transport.\n */\n #transport: SocketClientTransport\n\n /**\n * Whether the channel should stay subscribed.\n */\n #subscribed = false\n #active = false\n\n /**\n * Event handlers grouped by event type.\n */\n #eventHandlers = new Map<string, Set<EventHandler>>()\n\n /**\n * Current presence data.\n */\n #presence: PresenceData | null = null\n\n /**\n * Present user IDs used to detect join and leave events.\n */\n #presentUserIds = new Set<string>()\n\n /**\n * Handler registered through .here().\n */\n #hereHandler: EventHandler<PresenceUser[]> | null = null\n\n /**\n * Handler registered through .joining().\n */\n #joiningHandler: EventHandler<PresenceUser> | null = null\n\n /**\n * Handler registered through .leaving().\n */\n #leavingHandler: EventHandler<PresenceUser> | null = null\n\n /**\n * Internal transport handlers to clean up on unsubscribe.\n */\n #boundPresenceHandler: ((data: unknown) => void) | null = null\n #boundEventHandler: ((data: unknown) => void) | null = null\n #boundDisconnectHandler: (() => void) | null = null\n #listenersAttached = false\n #pendingSubscribe: PendingSubscribe | null = null\n #subscribeToken = 0\n\n constructor(name: string, transport: SocketClientTransport) {\n this.name = name\n this.#transport = transport\n }\n\n /**\n * Whether the channel should stay subscribed.\n */\n get subscribed(): boolean {\n return this.#subscribed\n }\n\n /**\n * Whether the channel is active on the server.\n */\n get active(): boolean {\n return this.#active\n }\n\n /**\n * List of present users.\n */\n get users(): PresenceUser[] {\n return this.#presence?.users ?? []\n }\n\n /**\n * Number of present users.\n */\n get count(): number {\n return this.#presence?.count ?? 0\n }\n\n /**\n * Registers a handler called with the present users.\n * Called immediately on subscribe and after each presence change.\n */\n here(handler: EventHandler<PresenceUser[]>): this {\n this.#hereHandler = handler\n return this\n }\n\n /**\n * Registers a handler called when a user joins.\n */\n joining(handler: EventHandler<PresenceUser>): this {\n this.#joiningHandler = handler\n return this\n }\n\n /**\n * Registers a handler called when a user leaves.\n */\n leaving(handler: EventHandler<PresenceUser>): this {\n this.#leavingHandler = handler\n return this\n }\n\n /**\n * Listens for an event on this channel.\n */\n listen<T = unknown>(event: string, handler: EventHandler<T>): this {\n if (!this.#eventHandlers.has(event)) {\n this.#eventHandlers.set(event, new Set())\n }\n this.#eventHandlers.get(event)!.add(handler as EventHandler)\n return this\n }\n\n /**\n * Removes an event listener.\n */\n stopListening(event: string, handler?: EventHandler): this {\n if (handler) {\n this.#eventHandlers.get(event)?.delete(handler)\n } else {\n this.#eventHandlers.delete(event)\n }\n return this\n }\n\n /**\n * Listens for a client event whispered by another channel member.\n */\n listenForWhisper<T = unknown>(event: string, handler: EventHandler<T>): this {\n return this.listen(`${CLIENT_EVENT_PREFIX}${event}`, handler)\n }\n\n /**\n * Removes a whispered client event listener.\n */\n stopListeningForWhisper(event: string, handler?: EventHandler): this {\n return this.stopListening(`${CLIENT_EVENT_PREFIX}${event}`, handler)\n }\n\n /**\n * Subscribes to the channel.\n *\n * client listeners -> subscribe ack -> active channel\n * | | |\n * v v v\n * events ready presence sync send/listen\n */\n async subscribe(options: SubscribeOptions = {}): Promise<this> {\n this.#subscribed = true\n\n if (this.#pendingSubscribe) {\n return this.#pendingSubscribe.promise as Promise<this>\n }\n\n if (this.#active) {\n return this\n }\n\n const timeout = options.timeout ?? 5000\n\n // Attach listeners before subscribing so the first server events are not missed.\n if (!this.#listenersAttached) {\n this.#setupSocketListeners()\n }\n\n const token = ++this.#subscribeToken\n\n let resolvePromise: (channel: Channel) => void\n let rejectPromise: (error: Error) => void\n\n const promise = new Promise<Channel>((resolve, reject) => {\n resolvePromise = resolve\n rejectPromise = reject\n })\n\n this.#pendingSubscribe = {\n promise,\n resolve: resolvePromise!,\n reject: rejectPromise!,\n token,\n }\n\n const { resolve, reject } = this.#pendingSubscribe\n\n const timer = setTimeout(() => {\n if (token !== this.#subscribeToken) return\n this.#pendingSubscribe = null\n this.#resetConnectionState()\n reject(new Error(`Subscribe timeout for channel: ${this.name}`))\n }, timeout)\n\n this.#transport\n .sendRequest<SubscribeResult>({ type: 'subscribe', channel: this.name }, timeout)\n .then((response) => {\n if (token !== this.#subscribeToken) return\n clearTimeout(timer)\n this.#pendingSubscribe = null\n\n if (response.ok) {\n this.#active = true\n\n const presenceData = response.data?.presenceData ?? response.presenceData\n\n // Apply the initial presence snapshot.\n if (presenceData) {\n this.#handleInitialPresence(presenceData)\n }\n\n resolve(this)\n } else {\n this.#resetConnectionState()\n reject(new Error(response.error ?? 'Subscribe failed'))\n }\n })\n .catch((error) => {\n if (token !== this.#subscribeToken) return\n clearTimeout(timer)\n this.#pendingSubscribe = null\n this.#resetConnectionState()\n reject(error instanceof Error ? error : new Error('Subscribe failed'))\n })\n\n return promise as Promise<this>\n }\n\n /**\n * Unsubscribes from the channel.\n */\n async unsubscribe(options: UnsubscribeOptions = {}): Promise<void> {\n if (!this.#subscribed && !this.#active) return\n this.#subscribed = false\n this.#subscribeToken++\n if (this.#pendingSubscribe) {\n this.#pendingSubscribe.reject(new Error(`Unsubscribed from channel: ${this.name}`))\n this.#pendingSubscribe = null\n }\n\n return new Promise((resolve) => {\n const timeout = options.timeout ?? 5000\n const timer = setTimeout(() => {\n this.#cleanupTerminal()\n resolve()\n }, timeout)\n\n this.#transport\n .sendRequest({ type: 'unsubscribe', channel: this.name }, timeout)\n .then(() => {\n clearTimeout(timer)\n this.#cleanupTerminal()\n resolve()\n })\n .catch(() => {\n clearTimeout(timer)\n this.#cleanupTerminal()\n resolve()\n })\n })\n }\n\n /**\n * Sends an event to the server.\n */\n send<T = unknown>(event: string, data?: T): this {\n if (!this.#active) {\n console.warn(`Cannot send to channel ${this.name}: not subscribed`)\n return this\n }\n const payload: ChannelMessage = {\n channel: this.name,\n event,\n data,\n }\n this.#transport.send({ type: 'message', ...payload })\n return this\n }\n\n /**\n * Relays a client event to other members of this channel.\n */\n whisper<T = unknown>(event: string, data?: T): this {\n if (!this.#active) {\n console.warn(`Cannot whisper to channel ${this.name}: not subscribed`)\n return this\n }\n const payload: ChannelMessage = {\n channel: this.name,\n event,\n data,\n }\n this.#transport.send({ type: 'whisper', ...payload })\n return this\n }\n\n /**\n * Sends an event and waits for a response.\n */\n async sendWithAck<T = unknown, R = unknown>(event: string, data?: T): Promise<R> {\n if (!this.#active) {\n throw new Error(`Cannot send to channel ${this.name}: not subscribed`)\n }\n const payload: ChannelMessage = {\n channel: this.name,\n event,\n data,\n }\n const response = await this.#transport.sendRequest<ChannelAck<R>>({\n type: 'message',\n ...payload,\n })\n if (!response?.ok) {\n throw new Error(response?.error ?? `Channel handler failed: ${event}`)\n }\n return response.data as R\n }\n\n /**\n * Configures transport listeners.\n */\n #setupSocketListeners(): void {\n // Handler for presence:update.\n this.#boundPresenceHandler = (data: unknown) => {\n if (!data || typeof data !== 'object') return\n this.#handlePresenceUpdate(data as PresenceData)\n }\n this.#transport.on(`channel:${this.name}:presence:update`, this.#boundPresenceHandler)\n\n this.#boundEventHandler = (data: unknown) => {\n if (!data || typeof data !== 'object') return\n\n const payload = data as { event?: string; data?: unknown }\n if (!payload.event) return\n\n const handlers = this.#eventHandlers.get(payload.event)\n handlers?.forEach((handler) => handler(payload.data))\n }\n this.#transport.on(`channel:${this.name}:event`, this.#boundEventHandler)\n\n // Mark the channel inactive when the socket disconnects.\n this.#boundDisconnectHandler = () => {\n this.#resetConnectionState()\n }\n this.#transport.on('disconnect', this.#boundDisconnectHandler)\n\n this.#listenersAttached = true\n }\n\n /**\n * Handles the initial presence snapshot.\n */\n #handleInitialPresence(data: PresenceData): void {\n this.#presence = data\n this.#presentUserIds = new Set(data.users.map((u) => u.id))\n\n // Call here() with all users.\n this.#hereHandler?.(data.users)\n }\n\n /**\n * Handles a presence update.\n *\n * previous IDs current IDs\n * | |\n * +-- diff in -----+--> joining / leaving callbacks\n */\n #handlePresenceUpdate(data: PresenceData): void {\n const previousIds = this.#presentUserIds\n const currentIds = new Set(data.users.map((u) => u.id))\n\n // Detect new users.\n for (const user of data.users) {\n if (!previousIds.has(user.id)) {\n this.#joiningHandler?.(user)\n }\n }\n\n // Detect users that left.\n if (this.#presence) {\n for (const user of this.#presence.users) {\n if (!currentIds.has(user.id)) {\n this.#leavingHandler?.(user)\n }\n }\n }\n\n // Update local state.\n this.#presence = data\n this.#presentUserIds = currentIds\n\n // Call here() with the updated list.\n this.#hereHandler?.(data.users)\n }\n\n #resetConnectionState(): void {\n this.#active = false\n this.#presence = null\n this.#presentUserIds.clear()\n }\n\n #detachTransportListeners(): void {\n if (this.#boundPresenceHandler) {\n this.#transport.off(`channel:${this.name}:presence:update`, this.#boundPresenceHandler)\n this.#boundPresenceHandler = null\n }\n\n if (this.#boundEventHandler) {\n this.#transport.off(`channel:${this.name}:event`, this.#boundEventHandler)\n this.#boundEventHandler = null\n }\n\n if (this.#boundDisconnectHandler) {\n this.#transport.off('disconnect', this.#boundDisconnectHandler)\n this.#boundDisconnectHandler = null\n }\n\n this.#listenersAttached = false\n }\n\n #clearUserCallbacks(): void {\n this.#eventHandlers.clear()\n this.#hereHandler = null\n this.#joiningHandler = null\n this.#leavingHandler = null\n }\n\n /**\n * Performs terminal cleanup after the user leaves or the socket is disposed.\n */\n #cleanupTerminal(): void {\n this.#subscribed = false\n this.#resetConnectionState()\n this.#detachTransportListeners()\n this.#clearUserCallbacks()\n }\n}\n","import type { ConnectionState, EventHandler } from './types.js'\nimport type { ServerProtocolMessage } from '../shared_types.js'\n\ninterface PendingRequest {\n resolve: (value: unknown) => void\n reject: (error: Error) => void\n timer: ReturnType<typeof setTimeout>\n}\n\ninterface ClientSocketSessionOptions {\n buildUrl: () => string\n createWebSocket?: (url: string) => WebSocket\n autoReconnect?: boolean\n reconnectDelay?: number\n reconnectMaxDelay?: number\n onConnected?: () => void\n}\n\nexport class ClientSocketSession {\n #ws: WebSocket | null = null\n #state: ConnectionState = 'disconnected'\n #connectPromise: Promise<void> | null = null\n #cancelConnect: ((error: Error) => void) | null = null\n #stateHandlers = new Set<EventHandler<ConnectionState>>()\n #eventHandlers = new Map<string, Set<EventHandler>>()\n #pendingRequests = new Map<string, PendingRequest>()\n #requestId = 0\n #reconnectAttempts = 0\n #reconnectTimer: ReturnType<typeof setTimeout> | null = null\n #manualDisconnect = false\n #buildUrl: () => string\n #createWebSocket: (url: string) => WebSocket\n #autoReconnect: boolean\n #reconnectDelay: number\n #reconnectMaxDelay: number\n #onConnected?: () => void\n\n constructor(options: ClientSocketSessionOptions) {\n this.#buildUrl = options.buildUrl\n this.#createWebSocket = options.createWebSocket ?? ((url) => new WebSocket(url))\n this.#autoReconnect = options.autoReconnect ?? true\n this.#reconnectDelay = Math.max(0, options.reconnectDelay ?? 250)\n this.#reconnectMaxDelay = Math.max(this.#reconnectDelay, options.reconnectMaxDelay ?? 5000)\n this.#onConnected = options.onConnected\n }\n\n get state(): ConnectionState {\n return this.#state\n }\n\n get connected(): boolean {\n return this.#state === 'connected'\n }\n\n connect(): Promise<void> {\n if (this.#state === 'connected') {\n return Promise.resolve()\n }\n\n if (this.#connectPromise) {\n return this.#connectPromise\n }\n\n this.#manualDisconnect = false\n this.#setState('connecting')\n\n const connectPromise = new Promise<void>((resolve, reject) => {\n const ws = this.#createWebSocket(this.#buildUrl())\n this.#ws = ws\n let settled = false\n\n const cleanup = () => {\n ws.removeEventListener('open', handleOpen)\n ws.removeEventListener('error', handleError)\n if (this.#connectPromise === connectPromise) {\n this.#connectPromise = null\n }\n if (this.#cancelConnect === cancelConnect) {\n this.#cancelConnect = null\n }\n }\n\n const cancelConnect = (error: Error) => {\n if (settled) {\n return\n }\n\n settled = true\n cleanup()\n reject(error)\n }\n\n const handleOpen = () => {\n settled = true\n cleanup()\n this.#reconnectAttempts = 0\n this.#setState('connected')\n this.#emitLocal('connect')\n this.#onConnected?.()\n resolve()\n }\n\n const handleError = () => {\n cancelConnect(new Error('WebSocket connection failed'))\n if (this.#ws === ws) {\n this.#setState('disconnected')\n }\n }\n\n const handleClose = () => {\n cancelConnect(new Error('WebSocket connection failed'))\n\n if (this.#ws === ws) {\n this.#handleClose()\n }\n }\n\n this.#cancelConnect = cancelConnect\n ws.addEventListener('open', handleOpen)\n ws.addEventListener('error', handleError)\n ws.addEventListener('message', (event) => this.#handleIncoming(event.data))\n ws.addEventListener('close', handleClose)\n })\n\n this.#connectPromise = connectPromise\n return connectPromise\n }\n\n disconnect(): void {\n this.#manualDisconnect = true\n if (this.#reconnectTimer) {\n clearTimeout(this.#reconnectTimer)\n this.#reconnectTimer = null\n }\n\n this.#cancelConnect?.(new Error('Socket disconnected'))\n this.#reconnectAttempts = 0\n this.#ws?.close()\n this.#rejectPending(new Error('Socket disconnected'))\n }\n\n onStateChange(handler: EventHandler<ConnectionState>): () => void {\n this.#stateHandlers.add(handler)\n\n return () => {\n this.#stateHandlers.delete(handler)\n }\n }\n\n on<T = unknown>(event: string, handler: EventHandler<T>): () => void {\n if (!this.#eventHandlers.has(event)) {\n this.#eventHandlers.set(event, new Set())\n }\n\n this.#eventHandlers.get(event)!.add(handler as EventHandler)\n\n return () => {\n this.off(event, handler as EventHandler)\n }\n }\n\n off(event: string, handler: EventHandler): void {\n this.#eventHandlers.get(event)?.delete(handler)\n }\n\n send(message: Record<string, unknown>): void {\n if (this.#ws?.readyState !== WebSocket.OPEN) {\n return\n }\n\n this.#ws.send(JSON.stringify(message))\n }\n\n sendRequest<T = unknown>(message: Record<string, unknown>, timeout = 5000): Promise<T> {\n if (this.#ws?.readyState !== WebSocket.OPEN) {\n return Promise.reject(new Error('Socket is not connected'))\n }\n\n const id = String(++this.#requestId)\n const payload = { id, ...message }\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingRequests.delete(id)\n reject(new Error('Socket request timed out'))\n }, timeout)\n\n this.#pendingRequests.set(id, { resolve: resolve as (value: unknown) => void, reject, timer })\n this.#ws!.send(JSON.stringify(payload))\n })\n }\n\n #handleIncoming(raw: unknown): void {\n const message = this.#parseMessage(raw)\n if (!message) {\n return\n }\n\n if (message.type === 'ack') {\n this.#resolveAck(message)\n return\n }\n\n if (message.type === 'event') {\n if (message.channel) {\n if (message.event === 'presence:update') {\n this.#emitLocal(`channel:${message.channel}:presence:update`, message.data)\n return\n }\n\n this.#emitLocal(`channel:${message.channel}:event`, {\n event: message.event,\n data: message.data,\n })\n return\n }\n\n this.#emitLocal(message.event, message.data)\n }\n }\n\n #parseMessage(raw: unknown): ServerProtocolMessage | null {\n try {\n const data = typeof raw === 'string' ? raw : String(raw)\n const message = JSON.parse(data)\n return message && typeof message === 'object' ? (message as ServerProtocolMessage) : null\n } catch {\n return null\n }\n }\n\n #resolveAck(message: Extract<ServerProtocolMessage, { type: 'ack' }>): void {\n if (!message.id) {\n return\n }\n\n const pending = this.#pendingRequests.get(message.id)\n if (!pending) {\n return\n }\n\n clearTimeout(pending.timer)\n this.#pendingRequests.delete(message.id)\n\n if (message.ok) {\n pending.resolve({ ok: true, data: message.data })\n } else {\n pending.resolve({ ok: false, error: message.error })\n }\n }\n\n #handleClose(): void {\n const shouldEmitDisconnect = this.#state !== 'disconnected'\n\n this.#setState('disconnected')\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n this.#rejectPending(new Error('Socket disconnected'))\n\n this.#scheduleReconnect()\n }\n\n #scheduleReconnect(): void {\n if (this.#manualDisconnect || !this.#autoReconnect || this.#reconnectTimer) {\n return\n }\n\n const delay = Math.min(\n this.#reconnectDelay * 2 ** this.#reconnectAttempts,\n this.#reconnectMaxDelay\n )\n this.#reconnectAttempts += 1\n\n this.#reconnectTimer = setTimeout(() => {\n this.#reconnectTimer = null\n this.connect().catch(() => this.#handleClose())\n }, delay)\n }\n\n #rejectPending(error: Error): void {\n for (const [id, pending] of this.#pendingRequests) {\n clearTimeout(pending.timer)\n pending.reject(error)\n this.#pendingRequests.delete(id)\n }\n }\n\n #emitLocal(event: string, data?: unknown): void {\n this.#eventHandlers.get(event)?.forEach((handler) => handler(data))\n }\n\n #setState(state: ConnectionState): void {\n if (this.#state === state) {\n return\n }\n\n this.#state = state\n this.#stateHandlers.forEach((handler) => handler(state))\n }\n}\n","import { Channel } from './channel.js'\nimport { ClientSocketSession } from './socket_session.js'\nimport type {\n SocketOptions,\n ConnectionState,\n EventHandler,\n SocketClientTransport,\n} from './types.js'\n\n/**\n * Main Socket client.\n */\nexport class Socket implements SocketClientTransport {\n #channels = new Map<string, Channel>()\n #url: string\n #path: string\n #session: ClientSocketSession\n\n constructor(options: SocketOptions = {}) {\n const browserWindow = globalThis as typeof globalThis & {\n window?: { location?: { origin?: string } }\n }\n const browserOrigin =\n typeof globalThis === 'object' && browserWindow.window?.location?.origin\n ? browserWindow.window.location.origin\n : ''\n\n this.#url = options.url ?? browserOrigin\n this.#path = options.path ?? '/socket'\n this.#session = new ClientSocketSession({\n buildUrl: () => this.#buildUrl(),\n autoReconnect: options.autoReconnect,\n reconnectDelay: options.reconnectDelay,\n reconnectMaxDelay: options.reconnectMaxDelay,\n onConnected: () => {\n void this.#resubscribeChannels()\n },\n })\n }\n\n get state(): ConnectionState {\n return this.#session.state\n }\n\n get connected(): boolean {\n return this.#session.connected\n }\n\n get id(): string | undefined {\n return undefined\n }\n\n connect(): Promise<void> {\n return this.#session.connect()\n }\n\n disconnect(): void {\n for (const channel of this.#channels.values()) {\n channel.unsubscribe().catch(() => {})\n }\n this.#channels.clear()\n\n this.#session.disconnect()\n }\n\n channel(name: string): Channel {\n if (!this.#channels.has(name)) {\n this.#channels.set(name, new Channel(name, this))\n }\n\n return this.#channels.get(name)!\n }\n\n async leave(name: string): Promise<void> {\n const channel = this.#channels.get(name)\n if (channel) {\n await channel.unsubscribe()\n this.#channels.delete(name)\n }\n }\n\n onStateChange(handler: EventHandler<ConnectionState>): () => void {\n return this.#session.onStateChange(handler)\n }\n\n on<T = unknown>(event: string, handler: EventHandler<T>): () => void {\n return this.#session.on(event, handler)\n }\n\n off(event: string, handler: EventHandler): void {\n this.#session.off(event, handler)\n }\n\n send(message: Record<string, unknown>): void {\n this.#session.send(message)\n }\n\n sendRequest<T = unknown>(message: Record<string, unknown>, timeout = 5000): Promise<T> {\n return this.#session.sendRequest(message, timeout)\n }\n\n #buildUrl(): string {\n const browserGlobal = globalThis as typeof globalThis & {\n location?: { origin?: string }\n }\n const url = new URL(this.#url || browserGlobal.location?.origin || 'http://localhost')\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'\n url.pathname = this.#path\n\n return url.toString()\n }\n\n async #resubscribeChannels(): Promise<void> {\n for (const channel of this.#channels.values()) {\n if (channel.subscribed && !channel.active) {\n await channel.subscribe().catch(console.error)\n }\n }\n }\n}\n"],"mappings":"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","names":["resolve","reject"]}
1
+ {"version":3,"sources":["../../../src/client/channel.ts","../../../src/client/socket_session.ts","../../../src/client/socket.ts"],"sourcesContent":["import type {\n SocketClientTransport,\n SubscribeOptions,\n SubscribeResult,\n UnsubscribeOptions,\n PresenceData,\n PresenceUser,\n EventHandler,\n ChannelMessage,\n ChannelAck,\n ChannelContract,\n} from './types.js'\nimport { callClientHandler } from './callback.js'\n\nconst CLIENT_EVENT_PREFIX = 'client:'\n\ntype Callable = (...args: never[]) => unknown\n\n/**\n * Represents a subscribed channel.\n * Chainable API inspired by Laravel Echo.\n *\n * @example\n * ```ts\n * socket.channel('chat/general')\n * .here((users) => setOnlineUsers(users))\n * .joining((user) => console.log(`${user.name} joined`))\n * .leaving((user) => console.log(`${user.name} left`))\n * .listen('chat:message', (msg) => addMessage(msg))\n * .subscribe()\n * ```\n */\ntype UnknownContract = ChannelContract<unknown, unknown>\ntype ClientMap<C> = C extends ChannelContract<infer E, unknown> ? E : unknown\ntype ServerMap<C> = C extends ChannelContract<unknown, infer E> ? E : unknown\ntype IsUnknown<T> = unknown extends T ? true : false\ntype StringKey<T> = Extract<keyof T, string>\ntype EventDataArgs<Payload> = undefined extends Payload ? [data?: Payload] : [data: Payload]\n\nexport class Channel<Contract = UnknownContract> {\n static #parsePresenceData(value: unknown): PresenceData | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null\n }\n\n const data = value as Partial<PresenceData>\n if (\n typeof data.channel !== 'string' ||\n !Array.isArray(data.users) ||\n !data.users.every(\n (user) =>\n user !== null &&\n typeof user === 'object' &&\n typeof user.id === 'string' &&\n typeof user.joinedAt === 'string'\n )\n ) {\n return null\n }\n\n const usersById = new Map<string, PresenceUser>()\n for (const user of data.users) {\n if (!usersById.has(user.id)) {\n usersById.set(user.id, user)\n }\n }\n\n const users = [...usersById.values()]\n return { ...data, channel: data.channel, users, count: users.length }\n }\n\n /**\n * Channel name.\n */\n readonly name: string\n\n /**\n * Socket client transport.\n */\n #transport: SocketClientTransport\n\n /**\n * Whether the channel should stay subscribed.\n */\n #subscribed = false\n #active = false\n\n /**\n * Event handlers grouped by event type.\n */\n #eventHandlers = new Map<string, Set<Callable>>()\n #managedEventHandlers = new Map<string, Set<Callable>>()\n\n /**\n * Current presence data.\n */\n #presence: PresenceData | null = null\n\n /**\n * Present user IDs used to detect join and leave events.\n */\n #presentUserIds = new Set<string>()\n\n /**\n * Handler registered through .here().\n */\n #hereHandler: EventHandler<PresenceUser[]> | null = null\n\n /**\n * Handler registered through .joining().\n */\n #joiningHandler: EventHandler<PresenceUser> | null = null\n\n /**\n * Handler registered through .leaving().\n */\n #leavingHandler: EventHandler<PresenceUser> | null = null\n\n /**\n * Internal transport handlers to clean up on unsubscribe.\n */\n #boundPresenceHandler: ((data: unknown) => void) | null = null\n #boundEventHandler: ((data: unknown) => void) | null = null\n #boundDisconnectHandler: (() => void) | null = null\n #listenersAttached = false\n #pendingSubscribe: {\n promise: Promise<Channel<Contract>>\n resolve: (channel: Channel<Contract>) => void\n reject: (error: Error) => void\n token: number\n } | null = null\n #subscribeToken = 0\n #managedSubscriptions = 0\n #pendingUnsubscribe: Promise<void> | null = null\n\n constructor(name: string, transport: SocketClientTransport) {\n this.name = name\n this.#transport = transport\n }\n\n /**\n * Whether the channel should stay subscribed.\n */\n get subscribed(): boolean {\n return this.#subscribed || this.#managedSubscriptions > 0\n }\n\n /** Whether a framework lifecycle currently owns this channel. @internal */\n get $managed(): boolean {\n return this.#managedSubscriptions > 0\n }\n\n /**\n * Whether the channel is active on the server.\n */\n get active(): boolean {\n return this.#active\n }\n\n /**\n * List of present users.\n */\n get users(): PresenceUser[] {\n return this.#presence?.users ?? []\n }\n\n /**\n * Number of present users.\n */\n get count(): number {\n return this.#presence?.count ?? 0\n }\n\n /**\n * Registers a handler called with the present users.\n * Called immediately on subscribe and after each presence change.\n */\n here(handler: EventHandler<PresenceUser[]>): this {\n this.#hereHandler = handler\n return this\n }\n\n /**\n * Registers a handler called when a user joins.\n */\n joining(handler: EventHandler<PresenceUser>): this {\n this.#joiningHandler = handler\n return this\n }\n\n /**\n * Registers a handler called when a user leaves.\n */\n leaving(handler: EventHandler<PresenceUser>): this {\n this.#leavingHandler = handler\n return this\n }\n\n /**\n * Listens for an event on this channel.\n */\n listen<T = unknown>(\n this: IsUnknown<ServerMap<Contract>> extends true ? Channel<Contract> : never,\n event: string,\n handler: EventHandler<T>\n ): this\n listen<Event extends StringKey<ServerMap<Contract>>>(\n this: Channel<Contract>,\n event: Event,\n handler: EventHandler<ServerMap<Contract>[Event]>\n ): this\n listen(event: string, handler: EventHandler<any>): this {\n const handlers = this.#eventHandlers.get(event) ?? new Set<Callable>()\n handlers.add(handler)\n this.#eventHandlers.set(event, handlers)\n return this\n }\n\n /**\n * Removes an event listener.\n */\n stopListening<T = unknown>(\n this: IsUnknown<ServerMap<Contract>> extends true ? Channel<Contract> : never,\n event: string,\n handler?: EventHandler<T>\n ): this\n stopListening<Event extends StringKey<ServerMap<Contract>>>(\n this: Channel<Contract>,\n event: Event,\n handler?: EventHandler<ServerMap<Contract>[Event]>\n ): this\n stopListening(event: string, handler?: EventHandler<any>): this {\n if (handler) {\n this.#eventHandlers.get(event)?.delete(handler)\n } else {\n this.#eventHandlers.delete(event)\n }\n return this\n }\n\n /** Registers a lifecycle-owned event handler. @internal */\n $listen(event: string, handler: EventHandler<any>): void {\n const handlers = this.#managedEventHandlers.get(event) ?? new Set<Callable>()\n handlers.add(handler)\n this.#managedEventHandlers.set(event, handlers)\n }\n\n /** Removes a lifecycle-owned event handler. @internal */\n $stopListening(event: string, handler: EventHandler<any>): void {\n const handlers = this.#managedEventHandlers.get(event)\n handlers?.delete(handler)\n if (handlers?.size === 0) this.#managedEventHandlers.delete(event)\n }\n\n /**\n * Listens for a client event whispered by another channel member.\n */\n listenForWhisper<T = unknown>(event: string, handler: EventHandler<T>): this {\n const handlers =\n this.#eventHandlers.get(`${CLIENT_EVENT_PREFIX}${event}`) ?? new Set<Callable>()\n handlers.add(handler)\n this.#eventHandlers.set(`${CLIENT_EVENT_PREFIX}${event}`, handlers)\n return this\n }\n\n /**\n * Removes a whispered client event listener.\n */\n stopListeningForWhisper<T = unknown>(event: string, handler?: EventHandler<T>): this {\n const name = `${CLIENT_EVENT_PREFIX}${event}`\n if (handler) this.#eventHandlers.get(name)?.delete(handler)\n else this.#eventHandlers.delete(name)\n return this\n }\n\n /**\n * Subscribes to the channel.\n *\n * client listeners -> subscribe ack -> active channel\n * | | |\n * v v v\n * events ready presence sync send/listen\n */\n async subscribe(options: SubscribeOptions = {}): Promise<this> {\n this.#subscribed = true\n return this.#ensureSubscribed(options)\n }\n\n /** Acquires subscription intent without overriding a direct consumer. @internal */\n $acquire(options: SubscribeOptions = {}): {\n ready: Promise<Channel<Contract>>\n release: () => Promise<void>\n } {\n this.#managedSubscriptions++\n const ready = this.#transport.connected\n ? this.#ensureSubscribed(options)\n : Promise.resolve(this)\n let released = false\n\n return {\n ready,\n release: () => {\n if (released) return this.#pendingUnsubscribe ?? Promise.resolve()\n released = true\n this.#managedSubscriptions--\n return this.#unsubscribeIfUnused()\n },\n }\n }\n\n /** Restores desired subscriptions after the transport reconnects. @internal */\n $resubscribe(options: SubscribeOptions = {}): Promise<this> {\n return this.#ensureSubscribed(options)\n }\n\n async #ensureSubscribed(options: SubscribeOptions): Promise<this> {\n if (this.#pendingUnsubscribe) {\n await this.#pendingUnsubscribe\n }\n\n if (!this.subscribed) return this\n\n if (this.#pendingSubscribe) {\n await this.#pendingSubscribe.promise\n return this\n }\n\n if (this.#active) {\n return this\n }\n\n const timeout = options.timeout ?? 5000\n\n // Attach listeners before subscribing so the first server events are not missed.\n if (!this.#listenersAttached) {\n this.#setupSocketListeners()\n }\n\n const token = ++this.#subscribeToken\n\n const deferred = Promise.withResolvers<Channel<Contract>>()\n\n this.#pendingSubscribe = {\n promise: deferred.promise,\n resolve: deferred.resolve,\n reject: deferred.reject,\n token,\n }\n\n const { resolve, reject } = this.#pendingSubscribe\n\n const timer = setTimeout(() => {\n if (token !== this.#subscribeToken) return\n this.#subscribeToken++\n this.#pendingSubscribe = null\n this.#resetConnectionState()\n reject(new Error(`Subscribe timeout for channel: ${this.name}`))\n }, timeout)\n\n this.#transport\n .sendRequest<SubscribeResult>({ type: 'subscribe', channel: this.name }, timeout)\n .then((response) => {\n if (token !== this.#subscribeToken) return\n clearTimeout(timer)\n this.#pendingSubscribe = null\n\n if (response.ok) {\n this.#active = true\n\n const presenceData = Channel.#parsePresenceData(\n response.data?.presenceData ?? response.presenceData\n )\n\n // Apply the initial presence snapshot.\n if (presenceData) {\n this.#handleInitialPresence(presenceData)\n }\n\n resolve(this)\n } else {\n this.#resetConnectionState()\n reject(new Error(response.error ?? 'Subscribe failed'))\n }\n })\n .catch((error) => {\n if (token !== this.#subscribeToken) return\n clearTimeout(timer)\n this.#pendingSubscribe = null\n this.#resetConnectionState()\n reject(error instanceof Error ? error : new Error('Subscribe failed'))\n })\n\n await deferred.promise\n return this\n }\n\n /**\n * Unsubscribes from the channel.\n */\n async unsubscribe(options: UnsubscribeOptions = {}): Promise<void> {\n this.#subscribed = false\n this.#clearUserCallbacks()\n return this.#unsubscribeIfUnused(options)\n }\n\n #unsubscribeIfUnused(options: UnsubscribeOptions = {}): Promise<void> {\n if (this.subscribed) return Promise.resolve()\n if (this.#pendingUnsubscribe) return this.#pendingUnsubscribe\n\n const hadPendingSubscribe = this.#pendingSubscribe !== null\n this.#subscribeToken++\n if (this.#pendingSubscribe) {\n this.#pendingSubscribe.reject(new Error(`Unsubscribed from channel: ${this.name}`))\n this.#pendingSubscribe = null\n }\n\n if (!hadPendingSubscribe && !this.#active) {\n this.#cleanupTerminal()\n return Promise.resolve()\n }\n\n this.#active = false\n const pending = new Promise<void>((resolve) => {\n const timeout = options.timeout ?? 5000\n const timer = setTimeout(() => {\n resolve()\n }, timeout)\n\n this.#transport\n .sendRequest({ type: 'unsubscribe', channel: this.name }, timeout)\n .then(() => {\n clearTimeout(timer)\n resolve()\n })\n .catch(() => {\n clearTimeout(timer)\n resolve()\n })\n })\n this.#pendingUnsubscribe = pending\n void pending.finally(() => {\n if (this.#pendingUnsubscribe !== pending) return\n this.#pendingUnsubscribe = null\n this.#resetConnectionState()\n this.#detachTransportListeners()\n if (!this.subscribed) this.#clearCallbacks()\n })\n return pending\n }\n\n /**\n * Sends an event to the server.\n */\n send<T = unknown>(\n this: IsUnknown<ClientMap<Contract>> extends true ? Channel<Contract> : never,\n event: string,\n data?: T\n ): this\n send<Event extends StringKey<ClientMap<Contract>>>(\n this: Channel<Contract>,\n event: Event,\n ...[data]: ClientMap<Contract>[Event] extends { payload: infer Payload }\n ? EventDataArgs<Payload>\n : never\n ): this\n send(event: string, data?: unknown): this {\n if (!this.#active) {\n console.warn(`Cannot send to channel ${this.name}: not subscribed`)\n return this\n }\n const payload: ChannelMessage = {\n channel: this.name,\n event,\n data,\n }\n this.#transport.send({ type: 'message', ...payload })\n return this\n }\n\n /**\n * Relays a client event to other members of this channel.\n */\n whisper<T = unknown>(event: string, data?: T): this {\n if (!this.#active) {\n console.warn(`Cannot whisper to channel ${this.name}: not subscribed`)\n return this\n }\n const payload: ChannelMessage = {\n channel: this.name,\n event,\n data,\n }\n this.#transport.send({ type: 'whisper', ...payload })\n return this\n }\n\n /**\n * Sends an event and waits for a response.\n */\n sendWithAck<T = unknown, Result = unknown>(\n this: IsUnknown<ClientMap<Contract>> extends true ? Channel<Contract> : never,\n event: string,\n data?: T\n ): Promise<Result>\n sendWithAck<Event extends StringKey<ClientMap<Contract>>>(\n this: Channel<Contract>,\n event: Event,\n ...[data]: ClientMap<Contract>[Event] extends { payload: infer Payload }\n ? EventDataArgs<Payload>\n : never\n ): Promise<\n ClientMap<Contract>[Event] extends { ack: infer Acknowledgement } ? Acknowledgement : unknown\n >\n async sendWithAck(event: string, data?: unknown): Promise<unknown> {\n if (!this.#active) {\n throw new Error(`Cannot send to channel ${this.name}: not subscribed`)\n }\n const payload: ChannelMessage = {\n channel: this.name,\n event,\n data,\n }\n const response = await this.#transport.sendRequest<ChannelAck>({\n type: 'message',\n ...payload,\n })\n if (!response?.ok) {\n throw new Error(response?.error ?? `Channel handler failed: ${event}`)\n }\n return response.data\n }\n\n /**\n * Configures transport listeners.\n */\n #setupSocketListeners(): void {\n // Handler for presence:update.\n this.#boundPresenceHandler = (data: unknown) => {\n const presenceData = Channel.#parsePresenceData(data)\n if (!presenceData) return\n this.#handlePresenceUpdate(presenceData)\n }\n this.#transport.on(`channel:${this.name}:presence:update`, this.#boundPresenceHandler)\n\n this.#boundEventHandler = (data: unknown) => {\n if (!data || typeof data !== 'object') return\n\n const payload = data as { event?: string; data?: unknown }\n if (!payload.event) return\n\n const handlers = this.#eventHandlers.get(payload.event)\n handlers?.forEach((handler) => callClientHandler(handler, payload.data))\n const managedHandlers = this.#managedEventHandlers.get(payload.event)\n managedHandlers?.forEach((handler) => callClientHandler(handler, payload.data))\n }\n this.#transport.on(`channel:${this.name}:event`, this.#boundEventHandler)\n\n // Mark the channel inactive when the socket disconnects.\n this.#boundDisconnectHandler = () => {\n this.#resetConnectionState()\n }\n this.#transport.on('disconnect', this.#boundDisconnectHandler)\n\n this.#listenersAttached = true\n }\n\n /**\n * Handles the initial presence snapshot.\n */\n #handleInitialPresence(data: PresenceData): void {\n this.#presence = data\n this.#presentUserIds = new Set(data.users.map((u) => u.id))\n\n // Call here() with all users.\n if (this.#hereHandler) {\n callClientHandler(this.#hereHandler, data.users)\n }\n }\n\n /**\n * Handles a presence update.\n *\n * previous IDs current IDs\n * | |\n * +-- diff in -----+--> joining / leaving callbacks\n */\n #handlePresenceUpdate(data: PresenceData): void {\n const previousIds = this.#presentUserIds\n const currentIds = new Set(data.users.map((u) => u.id))\n const joiningUsers = data.users.filter((user) => !previousIds.has(user.id))\n const leavingUsers = (this.#presence?.users ?? []).filter((user) => !currentIds.has(user.id))\n\n // Commit the validated update before invoking user code.\n this.#presence = data\n this.#presentUserIds = currentIds\n\n // Detect new users.\n for (const user of joiningUsers) {\n if (this.#joiningHandler) {\n callClientHandler(this.#joiningHandler, user)\n }\n }\n\n // Detect users that left.\n for (const user of leavingUsers) {\n if (this.#leavingHandler) {\n callClientHandler(this.#leavingHandler, user)\n }\n }\n\n // Call here() with the updated list.\n if (this.#hereHandler) {\n callClientHandler(this.#hereHandler, data.users)\n }\n }\n\n #resetConnectionState(): void {\n this.#active = false\n this.#presence = null\n this.#presentUserIds.clear()\n }\n\n #detachTransportListeners(): void {\n if (this.#boundPresenceHandler) {\n this.#transport.off(`channel:${this.name}:presence:update`, this.#boundPresenceHandler)\n this.#boundPresenceHandler = null\n }\n\n if (this.#boundEventHandler) {\n this.#transport.off(`channel:${this.name}:event`, this.#boundEventHandler)\n this.#boundEventHandler = null\n }\n\n if (this.#boundDisconnectHandler) {\n this.#transport.off('disconnect', this.#boundDisconnectHandler)\n this.#boundDisconnectHandler = null\n }\n\n this.#listenersAttached = false\n }\n\n #clearUserCallbacks(): void {\n this.#eventHandlers.clear()\n this.#hereHandler = null\n this.#joiningHandler = null\n this.#leavingHandler = null\n }\n\n #clearCallbacks(): void {\n this.#clearUserCallbacks()\n this.#managedEventHandlers.clear()\n }\n\n /**\n * Performs terminal cleanup after the user leaves or the socket is disposed.\n */\n #cleanupTerminal(): void {\n this.#resetConnectionState()\n this.#detachTransportListeners()\n this.#clearCallbacks()\n }\n}\n","import type { ConnectionState, EventHandler } from './types.js'\nimport type { ServerProtocolMessage } from '../shared_types.js'\nimport { callClientHandler } from './callback.js'\n\ntype Callable = (...args: never[]) => unknown\ntype IncomingMessage = Extract<ServerProtocolMessage, { type: 'ack' | 'event' }>\n\ninterface PendingRequest {\n resolve: (value: unknown) => void\n reject: (error: Error) => void\n timer: ReturnType<typeof setTimeout>\n}\n\ninterface ClientSocketSessionOptions {\n buildUrl: () => string\n createWebSocket?: (url: string) => WebSocket\n autoReconnect?: boolean\n reconnectDelay?: number\n reconnectMaxDelay?: number\n onConnected?: () => void\n}\n\nexport class ClientSocketSession {\n #ws: WebSocket | null = null\n #state: ConnectionState = 'disconnected'\n #connectPromise: Promise<void> | null = null\n #cancelConnect: ((error: Error) => void) | null = null\n #stateHandlers = new Set<Callable>()\n #eventHandlers = new Map<string, Set<Callable>>()\n #pendingRequests = new Map<string, PendingRequest>()\n #requestId = 0\n #reconnectAttempts = 0\n #reconnectTimer: ReturnType<typeof setTimeout> | null = null\n #manualDisconnect = false\n #buildUrl: () => string\n #createWebSocket: (url: string) => WebSocket\n #autoReconnect: boolean\n #reconnectDelay: number\n #reconnectMaxDelay: number\n #onConnected?: () => void\n\n constructor(options: ClientSocketSessionOptions) {\n this.#buildUrl = options.buildUrl\n this.#createWebSocket = options.createWebSocket ?? ((url) => new WebSocket(url))\n this.#autoReconnect = options.autoReconnect ?? true\n this.#reconnectDelay = Math.max(0, options.reconnectDelay ?? 250)\n this.#reconnectMaxDelay = Math.max(this.#reconnectDelay, options.reconnectMaxDelay ?? 5000)\n this.#onConnected = options.onConnected\n }\n\n get state(): ConnectionState {\n return this.#state\n }\n\n get connected(): boolean {\n return this.#state === 'connected'\n }\n\n connect(): Promise<void> {\n if (this.#state === 'connected') {\n return Promise.resolve()\n }\n\n if (this.#connectPromise) {\n return this.#connectPromise\n }\n\n this.#manualDisconnect = false\n this.#setState('connecting')\n\n let setupFailed = false\n const connectPromise = new Promise<void>((resolve, reject) => {\n let ws: WebSocket\n try {\n ws = this.#createWebSocket(this.#buildUrl())\n } catch (error) {\n setupFailed = true\n reject(error)\n return\n }\n\n this.#ws = ws\n let settled = false\n\n const cleanup = () => {\n ws.removeEventListener('open', handleOpen)\n ws.removeEventListener('error', handleError)\n if (this.#connectPromise === connectPromise) {\n this.#connectPromise = null\n }\n if (this.#cancelConnect === cancelConnect) {\n this.#cancelConnect = null\n }\n }\n\n const cancelConnect = (error: Error) => {\n if (settled) {\n return\n }\n\n settled = true\n cleanup()\n reject(error)\n }\n\n const handleOpen = () => {\n if (settled || this.#ws !== ws) {\n return\n }\n\n this.#setState('connected')\n if (settled || this.#ws !== ws || !this.connected) {\n return\n }\n\n settled = true\n cleanup()\n this.#reconnectAttempts = 0\n this.#emitLocal('connect')\n if (this.#onConnected) {\n this.#callHandler(this.#onConnected)\n }\n resolve()\n }\n\n const handleError = () => {\n cancelConnect(new Error('WebSocket connection failed'))\n if (this.#ws === ws) {\n this.#setState('disconnected')\n }\n }\n\n const handleClose = () => {\n cancelConnect(new Error('WebSocket connection failed'))\n\n if (this.#ws === ws) {\n this.#handleClose()\n }\n }\n\n this.#cancelConnect = cancelConnect\n ws.addEventListener('open', handleOpen)\n ws.addEventListener('error', handleError)\n ws.addEventListener('message', (event) => {\n if (this.#ws === ws) {\n this.#handleIncoming(event.data)\n }\n })\n ws.addEventListener('close', handleClose)\n })\n\n this.#connectPromise = connectPromise\n if (setupFailed) {\n this.#connectPromise = null\n this.#setState('disconnected')\n }\n\n return connectPromise\n }\n\n disconnect(): void {\n this.#manualDisconnect = true\n if (this.#reconnectTimer) {\n clearTimeout(this.#reconnectTimer)\n this.#reconnectTimer = null\n }\n\n this.#cancelConnect?.(new Error('Socket disconnected'))\n this.#reconnectAttempts = 0\n const ws = this.#ws\n const shouldEmitDisconnect = this.#state !== 'disconnected'\n this.#ws = null\n this.#setState('disconnected')\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n ws?.close()\n this.#rejectPending(new Error('Socket disconnected'))\n }\n\n onStateChange(handler: EventHandler<ConnectionState>): () => void {\n this.#stateHandlers.add(handler)\n\n return () => {\n this.#stateHandlers.delete(handler)\n }\n }\n\n on<T = unknown>(event: string, handler: EventHandler<T>): () => void {\n if (!this.#eventHandlers.has(event)) {\n this.#eventHandlers.set(event, new Set())\n }\n\n this.#eventHandlers.get(event)!.add(handler)\n\n return () => {\n this.off(event, handler)\n }\n }\n\n off<T = unknown>(event: string, handler: EventHandler<T>): void {\n this.#eventHandlers.get(event)?.delete(handler)\n }\n\n send(message: Record<string, unknown>): void {\n const ws = this.#ws\n if (ws?.readyState !== WebSocket.OPEN) {\n return\n }\n\n ws.send(JSON.stringify(message))\n }\n\n sendRequest(message: Record<string, unknown>, timeout = 5000): Promise<unknown> {\n const ws = this.#ws\n if (ws?.readyState !== WebSocket.OPEN) {\n return Promise.reject(new Error('Socket is not connected'))\n }\n\n const id = String(++this.#requestId)\n const payload = { ...message, id }\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingRequests.delete(id)\n reject(new Error('Socket request timed out'))\n }, timeout)\n\n this.#pendingRequests.set(id, {\n resolve,\n reject,\n timer,\n })\n ws.send(JSON.stringify(payload))\n })\n }\n\n #handleIncoming(raw: unknown): void {\n const message = this.#parseMessage(raw)\n if (!message) {\n return\n }\n\n if (message.type === 'ack') {\n this.#resolveAck(message)\n return\n }\n\n if (message.type === 'event') {\n if (message.channel) {\n if (message.event === 'presence:update') {\n this.#emitLocal(`channel:${message.channel}:presence:update`, message.data)\n return\n }\n\n this.#emitLocal(`channel:${message.channel}:event`, {\n event: message.event,\n data: message.data,\n })\n return\n }\n\n this.#emitLocal(message.event, message.data)\n }\n }\n\n #parseMessage(raw: unknown): IncomingMessage | null {\n try {\n const data = typeof raw === 'string' ? raw : String(raw)\n const message = JSON.parse(data) as Record<string, unknown> | null\n\n if (!message || typeof message !== 'object' || Array.isArray(message)) {\n return null\n }\n\n if (\n message.type === 'ack' &&\n typeof message.id === 'string' &&\n typeof message.ok === 'boolean' &&\n (message.error === undefined || typeof message.error === 'string')\n ) {\n return message as IncomingMessage\n }\n\n if (\n message.type === 'event' &&\n typeof message.event === 'string' &&\n (message.channel === undefined || typeof message.channel === 'string')\n ) {\n return message as IncomingMessage\n }\n\n return null\n } catch {\n return null\n }\n }\n\n #resolveAck(message: Extract<ServerProtocolMessage, { type: 'ack' }>): void {\n if (!message.id) {\n return\n }\n\n const pending = this.#pendingRequests.get(message.id)\n if (!pending) {\n return\n }\n\n clearTimeout(pending.timer)\n this.#pendingRequests.delete(message.id)\n\n if (message.ok) {\n pending.resolve({ ok: true, data: message.data })\n } else {\n pending.resolve({ ok: false, error: message.error })\n }\n }\n\n #handleClose(): void {\n const shouldEmitDisconnect = this.#state !== 'disconnected'\n\n this.#ws = null\n this.#setState('disconnected')\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n this.#rejectPending(new Error('Socket disconnected'))\n\n this.#scheduleReconnect()\n }\n\n #scheduleReconnect(): void {\n if (this.#manualDisconnect || !this.#autoReconnect || this.#reconnectTimer) {\n return\n }\n\n const delay = Math.min(\n this.#reconnectDelay * 2 ** this.#reconnectAttempts,\n this.#reconnectMaxDelay\n )\n this.#reconnectAttempts += 1\n\n this.#reconnectTimer = setTimeout(() => {\n this.#reconnectTimer = null\n this.connect().catch(() => {\n if (this.#state === 'disconnected') {\n this.#scheduleReconnect()\n }\n })\n }, delay)\n }\n\n #rejectPending(error: Error): void {\n for (const [id, pending] of this.#pendingRequests) {\n clearTimeout(pending.timer)\n pending.reject(error)\n this.#pendingRequests.delete(id)\n }\n }\n\n #emitLocal(event: string, data?: unknown): void {\n this.#eventHandlers.get(event)?.forEach((handler) => this.#callHandler(handler, data))\n }\n\n #setState(state: ConnectionState): void {\n if (this.#state === state) {\n return\n }\n\n this.#state = state\n this.#stateHandlers.forEach((handler) => this.#callHandler(handler, state))\n }\n\n #callHandler(handler: Callable, data?: unknown): void {\n callClientHandler(handler, data)\n }\n}\n","import { Channel } from './channel.js'\nimport { ClientSocketSession } from './socket_session.js'\nimport { reportClientError } from './callback.js'\nimport type {\n SocketOptions,\n ConnectionState,\n EventHandler,\n SocketClientTransport,\n ChannelContractFor,\n} from './types.js'\n\n/**\n * Main Socket client.\n */\ntype ChannelResult<Registry, Name extends string> = string extends Name\n ? Channel<unknown>\n : [Registry] extends [never]\n ? Channel\n : ChannelContractFor<Registry, Name> extends infer Contract\n ? [Contract] extends [never]\n ? never\n : Channel<Contract>\n : never\n\nexport class Socket<Registry = never> implements SocketClientTransport {\n #channels = new Map<string, Channel>()\n #url: string\n #path: string\n #session: ClientSocketSession\n\n constructor(options: SocketOptions = {}) {\n const browserWindow = globalThis as typeof globalThis & {\n window?: { location?: { origin?: string } }\n }\n const browserOrigin =\n typeof globalThis === 'object' && browserWindow.window?.location?.origin\n ? browserWindow.window.location.origin\n : ''\n\n this.#url = options.url ?? browserOrigin\n this.#path = options.path ?? '/socket'\n this.#session = new ClientSocketSession({\n buildUrl: () => this.#buildUrl(),\n autoReconnect: options.autoReconnect,\n reconnectDelay: options.reconnectDelay,\n reconnectMaxDelay: options.reconnectMaxDelay,\n onConnected: () => {\n void this.#resubscribeChannels()\n },\n })\n }\n\n get state(): ConnectionState {\n return this.#session.state\n }\n\n get connected(): boolean {\n return this.#session.connected\n }\n\n connect(): Promise<void> {\n return this.#session.connect()\n }\n\n disconnect(): void {\n for (const channel of this.#channels.values()) {\n channel.unsubscribe().catch(() => {})\n }\n\n this.#session.disconnect()\n }\n\n channel<const Name extends string>(\n name: Name & (ChannelResult<Registry, Name> extends never ? never : unknown)\n ): ChannelResult<Registry, Name> {\n if (!this.#channels.has(name)) {\n this.#channels.set(name, new Channel(name, this))\n }\n\n return this.#channels.get(name)! as ChannelResult<Registry, Name>\n }\n\n async leave(name: string): Promise<void> {\n const channel = this.#channels.get(name)\n if (channel) {\n await channel.unsubscribe()\n if (this.#channels.get(name) === channel && !channel.subscribed) {\n this.#channels.delete(name)\n }\n }\n }\n\n onStateChange(handler: EventHandler<ConnectionState>): () => void {\n return this.#session.onStateChange(handler)\n }\n\n on<T = unknown>(event: string, handler: EventHandler<T>): () => void {\n return this.#session.on(event, handler)\n }\n\n off<T = unknown>(event: string, handler: EventHandler<T>): void {\n this.#session.off(event, handler)\n }\n\n send(message: Record<string, unknown>): void {\n this.#session.send(message)\n }\n\n sendRequest<T = unknown>(message: Record<string, unknown>, timeout = 5000): Promise<T> {\n return this.#session.sendRequest(message, timeout) as Promise<T>\n }\n\n #buildUrl(): string {\n const browserGlobal = globalThis as typeof globalThis & {\n location?: { origin?: string }\n }\n const url = new URL(this.#url || browserGlobal.location?.origin || 'http://localhost')\n if (url.protocol === 'http:') {\n url.protocol = 'ws:'\n } else if (url.protocol === 'https:') {\n url.protocol = 'wss:'\n } else if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n throw new Error(`Unsupported socket URL protocol: ${url.protocol}`)\n }\n url.pathname = this.#path\n\n return url.toString()\n }\n\n async #resubscribeChannels(): Promise<void> {\n for (const channel of this.#channels.values()) {\n if (channel.subscribed && !channel.active) {\n await channel.$resubscribe().catch(reportClientError)\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,27 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { Socket } from './index.js';
4
+ import { ConnectionState, EventHandler } from './types.js';
5
+ import { F as FrameworkChannelName, a as FrameworkChannel, b as FrameworkChannelEvent, c as FrameworkChannelEventPayload } from '../../framework-DuW6zpPk.js';
6
+ import '../../types-DiYaFvgi.js';
7
+ import 'ws';
8
+ import 'node:http';
9
+ import '@adonisjs/core/types/http';
10
+ import '@adonisjs/core/http';
11
+ import '@boringnode/bus/types/main';
12
+
13
+ interface SocketProviderProps<Registry> {
14
+ socket: Socket<Registry>;
15
+ children?: ReactNode;
16
+ /** Connect on mount and disconnect on unmount. Use only for an exclusively owned socket. */
17
+ owned?: boolean;
18
+ }
19
+ declare function createSocketHooks<Registry = never>(): {
20
+ SocketProvider: ({ socket, children, owned }: SocketProviderProps<Registry>) => react.FunctionComponentElement<react.ProviderProps<Socket<Registry> | null>>;
21
+ useSocket: () => Socket<Registry>;
22
+ useSocketState: () => ConnectionState;
23
+ useChannel: <const Name extends string>(name: FrameworkChannelName<Registry, Name> | null) => FrameworkChannel<Registry, Name> | null;
24
+ useChannelEvent: <const Name extends string, Event extends FrameworkChannelEvent<Registry, Name>>(name: FrameworkChannelName<Registry, Name> | null, event: Event, handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>) => void;
25
+ };
26
+
27
+ export { type SocketProviderProps, createSocketHooks };
@@ -0,0 +1,69 @@
1
+ import {
2
+ acquireChannel,
3
+ acquireSocketOwnership
4
+ } from "../../chunk-FVPY6HZW.js";
5
+ import "../../chunk-SFAY2ZA4.js";
6
+
7
+ // src/client/react.ts
8
+ import {
9
+ createContext,
10
+ createElement,
11
+ useContext,
12
+ useEffect,
13
+ useRef,
14
+ useState,
15
+ useSyncExternalStore
16
+ } from "react";
17
+ function createSocketHooks() {
18
+ const SocketContext = createContext(null);
19
+ function useSocket() {
20
+ const socket = useContext(SocketContext);
21
+ if (!socket) throw new Error("SocketProvider is missing");
22
+ return socket;
23
+ }
24
+ function SocketProvider({ socket, children, owned = false }) {
25
+ useEffect(() => {
26
+ if (!owned) return;
27
+ return acquireSocketOwnership(socket);
28
+ }, [owned, socket]);
29
+ return createElement(SocketContext.Provider, { value: socket }, children);
30
+ }
31
+ function useSocketState() {
32
+ const socket = useSocket();
33
+ return useSyncExternalStore(
34
+ (notify) => socket.onStateChange(notify),
35
+ () => socket.state,
36
+ () => "disconnected"
37
+ );
38
+ }
39
+ function useChannel(name) {
40
+ const socket = useSocket();
41
+ const [acquired, setAcquired] = useState(null);
42
+ useEffect(() => {
43
+ if (name === null) {
44
+ setAcquired(null);
45
+ return;
46
+ }
47
+ const { channel, lease } = acquireChannel(socket, name);
48
+ setAcquired({ socket, name, channel });
49
+ return () => lease.release();
50
+ }, [name, socket]);
51
+ return acquired?.socket === socket && acquired.name === name ? acquired.channel : null;
52
+ }
53
+ function useChannelEvent(name, event, handler) {
54
+ const socket = useSocket();
55
+ const handlerRef = useRef(handler);
56
+ handlerRef.current = handler;
57
+ useEffect(() => {
58
+ if (name === null) return;
59
+ const { lease } = acquireChannel(socket, name);
60
+ lease.listen(event, (data) => handlerRef.current(data));
61
+ return () => lease.release();
62
+ }, [event, name, socket]);
63
+ }
64
+ return { SocketProvider, useSocket, useSocketState, useChannel, useChannelEvent };
65
+ }
66
+ export {
67
+ createSocketHooks
68
+ };
69
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/client/react.ts"],"sourcesContent":["import {\n createContext,\n createElement,\n useContext,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react'\nimport type { Socket } from './socket.js'\nimport type { ConnectionState, EventHandler } from './types.js'\nimport {\n acquireChannel,\n acquireSocketOwnership,\n type FrameworkChannel,\n type FrameworkChannelEvent,\n type FrameworkChannelEventPayload,\n type FrameworkChannelName,\n} from './framework.js'\n\nexport interface SocketProviderProps<Registry> {\n socket: Socket<Registry>\n children?: ReactNode\n /** Connect on mount and disconnect on unmount. Use only for an exclusively owned socket. */\n owned?: boolean\n}\n\nexport function createSocketHooks<Registry = never>() {\n const SocketContext = createContext<Socket<Registry> | null>(null)\n\n function useSocket(): Socket<Registry> {\n const socket = useContext(SocketContext)\n if (!socket) throw new Error('SocketProvider is missing')\n return socket\n }\n\n function SocketProvider({ socket, children, owned = false }: SocketProviderProps<Registry>) {\n useEffect(() => {\n if (!owned) return\n return acquireSocketOwnership(socket)\n }, [owned, socket])\n\n return createElement(SocketContext.Provider, { value: socket }, children)\n }\n\n function useSocketState(): ConnectionState {\n const socket = useSocket()\n return useSyncExternalStore(\n (notify) => socket.onStateChange(notify),\n () => socket.state,\n () => 'disconnected'\n )\n }\n\n function useChannel<const Name extends string>(\n name: FrameworkChannelName<Registry, Name> | null\n ): FrameworkChannel<Registry, Name> | null {\n const socket = useSocket()\n const [acquired, setAcquired] = useState<{\n socket: Socket<Registry>\n name: string\n channel: FrameworkChannel<Registry, Name>\n } | null>(null)\n\n useEffect(() => {\n if (name === null) {\n setAcquired(null)\n return\n }\n const { channel, lease } = acquireChannel(socket, name)\n setAcquired({ socket, name, channel })\n return () => lease.release()\n }, [name, socket])\n\n return acquired?.socket === socket && acquired.name === name ? acquired.channel : null\n }\n\n function useChannelEvent<\n const Name extends string,\n Event extends FrameworkChannelEvent<Registry, Name>,\n >(\n name: FrameworkChannelName<Registry, Name> | null,\n event: Event,\n handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>\n ): void {\n const socket = useSocket()\n const handlerRef = useRef(handler)\n handlerRef.current = handler\n\n useEffect(() => {\n if (name === null) return\n const { lease } = acquireChannel(socket, name)\n lease.listen(event, (data) => handlerRef.current(data))\n return () => lease.release()\n }, [event, name, socket])\n }\n\n return { SocketProvider, useSocket, useSocketState, useChannel, useChannelEvent }\n}\n"],"mappings":";;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAmBA,SAAS,oBAAsC;AACpD,QAAM,gBAAgB,cAAuC,IAAI;AAEjE,WAAS,YAA8B;AACrC,UAAM,SAAS,WAAW,aAAa;AACvC,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,2BAA2B;AACxD,WAAO;AAAA,EACT;AAEA,WAAS,eAAe,EAAE,QAAQ,UAAU,QAAQ,MAAM,GAAkC;AAC1F,cAAU,MAAM;AACd,UAAI,CAAC,MAAO;AACZ,aAAO,uBAAuB,MAAM;AAAA,IACtC,GAAG,CAAC,OAAO,MAAM,CAAC;AAElB,WAAO,cAAc,cAAc,UAAU,EAAE,OAAO,OAAO,GAAG,QAAQ;AAAA,EAC1E;AAEA,WAAS,iBAAkC;AACzC,UAAM,SAAS,UAAU;AACzB,WAAO;AAAA,MACL,CAAC,WAAW,OAAO,cAAc,MAAM;AAAA,MACvC,MAAM,OAAO;AAAA,MACb,MAAM;AAAA,IACR;AAAA,EACF;AAEA,WAAS,WACP,MACyC;AACzC,UAAM,SAAS,UAAU;AACzB,UAAM,CAAC,UAAU,WAAW,IAAI,SAItB,IAAI;AAEd,cAAU,MAAM;AACd,UAAI,SAAS,MAAM;AACjB,oBAAY,IAAI;AAChB;AAAA,MACF;AACA,YAAM,EAAE,SAAS,MAAM,IAAI,eAAe,QAAQ,IAAI;AACtD,kBAAY,EAAE,QAAQ,MAAM,QAAQ,CAAC;AACrC,aAAO,MAAM,MAAM,QAAQ;AAAA,IAC7B,GAAG,CAAC,MAAM,MAAM,CAAC;AAEjB,WAAO,UAAU,WAAW,UAAU,SAAS,SAAS,OAAO,SAAS,UAAU;AAAA,EACpF;AAEA,WAAS,gBAIP,MACA,OACA,SACM;AACN,UAAM,SAAS,UAAU;AACzB,UAAM,aAAa,OAAO,OAAO;AACjC,eAAW,UAAU;AAErB,cAAU,MAAM;AACd,UAAI,SAAS,KAAM;AACnB,YAAM,EAAE,MAAM,IAAI,eAAe,QAAQ,IAAI;AAC7C,YAAM,OAAO,OAAO,CAAC,SAAS,WAAW,QAAQ,IAAI,CAAC;AACtD,aAAO,MAAM,MAAM,QAAQ;AAAA,IAC7B,GAAG,CAAC,OAAO,MAAM,MAAM,CAAC;AAAA,EAC1B;AAEA,SAAO,EAAE,gBAAgB,WAAW,gBAAgB,YAAY,gBAAgB;AAClF;","names":[]}
@@ -0,0 +1,23 @@
1
+ import { Readable } from 'svelte/store';
2
+ import { Socket } from './index.js';
3
+ import { ConnectionState, EventHandler } from './types.js';
4
+ import { F as FrameworkChannelName, a as FrameworkChannel, b as FrameworkChannelEvent, c as FrameworkChannelEventPayload } from '../../framework-DuW6zpPk.js';
5
+ import '../../types-DiYaFvgi.js';
6
+ import 'ws';
7
+ import 'node:http';
8
+ import '@adonisjs/core/types/http';
9
+ import '@adonisjs/core/http';
10
+ import '@boringnode/bus/types/main';
11
+
12
+ type ChannelNameInput<Registry, Name extends string> = (Name & FrameworkChannelName<Registry, NoInfer<Name>>) | null | (Readable<Name | null> & Readable<FrameworkChannelName<Registry, NoInfer<Name>> | null>);
13
+ declare function createSocketContext<Registry = never>(): {
14
+ setSocket: (socket: Socket<Registry>, options?: {
15
+ owned?: boolean;
16
+ }) => void;
17
+ useSocket: () => Socket<Registry>;
18
+ useSocketState: () => Readable<ConnectionState>;
19
+ channel: <const Name extends string>(name: ChannelNameInput<Registry, Name>) => Readable<FrameworkChannel<Registry, Name> | null>;
20
+ onChannelEvent: <const Name extends string, Event extends FrameworkChannelEvent<Registry, Name>>(name: ChannelNameInput<Registry, Name>, event: Event, handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>) => () => void;
21
+ };
22
+
23
+ export { createSocketContext };
@@ -0,0 +1,82 @@
1
+ import {
2
+ acquireChannel,
3
+ acquireSocketOwnership
4
+ } from "../../chunk-FVPY6HZW.js";
5
+ import "../../chunk-SFAY2ZA4.js";
6
+
7
+ // src/client/svelte.ts
8
+ import { getContext, onDestroy, onMount, setContext } from "svelte";
9
+ import { readable } from "svelte/store";
10
+ function isReadable(value) {
11
+ return typeof value === "object" && value !== null && "subscribe" in value;
12
+ }
13
+ function createSocketContext() {
14
+ const key = /* @__PURE__ */ Symbol("socket");
15
+ function setSocket(socket, options = {}) {
16
+ const state = readable(socket.state, (set) => socket.onStateChange(set));
17
+ setContext(key, { socket, state });
18
+ if (options.owned) {
19
+ onMount(() => acquireSocketOwnership(socket));
20
+ }
21
+ }
22
+ function useContext() {
23
+ const context = getContext(key);
24
+ if (!context) throw new Error("setSocket must be called by an ancestor");
25
+ return context;
26
+ }
27
+ function useSocket() {
28
+ return useContext().socket;
29
+ }
30
+ function useSocketState() {
31
+ return useContext().state;
32
+ }
33
+ function channel(name) {
34
+ const socket = useSocket();
35
+ return readable(null, (set) => {
36
+ let release;
37
+ const acquire = (nextName) => {
38
+ release?.();
39
+ release = void 0;
40
+ if (nextName === null) {
41
+ set(null);
42
+ return;
43
+ }
44
+ const acquired = acquireChannel(socket, nextName);
45
+ release = () => acquired.lease.release();
46
+ set(acquired.channel);
47
+ };
48
+ const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), void 0);
49
+ return () => {
50
+ stopName?.();
51
+ release?.();
52
+ };
53
+ });
54
+ }
55
+ function onChannelEvent(name, event, handler) {
56
+ const socket = useSocket();
57
+ let release;
58
+ const acquire = (nextName) => {
59
+ release?.();
60
+ release = void 0;
61
+ if (nextName === null) return;
62
+ const { lease } = acquireChannel(socket, nextName);
63
+ lease.listen(event, handler);
64
+ release = () => lease.release();
65
+ };
66
+ const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), void 0);
67
+ let disposed = false;
68
+ const dispose = () => {
69
+ if (disposed) return;
70
+ disposed = true;
71
+ stopName?.();
72
+ release?.();
73
+ };
74
+ onDestroy(dispose);
75
+ return dispose;
76
+ }
77
+ return { setSocket, useSocket, useSocketState, channel, onChannelEvent };
78
+ }
79
+ export {
80
+ createSocketContext
81
+ };
82
+ //# sourceMappingURL=svelte.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/client/svelte.ts"],"sourcesContent":["import { getContext, onDestroy, onMount, setContext } from 'svelte'\nimport { readable, type Readable } from 'svelte/store'\nimport type { Socket } from './socket.js'\nimport type { ConnectionState, EventHandler } from './types.js'\nimport {\n acquireChannel,\n acquireSocketOwnership,\n type FrameworkChannel,\n type FrameworkChannelEvent,\n type FrameworkChannelEventPayload,\n type FrameworkChannelName,\n} from './framework.js'\n\ninterface SvelteSocketContext<Registry> {\n socket: Socket<Registry>\n state: Readable<ConnectionState>\n}\n\ntype ChannelNameInput<Registry, Name extends string> =\n | (Name & FrameworkChannelName<Registry, NoInfer<Name>>)\n | null\n | (Readable<Name | null> & Readable<FrameworkChannelName<Registry, NoInfer<Name>> | null>)\n\nfunction isReadable<Value>(value: Value | Readable<Value>): value is Readable<Value> {\n return typeof value === 'object' && value !== null && 'subscribe' in value\n}\n\nexport function createSocketContext<Registry = never>() {\n const key = Symbol('socket')\n\n function setSocket(socket: Socket<Registry>, options: { owned?: boolean } = {}): void {\n const state = readable(socket.state, (set) => socket.onStateChange(set))\n setContext<SvelteSocketContext<Registry>>(key, { socket, state })\n\n if (options.owned) {\n onMount(() => acquireSocketOwnership(socket))\n }\n }\n\n function useContext(): SvelteSocketContext<Registry> {\n const context = getContext<SvelteSocketContext<Registry>>(key)\n if (!context) throw new Error('setSocket must be called by an ancestor')\n return context\n }\n\n function useSocket(): Socket<Registry> {\n return useContext().socket\n }\n\n function useSocketState(): Readable<ConnectionState> {\n return useContext().state\n }\n\n function channel<const Name extends string>(\n name: ChannelNameInput<Registry, Name>\n ): Readable<FrameworkChannel<Registry, Name> | null> {\n const socket = useSocket()\n return readable<FrameworkChannel<Registry, Name> | null>(null, (set) => {\n let release: (() => void) | undefined\n const acquire = (nextName: FrameworkChannelName<Registry, Name> | null) => {\n release?.()\n release = undefined\n if (nextName === null) {\n set(null)\n return\n }\n const acquired = acquireChannel(socket, nextName)\n release = () => acquired.lease.release()\n set(acquired.channel)\n }\n\n const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), undefined)\n return () => {\n stopName?.()\n release?.()\n }\n })\n }\n\n function onChannelEvent<\n const Name extends string,\n Event extends FrameworkChannelEvent<Registry, Name>,\n >(\n name: ChannelNameInput<Registry, Name>,\n event: Event,\n handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>\n ): () => void {\n const socket = useSocket()\n let release: (() => void) | undefined\n const acquire = (nextName: FrameworkChannelName<Registry, Name> | null) => {\n release?.()\n release = undefined\n if (nextName === null) return\n const { lease } = acquireChannel(socket, nextName)\n lease.listen(event, handler)\n release = () => lease.release()\n }\n const stopName = isReadable(name) ? name.subscribe(acquire) : (acquire(name), undefined)\n let disposed = false\n const dispose = () => {\n if (disposed) return\n disposed = true\n stopName?.()\n release?.()\n }\n onDestroy(dispose)\n return dispose\n }\n\n return { setSocket, useSocket, useSocketState, channel, onChannelEvent }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,YAAY,WAAW,SAAS,kBAAkB;AAC3D,SAAS,gBAA+B;AAsBxC,SAAS,WAAkB,OAA0D;AACnF,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAe;AACvE;AAEO,SAAS,sBAAwC;AACtD,QAAM,MAAM,uBAAO,QAAQ;AAE3B,WAAS,UAAU,QAA0B,UAA+B,CAAC,GAAS;AACpF,UAAM,QAAQ,SAAS,OAAO,OAAO,CAAC,QAAQ,OAAO,cAAc,GAAG,CAAC;AACvE,eAA0C,KAAK,EAAE,QAAQ,MAAM,CAAC;AAEhE,QAAI,QAAQ,OAAO;AACjB,cAAQ,MAAM,uBAAuB,MAAM,CAAC;AAAA,IAC9C;AAAA,EACF;AAEA,WAAS,aAA4C;AACnD,UAAM,UAAU,WAA0C,GAAG;AAC7D,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,yCAAyC;AACvE,WAAO;AAAA,EACT;AAEA,WAAS,YAA8B;AACrC,WAAO,WAAW,EAAE;AAAA,EACtB;AAEA,WAAS,iBAA4C;AACnD,WAAO,WAAW,EAAE;AAAA,EACtB;AAEA,WAAS,QACP,MACmD;AACnD,UAAM,SAAS,UAAU;AACzB,WAAO,SAAkD,MAAM,CAAC,QAAQ;AACtE,UAAI;AACJ,YAAM,UAAU,CAAC,aAA0D;AACzE,kBAAU;AACV,kBAAU;AACV,YAAI,aAAa,MAAM;AACrB,cAAI,IAAI;AACR;AAAA,QACF;AACA,cAAM,WAAW,eAAe,QAAQ,QAAQ;AAChD,kBAAU,MAAM,SAAS,MAAM,QAAQ;AACvC,YAAI,SAAS,OAAO;AAAA,MACtB;AAEA,YAAM,WAAW,WAAW,IAAI,IAAI,KAAK,UAAU,OAAO,KAAK,QAAQ,IAAI,GAAG;AAC9E,aAAO,MAAM;AACX,mBAAW;AACX,kBAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,eAIP,MACA,OACA,SACY;AACZ,UAAM,SAAS,UAAU;AACzB,QAAI;AACJ,UAAM,UAAU,CAAC,aAA0D;AACzE,gBAAU;AACV,gBAAU;AACV,UAAI,aAAa,KAAM;AACvB,YAAM,EAAE,MAAM,IAAI,eAAe,QAAQ,QAAQ;AACjD,YAAM,OAAO,OAAO,OAAO;AAC3B,gBAAU,MAAM,MAAM,QAAQ;AAAA,IAChC;AACA,UAAM,WAAW,WAAW,IAAI,IAAI,KAAK,UAAU,OAAO,KAAK,QAAQ,IAAI,GAAG;AAC9E,QAAI,WAAW;AACf,UAAM,UAAU,MAAM;AACpB,UAAI,SAAU;AACd,iBAAW;AACX,iBAAW;AACX,gBAAU;AAAA,IACZ;AACA,cAAU,OAAO;AACjB,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,WAAW,WAAW,gBAAgB,SAAS,eAAe;AACzE;","names":[]}
@@ -1,5 +1,68 @@
1
- export { C as ChannelAck, a as ChannelMessage } from '../../shared_types-Dw9AphfO.js';
1
+ import { a as ChannelServerEventsOf } from '../../types-DiYaFvgi.js';
2
+ export { b as ChannelAck, c as ChannelMessage } from '../../types-DiYaFvgi.js';
3
+ import 'ws';
4
+ import 'node:http';
5
+ import '@adonisjs/core/types/http';
6
+ import '@adonisjs/core/http';
7
+ import '@boringnode/bus/types/main';
2
8
 
9
+ /** Type-only contract carried by a browser channel. */
10
+ interface ChannelContract<ClientEvents = unknown, ServerEvents = unknown> {
11
+ readonly clientEvents: ClientEvents;
12
+ readonly serverEvents: ServerEvents;
13
+ }
14
+ type ChannelInstance<Entry> = Entry extends {
15
+ readonly channel: abstract new (...args: any[]) => infer Instance;
16
+ } ? Instance : never;
17
+ type HandlerName<E, K> = E extends {
18
+ readonly handlers: infer H;
19
+ } ? K extends keyof H ? H[K] : never : never;
20
+ type HandlerAck<Entry, Event> = HandlerName<Entry, Event> extends keyof ChannelInstance<Entry> ? ChannelInstance<Entry>[HandlerName<Entry, Event>] extends (...args: any[]) => infer Result ? Awaited<Result> : unknown : unknown;
21
+ type HandlerPayload<Entry, Event> = HandlerName<Entry, Event> extends keyof ChannelInstance<Entry> ? ChannelInstance<Entry>[HandlerName<Entry, Event>] extends (...args: any[]) => unknown ? Parameters<ChannelInstance<Entry>[HandlerName<Entry, Event>]> extends [
22
+ unknown,
23
+ ...infer Rest
24
+ ] ? Rest extends [] ? undefined : Rest[0] : undefined : unknown : unknown;
25
+ type ClientContracts<Entry> = Entry extends {
26
+ readonly handlers: infer Handlers;
27
+ } ? {
28
+ [Event in Extract<keyof Handlers, string>]: {
29
+ payload: HandlerPayload<Entry, Event>;
30
+ ack: HandlerAck<Entry, Event>;
31
+ };
32
+ } : unknown;
33
+ type NormalizePath<Path extends string> = Path extends '/' ? '/' : Path extends `/${infer WithoutLeading}` ? WithoutLeading extends `${infer Normalized}/` ? Normalized : WithoutLeading : Path extends `${infer WithoutTrailing}/` ? WithoutTrailing : Path;
34
+ type SupportedPattern<Pattern extends string> = string extends Pattern ? false : NormalizePath<Pattern> extends infer Normalized extends string ? Normalized extends '/' ? true : Normalized extends `${infer Segment}/${infer Rest}` ? Segment extends `:${infer Param}` ? Param extends `${string}?${string}` | `${string}.${string}` ? false : SupportedPattern<Rest> : Segment extends '' | '*' | `${string}:${string}` | `${string}*${string}` | `${string}?${string}` ? false : SupportedPattern<Rest> : Normalized extends '*' ? true : Normalized extends `:${infer Param}` ? Param extends `${string}.${string}` ? false : Param extends `${infer Name}?` ? Name extends '' | `${string}?${string}` ? false : true : Param extends '' | `${string}?${string}` ? false : true : Normalized extends '' | `${string}:${string}` | `${string}*${string}` | `${string}?${string}` ? false : true : false;
35
+ type ReplaceNaN<Value extends string> = Value extends `${infer Prefix}NaN${infer Suffix}` ? `${Prefix}1.5${ReplaceNaN<Suffix>}` : Value;
36
+ type ReplaceInfinity<Value extends string> = Value extends `${infer Prefix}-Infinity${infer Suffix}` ? `${Prefix}1.5${ReplaceInfinity<Suffix>}` | `${Prefix}-1.5${ReplaceInfinity<Suffix>}` : Value extends `${infer Prefix}Infinity${infer Suffix}` ? `${Prefix}1.5${ReplaceInfinity<Suffix>}` : Value;
37
+ type ReplaceNonFiniteNumbers<Value extends string> = ReplaceInfinity<ReplaceNaN<Value>>;
38
+ type FiniteNumberWitness<Value extends string> = ReplaceNonFiniteNumbers<Value> extends Value ? never : ReplaceNonFiniteNumbers<Value>;
39
+ type PotentialStaticMatch<Pattern extends string, Name extends string> = Pattern extends Name ? true : [FiniteNumberWitness<Pattern>] extends [never] ? false : [Extract<FiniteNumberWitness<Pattern>, Name>] extends [never] ? false : true;
40
+ type MatchesNormalizedPattern<Pattern extends string, Name extends string> = Pattern extends '*' ? true : Pattern extends `${infer PatternHead}/${infer PatternTail}` ? Name extends `${infer NameHead}/${infer NameTail}` ? PatternHead extends `:${string}` ? MatchesNormalizedPattern<PatternTail, NameTail> : PotentialStaticMatch<PatternHead, NameHead> extends true ? MatchesNormalizedPattern<PatternTail, NameTail> : false : PatternHead extends Name ? PatternTail extends `:${string}?` ? true : false : false : Pattern extends `:${string}?` ? Name extends '/' ? true : Name extends `${string}/${string}` ? false : true : Pattern extends `:${string}` ? Name extends `${string}/${string}` ? false : true : PotentialStaticMatch<Pattern, Name> extends true ? true : false;
41
+ type MatchesChannelPattern<Pattern extends string, Name extends string> = SupportedPattern<Pattern> extends true ? MatchesNormalizedPattern<NormalizePath<Pattern>, NormalizePath<Name>> : false;
42
+ type HasOpenString<Value extends string> = string extends Value ? true : Value extends '' ? false : Value extends `${infer _First}${infer Rest}` ? string extends Rest ? true : HasOpenString<Rest> : false;
43
+ type DefinitelyMatchesNormalizedPattern<Pattern extends string, Name extends string> = Pattern extends '*' ? true : Pattern extends `${infer PatternHead}/${infer PatternTail}` ? Name extends `${infer NameHead}/${infer NameTail}` ? PatternHead extends `:${string}` ? HasOpenString<NameHead> extends true ? false : DefinitelyMatchesNormalizedPattern<PatternTail, NameTail> : NameHead extends PatternHead ? DefinitelyMatchesNormalizedPattern<PatternTail, NameTail> : false : PatternHead extends Name ? PatternTail extends `:${string}?` ? true : false : false : Pattern extends `:${string}?` ? HasOpenString<Name> extends true ? false : Name extends `${string}/${string}` ? Name extends '/' ? true : false : true : Pattern extends `:${string}` ? HasOpenString<Name> extends true ? false : Name extends `${string}/${string}` ? false : true : Name extends Pattern ? true : false;
44
+ type DefinitelyMatchesChannelPattern<Pattern extends string, Name extends string> = SupportedPattern<Pattern> extends true ? DefinitelyMatchesNormalizedPattern<NormalizePath<Pattern>, NormalizePath<Name>> : false;
45
+ type SegmentRank<Segment extends string> = Segment extends '*' ? 1 : Segment extends `:${string}?` ? 2 : Segment extends `:${string}` ? 3 : 4;
46
+ type PatternScore<Pattern extends string> = NormalizePath<Pattern> extends `${infer Head}/${infer Tail}` ? [SegmentRank<Head>, ...PatternScore<Tail>] : [SegmentRank<NormalizePath<Pattern>>];
47
+ type RankGreater<Left extends number, Right extends number> = Left extends 4 ? Right extends 4 ? false : true : Left extends 3 ? Right extends 1 | 2 ? true : false : Left extends 2 ? Right extends 1 ? true : false : false;
48
+ type ScoreGreater<Left extends number[], Right extends number[]> = Left extends [
49
+ infer LeftHead extends number,
50
+ ...infer LeftTail extends number[]
51
+ ] ? Right extends [infer RightHead extends number, ...infer RightTail extends number[]] ? LeftHead extends RightHead ? ScoreGreater<LeftTail, RightTail> : RankGreater<LeftHead, RightHead> : true : false;
52
+ type PatternOf<Entry> = Entry extends {
53
+ readonly pattern: infer Pattern extends string;
54
+ } ? Pattern : never;
55
+ type MoreSpecific<Left, Right> = ScoreGreater<PatternScore<PatternOf<Left>>, PatternScore<PatternOf<Right>>>;
56
+ type ResolveRegistryEntry<Entries extends readonly unknown[], Name extends string, Best = never, Ambiguous extends boolean = false> = Entries extends readonly [infer Current, ...infer Rest] ? true extends MatchesChannelPattern<PatternOf<Current>, Name> ? [Best] extends [never] ? ResolveRegistryEntry<Rest, Name, Current, false> : MoreSpecific<Current, Best> extends true ? ResolveRegistryEntry<Rest, Name, Current, false> : MoreSpecific<Best, Current> extends true ? ResolveRegistryEntry<Rest, Name, Best, Ambiguous> : ResolveRegistryEntry<Rest, Name, Best, true> : ResolveRegistryEntry<Rest, Name, Best, Ambiguous> : Ambiguous extends true ? unknown : Best;
57
+ type RegistryEntries<Registry> = Registry extends {
58
+ readonly channels: infer Entries extends readonly unknown[];
59
+ } ? Entries : [];
60
+ type PotentialMatchCount<Entries extends readonly unknown[], Name extends string, Count extends 0 | 1 | 2 = 0> = Entries extends readonly [infer Current, ...infer Rest] ? true extends MatchesChannelPattern<PatternOf<Current>, Name> ? PotentialMatchCount<Rest, Name, Count extends 0 ? 1 : 2> : PotentialMatchCount<Rest, Name, Count> : Count;
61
+ type ContractOfEntry<Entry> = ChannelContract<ClientContracts<Entry>, ChannelServerEventsOf<ChannelInstance<Entry>>>;
62
+ /** Resolves a literal channel name to its unique most-specific generated contract. */
63
+ type ChannelContractFor<Registry, Name extends string> = string extends Name ? unknown : Registry extends {
64
+ readonly uncertain: true;
65
+ } ? unknown : ResolveRegistryEntry<RegistryEntries<Registry>, Name> extends infer Entry ? unknown extends Entry ? unknown : [Entry] extends [never] ? never : DefinitelyMatchesChannelPattern<PatternOf<Entry>, Name> extends true ? ContractOfEntry<Entry> : PotentialMatchCount<RegistryEntries<Registry>, Name> extends 1 ? ContractOfEntry<Entry> : unknown : never;
3
66
  /**
4
67
  * Connection options.
5
68
  */
@@ -65,14 +128,15 @@ interface PresenceData {
65
128
  channel: string;
66
129
  users: PresenceUser[];
67
130
  count: number;
131
+ [key: string]: unknown;
68
132
  }
69
133
  /**
70
134
  * User in presence data.
71
135
  */
72
136
  interface PresenceUser {
73
137
  id: string;
74
- name: string;
75
138
  joinedAt: string;
139
+ [key: string]: unknown;
76
140
  }
77
141
  /**
78
142
  * Connection state.
@@ -89,8 +153,8 @@ interface SocketClientTransport {
89
153
  connected: boolean;
90
154
  sendRequest<T = unknown>(message: Record<string, unknown>, timeout?: number): Promise<T>;
91
155
  send(message: Record<string, unknown>): void;
92
- on(event: string, handler: EventHandler): void;
93
- off(event: string, handler: EventHandler): void;
156
+ on<T = unknown>(event: string, handler: EventHandler<T>): void;
157
+ off<T = unknown>(event: string, handler: EventHandler<T>): void;
94
158
  }
95
159
 
96
- export type { ConnectionState, EventHandler, PresenceData, PresenceUser, SocketClientTransport, SocketOptions, SubscribeAckData, SubscribeOptions, SubscribeResult, UnsubscribeOptions };
160
+ export { type ChannelContract, type ChannelContractFor, ChannelServerEventsOf, type ConnectionState, type EventHandler, type PresenceData, type PresenceUser, type SocketClientTransport, type SocketOptions, type SubscribeAckData, type SubscribeOptions, type SubscribeResult, type UnsubscribeOptions };
@@ -0,0 +1,26 @@
1
+ import { ShallowRef, ComputedRef, MaybeRefOrGetter } from 'vue';
2
+ import { Socket } from './index.js';
3
+ import { ConnectionState, EventHandler } from './types.js';
4
+ import { F as FrameworkChannelName, a as FrameworkChannel, b as FrameworkChannelEvent, c as FrameworkChannelEventPayload } from '../../framework-DuW6zpPk.js';
5
+ import '../../types-DiYaFvgi.js';
6
+ import 'ws';
7
+ import 'node:http';
8
+ import '@adonisjs/core/types/http';
9
+ import '@adonisjs/core/http';
10
+ import '@boringnode/bus/types/main';
11
+
12
+ type ChannelNameInput<Registry, Name extends string> = MaybeRefOrGetter<Name | null> & MaybeRefOrGetter<FrameworkChannelName<Registry, NoInfer<Name>> | null>;
13
+ declare function createSocketComposables<Registry = never>(): {
14
+ provideSocket: (socket: Socket<Registry>, options?: {
15
+ owned?: boolean;
16
+ }) => void;
17
+ useSocket: () => Socket<Registry>;
18
+ useSocketState: () => {
19
+ state: Readonly<ShallowRef<ConnectionState>>;
20
+ connected: ComputedRef<boolean>;
21
+ };
22
+ useChannel: <const Name extends string>(name: ChannelNameInput<Registry, Name>) => Readonly<ShallowRef<FrameworkChannel<Registry, Name> | null>>;
23
+ useChannelEvent: <const Name extends string, Event extends FrameworkChannelEvent<Registry, Name>>(name: ChannelNameInput<Registry, Name>, event: Event, handler: EventHandler<FrameworkChannelEventPayload<Registry, Name, Event>>) => void;
24
+ };
25
+
26
+ export { createSocketComposables };