@tanstack/db
Version:
A reactive client store for building super fast apps on sync
1 lines • 43 kB
Source Map (JSON)
{"version":3,"file":"live-query-observer.cjs","sources":["../../src/live-query-observer.ts"],"sourcesContent":["import { LiveQueryObserverDisposedError } from './errors.js'\nimport { runAllCallbacks } from './utils/callbacks.js'\nimport {\n getLiveQueryStatusFlags,\n getPublicCollection,\n isFailedStatus,\n isSingleResultCollection,\n} from './live-query-primitives.js'\nimport { describeProblem } from './collection/lifecycle.js'\nimport type { Collection } from './collection/index.js'\nimport type { LiveQueryObserverClient } from './live-query-observer-client.js'\nimport type { DbClient, DehydratedLiveQueryResult } from './client.js'\nimport type { ChangeMessage, CollectionStatus, HealthNode } from './types.js'\n\n/**\n * The canonical, adapter-agnostic view of a live query at a point in time.\n *\n * `getSnapshot()` returns a stable object identity that only changes when the\n * query changes, so `useSyncExternalStore`-style consumers can compare by\n * reference. Each snapshot owns a captured view of `state`/`data`, so reading\n * an older snapshot cannot expose rows from a later revision.\n */\nexport interface LiveQuerySnapshot<\n T extends object,\n TKey extends string | number,\n> {\n /** Keyed results, or `undefined` for a disabled query. */\n state: ReadonlyMap<TKey, T> | undefined\n /** Ordered results (single row for `findOne`), or `undefined` when disabled. */\n data: T | ReadonlyArray<T> | undefined\n /** The underlying collection, or `undefined` when disabled. */\n collection: Collection<T, TKey, any> | undefined\n /**\n * Monotonic counter bumped whenever the visible layout (the ordered key\n * sequence) changes — membership, ordering, or an order-only move. Lets\n * consumers detect a reorder that changed no row value (which `data`/`state`\n * identity alone can't express once row values are structurally shared).\n *\n * It is NOT in lockstep with snapshot identity: a value-only update produces a\n * new snapshot while `layoutRevision` stays put. A `layoutRevision` change\n * always accompanies a new snapshot, but not vice versa.\n */\n layoutRevision: number\n status: CollectionStatus | `disabled`\n isLoading: boolean\n isReady: boolean\n isIdle: boolean\n /** The first load failed: there is nothing to show. */\n isLoadingError: boolean\n /** Local storage or an invariant broke. Only a cascade cleanup and a fresh start recover. */\n isCrashed: boolean\n isCleanedUp: boolean\n isEnabled: boolean\n /**\n * The data is shown, and something keeps it from staying current: a sync\n * problem or a failed request somewhere in `health`.\n */\n isSyncError: boolean\n /**\n * The health tree for the query and every Collection it depends on, or\n * `undefined` for a disabled query. After the first ready, a source\n * problem shows here and the data stays.\n */\n health: HealthNode | undefined\n}\n\n/**\n * Listener payload: changes, `[]` for an internal layout-only publication, or\n * `undefined` for a synthetic status/ready notification.\n */\nexport type LiveQueryObserverListener<\n T extends object,\n TKey extends string | number,\n> = (changes: Array<ChangeMessage<T, TKey>> | undefined) => void\n\n/**\n * Wraps a resolved live-query `Collection` (or `null` for a disabled query) with\n * the shared lifecycle every framework adapter needs: start sync on first\n * subscribe, subscribe to changes and status transitions, expose a stable\n * snapshot for wholesale consumers, and deliver the raw change set for\n * granular consumers.\n *\n * Input resolution (query fn / config / collection / disabled) stays in the\n * adapter — it is framework-reactive. The observer owns everything after the\n * input is resolved to a concrete collection.\n *\n * @internal Unstable contract for TanStack DB's official framework adapters —\n * not a public extension point yet; may change in any release.\n */\nexport interface LiveQueryObserver<\n T extends object,\n TKey extends string | number,\n> {\n /** Stable per-revision snapshot for wholesale materialization. */\n getSnapshot: () => LiveQuerySnapshot<T, TKey>\n /** Server snapshot. preloadRequested marks an explicit streaming Suspense load. */\n getServerSnapshot: (preloadRequested?: boolean) => LiveQuerySnapshot<T, TKey>\n /**\n * Subscribe to changes. The listener receives the change set (or `undefined`\n * for the synthetic notify a ready collection emits on attach). Granular\n * adapters apply the changes; wholesale adapters can ignore them and re-read\n * `getSnapshot()`. Returns an unsubscribe function.\n */\n subscribe: (listener: LiveQueryObserverListener<T, TKey>) => () => void\n /** Resolve once the collection has loaded its first data. */\n preload: () => Promise<void>\n /** The transport or preload error for this query, if it has not produced data. */\n getError: () => unknown\n /** Capture the ordered query result without serializing its source collections. */\n dehydrate: () => DehydratedLiveQueryResult<T, TKey>\n /** Idempotent teardown. */\n dispose: () => void\n}\n\n/**\n * One logical subscription. Records — not raw callbacks — identify\n * subscriptions, so the same listener function can be subscribed twice and\n * each subscription tears down independently.\n */\ninterface SubscriptionRecord<T extends object, TKey extends string | number> {\n listener: LiveQueryObserverListener<T, TKey>\n active: boolean\n}\n\ninterface Publication<T extends object, TKey extends string | number> {\n changes: Array<ChangeMessage<T, TKey>> | undefined\n targets: Array<SubscriptionRecord<T, TKey>>\n entries?: Array<[TKey, T]>\n status: CollectionStatus\n collectionRevision?: number\n collectionLayoutRevision?: number\n layoutChanged: boolean\n}\n\nconst DISABLED_SNAPSHOT: LiveQuerySnapshot<any, any> = {\n state: undefined,\n data: undefined,\n collection: undefined,\n layoutRevision: 0,\n status: `disabled`,\n isLoading: false,\n isReady: true,\n isIdle: false,\n isLoadingError: false,\n isCrashed: false,\n isCleanedUp: false,\n isEnabled: false,\n isSyncError: false,\n health: undefined,\n}\n\nclass LiveQueryObserverImpl<\n T extends object,\n TKey extends string | number,\n> implements LiveQueryObserver<T, TKey> {\n private readonly collection: Collection<T, TKey, any> | null\n private readonly wholesale: boolean\n private readonly clientBinding: LiveQueryObserverClient<T, TKey> | undefined\n private readonly onPreload: (() => void) | undefined\n private visibleStatus: CollectionStatus | undefined\n private cachedEntries: Array<[TKey, T]> | undefined\n private cachedCollectionRevision: number | undefined\n private cachedCollectionLayoutRevision: number | undefined\n private snapshotDirty = true\n // While attached, the tree from the last status or health change. Every\n // tree change is announced, so a snapshot reuses it instead of rebuilding.\n private publishedHealth: { tree: HealthNode | undefined } | undefined\n // Whether the cached snapshot was built for the hydration read.\n private cachedServerView = false\n private cachedSnapshot: LiveQuerySnapshot<T, TKey> = DISABLED_SNAPSHOT\n private layoutRevision = 0\n private lastLayoutKeys: Array<TKey> | undefined\n private deliveredLayoutRevision: number | undefined\n private readonly subscriptions = new Set<SubscriptionRecord<T, TKey>>()\n // Publications are dispatched FIFO: an emit that happens while another\n // publication is being delivered (a listener mutating the collection\n // synchronously) is queued, never delivered reentrantly.\n private readonly publicationQueue: Array<Publication<T, TKey>> = []\n private dispatching = false\n private blockDelivery = false\n private attached = false\n private collectionUnsub: (() => void) | null = null\n private preloadPromise: Promise<void> | undefined\n private disposed = false\n\n // Sync activation belongs to the first subscription (attach), so building\n // an observer cannot activate collection resources on its own. Server\n // request clients still record ownership here because React may render an\n // observer without ever subscribing to it.\n constructor(\n collection: Collection<T, TKey, any> | null,\n wholesale: boolean,\n client: DbClient | undefined,\n queryHash: string | undefined,\n onPreload: (() => void) | undefined,\n suspendUntilReady: boolean,\n ) {\n this.collection = collection\n this.wholesale = wholesale\n this.onPreload = onPreload\n this.clientBinding = client?._bindLiveQueryObserver(\n collection,\n queryHash,\n suspendUntilReady,\n {\n observer: this,\n read: (server) => this.getSnapshot(server),\n entries: () => (collection ? this.getVisibleEntries(collection) : []),\n isAttached: () => this.attached,\n isDisposed: () => this.disposed,\n dirty: () => {\n this.snapshotDirty = true\n },\n publish: (changes, entries) => {\n const revision =\n entries && collection\n ? this.getCollectionRevision(collection)\n : undefined\n if (entries) {\n this.updateCachedEntries(entries, revision)\n this.snapshotDirty = true\n }\n this.emit(\n this.wholesale ? undefined : changes,\n undefined,\n entries,\n collection?.status,\n revision,\n entries && collection\n ? this.getCollectionLayoutRevision(collection)\n : undefined,\n entries !== undefined,\n )\n },\n preload: () => this.preloadCollection(),\n },\n )\n this.clientBinding?.registerResource()\n }\n\n getSnapshot(forServerSnapshot = false): LiveQuerySnapshot<T, TKey> {\n const collection = this.collection\n if (!collection) return DISABLED_SNAPSHOT\n\n this.clientBinding?.sync(forServerSnapshot)\n if (!this.attached) this.refreshDetachedState(collection)\n\n // The hydration read and an ordinary read differ only while a seed\n // stands in front of a failure.\n if (\n this.cachedServerView !== forServerSnapshot &&\n this.clientBinding?.seed &&\n isFailedStatus(this.visibleStatus ?? collection.status)\n ) {\n this.snapshotDirty = true\n }\n\n if (this.snapshotDirty) {\n const entries = this.getVisibleEntries(collection)\n const data = entries.map(([, value]) => value)\n const singleResult = isSingleResultCollection(collection)\n const liveStatus = this.visibleStatus ?? collection.status\n // The seed stands in only for a result that is still coming, so an\n // ordinary read never hides a failure behind it. The hydration read\n // keeps the server's view: it must reproduce what the server rendered.\n const status = this.clientBinding?.failed\n ? (`error` as const)\n : this.clientBinding?.seed &&\n (forServerSnapshot || !isFailedStatus(liveStatus))\n ? (this.clientBinding.seed.snapshot.status ?? `ready`)\n : liveStatus\n this.cachedServerView = forServerSnapshot\n\n // Bump the layout revision when the ordered key sequence changes\n // (membership, ordering, or an order-only move). Compare the key sequence\n // directly rather than via a serialized signature: a joined-with-separator\n // signature can collide when a key value equals the concatenation of\n // neighboring keys around the separator. Comparing keys also avoids\n // materializing a large string on every rebuild; a new key array is only\n // allocated when the layout actually moved.\n const prevKeys = this.lastLayoutKeys\n let layoutChanged =\n prevKeys === undefined || prevKeys.length !== entries.length\n if (!layoutChanged) {\n for (let i = 0; i < entries.length; i++) {\n if (prevKeys![i] !== entries[i]![0]) {\n layoutChanged = true\n break\n }\n }\n }\n if (layoutChanged) {\n this.lastLayoutKeys = entries.map(([key]) => key)\n this.layoutRevision++\n }\n\n const health = this.publishedHealth\n ? this.publishedHealth.tree\n : (collection as { health?: HealthNode }).health\n // Most consumers read only `data`; build the keyed view on first read.\n let state: Map<TKey, T> | undefined\n this.cachedSnapshot = {\n get state() {\n return (state ??= new Map(entries))\n },\n data: singleResult ? data[0] : data,\n collection: getPublicCollection(collection),\n layoutRevision: this.layoutRevision,\n status,\n ...getLiveQueryStatusFlags(status, health),\n isEnabled: true,\n }\n this.snapshotDirty = false\n }\n return this.cachedSnapshot\n }\n\n getServerSnapshot(preloadRequested = false): LiveQuerySnapshot<T, TKey> {\n return (\n this.clientBinding?.getServerSnapshot(preloadRequested) ??\n this.getSnapshot()\n )\n }\n\n getError(): unknown {\n this.clientBinding?.sync()\n return this.clientBinding?.error\n }\n\n dehydrate(): DehydratedLiveQueryResult<T, TKey> {\n const collection = this.collection\n if (!collection) return { rows: [] }\n\n const entries =\n this.clientBinding?.seed &&\n this.clientBinding.seed.snapshot.status === undefined\n ? this.clientBinding.seed.entries\n : this.readEntries(collection).entries\n\n return {\n rows: entries.map(([key, value]) => ({\n key,\n value,\n })),\n }\n }\n\n private getVisibleEntries(\n collection: Collection<T, TKey, any>,\n ): Array<[TKey, T]> {\n if (this.clientBinding?.seed) return this.clientBinding.seed.entries\n return this.cachedEntries ?? this.captureEntries(collection).entries\n }\n\n private getCollectionRevision(\n collection: Collection<T, TKey, any>,\n ): number | undefined {\n const revision = (collection as { _stateRevision?: unknown })._stateRevision\n return typeof revision === `number` ? revision : undefined\n }\n\n private getCollectionLayoutRevision(\n collection: Collection<T, TKey, any>,\n ): number | undefined {\n const revision = (collection as { _layoutRevision?: unknown })\n ._layoutRevision\n return typeof revision === `number` ? revision : undefined\n }\n\n private readEntries(collection: Collection<T, TKey, any>): {\n entries: Array<[TKey, T]>\n revision?: number\n } {\n const entries = Array.from(collection.entries()) as Array<[TKey, T]>\n const revision = this.getCollectionRevision(collection)\n return { entries, revision }\n }\n\n private captureEntries(collection: Collection<T, TKey, any>): {\n entries: Array<[TKey, T]>\n revision?: number\n } {\n const { entries, revision } = this.readEntries(collection)\n this.updateCachedEntries(entries, revision)\n return { entries, revision }\n }\n\n private updateCachedEntries(\n entries: Array<[TKey, T]>,\n revision: number | undefined,\n ): void {\n const changed =\n revision !== undefined\n ? this.cachedEntries === undefined ||\n revision !== this.cachedCollectionRevision\n : !this.entriesEqual(this.cachedEntries, entries)\n\n this.cachedEntries = entries\n this.cachedCollectionRevision = revision\n if (changed) this.snapshotDirty = true\n }\n\n private entriesEqual(\n left: Array<[TKey, T]> | undefined,\n right: Array<[TKey, T]>,\n ): boolean {\n if (!left || left.length !== right.length) return false\n return left.every(\n ([key, value], index) =>\n right[index]![0] === key && right[index]![1] === value,\n )\n }\n\n /**\n * While detached there is no delivered-publication clock, so fall back to\n * the collection revision. Compatible cross-copy collections that predate\n * `_stateRevision` are compared structurally instead.\n */\n private refreshDetachedState(collection: Collection<T, TKey, any>): void {\n const status = collection.status\n const revision = this.getCollectionRevision(collection)\n const layoutRevision = this.getCollectionLayoutRevision(collection)\n\n if (revision !== undefined) {\n if (\n this.cachedEntries === undefined ||\n revision !== this.cachedCollectionRevision ||\n layoutRevision !== this.cachedCollectionLayoutRevision\n ) {\n this.captureEntries(collection)\n this.cachedCollectionLayoutRevision = layoutRevision\n this.snapshotDirty = true\n }\n } else {\n const entries = Array.from(collection.entries()) as Array<[TKey, T]>\n this.updateCachedEntries(entries, undefined)\n }\n\n // A health-only change moves no row or status. Trees keep their identity\n // until their content changes, so identity tells whether it went stale.\n if (\n this.visibleStatus !== status ||\n this.cachedSnapshot.health !==\n (collection as { health?: HealthNode }).health\n ) {\n this.visibleStatus = status\n this.snapshotDirty = true\n }\n }\n\n subscribe(listener: LiveQueryObserverListener<T, TKey>): () => void {\n if (this.disposed) throw new LiveQueryObserverDisposedError()\n if (this.subscriptions.size === 0) this.clientBinding?.assertSources()\n\n const record: SubscriptionRecord<T, TKey> = { listener, active: true }\n const release = () => {\n if (!record.active) return\n record.active = false\n this.subscriptions.delete(record)\n if (this.subscriptions.size === 0) this.detach()\n }\n this.subscriptions.add(record)\n const attaching = !this.attached\n try {\n if (attaching) {\n this.attach()\n } else {\n // Seed only this late granular listener; a failed seed releases its\n // record without detaching peers that already own subscriptions.\n if (!this.wholesale) this.seed(record)\n }\n } catch (error) {\n // Setup returned no ownership handle. Release every acquired channel\n // and the logical record, so a later explicit subscription can attach.\n if (attaching) this.detach()\n release()\n throw error\n }\n return release\n }\n\n /** Deliver the collection's current rows to one late subscription as inserts. */\n private seed(record: SubscriptionRecord<T, TKey>): void {\n const collection = this.collection\n if (!collection) return\n\n const seedChanges: Array<ChangeMessage<T, TKey>> = []\n for (const [key, value] of this.getVisibleEntries(collection)) {\n seedChanges.push({ type: `insert`, key, value })\n }\n if (seedChanges.length === 0) return\n\n this.emit(seedChanges, [record])\n }\n\n private attach(): void {\n const collection = this.collection\n if (!collection || this.disposed) return\n // Install ownership before any registration can call back or throw.\n const releases: Array<() => void> = []\n const release = () => runAllCallbacks(releases.splice(0))\n this.collectionUnsub = release\n const ownRelease = (unsubscribe: () => void) => {\n if (this.collectionUnsub === release) releases.push(unsubscribe)\n else unsubscribe()\n }\n this.clientBinding?.registerResource()\n this.clientBinding?.sync()\n this.refreshDetachedState(collection)\n this.attached = true\n this.visibleStatus ??= collection.status\n this.deliveredLayoutRevision = this.getCollectionLayoutRevision(collection)\n const attachedWithHydrationSeed = !!this.clientBinding?.seed\n this.blockDelivery = this.wholesale || attachedWithHydrationSeed\n\n // Sync activation happens inside subscribeChanges (addSubscriber starts\n // an idle/cleaned-up collection) — the same startSync path the old\n // constructor-time startSyncImmediate() took, but now owned by the first\n // committed subscription and observed by the status listener below.\n\n // Granular consumers subscribe with initial state so they receive the\n // current rows as inserts followed by deltas through one consistent\n // channel (the collection's per-subscriber change stream requires this to\n // align deltas). Wholesale consumers subscribe WITHOUT initial state —\n // preserving their pre-observer loading policy: no snapshot request means\n // no unfiltered loadSubset({ where: undefined }) against on-demand\n // collections. The explicit `false` marks all state as seen so deletes\n // still flow through as notifies.\n const notify = (\n changes: Array<ChangeMessage<T, TKey>> | undefined,\n status: CollectionStatus = collection.status,\n explicitLayoutChange = false,\n ) => {\n if (this.disposed || this.subscriptions.size === 0) return\n\n if (this.clientBinding?.seed) {\n // Startup remains behind the hydration cut. A later failure ends the\n // sync run whose result the seed stood in for, and is already an\n // owned publication, so it must be visible synchronously.\n if (isFailedStatus(status) && !this.blockDelivery)\n this.clientBinding.handoff()\n else if (status === `ready` || isFailedStatus(status))\n this.clientBinding.scheduleHandoff()\n return\n }\n\n if (status === `ready` && !collection.isLoadingSubset) {\n this.clientBinding?.markAuthoritative()\n }\n\n const layoutRevision = this.getCollectionLayoutRevision(collection)\n let layoutChanged = explicitLayoutChange\n if (\n !explicitLayoutChange &&\n changes !== undefined &&\n changes.length === 0\n ) {\n // Empty ready events predate the explicit layout signal and share its\n // empty-array payload. Only forward an empty batch when the collection\n // confirms that a new layout-only publication occurred.\n if (\n layoutRevision === undefined ||\n layoutRevision === this.deliveredLayoutRevision\n ) {\n return\n }\n layoutChanged = true\n }\n if (changes !== undefined && layoutRevision !== undefined) {\n this.deliveredLayoutRevision = layoutRevision\n }\n const captured =\n changes !== undefined\n ? this.readEntries(collection)\n : status === `cleaned-up`\n ? this.readEntries(collection)\n : undefined\n this.emit(\n changes,\n undefined,\n captured?.entries,\n status,\n captured?.revision,\n layoutRevision,\n layoutChanged,\n )\n }\n\n // Status transitions that carry no change events (loading→ready with no\n // rows, error, cleaned-up) are part of the canonical publication path:\n // any status change publishes a synthetic notify so consumers re-read the\n // snapshot. Unlike onFirstReady, `on` returns a real unsubscribe, so a\n // detached attachment leaves nothing behind.\n // A health change below the query changes its health tree, not its rows.\n // Each status change is followed by a health change; tree identity\n // tells whether the health change has anything left to publish.\n const healthOf = () => (collection as { health?: HealthNode }).health\n this.publishedHealth = { tree: healthOf() }\n ownRelease(() => {\n this.publishedHealth = undefined\n })\n ownRelease(\n collection.on(`status:change`, ({ status }) => {\n this.publishedHealth = { tree: healthOf() }\n notify(undefined, status)\n }),\n )\n ownRelease(\n collection.on(`health:change`, () => {\n const health = healthOf()\n if (health === this.publishedHealth?.tree) return\n this.publishedHealth = { tree: health }\n // No rows or status changed, so only this marks the snapshot stale.\n this.snapshotDirty = true\n notify(undefined, collection.status)\n }),\n )\n const subscribeLayoutChanges = (\n collection as Collection<T, TKey, any> & {\n _subscribeLayoutChanges?: (listener: () => void) => () => void\n }\n )._subscribeLayoutChanges\n if (typeof subscribeLayoutChanges === `function`) {\n ownRelease(\n subscribeLayoutChanges.call(collection, () =>\n notify([], collection.status, true),\n ),\n )\n }\n // `subscribeChanges` delivers the initial state synchronously, so a\n // listener can dispose the observer while the collection subscription is\n // still being created. Register the release hook up front; if detach()\n // ran during that replay (collectionUnsub no longer points at our hook),\n // undo the subscription as soon as the call returns.\n if (this.clientBinding) ownRelease(this.clientBinding.subscribe())\n const subscription = collection.subscribeChanges(\n (changes) => notify(changes as Array<ChangeMessage<T, TKey>>),\n { includeInitialState: !this.wholesale && !attachedWithHydrationSeed },\n )\n ownRelease(() => subscription.unsubscribe())\n this.blockDelivery = false\n if (this.collectionUnsub !== release) return\n if (this.wholesale || attachedWithHydrationSeed) {\n // Publications raised while subscribeChanges starts sync are part of the\n // subscribe handshake. Apply their final snapshot state now, but suppress\n // listener delivery: useSyncExternalStore performs its consistency read\n // immediately after subscribe returns.\n this.flushPublications(!this.wholesale)\n // The render-time read is still current unless the handshake published.\n const revision = this.getCollectionRevision(collection)\n const layoutRevision = this.getCollectionLayoutRevision(collection)\n if (\n revision === undefined ||\n this.cachedEntries === undefined ||\n revision !== this.cachedCollectionRevision ||\n layoutRevision !== this.cachedCollectionLayoutRevision\n ) {\n const { entries } = this.readEntries(collection)\n this.updateCachedEntries(entries, revision)\n this.cachedCollectionLayoutRevision = layoutRevision\n }\n }\n if (this.clientBinding?.seed) {\n if (!this.wholesale) this.seed(Array.from(this.subscriptions)[0]!)\n if (collection.status === `ready` || isFailedStatus(collection.status)) {\n this.clientBinding.scheduleHandoff()\n }\n }\n }\n\n private detach(): void {\n const release = this.collectionUnsub\n const unregister = this.clientBinding?.takeResourceRelease()\n this.collectionUnsub = null\n this.attached = false\n this.blockDelivery = false\n this.publicationQueue.length = 0\n runAllCallbacks([() => release?.(), () => unregister?.()])\n }\n\n private emit(\n changes: Array<ChangeMessage<T, TKey>> | undefined,\n targets = Array.from(this.subscriptions),\n entries?: Array<[TKey, T]>,\n status = this.collection?.status ?? `cleaned-up`,\n collectionRevision?: number,\n collectionLayoutRevision?: number,\n layoutChanged = false,\n ): void {\n this.publicationQueue.push({\n changes,\n targets,\n entries,\n status,\n collectionRevision,\n collectionLayoutRevision,\n layoutChanged,\n })\n if (this.dispatching || this.blockDelivery) return\n\n this.flushPublications()\n }\n\n private flushPublications(deliver = true): void {\n if (this.dispatching) return\n\n let failure: { error: unknown } | undefined\n this.dispatching = true\n try {\n // A dispose() during dispatch empties the queue, ending this loop.\n while (this.publicationQueue.length > 0) {\n const publication = this.publicationQueue.shift()!\n if (publication.entries) {\n this.updateCachedEntries(\n publication.entries,\n publication.collectionRevision,\n )\n }\n if (publication.collectionLayoutRevision !== undefined) {\n this.cachedCollectionLayoutRevision =\n publication.collectionLayoutRevision\n }\n if (publication.layoutChanged) {\n this.snapshotDirty = true\n }\n if (this.visibleStatus !== publication.status) {\n this.visibleStatus = publication.status\n this.snapshotDirty = true\n }\n // Targets are captured when the publication is queued: a subscription\n // removed mid-delivery still receives the in-flight publication, and\n // one added later does not. Late-subscriber seeds use the same queue.\n if (deliver) {\n for (const subRecord of publication.targets) {\n if (this.disposed) break\n try {\n subRecord.listener(publication.changes)\n } catch (error) {\n failure ??= { error }\n }\n }\n }\n }\n } finally {\n this.dispatching = false\n }\n if (failure) throw failure.error\n }\n\n preload(): Promise<void> {\n return this.clientBinding?.preload() ?? this.preloadCollection()\n }\n\n private preloadCollection(): Promise<void> {\n if (this.preloadPromise) return this.preloadPromise\n this.onPreload?.()\n const promise = this.collection?.preload() ?? Promise.resolve()\n this.preloadPromise = promise\n const clear = () => {\n if (this.preloadPromise === promise) this.preloadPromise = undefined\n }\n void promise.then(clear, clear)\n return promise\n }\n\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.detach()\n for (const subRecord of this.subscriptions) subRecord.active = false\n this.subscriptions.clear()\n this.publicationQueue.length = 0\n }\n}\n\nexport interface CreateLiveQueryObserverOptions {\n /**\n * How subscribers consume the observer:\n *\n * - `granular` (default): subscribers apply the delivered `ChangeMessage[]`\n * deltas to their own keyed state (Vue/Svelte/Solid). The observer\n * subscribes with initial state and seeds late subscribers, so every\n * subscriber converges from deltas alone.\n * - `wholesale`: subscribers treat notifications as a wake-up and re-read\n * `getSnapshot()` (React/Angular). The observer subscribes WITHOUT initial\n * state, preserving those adapters' loading policy — no snapshot request,\n * so no unfiltered `loadSubset` against on-demand collections. Nothing is\n * delivered synchronously during `subscribe`, which keeps\n * `useSyncExternalStore`-style consumers safe by construction.\n */\n mode?: `granular` | `wholesale`\n /** DbClient cache that owns SSR snapshots for this query identity. */\n client?: DbClient\n /** Stable live-query identity used for dehydration and hydration. */\n queryHash?: string\n /** Resume framework-deferred query sources before a server preload. */\n onPreload?: () => void\n /** Read the completed stream rather than an earlier ordinary loading view. */\n suspendUntilReady?: boolean\n}\n\n/**\n * The Error an adapter sends to an error boundary for a failed first load or\n * a crash: the cause itself when it is an Error, otherwise an Error with the\n * problem's message (as in `health.error.message`) whose `cause` is the value\n * the sync adapter reported.\n *\n * @internal Shared by TanStack DB's official framework adapters.\n */\nexport const toBoundaryError = (cause: unknown): Error =>\n cause instanceof Error\n ? cause\n : new Error(describeProblem(cause).message, { cause })\n\n/**\n * Create a {@link LiveQueryObserver} for a resolved live-query collection, or a\n * disabled observer when `collection` is `null`/`undefined`.\n *\n * @internal This is an unstable contract shared by TanStack DB's official\n * framework adapters. It is exported so the adapter packages can use it, but\n * it is not a public extension point yet: its API may change in any release\n * without a semver major.\n */\nexport function createLiveQueryObserver<\n T extends object,\n TKey extends string | number,\n>(\n collection: Collection<T, TKey, any> | null | undefined,\n options: CreateLiveQueryObserverOptions = {},\n): LiveQueryObserver<T, TKey> {\n return new LiveQueryObserverImpl<T, TKey>(\n collection ?? null,\n options.mode === `wholesale`,\n options.client,\n options.queryHash,\n options.onPreload,\n options.suspendUntilReady === true,\n )\n}\n"],"names":["snapshotDirty","cachedServerView","cachedSnapshot","publicationQueue","dispatching","blockDelivery","attached","collectionUnsub","clientBinding","getVisibleEntries","getCollectionRevision","updateCachedEntries","getCollectionLayoutRevision","preloadCollection","refreshDetachedState","isFailedStatus","visibleStatus","isSingleResultCollection","lastLayoutKeys","publishedHealth","getPublicCollection","getLiveQueryStatusFlags","readEntries","cachedEntries","captureEntries","cachedCollectionRevision","entriesEqual","cachedCollectionLayoutRevision","LiveQueryObserverDisposedError","detach","attach","runAllCallbacks","deliveredLayoutRevision","flushPublications","describeProblem"],"mappings":"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"}