import { BufferSubscriptionEntry, DebugFeature } from "../debug-protocol.js"; //#region src/debug/SubscriberRegistry.d.ts /** * Resolved buffer subscription the producer can drain against. Keyed by * entry name; the value is the (mode, thumbSize) pair the consumers * collectively asked for after union. */ type BuffersSubscription = Map; /** * Server-side registry of active consumers and the feature subsets they * care about. * * Replaces the earlier `Heartbeat` (producer-driven ping/pong) with an * ack-driven model: * * 1. Consumer sends `subscribe { id, features }`; server calls * `onSubscribe(id, features)` → inserts/updates consumer state, * sets `lastAckAt = now` (so the consumer survives the first * grace window without having to have acked yet). * 2. Each `ack { id }` from a consumer refreshes `lastAckAt`. * 3. Each render tick (or any producer work-cycle), the server calls * `pruneStale()`; consumers whose `lastAckAt` is older than * `ACK_GRACE_MS` are removed. * 4. Producers ask `isActive(feature)` to decide whether to produce; * active iff any remaining consumer's feature set contains it. * * Self-healing: re-subscribe with the same id is how a stalled * consumer recovers — the subscribe path IS the reconnect path. */ declare class SubscriberRegistry { private _consumers; /** * Cached union-of-features across all consumers. Invalidated * (set to `null`) whenever any consumer's feature set changes or a * consumer is added/removed. Lazy-rebuilt by `isActive()` / `active()`. */ private _activeCache; /** * Cached union of registry filters. `undefined` = not yet computed; * `null` = at least one consumer wants everything; `Set` = the * narrow union (only these names are drained). */ private _registrySelectionCache; private _buffersSelectionCache; /** * Insert or update a consumer's subscription. Same id + different * features = feature-set modification. Same id + same features = no-op * (still refreshes `lastAckAt` — counts as implicit ack). */ onSubscribe(id: string, features: readonly DebugFeature[], registry?: readonly string[], buffers?: Record): void; /** Refresh a consumer's `lastAckAt`. No-op for unknown ids. */ onAck(id: string): void; /** Remove a consumer explicitly. */ onUnsubscribe(id: string): void; /** * Drop consumers whose `lastAckAt` is older than `ACK_GRACE_MS`. * Safe to call every tick — cheap when nothing's stale. */ pruneStale(): void; /** * Union of every consumer's registry selection. * - `null` → at least one consumer wants every entry (no-filter drain). * - `Set` → only these names are needed; provider drains only them. * - empty set → no consumer wants any entries; provider skips drain. */ registrySelection(): Set | null; /** * Union of every consumer's buffer subscription map. * - Entry present with `mode: 'stream'` in ANY consumer → stream wins. * - Else if any consumer asks for `mode: 'thumbnail'` → thumbnail, * using the MAX `thumbSize` requested by any consumer. * - Entry absent from all consumers → not in the union (metadata-only). * * An empty map means no consumer is watching any entry: the producer * can skip readback entirely. */ buffersSelection(): BuffersSubscription; /** Is any consumer subscribed to this feature right now? */ isActive(feature: DebugFeature): boolean; /** The full set of features at least one consumer is subscribed to. */ active(): ReadonlySet; /** Number of registered consumers (post-prune). */ size(): number; /** Look up a consumer's feature set. Used by subscribe:ack to echo back. */ featuresFor(id: string): readonly DebugFeature[] | null; /** Clear all state. Used on dispose. */ dispose(): void; private _active; } //#endregion export { BuffersSubscription, SubscriberRegistry }; //# sourceMappingURL=SubscriberRegistry.d.ts.map