/** * The item half of the SS4 client fold: upsert-by-revision plus delta * accumulation (spec 14990 FR-007, INV-003/INV-004). * * WHY THIS IS GENERIC. The concrete wire item type (`Item`, `ItemDeltaParams`, * …) is rendered by `crates/protocol` and is not yet in the committed * declarations — the session-view plane is enrolled by #14953. INV-001 * forbids hand-writing a protocol type to fill the gap, so this module states * only the *algebraic precondition* its rules need — an item has an identity * and a revision — and takes the payload as a type parameter. When #14953 * lands, `SessionFold` binds `T` to `@muse-code/msp`'s `Item` with no change here * and no protocol shape ever restated locally. */ /** The minimum an upsert needs: identity plus the monotonic ordering guard. */ export interface RevisionedItem { readonly itemId: string; readonly revision: number; } /** What an apply did — enough for a consumer to render without re-diffing. */ export type ItemApplyOutcome = { readonly kind: "inserted"; readonly itemId: string; } | { readonly kind: "replaced"; readonly itemId: string; readonly from: number; readonly to: number; } /** A stale or replayed re-emission. The store did not change (INV-003). */ | { readonly kind: "ignoredStaleRevision"; readonly itemId: string; readonly held: number; readonly offered: number; }; /** What a delta did. Deltas bump no revision (tdd SS4.4.1). */ export type DeltaApplyOutcome = { readonly kind: "appended"; readonly itemId: string; readonly field: string; readonly length: number; } /** * A delta for an item the store does not hold. Deltas are a streaming * optimization and are never a fold's only source of a fact (tdd SS4.7.3), * so this is buffered against the item's arrival rather than dropped or * treated as an error. */ | { readonly kind: "bufferedForAbsentItem"; readonly itemId: string; readonly field: string; }; /** Client-only annotation required when an ephemeral host dies abnormally. */ export interface TerminalUnknownItemAnnotation { readonly kind: "terminalUnknown"; readonly itemId: string; } /** * Items in first-opened order (the order tdd SS4.9.1 requires of a snapshot), * each held at its latest revision, with per-field delta accumulators. */ export declare class ItemStore { #private; /** * Apply an `item/started` | `item/updated` | `item/completed` payload. * Replace iff the incoming revision is strictly higher (INV-003). */ apply(item: T): ItemApplyOutcome; /** * Apply an `item/delta`: a UTF-8-safe append to the open item's field named * by `field` (default `"text"`), contiguous and lossless in cursor order. * The concatenation of all deltas for a field path equals that field's * value on the final `item/completed` object (INV-004, tdd SS4.3.1). */ applyDelta(itemId: string, delta: string, field?: string): DeltaApplyOutcome; /** The accumulated delta text for a field path, or `undefined` if none. */ accumulated(itemId: string, field?: string): string | undefined; /** Every field path that has accumulated deltas for this item. */ accumulatedFields(itemId: string): readonly string[]; get(itemId: string): T | undefined; has(itemId: string): boolean; /** Items in first-opened order (tdd SS4.9.1). */ list(): readonly T[]; /** The id of the most recently opened item, or `undefined` when empty. */ lastOpenedItemId(): string | undefined; get size(): number; /** * Seed from a snapshot's `state.items` (tdd SS4.9.1): every item at its * latest revision at the snapshot cursor, in first-opened order. Seeding * REPLACES the store — a snapshot is authoritative (tdd SS4.9), never * merged into stale local state. * * Delta accumulators are intentionally NOT seeded: a snapshot carries * streamed fields at their accumulated-so-far values on the item itself, * and `view/page` never replays ephemeral-sourced deltas (tdd SS4.7.3). */ seed(items: Iterable): void; /** * Permanently discard an ephemeral session after abnormal host death. * * The last wire item remains byte-for-byte intact: terminal-unknown is a * client display annotation, never a fabricated `item/completed` or wire * status (SS2.13.3b / SS4.4.3). Further events and snapshot seeding are * refused because this session has no resume surface. */ markEphemeralHostDeath(isInProgress: (item: T) => boolean): readonly TerminalUnknownItemAnnotation[]; isTerminalUnknown(itemId: string): boolean; get ephemeralSessionDiscarded(): boolean; }