UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines • 53.4 kB
{"version":3,"file":"sync.cjs","sources":["../../../src/collection/sync.ts"],"sourcesContent":["import {\n  CollectionConfigurationError,\n  CollectionIsInErrorStateError,\n  CollectionPreloadAbortedError,\n  DuplicateKeySyncError,\n  LoadSubsetOperationAbortedError,\n  NoPendingSyncTransactionCommitError,\n  NoPendingSyncTransactionWriteError,\n  SyncCleanupError,\n  SyncTransactionAlreadyCommittedError,\n  SyncTransactionAlreadyCommittedWriteError,\n} from '../errors'\nimport { createDeferred } from '../deferred'\nimport { isPromiseLike } from '../utils/type-guards'\nimport { LIVE_QUERY_INTERNAL } from '../query/live/internal.js'\nimport type { StandardSchemaV1 } from '@standard-schema/spec'\nimport type {\n  ChangeMessageOrDeleteKeyMessage,\n  CleanupFn,\n  CollectionConfig,\n  LoadSubsetFn,\n  LoadSubsetOptions,\n  LoadSubsetRequestResult,\n  OptimisticChangeMessage,\n  SyncConfigRes,\n  SyncMetadataApi,\n} from '../types'\nimport type { CollectionImpl } from './index.js'\nimport type { CollectionStateManager } from './state'\nimport type { CollectionLifecycleManager } from './lifecycle'\nimport type { CollectionEventsManager } from './events.js'\nimport type { LiveQueryCollectionUtils } from '../query/live/collection-config-builder.js'\nimport type { Deferred } from '../deferred'\n\ntype DeferredLoadSubset = {\n  options: LoadSubsetOptions\n  deferred: Deferred<void>\n}\n\ntype LoadSubsetOperation = {\n  pending: Set<Promise<unknown>>\n  waiting: boolean\n  completed: boolean\n  hasError: boolean\n  error?: unknown\n  deferred?: Deferred<void>\n}\n\nexport class CollectionSyncManager<\n  TOutput extends object = Record<string, unknown>,\n  TKey extends string | number = string | number,\n  TSchema extends StandardSchemaV1 = StandardSchemaV1,\n  TInput extends object = TOutput,\n> {\n  private collection!: CollectionImpl<TOutput, TKey, any, TSchema, TInput>\n  private state!: CollectionStateManager<TOutput, TKey, TSchema, TInput>\n  private lifecycle!: CollectionLifecycleManager<TOutput, TKey, TSchema, TInput>\n  private _events!: CollectionEventsManager\n  private config!: CollectionConfig<TOutput, TKey, TSchema, any>\n  private id: string\n  private syncMode: `eager` | `on-demand`\n\n  public preloadPromise: Promise<void> | null = null\n  private rejectPreload?: (error: unknown) => void\n  public syncCleanupFn: CleanupFn | null = null\n  public syncLoadSubsetFn: LoadSubsetFn | null = null\n  public syncUnloadSubsetFn: ((options: LoadSubsetOptions) => void) | null =\n    null\n\n  private pendingLoadSubsetPromises: Set<Promise<unknown>> = new Set()\n  private activeLoadSubsetOperation: LoadSubsetOperation | undefined\n  private loadSubsetOperations = new Set<LoadSubsetOperation>()\n  private syncStartDeferred = false\n  private syncStartRequested = false\n  private deferredLoadSubsets: Array<DeferredLoadSubset> = []\n  // Fences callbacks retained across reentrant sync entry and cleanup. This\n  // changes at both boundaries; syncRunGeneration changes only at cleanup.\n  private syncCallbackEpoch = 0\n  private syncRunGeneration = 0\n  private syncEntryActive = false\n  private pendingSyncEntryCleanup:\n    | {\n        tasks: Array<Promise<void>>\n        failure?: { error: unknown }\n        onSettled?: (failure?: { error: unknown }) => void\n        completion?: Deferred<void>\n      }\n    | undefined\n\n  /**\n   * Creates a new CollectionSyncManager instance\n   */\n  constructor(\n    config: CollectionConfig<TOutput, TKey, TSchema, any>,\n    id: string,\n  ) {\n    this.config = config\n    this.id = id\n    this.syncMode = config.syncMode ?? `eager`\n  }\n\n  setDeps(deps: {\n    collection: CollectionImpl<TOutput, TKey, any, TSchema, TInput>\n    state: CollectionStateManager<TOutput, TKey, TSchema, TInput>\n    lifecycle: CollectionLifecycleManager<TOutput, TKey, TSchema, TInput>\n    events: CollectionEventsManager\n  }) {\n    this.collection = deps.collection\n    this.state = deps.state\n    this.lifecycle = deps.lifecycle\n    this._events = deps.events\n  }\n\n  private createDuplicateKeyError(key: TKey): DuplicateKeySyncError {\n    const utils = this.config.utils as\n      | Partial<LiveQueryCollectionUtils>\n      | undefined\n    const internal = utils?.[LIVE_QUERY_INTERNAL]\n    return new DuplicateKeySyncError(key, this.id, {\n      hasCustomGetKey: internal?.hasCustomGetKey ?? false,\n      hasJoins: internal?.hasJoins ?? false,\n      hasDistinct: internal?.hasDistinct ?? false,\n    })\n  }\n\n  /** Mark the active sync transaction as changing collection layout. */\n  public markLayoutChange(): void {\n    this.getActivePendingSyncTransaction().layoutChanged = true\n  }\n\n  /**\n   * Start the sync process for this collection\n   * This is called when the collection is first accessed or preloaded\n   */\n  public startSync(): void {\n    this.lifecycle.assertCanStartSync()\n    if (\n      this.lifecycle.status !== `idle` &&\n      this.lifecycle.status !== `cleaned-up`\n    ) {\n      return // Already started or in progress\n    }\n\n    if (this.syncStartDeferred) {\n      this.syncStartRequested = true\n      return\n    }\n\n    const syncCallbackEpoch = ++this.syncCallbackEpoch\n    const isCurrentSync = () => syncCallbackEpoch === this.syncCallbackEpoch\n    this.lifecycle.setStatus(`loading`)\n    if (!isCurrentSync()) return\n    let syncEntryActive = true\n    let readyEffectFailure: { error: unknown } | undefined\n\n    this.syncEntryActive = true\n    try {\n      const syncRes = normalizeSyncFnResult(\n        this.config.sync.sync({\n          collection: this.collection,\n          begin: (options?: { immediate?: boolean }) => {\n            if (!isCurrentSync()) return\n            const applied = createDeferred<void>()\n            // A source may ignore a stream receipt. Keep cancellation from\n            // becoming an unhandled rejection while preserving the original\n            // promise's rejection for callers that do await it.\n            void applied.promise.catch(() => undefined)\n            this.state.pendingSyncedTransactions.push({\n              committed: false,\n              applicationStarted: false,\n              layoutChanged: false,\n              operations: [],\n              rowMetadataWrites: new Map(),\n              explicitRowMetadataWriteKeys: new Set(),\n              collectionMetadataWrites: new Map(),\n              immediate: options?.immediate,\n              applied,\n              duplicateKeyError: (key) => this.createDuplicateKeyError(key),\n            })\n          },\n          write: (\n            messageWithOptionalKey: ChangeMessageOrDeleteKeyMessage<\n              TOutput,\n              TKey\n            >,\n          ) => {\n            if (!isCurrentSync()) return\n            const pendingTransaction =\n              this.state.pendingSyncedTransactions[\n                this.state.pendingSyncedTransactions.length - 1\n              ]\n            if (!pendingTransaction) {\n              throw new NoPendingSyncTransactionWriteError()\n            }\n            if (pendingTransaction.committed) {\n              throw new SyncTransactionAlreadyCommittedWriteError()\n            }\n            // Cancellation can invalidate an open transaction between writes.\n            // Its commit receipt owns that failure; later writes cannot revive it.\n            if (pendingTransaction.invalidationError !== undefined) return\n\n            let key: TKey | undefined = undefined\n            if (`key` in messageWithOptionalKey) {\n              key = messageWithOptionalKey.key\n            } else {\n              key = this.config.getKey(messageWithOptionalKey.value)\n            }\n\n            let messageType = messageWithOptionalKey.type\n\n            // Check if an item with this key already exists when inserting\n            if (messageWithOptionalKey.type === `insert`) {\n              const disposition = this.state.classifyPendingSyncedInsert(\n                key,\n                messageWithOptionalKey.value,\n              )\n              if (disposition === `duplicate`)\n                throw this.createDuplicateKeyError(key)\n              messageType = disposition\n            }\n\n            const message = {\n              ...messageWithOptionalKey,\n              type: messageType,\n              key,\n              originalSyncType:\n                messageWithOptionalKey.type === `insert`\n                  ? (`insert` as const)\n                  : undefined,\n            } as OptimisticChangeMessage<TOutput, TKey> & {\n              originalSyncType?: `insert`\n            }\n            pendingTransaction.operations.push(message)\n            this.state.stagePendingSyncOperation(message)\n\n            if (messageType === `delete`) {\n              pendingTransaction.rowMetadataWrites.set(key, { type: `delete` })\n            } else if (messageType === `insert`) {\n              if (message.metadata !== undefined) {\n                pendingTransaction.rowMetadataWrites.set(key, {\n                  type: `set`,\n                  value: message.metadata,\n                })\n              } else {\n                pendingTransaction.rowMetadataWrites.set(key, {\n                  type: `delete`,\n                })\n              }\n            } else if (message.metadata !== undefined) {\n              pendingTransaction.rowMetadataWrites.set(key, {\n                type: `set`,\n                value: message.metadata,\n              })\n            }\n          },\n          commit: (signal?: AbortSignal) => {\n            if (!isCurrentSync()) return true\n            const pendingTransaction =\n              this.state.pendingSyncedTransactions[\n                this.state.pendingSyncedTransactions.length - 1\n              ]\n            if (!pendingTransaction) {\n              throw new NoPendingSyncTransactionCommitError()\n            }\n            if (pendingTransaction.committed) {\n              throw new SyncTransactionAlreadyCommittedError()\n            }\n\n            if (signal?.aborted) {\n              this.state.cancelPendingSyncedTransaction(pendingTransaction)\n              return pendingTransaction.applied.promise\n            }\n\n            if (pendingTransaction.invalidationError !== undefined) {\n              this.state.cancelPendingSyncedTransaction(\n                pendingTransaction,\n                pendingTransaction.invalidationError,\n              )\n              return pendingTransaction.applied.promise\n            }\n\n            pendingTransaction.committed = true\n\n            const cancel = () => {\n              this.state.cancelPendingSyncedTransaction(pendingTransaction)\n            }\n            signal?.addEventListener(`abort`, cancel, { once: true })\n\n            this.state.commitPendingTransactions()\n            if (!pendingTransaction.applied.isPending()) {\n              signal?.removeEventListener(`abort`, cancel)\n              return true\n            }\n\n            const receipt = pendingTransaction.applied.promise\n            if (signal) {\n              const removeAbortListener = () => {\n                signal.removeEventListener(`abort`, cancel)\n              }\n              void receipt.then(removeAbortListener, removeAbortListener)\n            }\n            return receipt\n          },\n          markReady: () => {\n            if (!isCurrentSync()) return\n            if (syncEntryActive) {\n              readyEffectFailure ??= this.lifecycle.markReadyDuringSyncStart()\n            } else {\n              this.lifecycle.markReady()\n            }\n          },\n          markError: (error?: unknown) => {\n            if (isCurrentSync()) this.lifecycle.markError(error)\n          },\n          truncate: () => {\n            if (!isCurrentSync()) return\n            const pendingTransaction =\n              this.state.pendingSyncedTransactions[\n                this.state.pendingSyncedTransactions.length - 1\n              ]\n            if (!pendingTransaction) {\n              throw new NoPendingSyncTransactionWriteError()\n            }\n            if (pendingTransaction.committed) {\n              throw new SyncTransactionAlreadyCommittedWriteError()\n            }\n\n            // Clear all operations from the current transaction\n            pendingTransaction.operations = []\n            pendingTransaction.rowMetadataWrites.clear()\n            pendingTransaction.explicitRowMetadataWriteKeys?.clear()\n            pendingTransaction.invalidationError = undefined\n            // Intentionally preserve collectionMetadataWrites across truncate.\n            // Collection-scoped metadata (for example persisted resume/reset\n            // state) can be staged before truncate and should commit atomically\n            // with the truncate transaction.\n\n            // Mark the transaction as a truncate operation. During commit, this triggers:\n            // - Delete events for all previously synced keys (excluding optimistic-deleted keys)\n            // - Clearing of syncedData/syncedMetadata\n            // - Subsequent synced ops applied on the fresh base\n            // - Finally, optimistic mutations re-applied on top (single batch)\n            pendingTransaction.truncate = true\n            this.state.refreshPendingSyncedProjection()\n\n            pendingTransaction.optimisticSnapshot =\n              this.state.captureTruncateOptimisticSnapshot()\n          },\n          metadata: this.createSyncMetadataApi(isCurrentSync),\n        }),\n      )\n      this.syncEntryActive = false\n      syncEntryActive = false\n\n      if (!isCurrentSync()) {\n        if (syncRes?.cleanup) {\n          this.registerPendingSyncEntryCleanup(syncRes.cleanup)\n        }\n        this.completePendingSyncEntryCleanup()\n        if (readyEffectFailure) throw readyEffectFailure.error\n        return\n      }\n\n      // Store cleanup function if provided\n      this.syncCleanupFn = syncRes?.cleanup ?? null\n\n      // Store loadSubset function if provided\n      this.syncLoadSubsetFn = syncRes?.loadSubset ?? null\n\n      // Store unloadSubset function if provided\n      this.syncUnloadSubsetFn = syncRes?.unloadSubset ?? null\n\n      // Validate: on-demand mode requires a loadSubset function\n      if (this.syncMode === `on-demand` && !this.syncLoadSubsetFn) {\n        throw new CollectionConfigurationError(\n          `Collection \"${this.id}\" is configured with syncMode \"on-demand\" but the sync function did not return a loadSubset handler. ` +\n            `Either provide a loadSubset handler or use syncMode \"eager\".`,\n        )\n      }\n\n      // Every route into sync passes through here, so it is the one place\n      // that sees sync start ahead of the subscriber that would justify it.\n      // `addSubscriber` counts itself in before calling us, so a subscription\n      // starting sync leaves the timer alone.\n      this.lifecycle.startGCTimerIfUnsubscribed()\n    } catch (error) {\n      this.syncEntryActive = false\n      this.completePendingSyncEntryCleanup()\n      syncEntryActive = false\n      if (isCurrentSync()) this.lifecycle.markError(error)\n      throw error\n    }\n    if (readyEffectFailure) throw readyEffectFailure.error\n  }\n\n  public deferStart(): boolean {\n    if (\n      this.lifecycle.status !== `idle` &&\n      this.lifecycle.status !== `cleaned-up`\n    ) {\n      return false\n    }\n\n    this.syncStartDeferred = true\n    return true\n  }\n\n  public resumeStart(): void {\n    if (!this.syncStartDeferred) {\n      return\n    }\n\n    this.syncStartDeferred = false\n    const shouldStart =\n      this.syncStartRequested || this.deferredLoadSubsets.length > 0\n    this.syncStartRequested = false\n    const deferredLoadSubsets = this.deferredLoadSubsets\n    this.deferredLoadSubsets = []\n    const syncRunGeneration = this.syncRunGeneration\n\n    try {\n      if (shouldStart) {\n        this.startSync()\n      }\n    } catch (error) {\n      for (const { deferred } of deferredLoadSubsets) {\n        deferred.reject(error)\n      }\n      throw error\n    }\n\n    for (const { options, deferred } of deferredLoadSubsets) {\n      const loadSubset = this.syncLoadSubsetFn\n      try {\n        if (\n          syncRunGeneration !== this.syncRunGeneration ||\n          options.signal?.aborted\n        ) {\n          throw new LoadSubsetOperationAbortedError()\n        }\n        const result = loadSubset?.(options) ?? true\n        if (result instanceof Promise) {\n          void result.then(\n            (sourceResult) => deferred.resolve(sourceResult),\n            (error: unknown) => deferred.reject(error),\n          )\n        } else {\n          deferred.resolve(undefined)\n        }\n      } catch (error) {\n        deferred.reject(error)\n      }\n    }\n  }\n\n  private getActivePendingSyncTransaction() {\n    const pendingTransaction =\n      this.state.pendingSyncedTransactions[\n        this.state.pendingSyncedTransactions.length - 1\n      ]\n\n    if (!pendingTransaction) {\n      throw new NoPendingSyncTransactionWriteError()\n    }\n    if (pendingTransaction.committed) {\n      throw new SyncTransactionAlreadyCommittedWriteError()\n    }\n\n    return pendingTransaction\n  }\n\n  private createSyncMetadataApi(\n    isCurrentSync: () => boolean,\n  ): SyncMetadataApi<TKey> {\n    return {\n      persistence: null,\n      row: {\n        get: (key) => {\n          if (!isCurrentSync()) return undefined\n          const pendingTransaction =\n            this.state.pendingSyncedTransactions[\n              this.state.pendingSyncedTransactions.length - 1\n            ]\n          const pendingWrite = pendingTransaction?.rowMetadataWrites.get(key)\n          if (pendingWrite) {\n            return pendingWrite.type === `delete`\n              ? undefined\n              : pendingWrite.value\n          }\n          if (pendingTransaction?.truncate) {\n            return undefined\n          }\n          return this.state.syncedMetadata.get(key)\n        },\n        set: (key, metadata) => {\n          if (!isCurrentSync()) return\n          const pendingTransaction = this.getActivePendingSyncTransaction()\n          pendingTransaction.explicitRowMetadataWriteKeys?.add(key)\n          pendingTransaction.rowMetadataWrites.set(key, {\n            type: `set`,\n            value: metadata,\n          })\n        },\n        delete: (key) => {\n          if (!isCurrentSync()) return\n          const pendingTransaction = this.getActivePendingSyncTransaction()\n          pendingTransaction.explicitRowMetadataWriteKeys?.add(key)\n          pendingTransaction.rowMetadataWrites.set(key, {\n            type: `delete`,\n          })\n        },\n      },\n      collection: {\n        get: (key) => {\n          if (!isCurrentSync()) return undefined\n          const pendingTransaction =\n            this.state.pendingSyncedTransactions[\n              this.state.pendingSyncedTransactions.length - 1\n            ]\n          const pendingWrite =\n            pendingTransaction?.collectionMetadataWrites.get(key)\n          if (pendingWrite) {\n            return pendingWrite.type === `delete`\n              ? undefined\n              : pendingWrite.value\n          }\n          return this.state.syncedCollectionMetadata.get(key)\n        },\n        set: (key, value) => {\n          if (!isCurrentSync()) return\n          const pendingTransaction = this.getActivePendingSyncTransaction()\n          pendingTransaction.collectionMetadataWrites.set(key, {\n            type: `set`,\n            value,\n          })\n        },\n        delete: (key) => {\n          if (!isCurrentSync()) return\n          const pendingTransaction = this.getActivePendingSyncTransaction()\n          pendingTransaction.collectionMetadataWrites.set(key, {\n            type: `delete`,\n          })\n        },\n        list: (prefix) => {\n          if (!isCurrentSync()) return []\n          const merged = new Map(this.state.syncedCollectionMetadata)\n          const pendingTransaction =\n            this.state.pendingSyncedTransactions[\n              this.state.pendingSyncedTransactions.length - 1\n            ]\n          if (pendingTransaction) {\n            for (const [\n              key,\n              pendingWrite,\n            ] of pendingTransaction.collectionMetadataWrites) {\n              if (pendingWrite.type === `delete`) {\n                merged.delete(key)\n              } else {\n                merged.set(key, pendingWrite.value)\n              }\n            }\n          }\n\n          return Array.from(merged.entries())\n            .filter(([key]) => (prefix ? key.startsWith(prefix) : true))\n            .map(([key, value]) => ({\n              key,\n              value,\n            }))\n        },\n      },\n    }\n  }\n\n  /** Whether a caller is still waiting for the initial sync to finish. */\n  public get hasPendingPreload(): boolean {\n    return this.rejectPreload !== undefined\n  }\n\n  /**\n   * Preload the collection data by starting sync if not already started\n   * Multiple concurrent calls will share the same promise\n   */\n  public preload(): Promise<void> {\n    try {\n      this.lifecycle.assertCanStartSync()\n    } catch (error) {\n      return Promise.reject(error)\n    }\n    // Warm preloads need the same handoff time as a load that just finished,\n    // including when the previous GC deadline already queued idle cleanup.\n    if (this.lifecycle.status === `ready`) {\n      this.lifecycle.cancelGCTimer()\n      this.lifecycle.startGCTimerIfUnsubscribed()\n    }\n    if (this.preloadPromise) {\n      return this.preloadPromise\n    }\n\n    // Warn when calling preload on an on-demand collection\n    if (this.syncMode === `on-demand`) {\n      console.warn(\n        `${this.id ? `[${this.id}] ` : ``}Calling .preload() on a collection with syncMode \"on-demand\" is a no-op. ` +\n          `In on-demand mode, data is only loaded when queries request it. ` +\n          `Instead, create a live query and call .preload() on that to load the specific data you need. ` +\n          `See https://tanstack.com/blog/tanstack-db-0.5-query-driven-sync for more details.`,\n      )\n    }\n\n    const attempt = new Promise<void>((resolve, reject) => {\n      if (this.lifecycle.status === `ready`) {\n        resolve()\n        return\n      }\n\n      if (this.lifecycle.status === `error`) {\n        reject(this.getPreloadError())\n        return\n      }\n\n      let settled = false\n      const syncStartState = { active: false, ready: false }\n      let unsubscribeError = () => {}\n      let unsubscribeReady = () => {}\n      const finishPreload = () => {\n        settled = true\n        unsubscribeError()\n        unsubscribeReady()\n        if (this.rejectPreload === rejectError) this.rejectPreload = undefined\n        this.lifecycle.startGCTimerIfUnsubscribed()\n      }\n      const resolveReady = () => {\n        if (syncStartState.active) {\n          syncStartState.ready = true\n          return\n        }\n        if (settled) return\n        finishPreload()\n        resolve()\n      }\n      const rejectError = (error: unknown) => {\n        if (settled) return\n        finishPreload()\n        reject(error)\n      }\n\n      // Register callback BEFORE starting sync to avoid race condition\n      this.rejectPreload = rejectError\n      // An awaited preload owns this sync run until it settles, including\n      // when GC has already queued the destructive idle callback.\n      this.lifecycle.cancelGCTimer()\n      unsubscribeReady = this.lifecycle.onFirstReady(resolveReady)\n      unsubscribeError = this.collection.on(`status:error`, () => {\n        if (syncStartState.active) {\n          return\n        }\n        rejectError(this.getPreloadError())\n      })\n\n      // Start sync if collection hasn't started yet or was cleaned up\n      if (\n        this.lifecycle.status === `idle` ||\n        this.lifecycle.status === `cleaned-up`\n      ) {\n        syncStartState.active = true\n        let startFailure: { error: unknown } | undefined\n        try {\n          this.startSync()\n        } catch (error) {\n          startFailure = { error }\n        } finally {\n          syncStartState.active = false\n        }\n        if (this.collection.status === `error`) {\n          rejectError(this.getPreloadError())\n        } else if (syncStartState.ready) {\n          // A first-ready listener can throw after readiness is established.\n          // That failure still escapes direct startSync(), but preload follows\n          // the final collection state after synchronous adapter entry.\n          resolveReady()\n        } else if (startFailure) {\n          rejectError(startFailure.error)\n        }\n      }\n    })\n\n    this.preloadPromise = attempt\n    void attempt.then(undefined, () => {\n      if (this.preloadPromise === attempt) {\n        this.preloadPromise = null\n      }\n    })\n    return attempt\n  }\n\n  private getPreloadError(): unknown {\n    const syncError = this.lifecycle.getSyncError()\n    return syncError === undefined\n      ? new CollectionIsInErrorStateError()\n      : syncError\n  }\n\n  /**\n   * Gets whether the collection is currently loading more data\n   */\n  public get isLoadingSubset(): boolean {\n    return this.pendingLoadSubsetPromises.size > 0\n  }\n\n  /** @internal Observe subset requests caused by one imperative operation. */\n  public beginLoadSubsetOperation(): {\n    wait: () => true | Promise<void>\n    cancel: () => void\n  } {\n    const previousOperation = this.activeLoadSubsetOperation\n    const operation: LoadSubsetOperation = {\n      pending: new Set(),\n      waiting: false,\n      completed: false,\n      hasError: false,\n    }\n    // A new imperative operation owns future requests. Older operations keep\n    // waiting for the promises they already acquired, but cannot absorb work\n    // caused by a superseding physical window.\n    this.activeLoadSubsetOperation = operation\n    this.loadSubsetOperations.add(operation)\n    return {\n      wait: () => this.waitForLoadSubsetOperation(operation),\n      cancel: () => {\n        operation.completed = true\n        this.loadSubsetOperations.delete(operation)\n        if (this.activeLoadSubsetOperation === operation) {\n          this.activeLoadSubsetOperation = previousOperation?.completed\n            ? undefined\n            : previousOperation\n        }\n      },\n    }\n  }\n\n  private waitForLoadSubsetOperation(\n    operation: LoadSubsetOperation,\n  ): true | Promise<void> {\n    operation.waiting = true\n    if (operation.pending.size === 0) {\n      operation.completed = true\n      this.loadSubsetOperations.delete(operation)\n      if (this.activeLoadSubsetOperation === operation) {\n        this.activeLoadSubsetOperation = undefined\n      }\n      return operation.hasError ? Promise.reject(operation.error) : true\n    }\n    operation.deferred = createDeferred<void>()\n    return operation.deferred.promise\n  }\n\n  private settleLoadSubsetOperation(\n    operation: LoadSubsetOperation,\n    promise: Promise<unknown>,\n    outcome: { ok: true } | { ok: false; error: unknown },\n  ): void {\n    if (operation.completed) return\n    operation.pending.delete(promise)\n    if (!outcome.ok && !operation.hasError) {\n      operation.hasError = true\n      operation.error = outcome.error\n    }\n    if (!operation.waiting || operation.pending.size > 0) return\n\n    // A resolved request can synchronously publish source rows that register\n    // follow-up loads. Let those registrations join this operation before it\n    // is considered complete.\n    queueMicrotask(() => {\n      if (operation.completed || operation.pending.size > 0) return\n      operation.completed = true\n      this.loadSubsetOperations.delete(operation)\n      if (this.activeLoadSubsetOperation === operation) {\n        this.activeLoadSubsetOperation = undefined\n      }\n      if (operation.hasError) {\n        operation.deferred!.reject(operation.error)\n      } else {\n        operation.deferred!.resolve()\n      }\n    })\n  }\n\n  /** @internal Attach a relevant existing request to the active operation. */\n  public trackLoadSubsetOperationPromise(promise: Promise<unknown>): void {\n    const operation = this.activeLoadSubsetOperation\n    if (!operation || operation.pending.has(promise)) return\n\n    operation.pending.add(promise)\n    void promise.then(\n      () => this.settleLoadSubsetOperation(operation, promise, { ok: true }),\n      (error) =>\n        this.settleLoadSubsetOperation(operation, promise, {\n          ok: false,\n          error,\n        }),\n    )\n  }\n\n  /**\n   * Tracks a load promise for isLoadingSubset state.\n   * @internal This is for internal coordination (e.g., live-query glue code), not for general use.\n   */\n  public trackLoadPromise(promise: Promise<unknown>): void {\n    const syncRunGeneration = this.syncRunGeneration\n    const loadingStarting = !this.isLoadingSubset\n    this.pendingLoadSubsetPromises.add(promise)\n    this.trackLoadSubsetOperationPromise(promise)\n\n    if (loadingStarting) {\n      this._events.emit(`loadingSubset:change`, {\n        type: `loadingSubset:change`,\n        collection: this.collection,\n        isLoadingSubset: true,\n        previousIsLoadingSubset: false,\n        loadingSubsetTransition: `start`,\n      })\n    }\n\n    const finish = () => {\n      if (syncRunGeneration !== this.syncRunGeneration) return\n\n      const loadingEnding =\n        this.pendingLoadSubsetPromises.size === 1 &&\n        this.pendingLoadSubsetPromises.has(promise)\n      this.pendingLoadSubsetPromises.delete(promise)\n\n      if (loadingEnding) {\n        this._events.emit(`loadingSubset:change`, {\n          type: `loadingSubset:change`,\n          collection: this.collection,\n          isLoadingSubset: false,\n          previousIsLoadingSubset: true,\n          loadingSubsetTransition: `end`,\n        })\n      }\n    }\n    void promise.then(finish, finish)\n  }\n\n  /** @internal Generation fence for subscription-owned async work. */\n  public getSyncRunGeneration(): number {\n    return this.syncRunGeneration\n  }\n\n  /**\n   * Requests the sync layer to load more data.\n   * @param options Options to control what data is being loaded\n   * @returns If data loading is asynchronous, this method returns a promise that resolves when the data is loaded.\n   *          Returns true if no sync function is configured, if syncMode is 'eager', or if there is no work to do.\n   */\n  public loadSubset(options: LoadSubsetOptions): LoadSubsetRequestResult {\n    if (options.signal?.aborted) {\n      return Promise.reject(new LoadSubsetOperationAbortedError())\n    }\n\n    // Bypass loadSubset when syncMode is 'eager'\n    if (this.syncMode === `eager`) {\n      return true\n    }\n\n    if (this.syncStartDeferred) {\n      this.syncStartRequested = true\n      const deferred = createDeferred<void>()\n      this.deferredLoadSubsets.push({ options, deferred })\n      this.trackLoadPromise(deferred.promise)\n      return deferred.promise\n    }\n\n    if (this.syncLoadSubsetFn) {\n      const result = this.syncLoadSubsetFn(options)\n      // If the result is a promise, track it\n      if (result instanceof Promise) {\n        this.trackLoadPromise(result)\n        return result\n      }\n    }\n\n    return true\n  }\n\n  /**\n   * Notifies the sync layer that a subset is no longer needed.\n   * @param options Options that identify what data is being unloaded\n   */\n  public unloadSubset(options: LoadSubsetOptions): void {\n    // Eager loading bypasses subset acquisition, so there is no lease to release.\n    if (this.syncMode === `eager`) return\n\n    if (this.syncStartDeferred) {\n      this.deferredLoadSubsets = this.deferredLoadSubsets.filter((request) => {\n        if (request.options !== options) {\n          return true\n        }\n\n        request.deferred.reject(new LoadSubsetOperationAbortedError())\n        return false\n      })\n      return\n    }\n\n    if (this.syncUnloadSubsetFn) {\n      this.syncUnloadSubsetFn(options)\n    }\n  }\n\n  private wrapCleanupError(error: unknown): SyncCleanupError {\n    const wrappedError = new SyncCleanupError(this.id, error as Error | string)\n    wrappedError.cause = error\n    if (error instanceof Error) wrappedError.stack = error.stack\n    return wrappedError\n  }\n\n  private invokeCleanup(cleanup: CleanupFn | null): true | Promise<void> {\n    if (!cleanup) return true\n\n    try {\n      const result = cleanup()\n      if (!isPromiseLike(result)) return true\n      return Promise.resolve(result).then(\n        () => undefined,\n        (error: unknown) => {\n          throw this.wrapCleanupError(error)\n        },\n      )\n    } catch (error) {\n      throw this.wrapCleanupError(error)\n    }\n  }\n\n  private registerPendingSyncEntryCleanup(cleanup: CleanupFn): void {\n    const pending = this.pendingSyncEntryCleanup\n    if (!pending) return\n\n    try {\n      const result = this.invokeCleanup(cleanup)\n      if (result !== true) {\n        pending.tasks.push(result)\n        void result.catch(() => undefined)\n      }\n    } catch (error) {\n      pending.failure ??= { error }\n    }\n  }\n\n  private completePendingSyncEntryCleanup(): void {\n    const pending = this.pendingSyncEntryCleanup\n    if (!pending) return\n    this.pendingSyncEntryCleanup = undefined\n\n    const settle = (failure?: { error: unknown }) => {\n      const outcome = pending.failure ?? failure\n      pending.onSettled?.(outcome)\n      if (outcome) pending.completion?.reject(outcome.error)\n      else pending.completion?.resolve()\n    }\n\n    if (pending.tasks.length === 0) {\n      settle()\n      return\n    }\n\n    void Promise.allSettled(pending.tasks).then((outcomes) => {\n      const rejected = outcomes.find(\n        (outcome): outcome is PromiseRejectedResult =>\n          outcome.status === `rejected`,\n      )\n      settle(rejected ? { error: rejected.reason } : undefined)\n    })\n  }\n\n  public cleanup(): true | Promise<void>\n  public cleanup(onSettled: (failure?: { error: unknown }) => void): boolean\n  public cleanup(\n    onSettled?: (failure?: { error: unknown }) => void,\n  ): boolean | Promise<void> {\n    // Invalidate callbacks retained by asynchronous work from this sync run\n    // before invoking adapter cleanup or allowing a new sync run to start.\n    ++this.syncCallbackEpoch\n    this.syncRunGeneration++\n    this.rejectPreload?.(new CollectionPreloadAbortedError())\n    const cleanup = this.syncCleanupFn\n    this.syncCleanupFn = null\n    this.syncLoadSubsetFn = null\n    this.syncUnloadSubsetFn = null\n\n    let cleanupResult: true | Promise<void> = true\n    let cleanupFailure: { error: unknown } | undefined\n    try {\n      cleanupResult = this.invokeCleanup(cleanup)\n    } catch (error) {\n      cleanupFailure = { error }\n    }\n\n    this.preloadPromise = null\n    this.syncStartDeferred = false\n    this.syncStartRequested = false\n    const wasLoadingSubset = this.pendingLoadSubsetPromises.size > 0\n    this.pendingLoadSubsetPromises.clear()\n    if (wasLoadingSubset) {\n      this._events.emit(`loadingSubset:change`, {\n        type: `loadingSubset:change`,\n        collection: this.collection,\n        isLoadingSubset: false,\n        previousIsLoadingSubset: true,\n        loadingSubsetTransition: `end`,\n      })\n    }\n    this.activeLoadSubsetOperation = undefined\n    for (const operation of this.loadSubsetOperations) {\n      if (!operation.completed) {\n        operation.completed = true\n        operation.pending.clear()\n        operation.hasError = true\n        operation.error = new LoadSubsetOperationAbortedError()\n        operation.deferred?.reject(operation.error)\n      }\n    }\n    this.loadSubsetOperations.clear()\n    const deferredLoadSubsets = this.deferredLoadSubsets\n    this.deferredLoadSubsets = []\n    for (const request of deferredLoadSubsets) {\n      request.deferred.reject(new LoadSubsetOperationAbortedError())\n    }\n\n    if (this.syncEntryActive) {\n      const completion = onSettled ? undefined : createDeferred<void>()\n      const pending = {\n        tasks: [] as Array<Promise<void>>,\n        failure: cleanupFailure,\n        onSettled,\n        completion,\n      }\n      if (cleanupResult !== true) {\n        pending.tasks.push(cleanupResult)\n        void cleanupResult.catch(() => undefined)\n      }\n      this.pendingSyncEntryCleanup = pending\n      return onSettled ? false : completion!.promise\n    }\n\n    if (cleanupFailure) throw cleanupFailure.error\n    if (cleanupResult === true) return true\n\n    if (!onSettled) return cleanupResult\n    void cleanupResult.then(\n      () => onSettled(),\n      (error: unknown) => onSettled({ error }),\n    )\n    return false\n  }\n}\n\nfunction normalizeSyncFnResult(result: void | CleanupFn | SyncConfigRes) {\n  if (typeof result === `function`) {\n    return { cleanup: result }\n  }\n\n  if (typeof result === `object`) {\n    return result\n  }\n\n  return undefined\n}\n"],"names":["internal","LIVE_QUERY_INTERNAL","DuplicateKeySyncError","createDeferred","NoPendingSyncTransactionWriteError","SyncTransactionAlreadyCommittedWriteError","NoPendingSyncTransactionCommitError","SyncTransactionAlreadyCommittedError","CollectionConfigurationError","deferred","LoadSubsetOperationAbortedError","CollectionIsInErrorStateError","SyncCleanupError","isPromiseLike","CollectionPreloadAbortedError"],"mappings":"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"}