@rlanz/socket 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -524,6 +524,10 @@ const socket = new Socket<AppSocket>({
524
524
  autoReconnect: true,
525
525
  reconnectDelay: 250,
526
526
  reconnectMaxDelay: 5000,
527
+ onResubscribeError({ channel, error }) {
528
+ if (error.message === 'Session expired') return
529
+ console.error(`Could not resubscribe to ${channel}`, error)
530
+ },
527
531
  })
528
532
 
529
533
  socket.onStateChange((state) => {
@@ -565,7 +569,9 @@ socket.disconnect()
565
569
 
566
570
  Automatic reconnection starts at `250ms` and doubles up to `5s`. After reconnecting, the client
567
571
  subscribes again to desired channels. Pending acknowledgements fail and authentication and channel
568
- middleware run again. Events sent while disconnected are not replayed.
572
+ middleware run again. Events sent while disconnected are not replayed. A rejected automatic
573
+ subscription calls `onResubscribeError` with the channel name and error. The client does not report
574
+ this protocol outcome as a global JavaScript error.
569
575
 
570
576
  Set `autoReconnect: false` to disable retries. A deliberate server disconnect is terminal by
571
577
  default. Use `shouldReconnect(closeEvent)` to override the decision for any close code or reason.
@@ -842,11 +842,13 @@ var Socket = class {
842
842
  #url;
843
843
  #path;
844
844
  #session;
845
+ #onResubscribeError;
845
846
  constructor(options = {}) {
846
847
  const browserWindow = globalThis;
847
848
  const browserOrigin = typeof globalThis === "object" && browserWindow.window?.location?.origin ? browserWindow.window.location.origin : "";
848
849
  this.#url = options.url ?? browserOrigin;
849
850
  this.#path = options.path ?? "/socket";
851
+ this.#onResubscribeError = options.onResubscribeError;
850
852
  this.#session = new ClientSocketSession({
851
853
  buildUrl: () => this.#buildUrl(),
852
854
  autoReconnect: options.autoReconnect,
@@ -927,7 +929,14 @@ var Socket = class {
927
929
  async #resubscribeChannels() {
928
930
  for (const channel of this.#channels.values()) {
929
931
  if (channel.subscribed && !channel.active) {
930
- await channel.$resubscribe().catch(reportClientError);
932
+ await channel.$resubscribe().catch((error) => {
933
+ if (this.#onResubscribeError) {
934
+ callClientHandler(this.#onResubscribeError, {
935
+ channel: channel.name,
936
+ error: error instanceof Error ? error : new Error("Resubscribe failed")
937
+ });
938
+ }
939
+ });
931
940
  }
932
941
  }
933
942
  }
@@ -939,4 +948,4 @@ export {
939
948
  buildChannelName,
940
949
  Socket
941
950
  };
942
- //# sourceMappingURL=chunk-DR6GWQUW.js.map
951
+ //# sourceMappingURL=chunk-3FY7EIZF.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/callback.ts","../src/client/presence_snapshot.ts","../src/client/channel.ts","../src/client/socket_session.ts","../src/client/socket.ts"],"sourcesContent":["type Callable = (...args: never[]) => unknown\n\nexport function reportClientError(error: unknown): void {\n try {\n const reportError = (\n globalThis as typeof globalThis & { reportError?: (error: unknown) => void }\n ).reportError\n\n if (typeof reportError === 'function') {\n reportError(error)\n } else {\n console.error(error)\n }\n } catch {\n // Error reporting must never affect socket state or create another rejected promise.\n }\n}\n\nexport function callClientHandler(handler: Callable, data?: unknown): void {\n try {\n const result = Reflect.apply(handler, undefined, [data])\n if (result && typeof (result as PromiseLike<unknown>).then === 'function') {\n void Promise.resolve(result).catch(reportClientError)\n }\n } catch (error) {\n reportClientError(error)\n }\n}\n","import type { PresenceUser } from './types.js'\n\nexport interface ClientPresenceDiff {\n readonly joining: readonly PresenceUser[]\n readonly leaving: readonly PresenceUser[]\n}\n\n/**\n * Immutable, validated client view of one channel's presence.\n */\nexport class ClientPresenceSnapshot {\n readonly count: number\n readonly users: readonly PresenceUser[]\n readonly #usersById: ReadonlyMap<string, PresenceUser>\n\n private constructor(users: PresenceUser[]) {\n // Copy and freeze each user. Consumer code cannot change the snapshot.\n this.users = Object.freeze(users.map((user) => Object.freeze({ ...user }) as PresenceUser))\n this.count = this.users.length\n\n // Build the ID index once. Diff operations do not need a second channel state.\n this.#usersById = new Map(this.users.map((user) => [user.id, user]))\n }\n\n /**\n * Validate one transport snapshot for the expected channel.\n */\n static fromTransport(value: unknown, expectedChannel: string): ClientPresenceSnapshot | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null\n }\n\n const data = value as Record<string, unknown>\n\n // The transport count must be an integer and must match the user list.\n if (\n data.channel !== expectedChannel ||\n !Array.isArray(data.users) ||\n !Number.isInteger(data.count) ||\n data.count !== data.users.length\n ) {\n return null\n }\n\n const users: PresenceUser[] = []\n const userIds = new Set<string>()\n for (const candidate of data.users) {\n // Each user needs a unique ID and one transport timestamp.\n if (\n !candidate ||\n typeof candidate !== 'object' ||\n Array.isArray(candidate) ||\n typeof candidate.id !== 'string' ||\n typeof candidate.joinedAt !== 'string' ||\n userIds.has(candidate.id)\n ) {\n return null\n }\n userIds.add(candidate.id)\n users.push(candidate as PresenceUser)\n }\n\n return new ClientPresenceSnapshot(users)\n }\n\n /**\n * Return users that joined or left since the previous snapshot.\n */\n diff(previous: ClientPresenceSnapshot | null): ClientPresenceDiff {\n if (!previous) {\n return { joining: this.users, leaving: [] }\n }\n\n // Keep the order from the snapshot that owns each user.\n return {\n joining: this.users.filter((user) => !previous.#usersById.has(user.id)),\n leaving: previous.users.filter((user) => !this.#usersById.has(user.id)),\n }\n }\n}\n","import type {\n SocketClientTransport,\n SubscribeOptions,\n SubscribeResult,\n UnsubscribeOptions,\n PresenceUser,\n EventHandler,\n ChannelMessage,\n ChannelAck,\n ChannelContract,\n} from './types.js'\nimport { callClientHandler } from './callback.js'\nimport { ClientPresenceSnapshot } from './presence_snapshot.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/:roomId', { roomId: '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 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\ninterface PendingSubscribe<Contract> {\n promise: Promise<Channel<Contract>>\n resolve: (channel: Channel<Contract>) => void\n reject: (error: Error) => void\n}\n\ntype RemoteSynchronization<Contract> =\n | { status: 'idle' }\n | { status: 'subscribing'; pending: PendingSubscribe<Contract>; connected: boolean }\n | { status: 'active' }\n | { status: 'unsubscribing'; promise: Promise<void> }\n | { status: 'waitingForReconnect' }\n | { status: 'subscriptionUncertain' }\n | { status: 'remoteSubscriptionUncertain' }\n\nexport class Channel<Contract> {\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 #remoteSynchronization: RemoteSynchronization<Contract> = { status: 'idle' }\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: ClientPresenceSnapshot | null = null\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 #managedSubscriptions = 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 || 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.#remoteSynchronization.status === '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) {\n return this.#remoteSynchronization.status === 'unsubscribing'\n ? this.#remoteSynchronization.promise\n : Promise.resolve()\n }\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.#remoteSynchronization.status === 'unsubscribing') {\n await this.#remoteSynchronization.promise\n }\n\n if (!this.subscribed) return this\n\n if (this.#remoteSynchronization.status === 'subscribing') {\n await this.#remoteSynchronization.pending.promise\n return this\n }\n\n if (this.#remoteSynchronization.status === '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 (\n this.#remoteSynchronization.status === 'idle' ||\n this.#remoteSynchronization.status === 'remoteSubscriptionUncertain'\n ) {\n this.#setupSocketListeners()\n }\n\n const deferred = Promise.withResolvers<Channel<Contract>>()\n const synchronization: RemoteSynchronization<Contract> = {\n status: 'subscribing',\n pending: deferred,\n connected: true,\n }\n this.#remoteSynchronization = synchronization\n\n const timer = setTimeout(() => {\n if (this.#remoteSynchronization !== synchronization) return\n this.#remoteSynchronization = { status: 'waitingForReconnect' }\n this.#resetConnectionState()\n synchronization.pending.reject(new Error(`Subscribe timeout for channel: ${this.name}`))\n void this.#transport\n .sendRequest({ type: 'unsubscribe', channel: this.name }, timeout)\n .catch(() => {})\n }, timeout)\n\n this.#transport\n .sendRequest<SubscribeResult>({ type: 'subscribe', channel: this.name }, timeout)\n .then((response) => {\n if (this.#remoteSynchronization !== synchronization) return\n clearTimeout(timer)\n\n if (response.ok) {\n this.#remoteSynchronization = { status: 'active' }\n\n const presenceData = ClientPresenceSnapshot.fromTransport(\n response.data?.presenceData,\n this.name\n )\n\n // Apply the initial presence snapshot.\n if (presenceData) {\n this.#handleInitialPresence(presenceData)\n }\n\n synchronization.pending.resolve(this)\n } else {\n this.#remoteSynchronization = { status: 'waitingForReconnect' }\n this.#resetConnectionState()\n synchronization.pending.reject(new Error(response.error))\n }\n })\n .catch((error) => {\n if (this.#remoteSynchronization !== synchronization) return\n clearTimeout(timer)\n this.#remoteSynchronization = synchronization.connected\n ? { status: 'subscriptionUncertain' }\n : { status: 'waitingForReconnect' }\n this.#resetConnectionState()\n synchronization.pending.reject(\n error instanceof Error ? error : new Error('Subscribe failed')\n )\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.#remoteSynchronization.status === 'unsubscribing') {\n return this.#remoteSynchronization.promise\n }\n\n const previousSynchronization = this.#remoteSynchronization\n const hadPendingSubscribe = previousSynchronization.status === 'subscribing'\n if (previousSynchronization.status === 'subscribing') {\n previousSynchronization.pending.reject(new Error(`Unsubscribed from channel: ${this.name}`))\n }\n\n const remoteSubscriptionPossible =\n previousSynchronization.status === 'active' ||\n previousSynchronization.status === 'subscriptionUncertain' ||\n previousSynchronization.status === 'remoteSubscriptionUncertain'\n\n if (!hadPendingSubscribe && !remoteSubscriptionPossible) {\n this.#cleanupTerminal()\n return Promise.resolve()\n }\n\n const timeout = options.timeout ?? 5000\n const deferred = Promise.withResolvers<void>()\n const synchronization: RemoteSynchronization<Contract> = {\n status: 'unsubscribing',\n promise: deferred.promise,\n }\n this.#remoteSynchronization = synchronization\n let remoteMayRemain = true\n let terminalSynchronization: RemoteSynchronization<Contract> | null = null\n const timer = setTimeout(() => deferred.resolve(), timeout)\n\n this.#transport\n .sendRequest({ type: 'unsubscribe', channel: this.name }, timeout)\n .then(() => {\n remoteMayRemain = false\n clearTimeout(timer)\n deferred.resolve()\n if (this.#remoteSynchronization === terminalSynchronization) {\n this.#remoteSynchronization = { status: 'idle' }\n }\n })\n .catch(() => {\n clearTimeout(timer)\n deferred.resolve()\n })\n\n const pending = deferred.promise\n void pending.finally(() => {\n if (this.#remoteSynchronization !== synchronization) return\n terminalSynchronization = remoteMayRemain\n ? { status: 'remoteSubscriptionUncertain' }\n : { status: 'idle' }\n this.#remoteSynchronization = terminalSynchronization\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 = ClientPresenceSnapshot.fromTransport(data, this.name)\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 if (this.#remoteSynchronization.status === 'subscribing') {\n this.#remoteSynchronization.connected = false\n } else if (\n this.#remoteSynchronization.status === 'active' ||\n this.#remoteSynchronization.status === 'subscriptionUncertain'\n ) {\n this.#remoteSynchronization = { status: 'waitingForReconnect' }\n } else if (this.#remoteSynchronization.status === 'remoteSubscriptionUncertain') {\n this.#remoteSynchronization = { status: 'idle' }\n }\n this.#resetConnectionState()\n }\n this.#transport.on('disconnect', this.#boundDisconnectHandler)\n }\n\n /**\n * Handles the initial presence snapshot.\n */\n #handleInitialPresence(data: ClientPresenceSnapshot): void {\n this.#presence = data\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: ClientPresenceSnapshot): void {\n const { joining, leaving } = data.diff(this.#presence)\n\n // Commit the validated update before invoking user code.\n this.#presence = data\n\n // Detect new users.\n for (const user of joining) {\n if (this.#joiningHandler) {\n callClientHandler(this.#joiningHandler, user)\n }\n }\n\n // Detect users that left.\n for (const user of leaving) {\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.#presence = null\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\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.#remoteSynchronization = { status: 'idle' }\n this.#resetConnectionState()\n this.#detachTransportListeners()\n this.#clearCallbacks()\n }\n}\n","import type { ConnectionState, EventHandler } from './types.js'\nimport { SERVER_DISCONNECT_CODE, 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 ConnectDeferred extends PromiseWithResolvers<void> {}\n\ninterface SocketConnection {\n socket: WebSocket\n}\n\ntype ClientSocketLifecycle =\n | { kind: 'disconnected'; reconnectAttempt: number }\n | { kind: 'waiting'; timer: ReturnType<typeof setTimeout>; reconnectAttempt: number }\n | { kind: 'opening'; deferred: ConnectDeferred; reconnectAttempt: number }\n | {\n kind: 'connecting'\n connection: SocketConnection\n deferred: ConnectDeferred\n reconnectAttempt: number\n }\n | {\n kind: 'opened'\n connection: SocketConnection\n deferred: ConnectDeferred\n reconnectAttempt: number\n }\n | { kind: 'connected'; connection: SocketConnection }\n | { kind: 'failed'; connection: SocketConnection; reconnectAttempt: number }\n\ntype DisconnectedLifecycle = Extract<ClientSocketLifecycle, { kind: 'disconnected' }>\ntype WaitingLifecycle = Extract<ClientSocketLifecycle, { kind: 'waiting' }>\n\ninterface ClientSocketSessionOptions {\n buildUrl: () => string\n createWebSocket?: (url: string) => WebSocket\n autoReconnect?: boolean\n reconnectDelay?: number\n reconnectMaxDelay?: number\n shouldReconnect?: (event: CloseEvent) => boolean\n onConnected?: () => void\n}\n\nexport class ClientSocketSession {\n #lifecycle: ClientSocketLifecycle = { kind: 'disconnected', reconnectAttempt: 0 }\n #stateHandlers = new Set<Callable>()\n #eventHandlers = new Map<string, Set<Callable>>()\n #pendingRequests = new Map<string, PendingRequest>()\n #requestId = 0\n #buildUrl: () => string\n #createWebSocket: (url: string) => WebSocket\n #autoReconnect: boolean\n #reconnectDelay: number\n #reconnectMaxDelay: number\n #shouldReconnect: (event: CloseEvent) => boolean\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.#shouldReconnect =\n options.shouldReconnect ?? ((event) => event.code !== SERVER_DISCONNECT_CODE)\n this.#onConnected = options.onConnected\n }\n\n get state(): ConnectionState {\n switch (this.#lifecycle.kind) {\n case 'opening':\n case 'connecting':\n return 'connecting'\n case 'opened':\n case 'connected':\n return 'connected'\n case 'disconnected':\n case 'waiting':\n case 'failed':\n return 'disconnected'\n }\n }\n\n get connected(): boolean {\n return this.state === 'connected'\n }\n\n connect(): Promise<void> {\n if (this.#lifecycle.kind === 'connected') return Promise.resolve()\n if (this.#lifecycle.kind === 'opening' || this.#lifecycle.kind === 'connecting') {\n return this.#lifecycle.deferred.promise\n }\n if (this.#lifecycle.kind === 'opened') return this.#lifecycle.deferred.promise\n\n const reconnectAttempt = this.#reconnectAttempt\n const failedSocket =\n this.#lifecycle.kind === 'failed' ? this.#lifecycle.connection.socket : null\n if (this.#lifecycle.kind === 'waiting') clearTimeout(this.#lifecycle.timer)\n\n const connection = this.#startConnection(reconnectAttempt)\n failedSocket?.close()\n return connection\n }\n\n #startConnection(reconnectAttempt: number): Promise<void> {\n const deferred = Promise.withResolvers<void>()\n const opening: ClientSocketLifecycle = { kind: 'opening', deferred, reconnectAttempt }\n this.#setLifecycle(opening)\n if (this.#lifecycle !== opening) return deferred.promise\n\n let socket: WebSocket\n try {\n socket = this.#createWebSocket(this.#buildUrl())\n } catch (error) {\n this.#setLifecycle({ kind: 'disconnected', reconnectAttempt })\n deferred.reject(error)\n return deferred.promise\n }\n\n const connection = { socket }\n const connecting: ClientSocketLifecycle = {\n kind: 'connecting',\n connection,\n deferred,\n reconnectAttempt,\n }\n this.#lifecycle = connecting\n\n const cleanup = () => {\n socket.removeEventListener('open', handleOpen)\n socket.removeEventListener('error', handleError)\n }\n\n const handleOpen = () => {\n if (this.#lifecycle !== connecting) return\n\n cleanup()\n const opened: ClientSocketLifecycle = {\n kind: 'opened',\n connection,\n deferred,\n reconnectAttempt,\n }\n this.#setLifecycle(opened)\n if (!this.#isCurrent(opened)) return\n\n this.#lifecycle = { kind: 'connected', connection }\n this.#emitLocal('connect')\n if (this.#onConnected) this.#callHandler(this.#onConnected)\n deferred.resolve()\n }\n\n const handleError = () => {\n if (this.#lifecycle !== connecting) return\n\n cleanup()\n deferred.reject(new Error('WebSocket connection failed'))\n this.#setLifecycle({ kind: 'failed', connection, reconnectAttempt })\n }\n\n socket.addEventListener('open', handleOpen)\n socket.addEventListener('error', handleError)\n socket.addEventListener('message', (event) => {\n if (this.#owns(connection)) this.#handleIncoming(event.data)\n })\n socket.addEventListener('close', (event) => {\n cleanup()\n if (this.#owns(connection)) this.#handleClose(event)\n })\n\n return deferred.promise\n }\n\n disconnect(): void {\n const lifecycle = this.#lifecycle\n const shouldEmitDisconnect = this.state !== 'disconnected'\n if (lifecycle.kind === 'waiting') clearTimeout(lifecycle.timer)\n if (\n lifecycle.kind === 'opening' ||\n lifecycle.kind === 'connecting' ||\n lifecycle.kind === 'opened'\n ) {\n lifecycle.deferred.reject(new Error('Socket disconnected'))\n }\n\n this.#setLifecycle({ kind: 'disconnected', reconnectAttempt: 0 })\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n if ('connection' in lifecycle) lifecycle.connection.socket.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 socket = this.#connection?.socket\n if (socket?.readyState !== WebSocket.OPEN) {\n return\n }\n\n socket.send(JSON.stringify(message))\n }\n\n sendRequest(message: Record<string, unknown>, timeout = 5000): Promise<unknown> {\n const socket = this.#connection?.socket\n if (socket?.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 socket.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 ((message.ok === true && message.error === undefined) ||\n (message.ok === false && typeof message.error === 'string' && message.data === undefined))\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(event: CloseEvent): void {\n const lifecycle = this.#lifecycle\n const reconnectAttempt = 'reconnectAttempt' in lifecycle ? lifecycle.reconnectAttempt : 0\n const shouldEmitDisconnect = this.state !== 'disconnected'\n if (lifecycle.kind === 'connecting') {\n lifecycle.deferred.reject(new Error('WebSocket connection failed'))\n }\n\n const disconnected: DisconnectedLifecycle = { kind: 'disconnected', reconnectAttempt }\n this.#setLifecycle(disconnected)\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n this.#rejectPending(new Error('Socket disconnected'))\n\n if (this.#shouldReconnect(event) && this.#lifecycle === disconnected) {\n this.#scheduleReconnect(disconnected)\n }\n }\n\n #scheduleReconnect(disconnected: DisconnectedLifecycle): void {\n if (!this.#autoReconnect || this.#lifecycle !== disconnected) return\n\n const delay = Math.min(\n this.#reconnectDelay * 2 ** disconnected.reconnectAttempt,\n this.#reconnectMaxDelay\n )\n const waiting: WaitingLifecycle = {\n kind: 'waiting',\n reconnectAttempt: disconnected.reconnectAttempt + 1,\n timer: setTimeout(() => {\n if (this.#lifecycle !== waiting) return\n\n this.#startConnection(waiting.reconnectAttempt).catch(() => {\n if (this.#lifecycle.kind === 'failed') {\n const failed = this.#lifecycle\n const disconnected: DisconnectedLifecycle = {\n kind: 'disconnected',\n reconnectAttempt: failed.reconnectAttempt,\n }\n this.#setLifecycle(disconnected)\n failed.connection.socket.close()\n if (this.#isCurrent(disconnected)) this.#scheduleReconnect(disconnected)\n return\n }\n\n if (this.#lifecycle.kind === 'disconnected') {\n this.#scheduleReconnect(this.#lifecycle)\n }\n })\n }, delay),\n }\n this.#setLifecycle(waiting)\n }\n\n get #connection(): SocketConnection | undefined {\n const lifecycle = this.#lifecycle\n return 'connection' in lifecycle ? lifecycle.connection : undefined\n }\n\n get #reconnectAttempt(): number {\n const lifecycle = this.#lifecycle\n return 'reconnectAttempt' in lifecycle ? lifecycle.reconnectAttempt : 0\n }\n\n #owns(connection: SocketConnection): boolean {\n return this.#connection === connection\n }\n\n #isCurrent(lifecycle: ClientSocketLifecycle): boolean {\n return this.#lifecycle === lifecycle\n }\n\n #setLifecycle(lifecycle: ClientSocketLifecycle): void {\n const previousState = this.state\n this.#lifecycle = lifecycle\n const state = this.state\n\n if (previousState !== state) {\n this.#stateHandlers.forEach((handler) => this.#callHandler(handler, state))\n }\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 #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 { BindableChannelPattern } from '../bindable_channel_pattern.js'\nimport type {\n SocketOptions,\n ConnectionState,\n EventHandler,\n SocketClientTransport,\n ChannelContractFor,\n ChannelContract,\n ChannelCallArgs,\n} from './types.js'\n\nexport const resolveChannel = Symbol('resolveChannel')\n\n/**\n * Main Socket client.\n */\ntype IsUntypedRegistry<Registry> = unknown extends Registry\n ? true\n : [Registry] extends [undefined]\n ? true\n : false\n\ntype SocketChannelArgs<Registry> =\n IsUntypedRegistry<Registry> extends true ? [name: string] : ChannelCallArgs<Registry>\n\ntype ChannelResult<Registry, Pattern extends string> =\n IsUntypedRegistry<Registry> extends true\n ? Channel<ChannelContract>\n : Channel<ChannelContractFor<Registry, Pattern>>\n\ntype RuntimeChannelParameters = object\n\n/** Constructs a concrete channel name from a supported generated pattern. @internal */\nexport function buildChannelName(\n pattern: string,\n parameters: RuntimeChannelParameters = {}\n): string {\n const bindablePattern = BindableChannelPattern.parse(pattern)\n if (!bindablePattern) {\n throw new Error(`Unsupported generated channel pattern: ${pattern}`)\n }\n return bindablePattern.bind(parameters)\n}\n\nexport class Socket<Registry = undefined> implements SocketClientTransport {\n #channels = new Map<string, Channel<any>>()\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 shouldReconnect: options.shouldReconnect,\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 Args extends SocketChannelArgs<Registry>>(\n ...args: Args\n ): ChannelResult<Registry, Args[0]> {\n const [pattern, parameters] = args as [string, object?]\n const name = args.length > 1 ? buildChannelName(pattern, parameters) : pattern\n return this[resolveChannel](name) as ChannelResult<Registry, Args[0]>\n }\n\n /** Resolves a channel for framework adapters after their public type checks. @internal */\n [resolveChannel](name: string): Channel<any> {\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 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 url.hash = ''\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":["disconnected"]}
1
+ {"version":3,"sources":["../src/client/callback.ts","../src/client/presence_snapshot.ts","../src/client/channel.ts","../src/client/socket_session.ts","../src/client/socket.ts"],"sourcesContent":["type Callable = (...args: never[]) => unknown\n\nexport function reportClientError(error: unknown): void {\n try {\n const reportError = (\n globalThis as typeof globalThis & { reportError?: (error: unknown) => void }\n ).reportError\n\n if (typeof reportError === 'function') {\n reportError(error)\n } else {\n console.error(error)\n }\n } catch {\n // Error reporting must never affect socket state or create another rejected promise.\n }\n}\n\nexport function callClientHandler(handler: Callable, data?: unknown): void {\n try {\n const result = Reflect.apply(handler, undefined, [data])\n if (result && typeof (result as PromiseLike<unknown>).then === 'function') {\n void Promise.resolve(result).catch(reportClientError)\n }\n } catch (error) {\n reportClientError(error)\n }\n}\n","import type { PresenceUser } from './types.js'\n\nexport interface ClientPresenceDiff {\n readonly joining: readonly PresenceUser[]\n readonly leaving: readonly PresenceUser[]\n}\n\n/**\n * Immutable, validated client view of one channel's presence.\n */\nexport class ClientPresenceSnapshot {\n readonly count: number\n readonly users: readonly PresenceUser[]\n readonly #usersById: ReadonlyMap<string, PresenceUser>\n\n private constructor(users: PresenceUser[]) {\n // Copy and freeze each user. Consumer code cannot change the snapshot.\n this.users = Object.freeze(users.map((user) => Object.freeze({ ...user }) as PresenceUser))\n this.count = this.users.length\n\n // Build the ID index once. Diff operations do not need a second channel state.\n this.#usersById = new Map(this.users.map((user) => [user.id, user]))\n }\n\n /**\n * Validate one transport snapshot for the expected channel.\n */\n static fromTransport(value: unknown, expectedChannel: string): ClientPresenceSnapshot | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null\n }\n\n const data = value as Record<string, unknown>\n\n // The transport count must be an integer and must match the user list.\n if (\n data.channel !== expectedChannel ||\n !Array.isArray(data.users) ||\n !Number.isInteger(data.count) ||\n data.count !== data.users.length\n ) {\n return null\n }\n\n const users: PresenceUser[] = []\n const userIds = new Set<string>()\n for (const candidate of data.users) {\n // Each user needs a unique ID and one transport timestamp.\n if (\n !candidate ||\n typeof candidate !== 'object' ||\n Array.isArray(candidate) ||\n typeof candidate.id !== 'string' ||\n typeof candidate.joinedAt !== 'string' ||\n userIds.has(candidate.id)\n ) {\n return null\n }\n userIds.add(candidate.id)\n users.push(candidate as PresenceUser)\n }\n\n return new ClientPresenceSnapshot(users)\n }\n\n /**\n * Return users that joined or left since the previous snapshot.\n */\n diff(previous: ClientPresenceSnapshot | null): ClientPresenceDiff {\n if (!previous) {\n return { joining: this.users, leaving: [] }\n }\n\n // Keep the order from the snapshot that owns each user.\n return {\n joining: this.users.filter((user) => !previous.#usersById.has(user.id)),\n leaving: previous.users.filter((user) => !this.#usersById.has(user.id)),\n }\n }\n}\n","import type {\n SocketClientTransport,\n SubscribeOptions,\n SubscribeResult,\n UnsubscribeOptions,\n PresenceUser,\n EventHandler,\n ChannelMessage,\n ChannelAck,\n ChannelContract,\n} from './types.js'\nimport { callClientHandler } from './callback.js'\nimport { ClientPresenceSnapshot } from './presence_snapshot.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/:roomId', { roomId: '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 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\ninterface PendingSubscribe<Contract> {\n promise: Promise<Channel<Contract>>\n resolve: (channel: Channel<Contract>) => void\n reject: (error: Error) => void\n}\n\ntype RemoteSynchronization<Contract> =\n | { status: 'idle' }\n | { status: 'subscribing'; pending: PendingSubscribe<Contract>; connected: boolean }\n | { status: 'active' }\n | { status: 'unsubscribing'; promise: Promise<void> }\n | { status: 'waitingForReconnect' }\n | { status: 'subscriptionUncertain' }\n | { status: 'remoteSubscriptionUncertain' }\n\nexport class Channel<Contract> {\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 #remoteSynchronization: RemoteSynchronization<Contract> = { status: 'idle' }\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: ClientPresenceSnapshot | null = null\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 #managedSubscriptions = 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 || 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.#remoteSynchronization.status === '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) {\n return this.#remoteSynchronization.status === 'unsubscribing'\n ? this.#remoteSynchronization.promise\n : Promise.resolve()\n }\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.#remoteSynchronization.status === 'unsubscribing') {\n await this.#remoteSynchronization.promise\n }\n\n if (!this.subscribed) return this\n\n if (this.#remoteSynchronization.status === 'subscribing') {\n await this.#remoteSynchronization.pending.promise\n return this\n }\n\n if (this.#remoteSynchronization.status === '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 (\n this.#remoteSynchronization.status === 'idle' ||\n this.#remoteSynchronization.status === 'remoteSubscriptionUncertain'\n ) {\n this.#setupSocketListeners()\n }\n\n const deferred = Promise.withResolvers<Channel<Contract>>()\n const synchronization: RemoteSynchronization<Contract> = {\n status: 'subscribing',\n pending: deferred,\n connected: true,\n }\n this.#remoteSynchronization = synchronization\n\n const timer = setTimeout(() => {\n if (this.#remoteSynchronization !== synchronization) return\n this.#remoteSynchronization = { status: 'waitingForReconnect' }\n this.#resetConnectionState()\n synchronization.pending.reject(new Error(`Subscribe timeout for channel: ${this.name}`))\n void this.#transport\n .sendRequest({ type: 'unsubscribe', channel: this.name }, timeout)\n .catch(() => {})\n }, timeout)\n\n this.#transport\n .sendRequest<SubscribeResult>({ type: 'subscribe', channel: this.name }, timeout)\n .then((response) => {\n if (this.#remoteSynchronization !== synchronization) return\n clearTimeout(timer)\n\n if (response.ok) {\n this.#remoteSynchronization = { status: 'active' }\n\n const presenceData = ClientPresenceSnapshot.fromTransport(\n response.data?.presenceData,\n this.name\n )\n\n // Apply the initial presence snapshot.\n if (presenceData) {\n this.#handleInitialPresence(presenceData)\n }\n\n synchronization.pending.resolve(this)\n } else {\n this.#remoteSynchronization = { status: 'waitingForReconnect' }\n this.#resetConnectionState()\n synchronization.pending.reject(new Error(response.error))\n }\n })\n .catch((error) => {\n if (this.#remoteSynchronization !== synchronization) return\n clearTimeout(timer)\n this.#remoteSynchronization = synchronization.connected\n ? { status: 'subscriptionUncertain' }\n : { status: 'waitingForReconnect' }\n this.#resetConnectionState()\n synchronization.pending.reject(\n error instanceof Error ? error : new Error('Subscribe failed')\n )\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.#remoteSynchronization.status === 'unsubscribing') {\n return this.#remoteSynchronization.promise\n }\n\n const previousSynchronization = this.#remoteSynchronization\n const hadPendingSubscribe = previousSynchronization.status === 'subscribing'\n if (previousSynchronization.status === 'subscribing') {\n previousSynchronization.pending.reject(new Error(`Unsubscribed from channel: ${this.name}`))\n }\n\n const remoteSubscriptionPossible =\n previousSynchronization.status === 'active' ||\n previousSynchronization.status === 'subscriptionUncertain' ||\n previousSynchronization.status === 'remoteSubscriptionUncertain'\n\n if (!hadPendingSubscribe && !remoteSubscriptionPossible) {\n this.#cleanupTerminal()\n return Promise.resolve()\n }\n\n const timeout = options.timeout ?? 5000\n const deferred = Promise.withResolvers<void>()\n const synchronization: RemoteSynchronization<Contract> = {\n status: 'unsubscribing',\n promise: deferred.promise,\n }\n this.#remoteSynchronization = synchronization\n let remoteMayRemain = true\n let terminalSynchronization: RemoteSynchronization<Contract> | null = null\n const timer = setTimeout(() => deferred.resolve(), timeout)\n\n this.#transport\n .sendRequest({ type: 'unsubscribe', channel: this.name }, timeout)\n .then(() => {\n remoteMayRemain = false\n clearTimeout(timer)\n deferred.resolve()\n if (this.#remoteSynchronization === terminalSynchronization) {\n this.#remoteSynchronization = { status: 'idle' }\n }\n })\n .catch(() => {\n clearTimeout(timer)\n deferred.resolve()\n })\n\n const pending = deferred.promise\n void pending.finally(() => {\n if (this.#remoteSynchronization !== synchronization) return\n terminalSynchronization = remoteMayRemain\n ? { status: 'remoteSubscriptionUncertain' }\n : { status: 'idle' }\n this.#remoteSynchronization = terminalSynchronization\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 = ClientPresenceSnapshot.fromTransport(data, this.name)\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 if (this.#remoteSynchronization.status === 'subscribing') {\n this.#remoteSynchronization.connected = false\n } else if (\n this.#remoteSynchronization.status === 'active' ||\n this.#remoteSynchronization.status === 'subscriptionUncertain'\n ) {\n this.#remoteSynchronization = { status: 'waitingForReconnect' }\n } else if (this.#remoteSynchronization.status === 'remoteSubscriptionUncertain') {\n this.#remoteSynchronization = { status: 'idle' }\n }\n this.#resetConnectionState()\n }\n this.#transport.on('disconnect', this.#boundDisconnectHandler)\n }\n\n /**\n * Handles the initial presence snapshot.\n */\n #handleInitialPresence(data: ClientPresenceSnapshot): void {\n this.#presence = data\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: ClientPresenceSnapshot): void {\n const { joining, leaving } = data.diff(this.#presence)\n\n // Commit the validated update before invoking user code.\n this.#presence = data\n\n // Detect new users.\n for (const user of joining) {\n if (this.#joiningHandler) {\n callClientHandler(this.#joiningHandler, user)\n }\n }\n\n // Detect users that left.\n for (const user of leaving) {\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.#presence = null\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\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.#remoteSynchronization = { status: 'idle' }\n this.#resetConnectionState()\n this.#detachTransportListeners()\n this.#clearCallbacks()\n }\n}\n","import type { ConnectionState, EventHandler } from './types.js'\nimport { SERVER_DISCONNECT_CODE, 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 ConnectDeferred extends PromiseWithResolvers<void> {}\n\ninterface SocketConnection {\n socket: WebSocket\n}\n\ntype ClientSocketLifecycle =\n | { kind: 'disconnected'; reconnectAttempt: number }\n | { kind: 'waiting'; timer: ReturnType<typeof setTimeout>; reconnectAttempt: number }\n | { kind: 'opening'; deferred: ConnectDeferred; reconnectAttempt: number }\n | {\n kind: 'connecting'\n connection: SocketConnection\n deferred: ConnectDeferred\n reconnectAttempt: number\n }\n | {\n kind: 'opened'\n connection: SocketConnection\n deferred: ConnectDeferred\n reconnectAttempt: number\n }\n | { kind: 'connected'; connection: SocketConnection }\n | { kind: 'failed'; connection: SocketConnection; reconnectAttempt: number }\n\ntype DisconnectedLifecycle = Extract<ClientSocketLifecycle, { kind: 'disconnected' }>\ntype WaitingLifecycle = Extract<ClientSocketLifecycle, { kind: 'waiting' }>\n\ninterface ClientSocketSessionOptions {\n buildUrl: () => string\n createWebSocket?: (url: string) => WebSocket\n autoReconnect?: boolean\n reconnectDelay?: number\n reconnectMaxDelay?: number\n shouldReconnect?: (event: CloseEvent) => boolean\n onConnected?: () => void\n}\n\nexport class ClientSocketSession {\n #lifecycle: ClientSocketLifecycle = { kind: 'disconnected', reconnectAttempt: 0 }\n #stateHandlers = new Set<Callable>()\n #eventHandlers = new Map<string, Set<Callable>>()\n #pendingRequests = new Map<string, PendingRequest>()\n #requestId = 0\n #buildUrl: () => string\n #createWebSocket: (url: string) => WebSocket\n #autoReconnect: boolean\n #reconnectDelay: number\n #reconnectMaxDelay: number\n #shouldReconnect: (event: CloseEvent) => boolean\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.#shouldReconnect =\n options.shouldReconnect ?? ((event) => event.code !== SERVER_DISCONNECT_CODE)\n this.#onConnected = options.onConnected\n }\n\n get state(): ConnectionState {\n switch (this.#lifecycle.kind) {\n case 'opening':\n case 'connecting':\n return 'connecting'\n case 'opened':\n case 'connected':\n return 'connected'\n case 'disconnected':\n case 'waiting':\n case 'failed':\n return 'disconnected'\n }\n }\n\n get connected(): boolean {\n return this.state === 'connected'\n }\n\n connect(): Promise<void> {\n if (this.#lifecycle.kind === 'connected') return Promise.resolve()\n if (this.#lifecycle.kind === 'opening' || this.#lifecycle.kind === 'connecting') {\n return this.#lifecycle.deferred.promise\n }\n if (this.#lifecycle.kind === 'opened') return this.#lifecycle.deferred.promise\n\n const reconnectAttempt = this.#reconnectAttempt\n const failedSocket =\n this.#lifecycle.kind === 'failed' ? this.#lifecycle.connection.socket : null\n if (this.#lifecycle.kind === 'waiting') clearTimeout(this.#lifecycle.timer)\n\n const connection = this.#startConnection(reconnectAttempt)\n failedSocket?.close()\n return connection\n }\n\n #startConnection(reconnectAttempt: number): Promise<void> {\n const deferred = Promise.withResolvers<void>()\n const opening: ClientSocketLifecycle = { kind: 'opening', deferred, reconnectAttempt }\n this.#setLifecycle(opening)\n if (this.#lifecycle !== opening) return deferred.promise\n\n let socket: WebSocket\n try {\n socket = this.#createWebSocket(this.#buildUrl())\n } catch (error) {\n this.#setLifecycle({ kind: 'disconnected', reconnectAttempt })\n deferred.reject(error)\n return deferred.promise\n }\n\n const connection = { socket }\n const connecting: ClientSocketLifecycle = {\n kind: 'connecting',\n connection,\n deferred,\n reconnectAttempt,\n }\n this.#lifecycle = connecting\n\n const cleanup = () => {\n socket.removeEventListener('open', handleOpen)\n socket.removeEventListener('error', handleError)\n }\n\n const handleOpen = () => {\n if (this.#lifecycle !== connecting) return\n\n cleanup()\n const opened: ClientSocketLifecycle = {\n kind: 'opened',\n connection,\n deferred,\n reconnectAttempt,\n }\n this.#setLifecycle(opened)\n if (!this.#isCurrent(opened)) return\n\n this.#lifecycle = { kind: 'connected', connection }\n this.#emitLocal('connect')\n if (this.#onConnected) this.#callHandler(this.#onConnected)\n deferred.resolve()\n }\n\n const handleError = () => {\n if (this.#lifecycle !== connecting) return\n\n cleanup()\n deferred.reject(new Error('WebSocket connection failed'))\n this.#setLifecycle({ kind: 'failed', connection, reconnectAttempt })\n }\n\n socket.addEventListener('open', handleOpen)\n socket.addEventListener('error', handleError)\n socket.addEventListener('message', (event) => {\n if (this.#owns(connection)) this.#handleIncoming(event.data)\n })\n socket.addEventListener('close', (event) => {\n cleanup()\n if (this.#owns(connection)) this.#handleClose(event)\n })\n\n return deferred.promise\n }\n\n disconnect(): void {\n const lifecycle = this.#lifecycle\n const shouldEmitDisconnect = this.state !== 'disconnected'\n if (lifecycle.kind === 'waiting') clearTimeout(lifecycle.timer)\n if (\n lifecycle.kind === 'opening' ||\n lifecycle.kind === 'connecting' ||\n lifecycle.kind === 'opened'\n ) {\n lifecycle.deferred.reject(new Error('Socket disconnected'))\n }\n\n this.#setLifecycle({ kind: 'disconnected', reconnectAttempt: 0 })\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n if ('connection' in lifecycle) lifecycle.connection.socket.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 socket = this.#connection?.socket\n if (socket?.readyState !== WebSocket.OPEN) {\n return\n }\n\n socket.send(JSON.stringify(message))\n }\n\n sendRequest(message: Record<string, unknown>, timeout = 5000): Promise<unknown> {\n const socket = this.#connection?.socket\n if (socket?.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 socket.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 ((message.ok === true && message.error === undefined) ||\n (message.ok === false && typeof message.error === 'string' && message.data === undefined))\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(event: CloseEvent): void {\n const lifecycle = this.#lifecycle\n const reconnectAttempt = 'reconnectAttempt' in lifecycle ? lifecycle.reconnectAttempt : 0\n const shouldEmitDisconnect = this.state !== 'disconnected'\n if (lifecycle.kind === 'connecting') {\n lifecycle.deferred.reject(new Error('WebSocket connection failed'))\n }\n\n const disconnected: DisconnectedLifecycle = { kind: 'disconnected', reconnectAttempt }\n this.#setLifecycle(disconnected)\n if (shouldEmitDisconnect) {\n this.#emitLocal('disconnect')\n }\n this.#rejectPending(new Error('Socket disconnected'))\n\n if (this.#shouldReconnect(event) && this.#lifecycle === disconnected) {\n this.#scheduleReconnect(disconnected)\n }\n }\n\n #scheduleReconnect(disconnected: DisconnectedLifecycle): void {\n if (!this.#autoReconnect || this.#lifecycle !== disconnected) return\n\n const delay = Math.min(\n this.#reconnectDelay * 2 ** disconnected.reconnectAttempt,\n this.#reconnectMaxDelay\n )\n const waiting: WaitingLifecycle = {\n kind: 'waiting',\n reconnectAttempt: disconnected.reconnectAttempt + 1,\n timer: setTimeout(() => {\n if (this.#lifecycle !== waiting) return\n\n this.#startConnection(waiting.reconnectAttempt).catch(() => {\n if (this.#lifecycle.kind === 'failed') {\n const failed = this.#lifecycle\n const disconnected: DisconnectedLifecycle = {\n kind: 'disconnected',\n reconnectAttempt: failed.reconnectAttempt,\n }\n this.#setLifecycle(disconnected)\n failed.connection.socket.close()\n if (this.#isCurrent(disconnected)) this.#scheduleReconnect(disconnected)\n return\n }\n\n if (this.#lifecycle.kind === 'disconnected') {\n this.#scheduleReconnect(this.#lifecycle)\n }\n })\n }, delay),\n }\n this.#setLifecycle(waiting)\n }\n\n get #connection(): SocketConnection | undefined {\n const lifecycle = this.#lifecycle\n return 'connection' in lifecycle ? lifecycle.connection : undefined\n }\n\n get #reconnectAttempt(): number {\n const lifecycle = this.#lifecycle\n return 'reconnectAttempt' in lifecycle ? lifecycle.reconnectAttempt : 0\n }\n\n #owns(connection: SocketConnection): boolean {\n return this.#connection === connection\n }\n\n #isCurrent(lifecycle: ClientSocketLifecycle): boolean {\n return this.#lifecycle === lifecycle\n }\n\n #setLifecycle(lifecycle: ClientSocketLifecycle): void {\n const previousState = this.state\n this.#lifecycle = lifecycle\n const state = this.state\n\n if (previousState !== state) {\n this.#stateHandlers.forEach((handler) => this.#callHandler(handler, state))\n }\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 #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 { callClientHandler } from './callback.js'\nimport { BindableChannelPattern } from '../bindable_channel_pattern.js'\nimport type {\n SocketOptions,\n ConnectionState,\n EventHandler,\n SocketClientTransport,\n ChannelContractFor,\n ChannelContract,\n ChannelCallArgs,\n} from './types.js'\n\nexport const resolveChannel = Symbol('resolveChannel')\n\n/**\n * Main Socket client.\n */\ntype IsUntypedRegistry<Registry> = unknown extends Registry\n ? true\n : [Registry] extends [undefined]\n ? true\n : false\n\ntype SocketChannelArgs<Registry> =\n IsUntypedRegistry<Registry> extends true ? [name: string] : ChannelCallArgs<Registry>\n\ntype ChannelResult<Registry, Pattern extends string> =\n IsUntypedRegistry<Registry> extends true\n ? Channel<ChannelContract>\n : Channel<ChannelContractFor<Registry, Pattern>>\n\ntype RuntimeChannelParameters = object\n\n/** Constructs a concrete channel name from a supported generated pattern. @internal */\nexport function buildChannelName(\n pattern: string,\n parameters: RuntimeChannelParameters = {}\n): string {\n const bindablePattern = BindableChannelPattern.parse(pattern)\n if (!bindablePattern) {\n throw new Error(`Unsupported generated channel pattern: ${pattern}`)\n }\n return bindablePattern.bind(parameters)\n}\n\nexport class Socket<Registry = undefined> implements SocketClientTransport {\n #channels = new Map<string, Channel<any>>()\n #url: string\n #path: string\n #session: ClientSocketSession\n #onResubscribeError: SocketOptions['onResubscribeError']\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.#onResubscribeError = options.onResubscribeError\n this.#session = new ClientSocketSession({\n buildUrl: () => this.#buildUrl(),\n autoReconnect: options.autoReconnect,\n reconnectDelay: options.reconnectDelay,\n reconnectMaxDelay: options.reconnectMaxDelay,\n shouldReconnect: options.shouldReconnect,\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 Args extends SocketChannelArgs<Registry>>(\n ...args: Args\n ): ChannelResult<Registry, Args[0]> {\n const [pattern, parameters] = args as [string, object?]\n const name = args.length > 1 ? buildChannelName(pattern, parameters) : pattern\n return this[resolveChannel](name) as ChannelResult<Registry, Args[0]>\n }\n\n /** Resolves a channel for framework adapters after their public type checks. @internal */\n [resolveChannel](name: string): Channel<any> {\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 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 url.hash = ''\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((error) => {\n if (this.#onResubscribeError) {\n callClientHandler(this.#onResubscribeError, {\n channel: channel.name,\n error: error instanceof Error ? error : new Error('Resubscribe failed'),\n })\n }\n })\n }\n }\n }\n}\n"],"mappings":"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","names":["disconnected"]}
@@ -2,7 +2,7 @@ import {
2
2
  buildChannelName,
3
3
  callClientHandler,
4
4
  resolveChannel
5
- } from "./chunk-DR6GWQUW.js";
5
+ } from "./chunk-3FY7EIZF.js";
6
6
 
7
7
  // src/client/framework.ts
8
8
  function createChannelCallArgs(pattern, parameters) {
@@ -149,4 +149,4 @@ export {
149
149
  acquireChannel,
150
150
  acquireSocketOwnership
151
151
  };
152
- //# sourceMappingURL=chunk-UE75J3JE.js.map
152
+ //# sourceMappingURL=chunk-OAI6SAER.js.map
@@ -1,3 +1,3 @@
1
1
  export { S as Socket } from '../../index-DCPtfkJL.js';
2
- export { ChannelBroadcastEvent, ChannelBroadcastPayload, ChannelCallArgs, ChannelClientEvent, ChannelClientEventPayload, ChannelParameters, ChannelPattern, ConnectionState, EventHandler, PresenceData, PresenceUser, SocketOptions, SubscribeAckData, SubscribeOptions, SubscribeResult, UnsubscribeOptions } from './types.js';
2
+ export { ChannelBroadcastEvent, ChannelBroadcastPayload, ChannelCallArgs, ChannelClientEvent, ChannelClientEventPayload, ChannelParameters, ChannelPattern, ConnectionState, EventHandler, PresenceData, PresenceUser, ResubscribeErrorContext, SocketOptions, SubscribeAckData, SubscribeOptions, SubscribeResult, UnsubscribeOptions } from './types.js';
3
3
  export { a as ChannelAck, b as ChannelMessage } from '../../shared_types-B11CaOr5.js';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Socket
3
- } from "../../chunk-DR6GWQUW.js";
3
+ } from "../../chunk-3FY7EIZF.js";
4
4
  import "../../chunk-YSW4MNFR.js";
5
5
  import "../../chunk-DM3UQMWW.js";
6
6
  import "../../chunk-E6ILCRL3.js";
@@ -3,10 +3,10 @@ import {
3
3
  acquireSocketOwnership,
4
4
  createChannelCallArgs,
5
5
  resolveChannelEventArgs
6
- } from "../../chunk-UE75J3JE.js";
6
+ } from "../../chunk-OAI6SAER.js";
7
7
  import {
8
8
  buildChannelName
9
- } from "../../chunk-DR6GWQUW.js";
9
+ } from "../../chunk-3FY7EIZF.js";
10
10
  import "../../chunk-YSW4MNFR.js";
