import './utils/disposable'; import { MessageBus } from './MessageBus'; import type { FrameKind, FramePayload, Logger } from './types'; /** * Tracks this tab's channel and topic subscriptions and replays them onto a * freshly connected leader socket. * * Two roles: * - **Bookkeeping** — a refcount of channel subscriptions (so N `channel()` * handles for the same name share one server-side join) and the set of * subscribed topics. `channelNames()` feeds the incoming-event prefix * routing in SharedWebSocket. * - **Replay** — on leader handover/reconnect, gather the *union* of * channels/topics across every surviving tab and re-send the join / * topic-subscribe frames, so a promoted follower doesn't silently drop * subscriptions any tab still cares about. It also answers other tabs' * gather requests. * * Extracted from SharedWebSocket so this bookkeeping + cross-tab replay is one * cohesive unit. Auth-specific subscription sets (auto-leave on deauth) stay in * SharedWebSocket — this registry holds the full set used for routing/replay. */ export declare class SubscriptionRegistry implements Disposable { private readonly bus; /** Writes a frame to the live socket — supplied by the owner (FramePipeline). */ private readonly transmit; private readonly log; /** Refcount of active channel subscriptions per name. */ private readonly channelRefs; /** All topic subscriptions (auth and non-auth). */ private readonly topics; private cleanups; constructor(bus: MessageBus, /** Writes a frame to the live socket — supplied by the owner (FramePipeline). */ transmit: (kind: FrameKind, payload: FramePayload) => void, log: Logger); /** Track a channel subscription (refcounted across multiple handles). */ addChannel(name: string): void; /** Drop one channel reference; forgets the channel at zero. */ removeChannel(name: string): void; addTopic(topic: string): void; removeTopic(topic: string): void; /** Channel names currently held by this tab (for incoming-event routing). */ channelNames(): IterableIterator; /** * Re-establish subscriptions on a freshly connected leader socket: gather the * union of channels/topics across all surviving tabs, then transmit a join / * topic-subscribe for each. `isValid` aborts if the socket was replaced while * we were gathering. */ replay(isValid?: () => boolean): Promise; /** * Best-effort cross-tab gather. Broadcasts a request and collects responses * for a short window. Times out gracefully — late responses are dropped. Own * subs are seeded so we don't rely on BroadcastChannel echo to self. */ private gather; [Symbol.dispose](): void; }