/** * One-shot read state, render-safe and timer-free. * * WHY a tiny external store instead of `useState` + `useEffect`: a read effect * never runs under server rendering (`renderToStaticMarkup`), so a seat mounted * in a test stayed in its "waiting" arm forever and the transport states were * untestable. This reader starts the read on first use (a microtask, never * during render), notifies subscribers when the answer lands, and does nothing * else: no interval, no visibility gate, no re-read unless the identity changes * or `reload()` is called. * * @module @mstar-harness/dsh/client/panel/once-reader */ import type { MstarPanelSnapshotClient } from './panel-snapshot-client.ts'; /** The three states of one requested read, plus the closed answer kinds. */ export type OnceState = { readonly kind: 'waiting'; } | { readonly kind: 'loading'; } | T; /** A render-safe one-shot read over one identity. */ export declare class OnceReader { private state; private key; private readonly listeners; /** * The read for the CURRENT identity. It is a field, not a constructor * capture: a reader cached for a seat must always read with that render's * props (`cwd`, `view`, `id`), never with the props of the render that * created it — the first render often has none (`waiting`), and a captured * closure would fire `readView({ cwd: '', view: '' })` forever. */ private read; /** Current snapshot (stable reference until an answer lands). */ readonly getSnapshot: () => OnceState; /** Subscribe to answers; stable identity for `useSyncExternalStore`. */ readonly subscribe: (listener: () => void) => (() => void); /** * Start the read for `key` unless it is already the current identity. * * Safe in a render body: the first call for a key only writes the `loading` * arm (no listener exists yet) and schedules the request as a microtask. * @param key - the identity string; a new key is a new read. * @param client - the transport face, or undefined when none is injected. */ begin(key: string | null, client: MstarPanelSnapshotClient | undefined, read: (client: MstarPanelSnapshotClient) => Promise): void; /** Read the current identity again (an explicit retry, a pick). */ reload(): void; private write; } /** * The reader for one identity, created on first use. * @param client - the transport face the read goes through (the cache key owner). * @param key - the identity string. * @param make - the reader's read function. * @returns the shared reader instance. */ export declare function cachedReader(client: object | undefined, key: string | null, make: () => OnceReader): OnceReader; /** * Subscribe one component to a one-shot reader. * @param reader - the per-identity reader instance. * @param key - the identity (null asks for nothing). * @param client - the transport face. * @returns the state and the reload function. */ export declare function useOnceReader(reader: OnceReader, key: string | null, client: MstarPanelSnapshotClient | undefined, read: (face: MstarPanelSnapshotClient) => Promise): { readonly state: OnceState; readonly reload: () => void; };