{"version":3,"file":"state.cjs","sources":["../../../src/collection/state.ts"],"sourcesContent":["import { deepEquals } from '../utils'\nimport { SortedMap } from '../SortedMap'\nimport type { Transaction } from '../transactions'\nimport type { StandardSchemaV1 } from '@standard-schema/spec'\nimport type {\n  ChangeMessage,\n  CollectionConfig,\n  OptimisticChangeMessage,\n} from '../types'\nimport type { CollectionImpl } from './index.js'\nimport type { CollectionLifecycleManager } from './lifecycle'\nimport type { CollectionChangesManager } from './changes'\nimport type { CollectionIndexesManager } from './indexes'\nimport type { CollectionEventsManager } from './events'\n\ninterface PendingSyncedTransaction<\n  T extends object = Record<string, unknown>,\n  TKey extends string | number = string | number,\n> {\n  committed: boolean\n  operations: Array<OptimisticChangeMessage<T>>\n  truncate?: boolean\n  deletedKeys: Set<string | number>\n  optimisticSnapshot?: {\n    upserts: Map<TKey, T>\n    deletes: Set<TKey>\n  }\n  /**\n   * When true, this transaction should be processed immediately even if there\n   * are persisting user transactions. Used by manual write operations (writeInsert,\n   * writeUpdate, writeDelete, writeUpsert) which need synchronous updates to syncedData.\n   */\n  immediate?: boolean\n}\n\nexport class CollectionStateManager<\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  public config!: CollectionConfig<TOutput, TKey, TSchema>\n  public collection!: CollectionImpl<TOutput, TKey, any, TSchema, TInput>\n  public lifecycle!: CollectionLifecycleManager<TOutput, TKey, TSchema, TInput>\n  public changes!: CollectionChangesManager<TOutput, TKey, TSchema, TInput>\n  public indexes!: CollectionIndexesManager<TOutput, TKey, TSchema, TInput>\n  private _events!: CollectionEventsManager\n\n  // Core state - make public for testing\n  public transactions: SortedMap<string, Transaction<any>>\n  public pendingSyncedTransactions: Array<\n    PendingSyncedTransaction<TOutput, TKey>\n  > = []\n  public syncedData: SortedMap<TKey, TOutput>\n  public syncedMetadata = new Map<TKey, unknown>()\n\n  // Optimistic state tracking - make public for testing\n  public optimisticUpserts = new Map<TKey, TOutput>()\n  public optimisticDeletes = new Set<TKey>()\n\n  // Cached size for performance\n  public size = 0\n\n  // State used for computing the change events\n  public syncedKeys = new Set<TKey>()\n  public preSyncVisibleState = new Map<TKey, TOutput>()\n  public recentlySyncedKeys = new Set<TKey>()\n  public hasReceivedFirstCommit = false\n  public isCommittingSyncTransactions = false\n\n  /**\n   * Creates a new CollectionState manager\n   */\n  constructor(config: CollectionConfig<TOutput, TKey, TSchema>) {\n    this.config = config\n    this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n      a.compareCreatedAt(b),\n    )\n\n    // Set up data storage - always use SortedMap for deterministic iteration.\n    // If a custom compare function is provided, use it; otherwise entries are sorted by key only.\n    this.syncedData = new SortedMap<TKey, TOutput>(config.compare)\n  }\n\n  setDeps(deps: {\n    collection: CollectionImpl<TOutput, TKey, any, TSchema, TInput>\n    lifecycle: CollectionLifecycleManager<TOutput, TKey, TSchema, TInput>\n    changes: CollectionChangesManager<TOutput, TKey, TSchema, TInput>\n    indexes: CollectionIndexesManager<TOutput, TKey, TSchema, TInput>\n    events: CollectionEventsManager\n  }) {\n    this.collection = deps.collection\n    this.lifecycle = deps.lifecycle\n    this.changes = deps.changes\n    this.indexes = deps.indexes\n    this._events = deps.events\n  }\n\n  /**\n   * Get the current value for a key (virtual derived state)\n   */\n  public get(key: TKey): TOutput | undefined {\n    const { optimisticDeletes, optimisticUpserts, syncedData } = this\n    // Check if optimistically deleted\n    if (optimisticDeletes.has(key)) {\n      return undefined\n    }\n\n    // Check optimistic upserts first\n    if (optimisticUpserts.has(key)) {\n      return optimisticUpserts.get(key)\n    }\n\n    // Fall back to synced data\n    return syncedData.get(key)\n  }\n\n  /**\n   * Check if a key exists in the collection (virtual derived state)\n   */\n  public has(key: TKey): boolean {\n    const { optimisticDeletes, optimisticUpserts, syncedData } = this\n    // Check if optimistically deleted\n    if (optimisticDeletes.has(key)) {\n      return false\n    }\n\n    // Check optimistic upserts first\n    if (optimisticUpserts.has(key)) {\n      return true\n    }\n\n    // Fall back to synced data\n    return syncedData.has(key)\n  }\n\n  /**\n   * Get all keys (virtual derived state)\n   */\n  public *keys(): IterableIterator<TKey> {\n    const { syncedData, optimisticDeletes, optimisticUpserts } = this\n    // Yield keys from synced data, skipping any that are deleted.\n    for (const key of syncedData.keys()) {\n      if (!optimisticDeletes.has(key)) {\n        yield key\n      }\n    }\n    // Yield keys from upserts that were not already in synced data.\n    for (const key of optimisticUpserts.keys()) {\n      if (!syncedData.has(key) && !optimisticDeletes.has(key)) {\n        // The optimisticDeletes check is technically redundant if inserts/updates always remove from deletes,\n        // but it's safer to keep it.\n        yield key\n      }\n    }\n  }\n\n  /**\n   * Get all values (virtual derived state)\n   */\n  public *values(): IterableIterator<TOutput> {\n    for (const key of this.keys()) {\n      const value = this.get(key)\n      if (value !== undefined) {\n        yield value\n      }\n    }\n  }\n\n  /**\n   * Get all entries (virtual derived state)\n   */\n  public *entries(): IterableIterator<[TKey, TOutput]> {\n    for (const key of this.keys()) {\n      const value = this.get(key)\n      if (value !== undefined) {\n        yield [key, value]\n      }\n    }\n  }\n\n  /**\n   * Get all entries (virtual derived state)\n   */\n  public *[Symbol.iterator](): IterableIterator<[TKey, TOutput]> {\n    for (const [key, value] of this.entries()) {\n      yield [key, value]\n    }\n  }\n\n  /**\n   * Execute a callback for each entry in the collection\n   */\n  public forEach(\n    callbackfn: (value: TOutput, key: TKey, index: number) => void,\n  ): void {\n    let index = 0\n    for (const [key, value] of this.entries()) {\n      callbackfn(value, key, index++)\n    }\n  }\n\n  /**\n   * Create a new array with the results of calling a function for each entry in the collection\n   */\n  public map<U>(\n    callbackfn: (value: TOutput, key: TKey, index: number) => U,\n  ): Array<U> {\n    const result: Array<U> = []\n    let index = 0\n    for (const [key, value] of this.entries()) {\n      result.push(callbackfn(value, key, index++))\n    }\n    return result\n  }\n\n  /**\n   * Check if the given collection is this collection\n   * @param collection The collection to check\n   * @returns True if the given collection is this collection, false otherwise\n   */\n  private isThisCollection(\n    collection: CollectionImpl<any, any, any, any, any>,\n  ): boolean {\n    return collection === this.collection\n  }\n\n  /**\n   * Recompute optimistic state from active transactions\n   */\n  public recomputeOptimisticState(\n    triggeredByUserAction: boolean = false,\n  ): void {\n    // Skip redundant recalculations when we're in the middle of committing sync transactions\n    // While the sync pipeline is replaying a large batch we still want to honour\n    // fresh optimistic mutations from the UI. Only skip recompute for the\n    // internal sync-driven redraws; user-triggered work (triggeredByUserAction)\n    // must run so live queries stay responsive during long commits.\n    if (this.isCommittingSyncTransactions && !triggeredByUserAction) {\n      return\n    }\n\n    const previousState = new Map(this.optimisticUpserts)\n    const previousDeletes = new Set(this.optimisticDeletes)\n\n    // Clear current optimistic state\n    this.optimisticUpserts.clear()\n    this.optimisticDeletes.clear()\n\n    const activeTransactions: Array<Transaction<any>> = []\n\n    for (const transaction of this.transactions.values()) {\n      if (![`completed`, `failed`].includes(transaction.state)) {\n        activeTransactions.push(transaction)\n      }\n    }\n\n    // Apply active transactions only (completed transactions are handled by sync operations)\n    for (const transaction of activeTransactions) {\n      for (const mutation of transaction.mutations) {\n        if (this.isThisCollection(mutation.collection) && mutation.optimistic) {\n          switch (mutation.type) {\n            case `insert`:\n            case `update`:\n              this.optimisticUpserts.set(\n                mutation.key,\n                mutation.modified as TOutput,\n              )\n              this.optimisticDeletes.delete(mutation.key)\n              break\n            case `delete`:\n              this.optimisticUpserts.delete(mutation.key)\n              this.optimisticDeletes.add(mutation.key)\n              break\n          }\n        }\n      }\n    }\n\n    // Update cached size\n    this.size = this.calculateSize()\n\n    // Collect events for changes\n    const events: Array<ChangeMessage<TOutput, TKey>> = []\n    this.collectOptimisticChanges(previousState, previousDeletes, events)\n\n    // Filter out events for recently synced keys to prevent duplicates\n    // BUT: Only filter out events that are actually from sync operations\n    // New user transactions should NOT be filtered even if the key was recently synced\n    const filteredEventsBySyncStatus = events.filter((event) => {\n      if (!this.recentlySyncedKeys.has(event.key)) {\n        return true // Key not recently synced, allow event through\n      }\n\n      // Key was recently synced - allow if this is a user-triggered action\n      if (triggeredByUserAction) {\n        return true\n      }\n\n      // Otherwise filter out duplicate sync events\n      return false\n    })\n\n    // Filter out redundant delete events if there are pending sync transactions\n    // that will immediately restore the same data, but only for completed transactions\n    // IMPORTANT: Skip complex filtering for user-triggered actions to prevent UI blocking\n    if (this.pendingSyncedTransactions.length > 0 && !triggeredByUserAction) {\n      const pendingSyncKeys = new Set<TKey>()\n\n      // Collect keys from pending sync operations\n      for (const transaction of this.pendingSyncedTransactions) {\n        for (const operation of transaction.operations) {\n          pendingSyncKeys.add(operation.key as TKey)\n        }\n      }\n\n      // Only filter out delete events for keys that:\n      // 1. Have pending sync operations AND\n      // 2. Are from completed transactions (being cleaned up)\n      const filteredEvents = filteredEventsBySyncStatus.filter((event) => {\n        if (event.type === `delete` && pendingSyncKeys.has(event.key)) {\n          // Check if this delete is from clearing optimistic state of completed transactions\n          // We can infer this by checking if we have no remaining optimistic mutations for this key\n          const hasActiveOptimisticMutation = activeTransactions.some((tx) =>\n            tx.mutations.some(\n              (m) => this.isThisCollection(m.collection) && m.key === event.key,\n            ),\n          )\n\n          if (!hasActiveOptimisticMutation) {\n            return false // Skip this delete event as sync will restore the data\n          }\n        }\n        return true\n      })\n\n      // Update indexes for the filtered events\n      if (filteredEvents.length > 0) {\n        this.indexes.updateIndexes(filteredEvents)\n      }\n      this.changes.emitEvents(filteredEvents, triggeredByUserAction)\n    } else {\n      // Update indexes for all events\n      if (filteredEventsBySyncStatus.length > 0) {\n        this.indexes.updateIndexes(filteredEventsBySyncStatus)\n      }\n      // Emit all events if no pending sync transactions\n      this.changes.emitEvents(filteredEventsBySyncStatus, triggeredByUserAction)\n    }\n  }\n\n  /**\n   * Calculate the current size based on synced data and optimistic changes\n   */\n  private calculateSize(): number {\n    const syncedSize = this.syncedData.size\n    const deletesFromSynced = Array.from(this.optimisticDeletes).filter(\n      (key) => this.syncedData.has(key) && !this.optimisticUpserts.has(key),\n    ).length\n    const upsertsNotInSynced = Array.from(this.optimisticUpserts.keys()).filter(\n      (key) => !this.syncedData.has(key),\n    ).length\n\n    return syncedSize - deletesFromSynced + upsertsNotInSynced\n  }\n\n  /**\n   * Collect events for optimistic changes\n   */\n  private collectOptimisticChanges(\n    previousUpserts: Map<TKey, TOutput>,\n    previousDeletes: Set<TKey>,\n    events: Array<ChangeMessage<TOutput, TKey>>,\n  ): void {\n    const allKeys = new Set([\n      ...previousUpserts.keys(),\n      ...this.optimisticUpserts.keys(),\n      ...previousDeletes,\n      ...this.optimisticDeletes,\n    ])\n\n    for (const key of allKeys) {\n      const currentValue = this.get(key)\n      const previousValue = this.getPreviousValue(\n        key,\n        previousUpserts,\n        previousDeletes,\n      )\n\n      if (previousValue !== undefined && currentValue === undefined) {\n        events.push({ type: `delete`, key, value: previousValue })\n      } else if (previousValue === undefined && currentValue !== undefined) {\n        events.push({ type: `insert`, key, value: currentValue })\n      } else if (\n        previousValue !== undefined &&\n        currentValue !== undefined &&\n        previousValue !== currentValue\n      ) {\n        events.push({\n          type: `update`,\n          key,\n          value: currentValue,\n          previousValue,\n        })\n      }\n    }\n  }\n\n  /**\n   * Get the previous value for a key given previous optimistic state\n   */\n  private getPreviousValue(\n    key: TKey,\n    previousUpserts: Map<TKey, TOutput>,\n    previousDeletes: Set<TKey>,\n  ): TOutput | undefined {\n    if (previousDeletes.has(key)) {\n      return undefined\n    }\n    if (previousUpserts.has(key)) {\n      return previousUpserts.get(key)\n    }\n    return this.syncedData.get(key)\n  }\n\n  /**\n   * Attempts to commit pending synced transactions if there are no active transactions\n   * This method processes operations from pending transactions and applies them to the synced data\n   */\n  commitPendingTransactions = () => {\n    // Check if there are any persisting transaction\n    let hasPersistingTransaction = false\n    for (const transaction of this.transactions.values()) {\n      if (transaction.state === `persisting`) {\n        hasPersistingTransaction = true\n        break\n      }\n    }\n\n    // pending synced transactions could be either `committed` or still open.\n    // we only want to process `committed` transactions here\n    const {\n      committedSyncedTransactions,\n      uncommittedSyncedTransactions,\n      hasTruncateSync,\n      hasImmediateSync,\n    } = this.pendingSyncedTransactions.reduce(\n      (acc, t) => {\n        if (t.committed) {\n          acc.committedSyncedTransactions.push(t)\n          if (t.truncate) {\n            acc.hasTruncateSync = true\n          }\n          if (t.immediate) {\n            acc.hasImmediateSync = true\n          }\n        } else {\n          acc.uncommittedSyncedTransactions.push(t)\n        }\n        return acc\n      },\n      {\n        committedSyncedTransactions: [] as Array<\n          PendingSyncedTransaction<TOutput, TKey>\n        >,\n        uncommittedSyncedTransactions: [] as Array<\n          PendingSyncedTransaction<TOutput, TKey>\n        >,\n        hasTruncateSync: false,\n        hasImmediateSync: false,\n      },\n    )\n\n    // Process committed transactions if:\n    // 1. No persisting user transaction (normal sync flow), OR\n    // 2. There's a truncate operation (must be processed immediately), OR\n    // 3. There's an immediate transaction (manual writes must be processed synchronously)\n    //\n    // Note: When hasImmediateSync or hasTruncateSync is true, we process ALL committed\n    // sync transactions (not just the immediate/truncate ones). This is intentional for\n    // ordering correctness: if we only processed the immediate transaction, earlier\n    // non-immediate transactions would be applied later and could overwrite newer state.\n    // Processing all committed transactions together preserves causal ordering.\n    if (!hasPersistingTransaction || hasTruncateSync || hasImmediateSync) {\n      // Set flag to prevent redundant optimistic state recalculations\n      this.isCommittingSyncTransactions = true\n\n      // Get the optimistic snapshot from the truncate transaction (captured when truncate() was called)\n      const truncateOptimisticSnapshot = hasTruncateSync\n        ? committedSyncedTransactions.find((t) => t.truncate)\n            ?.optimisticSnapshot\n        : null\n\n      // First collect all keys that will be affected by sync operations\n      const changedKeys = new Set<TKey>()\n      for (const transaction of committedSyncedTransactions) {\n        for (const operation of transaction.operations) {\n          changedKeys.add(operation.key as TKey)\n        }\n      }\n\n      // Use pre-captured state if available (from optimistic scenarios),\n      // otherwise capture current state (for pure sync scenarios)\n      let currentVisibleState = this.preSyncVisibleState\n      if (currentVisibleState.size === 0) {\n        // No pre-captured state, capture it now for pure sync operations\n        currentVisibleState = new Map<TKey, TOutput>()\n        for (const key of changedKeys) {\n          const currentValue = this.get(key)\n          if (currentValue !== undefined) {\n            currentVisibleState.set(key, currentValue)\n          }\n        }\n      }\n\n      const events: Array<ChangeMessage<TOutput, TKey>> = []\n      const rowUpdateMode = this.config.sync.rowUpdateMode || `partial`\n\n      for (const transaction of committedSyncedTransactions) {\n        // Handle truncate operations first\n        if (transaction.truncate) {\n          // TRUNCATE PHASE\n          // 1) Emit a delete for every visible key (synced + optimistic) so downstream listeners/indexes\n          //    observe a clear-before-rebuild. We intentionally skip keys already in\n          //    optimisticDeletes because their delete was previously emitted by the user.\n          // Use the snapshot to ensure we emit deletes for all items that existed at truncate start.\n          const visibleKeys = new Set([\n            ...this.syncedData.keys(),\n            ...(truncateOptimisticSnapshot?.upserts.keys() || []),\n          ])\n          for (const key of visibleKeys) {\n            if (truncateOptimisticSnapshot?.deletes.has(key)) continue\n            const previousValue =\n              truncateOptimisticSnapshot?.upserts.get(key) ||\n              this.syncedData.get(key)\n            if (previousValue !== undefined) {\n              events.push({ type: `delete`, key, value: previousValue })\n            }\n          }\n\n          // 2) Clear the authoritative synced base. Subsequent server ops in this\n          //    same commit will rebuild the base atomically.\n          this.syncedData.clear()\n          this.syncedMetadata.clear()\n          this.syncedKeys.clear()\n\n          // 3) Clear currentVisibleState for truncated keys to ensure subsequent operations\n          //    are compared against the post-truncate state (undefined) rather than pre-truncate state\n          //    This ensures that re-inserted keys are emitted as INSERT events, not UPDATE events\n          for (const key of changedKeys) {\n            currentVisibleState.delete(key)\n          }\n\n          // 4) Emit truncate event so subscriptions can reset their cursor tracking state\n          this._events.emit(`truncate`, {\n            type: `truncate`,\n            collection: this.collection,\n          })\n        }\n\n        for (const operation of transaction.operations) {\n          const key = operation.key as TKey\n          this.syncedKeys.add(key)\n\n          // Update metadata\n          switch (operation.type) {\n            case `insert`:\n              this.syncedMetadata.set(key, operation.metadata)\n              break\n            case `update`:\n              this.syncedMetadata.set(\n                key,\n                Object.assign(\n                  {},\n                  this.syncedMetadata.get(key),\n                  operation.metadata,\n                ),\n              )\n              break\n            case `delete`:\n              this.syncedMetadata.delete(key)\n              break\n          }\n\n          // Update synced data\n          switch (operation.type) {\n            case `insert`:\n              this.syncedData.set(key, operation.value)\n              break\n            case `update`: {\n              if (rowUpdateMode === `partial`) {\n                const updatedValue = Object.assign(\n                  {},\n                  this.syncedData.get(key),\n                  operation.value,\n                )\n                this.syncedData.set(key, updatedValue)\n              } else {\n                this.syncedData.set(key, operation.value)\n              }\n              break\n            }\n            case `delete`:\n              this.syncedData.delete(key)\n              break\n          }\n        }\n      }\n\n      // After applying synced operations, if this commit included a truncate,\n      // re-apply optimistic mutations on top of the fresh synced base. This ensures\n      // the UI preserves local intent while respecting server rebuild semantics.\n      // Ordering: deletes (above) -> server ops (just applied) -> optimistic upserts.\n      if (hasTruncateSync) {\n        // Avoid duplicating keys that were inserted/updated by synced operations in this commit\n        const syncedInsertedOrUpdatedKeys = new Set<TKey>()\n        for (const t of committedSyncedTransactions) {\n          for (const op of t.operations) {\n            if (op.type === `insert` || op.type === `update`) {\n              syncedInsertedOrUpdatedKeys.add(op.key as TKey)\n            }\n          }\n        }\n\n        // Build re-apply sets from the snapshot taken at the start of this function.\n        // This prevents losing optimistic state if transactions complete during truncate processing.\n        const reapplyUpserts = new Map<TKey, TOutput>(\n          truncateOptimisticSnapshot!.upserts,\n        )\n        const reapplyDeletes = new Set<TKey>(\n          truncateOptimisticSnapshot!.deletes,\n        )\n\n        // Emit inserts for re-applied upserts, skipping any keys that have an optimistic delete.\n        // If the server also inserted/updated the same key in this batch, override that value\n        // with the optimistic value to preserve local intent.\n        for (const [key, value] of reapplyUpserts) {\n          if (reapplyDeletes.has(key)) continue\n          if (syncedInsertedOrUpdatedKeys.has(key)) {\n            let foundInsert = false\n            for (let i = events.length - 1; i >= 0; i--) {\n              const evt = events[i]!\n              if (evt.key === key && evt.type === `insert`) {\n                evt.value = value\n                foundInsert = true\n                break\n              }\n            }\n            if (!foundInsert) {\n              events.push({ type: `insert`, key, value })\n            }\n          } else {\n            events.push({ type: `insert`, key, value })\n          }\n        }\n\n        // Finally, ensure we do NOT insert keys that have an outstanding optimistic delete.\n        if (events.length > 0 && reapplyDeletes.size > 0) {\n          const filtered: Array<ChangeMessage<TOutput, TKey>> = []\n          for (const evt of events) {\n            if (evt.type === `insert` && reapplyDeletes.has(evt.key)) {\n              continue\n            }\n            filtered.push(evt)\n          }\n          events.length = 0\n          events.push(...filtered)\n        }\n\n        // Ensure listeners are active before emitting this critical batch\n        if (this.lifecycle.status !== `ready`) {\n          this.lifecycle.markReady()\n        }\n      }\n\n      // Maintain optimistic state appropriately\n      // Clear optimistic state since sync operations will now provide the authoritative data.\n      // Any still-active user transactions will be re-applied below in recompute.\n      this.optimisticUpserts.clear()\n      this.optimisticDeletes.clear()\n\n      // Reset flag and recompute optimistic state for any remaining active transactions\n      this.isCommittingSyncTransactions = false\n\n      // If we had a truncate, restore the preserved optimistic state from the snapshot\n      // This includes items from transactions that may have completed during processing\n      if (hasTruncateSync && truncateOptimisticSnapshot) {\n        for (const [key, value] of truncateOptimisticSnapshot.upserts) {\n          this.optimisticUpserts.set(key, value)\n        }\n        for (const key of truncateOptimisticSnapshot.deletes) {\n          this.optimisticDeletes.add(key)\n        }\n      }\n\n      // Always overlay any still-active optimistic transactions so mutations that started\n      // after the truncate snapshot are preserved.\n      for (const transaction of this.transactions.values()) {\n        if (![`completed`, `failed`].includes(transaction.state)) {\n          for (const mutation of transaction.mutations) {\n            if (\n              this.isThisCollection(mutation.collection) &&\n              mutation.optimistic\n            ) {\n              switch (mutation.type) {\n                case `insert`:\n                case `update`:\n                  this.optimisticUpserts.set(\n                    mutation.key,\n                    mutation.modified as TOutput,\n                  )\n                  this.optimisticDeletes.delete(mutation.key)\n                  break\n                case `delete`:\n                  this.optimisticUpserts.delete(mutation.key)\n                  this.optimisticDeletes.add(mutation.key)\n                  break\n              }\n            }\n          }\n        }\n      }\n\n      // Check for redundant sync operations that match completed optimistic operations\n      const completedOptimisticOps = new Map<TKey, any>()\n\n      for (const transaction of this.transactions.values()) {\n        if (transaction.state === `completed`) {\n          for (const mutation of transaction.mutations) {\n            if (\n              mutation.optimistic &&\n              this.isThisCollection(mutation.collection) &&\n              changedKeys.has(mutation.key)\n            ) {\n              completedOptimisticOps.set(mutation.key, {\n                type: mutation.type,\n                value: mutation.modified,\n              })\n            }\n          }\n        }\n      }\n\n      // Now check what actually changed in the final visible state\n      for (const key of changedKeys) {\n        const previousVisibleValue = currentVisibleState.get(key)\n        const newVisibleValue = this.get(key) // This returns the new derived state\n\n        // Check if this sync operation is redundant with a completed optimistic operation\n        const completedOp = completedOptimisticOps.get(key)\n        let isRedundantSync = false\n\n        if (completedOp) {\n          if (\n            completedOp.type === `delete` &&\n            previousVisibleValue !== undefined &&\n            newVisibleValue === undefined &&\n            deepEquals(completedOp.value, previousVisibleValue)\n          ) {\n            isRedundantSync = true\n          } else if (\n            newVisibleValue !== undefined &&\n            deepEquals(completedOp.value, newVisibleValue)\n          ) {\n            isRedundantSync = true\n          }\n        }\n\n        if (!isRedundantSync) {\n          if (\n            previousVisibleValue === undefined &&\n            newVisibleValue !== undefined\n          ) {\n            events.push({\n              type: `insert`,\n              key,\n              value: newVisibleValue,\n            })\n          } else if (\n            previousVisibleValue !== undefined &&\n            newVisibleValue === undefined\n          ) {\n            events.push({\n              type: `delete`,\n              key,\n              value: previousVisibleValue,\n            })\n          } else if (\n            previousVisibleValue !== undefined &&\n            newVisibleValue !== undefined &&\n            !deepEquals(previousVisibleValue, newVisibleValue)\n          ) {\n            events.push({\n              type: `update`,\n              key,\n              value: newVisibleValue,\n              previousValue: previousVisibleValue,\n            })\n          }\n        }\n      }\n\n      // Update cached size after synced data changes\n      this.size = this.calculateSize()\n\n      // Update indexes for all events before emitting\n      if (events.length > 0) {\n        this.indexes.updateIndexes(events)\n      }\n\n      // End batching and emit all events (combines any batched events with sync events)\n      this.changes.emitEvents(events, true)\n\n      this.pendingSyncedTransactions = uncommittedSyncedTransactions\n\n      // Clear the pre-sync state since sync operations are complete\n      this.preSyncVisibleState.clear()\n\n      // Clear recently synced keys after a microtask to allow recomputeOptimisticState to see them\n      Promise.resolve().then(() => {\n        this.recentlySyncedKeys.clear()\n      })\n\n      // Mark that we've received the first commit (for tracking purposes)\n      if (!this.hasReceivedFirstCommit) {\n        this.hasReceivedFirstCommit = true\n      }\n    }\n  }\n\n  /**\n   * Schedule cleanup of a transaction when it completes\n   */\n  public scheduleTransactionCleanup(transaction: Transaction<any>): void {\n    // Only schedule cleanup for transactions that aren't already completed\n    if (transaction.state === `completed`) {\n      this.transactions.delete(transaction.id)\n      return\n    }\n\n    // Schedule cleanup when the transaction completes\n    transaction.isPersisted.promise\n      .then(() => {\n        // Transaction completed successfully, remove it immediately\n        this.transactions.delete(transaction.id)\n      })\n      .catch(() => {\n        // Transaction failed, but we want to keep failed transactions for reference\n        // so don't remove it.\n        // This empty catch block is necessary to prevent unhandled promise rejections.\n      })\n  }\n\n  /**\n   * Capture visible state for keys that will be affected by pending sync operations\n   * This must be called BEFORE onTransactionStateChange clears optimistic state\n   */\n  public capturePreSyncVisibleState(): void {\n    if (this.pendingSyncedTransactions.length === 0) return\n\n    // Get all keys that will be affected by sync operations\n    const syncedKeys = new Set<TKey>()\n    for (const transaction of this.pendingSyncedTransactions) {\n      for (const operation of transaction.operations) {\n        syncedKeys.add(operation.key as TKey)\n      }\n    }\n\n    // Mark keys as about to be synced to suppress intermediate events from recomputeOptimisticState\n    for (const key of syncedKeys) {\n      this.recentlySyncedKeys.add(key)\n    }\n\n    // Only capture current visible state for keys that will be affected by sync operations\n    // This is much more efficient than capturing the entire collection state\n    // Only capture keys that haven't been captured yet to preserve earlier captures\n    for (const key of syncedKeys) {\n      if (!this.preSyncVisibleState.has(key)) {\n        const currentValue = this.get(key)\n        if (currentValue !== undefined) {\n          this.preSyncVisibleState.set(key, currentValue)\n        }\n      }\n    }\n  }\n\n  /**\n   * Trigger a recomputation when transactions change\n   * This method should be called by the Transaction class when state changes\n   */\n  public onTransactionStateChange(): void {\n    // Check if commitPendingTransactions will be called after this\n    // by checking if there are pending sync transactions (same logic as in transactions.ts)\n    this.changes.shouldBatchEvents = this.pendingSyncedTransactions.length > 0\n\n    // CRITICAL: Capture visible state BEFORE clearing optimistic state\n    this.capturePreSyncVisibleState()\n\n    this.recomputeOptimisticState(false)\n  }\n\n  /**\n   * Clean up the collection by stopping sync and clearing data\n   * This can be called manually or automatically by garbage collection\n   */\n  public cleanup(): void {\n    this.syncedData.clear()\n    this.syncedMetadata.clear()\n    this.optimisticUpserts.clear()\n    this.optimisticDeletes.clear()\n    this.size = 0\n    this.pendingSyncedTransactions = []\n    this.syncedKeys.clear()\n    this.hasReceivedFirstCommit = false\n  }\n}\n"],"names":["deepEquals","SortedMap"],"mappings":"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"}