UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines 87.8 kB
{"version":3,"file":"subscription.cjs","sources":["../../../src/collection/subscription.ts"],"sourcesContent":["import { ensureIndexForExpression } from '../indexes/auto-index.js'\nimport { and, eq } from '../query/builder/functions.js'\nimport { PropRef, Value } from '../query/ir.js'\nimport { EventEmitter } from '../event-emitter.js'\nimport { compileExpression } from '../query/compiler/evaluators.js'\nimport { buildCursor, buildCursorCurrent } from '../utils/cursor.js'\nimport { deepEquals } from '../utils.js'\nimport { normalizeError } from '../utils/error.js'\nimport { runAllCallbacks } from '../utils/callbacks.js'\nimport { createDeferred } from '../deferred.js'\nimport { LoadSubsetOperationAbortedError } from '../errors.js'\nimport {\n  createFilterFunctionFromExpression,\n  createFilteredCallback,\n} from './change-events.js'\nimport type { BasicExpression, OrderBy } from '../query/ir.js'\nimport type { IndexReader } from '../indexes/base-index.js'\nimport type {\n  ChangeMessage,\n  LoadSubsetOptions,\n  LoadSubsetRequestResult,\n  Subscription,\n  SubscriptionEvents,\n  SubscriptionLoadSubsetErrorEvent,\n  SubscriptionStatus,\n  SubscriptionUnsubscribedEvent,\n} from '../types.js'\nimport type { CollectionImpl } from './index.js'\nimport type { Deferred } from '../deferred.js'\n\ntype RequestSnapshotOptions = {\n  where?: BasicExpression<boolean>\n  signal?: AbortSignal\n  optimizedOnly?: boolean\n  trackLoadSubsetPromise?: boolean\n  /** Optional orderBy to pass to loadSubset for backend optimization */\n  orderBy?: OrderBy\n  /** Optional limit to pass to loadSubset for backend optimization */\n  limit?: number\n  /** Callback that receives the normalized loadSubset result for internal tracking */\n  onLoadSubsetResult?: SubsetResultObserver\n  /** Called when the local snapshot must fall back from an index to a scan. */\n  onUnoptimized?: () => void\n}\n\ntype RequestLimitedSnapshotOptions = {\n  orderBy: OrderBy\n  limit: number\n  /** A single cursor value; composite cursor inputs are rejected. */\n  minValues?: Array<unknown>\n  /** Row offset for offset-based pagination (passed to sync layer) */\n  offset?: number\n  /** Whether to track the loadSubset promise on this subscription (default: true) */\n  trackLoadSubsetPromise?: boolean\n  /** Callback that receives the normalized loadSubset result for internal tracking */\n  onLoadSubsetResult?: SubsetResultObserver\n}\n\nexport type ReleaseLoadSubset = (primaryFailure?: { error: unknown }) => void\n\ntype SubsetResultObserver = (\n  result: LoadSubsetRequestResult,\n  options: LoadSubsetOptions,\n  release: ReleaseLoadSubset,\n) => void\n\ntype CollectionSubscriptionOptions = {\n  includeInitialState?: boolean\n  /** Pre-compiled expression for filtering changes */\n  whereExpression?: BasicExpression<boolean>\n  /** Callback to call when the subscription is unsubscribed */\n  onUnsubscribe?: (event: SubscriptionUnsubscribedEvent) => void\n  /** Callback for subset-load failures scoped to this subscription. */\n  onLoadSubsetError?: (event: SubscriptionLoadSubsetErrorEvent) => void\n  truncateReplayPublication?: TruncateReplayPublicationControl\n}\n\ntype TruncateReplayPublicationControl = Readonly<{\n  start: () => void\n  succeed: () => void\n}>\n\ntype TruncatePublicationState = {\n  loadedInitialState: boolean\n  snapshotSent: boolean\n  limitedSnapshotRowCount: number\n  lastSentKey: string | number | undefined\n}\n\ntype SubsetAcquisition = {\n  options: LoadSubsetOptions\n  loadSubsetSession: number\n  abortController?: AbortController\n  removeRequestAbortListener?: () => void\n  releaseAttempted?: true\n}\n\ntype SubsetDemand = {\n  requestOptions: LoadSubsetOptions\n  acquisition: SubsetAcquisition\n  acquisitionState: `starting` | `active` | `detached`\n  initialResult?: Deferred<void>\n}\n\ntype TruncateReplayAttempt = {\n  pendingCount: number\n  setupComplete: boolean\n}\n\ntype TruncateReplaySession = {\n  loadSubsetSession: number\n  publicationState: TruncatePublicationState\n  /** Direct subscribers buffer the replacement here; delegated publication has no buffer. */\n  privateRows: Map<string | number, object> | undefined\n  pending: Set<{ demand: SubsetDemand; attempt: TruncateReplayAttempt }>\n  pendingSetups: number\n  currentAttempt: TruncateReplayAttempt\n  failures: Map<SubsetDemand, Error>\n  completion: Deferred<void>\n}\n\nfunction createReplayCompletion(): Deferred<void> {\n  const completion = createDeferred<void>()\n  void completion.promise.catch(() => {})\n  return completion\n}\n\nfunction cancelAcquisition(acquisition: SubsetAcquisition): void {\n  acquisition.abortController?.abort()\n  acquisition.removeRequestAbortListener?.()\n}\n\nexport class CollectionSubscription\n  extends EventEmitter<SubscriptionEvents>\n  implements Subscription\n{\n  private loadedInitialState = false\n\n  // Flag to skip filtering in filterAndFlipChanges.\n  // This is separate from loadedInitialState because we want to allow\n  // requestSnapshot to still work even when filtering is skipped.\n  private skipFiltering = false\n\n  // Flag to indicate that we have sent at least 1 snapshot.\n  // While `snapshotSent` is false we filter out all changes from subscription to the collection.\n  private snapshotSent = false\n\n  /**\n   * Track all loadSubset calls made by this subscription so we can unload them on cleanup.\n   * We store the exact LoadSubsetOptions we passed to loadSubset to ensure symmetric unload.\n   */\n  private subsetDemands: Array<SubsetDemand> = []\n  private primaryFailureDeliveryDepth = 0\n  private readonly requestedSubsetWhere = new WeakMap<\n    LoadSubsetOptions,\n    BasicExpression<boolean>\n  >()\n\n  // Keep track of the keys we've sent (needed for join and orderBy optimizations)\n  private sentKeys = new Set<string | number>()\n  private publishedRows = new Map<string | number, object>()\n  private stalePublishedRows = new Map<string | number, object>()\n\n  // Track the count of rows sent via requestLimitedSnapshot for offset-based pagination\n  private limitedSnapshotRowCount = 0\n\n  // Track the last key sent via requestLimitedSnapshot for cursor-based pagination\n  private lastSentKey: string | number | undefined\n\n  private filteredCallback: (changes: Array<ChangeMessage<any, any>>) => boolean\n\n  private orderByIndex: IndexReader<string | number> | undefined\n\n  // Status tracking\n  private _status: SubscriptionStatus = `ready`\n  private statusRevision = 0\n  private _lastError: unknown | undefined\n  private pendingLoadSubsetParticipants = new Set<{\n    demand: SubsetDemand\n    promise: Promise<unknown>\n  }>()\n\n  // Cleanup function for truncate event listener\n  private truncateCleanup: (() => void) | undefined\n  private collectionCleanup: (() => void) | undefined\n  private collectionRestartCleanup: (() => void) | undefined\n\n  // One replay session owns the publication baseline, overlapping attempts,\n  // and buffered changes until every attempt settles.\n  private truncateReplaySession: TruncateReplaySession | undefined\n  private readonly loadSubsetPromiseErrors = new WeakMap<\n    Promise<unknown>,\n    Error\n  >()\n  private truncateReplacementPending = false\n  private unsubscribed = false\n\n  public get status(): SubscriptionStatus {\n    return this._status\n  }\n\n  public get lastError(): unknown | undefined {\n    return this._lastError\n  }\n\n  constructor(\n    private collection: CollectionImpl<any, any, any, any, any>,\n    private callback: (changes: Array<ChangeMessage<any, any>>) => void,\n    private options: CollectionSubscriptionOptions,\n  ) {\n    super()\n    if (options.onUnsubscribe) {\n      this.on(`unsubscribed`, options.onUnsubscribe)\n    }\n    if (options.onLoadSubsetError) {\n      this.on(`loadSubset:error`, options.onLoadSubsetError)\n    }\n\n    // Auto-index for where expressions if enabled\n    if (options.whereExpression) {\n      ensureIndexForExpression(options.whereExpression, this.collection)\n    }\n\n    const callbackWithSentKeysTracking = (\n      changes: Array<ChangeMessage<any, any>>,\n    ) => {\n      this.trackPublishedRows(changes)\n      this.trackSentKeys(changes)\n      callback(changes)\n    }\n\n    this.callback = callbackWithSentKeysTracking\n\n    // Create a filtered callback if where clause is provided\n    this.filteredCallback = options.whereExpression\n      ? createFilteredCallback(this.callback, options)\n      : (changes) => {\n          this.callback(changes)\n          return true\n        }\n\n    // Listen for truncate events to re-request data after must-refetch\n    // When a truncate happens (e.g., from a 409 must-refetch), all collection data is cleared.\n    // We need to re-request all previously loaded subsets to repopulate the data.\n    this.truncateCleanup = this.collection.on(`truncate`, () => {\n      this.handleTruncate()\n    })\n    this.collectionCleanup = this.collection.on(`status:cleaned-up`, () => {\n      this.handleCollectionCleanup()\n    })\n    this.collectionRestartCleanup = this.collection.on(\n      `status:change`,\n      ({ status }) => {\n        if (status !== `loading` && status !== `ready`) return\n        const loadSubsetSession = this.collection._sync.getLoadSubsetSession()\n        const replaySession = this.truncateReplaySession\n        if (\n          this.subsetDemands.some(\n            (demand) => demand.acquisitionState === `detached`,\n          )\n        ) {\n          this.setStatus(`loadingSubset`)\n        }\n        queueMicrotask(() => {\n          if (this.truncateReplaySession === replaySession) {\n            this.restartDetachedDemands(loadSubsetSession)\n          }\n        })\n      },\n    )\n  }\n\n  /** Detach logical demand from work owned by a discarded sync session. */\n  private handleCollectionCleanup(): void {\n    this.discardTruncateReplay()\n    this.stalePublishedRows = new Map(this.publishedRows)\n    this.pendingLoadSubsetParticipants.clear()\n\n    for (const demand of [...this.subsetDemands]) {\n      demand.initialResult?.reject(new LoadSubsetOperationAbortedError())\n      cancelAcquisition(demand.acquisition)\n      if (demand.acquisitionState === `starting`) {\n        const index = this.subsetDemands.indexOf(demand)\n        if (index !== -1) this.subsetDemands.splice(index, 1)\n      } else {\n        demand.acquisitionState = `detached`\n        demand.acquisition = {\n          options: demand.requestOptions,\n          loadSubsetSession: demand.acquisition.loadSubsetSession,\n        }\n      }\n    }\n    this.setReadyIfIdle()\n  }\n\n  /** Acquire detached demand after startup or initial-error recovery. */\n  private restartDetachedDemands(loadSubsetSession: number): void {\n    if (\n      this.unsubscribed ||\n      !this.isLoadSubsetSessionCurrent(loadSubsetSession)\n    ) {\n      return\n    }\n    if (\n      this.collection.status === `error` ||\n      this.collection._sync.syncLoadSubsetFn === null\n    ) {\n      this.setReadyIfIdle()\n      return\n    }\n    const demands = this.subsetDemands.filter(\n      (demand) =>\n        demand.acquisitionState === `detached` &&\n        !demand.requestOptions.signal?.aborted,\n    )\n    if (demands.length === 0) {\n      this.setReadyIfIdle()\n      return\n    }\n\n    const session = this.createTruncateReplaySession(loadSubsetSession, () => {\n      const currentRows = this.collection.currentStateAsChanges({\n        optimizedOnly: false,\n      })\n      return new Map(\n        // The API returns void for unavailable snapshots, not just undefined.\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n        (currentRows ?? [])\n          .filter((change) => change.type !== `delete`)\n          .map((change) => [change.key, change.value]),\n      )\n    })\n    const attempt = session.currentAttempt\n    this.truncateReplaySession = session\n    this.setStatus(`loadingSubset`)\n    if (this.truncateReplaySession !== session) return\n    this.startTruncateReplayAttempt(session, attempt, demands)\n  }\n\n  /**\n   * Handle collection truncate event by resetting state and re-requesting subsets.\n   * This is called when the sync layer receives a must-refetch and clears all data.\n   *\n   * To prevent a flash of missing content, we buffer all changes (deletes from truncate\n   * and inserts from refetch) until all loadSubset calls succeed, then emit them together.\n   * A failed replay keeps the last published snapshot private until a later\n   * authoritative replay succeeds.\n   */\n  private handleTruncate() {\n    // Without a loader, replay only reconciles rows retained across cleanup.\n    const hasLoadSubsetHandler = this.collection._sync.syncLoadSubsetFn !== null\n    const demandsToReload = hasLoadSubsetHandler ? [...this.subsetDemands] : []\n\n    // Retained rows still need the committed replacement even without demand.\n    if (demandsToReload.length === 0 && this.stalePublishedRows.size === 0) {\n      this.resetSnapshotTracking()\n      return\n    }\n\n    let session = this.truncateReplaySession\n    if (session) {\n      if (!session.completion.isPending()) {\n        session.completion = createReplayCompletion()\n      }\n      // Setup itself holds publication: adapter/status callbacks may reenter\n      // before a request returns its promise and joins the pending set.\n      session.pendingSetups++\n      session.failures.clear()\n      session.currentAttempt = { pendingCount: 0, setupComplete: false }\n    } else {\n      // Every overlapping attempt shares one publication baseline and buffer.\n      session = this.createTruncateReplaySession(\n        this.collection._sync.getLoadSubsetSession(),\n        () => new Map(this.publishedRows),\n      )\n      this.truncateReplaySession = session\n    }\n    const attempt = session.currentAttempt\n    this.setStatus(`loadingSubset`)\n\n    if (this.truncateReplaySession !== session) return\n\n    if (this.options.truncateReplayPublication) {\n      this.truncateReplacementPending = true\n      this.options.truncateReplayPublication.start()\n    }\n\n    // A newer replay replaces every prior acquisition for these demands. Abort\n    // the old work before it can install rows into the new generation.\n    for (const demand of demandsToReload) {\n      demand.acquisition.abortController?.abort()\n    }\n\n    // Reset snapshot/pagination tracking for the replacement snapshot. Rows\n    // retained from an earlier failed replay stay marked until this attempt\n    // either replaces them or proves they are absent.\n    this.resetSnapshotTracking()\n\n    // Defer the requests so the truncate commit's deletes enter the session\n    // buffer before a synchronous adapter can publish replacement rows.\n    queueMicrotask(() => {\n      if (this.truncateReplaySession !== session) return\n      if (!this.isLoadSubsetSessionCurrent(session.loadSubsetSession)) {\n        this.retireStaleTruncateReplay(session)\n        return\n      }\n      // A newer truncate that arrived before this attempt began source work\n      // already captured the active demands. Starting them now would place the\n      // obsolete acquisition outside the newer abort sweep.\n      this.startTruncateReplayAttempt(\n        session,\n        attempt,\n        session.currentAttempt === attempt ? demandsToReload : [],\n      )\n    })\n  }\n\n  /** Make tentative replay ownership visible before adapter code can reenter. */\n  private startTruncateReplayDemand(\n    session: TruncateReplaySession,\n    attempt: TruncateReplayAttempt,\n    demand: SubsetDemand,\n  ): void {\n    const isCurrentAttempt = () =>\n      this.truncateReplaySession === session &&\n      session.currentAttempt === attempt\n    const isCurrent = () =>\n      isCurrentAttempt() &&\n      this.isLoadSubsetSessionCurrent(session.loadSubsetSession) &&\n      this.isDemandActive(demand)\n    const fail = (error: unknown) => {\n      if (isCurrent()) session.failures.set(demand, normalizeError(error))\n    }\n    if (demand.initialResult) {\n      void session.completion.promise.then(\n        demand.initialResult.resolve,\n        demand.initialResult.reject,\n      )\n    }\n\n    // Sequential handoff: retire the old physical lease while retaining its\n    // logical demand. Callback reentry cannot release that lease twice.\n    const previous = demand.acquisition\n    const hadPreviousAcquisition = demand.acquisitionState === `active`\n    demand.acquisitionState = `detached`\n    if (hadPreviousAcquisition) {\n      try {\n        this.releaseAcquisition(previous)\n      } catch (error) {\n        fail(error)\n        return\n      }\n    }\n    if (!isCurrent() || demand.requestOptions.signal?.aborted) return\n\n    const next = this.createSubsetAcquisition(demand)\n    demand.acquisition = next\n    demand.acquisitionState = `starting`\n    let result: LoadSubsetRequestResult\n    try {\n      result = this.loadSubset(next.options, isCurrent)\n    } catch (error) {\n      if (demand.acquisition === next) demand.acquisitionState = `detached`\n      cancelAcquisition(next)\n      fail(error)\n      return\n    }\n\n    if (!isCurrent()) {\n      if (demand.acquisition === next) demand.acquisitionState = `detached`\n      try {\n        this.releaseAcquisition(next)\n      } catch (error) {\n        fail(error)\n      }\n      return\n    }\n\n    demand.acquisitionState = `active`\n    this.trackTruncateReplayParticipant(session, attempt, demand, result)\n    this.observeLoadSubsetResult(\n      result,\n      demand,\n      next.options,\n      true,\n      () => isCurrent() && !next.options.signal?.aborted,\n    )\n  }\n\n  private settleTruncateReplay(\n    session: TruncateReplaySession,\n    pending: { demand: SubsetDemand; attempt: TruncateReplayAttempt },\n  ): void {\n    try {\n      if (this.truncateReplaySession !== session) return\n      if (!this.isLoadSubsetSessionCurrent(session.loadSubsetSession)) {\n        this.retireStaleTruncateReplay(session)\n        return\n      }\n      if (session.pending.delete(pending)) pending.attempt.pendingCount--\n      this.checkTruncateReplayComplete(session)\n    } catch (error) {\n      // Replay settlement runs from a Promise callback, so throwing here would\n      // create an unobserved derived rejection. Surface subscriber errors like\n      // other async collection events instead.\n      queueMicrotask(() => {\n        throw error\n      })\n    }\n  }\n\n  /** Keep every acquisition begun during recovery inside its publication barrier. */\n  private trackTruncateReplayParticipant(\n    session: TruncateReplaySession,\n    attempt: TruncateReplayAttempt,\n    demand: SubsetDemand,\n    result: LoadSubsetRequestResult,\n  ): void {\n    if (\n      this.truncateReplaySession !== session ||\n      (session.currentAttempt !== attempt &&\n        attempt.setupComplete &&\n        attempt.pendingCount === 0) ||\n      !(result instanceof Promise)\n    ) {\n      return\n    }\n\n    // An older attempt can still accept returning startup work while setup or\n    // another participant retains it. Once drained, it cannot reopen. Shared\n    // promises still get one participant per logical acquisition.\n    const pending = { demand, attempt }\n    attempt.pendingCount++\n    session.pending.add(pending)\n    void result.then(\n      () => this.settleTruncateReplay(session, pending),\n      (error: unknown) => {\n        // A released demand no longer participates in this replacement. Its\n        // cooperative AbortError must not discard rows from active demands.\n        if (\n          this.truncateReplaySession === session &&\n          session.currentAttempt === attempt &&\n          this.isLoadSubsetSessionCurrent(session.loadSubsetSession) &&\n          this.subsetDemands.includes(demand)\n        ) {\n          const normalized = this.normalizeLoadSubsetPromiseError(result, error)\n          session.failures.set(demand, normalized)\n        }\n        this.settleTruncateReplay(session, pending)\n      },\n    )\n  }\n\n  /** Stop obsolete logical demand from pinning a replay barrier. */\n  private removeTruncateReplayParticipant(demand: SubsetDemand): void {\n    const session = this.truncateReplaySession\n    if (!session) return\n    session.failures.delete(demand)\n    for (const pending of session.pending) {\n      if (pending.demand === demand) {\n        session.pending.delete(pending)\n        pending.attempt.pendingCount--\n      }\n    }\n  }\n\n  /** Publish only after every overlapping replay attempt has settled. */\n  private checkTruncateReplayComplete(session: TruncateReplaySession): void {\n    if (this.truncateReplaySession !== session) return\n    if (session.pendingSetups > 0 || session.pending.size > 0) return\n\n    const activeFailure = [...session.failures].find(([demand]) =>\n      this.subsetDemands.includes(demand),\n    )\n    try {\n      if (activeFailure) {\n        this.abandonTruncateReplay(session, activeFailure[1])\n      } else {\n        this.flushTruncateReplay(session)\n      }\n    } finally {\n      this.setReadyIfIdle()\n    }\n  }\n\n  /**\n   * Keep an incomplete replay private. The source no longer proves a complete\n   * state, so only a later successful truncate replay may reopen publication.\n   */\n  private abandonTruncateReplay(\n    session: TruncateReplaySession,\n    failure: Error,\n  ): void {\n    if (this.truncateReplaySession !== session) return\n    session.completion.reject(failure)\n    // Delegated publication already delivered its rows. Only a private buffer\n    // returns the caller's pagination position to the public snapshot; the\n    // private rows and their sent-key tracking stay together for a retry.\n    if (!session.privateRows) return\n    const publicationState = session.publicationState\n    this.loadedInitialState = publicationState.loadedInitialState\n    this.snapshotSent = publicationState.snapshotSent\n    this.limitedSnapshotRowCount = publicationState.limitedSnapshotRowCount\n    this.lastSentKey = publicationState.lastSentKey\n  }\n\n  /** Publish the buffered replacement as one batch, or release the delegate. */\n  private flushTruncateReplay(session: TruncateReplaySession): void {\n    if (this.truncateReplaySession !== session) return\n    this.truncateReplaySession = undefined\n    this.truncateReplacementPending = false\n\n    // Retained rows the source never re-delivered leave the replacement.\n    const { privateRows } = session\n    for (const key of this.stalePublishedRows.keys()) privateRows?.delete(key)\n    this.stalePublishedRows.clear()\n    try {\n      if (privateRows) {\n        // Diff the retained public snapshot against the applied source replacement.\n        const replacement = this.createStateDiff(\n          this.publishedRows,\n          privateRows,\n        )\n        if (replacement.length > 0) this.filteredCallback(replacement)\n      }\n    } finally {\n      // Restore tracking even when a subscriber rejects the replacement.\n      this.restorePublishedSnapshotTracking()\n      session.completion.resolve()\n      this.options.truncateReplayPublication?.succeed()\n    }\n  }\n\n  private restorePublishedSnapshotTracking(): void {\n    this.sentKeys = new Set(this.publishedRows.keys())\n    if (!this.orderByIndex) return\n\n    this.limitedSnapshotRowCount = this.sentKeys.size\n    const orderedSentKeys = this.orderByIndex.takeFromStart(\n      this.sentKeys.size,\n      (key) => this.sentKeys.has(key),\n    )\n    this.lastSentKey = orderedSentKeys.at(-1)\n  }\n\n  /** Fold changes into the private replacement; false when they publish now. */\n  private bufferPrivately(\n    changes: ReadonlyArray<ChangeMessage<any, any>>,\n  ): boolean {\n    const privateRows = this.truncateReplaySession?.privateRows\n    if (!privateRows) return false\n    for (const change of changes) {\n      if (change.type === `delete`) privateRows.delete(change.key)\n      else privateRows.set(change.key, change.value)\n    }\n    return true\n  }\n\n  private createStateDiff(\n    baseline: ReadonlyMap<string | number, object>,\n    finalRows: ReadonlyMap<string | number, object>,\n  ): Array<ChangeMessage<any, any>> {\n    const replacement: Array<ChangeMessage<any, any>> = []\n    for (const [key, previousValue] of baseline) {\n      const value = finalRows.get(key)\n      if (value === undefined) {\n        replacement.push({\n          type: `delete`,\n          key,\n          value: previousValue,\n        })\n      } else if (!deepEquals(value, previousValue)) {\n        replacement.push({\n          type: `update`,\n          key,\n          value,\n          previousValue,\n        })\n      }\n    }\n    for (const [key, value] of finalRows) {\n      if (!baseline.has(key)) replacement.push({ type: `insert`, key, value })\n    }\n    return replacement\n  }\n\n  private get isBufferingForTruncate(): boolean {\n    return this.truncateReplaySession !== undefined\n  }\n\n  private setReadyIfIdle(): void {\n    const session = this.truncateReplaySession\n    const hasPendingReplayWork =\n      session && (session.pendingSetups > 0 || session.pending.size > 0)\n    if (\n      this.pendingLoadSubsetParticipants.size === 0 &&\n      !hasPendingReplayWork\n    ) {\n      this.setStatus(`ready`)\n    }\n  }\n\n  private isLoadSubsetSessionCurrent(session: number): boolean {\n    return session === this.collection._sync.getLoadSubsetSession()\n  }\n\n  private retireStaleTruncateReplay(session: TruncateReplaySession): void {\n    if (this.truncateReplaySession !== session) return\n    this.discardTruncateReplay()\n    this.stalePublishedRows.clear()\n  }\n\n  /** Drop the replay without publishing; an unfinished wait rejects as aborted. */\n  private discardTruncateReplay(): void {\n    const session = this.truncateReplaySession\n    if (session?.completion.isPending()) {\n      session.completion.reject(new LoadSubsetOperationAbortedError())\n    }\n    this.truncateReplaySession = undefined\n    this.truncateReplacementPending = false\n  }\n\n  private resetSnapshotTracking(): void {\n    this.snapshotSent = false\n    this.loadedInitialState = false\n    this.limitedSnapshotRowCount = 0\n    this.lastSentKey = undefined\n  }\n\n  /** One replay session; only direct subscribers buffer a private replacement. */\n  private createTruncateReplaySession(\n    loadSubsetSession: number,\n    privateRows: () => Map<string | number, object>,\n  ): TruncateReplaySession {\n    return {\n      loadSubsetSession,\n      publicationState: {\n        loadedInitialState: this.loadedInitialState,\n        snapshotSent: this.snapshotSent,\n        limitedSnapshotRowCount: this.limitedSnapshotRowCount,\n        lastSentKey: this.lastSentKey,\n      },\n      privateRows: this.options.truncateReplayPublication\n        ? undefined\n        : privateRows(),\n      pending: new Set(),\n      // Setup itself holds publication: adapter/status callbacks may reenter\n      // before a request returns its promise and joins the pending set.\n      pendingSetups: 1,\n      currentAttempt: { pendingCount: 0, setupComplete: false },\n      failures: new Map(),\n      completion: createReplayCompletion(),\n    }\n  }\n\n  /** Start one attempt's demands, then release the setup hold on publication. */\n  private startTruncateReplayAttempt(\n    session: TruncateReplaySession,\n    attempt: TruncateReplayAttempt,\n    demands: ReadonlyArray<SubsetDemand>,\n  ): void {\n    for (const demand of demands) {\n      if (!this.subsetDemands.includes(demand)) continue\n      this.startTruncateReplayDemand(session, attempt, demand)\n      if (\n        this.truncateReplaySession !== session ||\n        session.currentAttempt !== attempt\n      ) {\n        break\n      }\n    }\n    attempt.setupComplete = true\n    session.pendingSetups--\n    this.checkTruncateReplayComplete(session)\n  }\n\n  public get hasPendingTruncateReplacement(): boolean {\n    return this.truncateReplacementPending\n  }\n\n  public get pendingTruncateReplacement(): Promise<void> | undefined {\n    const completion = this.truncateReplaySession?.completion\n    return completion?.isPending() ? completion.promise : undefined\n  }\n\n  public get hasFailedTruncateReplacement(): boolean {\n    const completion = this.truncateReplaySession?.completion\n    return (\n      this.truncateReplacementPending &&\n      completion !== undefined &&\n      !completion.isPending()\n    )\n  }\n\n  setOrderByIndex(index: IndexReader<any>) {\n    this.orderByIndex = index\n  }\n\n  /**\n   * Set subscription status and emit events if changed\n   */\n  private setStatus(newStatus: SubscriptionStatus) {\n    if (this.unsubscribed) return\n    if (this._status === newStatus) {\n      return // No change\n    }\n\n    const previousStatus = this._status\n    this._status = newStatus\n    const revision = ++this.statusRevision\n\n    // Emit status:change event\n    this.emitInnerWhile(\n      `status:change`,\n      {\n        type: `status:change`,\n        subscription: this,\n        previousStatus,\n        status: newStatus,\n      },\n      () => this.statusRevision === revision,\n    )\n\n    // A listener may synchronously start or release demand. Do not follow that\n    // newer transition with a stale specific event.\n    if (this.statusRevision !== revision) return\n\n    // Emit specific status event\n    const eventKey: `status:${SubscriptionStatus}` = `status:${newStatus}`\n    this.emitInnerWhile(\n      eventKey,\n      {\n        type: eventKey,\n        subscription: this,\n        previousStatus,\n        status: newStatus,\n      } as SubscriptionEvents[typeof eventKey],\n      () => this.statusRevision === revision,\n    )\n  }\n\n  /** Observe an asynchronous subset load and restore status on settlement. */\n  private observeLoadSubsetResult(\n    syncResult: LoadSubsetRequestResult,\n    demand: SubsetDemand,\n    options: LoadSubsetOptions,\n    trackStatus: boolean,\n    shouldReportError: () => boolean = () => true,\n  ): void {\n    if (!(syncResult instanceof Promise)) return\n\n    const loadSubsetSession = this.collection._sync.getLoadSubsetSession()\n    const participant = { demand, promise: syncResult }\n\n    if (trackStatus) {\n      this.pendingLoadSubsetParticipants.add(participant)\n      this.setStatus(`loadingSubset`)\n    }\n\n    const finish = () => {\n      if (trackStatus) {\n        this.pendingLoadSubsetParticipants.delete(participant)\n        if (this.isLoadSubsetSessionCurrent(loadSubsetSession)) {\n          this.setReadyIfIdle()\n        }\n      }\n    }\n\n    void syncResult.then(finish, (error: unknown) => {\n      if (\n        this.isLoadSubsetSessionCurrent(loadSubsetSession) &&\n        shouldReportError()\n      ) {\n        this.recordLoadSubsetError(\n          options,\n          this.normalizeLoadSubsetPromiseError(syncResult, error),\n        )\n      }\n      finish()\n    })\n  }\n\n  /** Give every logical observer of one transport rejection the same Error. */\n  private normalizeLoadSubsetPromiseError(\n    promise: Promise<unknown>,\n    error: unknown,\n  ): Error {\n    const existing = this.loadSubsetPromiseErrors.get(promise)\n    if (existing) return existing\n    const normalized = normalizeError(error)\n    this.loadSubsetPromiseErrors.set(promise, normalized)\n    return normalized\n  }\n\n  private stopDemandStatusParticipants(demand: SubsetDemand): void {\n    for (const participant of this.pendingLoadSubsetParticipants) {\n      if (participant.demand === demand) {\n        this.pendingLoadSubsetParticipants.delete(participant)\n      }\n    }\n    this.setReadyIfIdle()\n  }\n\n  private loadSubset(\n    options: LoadSubsetOptions,\n    shouldReportError: () => boolean = () => true,\n  ): LoadSubsetRequestResult {\n    try {\n      return this.collection._sync.loadSubset(options)\n    } catch (error) {\n      const normalized = normalizeError(error)\n      if (shouldReportError()) this.recordLoadSubsetError(options, normalized)\n      throw normalized\n    }\n  }\n\n  /** Create a fresh, abortable adapter acquisition for a replay generation. */\n  private createSubsetAcquisition(\n    demand: SubsetDemand,\n  ): SubsetAcquisition & { abortController: AbortController } {\n    const abortController = new AbortController()\n    const requestSignal = demand.requestOptions.signal\n    let removeRequestAbortListener: (() => void) | undefined\n\n    if (requestSignal?.aborted) {\n      abortController.abort(requestSignal.reason)\n    } else if (requestSignal) {\n      const abort = () => abortController.abort(requestSignal.reason)\n      requestSignal.addEventListener(`abort`, abort, { once: true })\n      removeRequestAbortListener = () =>\n        requestSignal.removeEventListener(`abort`, abort)\n    }\n\n    return {\n      options: {\n        ...demand.requestOptions,\n        signal: abortController.signal,\n      },\n      loadSubsetSession: this.collection._sync.getLoadSubsetSession(),\n      abortController,\n      removeRequestAbortListener,\n    }\n  }\n\n  /** Retire an acquisition before user code; failed cleanup is not retryable. */\n  private releaseAcquisition(\n    acquisition: SubsetAcquisition,\n    reportReleaseError = this.primaryFailureDeliveryDepth === 0,\n  ): void {\n    if (acquisition.releaseAttempted) return\n    acquisition.releaseAttempted = true\n    try {\n      acquisition.abortController?.abort()\n      if (this.isLoadSubsetSessionCurrent(acquisition.loadSubsetSession)) {\n        this.collection._sync.unloadSubset(acquisition.options)\n      }\n    } catch (error) {\n      const normalized = reportReleaseError\n        ? this.recordLoadSubsetError(\n            acquisition.options,\n            normalizeError(error),\n            true,\n          )\n        : normalizeError(error)\n      throw normalized\n    } finally {\n      acquisition.removeRequestAbortListener?.()\n    }\n  }\n\n  /** Start and retain the first acquisition for one logical subset demand. */\n  private startSubsetDemand(requestOptions: LoadSubsetOptions): {\n    demand: SubsetDemand\n    result: LoadSubsetRequestResult\n    started: boolean\n  } {\n    const demand: SubsetDemand = {\n      requestOptions,\n      acquisition: {\n        options: requestOptions,\n        loadSubsetSession: this.collection._sync.getLoadSubsetSession(),\n      },\n      acquisitionState: `starting`,\n    }\n    if (\n      this.collection.status === `cleaned-up` ||\n      // Ready/error callbacks can run before sync returns its loader. Idle\n      // deferred starts still acquire through the sync manager's queue.\n      (this.collection.config.syncMode === `on-demand` &&\n        (this.collection.status === `error` ||\n          (this.collection.status !== `idle` &&\n            this.collection._sync.syncLoadSubsetFn === null)))\n    ) {\n      demand.acquisitionState = `detached`\n      this.subsetDemands.push(demand)\n      const initialResult = createDeferred<void>()\n      demand.initialResult = initialResult\n      const abort = () =>\n        initialResult.reject(new LoadSubsetOperationAbortedError())\n      requestOptions.signal?.addEventListener(`abort`, abort, { once: true })\n      const finish = () => {\n        requestOptions.signal?.removeEventListener(`abort`, abort)\n        demand.initialResult = undefined\n      }\n      void initialResult.promise.then(finish, finish)\n      return { demand, result: initialResult.promise, started: false }\n    }\n    const acquisition = this.createSubsetAcquisition(demand)\n    demand.acquisition = acquisition\n    const replaySession = this.truncateReplaySession\n    const replayAttempt = replaySession?.currentAttempt\n    const loadSubsetSession = this.collection._sync.getLoadSubsetSession()\n    // Reentrant release must see the exact acquisition before adapter work\n    // starts. A genuine load throw removes this tentative logical owner below.\n    this.subsetDemands.push(demand)\n    let result: LoadSubsetRequestResult\n    try {\n      result = this.loadSubset(\n        acquisition.options,\n        () =>\n          this.isLoadSubsetSessionCurrent(loadSubsetSession) &&\n          this.subsetDemands.includes(demand) &&\n          (replaySession === undefined ||\n            (this.truncateReplaySession === replaySession &&\n              replaySession.currentAttempt === replayAttempt)),\n      )\n    } catch (error) {\n      const demandIndex = this.subsetDemands.indexOf(demand)\n      if (demandIndex !== -1) {\n        if (\n          replaySession &&\n          replayAttempt &&\n          this.truncateReplaySession === replaySession &&\n          replaySession.currentAttempt === replayAttempt\n        ) {\n          replaySession.failures.set(demand, normalizeError(error))\n        }\n        this.subsetDemands.splice(demandIndex, 1)\n      }\n      cancelAcquisition(acquisition)\n      throw error\n    }\n\n    if (!this.isLoadSubsetSessionCurrent(loadSubsetSession)) {\n      const demandIndex = this.subsetDemands.indexOf(demand)\n      if (demandIndex !== -1) this.subsetDemands.splice(demandIndex, 1)\n      cancelAcquisition(acquisition)\n      return { demand, result, started: true }\n    }\n\n    demand.acquisitionState = `active`\n    if (!this.subsetDemands.includes(demand)) {\n      this.releaseAcquisition(acquisition)\n      return { demand, result, started: true }\n    }\n\n    if (replaySession && replayAttempt) {\n      this.trackTruncateReplayParticipant(\n        replaySession,\n        replayAttempt,\n        demand,\n        result,\n      )\n    }\n    return { demand, result, started: true }\n  }\n\n  /** Re-check ownership after adapter and event callbacks that may reenter. */\n  private isDemandActive(demand: SubsetDemand): boolean {\n    return !this.unsubscribed && this.subsetDemands.includes(demand)\n  }\n\n  private recordLoadSubsetError(\n    options: LoadSubsetOptions,\n    error: unknown,\n    reportAborted = false,\n  ): Error {\n    const normalized = normalizeError(error)\n    // Aborted subset requests are obsolete demand, not load failures. The\n    // request may reject after its route has already been released.\n    if (options.signal?.aborted && !reportAborted) return normalized\n\n    this._lastError = normalized\n    this.primaryFailureDeliveryDepth++\n    try {\n      this.emitInner(`loadSubset:error`, {\n        type: `loadSubset:error`,\n        subscription: this,\n        options,\n        error: normalized,\n      })\n    } finally {\n      this.primaryFailureDeliveryDepth--\n    }\n    return normalized\n  }\n\n  emitEvents(changes: Array<ChangeMessage<any, any>>): boolean {\n    if (this.unsubscribed) return false\n    const newChanges = this.filterAndFlipChanges(changes)\n\n    // Reconciliation can reduce a source delta to no visible change. Do not\n    // wake subscribers for an empty semantic batch.\n    if (changes.length > 0 && newChanges.length === 0) return false\n\n    // A direct subscriber sees the replacement as one batch, not a flash of\n    // missing content. Delegated publication keeps its private D2 contributions.\n    if (this.bufferPrivately(newChanges)) return false\n    return this.filteredCallback(newChanges)\n  }\n\n  /** Keep direct snapshot reads private while an authoritative replay is open. */\n  private publishSnapshot(changes: Array<ChangeMessage<any, any>>): void {\n    if (!this.bufferPrivately(changes)) this.callback(changes)\n  }\n\n  /**\n   * Sends the snapshot to the callback.\n   * Returns a boolean indicating if it succeeded.\n   * It can only fail if there is no index to fulfill the request\n   * and the optimizedOnly option is set to true,\n   * or, the entire state was already loaded or the request was cancelled.\n   */\n  requestSnapshot(opts?: RequestSnapshotOptions): boolean {\n    // Cancel before acquiring ownership or publishing a local snapshot.\n    if (this.unsubscribed || opts?.signal?.aborted) return false\n    if (this.loadedInitialState) {\n      // Subscription was deoptimized so we already sent the entire initial state\n      return false\n    }\n\n    const stateOpts: RequestSnapshotOptions = {\n      where: this.options.whereExpression,\n      optimizedOnly: opts?.optimizedOnly ?? false,\n    }\n\n    if (opts) {\n      if (`where` in opts) {\n        const snapshotWhereExp = opts.where\n        if (stateOpts.where) {\n          // Combine the two where expressions\n          const subWhereExp = stateOpts.where\n          const combinedWhereExp = and(subWhereExp, snapshotWhereExp)\n          stateOpts.where = combinedWhereExp\n        } else {\n          stateOpts.where = snapshotWhereExp\n        }\n      }\n    } else {\n      // No options provided so it's loading the entire initial state\n      this.loadedInitialState = true\n    }\n\n    // Request the sync layer to load more data\n    // don't await it, we will load the data into the collection when it comes in\n    const loadOptions: LoadSubsetOptions = {\n      where: stateOpts.where,\n      signal: opts?.signal,\n      subscription: this,\n      // Include orderBy and limit if provided so sync layer can optimize the query\n      orderBy: opts?.orderBy,\n      limit: opts?.limit,\n    }\n\n    const {\n      demand,\n      result: syncResult,\n      started,\n    } = this.startSubsetDemand(loadOptions)\n    if (!this.isDemandActive(demand)) return false\n    if (opts?.where) this.requestedSubsetWhere.set(loadOptions, opts.where)\n\n    // Report the result synchronously, including a wait for an unavailable loader.\n    opts?.onLoadSubsetResult?.(\n      syncResult,\n      demand.acquisition.options,\n      (primaryFailure) => this.releaseDemand(demand, primaryFailure),\n    )\n    if (!this.isDemandActive(demand)) return false\n\n    if (started) {\n      this.observeLoadSubsetResult(\n        syncResult,\n        demand,\n        demand.acquisition.options,\n        opts?.trackLoadSubsetPromise ?? true,\n      )\n    }\n    if (!this.isDemandActive(demand)) return false\n\n    // Also load data immediately from the collection\n    let snapshot: Array<ChangeMessage<any, any>> | void\n    if (opts?.onUnoptimized) {\n      snapshot = this.collection.currentStateAsChanges({\n        ...stateOpts,\n        optimizedOnly: true,\n      })\n      if (snapshot === undefined) {\n        opts.onUnoptimized()\n        // The callback can unsubscribe; TypeScript retains the pre-call narrowing.\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n        if (this.unsubscribed) return false\n        snapshot = this.collection.currentStateAsChanges({\n          ...stateOpts,\n          optimizedOnly: false,\n        })\n      }\n    } else {\n      snapshot = this.collection.currentStateAsChanges(stateOpts)\n    }\n    // Snapshot evaluation may call user code that tears down the subscription.\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n    if (this.unsubscribed) return false\n\n    if (snapshot === undefined) {\n      // Couldn't load from indexes\n      return false\n    }\n\n    // Skip known rows, except retained rows from an abandoned replay: a new\n    // snapshot must reconcile those with the source, not suppress their update.\n    const knownRows =\n      this.truncateReplaySession?.privateRows ?? this.publishedRows\n    const filteredSnapshot = snapshot.filter(\n      (change) =>\n        (!this.isBufferingForTruncate &&\n          this.stalePublishedRows.has(change.key)) ||\n        (!this.sentKeys.has(change.key) && !knownRows.has(change.key)),\n    )\n\n    // Add keys to sentKeys BEFORE calling callback to prevent race condition.\n    // If a change event arrives while the callback is executing, it will see\n    // the keys already in sentKeys and filter out duplicates correctly.\n    for (const change of filteredSnapshot) {\n      this.sentKeys.add(change.key)\n    }\n\n    this.snapshotSent = true\n    this.publishSnapshot(\n      this.isBufferingForTruncate\n        ? filteredSnapshot\n        : this.reconcileStalePublishedChanges(filteredSnapshot),\n    )\n    return true\n  }\n\n  /** Release one exact subset request while keeping the subscription alive. */\n  releaseSnapshot(where: BasicExpression<boolean>): void {\n    const index = this.subsetDemands.findIndex(\n      (demand) =>\n        demand.requestOptions.where === where ||\n        this.requestedSubsetWhere.get(demand.requestOptions) === where,\n    )\n    if (index === -1) return\n\n    this.releaseDemandAt(index)\n  }\n\n  private releaseDemand(\n    demand: SubsetDemand,\n    primaryFailure?: { error: unknown },\n  ): void {\n    if (!primaryFailure) {\n      const index = this.subsetDemands.indexOf(demand)\n      if (index !== -1) this.releaseDemandAt(index)\n      return\n    }\n\n    try {\n      this.recordLoadSubsetError(\n        demand.acquisition.options,\n        primaryFailure.error,\n        true,\n      )\n    } finally {\n      // The failed request remains the public error, even if cleanup also fails.\n      const index = this.subsetDemands.indexOf(demand)\n      if (index !== -1) this.releaseDemandAt(index, false)\n    }\n  }\n\n  private releaseDemandAt(\n    index: number,\n    reportReleaseError = this.primaryFailureDeliveryDepth === 0,\n  ): void {\n    const demand = this.subsetDemands[index]\n    if (!demand) return\n    const replaySession = this.truncateReplaySession\n    const acquisition = demand.acquisition\n    this.subsetDemands.splice(index, 1)\n    demand.initialResult?.reject(new LoadSubsetOperationAbortedError())\n    const releaseCallbacks = [\n      () => this.removeTruncateReplayParticipant(demand),\n      ...(demand.acquisitionState === `active`\n        ? [\n            // Adapter release is a supported reentrancy boundary. A demand\n            // started from unload joins this replacement before completion.\n            () => this.releaseAcquisition(acquisition, reportReleaseError),\n          ]\n        : []),\n      () => this.retireEmptyReplay(),\n      () => {\n        if (replaySession) this.checkTruncateReplayComplete(replaySession)\n      },\n      // Ready follows replacement publication, never the delete half of it.\n      () => this.stopDemandStatusParticipants(demand),\n    ]\n    runAllCallbacks(releaseCallbacks)\n  }\n\n  /** A replay with no remaining logical demand cannot establish more rows. */\n  private retireEmptyReplay(): void {\n    if (this.subsetDemands.length !== 0 || !this.truncateReplaySession) {\n      return\n    }\n    this.discardTruncateReplay()\n    this.stalePublishedRows = new Map(this.publishedRows)\n    this.restorePublishedSnapshotTracking()\n    this.options.truncateReplayPublication?.succeed()\n  }\n\n  /** Read the applied rows in an ordered acquisition without starting demand. */\n  readOrderedSnapshot(\n    options: LoadSubsetOptions,\n  ): Array<ChangeMessage<Record<string, unknown>, string | number>> {\n    const predicates = [\n      this.options.whereExpression,\n      options.where,\n      options.cursor?.whereFrom,\n    ].filter((where) => where !== undefined)\n    const snapshot = this.collection.currentStateAsChanges({\n      orderBy: options.orderBy,\n      limit: options.limit,\n      where:\n        predicates.length > 0\n          ? predicates.reduce((left, right) => and(left, right))\n          : undefined,\n    })\n    return Array.isArray(snapshot) ? snapshot : []\n  }\n\n  /**\n   * Sends a snapshot that fulfills the `where` clause and all rows are bigger or equal to the cursor.\n   * Requires a range index to be set with `setOrderByIndex` prior to calling this method.\n   * It uses that range index to load the items in the order of the index.\n   *\n   * Cursor requests support one order term and one minValue. Multi-column\n   * queries use the ordered loader's prefix-and-tie fallback instead.\n   *\n   * Note 1: it may load more rows than the provided LIMIT because it loads all values equal to the first cursor value + limit values greater.\n   *         This is needed to ensure that it does not accidentally skip duplicate values when the limit falls in the middle of some duplicated values.\n   * Note 2: it does not send keys that have already been sent before.\n   */\n  requestLimitedSnapshot({\n    orderBy,\n    limit,\n    minValues,\n    offset,\n    trackLoadSubsetPromise: shouldTrackLoadSubsetPromise = true,\n    onLoadSubsetResult,\n  }: RequestLimitedSnapshotOptions) {\n    if (this.unsubscribed) return\n    if (!limit) throw new Error(`limit is required`)\n\n    if (!this.orderByIndex) {\n      throw new Error(\n        `Ordered snapshot was requested but no index was found. You have to call setOrderByIndex before requesting an ordered snapshot.`,\n      )\n    }\n\n    // Validate cursor input before local delivery changes sent keys or calls user code.\n    const whereFromCursor = minValues\n      ? buildCursor(orderBy, minValues)\n      : undefined\n\n    // Check if minValues has a first element (regardless of its value)\n    // This distinguishes between \"no min value provided\" vs \"min value is undefined\"\n    const hasMinValue = minValues !== undefined && minValues.length > 0\n    // Derive first column value from minValues (used for local index operations)\n    const minValue = minValues?.[0]\n    // Cast for index operations (index expects string | number)\n    const minValueForIndex = minValue as string | number | undefined\n\n    const index = this.orderByIndex\n    const where = this.options.whereExpression\n    const whereFilterFn = where\n      ? createFilterFunctionFromExpression(where)\n      : undefined\n\n    const filterFn = (key: string | number | undefined): boolean => {\n      if (key !== undefined && this.sentKeys.has(key)) {\n        return false\n      }\n\n      const value = this.collection.get(key)\n      if (value === undefined) {\n        return false\n      }\n\n      return whereFilterFn?.(value) ?? true\n    }\n\n    let biggestObservedValue = minValueForIndex\n    const changes: Array<ChangeMessage<any, string | number>> = []\n\n    // If we have a minValue we need to handle the case\n    // where there might be duplicate values equal to minValue that we need to include\n    // because we can have data like this: [1, 2, 3, 3, 3, 4, 5]\n    // so if minValue is 3 then the previous snapshot may not have included all 3s\n    // e.g. if it was offset 0 and limit 3 it would only have loaded the first 3\n    //      so we load all rows equal to minValue first, to be sure we don't skip any duplicate values\n    let keys: Array<string | number> = []\n    if (hasMinValue) {\n      // First, get all items with the same FIRST COLUMN value as minValue\n      // This provides wide bounds for the local index\n      const { expression } = orderBy[0]!\n      const allRowsWithMinValue = this.collection.currentStateAsChanges({\n        where: eq(expression, new Value(minValueForIndex)),\n      })\n\n      if (allRowsWithMinValue) {\n        const keysWithMinValue = allRowsWithMinValue\n          .map((change) => change.key)\n          .filter((key) => !this.sentKeys.has(key) && filterFn(key))\n\n        // Add items with the minValue first\n        keys.push(...keysWithMinValue)\n\n        // Then get items greater than minValue\n        const keysGreaterThanMin = index.take(\n          limit - keys.length,\n          minValueForIndex!,\n          filterFn,\n        )\n        keys.push(...keysGreaterThanMin)\n      } else {\n        keys = index.take(limit, minValueForIndex!, filterFn)\n      }\n    } else {\n      // No min value provided, start from the beginning\n      keys = index.takeFromStart(limit, filterFn)\n    }\n\n    const valuesNeeded = () => Math.max(limit - changes.length, 0)\n    const collectionExhausted = () => keys.length === 0\n\n    // Create a value extractor for the orderBy field to properly track the biggest indexed value\n    const orderByExpression = orderBy[0]!.expression\n    const valueExtractor =\n      orderByExpression.type === `ref`\n        ? compileExpression(new PropRef(orderByExpression.path), true)\n        : null\n\n    while (valuesNeeded() > 0 && !collectionExhausted()) {\n      for (const key of keys) {\n        const value = this.collection.get(key)!\n        changes.push({\n          type: `insert`,\n          key,\n          value,\n        })\n        // Extract the indexed value (e.g., salary) from the row, not the full row\n        // This is needed for index.take() to work correctly with the BTree comparator\n        biggestObservedValue = valueExtractor ? valueExtractor(value) : value\n      }\n\n      keys = index.take(valuesNeeded(), biggestObservedValue!, filterFn)\n    }\n\n    // Track row count for offset-based pagination (before sending to callback)\n    // Use the current count as the offset for this load\n    const currentOffset = this.limitedSnapshotRowCount\n\n    // Add keys to sentKeys BEFORE calling callback to prevent race condition.\n    // If a change event arrives while the callback is executing, it will see\n    // the keys already in sentKeys and filter out duplicates correctly.\n    for (const change of changes) {\n      this.sentKeys.add(change.key)\n    }\n\n    this.publishSnapshot(changes)\n    // A subscriber callback can synchronously tear down this subscription.\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n    if (this.unsubscribed) return\n\n    // Update the row count and last key after sending (for next call's offset/cursor)\n    this.limitedSnapshotRowCount = Math.max(\n      this.limitedSnapshotRowCount,\n      currentOffset + changes.length,\n    )\n    if (changes.length > 0) {\n      this.lastSentKey = changes[changes.length - 1]!.key\n    }\n\n    // Build cursor expressions for sync layer loadSubset\n    // The cursor expressions are separate from the main where clause\n    // so the sync layer can choose cursor-based or offset-based pagination\n    let cursorExpressions:\n      | {\n          whereFrom: BasicExpression<boolean>\n          whereCurrent: BasicExpression<boolean>\n          lastKey?: string | number\n        }\n      | undefined\n\n    if (whereFromCursor && minValues) {\n      const whereCurrentCursor = buildCursorCurrent(orderBy, minValues)\n      if (whereCurrentCursor) {\n        cursorExpressions = {\n          whereFrom: whereFromCursor,\n          whereCurrent: whereCurrentCursor,\n          lastKey: this.lastSentKey,\n        }\n      }\n    }\n\n    // Request the sync layer to load more data\n    // don't await it, we will load the data into the collection when it comes in\n    // Note: `where` does NOT include cursor expressions - they are passed separately\n    // The sync layer can choose to use cursor-based or offset-based pagination\n    const loadOptions: LoadSubsetOptions = {\n      where, // Main filter only, no cursor\n      limit,\n      orderBy,\n      cursor: cursorExpressions, // Cursor expressions passed separately\n      offset: offset ?? currentOffset, // Use provided offset, or auto-tracked offset\n      subscription: this,\n    }\n\n    const {\n      demand,\n      result: syncResult,\n      started,\n    } = this.startSubsetDemand(loadOptions)\n    if (!this.isDemandActive(demand)) return\n\n    // Report the result synchronously, including a wait for an unavailable loader.\n    onLoadSubsetResult?.(\n      syncResult,\n      demand.acquisition.options,\n      (primaryFailure) => this.releaseDemand(demand, primaryFailure),\n    )\n    if (!this.isDemandActive(demand)) return\n    if (started) {\n      this.observeLoadSubsetResult(\n        syncResult,\n        demand,\n        demand.acquisition.options,\n        shouldTrackLoadSubsetPromise,\n      )\n    }\n    if (!this.isDemandActive(demand)) return\n  }\n\n  // TODO: also add similar test but that checks that it can also load it from the collection's loadSubset function\n  //       and that that also works properly (i.e. does not skip duplicate values)\n\n  /**\n   * Filters and flips changes for keys that have not been sent yet.\n   * Deletes are filtered out for keys that have not been sent yet.\n   * Updates are flipped into inserts for keys that have not been sent yet.\n   * Duplicate inserts are filtered out to prevent D2 multiplicity > 1.\n   */\n  private filterAndFlipChanges(changes: Array<ChangeMessage<any, any>>) {\n    changes = this.reconcileStalePublishedChanges(changes)\n\n    if (this.loadedInitialState || this.skipFiltering) {\n      // We loaded the entire initial state or filtering is explicitly skipped\n      // so no need to filter or flip changes\n      return changes\n    }\n\n    // When buffering for truncate, we need all changes (including deletes) to pass through.\n    // This is important because:\n    // 1. If loadedInitialState was previously true, sentKeys will be empty\n    //    (trackSentKeys early-returns when loadedInitialState is true)\n    // 2. The truncate deletes are for keys that WERE sent to the subscriber\n    // 3. We're collecting all changes atomically, so filtering doesn't make sense\n    const skipDeleteFilter = this.isBufferingForTruncate\n\n    const newChanges = []\n    for (const change of changes) {\n      let newChange = change\n      const keyInSentKeys = this.sentKeys.has(change.key)\n\n      if (!keyInSentKeys) {\n        if (change.type === `update`) {\n          newChange = { ...change, type: `insert`, previousValue: undefined }\n          this.sentKeys.add(change.key)\n        } else if (change.type === `delete`) {\n          // Filter out deletes for keys that have not been sent,\n          // UNLESS we're buffering for truncate (where all deletes should pass through)\n          if (!skipDeleteFilter) {\n            continue\n          }\n        } else {\n          this.sentKeys.add(change.key)\n        }\n      } else {\n        // Key was already sent - handle based on change type\n        if (change.type === `insert`) {\n          // Filter out duplicate inserts - the key was already inserted.\n          // This prevents D2 multiplicity from going above 1, which would\n          // cause deletes to not properly remove items (multiplicity would\n          // go from 2 to 1 instead of 1 to 0).\n          continue\n        } else if (change.type === `delete`) {\n          // Remove from sentKeys so future inserts for this key are allowed\n          // (e.g., after truncate + reinsert)\n          this.sentKeys.delete(change.key)\n        }\n      }\n      newChanges.push(newChange)\n    }\n    return newChanges\n  }\n\n  /**\n   * After a failed replay, the source collection is empty but subscribers still\n   * hold the last good publication. Reconcile the first later source delta for\n   * each retained key against that publication instead of treating it as a\n   * duplicate insert.\n   */\n  private reconcileStalePublishedChanges(\n    changes: Array<ChangeMessage<any, any>>,\n  ): Array<ChangeMessage<any, any>> {\n    if (this.stalePublishedRows.size === 0) return changes\n\n    const reconciled: Array<ChangeMessage<any, any>> = []\n    for (const change of changes) {\n      const previous = this.stalePublishedRows.get(change.key)\n      if (previous === undefined) {\n        reconciled.push(change)\n        continue\n      }\n\n      this.stalePublishedRows.delete(change.key)\n      if (change.type === `delete`) {\n        reconciled.push({\n          ...change,\n          value: previous,\n          previousValue: undefined,\n        })\n      } else if (!deepEquals(previous, change.value)) {\n        reconciled.push({\n          ...change,\n          type: `update`,\n          previousValue: previous,\n        })\n      }\n    }\n    // Cleanup discards rows without publishing deletes. Eager sources publish\n    // their installed state; subset sources must first finish reacquisition.\n    if (\n      this.collection.config.syncMode !== `on-demand` &&\n      !this.isBufferingForTruncate\n    ) {\n      for (const [key, value] of this.stalePublishedRows) {\n        if (this.collection.has(key)) continue\n        this.stalePublishedRows.delete(key)\n        reconciled.push({ type: `delete`, key, value })\n      }\n    }\n    return reconciled\n  }\n\n  private trackPublishedRows(\n    changes: Array<ChangeMessage<any, string | number>>,\n  ): void {\n    for (const change of changes) {\n      if (change.type === `delete`) {\n        this.publishedRows.delete(change.key)\n      } else {\n        this.publishedRows.set(change.key, change.value)\n      }\n    }\n  }\n\n  private trackSentKeys(changes: Array<ChangeMessage<any, string | number>>) {\n    if (this.loadedInitialState || this.skipFiltering) {\n      // No need to track sent keys if we loaded the entire state or filtering is skipped.\n      // Since filtering won't be applied, all keys are effectively \"observed\".\n      return\n    }\n\n    for (const change of changes) {\n      if (change.type === `delete`) {\n        this.sentKeys.delete(change.key)\n      } else {\n        this.sentKeys.add(change.key)\n      }\n    }\n\n    // Keep the limited snapshot offset in sync with keys we've actually sent.\n    // This matters when loadSubset resolves asynchronously and requestLimitedSnapshot\n    // didn't have local rows to count yet.\n    if (this.orderByIndex) {\n      this.limitedSnapshotRowCount = Math.max(\n        this.limitedSnapshotRowCount,\n        this.sentKeys.size,\n      )\n    }\n  }\n\n  /**\n   * Mark that the subscription should not filter any changes.\n   * This is used when includeInitialState is explicitly set to false,\n   * meaning the caller doesn't want initial state but does want ALL future changes.\n   */\n  markAllStateAsSeen() {\n    this.skipFiltering = true\n  }\n\n  unsubscribe() {\n    if (this.unsubscribed) return\n    this.unsubscribed = true\n    // Stop any status listener set already being iterated. Clearing the\n    // emitter's map cannot invalidate that captured Set by itself.\n    this.statusRevision++\n    const sourceListenerCleanups = [\n      this.truncateCleanup,\n      this.collectionCleanup,\n      this.collectionRestartCleanup,\n    ]\n    this.truncateCleanup = undefined\n    this.collectionCleanup = undefined\n    this.collectionRestartCleanup = undefined\n\n    runAllCallbacks([\n      ...sourceListenerCleanups.map((cleanup) => () => cleanup?.()),\n      () => {\n        // Stop any buffered replay from publishing after unsubscription.\n        this.discardTruncateReplay()\n        this.stalePublishedRows.clear()\n\n        // Retire every owner before an unload can reenter teardown.\n        const acquisitions = this.subsetDemands\n          .filter((demand) => demand.acquisitionState === `active`)\n          .map((demand) => demand.acquisition)\n        for (const demand of this.subsetDemands) {\n          demand.initialResult?.reject(new LoadSubsetOperationAbortedError())\n          this.stopDemandStatusParticipants(demand)\n          if (demand.acquisitionState === `starting`) {\n            cancelAcquisition(demand.acquisition)\n          }\n        }\n        this.subsetDemands = []\n        runAllCallbacks(\n          acquisitions.map(\n            (acquisition) => () => this.releaseAcquisition(acquisition),\n          ),\n        )\n      },\n      () =>\n        this.emitInner(`unsubscribed`, {\n          type: `unsubscribed`,\n          subscription: this,\n        }),\n      // Clear all event listeners to prevent memory leaks\n      () => this.clearListeners(),\n    ])\n  }\n}\n"],"names":["createDeferred","EventEmitter","ensureIndexForExpression","createFilteredCallback","LoadSubsetOperationAbortedError","error","normalizeError","deepEquals","and","runAllCallbacks","buildCursor","createFilterFunctionFromExpression","eq","Value","compileExpression","PropRef","buildCursorCurrent"],"mappings":"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"}