/** * The recording session behind the {@link TimelineSink}: ring buffers, event * id stamping, the rising-edge clear, the `sinceMs`/`limit` window and the * inspector caches. Plain state and pure queries -- no devframe, no Vite, no * streams -- so the window semantics can be unit-tested without booting * anything. Private to `followed-page.ts`, which decides when to clear, forget * and accept; nothing else drives it. * * @see plans/devframe-foundation.md */ import type { InspectorDetails, InspectorMessage, InspectorTreeNode } from '../../types/inspector.js'; import type { HmrIncompatibilityEvent } from '../../types/hmr-incompatibility.js'; import type { HmrPatchEvent } from '../../types/hmr-patch.js'; import type { TimelineEvent, TimelineLayer } from '../../types/timeline.js'; import type { SessionSnapshot } from '../../types/snapshot.js'; import type { HmrHistoryEntry, LitRuntimeInfo, RangeSummaryArgs, RangeSummaryResult, RecentEventsArgs, RecentEventsResult, UpdateSummaryArgs, UpdateSummaryResult } from './protocol.js'; export interface RecordingSessionOptions { /** Boot from a recorded session: caches start populated, ids are kept. */ replay?: SessionSnapshot; /** Whether recording is already on, so a first `setRecording(true)` is not an edge. */ recording?: boolean; /** Id epoch (the session start). Defaults to `Date.now()` in base 36. */ epoch?: string; } export interface RecordingSession { /** * Stamp `${epoch}-${seq}` on events that lack an id (a replayed or * already-identified event keeps its own), buffer them and return the * stamped copies for the caller to stream. */ push(events: readonly TimelineEvent[]): TimelineEvent[]; /** Forget the buffered events (a new page, or a new recording clock). */ clear(): void; /** * Report the recording flag. Turning it on (a rising edge) clears the * buffer, because the runtime re-zeroes its clock on that edge. */ setRecording(recording: boolean): void; /** A copy of the buffered events, oldest first. */ history(): TimelineEvent[]; /** The `recent-events` query. */ query(args: RecentEventsArgs, recording: boolean): RecentEventsResult; /** The `update-summary` query. */ summarize(args: UpdateSummaryArgs, recording: boolean): UpdateSummaryResult; /** The `range-summary` query. Throws on a window with no width. */ summarizeRange(args: RangeSummaryArgs, recording: boolean): RangeSummaryResult; /** Remember an HMR-incompatibility notice, capped. */ pushHmrIncompatibility(event: HmrIncompatibilityEvent): void; hmrIncompatibilities(): HmrIncompatibilityEvent[]; /** * Remember a successful HMR patch, capped. Fills `file` from the cached * component tree when the page did not send one. */ pushHmrPatch(event: HmrPatchEvent): void; hmrPatches(): HmrPatchEvent[]; /** Patches and incompatibilities as one list, oldest first. */ hmrHistory(): HmrHistoryEntry[]; /** Fold a runtime inspector message into the caches. */ applyInspector(message: InspectorMessage): void; /** * Forget what the previous page reported once another takes over: the * cached tree and details, and its HMR patches and failures. */ forgetPage(): void; roots(): InspectorTreeNode[]; details(id: number): InspectorDetails | null; /** The page runtime's last `ready` announcement; `ready: false` before it. */ runtime(): LitRuntimeInfo; /** * The page whose traffic the session accepts. `undefined` until a runtime * announces itself with an id; a runtime without one (older plugin * version) leaves it undefined and is never filtered. */ activePageId(): string | undefined; /** The tab the followed page runs in, when its runtime reported one. */ activeTabId(): string | undefined; /** * Fold a runtime `ready`. Returns what happened so the caller can clear, * replay and notify: `'same'` (a reconnect of the active page -- keep the * buffer), `'first'` (no page was active), `'switched'` (a different page * took over) or `'legacy'` (no id -- behave as before). */ pageReady(pageId: string | undefined, tabId?: string): 'same' | 'first' | 'switched' | 'legacy'; /** Whether a message stamped `pageId` belongs to the active page. */ accepts(pageId: string | undefined): boolean; /** Everything a frozen panel needs, as of now. */ capture(meta: { capturedAt: string; version: string; customLayers: readonly TimelineLayer[]; }): SessionSnapshot; } /** Drop the oldest entries so `items` holds at most `max`. */ export declare const capTail: (items: T[], max: number) => void; /** * Events from the last `sinceMs`, measured against the newest event of the * whole `buffer` rather than of `events`: an element that last rendered 10s * ago must come back empty for `sinceMs: 1000`, not report its own stale * events as recent. `sinceMs` is a duration on the page's recording clock, * which has no relation to this process's wall clock. */ export declare const sinceWindow: (events: T[], buffer: readonly TimelineEvent[], sinceMs: number | undefined) => T[]; export declare function createRecordingSession(options?: RecordingSessionOptions): RecordingSession; //# sourceMappingURL=session.d.ts.map