state
js/ui/web/state.ts
fino:ui/web/state — view-snapshot codecs over a generic atomic store.
Applications pass the same AtomicStore used by other subsystems. These
functions own only the UI record layout: one current head per viewId,
retained history, JSON validation, optimistic saves, and expiry sweeps. The
store provider owns memory, persistence, serialization, and lifecycle.
Snapshot values are cloned at this domain boundary, so request-local
mutation cannot leak through providers such as memoryStore() that retain
values by reference. saveViewState() can require the current snapshot
version and throws ViewVersionConflictError on mismatch.
import { sqliteStore } from 'fino:store';
import { loadViewState, saveViewState } from 'fino:ui/web/state';
const store = await sqliteStore({ path: './ui.db' });
await saveViewState(store, {
viewId: 'todos-1', view: 'todos', version: 0,
data: { items: [] }, regions: {}, applied: [],
createdAt: Date.now(), updatedAt: Date.now(), expiresAt: Date.now() + 60_000,
});
const head = await loadViewState(store, 'todos-1');Interfaces
interface ViewSnapshot {
Durable state for one mounted view instance.
Properties
viewId: string
Random or keyed view instance id embedded in forms and live channels.
view: string
Stable view definition id.
version: number
Monotonic application-level version and SSE event id.
sessionId?: string
Optional owning browser session id.
data: Record<string, unknown>
JSON-serializable server-owned signal values.
regions: Record<string, string>
Last-rendered HTML hashes keyed by region element id.
applied: Array<{ rid: string; action: string }>
Recent action nonces used to avoid double-submit replays.
createdAt: number
Creation time in Unix milliseconds.
updatedAt: number
Last update time in Unix milliseconds.
expiresAt: number
Expiration time in Unix milliseconds.
Classes
class ViewVersionConflictError extends Error {
Error raised when a guarded snapshot save observes another version.
Constructors
constructor(viewId: string, expected: number, actual: number | null)
Create a conflict describing expected and observed application versions.
Functions
async function loadViewState(
store: AtomicStore,
viewId: string,
): Promise<ViewSnapshot | null>
Load a detached view head, or null when it is absent.
async function saveViewState(
store: AtomicStore,
snapshot: ViewSnapshot,
options: { expectVersion?: number } = {},
): Promise<void>
Atomically replace a view head and append the same snapshot to history.
async function viewStateHistory(
store: AtomicStore,
viewId: string,
options: { limit?: number } = {},
): Promise<ViewSnapshot[]>
Return retained snapshots newest first, optionally limited.
async function deleteViewState(store: AtomicStore, viewId: string): Promise<void>
Delete a view head and all retained history.
async function sweepViewState(
store: AtomicStore,
now: number = Date.now(),
): Promise<number>
Delete expired view heads and return the number removed.