Rindle

API index and search · Build metadata

Supporting declarations

packages/normalized/src/backend.ts. These declarations explain referenced types. Only package-page symbols are package exports.

Exact source

NormalizedBackend

export declare class NormalizedBackend<S extends ColsMap> implements Backend {
    private readonly local;
    private readonly sync;
    private readonly source;
    private handler;
    /** The Store's commit-boundary handler ({@link Backend.onCommitBoundary}), forwarded from the
     *  local engine's `dispatch` brackets so the Store folds every affected view before notifying any
     *  subscriber (cross-view-atomic notification). A normalized batch becomes net base mutations
     *  applied to the local engine in one commit, which fans to every view reading those rows — this
     *  carries that commit's boundary up so all those views notify together. */
    private boundaryHandler;
    private readonly devObservers;
    private readonly remoteSubs;
    private readonly localToRemote;
    private readonly remoteRetainToLocal;
    private readonly sourceToRemote;
    private readonly resultTypes;
    private readonly hydrated;
    /** Local qids that are JUST hydrating on the in-flight `onNormalized` snapshot — set only for the
     *  duration of its `local.mutate`, so the local-event forwarder stamps their fold `catchUp`: the
     *  whole first result set arrives as a `batch` (we hydrate the view by mutating the embedded engine,
     *  which speaks in batches — there is no second `snapshot`), and `catchUp` is the flag that tells the
     *  Store this batch IS hydration (retire the SSR seed, phase it as a snapshot for narration). The
     *  optimistic backend does the identical thing across its reconcile cycle. `null` outside a hydrate. */
    private catchUpQids;
    private resultTypeHandler;
    /** The client's OWN typed per-table schemas (for CRIT#4 validation), fixed at construction. */
    private readonly clientTables;
    /** Synthetic aggregate tables (`__agg_*`) registered so far, by name (§3.3). Per aggregate
     *  DEFINITION (not per query), so two queries over the same count share one table. */
    private readonly synthetic;
    /** table → (column name → base ColId), for mapping a projected hello to base positions. */
    private readonly colIndex;
    /** table → full column count, to detect whether a hello's table is projected. */
    private readonly colCounts;
    /** Synthetic table name → how many registered queries reference it. Materialized on `0→1`,
     *  reclaimed (engine source + refcount layer) on `1→0` — so aggregate state is not permanent (§4). */
    private readonly syntheticRefs;
    /** queryId → the synthetic tables it referenced at registration, to decrement on teardown. */
    private readonly queryAggTables;
    constructor(schema: Schema<S>, source: NormalizedSource);
    registerQuery(qid: QueryId, ast: Ast, remote?: RemoteQuery): void;
    /** Register every synthetic aggregate table `ast` needs that we haven't seen yet: on the
     *  local engine (so it can join to it), on `NormalizedSync` (so its rows refcount/GC by
     *  group key), and into the source's expected-schema set (so the server's `hello` — which
     *  advertises the same table — passes CRIT#4 validation, the client deriving the schema
     *  identically). Idempotent across queries that share an aggregate definition. */
    private ensureSyntheticTables;
    /** Decrement each synthetic table query `qid` referenced; remove the ones that reach 0 (no
     *  reader left) from the engine + refcount layer — aggregate state reclaimed, not permanent
     *  (§4). Runs AFTER `local.unregisterQuery(qid)` so the source has no live connection when
     *  `unregisterTable` frees it. */
    private releaseSyntheticTables;
    unregisterQuery(qid: QueryId): void;
    retainRemoteQuery(qid: QueryId, remote: RemoteQuery, localQueryId?: QueryId, ast?: Ast): void;
    releaseRemoteQuery(qid: QueryId): void;
    /** Writes are authoritative-only here: send to the server, the stream reconciles locally.
     *  (Optimistic local apply + rebase is Slice 6.) */
    mutate(mutations: Mutation[]): Promise<void>;
    onEvent(handler: (qid: QueryId, ev: ChangeEvent) => void): void;
    onCommitBoundary(handler: (phase: "begin" | "end") => void): void;
    onResultType(handler: (qid: QueryId, rt: ResultType) => void): void;
    __attachDevtoolsServerDeltas(observer: BackendDevObserver): () => void;
    private onNormalized;
    private emitServerDelta;
    private localQidsForSource;
    private retainRemote;
    private releaseRemote;
    private markSubHydrated;
    private hasRemoteDependency;
    private setResultType;
    private recomputeResultType;
}

createNormalizedStore

/** A local-first {@link Store} whose base tables are fed by a server's normalized stream.
 *  The returned Store is the ordinary `@rindle/client` Store — `store.query…materialize()` and
 *  `store.write(…)` work as always; only the backend composition differs. */
export declare function createNormalizedStore<S extends ColsMap>(schema: Schema<S>, source: NormalizedSource): Store<S>;