import type { AnyEvent } from "@uptimizr/schema"; /** * In-process live event bus + presence tracker (ADR 0032 §1, §2, §3a, §6). * * The collector is a single process (DuckDB single-writer, ADR 0020), so every * ingested event passes through one place. The ingest route publishes each * enriched, validated event here; live consumers (SSE endpoints, ADR §3) read * from it. This is the OSS fan-out source — a multi-instance scale tier * supplies its own shared-bus implementation behind the same interface * (ADR 0004/0020) without touching `oss/**`. * * Nothing here is persisted: presence is a rolling in-memory view and the * per-session backfill ring is bounded. Privacy: the roster exposed to clients * is non-identifying (no geo/UA/visitorId — ADR §3a); `visitorId` is used only * internally to count distinct active visitors. */ /** Coarse, non-identifying recency bucket for a live session (ADR §3a). */ export type ActivityLevel = "active" | "recent" | "idle"; /** A single non-identifying roster entry surfaced to clients (ADR §3a). */ export interface PresenceRosterItem { sessionId: string; sceneId: string; /** Server receive time of the session's first seen event (epoch ms). */ startedAt: number; /** Server receive time of the session's most recent event (epoch ms). */ lastSeen: number; /** Coarse recency bucket derived from `lastSeen`. */ activity: ActivityLevel; } /** Aggregate live snapshot for a project (ADR §3). */ export interface PresenceSnapshot { /** Distinct live sessions within the window. */ activeSessions: number; /** Distinct live visitors within the window. */ activeVisitors: number; /** Non-identifying roster, most-recently-active first. */ sessions: PresenceRosterItem[]; } /** Options for a live subscription (used by the SSE endpoints — ADR §3). */ export interface LiveSubscribeOptions { projectId: string; /** Restrict to one session (live-follow tail); omit for the project firehose. */ sessionId?: string; /** Optional event-type allow-list. */ types?: ReadonlySet; /** Per-subscriber bounded queue size; overrides the bus default. */ queueLimit?: number; } /** * A bounded, drop-oldest async stream of events (ADR §6). A slow consumer loses * its oldest buffered events (counted in {@link dropped}); it never back-pressures * ingest or grows memory without bound. */ export interface LiveSubscriber extends AsyncIterable { /** Close the subscription and release it from the bus. Idempotent. */ close(): void; /** Count of events dropped due to a full queue. */ readonly dropped: number; } export interface LiveBus { /** Publish enriched, validated events (called from the ingest route). */ publish(events: readonly AnyEvent[]): void; /** Current aggregate + roster snapshot for a project (ADR §3). */ presence(projectId: string): PresenceSnapshot; /** Recent buffered events for one session, oldest first (connect-time backfill). */ recentForSession(projectId: string, sessionId: string): AnyEvent[]; /** Open a bounded live subscription (ADR §6). */ subscribe(options: LiveSubscribeOptions): LiveSubscriber; /** Number of open subscriptions (for connection caps — ADR §6). */ readonly subscriberCount: number; /** Release timers/subscribers. */ stop(): void; } export interface CreateLiveBusOptions { /** Liveness window in ms (ADR §1, default 30_000). Must be ≥ SDK flush cadence. */ windowMs?: number; /** Per-session backfill ring size (ADR §3, default 200). */ backfillRingSize?: number; /** Default per-subscriber queue size (ADR §6, default 1_000). */ subscriberQueueLimit?: number; /** Clock injection for tests; defaults to `Date.now`. */ now?: () => number; } /** Create the default in-process live bus (ADR 0032 §2). */ export declare function createLiveBus(options?: CreateLiveBusOptions): LiveBus; //# sourceMappingURL=liveBus.d.ts.map