UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines • 49.9 kB
{"version":3,"file":"live-query-window-controller.cjs","sources":["../../src/live-query-window-controller.ts"],"sourcesContent":["import {\n LiveQueryWindowControllerDisposedError,\n SetWindowRequiresOrderByError,\n} from './errors.js'\nimport {\n getLiveQueryStatusFlags,\n isCollection,\n isSingleResultCollection,\n} from './live-query-adapter.js'\nimport { createLiveQueryObserver } from './live-query-observer.js'\nimport { BaseQueryBuilder } from './query/builder/index.js'\nimport { deepEquals } from './utils.js'\nimport type {\n LiveQueryObserver,\n LiveQuerySnapshot,\n} from './live-query-observer.js'\nimport type { Collection } from './collection/index.js'\nimport type { CollectionStatus } from './types.js'\nimport type {\n Context,\n InitialQueryBuilder,\n QueryBuilder,\n} from './query/builder/index.js'\n\nconst DEFAULT_PAGE_SIZE = 20\n\nexport type LiveQueryWindowInputKind = `collection` | `query`\n\n/** @internal The supported, enabled input forms for infinite-query adapters. */\nexport type ResolvedLiveQueryWindowInput<TContext extends Context> =\n | { kind: `collection`; collection: Collection<any, any, any> }\n | { kind: `query`; query: QueryBuilder<TContext> }\n\n/**\n * Classify an infinite-query input without invoking its query callback.\n * Frameworks use this during lifecycle comparison so unchanged React renders\n * do not execute the callback again.\n *\n * @internal This contract is unstable while RFC #1623 is being implemented.\n */\nexport function getLiveQueryWindowInputKind(\n input: unknown,\n): LiveQueryWindowInputKind {\n if (isCollection(input)) return `collection`\n if (typeof input === `function`) return `query`\n throw new Error(\n `useLiveInfiniteQuery: First argument must be either a pre-created live query collection or a query function. ` +\n `Received: ${typeof input}`,\n )\n}\n\n/**\n * Resolve a supported infinite-query input and invoke a query callback once.\n * A function may resolve to a collection for framework getter compatibility.\n * Nullable/disabled and config-object inputs are intentionally not supported.\n *\n * @internal This contract is unstable while RFC #1623 is being implemented.\n */\nexport function resolveLiveQueryWindowInput<TContext extends Context>(\n input: unknown,\n): ResolvedLiveQueryWindowInput<TContext> {\n if (getLiveQueryWindowInputKind(input) === `collection`) {\n return {\n kind: `collection`,\n collection: input as Collection<any, any, any>,\n }\n }\n\n const value = (\n input as (q: InitialQueryBuilder) => QueryBuilder<TContext> | unknown\n )(new BaseQueryBuilder() as InitialQueryBuilder)\n if (isCollection(value)) {\n return { kind: `collection`, collection: value }\n }\n if (\n typeof value !== `object` ||\n value === null ||\n typeof (value as { limit?: unknown }).limit !== `function` ||\n typeof (value as { offset?: unknown }).offset !== `function`\n ) {\n throw new Error(\n `useLiveInfiniteQuery: Query function must return a query builder. ` +\n `Disabled null or undefined queries are not supported.`,\n )\n }\n return { kind: `query`, query: value as QueryBuilder<TContext> }\n}\n\n/** @internal This contract is unstable while RFC #1623 is being implemented. */\nexport function normalizeLiveQueryWindowPageSize(\n pageSize: number | undefined,\n): number {\n if (\n pageSize === undefined ||\n !Number.isSafeInteger(pageSize) ||\n pageSize <= 0 ||\n pageSize >= Number.MAX_SAFE_INTEGER\n ) {\n return DEFAULT_PAGE_SIZE\n }\n return pageSize\n}\n\ntype WindowResult = true | Promise<void>\n\ntype LiveQueryWindow = { offset: number; limit: number }\n\n/** @internal Shared adapter view of a collection with an ordered window. */\nexport type LiveQueryWindowCollection = Collection<any, any, any> & {\n utils: {\n setWindow: (options: LiveQueryWindow) => WindowResult\n getWindow: () => LiveQueryWindow | undefined\n }\n}\n\ntype WindowTarget = object & {\n utils?: {\n setWindow?: (options: { offset: number; limit: number }) => WindowResult\n getWindow?: () => { offset: number; limit: number } | undefined\n }\n}\n\ntype PendingWindow = {\n generation: number\n limit: number\n promise: Promise<void>\n}\n\nclass WindowCoordinator {\n private readonly leases = new Map<symbol, number>()\n private readonly leaseVersions = new Map<symbol, number>()\n private baselineWindow: { offset: number; limit: number } | undefined\n private retainedWindow: { offset: number; limit: number } | undefined\n private shouldCaptureBaseline = true\n private appliedLimit: number | undefined\n private pending: PendingWindow | undefined\n private generation = 0\n private leaseVersion = 0\n\n constructor(private readonly target: WindowTarget) {}\n\n request(lease: symbol, limit: number): WindowResult {\n if (this.leases.size === 0) {\n const currentWindow = this.target.utils?.getWindow?.()\n const retainedWindowChanged =\n this.retainedWindow !== undefined &&\n (currentWindow?.offset !== this.retainedWindow.offset ||\n currentWindow.limit !== this.retainedWindow.limit)\n if (this.shouldCaptureBaseline || retainedWindowChanged) {\n this.baselineWindow = currentWindow\n this.shouldCaptureBaseline = false\n }\n this.retainedWindow = undefined\n }\n const previousLimit = this.leases.get(lease)\n const previousVersion = this.leaseVersions.get(lease)\n const version = ++this.leaseVersion\n this.leases.set(lease, limit)\n this.leaseVersions.set(lease, version)\n\n let result: WindowResult\n try {\n result = this.applyDesiredWindow()\n } catch (error) {\n this.rollbackLease(lease, version, previousLimit, previousVersion)\n this.appliedLimit = undefined\n if (this.leases.size === 0) this.shouldCaptureBaseline = true\n throw error\n }\n\n if (result === true) return true\n return result.catch(async (error: unknown) => {\n if (this.rollbackLease(lease, version, previousLimit, previousVersion)) {\n this.generation++\n this.pending = undefined\n this.appliedLimit = undefined\n try {\n if (this.leases.size === 0) {\n this.restoreInitialWindow()\n } else {\n const rollback = this.applyDesiredWindow()\n if (rollback !== true) await rollback\n }\n } catch {\n // Preserve the failure from the requested window.\n }\n }\n throw error\n })\n }\n\n getLeaseResult(lease: symbol, minimumLimit: number): WindowResult | false {\n const limit = this.leases.get(lease)\n if (limit === undefined || limit < minimumLimit) return false\n const desiredLimit = this.getDesiredLimit()\n // getWindow reports settled state; the current lease may still be loading.\n if (this.pending && this.pending.limit === desiredLimit)\n return this.pending.promise\n const currentWindow = this.target.utils?.getWindow?.()\n return (\n currentWindow === undefined ||\n (currentWindow.offset === 0 && currentWindow.limit === desiredLimit)\n )\n }\n\n hasLeases(): boolean {\n return this.leases.size > 0\n }\n\n release(lease: symbol, restoreWhenEmpty: boolean): void {\n if (!this.leases.delete(lease)) return\n this.leaseVersions.delete(lease)\n\n // A pending request may still mutate the physical operator, but it no longer\n // establishes the accepted window for the remaining lease set.\n this.generation++\n this.pending = undefined\n this.appliedLimit = undefined\n\n if (this.leases.size === 0) {\n if (restoreWhenEmpty) {\n this.restoreInitialWindow()\n } else {\n this.retainedWindow = this.target.utils?.getWindow?.()\n }\n return\n }\n\n try {\n const result = this.applyDesiredWindow()\n if (result !== true) {\n void result.catch(() => {\n // Unsubscribe has no async error channel. Leave the physical window\n // unaccepted so the next request retries it.\n this.appliedLimit = undefined\n })\n }\n } catch {\n // The remaining controller will retry on its next request.\n this.appliedLimit = undefined\n }\n }\n\n private getDesiredLimit(): number | undefined {\n let desired: number | undefined\n for (const limit of this.leases.values()) {\n desired = desired === undefined ? limit : Math.max(desired, limit)\n }\n return desired\n }\n\n private rollbackLease(\n lease: symbol,\n version: number,\n previousLimit: number | undefined,\n previousVersion: number | undefined,\n ): boolean {\n if (this.leaseVersions.get(lease) !== version) return false\n if (previousLimit === undefined) {\n this.leases.delete(lease)\n this.leaseVersions.delete(lease)\n } else {\n this.leases.set(lease, previousLimit)\n if (previousVersion === undefined) {\n this.leaseVersions.delete(lease)\n } else {\n this.leaseVersions.set(lease, previousVersion)\n }\n }\n return true\n }\n\n private restoreInitialWindow(): void {\n const setWindow = this.target.utils?.setWindow\n const baselineWindow = this.baselineWindow\n this.retainedWindow = undefined\n this.shouldCaptureBaseline = false\n if (!baselineWindow || typeof setWindow !== `function`) {\n this.shouldCaptureBaseline = true\n return\n }\n const generation = this.generation\n const markRestored = () => {\n if (generation === this.generation && this.leases.size === 0) {\n this.shouldCaptureBaseline = true\n }\n }\n try {\n const result = setWindow.call(this.target.utils, baselineWindow)\n if (result === true) {\n markRestored()\n } else {\n void result.then(markRestored, () => {\n // Keep the original baseline so a later release can retry it.\n })\n }\n } catch {\n // Release has no error channel. Keep the baseline for a later retry.\n }\n }\n\n private applyDesiredWindow(): WindowResult {\n const limit = this.getDesiredLimit()\n if (limit === undefined) return true\n if (this.pending?.limit === limit) return this.pending.promise\n if (this.pending) {\n // `setWindow` mutates the physical operator before its load promise\n // settles. A different desired window must therefore be applied again,\n // even when it matches the last settled limit.\n this.generation++\n this.pending = undefined\n this.appliedLimit = undefined\n }\n const currentWindow = this.target.utils?.getWindow?.()\n if (\n limit === this.appliedLimit &&\n currentWindow?.offset === 0 &&\n currentWindow.limit === limit\n ) {\n return true\n }\n\n const setWindow = this.target.utils?.setWindow\n if (typeof setWindow !== `function`) {\n throw new SetWindowRequiresOrderByError()\n }\n\n const generation = ++this.generation\n const result = setWindow.call(this.target.utils, { offset: 0, limit })\n if (result === true) {\n if (generation === this.generation && this.getDesiredLimit() === limit) {\n this.appliedLimit = limit\n }\n return true\n }\n\n const promise = result.then(\n () => {\n if (\n generation === this.generation &&\n this.getDesiredLimit() === limit\n ) {\n this.appliedLimit = limit\n }\n if (this.pending?.generation === generation) {\n this.pending = undefined\n }\n },\n (error: unknown) => {\n if (this.pending?.generation === generation) {\n this.pending = undefined\n }\n throw error\n },\n )\n this.pending = { generation, limit, promise }\n return promise\n }\n}\n\nconst windowCoordinators = new WeakMap<object, WindowCoordinator>()\n\nfunction getWindowCoordinator(target: WindowTarget): WindowCoordinator {\n let coordinator = windowCoordinators.get(target)\n if (!coordinator) {\n coordinator = new WindowCoordinator(target)\n windowCoordinators.set(target, coordinator)\n }\n return coordinator\n}\n\n/** @internal Whether an infinite-query controller currently owns this window. */\nexport function hasLiveQueryWindowLeases(target: object): boolean {\n return windowCoordinators.get(target)?.hasLeases() ?? false\n}\n\n/** @internal Shared validation for infinite-query adapters. */\nexport function assertLiveQueryWindowManyResult(\n collection: Collection<any, any, any>,\n): void {\n if (isSingleResultCollection(collection)) {\n throw new Error(\n `useLiveInfiniteQuery: Infinite queries do not support single-result queries. Remove .findOne().`,\n )\n }\n}\n\n/** @internal Whether a collection exposes an active ordered window. */\nexport function isLiveQueryWindowCollection(\n collection: Collection<any, any, any>,\n): collection is LiveQueryWindowCollection {\n return (\n typeof collection.utils?.setWindow === `function` &&\n collection.utils.getWindow?.() !== undefined\n )\n}\n\n/**\n * Validate a pre-created infinite-query collection and describe any window\n * adjustment the adapter should warn about.\n *\n * @internal Shared validation for infinite-query adapters.\n */\nexport function getLiveQueryWindowCollectionWarning(\n collection: Collection<any, any, any>,\n expectedLimit: number,\n): string | undefined {\n assertLiveQueryWindowManyResult(collection)\n if (!isLiveQueryWindowCollection(collection)) {\n throw new Error(\n `useLiveInfiniteQuery: Pre-created live query collection must have an ORDER BY (orderBy) clause for infinite pagination to work. ` +\n `Please add .orderBy() to your createLiveQueryCollection query.`,\n )\n }\n\n const currentWindow = collection.utils.getWindow()\n if (\n !currentWindow ||\n hasLiveQueryWindowLeases(collection) ||\n (currentWindow.offset === 0 && currentWindow.limit === expectedLimit)\n ) {\n return undefined\n }\n\n return (\n `useLiveInfiniteQuery: Pre-created collection has window {offset: ${currentWindow.offset}, limit: ${currentWindow.limit}} ` +\n `but the hook expects {offset: 0, limit: ${expectedLimit}}. Adjusting window now.`\n )\n}\n\n/** @internal Compare adapter dependencies by identity and structure. */\nexport function compareLiveQueryWindowDependencies(\n previous: ReadonlyArray<unknown> | null | undefined,\n current: ReadonlyArray<unknown>,\n): { changed: boolean; structurallyEqual: boolean } {\n const changed =\n previous === null ||\n previous === undefined ||\n previous.length !== current.length ||\n previous.some((dependency, index) => dependency !== current[index])\n return {\n changed,\n structurallyEqual:\n previous !== null &&\n previous !== undefined &&\n deepEquals(previous, current),\n }\n}\n\n/** @internal Shared page-depth preservation policy for framework adapters. */\nexport function shouldPreserveLiveQueryWindowPageCount(options: {\n hasPreviousController: boolean\n previousInputKind: `collection` | `query` | undefined\n inputKind: `collection` | `query`\n sameCollection: boolean\n dependenciesChanged: boolean\n dependenciesStructurallyEqual: boolean\n pageShapeChanged: boolean\n}): boolean {\n if (\n !options.hasPreviousController ||\n options.previousInputKind !== options.inputKind\n ) {\n return false\n }\n if (options.inputKind === `collection`) return options.sameCollection\n return options.dependenciesChanged\n ? options.dependenciesStructurallyEqual\n : options.pageShapeChanged\n}\n\n/**\n * A page-windowed view of a live query at a point in time.\n *\n * @internal This contract is unstable while RFC #1623 is being implemented.\n */\nexport interface LiveQueryWindowSnapshot<\n T extends object,\n TKey extends string | number,\n> {\n /** Rows across all committed pages, with the peek-ahead row removed. */\n data: ReadonlyArray<T>\n /** Rows grouped into committed pages of `pageSize`. */\n pages: ReadonlyArray<ReadonlyArray<T>>\n /** `initialPageParam + i` for each committed page. */\n pageParams: ReadonlyArray<number>\n hasNextPage: boolean\n isFetchingNextPage: boolean\n /** Last pagination failure, retained through an earlier-started success until recovery begins. */\n error: unknown\n /** Keyed results for the physical window, or `undefined` when disabled. */\n state: ReadonlyMap<TKey, T> | undefined\n collection: Collection<T, TKey, any> | undefined\n status: CollectionStatus | `disabled`\n isLoading: boolean\n isReady: boolean\n persistedStatus: LiveQuerySnapshot<T, TKey>[`persistedStatus`]\n isPersistedReady: boolean\n persistedError: unknown | undefined\n isIdle: boolean\n isError: boolean\n isCleanedUp: boolean\n isEnabled: boolean\n}\n\n/** @internal This contract is unstable while RFC #1623 is being implemented. */\nexport interface CreateLiveQueryWindowControllerOptions {\n /** Rows per page (default 20). Invalid values use the default. */\n pageSize?: number\n /** Value of the first page's `pageParam` (default 0). */\n initialPageParam?: number\n /** Committed pages to preserve when a framework binding changes page shape. */\n initialPageCount?: number\n}\n\n/** @internal This contract is unstable while RFC #1623 is being implemented. */\nexport interface LiveQueryWindowController<\n T extends object,\n TKey extends string | number,\n> {\n getSnapshot: () => LiveQueryWindowSnapshot<T, TKey>\n subscribe: (listener: () => void) => () => void\n /** Load one more page, resolving only after that page is committed. */\n fetchNextPage: () => Promise<void>\n /** Reset to the first page, resolving after the smaller window is accepted. */\n reset: () => Promise<void>\n preload: () => Promise<void>\n dispose: () => void\n}\n\n/**\n * Run an adapter-facing page fetch. The controller records failures in its\n * snapshot; consuming the rejection here keeps event handlers safe while the\n * returned promise still settles with the request.\n *\n * @internal This contract is unstable while RFC #1623 is being implemented.\n */\nexport function fetchNextLiveQueryWindowPage(\n controller: Pick<\n LiveQueryWindowController<object, string | number>,\n `fetchNextPage`\n >,\n): Promise<void> {\n return controller.fetchNextPage().catch(() => {})\n}\n\ninterface CachedFrom {\n observerSnapshot: unknown\n committedPageCount: number\n isFetchingNextPage: boolean\n hasPaginationError: boolean\n paginationError: unknown\n failedHasNextPage: boolean\n}\n\ninterface SubscriptionRecord {\n listener: () => void\n active: boolean\n}\n\ninterface Publication {\n targets: Array<SubscriptionRecord>\n}\n\nclass LiveQueryWindowControllerImpl<\n T extends object,\n TKey extends string | number,\n> implements LiveQueryWindowController<T, TKey> {\n private readonly observer: LiveQueryObserver<T, TKey>\n private readonly collection: Collection<T, TKey, any> | null\n private readonly coordinator: WindowCoordinator | null\n private readonly lease = Symbol(`liveQueryWindowLease`)\n private readonly pageSize: number\n private readonly initialPageParam: number\n\n private committedPageCount: number\n private isFetchingNextPage = false\n private hasPaginationError = false\n private paginationError: unknown\n private failedHasNextPage = false\n private activeFetchPromise: Promise<void> | null = null\n private windowGeneration = 0\n private pendingWindowGeneration: number | undefined\n private leaseActive = false\n private leaseGeneration = 0\n private inFlightLeaseHolders = 0\n private restoreInitialWindowOnRelease = false\n\n private readonly subscriptions = new Set<SubscriptionRecord>()\n private readonly publicationQueue: Array<Publication> = []\n private dispatching = false\n private blockDelivery = false\n private transitionDepth = 0\n private transitionNeedsNotify = false\n private observerUnsub: (() => void) | null = null\n private cachedSnapshot: LiveQueryWindowSnapshot<T, TKey> | null = null\n private cachedFrom: CachedFrom | null = null\n private disposed = false\n\n constructor(\n collection: Collection<T, TKey, any> | null,\n options: CreateLiveQueryWindowControllerOptions,\n ) {\n this.collection = collection\n this.coordinator = collection\n ? getWindowCoordinator(collection as unknown as WindowTarget)\n : null\n this.pageSize = normalizeLiveQueryWindowPageSize(options.pageSize)\n this.initialPageParam = options.initialPageParam ?? 0\n const initialPageCount = Math.floor(options.initialPageCount ?? 1)\n this.committedPageCount = Number.isFinite(initialPageCount)\n ? Math.max(1, initialPageCount)\n : 1\n // The controller listener carries no delta payload, so wholesale is the\n // only coherent observer contract and guarantees non-reentrant subscribe.\n this.observer = createLiveQueryObserver<T, TKey>(collection, {\n mode: `wholesale`,\n })\n }\n\n getSnapshot(): LiveQueryWindowSnapshot<T, TKey> {\n const observerSnapshot = this.observer.getSnapshot()\n if (this.hasPaginationError && observerSnapshot.status === `ready`) {\n this.failedHasNextPage = this.getComputedHasNextPage(observerSnapshot)\n }\n const cached = this.cachedSnapshot\n if (\n cached &&\n this.cachedFrom &&\n this.cachedFrom.observerSnapshot === observerSnapshot &&\n this.cachedFrom.committedPageCount === this.committedPageCount &&\n this.cachedFrom.isFetchingNextPage === this.isFetchingNextPage &&\n this.cachedFrom.hasPaginationError === this.hasPaginationError &&\n this.cachedFrom.paginationError === this.paginationError &&\n this.cachedFrom.failedHasNextPage === this.failedHasNextPage\n ) {\n return cached\n }\n\n const enabled = observerSnapshot.isEnabled\n const rows =\n enabled && Array.isArray(observerSnapshot.data)\n ? (observerSnapshot.data as ReadonlyArray<T>)\n : []\n const totalRequested = this.committedPageCount * this.pageSize\n const computedHasNextPage = enabled && rows.length > totalRequested\n const hasNextPage = this.hasPaginationError\n ? this.failedHasNextPage\n : computedHasNextPage\n\n const pageCount = enabled ? this.committedPageCount : 0\n const pages: Array<ReadonlyArray<T>> = []\n const pageParams: Array<number> = []\n for (let i = 0; i < pageCount; i++) {\n pages.push(rows.slice(i * this.pageSize, (i + 1) * this.pageSize))\n pageParams.push(this.initialPageParam + i)\n }\n\n const status = this.hasPaginationError ? `error` : observerSnapshot.status\n const statusFlags = this.hasPaginationError\n ? getLiveQueryStatusFlags(`error`)\n : observerSnapshot\n this.cachedSnapshot = {\n data: rows.slice(0, totalRequested),\n pages,\n pageParams,\n hasNextPage,\n isFetchingNextPage: this.isFetchingNextPage,\n error: this.hasPaginationError ? this.paginationError : undefined,\n state: observerSnapshot.state,\n collection: observerSnapshot.collection,\n status,\n isLoading: statusFlags.isLoading,\n isReady: statusFlags.isReady,\n persistedStatus: observerSnapshot.persistedStatus,\n isPersistedReady: observerSnapshot.isPersistedReady,\n persistedError: observerSnapshot.persistedError,\n isIdle: statusFlags.isIdle,\n isError: statusFlags.isError,\n isCleanedUp: observerSnapshot.isCleanedUp,\n isEnabled: observerSnapshot.isEnabled,\n }\n this.cachedFrom = {\n observerSnapshot,\n committedPageCount: this.committedPageCount,\n isFetchingNextPage: this.isFetchingNextPage,\n hasPaginationError: this.hasPaginationError,\n paginationError: this.paginationError,\n failedHasNextPage: this.failedHasNextPage,\n }\n return this.cachedSnapshot\n }\n\n subscribe(listener: () => void): () => void {\n if (this.disposed) throw new LiveQueryWindowControllerDisposedError()\n\n const record: SubscriptionRecord = { listener, active: true }\n this.subscriptions.add(record)\n if (this.subscriptions.size === 1) {\n this.restoreInitialWindowOnRelease = false\n this.blockDelivery = true\n let observerUnsub: (() => void) | null = null\n try {\n // Store the desired physical window before observer activation can\n // compile or restart the live-query pipeline.\n const windowResult = this.ensureLeaseActive(this.committedPageCount)\n const leaseGeneration = this.leaseGeneration\n observerUnsub = this.observer.subscribe(() => this.notify())\n this.observerUnsub = observerUnsub\n if (windowResult !== true) {\n this.trackAttachmentFailure(windowResult, leaseGeneration)\n }\n } catch (error) {\n observerUnsub?.()\n this.observerUnsub = null\n this.deactivateLease(true)\n record.active = false\n this.subscriptions.delete(record)\n throw error\n } finally {\n this.blockDelivery = false\n }\n }\n\n return () => {\n if (!record.active) return\n record.active = false\n this.subscriptions.delete(record)\n if (this.subscriptions.size === 0) {\n this.restoreInitialWindowOnRelease = true\n this.observerUnsub?.()\n this.observerUnsub = null\n if (this.inFlightLeaseHolders === 0) this.deactivateLease(true)\n }\n }\n }\n\n fetchNextPage(): Promise<void> {\n if (this.disposed) return Promise.resolve()\n if (this.activeFetchPromise) {\n return this.activeFetchPromise\n }\n const snapshot = this.getSnapshot()\n const awaitingInitialLoad = snapshot.isLoading || snapshot.isIdle\n if (!snapshot.hasNextPage && !awaitingInitialLoad) return Promise.resolve()\n\n let resolveFetch!: () => void\n let rejectFetch!: (error: unknown) => void\n const activeFetchPromise = new Promise<void>((resolve, reject) => {\n resolveFetch = resolve\n rejectFetch = reject\n })\n this.activeFetchPromise = activeFetchPromise\n\n let request: Promise<void>\n try {\n const generation = this.windowGeneration\n // An unpublished initial snapshot cannot establish that there is no next\n // page. Keep one fetch pending, then decide from the settled first page.\n request = awaitingInitialLoad\n ? this.preload().then(() => {\n if (\n this.disposed ||\n generation !== this.windowGeneration ||\n !this.getSnapshot().hasNextPage\n ) {\n return\n }\n return this.requestPageCount(this.committedPageCount + 1, true)\n })\n : this.requestPageCount(this.committedPageCount + 1, true)\n } catch (error) {\n this.activeFetchPromise = null\n rejectFetch(error)\n return activeFetchPromise\n }\n void request.then(\n () => {\n if (this.activeFetchPromise === activeFetchPromise) {\n this.activeFetchPromise = null\n }\n resolveFetch()\n },\n (error: unknown) => {\n if (this.activeFetchPromise === activeFetchPromise) {\n this.activeFetchPromise = null\n }\n rejectFetch(error)\n },\n )\n return activeFetchPromise\n }\n\n reset(): Promise<void> {\n if (this.disposed) return Promise.resolve()\n if (\n this.committedPageCount === 1 &&\n !this.hasPaginationError &&\n !this.isFetchingNextPage &&\n !this.activeFetchPromise &&\n this.pendingWindowGeneration === undefined\n ) {\n return Promise.resolve()\n }\n this.activeFetchPromise = null\n return this.requestPageCount(1, false)\n }\n\n async preload(): Promise<void> {\n if (this.disposed) throw new LiveQueryWindowControllerDisposedError()\n\n const hadPaginationError = this.hasPaginationError\n this.hasPaginationError = false\n this.paginationError = undefined\n this.acquireInFlightLease()\n try {\n const result = this.ensureLeaseActive(this.committedPageCount)\n if (result !== true) await result\n await this.observer.preload()\n this.failedHasNextPage = false\n if (hadPaginationError) this.notify()\n } catch (error) {\n this.hasPaginationError = true\n this.paginationError = error\n this.failedHasNextPage = this.getComputedHasNextPage()\n this.notify()\n throw error\n } finally {\n this.releaseInFlightLease()\n }\n }\n\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.windowGeneration++\n this.pendingWindowGeneration = undefined\n this.observerUnsub?.()\n this.observerUnsub = null\n this.deactivateLease(true)\n this.observer.dispose()\n for (const record of this.subscriptions) record.active = false\n this.subscriptions.clear()\n this.publicationQueue.length = 0\n }\n\n private requestPageCount(\n requestedPageCount: number,\n fetchingNextPage: boolean,\n ): Promise<void> {\n const generation = ++this.windowGeneration\n const previousHasNextPage = this.getSnapshot().hasNextPage\n this.pendingWindowGeneration = undefined\n this.acquireInFlightLease()\n\n this.beginTransition()\n this.isFetchingNextPage = fetchingNextPage\n this.hasPaginationError = false\n this.paginationError = undefined\n if (fetchingNextPage) this.notify()\n\n let result: WindowResult\n try {\n result = this.activateLease(requestedPageCount)\n } catch (error) {\n this.isFetchingNextPage = false\n this.hasPaginationError = true\n this.paginationError = error\n this.failedHasNextPage = previousHasNextPage\n this.notify()\n this.endTransition()\n this.releaseInFlightLease()\n return Promise.reject(error)\n }\n\n if (result === true) {\n if (!this.disposed && generation === this.windowGeneration) {\n this.committedPageCount = requestedPageCount\n this.isFetchingNextPage = false\n this.notify()\n }\n this.endTransition()\n this.releaseInFlightLease()\n return Promise.resolve()\n }\n\n this.pendingWindowGeneration = generation\n this.endTransition()\n\n return result\n .then(\n () => {\n if (this.disposed || generation !== this.windowGeneration) return\n this.beginTransition()\n this.pendingWindowGeneration = undefined\n this.committedPageCount = requestedPageCount\n this.isFetchingNextPage = false\n this.failedHasNextPage = this.getComputedHasNextPage()\n this.notify()\n this.endTransition()\n },\n (error: unknown) => {\n if (!this.disposed && generation === this.windowGeneration) {\n this.beginTransition()\n this.pendingWindowGeneration = undefined\n this.isFetchingNextPage = false\n this.hasPaginationError = true\n this.paginationError = error\n this.failedHasNextPage = previousHasNextPage\n this.notify()\n this.endTransition()\n }\n throw error\n },\n )\n .finally(() => {\n this.releaseInFlightLease()\n })\n }\n\n private acquireInFlightLease(): void {\n this.inFlightLeaseHolders++\n }\n\n private releaseInFlightLease(): void {\n this.inFlightLeaseHolders--\n if (this.inFlightLeaseHolders === 0 && this.subscriptions.size === 0) {\n this.deactivateLease(this.restoreInitialWindowOnRelease)\n }\n }\n\n private activateLease(pageCount: number): WindowResult {\n this.leaseGeneration++\n if (!this.coordinator || !this.collection) return true\n this.leaseActive = true\n return this.coordinator.request(this.lease, pageCount * this.pageSize + 1)\n }\n\n private ensureLeaseActive(pageCount: number): WindowResult {\n const minimumLimit = pageCount * this.pageSize + 1\n if (this.leaseActive) {\n const result = this.coordinator?.getLeaseResult(this.lease, minimumLimit)\n if (result) return result\n }\n return this.activateLease(pageCount)\n }\n\n private deactivateLease(restoreWhenEmpty = false): void {\n if (!this.leaseActive || !this.coordinator) return\n this.leaseGeneration++\n this.leaseActive = false\n this.restoreInitialWindowOnRelease = false\n this.coordinator.release(this.lease, restoreWhenEmpty)\n }\n\n private trackAttachmentFailure(\n result: Promise<void>,\n leaseGeneration: number,\n ): void {\n void result.catch((error: unknown) => {\n if (\n this.disposed ||\n !this.leaseActive ||\n leaseGeneration !== this.leaseGeneration\n ) {\n return\n }\n this.beginTransition()\n this.hasPaginationError = true\n this.paginationError = error\n this.failedHasNextPage = this.getComputedHasNextPage()\n this.notify()\n this.endTransition()\n })\n }\n\n private getComputedHasNextPage(\n snapshot: LiveQuerySnapshot<T, TKey> = this.observer.getSnapshot(),\n ): boolean {\n return (\n snapshot.isEnabled &&\n Array.isArray(snapshot.data) &&\n snapshot.data.length > this.committedPageCount * this.pageSize\n )\n }\n\n private beginTransition(): void {\n this.transitionDepth++\n }\n\n private endTransition(): void {\n this.transitionDepth--\n if (this.transitionDepth === 0 && this.transitionNeedsNotify) {\n this.transitionNeedsNotify = false\n this.publish()\n }\n }\n\n private notify(): void {\n if (this.transitionDepth > 0) {\n this.transitionNeedsNotify = true\n return\n }\n this.publish()\n }\n\n private publish(): void {\n if (this.disposed || this.blockDelivery || this.subscriptions.size === 0) {\n return\n }\n\n this.publicationQueue.push({ targets: [...this.subscriptions] })\n if (this.dispatching) return\n\n this.dispatching = true\n try {\n while (this.publicationQueue.length > 0) {\n const publication = this.publicationQueue.shift()!\n for (const record of publication.targets) {\n if (this.hasBeenDisposed()) return\n if (!record.active) continue\n record.listener()\n }\n }\n } finally {\n this.dispatching = false\n }\n }\n\n private hasBeenDisposed(): boolean {\n return this.disposed\n }\n}\n\n/**\n * Create an internal forward-window controller for an ordered live query.\n *\n * @internal This factory is unstable while RFC #1623 is being implemented.\n */\nexport function createLiveQueryWindowController<\n T extends object,\n TKey extends string | number,\n>(\n collection: Collection<T, TKey, any> | null | undefined,\n options: CreateLiveQueryWindowControllerOptions = {},\n): LiveQueryWindowController<T, TKey> {\n return new LiveQueryWindowControllerImpl<T, TKey>(collection ?? null, options)\n}\n"],"names":["isCollection","BaseQueryBuilder","leases","leaseVersions","shouldCaptureBaseline","leaseVersion","retainedWindow","baselineWindow","applyDesiredWindow","rollbackLease","appliedLimit","restoreInitialWindow","getDesiredLimit","SetWindowRequiresOrderByError","isSingleResultCollection","index","deepEquals","lease","activeFetchPromise","windowGeneration","leaseActive","leaseGeneration","inFlightLeaseHolders","restoreInitialWindowOnRelease","publicationQueue","dispatching","blockDelivery","transitionDepth","transitionNeedsNotify","observerUnsub","cachedSnapshot","cachedFrom","createLiveQueryObserver","getComputedHasNextPage","getLiveQueryStatusFlags","LiveQueryWindowControllerDisposedError","ensureLeaseActive","trackAttachmentFailure","deactivateLease","requestPageCount","pendingWindowGeneration","acquireInFlightLease","releaseInFlightLease","beginTransition","activateLease","endTransition","hasBeenDisposed"],"mappings":"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"}