11
11
  import "../../chunk-DM3UQMWW.js";
12
12
  import "../../chunk-E6ILCRL3.js";
@@ -53,6 +53,11 @@ type ChannelClientEventPayload<Registry, Pattern extends ChannelPattern<Registry
53
53
  type ChannelBroadcastEvent<Registry, Pattern extends ChannelPattern<Registry>> = Extract<keyof ServerEvents<ChannelContractFor<Registry, Pattern>>, string>;
54
54
  /** Payload received from a server broadcast on a generated channel. */
55
55
  type ChannelBroadcastPayload<Registry, Pattern extends ChannelPattern<Registry>, Event extends ChannelBroadcastEvent<Registry, Pattern>> = ServerEvents<ChannelContractFor<Registry, Pattern>>[Event];
56
+ /** Details about a rejected automatic channel resubscription. */
57
+ interface ResubscribeErrorContext {
58
+ channel: string;
59
+ error: Error;
60
+ }
56
61
  /**
57
62
  * Connection options.
58
63
  */
@@ -82,6 +87,10 @@ interface SocketOptions {
82
87
  * By default, deliberate server disconnects are terminal and other closes reconnect.
83
88
  */
84
89
  shouldReconnect?: (event: CloseEvent) => boolean;
90
+ /**
91
+ * Handles a rejected automatic channel resubscription.
92
+ */
93
+ onResubscribeError?: (context: ResubscribeErrorContext) => void;
85
94
  }
