import type { RailSession as Session } from "./session-list-entry.js"; /** Archive order is personal filing time, never activity or running status. */ export declare function compareSessionArchiveOrder(a: Session, b: Session): number; export type SessionPageIdentity = { key: string; generation: number; }; export type SessionContinuationState = { generation: number; sessions: Session[]; nextCursor: string | null | undefined; failed: boolean; /** Page-one read revision whose snapshot produced the retained cursor chain. */ snapshotRevision: number; /** Shared causal generation captured when that snapshot's page-one read started. */ snapshotGeneration: number; /** Root-hook snapshots and direct cursor-rebase snapshots have independent identities. */ source: "root" | "rebase" | "group"; /** Rows fetched from that snapshot, excluding display-only rows retained from older snapshots. */ authoritativeIds: ReadonlySet; /** Actual request-start generation for each accepted continuation row's live channel fields. */ channelGenerations: ReadonlyMap; }; export type SessionContinuationChannelEvidence = readonly [ session: Session, readGeneration: number ]; /** * Apply the exact archive mutation fields without allowing its full response * object to overwrite unrelated list projections that may have advanced while * the request was in flight. */ export declare function applySessionArchiveProjection(current: T, updated: Session): T; /** Keep archive/restore writes authoritative over causally older retained pages. */ export declare function projectSessionArchiveMembership(sessions: readonly Session[], overrides: ReadonlyMap, archived: boolean | "all", workspaceId: string, options?: { flat?: boolean | undefined; /** Local receipt completion fences, on the same clock as list request starts. */ completedGenerations?: ReadonlyMap | undefined; rowReadGenerations?: ReadonlyMap | undefined; }): Session[]; export declare function sessionPageKey(workspaceId: string, search: string): string; /** * Advance the request generation whenever the workspace/query changes. The * integer matters in addition to the key: a delayed request for A must still be * rejected after the user visits A → B → A while it is in flight. */ export declare function advanceSessionPageIdentity(current: SessionPageIdentity, key: string): SessionPageIdentity; export declare function emptySessionContinuation(generation: number): SessionContinuationState; export declare function activeSessionContinuation(state: SessionContinuationState, activeGeneration: number): SessionContinuationState; /** Merge a continuation only when it belongs to the still-active query. */ export declare function mergeSessionContinuation(state: SessionContinuationState, activeGeneration: number, requestGeneration: number, page: { sessions: Session[]; nextCursor: string | null; }, snapshotRevision: number, snapshotGeneration?: number, source?: "root" | "rebase" | "group", pageReadGeneration?: number): SessionContinuationState; /** Current continuation rows that may own channel filing, with each page's actual read start. */ export declare function authoritativeSessionContinuationChannels(state: SessionContinuationState, activeGeneration: number, currentReadRevision: number, currentReadGeneration?: number): SessionContinuationChannelEvidence[]; /** Current continuation rows that may still own mutable list projections. */ export declare function authoritativeSessionContinuation(state: SessionContinuationState, activeGeneration: number, currentReadRevision: number, currentReadGeneration?: number): Session[]; /** * Persist a causally fresh detail channel onto a display-only retained row. * Current-snapshot list evidence remains authoritative and is never rewritten. */ export declare function reconcileRetainedSessionContinuationChannel(state: SessionContinuationState, activeGeneration: number, currentReadRevision: number, projected: Pick | null, currentReadGeneration?: number): SessionContinuationState; /** * Rebase retained rows onto a fresh first-page snapshot after the server says * the previous cursor expired. Fresh rows replace retained duplicates and own * the new snapshot while older off-page rows remain display-only. Delayed * rebases are fenced like ordinary page merges so an A → B → A query * transition cannot revive an obsolete cursor. */ export declare function rebaseSessionContinuation(state: SessionContinuationState, activeGeneration: number, requestGeneration: number, page: { sessions: Session[]; nextCursor: string | null; }, snapshotRevision: number, snapshotGeneration?: number, source?: "root" | "rebase" | "group"): SessionContinuationState;