import type { CockpitStreamEvent } from '../watch/stream-event.js'; export interface EventBusEntry { cursor: number; event: CockpitStreamEvent; emittedAt: number; } export interface WaitForInput { sinceCursor: number; maxWaitMs: number; coalesceWindowMs: number; maxBatchSize: number; /** Optional clock injection for tests. */ now?: () => number; } export interface WaitForResult { entries: EventBusEntry[]; resetFrom?: 'expired'; } export type CursorParseResult = { kind: 'valid'; position: number; } | { kind: 'expired'; requestedPosition: number; } | { kind: 'discarded'; reason: 'legacy' | 'cross-instance' | 'evicted'; } | { kind: 'malformed'; } | { kind: 'never-issued'; } | { kind: 'wrong-epic'; requestedEpic: string; boundEpic: string; }; export interface EpicEventBusOptions { epic: string; retentionCount?: number; retentionMs?: number; now?: () => number; /** Test seam: override the per-bus nonce. Defaults to a fresh random. */ nonce?: string; } /** * Per-process nonce generated once at module load. Embedded in every cursor * token so cross-instance cursors (server restart) classify as `discarded` * rather than `never-issued`. */ export declare const INSTANCE_NONCE: string; /** * Shared default horizon (ms) for BOTH the in-memory buffer retention window * AND the registry's idle-TTL for refcount-0 buses. Any change here changes * both call sites in lockstep — FR-003. */ export declare const DEFAULT_QUIET_HORIZON_MS = 7200000; export declare function encodeCursor(epic: string, position: number, pnonce: string, bnonce: string): string; export declare function decodeCursor(str: string): { epic: string; position: number; pnonce?: string; bnonce?: string; } | null; export declare class EpicEventBus { readonly epic: string; readonly busNonce: string; private buffer; private nextCursor; private waiters; private readonly retentionCount; private readonly retentionMs; private readonly clock; constructor(options: EpicEventBusOptions); emit(event: CockpitStreamEvent): EventBusEntry; parseCursor(str: string | undefined): CursorParseResult; /** * Drain entries with cursor > sinceCursor immediately (up to maxBatchSize); * if empty, wait up to maxWaitMs for the first emit, then coalesce for * coalesceWindowMs (or until maxBatchSize is reached). */ waitFor(input: WaitForInput): Promise; private waitForFirstEmit; private flushWaiters; private trim; /** Test-only inspector. */ size(): number; } //# sourceMappingURL=event-bus.d.ts.map