UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

98 lines (97 loc) 4.99 kB
import { Collection } from './collection/index.js'; import { ChangeMessage, CollectionStatus } from './types.js'; /** * The canonical, adapter-agnostic view of a live query at a point in time. * * `getSnapshot()` returns a stable object identity that only changes when the * query changes, so `useSyncExternalStore`-style consumers can compare by * reference. Each snapshot owns a captured view of `state`/`data`, so reading * an older snapshot cannot expose rows from a later revision. */ export interface LiveQuerySnapshot<T extends object, TKey extends string | number> { /** Keyed results, or `undefined` for a disabled query. */ state: ReadonlyMap<TKey, T> | undefined; /** Ordered results (single row for `findOne`), or `undefined` when disabled. */ data: T | ReadonlyArray<T> | undefined; /** The underlying collection, or `undefined` when disabled. */ collection: Collection<T, TKey, any> | undefined; /** * Monotonic counter bumped whenever the visible layout (the ordered key * sequence) changes — membership, ordering, or an order-only move. Lets * consumers detect a reorder that changed no row value (which `data`/`state` * identity alone can't express once row values are structurally shared). * * It is NOT in lockstep with snapshot identity: a value-only update produces a * new snapshot while `layoutRevision` stays put. A `layoutRevision` change * always accompanies a new snapshot, but not vice versa. */ layoutRevision: number; status: CollectionStatus | `disabled`; isLoading: boolean; isReady: boolean; isIdle: boolean; isError: boolean; isCleanedUp: boolean; isEnabled: boolean; } /** * Listener payload: changes, `[]` for an internal layout-only publication, or * `undefined` for a synthetic status/ready notification. */ export type LiveQueryObserverListener<T extends object, TKey extends string | number> = (changes: Array<ChangeMessage<T, TKey>> | undefined) => void; /** * Wraps a resolved live-query `Collection` (or `null` for a disabled query) with * the shared lifecycle every framework adapter needs: start sync on first * subscribe, subscribe to changes and status transitions, expose a stable * snapshot for wholesale consumers, and deliver the raw change set for * granular consumers. * * Input resolution (query fn / config / collection / disabled) stays in the * adapter — it is framework-reactive. The observer owns everything after the * input is resolved to a concrete collection. * * @internal Unstable contract for TanStack DB's official framework adapters — * not a public extension point yet; may change in any release. */ export interface LiveQueryObserver<T extends object, TKey extends string | number> { /** Stable per-revision snapshot for wholesale materialization. */ getSnapshot: () => LiveQuerySnapshot<T, TKey>; /** * Subscribe to changes. The listener receives the change set (or `undefined` * for the synthetic notify a ready collection emits on attach). Granular * adapters apply the changes; wholesale adapters can ignore them and re-read * `getSnapshot()`. Returns an unsubscribe function. */ subscribe: (listener: LiveQueryObserverListener<T, TKey>) => () => void; /** Resolve once the collection has loaded its first data. */ preload: () => Promise<void>; /** Idempotent teardown. */ dispose: () => void; } export interface CreateLiveQueryObserverOptions { /** * How subscribers consume the observer: * * - `granular` (default): subscribers apply the delivered `ChangeMessage[]` * deltas to their own keyed state (Vue/Svelte/Solid). The observer * subscribes with initial state and seeds late subscribers, so every * subscriber converges from deltas alone. * - `wholesale`: subscribers treat notifications as a wake-up and re-read * `getSnapshot()` (React/Angular). The observer subscribes WITHOUT initial * state, preserving those adapters' loading policy — no snapshot request, * so no unfiltered `loadSubset` against on-demand collections. Nothing is * delivered synchronously during `subscribe`, which keeps * `useSyncExternalStore`-style consumers safe by construction. */ mode?: `granular` | `wholesale`; } /** * Create a {@link LiveQueryObserver} for a resolved live-query collection, or a * disabled observer when `collection` is `null`/`undefined`. * * @internal This is an unstable contract shared by TanStack DB's official * framework adapters. It is exported so the adapter packages can use it, but * it is not a public extension point yet: its API may change in any release * without a semver major. */ export declare function createLiveQueryObserver<T extends object, TKey extends string | number>(collection: Collection<T, TKey, any> | null | undefined, options?: CreateLiveQueryObserverOptions): LiveQueryObserver<T, TKey>;