86
95
  /**
87
96
  * Channel subscription options.
@@ -147,4 +156,4 @@ interface SocketClientTransport {
147
156
  off<T = unknown>(event: string, handler: EventHandler<T>): void;
148
157
  }
149
158
 
150
- export { ChannelAck, type ChannelBroadcastEvent, type ChannelBroadcastPayload, type ChannelCallArgs, type ChannelClientEvent, type ChannelClientEventPayload, type ChannelContract, type ChannelContractFor, type ChannelParameterValue, type ChannelParameters, type ChannelPattern, ChannelServerEventsOf, type ConnectionState, type EventHandler, type PresenceData, type PresenceUser, type SocketClientTransport, type SocketOptions, type SubscribeAckData, type SubscribeOptions, type SubscribeResult, type UnsubscribeOptions };
159
+ export { ChannelAck, type ChannelBroadcastEvent, type ChannelBroadcastPayload, type ChannelCallArgs, type ChannelClientEvent, type ChannelClientEventPayload, type ChannelContract, type ChannelContractFor, type ChannelParameterValue, type ChannelParameters, type ChannelPattern, ChannelServerEventsOf, type ConnectionState, type EventHandler, type PresenceData, type PresenceUser, type ResubscribeErrorContext, type SocketClientTransport, type SocketOptions, type SubscribeAckData, type SubscribeOptions, type SubscribeResult, type UnsubscribeOptions };
@@ -3,10 +3,10 @@ import {
3
3
  acquireSocketOwnership,
4
4
  createChannelCallArgs,
5
5
  resolveChannelEventArgs
6
- } from "../../chunk-UE75J3JE.js";
6
+ } from "../../chunk-OAI6SAER.js";
7
7
  import {
8
8
  buildChannelName
9
- } from "../../chunk-DR6GWQUW.js";
9
+ } from "../../chunk-3FY7EIZF.js";
10
10
  import "../../chunk-YSW4MNFR.js";
11
11
  import "../../chunk-DM3UQMWW.js";
12
12
  import "../../chunk-E6ILCRL3.js";
package/build/src/otel.js CHANGED
@@ -20,7 +20,7 @@ import { InstrumentationBase } from "@opentelemetry/instrumentation";
20
20
  // package.json
21
21
  var package_default = {
22
22
  name: "@rlanz/socket",
23
- version: "0.1.0",
23
+ version: "0.1.1",
24
24
  description: "WebSocket integration for AdonisJS",
25
25
  type: "module",
26
26
  main: "./build/index.js",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/otel.ts","../../package.json"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Counter,\n type Span,\n type UpDownCounter,\n} from '@opentelemetry/api'\nimport type { TracingChannelSubscribers } from 'node:diagnostics_channel'\nimport { InstrumentationBase } from '@opentelemetry/instrumentation'\nimport type { InstrumentationConfig } from '@opentelemetry/instrumentation'\nimport packageJson from '../package.json' with { type: 'json' }\nimport {\n broadcastChannel,\n channelMessageChannel,\n connectChannel,\n disconnectChannel,\n subscribeChannel,\n setTracingOperationRunner,\n unsubscribeChannel,\n} from './tracing_channels.js'\nimport type {\n SocketBroadcastMessage,\n SocketChannelMessage,\n SocketConnectMessage,\n SocketDisconnectMessage,\n SocketSubscribeMessage,\n SocketUnsubscribeMessage,\n} from './types/tracing_channels.js'\n\nexport interface SocketInstrumentationConfig extends InstrumentationConfig {\n /**\n * The messaging system identifier.\n *\n * @default '@rlanz/socket'\n */\n messagingSystem?: string\n}\n\ntype AttributeValue = string | number | boolean\n\nexport class SocketInstrumentation extends InstrumentationBase<SocketInstrumentationConfig> {\n protected subscribed = false\n protected spans = new WeakMap<object, Span>()\n protected connectHandlers?: TracingChannelSubscribers<SocketConnectMessage>\n protected disconnectHandlers?: TracingChannelSubscribers<SocketDisconnectMessage>\n protected subscribeHandlers?: TracingChannelSubscribers<SocketSubscribeMessage>\n protected unsubscribeHandlers?: TracingChannelSubscribers<SocketUnsubscribeMessage>\n protected messageHandlers?: TracingChannelSubscribers<SocketChannelMessage>\n protected broadcastHandlers?: TracingChannelSubscribers<SocketBroadcastMessage>\n\n #connectionCounter!: Counter\n #disconnectionCounter!: Counter\n #activeConnections!: UpDownCounter\n #subscriptionCounter!: Counter\n #activeSubscriptions!: UpDownCounter\n #messageCounter!: Counter\n #broadcastCounter!: Counter\n #broadcastDeliveryCounter!: Counter\n\n constructor(config: SocketInstrumentationConfig = {}) {\n super('@rlanz/socket', packageJson.version, config)\n this._updateMetricInstruments()\n if (this.isEnabled()) this.enable()\n }\n\n get #messagingSystem(): string {\n return this.getConfig().messagingSystem ?? '@rlanz/socket'\n }\n\n protected init() {\n return undefined\n }\n\n protected _updateMetricInstruments() {\n if (this.subscribed === undefined) return\n\n this.#connectionCounter = this.meter.createCounter('rlanz_socket_connections_total', {\n description: 'Total number of accepted socket connections',\n })\n this.#disconnectionCounter = this.meter.createCounter('rlanz_socket_disconnections_total', {\n description: 'Total number of closed socket connections',\n })\n this.#activeConnections = this.meter.createUpDownCounter('rlanz_socket_connections_active', {\n description: 'Number of currently active socket connections',\n })\n this.#subscriptionCounter = this.meter.createCounter('rlanz_socket_subscriptions_total', {\n description: 'Total number of successful channel subscriptions',\n })\n this.#activeSubscriptions = this.meter.createUpDownCounter(\n 'rlanz_socket_subscriptions_active',\n { description: 'Number of currently active channel subscriptions' }\n )\n this.#messageCounter = this.meter.createCounter('rlanz_socket_messages_total', {\n description: 'Total number of channel messages received from clients',\n })\n this.#broadcastCounter = this.meter.createCounter('rlanz_socket_broadcasts_total', {\n description: 'Total number of broadcast operations',\n })\n this.#broadcastDeliveryCounter = this.meter.createCounter(\n 'rlanz_socket_broadcast_deliveries_total',\n { description: 'Total number of socket deliveries made by broadcast operations' }\n )\n }\n\n enable() {\n super.enable()\n // `InstrumentationBase` calls `enable()` from its constructor, before this\n // subclass's fields and private methods are installed on the instance.\n // During that premature call `this.subscribed` is still `undefined`, so the\n // guard prevents calling `#subscribe()` on a not-yet-branded instance.\n if (this.subscribed !== undefined) this.#subscribe()\n }\n\n disable() {\n if (this.subscribed !== undefined) this.#unsubscribe()\n super.disable()\n }\n\n manuallyRegister() {\n this.#subscribe()\n }\n\n #subscribe() {\n if (this.subscribed) return\n if (!this.isEnabled()) return\n\n this.subscribed = true\n\n this.connectHandlers = {\n start: (message) =>\n this.#startSpan(message, 'socket connect', SpanKind.SERVER, {\n 'network.transport': 'websocket',\n }),\n end: (message) => this.#handleConnectEnd(message),\n asyncStart: () => {},\n asyncEnd: () => {},\n error: (message) => this.#recordError(message),\n }\n\n this.disconnectHandlers = {\n start: (message) =>\n this.#startSpan(message, 'socket disconnect', SpanKind.INTERNAL, {\n 'socket.disconnect.reason': message.reason,\n 'socket.disconnect.subscriptions': message.subscriptions ?? 0,\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleDisconnectEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.subscribeHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket subscribe ${message.channel}`, SpanKind.SERVER, {\n 'messaging.destination.name': message.channel,\n 'messaging.operation.name': 'subscribe',\n 'messaging.operation.type': 'receive',\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleSubscribeEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.unsubscribeHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket unsubscribe ${message.channel}`, SpanKind.SERVER, {\n 'messaging.destination.name': message.channel,\n 'messaging.operation.name': 'unsubscribe',\n 'messaging.operation.type': 'receive',\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleUnsubscribeEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.messageHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket message ${message.channel}`, SpanKind.SERVER, {\n 'messaging.destination.name': message.channel,\n 'messaging.operation.name': 'process',\n 'messaging.operation.type': 'receive',\n 'messaging.event.name': message.event,\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleMessageEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.broadcastHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket broadcast ${message.target}`, SpanKind.PRODUCER, {\n ...this.#broadcastAttributes(message),\n }),\n end: (message) => this.#handleBroadcastEnd(message),\n asyncStart: () => {},\n asyncEnd: () => {},\n error: (message) => this.#recordError(message),\n }\n\n connectChannel.subscribe(this.connectHandlers)\n disconnectChannel.subscribe(this.disconnectHandlers)\n subscribeChannel.subscribe(this.subscribeHandlers)\n unsubscribeChannel.subscribe(this.unsubscribeHandlers)\n channelMessageChannel.subscribe(this.messageHandlers)\n broadcastChannel.subscribe(this.broadcastHandlers)\n }\n\n #unsubscribe() {\n if (!this.subscribed) return\n\n if (this.connectHandlers) connectChannel.unsubscribe(this.connectHandlers)\n if (this.disconnectHandlers) disconnectChannel.unsubscribe(this.disconnectHandlers)\n if (this.subscribeHandlers) subscribeChannel.unsubscribe(this.subscribeHandlers)\n if (this.unsubscribeHandlers) unsubscribeChannel.unsubscribe(this.unsubscribeHandlers)\n if (this.messageHandlers) channelMessageChannel.unsubscribe(this.messageHandlers)\n if (this.broadcastHandlers) broadcastChannel.unsubscribe(this.broadcastHandlers)\n\n this.subscribed = false\n this.spans = new WeakMap()\n }\n\n #startSpan(\n message: object,\n name: string,\n kind: SpanKind,\n attributes: Record<string, AttributeValue> = {}\n ) {\n const span = this.tracer.startSpan(name, {\n kind,\n attributes: {\n 'messaging.system': this.#messagingSystem,\n ...attributes,\n },\n })\n\n this.spans.set(message, span)\n const spanContext = trace.setSpan(context.active(), span)\n setTracingOperationRunner(message, (operation) => context.with(spanContext, operation))\n }\n\n #handleDisconnectEnd(message: SocketDisconnectMessage) {\n this.#disconnectionCounter.add(1, { 'socket.disconnect.reason': message.reason })\n this.#activeConnections.add(-1)\n if (message.subscriptions) {\n this.#activeSubscriptions.add(-message.subscriptions)\n }\n\n this.#endSpan(message)\n }\n\n #handleConnectEnd(message: SocketConnectMessage) {\n this.#connectionCounter.add(1)\n this.#activeConnections.add(1)\n this.#endSpan(message)\n }\n\n #handleSubscribeEnd(message: SocketSubscribeMessage) {\n const attributes = {\n 'messaging.destination.name': message.channel,\n 'socket.subscription.created': Boolean(message.created),\n }\n\n if (message.ok) {\n this.#subscriptionCounter.add(1, attributes)\n if (message.created) this.#activeSubscriptions.add(1, attributes)\n }\n\n this.#endSpanWithOutcome(message, attributes)\n }\n\n #handleUnsubscribeEnd(message: SocketUnsubscribeMessage) {\n const attributes = {\n 'messaging.destination.name': message.channel,\n 'socket.subscription.removed': Boolean(message.removed),\n }\n\n if (message.ok && message.removed) {\n this.#activeSubscriptions.add(-1, attributes)\n }\n\n this.#endSpanWithOutcome(message, attributes)\n }\n\n #handleMessageEnd(message: SocketChannelMessage) {\n const attributes = {\n 'messaging.destination.name': message.channel,\n 'messaging.event.name': message.event,\n }\n\n this.#messageCounter.add(1, {\n ...attributes,\n 'socket.message.ok': Boolean(message.ok),\n })\n\n this.#endSpanWithOutcome(message, attributes)\n }\n\n #handleBroadcastEnd(message: SocketBroadcastMessage) {\n const attributes = this.#broadcastAttributes(message)\n\n this.#broadcastCounter.add(1, attributes)\n if (message.delivered !== undefined) {\n this.#broadcastDeliveryCounter.add(message.delivered, attributes)\n }\n\n this.#endSpan(message, {\n ...attributes,\n ...(message.delivered !== undefined\n ? { 'socket.broadcast.delivered': message.delivered }\n : {}),\n })\n }\n\n #recordError(message: object & { error: unknown }) {\n const span = this.spans.get(message)\n if (!span) return\n\n if (message.error instanceof Error) {\n span.recordException(message.error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: message.error.message })\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR })\n }\n\n span.end()\n this.spans.delete(message)\n }\n\n #endSpanWithOutcome(\n message: SocketSubscribeMessage | SocketUnsubscribeMessage | SocketChannelMessage,\n attributes: Record<string, AttributeValue>\n ) {\n this.#endSpan(message, attributes, message)\n }\n\n #endSpan(\n message: object,\n attributes: Record<string, AttributeValue> = {},\n outcome?: { ok?: boolean; error?: string }\n ) {\n const span = this.spans.get(message)\n if (!span) return\n\n span.setAttributes(attributes)\n\n if (outcome?.ok === false) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: outcome.error })\n if (outcome.error) {\n span.setAttribute('error.type', outcome.error)\n }\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n span.end()\n this.spans.delete(message)\n }\n\n #broadcastAttributes(message: SocketBroadcastMessage): Record<string, AttributeValue> {\n const attributes: Record<string, AttributeValue> = {\n 'messaging.operation.name': 'publish',\n 'messaging.operation.type': 'send',\n 'messaging.event.name': message.event,\n 'socket.broadcast.target': message.target,\n 'socket.broadcast.via': message.via,\n }\n\n if (message.channel) attributes['messaging.destination.name'] = message.channel\n if (message.except) attributes['socket.broadcast.except_count'] = message.except.length\n\n return attributes\n }\n}\n","{\n \"name\": \"@rlanz/socket\",\n \"version\": \"0.1.0\",\n \"description\": \"WebSocket integration for AdonisJS\",\n \"type\": \"module\",\n \"main\": \"./build/index.js\",\n \"types\": \"./build/index.d.ts\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=24.0.0\"\n },\n \"packageManager\": \"yarn@4.18.0\",\n \"files\": [\n \"build\"\n ],\n \"exports\": {\n \".\": \"./build/index.js\",\n \"./provider\": \"./build/providers/socket_provider.js\",\n \"./assembler_hook\": \"./build/src/assembler_hook.js\",\n \"./services/main\": \"./build/services/socket.js\",\n \"./decorators\": \"./build/src/decorators.js\",\n \"./health_check\": \"./build/src/health_check.js\",\n \"./otel\": \"./build/src/otel.js\",\n \"./testing\": \"./build/src/testing.js\",\n \"./types\": \"./build/src/types.js\",\n \"./types/tracing_channels\": \"./build/src/types/tracing_channels.js\",\n \"./client\": \"./build/src/client/index.js\",\n \"./client/types\": \"./build/src/client/types.js\",\n \"./client/react\": \"./build/src/client/react.js\",\n \"./client/vue\": \"./build/src/client/vue.js\"\n },\n \"scripts\": {\n \"build\": \"npm run compile\",\n \"clean\": \"del-cli build\",\n \"compile\": \"npm run clean && tsup-node\",\n \"lint\": \"oxlint\",\n \"lint:fix\": \"oxlint --fix\",\n \"format\": \"oxfmt --check .\",\n \"format:fix\": \"oxfmt --write .\",\n \"prepublishOnly\": \"npm run build\",\n \"release\": \"release-it\",\n \"test\": \"node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"version\": \"npm run build\"\n },\n \"dependencies\": {\n \"@boringnode/bus\": \"^0.9.1\",\n \"@lukeed/ms\": \"^2.0.2\",\n \"emittery\": \"^1.2.0\",\n \"ws\": \"^8.21.0\"\n },\n \"devDependencies\": {\n \"@adonisjs/assembler\": \"^8.0.0\",\n \"@adonisjs/core\": \"^7.0.1\",\n \"@adonisjs/tsconfig\": \"^2.0.0\",\n \"@japa/assert\": \"^4.2.0\",\n \"@japa/runner\": \"^5.3.0\",\n \"@opentelemetry/api\": \"^1.9.1\",\n \"@opentelemetry/context-async-hooks\": \"^2.7.1\",\n \"@opentelemetry/core\": \"^2.7.1\",\n \"@opentelemetry/instrumentation\": \"^0.218.0\",\n \"@opentelemetry/sdk-metrics\": \"^2.7.1\",\n \"@opentelemetry/sdk-trace-base\": \"^2.7.1\",\n \"@poppinss/ts-exec\": \"^1.4.4\",\n \"@release-it/conventional-changelog\": \"^12.0.0\",\n \"@types/node\": \"^24.0.0\",\n \"@types/react\": \"^19.1.9\",\n \"@types/react-test-renderer\": \"^19.1.0\",\n \"@types/scheduler\": \"^0\",\n \"@types/ws\": \"^8.18.1\",\n \"del-cli\": \"^7.0.0\",\n \"oxfmt\": \"^0.38.0\",\n \"oxlint\": \"^1.53.0\",\n \"react\": \"^19.1.1\",\n \"react-test-renderer\": \"^19.1.1\",\n \"reflect-metadata\": \"^0.2.2\",\n \"release-it\": \"^19.2.4\",\n \"scheduler\": \"^0.27.0\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.9.3\",\n \"vue\": \"^3.5.18\"\n },\n \"peerDependencies\": {\n \"@adonisjs/assembler\": \"^8.0.0\",\n \"@adonisjs/core\": \"^7.0.1\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/instrumentation\": \"^0.200.0\",\n \"react\": \"^18.0.0 || ^19.0.0\",\n \"typescript\": \"^5.9.0 || ^6.0.0\",\n \"vue\": \"^3.3.0\"\n },\n \"peerDependenciesMeta\": {\n \"@adonisjs/assembler\": {\n \"optional\": true\n },\n \"@opentelemetry/api\": {\n \"optional\": true\n },\n \"@opentelemetry/instrumentation\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n },\n \"typescript\": {\n \"optional\": true\n },\n \"vue\": {\n \"optional\": true\n }\n },\n \"keywords\": [\n \"adonisjs\",\n \"adonis\",\n \"websocket\",\n \"realtime\"\n ],\n \"homepage\": \"https://github.com/rlanz/socket#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/RomainLanz/socket\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/rlanz/socket/issues\"\n },\n \"author\": \"Romain Lanz <romain.lanz@pm.me>\",\n \"publishConfig\": {\n \"access\": \"public\",\n \"tag\": \"latest\",\n \"provenance\": true\n },\n \"release-it\": {\n \"git\": {\n \"requireCleanWorkingDir\": true,\n \"requireUpstream\": true,\n \"commitMessage\": \"chore(release): ${version}\",\n \"tagAnnotation\": \"v${version}\",\n \"push\": true,\n \"tagName\": \"v${version}\"\n },\n \"github\": {\n \"release\": true,\n \"releaseName\": \"v${version}\"\n },\n \"npm\": {\n \"publish\": true,\n \"skipChecks\": true\n },\n \"plugins\": {\n \"@release-it/conventional-changelog\": {\n \"preset\": {\n \"name\": \"angular\"\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/otel.ts","../../package.json"],"sourcesContent":["import {\n context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Counter,\n type Span,\n type UpDownCounter,\n} from '@opentelemetry/api'\nimport type { TracingChannelSubscribers } from 'node:diagnostics_channel'\nimport { InstrumentationBase } from '@opentelemetry/instrumentation'\nimport type { InstrumentationConfig } from '@opentelemetry/instrumentation'\nimport packageJson from '../package.json' with { type: 'json' }\nimport {\n broadcastChannel,\n channelMessageChannel,\n connectChannel,\n disconnectChannel,\n subscribeChannel,\n setTracingOperationRunner,\n unsubscribeChannel,\n} from './tracing_channels.js'\nimport type {\n SocketBroadcastMessage,\n SocketChannelMessage,\n SocketConnectMessage,\n SocketDisconnectMessage,\n SocketSubscribeMessage,\n SocketUnsubscribeMessage,\n} from './types/tracing_channels.js'\n\nexport interface SocketInstrumentationConfig extends InstrumentationConfig {\n /**\n * The messaging system identifier.\n *\n * @default '@rlanz/socket'\n */\n messagingSystem?: string\n}\n\ntype AttributeValue = string | number | boolean\n\nexport class SocketInstrumentation extends InstrumentationBase<SocketInstrumentationConfig> {\n protected subscribed = false\n protected spans = new WeakMap<object, Span>()\n protected connectHandlers?: TracingChannelSubscribers<SocketConnectMessage>\n protected disconnectHandlers?: TracingChannelSubscribers<SocketDisconnectMessage>\n protected subscribeHandlers?: TracingChannelSubscribers<SocketSubscribeMessage>\n protected unsubscribeHandlers?: TracingChannelSubscribers<SocketUnsubscribeMessage>\n protected messageHandlers?: TracingChannelSubscribers<SocketChannelMessage>\n protected broadcastHandlers?: TracingChannelSubscribers<SocketBroadcastMessage>\n\n #connectionCounter!: Counter\n #disconnectionCounter!: Counter\n #activeConnections!: UpDownCounter\n #subscriptionCounter!: Counter\n #activeSubscriptions!: UpDownCounter\n #messageCounter!: Counter\n #broadcastCounter!: Counter\n #broadcastDeliveryCounter!: Counter\n\n constructor(config: SocketInstrumentationConfig = {}) {\n super('@rlanz/socket', packageJson.version, config)\n this._updateMetricInstruments()\n if (this.isEnabled()) this.enable()\n }\n\n get #messagingSystem(): string {\n return this.getConfig().messagingSystem ?? '@rlanz/socket'\n }\n\n protected init() {\n return undefined\n }\n\n protected _updateMetricInstruments() {\n if (this.subscribed === undefined) return\n\n this.#connectionCounter = this.meter.createCounter('rlanz_socket_connections_total', {\n description: 'Total number of accepted socket connections',\n })\n this.#disconnectionCounter = this.meter.createCounter('rlanz_socket_disconnections_total', {\n description: 'Total number of closed socket connections',\n })\n this.#activeConnections = this.meter.createUpDownCounter('rlanz_socket_connections_active', {\n description: 'Number of currently active socket connections',\n })\n this.#subscriptionCounter = this.meter.createCounter('rlanz_socket_subscriptions_total', {\n description: 'Total number of successful channel subscriptions',\n })\n this.#activeSubscriptions = this.meter.createUpDownCounter(\n 'rlanz_socket_subscriptions_active',\n { description: 'Number of currently active channel subscriptions' }\n )\n this.#messageCounter = this.meter.createCounter('rlanz_socket_messages_total', {\n description: 'Total number of channel messages received from clients',\n })\n this.#broadcastCounter = this.meter.createCounter('rlanz_socket_broadcasts_total', {\n description: 'Total number of broadcast operations',\n })\n this.#broadcastDeliveryCounter = this.meter.createCounter(\n 'rlanz_socket_broadcast_deliveries_total',\n { description: 'Total number of socket deliveries made by broadcast operations' }\n )\n }\n\n enable() {\n super.enable()\n // `InstrumentationBase` calls `enable()` from its constructor, before this\n // subclass's fields and private methods are installed on the instance.\n // During that premature call `this.subscribed` is still `undefined`, so the\n // guard prevents calling `#subscribe()` on a not-yet-branded instance.\n if (this.subscribed !== undefined) this.#subscribe()\n }\n\n disable() {\n if (this.subscribed !== undefined) this.#unsubscribe()\n super.disable()\n }\n\n manuallyRegister() {\n this.#subscribe()\n }\n\n #subscribe() {\n if (this.subscribed) return\n if (!this.isEnabled()) return\n\n this.subscribed = true\n\n this.connectHandlers = {\n start: (message) =>\n this.#startSpan(message, 'socket connect', SpanKind.SERVER, {\n 'network.transport': 'websocket',\n }),\n end: (message) => this.#handleConnectEnd(message),\n asyncStart: () => {},\n asyncEnd: () => {},\n error: (message) => this.#recordError(message),\n }\n\n this.disconnectHandlers = {\n start: (message) =>\n this.#startSpan(message, 'socket disconnect', SpanKind.INTERNAL, {\n 'socket.disconnect.reason': message.reason,\n 'socket.disconnect.subscriptions': message.subscriptions ?? 0,\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleDisconnectEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.subscribeHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket subscribe ${message.channel}`, SpanKind.SERVER, {\n 'messaging.destination.name': message.channel,\n 'messaging.operation.name': 'subscribe',\n 'messaging.operation.type': 'receive',\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleSubscribeEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.unsubscribeHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket unsubscribe ${message.channel}`, SpanKind.SERVER, {\n 'messaging.destination.name': message.channel,\n 'messaging.operation.name': 'unsubscribe',\n 'messaging.operation.type': 'receive',\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleUnsubscribeEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.messageHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket message ${message.channel}`, SpanKind.SERVER, {\n 'messaging.destination.name': message.channel,\n 'messaging.operation.name': 'process',\n 'messaging.operation.type': 'receive',\n 'messaging.event.name': message.event,\n }),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (message) => this.#handleMessageEnd(message),\n error: (message) => this.#recordError(message),\n }\n\n this.broadcastHandlers = {\n start: (message) =>\n this.#startSpan(message, `socket broadcast ${message.target}`, SpanKind.PRODUCER, {\n ...this.#broadcastAttributes(message),\n }),\n end: (message) => this.#handleBroadcastEnd(message),\n asyncStart: () => {},\n asyncEnd: () => {},\n error: (message) => this.#recordError(message),\n }\n\n connectChannel.subscribe(this.connectHandlers)\n disconnectChannel.subscribe(this.disconnectHandlers)\n subscribeChannel.subscribe(this.subscribeHandlers)\n unsubscribeChannel.subscribe(this.unsubscribeHandlers)\n channelMessageChannel.subscribe(this.messageHandlers)\n broadcastChannel.subscribe(this.broadcastHandlers)\n }\n\n #unsubscribe() {\n if (!this.subscribed) return\n\n if (this.connectHandlers) connectChannel.unsubscribe(this.connectHandlers)\n if (this.disconnectHandlers) disconnectChannel.unsubscribe(this.disconnectHandlers)\n if (this.subscribeHandlers) subscribeChannel.unsubscribe(this.subscribeHandlers)\n if (this.unsubscribeHandlers) unsubscribeChannel.unsubscribe(this.unsubscribeHandlers)\n if (this.messageHandlers) channelMessageChannel.unsubscribe(this.messageHandlers)\n if (this.broadcastHandlers) broadcastChannel.unsubscribe(this.broadcastHandlers)\n\n this.subscribed = false\n this.spans = new WeakMap()\n }\n\n #startSpan(\n message: object,\n name: string,\n kind: SpanKind,\n attributes: Record<string, AttributeValue> = {}\n ) {\n const span = this.tracer.startSpan(name, {\n kind,\n attributes: {\n 'messaging.system': this.#messagingSystem,\n ...attributes,\n },\n })\n\n this.spans.set(message, span)\n const spanContext = trace.setSpan(context.active(), span)\n setTracingOperationRunner(message, (operation) => context.with(spanContext, operation))\n }\n\n #handleDisconnectEnd(message: SocketDisconnectMessage) {\n this.#disconnectionCounter.add(1, { 'socket.disconnect.reason': message.reason })\n this.#activeConnections.add(-1)\n if (message.subscriptions) {\n this.#activeSubscriptions.add(-message.subscriptions)\n }\n\n this.#endSpan(message)\n }\n\n #handleConnectEnd(message: SocketConnectMessage) {\n this.#connectionCounter.add(1)\n this.#activeConnections.add(1)\n this.#endSpan(message)\n }\n\n #handleSubscribeEnd(message: SocketSubscribeMessage) {\n const attributes = {\n 'messaging.destination.name': message.channel,\n 'socket.subscription.created': Boolean(message.created),\n }\n\n if (message.ok) {\n this.#subscriptionCounter.add(1, attributes)\n if (message.created) this.#activeSubscriptions.add(1, attributes)\n }\n\n this.#endSpanWithOutcome(message, attributes)\n }\n\n #handleUnsubscribeEnd(message: SocketUnsubscribeMessage) {\n const attributes = {\n 'messaging.destination.name': message.channel,\n 'socket.subscription.removed': Boolean(message.removed),\n }\n\n if (message.ok && message.removed) {\n this.#activeSubscriptions.add(-1, attributes)\n }\n\n this.#endSpanWithOutcome(message, attributes)\n }\n\n #handleMessageEnd(message: SocketChannelMessage) {\n const attributes = {\n 'messaging.destination.name': message.channel,\n 'messaging.event.name': message.event,\n }\n\n this.#messageCounter.add(1, {\n ...attributes,\n 'socket.message.ok': Boolean(message.ok),\n })\n\n this.#endSpanWithOutcome(message, attributes)\n }\n\n #handleBroadcastEnd(message: SocketBroadcastMessage) {\n const attributes = this.#broadcastAttributes(message)\n\n this.#broadcastCounter.add(1, attributes)\n if (message.delivered !== undefined) {\n this.#broadcastDeliveryCounter.add(message.delivered, attributes)\n }\n\n this.#endSpan(message, {\n ...attributes,\n ...(message.delivered !== undefined\n ? { 'socket.broadcast.delivered': message.delivered }\n : {}),\n })\n }\n\n #recordError(message: object & { error: unknown }) {\n const span = this.spans.get(message)\n if (!span) return\n\n if (message.error instanceof Error) {\n span.recordException(message.error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: message.error.message })\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR })\n }\n\n span.end()\n this.spans.delete(message)\n }\n\n #endSpanWithOutcome(\n message: SocketSubscribeMessage | SocketUnsubscribeMessage | SocketChannelMessage,\n attributes: Record<string, AttributeValue>\n ) {\n this.#endSpan(message, attributes, message)\n }\n\n #endSpan(\n message: object,\n attributes: Record<string, AttributeValue> = {},\n outcome?: { ok?: boolean; error?: string }\n ) {\n const span = this.spans.get(message)\n if (!span) return\n\n span.setAttributes(attributes)\n\n if (outcome?.ok === false) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: outcome.error })\n if (outcome.error) {\n span.setAttribute('error.type', outcome.error)\n }\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n span.end()\n this.spans.delete(message)\n }\n\n #broadcastAttributes(message: SocketBroadcastMessage): Record<string, AttributeValue> {\n const attributes: Record<string, AttributeValue> = {\n 'messaging.operation.name': 'publish',\n 'messaging.operation.type': 'send',\n 'messaging.event.name': message.event,\n 'socket.broadcast.target': message.target,\n 'socket.broadcast.via': message.via,\n }\n\n if (message.channel) attributes['messaging.destination.name'] = message.channel\n if (message.except) attributes['socket.broadcast.except_count'] = message.except.length\n\n return attributes\n }\n}\n","{\n \"name\": \"@rlanz/socket\",\n \"version\": \"0.1.1\",\n \"description\": \"WebSocket integration for AdonisJS\",\n \"type\": \"module\",\n \"main\": \"./build/index.js\",\n \"types\": \"./build/index.d.ts\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=24.0.0\"\n },\n \"packageManager\": \"yarn@4.18.0\",\n \"files\": [\n \"build\"\n ],\n \"exports\": {\n \".\": \"./build/index.js\",\n \"./provider\": \"./build/providers/socket_provider.js\",\n \"./assembler_hook\": \"./build/src/assembler_hook.js\",\n \"./services/main\": \"./build/services/socket.js\",\n \"./decorators\": \"./build/src/decorators.js\",\n \"./health_check\": \"./build/src/health_check.js\",\n \"./otel\": \"./build/src/otel.js\",\n \"./testing\": \"./build/src/testing.js\",\n \"./types\": \"./build/src/types.js\",\n \"./types/tracing_channels\": \"./build/src/types/tracing_channels.js\",\n \"./client\": \"./build/src/client/index.js\",\n \"./client/types\": \"./build/src/client/types.js\",\n \"./client/react\": \"./build/src/client/react.js\",\n \"./client/vue\": \"./build/src/client/vue.js\"\n },\n \"scripts\": {\n \"build\": \"npm run compile\",\n \"clean\": \"del-cli build\",\n \"compile\": \"npm run clean && tsup-node\",\n \"lint\": \"oxlint\",\n \"lint:fix\": \"oxlint --fix\",\n \"format\": \"oxfmt --check .\",\n \"format:fix\": \"oxfmt --write .\",\n \"prepublishOnly\": \"npm run build\",\n \"release\": \"release-it\",\n \"test\": \"node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"version\": \"npm run build\"\n },\n \"dependencies\": {\n \"@boringnode/bus\": \"^0.9.1\",\n \"@lukeed/ms\": \"^2.0.2\",\n \"emittery\": \"^1.2.0\",\n \"ws\": \"^8.21.0\"\n },\n \"devDependencies\": {\n \"@adonisjs/assembler\": \"^8.0.0\",\n \"@adonisjs/core\": \"^7.0.1\",\n \"@adonisjs/tsconfig\": \"^2.0.0\",\n \"@japa/assert\": \"^4.2.0\",\n \"@japa/runner\": \"^5.3.0\",\n \"@opentelemetry/api\": \"^1.9.1\",\n \"@opentelemetry/context-async-hooks\": \"^2.7.1\",\n \"@opentelemetry/core\": \"^2.7.1\",\n \"@opentelemetry/instrumentation\": \"^0.218.0\",\n \"@opentelemetry/sdk-metrics\": \"^2.7.1\",\n \"@opentelemetry/sdk-trace-base\": \"^2.7.1\",\n \"@poppinss/ts-exec\": \"^1.4.4\",\n \"@release-it/conventional-changelog\": \"^12.0.0\",\n \"@types/node\": \"^24.0.0\",\n \"@types/react\": \"^19.1.9\",\n \"@types/react-test-renderer\": \"^19.1.0\",\n \"@types/scheduler\": \"^0\",\n \"@types/ws\": \"^8.18.1\",\n \"del-cli\": \"^7.0.0\",\n \"oxfmt\": \"^0.38.0\",\n \"oxlint\": \"^1.53.0\",\n \"react\": \"^19.1.1\",\n \"react-test-renderer\": \"^19.1.1\",\n \"reflect-metadata\": \"^0.2.2\",\n \"release-it\": \"^19.2.4\",\n \"scheduler\": \"^0.27.0\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.9.3\",\n \"vue\": \"^3.5.18\"\n },\n \"peerDependencies\": {\n \"@adonisjs/assembler\": \"^8.0.0\",\n \"@adonisjs/core\": \"^7.0.1\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/instrumentation\": \"^0.200.0\",\n \"react\": \"^18.0.0 || ^19.0.0\",\n \"typescript\": \"^5.9.0 || ^6.0.0\",\n \"vue\": \"^3.3.0\"\n },\n \"peerDependenciesMeta\": {\n \"@adonisjs/assembler\": {\n \"optional\": true\n },\n \"@opentelemetry/api\": {\n \"optional\": true\n },\n \"@opentelemetry/instrumentation\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n },\n \"typescript\": {\n \"optional\": true\n },\n \"vue\": {\n \"optional\": true\n }\n },\n \"keywords\": [\n \"adonisjs\",\n \"adonis\",\n \"websocket\",\n \"realtime\"\n ],\n \"homepage\": \"https://github.com/rlanz/socket#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/RomainLanz/socket\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/rlanz/socket/issues\"\n },\n \"author\": \"Romain Lanz <romain.lanz@pm.me>\",\n \"publishConfig\": {\n \"access\": \"public\",\n \"tag\": \"latest\",\n \"provenance\": true\n },\n \"release-it\": {\n \"git\": {\n \"requireCleanWorkingDir\": true,\n \"requireUpstream\": true,\n \"commitMessage\": \"chore(release): ${version}\",\n \"tagAnnotation\": \"v${version}\",\n \"push\": true,\n \"tagName\": \"v${version}\"\n },\n \"github\": {\n \"release\": true,\n \"releaseName\": \"v${version}\"\n },\n \"npm\": {\n \"publish\": true,\n \"skipChecks\": true\n },\n \"plugins\": {\n \"@release-it/conventional-changelog\": {\n \"preset\": {\n \"name\": \"angular\"\n }\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rlanz/socket",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "WebSocket integration for AdonisJS",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",