@tanstack/db 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"collection.js","sources":["../../src/collection.ts"],"sourcesContent":["import { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { deepEquals } from \"./utils\"\nimport { SortedMap } from \"./SortedMap\"\nimport {\n createSingleRowRefProxy,\n toExpression,\n} from \"./query/builder/ref-proxy\"\nimport { BTreeIndex } from \"./indexes/btree-index.js\"\nimport { IndexProxy, LazyIndexWrapper } from \"./indexes/lazy-index.js\"\nimport { ensureIndexForExpression } from \"./indexes/auto-index.js\"\nimport { createTransaction, getActiveTransaction } from \"./transactions\"\nimport {\n CollectionInErrorStateError,\n CollectionIsInErrorStateError,\n CollectionRequiresConfigError,\n CollectionRequiresSyncConfigError,\n DeleteKeyNotFoundError,\n DuplicateKeyError,\n DuplicateKeySyncError,\n InvalidCollectionStatusTransitionError,\n InvalidSchemaError,\n KeyUpdateNotAllowedError,\n MissingDeleteHandlerError,\n MissingInsertHandlerError,\n MissingUpdateArgumentError,\n MissingUpdateHandlerError,\n NegativeActiveSubscribersError,\n NoKeysPassedToDeleteError,\n NoKeysPassedToUpdateError,\n NoPendingSyncTransactionCommitError,\n NoPendingSyncTransactionWriteError,\n SchemaMustBeSynchronousError,\n SchemaValidationError,\n SyncCleanupError,\n SyncTransactionAlreadyCommittedError,\n SyncTransactionAlreadyCommittedWriteError,\n UndefinedKeyError,\n UpdateKeyNotFoundError,\n} from \"./errors\"\nimport { createFilteredCallback, currentStateAsChanges } from \"./change-events\"\nimport type { Transaction } from \"./transactions\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport type { SingleRowRefProxy } from \"./query/builder/ref-proxy\"\nimport type {\n ChangeListener,\n ChangeMessage,\n CollectionConfig,\n CollectionStatus,\n CurrentStateAsChangesOptions,\n Fn,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n ResolveInsertInput,\n ResolveType,\n StandardSchema,\n SubscribeChangesOptions,\n Transaction as TransactionType,\n TransactionWithMutations,\n UtilsRecord,\n WritableDeep,\n} from \"./types\"\nimport type { IndexOptions } from \"./indexes/index-options.js\"\nimport type { BaseIndex, IndexResolver } from \"./indexes/base-index.js\"\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\n truncate?: boolean\n deletedKeys: Set<string | number>\n}\n\n/**\n * Enhanced Collection interface that includes both data type T and utilities TUtils\n * @template T - The type of items in the collection\n * @template TKey - The type of the key for the collection\n * @template TUtils - The utilities record type\n * @template TInsertInput - The type for insert operations (can be different from T for schemas with defaults)\n */\nexport interface Collection<\n T extends object = Record<string, unknown>,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TInsertInput extends object = T,\n> extends CollectionImpl<T, TKey, TUtils, TSchema, TInsertInput> {\n readonly utils: TUtils\n}\n\n/**\n * Creates a new Collection instance with the given configuration\n *\n * @template TExplicit - The explicit type of items in the collection (highest priority)\n * @template TKey - The type of the key for the collection\n * @template TUtils - The utilities record type\n * @template TSchema - The schema type for validation and type inference (second priority)\n * @template TFallback - The fallback type if no explicit or schema type is provided\n * @param options - Collection options with optional utilities\n * @returns A new Collection with utilities exposed both at top level and under .utils\n *\n * @example\n * // Pattern 1: With operation handlers (direct collection calls)\n * const todos = createCollection({\n * id: \"todos\",\n * getKey: (todo) => todo.id,\n * schema,\n * onInsert: async ({ transaction, collection }) => {\n * // Send to API\n * await api.createTodo(transaction.mutations[0].modified)\n * },\n * onUpdate: async ({ transaction, collection }) => {\n * await api.updateTodo(transaction.mutations[0].modified)\n * },\n * onDelete: async ({ transaction, collection }) => {\n * await api.deleteTodo(transaction.mutations[0].key)\n * },\n * sync: { sync: () => {} }\n * })\n *\n * // Direct usage (handlers manage transactions)\n * const tx = todos.insert({ id: \"1\", text: \"Buy milk\", completed: false })\n * await tx.isPersisted.promise\n *\n * @example\n * // Pattern 2: Manual transaction management\n * const todos = createCollection({\n * getKey: (todo) => todo.id,\n * schema: todoSchema,\n * sync: { sync: () => {} }\n * })\n *\n * // Explicit transaction usage\n * const tx = createTransaction({\n * mutationFn: async ({ transaction }) => {\n * // Handle all mutations in transaction\n * await api.saveChanges(transaction.mutations)\n * }\n * })\n *\n * tx.mutate(() => {\n * todos.insert({ id: \"1\", text: \"Buy milk\" })\n * todos.update(\"2\", draft => { draft.completed = true })\n * })\n *\n * await tx.isPersisted.promise\n *\n * @example\n * // Using schema for type inference (preferred as it also gives you client side validation)\n * const todoSchema = z.object({\n * id: z.string(),\n * title: z.string(),\n * completed: z.boolean()\n * })\n *\n * const todos = createCollection({\n * schema: todoSchema,\n * getKey: (todo) => todo.id,\n * sync: { sync: () => {} }\n * })\n *\n * // Note: You can provide an explicit type, a schema, or both. When both are provided, the explicit type takes precedence.\n */\n\n// Overload for when schema is provided - infers schema type\nexport function createCollection<\n TSchema extends StandardSchemaV1,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TFallback extends object = Record<string, unknown>,\n>(\n options: CollectionConfig<\n ResolveType<unknown, TSchema, TFallback>,\n TKey,\n TSchema,\n ResolveInsertInput<unknown, TSchema, TFallback>\n > & {\n schema: TSchema\n utils?: TUtils\n }\n): Collection<\n ResolveType<unknown, TSchema, TFallback>,\n TKey,\n TUtils,\n TSchema,\n ResolveInsertInput<unknown, TSchema, TFallback>\n>\n\n// Overload for when explicit type is provided with schema - explicit type takes precedence\nexport function createCollection<\n TExplicit extends object,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TFallback extends object = Record<string, unknown>,\n>(\n options: CollectionConfig<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n > & {\n schema: TSchema\n utils?: TUtils\n }\n): Collection<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TUtils,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n>\n\n// Overload for when explicit type is provided or no schema\nexport function createCollection<\n TExplicit = unknown,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TFallback extends object = Record<string, unknown>,\n>(\n options: CollectionConfig<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n > & { utils?: TUtils }\n): Collection<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TUtils,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n>\n\n// Implementation\nexport function createCollection<\n TExplicit = unknown,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TFallback extends object = Record<string, unknown>,\n>(\n options: CollectionConfig<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n > & { utils?: TUtils }\n): Collection<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TUtils,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n> {\n const collection = new CollectionImpl<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TUtils,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n >(options)\n\n // Copy utils to both top level and .utils namespace\n if (options.utils) {\n collection.utils = { ...options.utils }\n } else {\n collection.utils = {} as TUtils\n }\n\n return collection as Collection<\n ResolveType<TExplicit, TSchema, TFallback>,\n TKey,\n TUtils,\n TSchema,\n ResolveInsertInput<TExplicit, TSchema, TFallback>\n >\n}\n\nexport class CollectionImpl<\n T extends object = Record<string, unknown>,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TInsertInput extends object = T,\n> {\n public config: CollectionConfig<T, TKey, TSchema, TInsertInput>\n\n // Core state - make public for testing\n public transactions: SortedMap<string, Transaction<any>>\n public pendingSyncedTransactions: Array<PendingSyncedTransaction<T>> = []\n public syncedData: Map<TKey, T> | SortedMap<TKey, T>\n public syncedMetadata = new Map<TKey, unknown>()\n\n // Optimistic state tracking - make public for testing\n public optimisticUpserts = new Map<TKey, T>()\n public optimisticDeletes = new Set<TKey>()\n\n // Cached size for performance\n private _size = 0\n\n // Index storage\n private lazyIndexes = new Map<number, LazyIndexWrapper<TKey>>()\n private resolvedIndexes = new Map<number, BaseIndex<TKey>>()\n private isIndexesResolved = false\n private indexCounter = 0\n\n // Event system\n private changeListeners = new Set<ChangeListener<T, TKey>>()\n private changeKeyListeners = new Map<TKey, Set<ChangeListener<T, TKey>>>()\n\n // Utilities namespace\n // This is populated by createCollection\n public utils: Record<string, Fn> = {}\n\n // State used for computing the change events\n private syncedKeys = new Set<TKey>()\n private preSyncVisibleState = new Map<TKey, T>()\n private recentlySyncedKeys = new Set<TKey>()\n private hasReceivedFirstCommit = false\n private isCommittingSyncTransactions = false\n\n // Array to store one-time ready listeners\n private onFirstReadyCallbacks: Array<() => void> = []\n private hasBeenReady = false\n\n // Event batching for preventing duplicate emissions during transaction flows\n private batchedEvents: Array<ChangeMessage<T, TKey>> = []\n private shouldBatchEvents = false\n\n // Lifecycle management\n private _status: CollectionStatus = `idle`\n private activeSubscribersCount = 0\n private gcTimeoutId: ReturnType<typeof setTimeout> | null = null\n private preloadPromise: Promise<void> | null = null\n private syncCleanupFn: (() => void) | null = null\n\n /**\n * Register a callback to be executed when the collection first becomes ready\n * Useful for preloading collections\n * @param callback Function to call when the collection first becomes ready\n * @example\n * collection.onFirstReady(() => {\n * console.log('Collection is ready for the first time')\n * // Safe to access collection.state now\n * })\n */\n public onFirstReady(callback: () => void): void {\n // If already ready, call immediately\n if (this.hasBeenReady) {\n callback()\n return\n }\n\n this.onFirstReadyCallbacks.push(callback)\n }\n\n /**\n * Check if the collection is ready for use\n * Returns true if the collection has been marked as ready by its sync implementation\n * @returns true if the collection is ready, false otherwise\n * @example\n * if (collection.isReady()) {\n * console.log('Collection is ready, data is available')\n * // Safe to access collection.state\n * } else {\n * console.log('Collection is still loading')\n * }\n */\n public isReady(): boolean {\n return this._status === `ready`\n }\n\n /**\n * Mark the collection as ready for use\n * This is called by sync implementations to explicitly signal that the collection is ready,\n * providing a more intuitive alternative to using commits for readiness signaling\n * @private - Should only be called by sync implementations\n */\n private markReady(): void {\n // Can transition to ready from loading or initialCommit states\n if (this._status === `loading` || this._status === `initialCommit`) {\n this.setStatus(`ready`)\n\n // Call any registered first ready callbacks (only on first time becoming ready)\n if (!this.hasBeenReady) {\n this.hasBeenReady = true\n\n // Also mark as having received first commit for backwards compatibility\n if (!this.hasReceivedFirstCommit) {\n this.hasReceivedFirstCommit = true\n }\n\n const callbacks = [...this.onFirstReadyCallbacks]\n this.onFirstReadyCallbacks = []\n callbacks.forEach((callback) => callback())\n }\n }\n\n // Always notify dependents when markReady is called, after status is set\n // This ensures live queries get notified when their dependencies become ready\n if (this.changeListeners.size > 0) {\n this.emitEmptyReadyEvent()\n }\n }\n\n public id = ``\n\n /**\n * Gets the current status of the collection\n */\n public get status(): CollectionStatus {\n return this._status\n }\n\n /**\n * Validates that the collection is in a usable state for data operations\n * @private\n */\n private validateCollectionUsable(operation: string): void {\n switch (this._status) {\n case `error`:\n throw new CollectionInErrorStateError(operation, this.id)\n case `cleaned-up`:\n // Automatically restart the collection when operations are called on cleaned-up collections\n this.startSync()\n break\n }\n }\n\n /**\n * Validates state transitions to prevent invalid status changes\n * @private\n */\n private validateStatusTransition(\n from: CollectionStatus,\n to: CollectionStatus\n ): void {\n if (from === to) {\n // Allow same state transitions\n return\n }\n const validTransitions: Record<\n CollectionStatus,\n Array<CollectionStatus>\n > = {\n idle: [`loading`, `error`, `cleaned-up`],\n loading: [`initialCommit`, `ready`, `error`, `cleaned-up`],\n initialCommit: [`ready`, `error`, `cleaned-up`],\n ready: [`cleaned-up`, `error`],\n error: [`cleaned-up`, `idle`],\n \"cleaned-up\": [`loading`, `error`],\n }\n\n if (!validTransitions[from].includes(to)) {\n throw new InvalidCollectionStatusTransitionError(from, to, this.id)\n }\n }\n\n /**\n * Safely update the collection status with validation\n * @private\n */\n private setStatus(newStatus: CollectionStatus): void {\n this.validateStatusTransition(this._status, newStatus)\n this._status = newStatus\n\n // Resolve indexes when collection becomes ready\n if (newStatus === `ready` && !this.isIndexesResolved) {\n // Resolve indexes asynchronously without blocking\n this.resolveAllIndexes().catch((error) => {\n console.warn(`Failed to resolve indexes:`, error)\n })\n }\n }\n\n /**\n * Creates a new Collection instance\n *\n * @param config - Configuration object for the collection\n * @throws Error if sync config is missing\n */\n constructor(config: CollectionConfig<T, TKey, TSchema, TInsertInput>) {\n // eslint-disable-next-line\n if (!config) {\n throw new CollectionRequiresConfigError()\n }\n if (config.id) {\n this.id = config.id\n } else {\n this.id = crypto.randomUUID()\n }\n\n // eslint-disable-next-line\n if (!config.sync) {\n throw new CollectionRequiresSyncConfigError()\n }\n\n this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n a.compareCreatedAt(b)\n )\n\n // Set default values for optional config properties\n this.config = {\n ...config,\n autoIndex: config.autoIndex ?? `eager`,\n }\n\n // Set up data storage with optional comparison function\n if (this.config.compare) {\n this.syncedData = new SortedMap<TKey, T>(this.config.compare)\n } else {\n this.syncedData = new Map<TKey, T>()\n }\n\n // Only start sync immediately if explicitly enabled\n if (config.startSync === true) {\n this.startSync()\n }\n }\n\n /**\n * Start sync immediately - internal method for compiled queries\n * This bypasses lazy loading for special cases like live query results\n */\n public startSyncImmediate(): void {\n this.startSync()\n }\n\n /**\n * Start the sync process for this collection\n * This is called when the collection is first accessed or preloaded\n */\n private startSync(): void {\n if (this._status !== `idle` && this._status !== `cleaned-up`) {\n return // Already started or in progress\n }\n\n this.setStatus(`loading`)\n\n try {\n const cleanupFn = this.config.sync.sync({\n collection: this,\n begin: () => {\n this.pendingSyncedTransactions.push({\n committed: false,\n operations: [],\n deletedKeys: new Set(),\n })\n },\n write: (messageWithoutKey: Omit<ChangeMessage<T>, `key`>) => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new NoPendingSyncTransactionWriteError()\n }\n if (pendingTransaction.committed) {\n throw new SyncTransactionAlreadyCommittedWriteError()\n }\n const key = this.getKeyFromItem(messageWithoutKey.value)\n\n // Check if an item with this key already exists when inserting\n if (messageWithoutKey.type === `insert`) {\n const insertingIntoExistingSynced = this.syncedData.has(key)\n const hasPendingDeleteForKey =\n pendingTransaction.deletedKeys.has(key)\n const isTruncateTransaction = pendingTransaction.truncate === true\n // Allow insert after truncate in the same transaction even if it existed in syncedData\n if (\n insertingIntoExistingSynced &&\n !hasPendingDeleteForKey &&\n !isTruncateTransaction\n ) {\n throw new DuplicateKeySyncError(key, this.id)\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n\n if (messageWithoutKey.type === `delete`) {\n pendingTransaction.deletedKeys.add(key)\n }\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new NoPendingSyncTransactionCommitError()\n }\n if (pendingTransaction.committed) {\n throw new SyncTransactionAlreadyCommittedError()\n }\n\n pendingTransaction.committed = true\n\n // Update status to initialCommit when transitioning from loading\n // This indicates we're in the process of committing the first transaction\n if (this._status === `loading`) {\n this.setStatus(`initialCommit`)\n }\n\n this.commitPendingTransactions()\n },\n markReady: () => {\n this.markReady()\n },\n truncate: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new NoPendingSyncTransactionWriteError()\n }\n if (pendingTransaction.committed) {\n throw new SyncTransactionAlreadyCommittedWriteError()\n }\n\n // Clear all operations from the current transaction\n pendingTransaction.operations = []\n pendingTransaction.deletedKeys.clear()\n\n // Mark the transaction as a truncate operation. During commit, this triggers:\n // - Delete events for all previously synced keys (excluding optimistic-deleted keys)\n // - Clearing of syncedData/syncedMetadata\n // - Subsequent synced ops applied on the fresh base\n // - Finally, optimistic mutations re-applied on top (single batch)\n pendingTransaction.truncate = true\n },\n })\n\n // Store cleanup function if provided\n this.syncCleanupFn = typeof cleanupFn === `function` ? cleanupFn : null\n } catch (error) {\n this.setStatus(`error`)\n throw error\n }\n }\n\n /**\n * Preload the collection data by starting sync if not already started\n * Multiple concurrent calls will share the same promise\n */\n public preload(): Promise<void> {\n if (this.preloadPromise) {\n return this.preloadPromise\n }\n\n this.preloadPromise = new Promise<void>((resolve, reject) => {\n if (this._status === `ready`) {\n resolve()\n return\n }\n\n if (this._status === `error`) {\n reject(new CollectionIsInErrorStateError())\n return\n }\n\n // Register callback BEFORE starting sync to avoid race condition\n this.onFirstReady(() => {\n resolve()\n })\n\n // Start sync if collection hasn't started yet or was cleaned up\n if (this._status === `idle` || this._status === `cleaned-up`) {\n try {\n this.startSync()\n } catch (error) {\n reject(error)\n return\n }\n }\n })\n\n return this.preloadPromise\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 async cleanup(): Promise<void> {\n // Clear GC timeout\n if (this.gcTimeoutId) {\n clearTimeout(this.gcTimeoutId)\n this.gcTimeoutId = null\n }\n\n // Stop sync - wrap in try/catch since it's user-provided code\n try {\n if (this.syncCleanupFn) {\n this.syncCleanupFn()\n this.syncCleanupFn = null\n }\n } catch (error) {\n // Re-throw in a microtask to surface the error after cleanup completes\n queueMicrotask(() => {\n if (error instanceof Error) {\n // Preserve the original error and stack trace\n const wrappedError = new SyncCleanupError(this.id, error)\n wrappedError.cause = error\n wrappedError.stack = error.stack\n throw wrappedError\n } else {\n throw new SyncCleanupError(this.id, error as Error | string)\n }\n })\n }\n\n // Clear data\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 this.hasBeenReady = false\n this.onFirstReadyCallbacks = []\n this.preloadPromise = null\n this.batchedEvents = []\n this.shouldBatchEvents = false\n\n // Update status\n this.setStatus(`cleaned-up`)\n\n return Promise.resolve()\n }\n\n /**\n * Start the garbage collection timer\n * Called when the collection becomes inactive (no subscribers)\n */\n private startGCTimer(): void {\n if (this.gcTimeoutId) {\n clearTimeout(this.gcTimeoutId)\n }\n\n const gcTime = this.config.gcTime ?? 300000 // 5 minutes default\n\n // If gcTime is 0, GC is disabled\n if (gcTime === 0) {\n return\n }\n\n this.gcTimeoutId = setTimeout(() => {\n if (this.activeSubscribersCount === 0) {\n this.cleanup()\n }\n }, gcTime)\n }\n\n /**\n * Cancel the garbage collection timer\n * Called when the collection becomes active again\n */\n private cancelGCTimer(): void {\n if (this.gcTimeoutId) {\n clearTimeout(this.gcTimeoutId)\n this.gcTimeoutId = null\n }\n }\n\n /**\n * Increment the active subscribers count and start sync if needed\n */\n private addSubscriber(): void {\n this.activeSubscribersCount++\n this.cancelGCTimer()\n\n // Start sync if collection was cleaned up\n if (this._status === `cleaned-up` || this._status === `idle`) {\n this.startSync()\n }\n }\n\n /**\n * Decrement the active subscribers count and start GC timer if needed\n */\n private removeSubscriber(): void {\n this.activeSubscribersCount--\n\n if (this.activeSubscribersCount === 0) {\n this.startGCTimer()\n } else if (this.activeSubscribersCount < 0) {\n throw new NegativeActiveSubscribersError()\n }\n }\n\n /**\n * Recompute optimistic state from active transactions\n */\n private recomputeOptimisticState(\n triggeredByUserAction: boolean = false\n ): void {\n // Skip redundant recalculations when we're in the middle of committing sync transactions\n if (this.isCommittingSyncTransactions) {\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 (mutation.collection === this && mutation.optimistic) {\n switch (mutation.type) {\n case `insert`:\n case `update`:\n this.optimisticUpserts.set(mutation.key, mutation.modified as T)\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<T, 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) => m.collection === this && 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.updateIndexes(filteredEvents)\n }\n this.emitEvents(filteredEvents, triggeredByUserAction)\n } else {\n // Update indexes for all events\n if (filteredEventsBySyncStatus.length > 0) {\n this.updateIndexes(filteredEventsBySyncStatus)\n }\n // Emit all events if no pending sync transactions\n this.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, T>,\n previousDeletes: Set<TKey>,\n events: Array<ChangeMessage<T, 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, T>,\n previousDeletes: Set<TKey>\n ): T | 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 * Emit an empty ready event to notify subscribers that the collection is ready\n * This bypasses the normal empty array check in emitEvents\n */\n private emitEmptyReadyEvent(): void {\n // Emit empty array directly to all listeners\n for (const listener of this.changeListeners) {\n listener([])\n }\n // Emit to key-specific listeners\n for (const [_key, keyListeners] of this.changeKeyListeners) {\n for (const listener of keyListeners) {\n listener([])\n }\n }\n }\n\n /**\n * Emit events either immediately or batch them for later emission\n */\n private emitEvents(\n changes: Array<ChangeMessage<T, TKey>>,\n forceEmit = false\n ): void {\n // Skip batching for user actions (forceEmit=true) to keep UI responsive\n if (this.shouldBatchEvents && !forceEmit) {\n // Add events to the batch\n this.batchedEvents.push(...changes)\n return\n }\n\n // Either we're not batching, or we're forcing emission (user action or ending batch cycle)\n let eventsToEmit = changes\n\n // If we have batched events and this is a forced emit, combine them\n if (this.batchedEvents.length > 0 && forceEmit) {\n eventsToEmit = [...this.batchedEvents, ...changes]\n this.batchedEvents = []\n this.shouldBatchEvents = false\n }\n\n if (eventsToEmit.length === 0) return\n\n // Emit to all listeners\n for (const listener of this.changeListeners) {\n listener(eventsToEmit)\n }\n\n // Emit to key-specific listeners\n if (this.changeKeyListeners.size > 0) {\n // Group changes by key, but only for keys that have listeners\n const changesByKey = new Map<TKey, Array<ChangeMessage<T, TKey>>>()\n for (const change of eventsToEmit) {\n if (this.changeKeyListeners.has(change.key)) {\n if (!changesByKey.has(change.key)) {\n changesByKey.set(change.key, [])\n }\n changesByKey.get(change.key)!.push(change)\n }\n }\n\n // Emit batched changes to each key's listeners\n for (const [key, keyChanges] of changesByKey) {\n const keyListeners = this.changeKeyListeners.get(key)!\n for (const listener of keyListeners) {\n listener(keyChanges)\n }\n }\n }\n }\n\n /**\n * Get the current value for a key (virtual derived state)\n */\n public get(key: TKey): T | undefined {\n // Check if optimistically deleted\n if (this.optimisticDeletes.has(key)) {\n return undefined\n }\n\n // Check optimistic upserts first\n if (this.optimisticUpserts.has(key)) {\n return this.optimisticUpserts.get(key)\n }\n\n // Fall back to synced data\n return this.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 // Check if optimistically deleted\n if (this.optimisticDeletes.has(key)) {\n return false\n }\n\n // Check optimistic upserts first\n if (this.optimisticUpserts.has(key)) {\n return true\n }\n\n // Fall back to synced data\n return this.syncedData.has(key)\n }\n\n /**\n * Get the current size of the collection (cached)\n */\n public get size(): number {\n return this._size\n }\n\n /**\n * Get all keys (virtual derived state)\n */\n public *keys(): IterableIterator<TKey> {\n // Yield keys from synced data, skipping any that are deleted.\n for (const key of this.syncedData.keys()) {\n if (!this.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 this.optimisticUpserts.keys()) {\n if (!this.syncedData.has(key) && !this.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<T> {\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, T]> {\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, T]> {\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: T, 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: T, 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 * 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 } = this.pendingSyncedTransactions.reduce(\n (acc, t) => {\n if (t.committed) {\n acc.committedSyncedTransactions.push(t)\n if (t.truncate === true) {\n acc.hasTruncateSync = true\n }\n } else {\n acc.uncommittedSyncedTransactions.push(t)\n }\n return acc\n },\n {\n committedSyncedTransactions: [] as Array<PendingSyncedTransaction<T>>,\n uncommittedSyncedTransactions: [] as Array<PendingSyncedTransaction<T>>,\n hasTruncateSync: false,\n }\n )\n\n if (!hasPersistingTransaction || hasTruncateSync) {\n // Set flag to prevent redundant optimistic state recalculations\n this.isCommittingSyncTransactions = true\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, T>()\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<T, 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 currently-synced key 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 for (const key of this.syncedData.keys()) {\n if (this.optimisticDeletes.has(key)) continue\n const previousValue =\n this.optimisticUpserts.get(key) || 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\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 ACTIVE optimistic transactions against the new synced base\n // We do not copy maps; we compute intent directly from transactions to avoid drift.\n const reapplyUpserts = new Map<TKey, T>()\n const reapplyDeletes = new Set<TKey>()\n\n for (const tx of this.transactions.values()) {\n if ([`completed`, `failed`].includes(tx.state)) continue\n for (const mutation of tx.mutations) {\n if (mutation.collection !== this || !mutation.optimistic) continue\n const key = mutation.key as TKey\n switch (mutation.type) {\n case `insert`:\n reapplyUpserts.set(key, mutation.modified as T)\n reapplyDeletes.delete(key)\n break\n case `update`: {\n const base = this.syncedData.get(key)\n const next = base\n ? (Object.assign({}, base, mutation.changes) as T)\n : (mutation.modified as T)\n reapplyUpserts.set(key, next)\n reapplyDeletes.delete(key)\n break\n }\n case `delete`:\n reapplyUpserts.delete(key)\n reapplyDeletes.add(key)\n break\n }\n }\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<T, 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.isReady()) {\n this.setStatus(`ready`)\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 for (const transaction of this.transactions.values()) {\n if (![`completed`, `failed`].includes(transaction.state)) {\n for (const mutation of transaction.mutations) {\n if (mutation.collection === this && mutation.optimistic) {\n switch (mutation.type) {\n case `insert`:\n case `update`:\n this.optimisticUpserts.set(\n mutation.key,\n mutation.modified as T\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 (mutation.collection === this && changedKeys.has(mutation.key)) {\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 const isRedundantSync =\n completedOp &&\n newVisibleValue !== undefined &&\n deepEquals(completedOp.value, newVisibleValue)\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.updateIndexes(events)\n }\n\n // End batching and emit all events (combines any batched events with sync events)\n this.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 // Call any registered one-time commit listeners\n if (!this.hasReceivedFirstCommit) {\n this.hasReceivedFirstCommit = true\n const callbacks = [...this.onFirstReadyCallbacks]\n this.onFirstReadyCallbacks = []\n callbacks.forEach((callback) => callback())\n }\n }\n }\n\n /**\n * Schedule cleanup of a transaction when it completes\n * @private\n */\n private 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 private ensureStandardSchema(schema: unknown): StandardSchema<T> {\n // If the schema already implements the standard-schema interface, return it\n if (schema && `~standard` in (schema as {})) {\n return schema as StandardSchema<T>\n }\n\n throw new InvalidSchemaError()\n }\n\n public getKeyFromItem(item: T): TKey {\n return this.config.getKey(item)\n }\n\n public generateGlobalKey(key: any, item: any): string {\n if (typeof key === `undefined`) {\n throw new UndefinedKeyError(item)\n }\n\n return `KEY::${this.id}/${key}`\n }\n\n /**\n * Creates an index on a collection for faster queries.\n * Indexes significantly improve query performance by allowing constant time lookups\n * and logarithmic time range queries instead of full scans.\n *\n * @template TResolver - The type of the index resolver (constructor or async loader)\n * @param indexCallback - Function that extracts the indexed value from each item\n * @param config - Configuration including index type and type-specific options\n * @returns An index proxy that provides access to the index when ready\n *\n * @example\n * // Create a default B+ tree index\n * const ageIndex = collection.createIndex((row) => row.age)\n *\n * // Create a ordered index with custom options\n * const ageIndex = collection.createIndex((row) => row.age, {\n * indexType: BTreeIndex,\n * options: { compareFn: customComparator },\n * name: 'age_btree'\n * })\n *\n * // Create an async-loaded index\n * const textIndex = collection.createIndex((row) => row.content, {\n * indexType: async () => {\n * const { FullTextIndex } = await import('./indexes/fulltext.js')\n * return FullTextIndex\n * },\n * options: { language: 'en' }\n * })\n */\n public createIndex<TResolver extends IndexResolver<TKey> = typeof BTreeIndex>(\n indexCallback: (row: SingleRowRefProxy<T>) => any,\n config: IndexOptions<TResolver> = {}\n ): IndexProxy<TKey> {\n this.validateCollectionUsable(`createIndex`)\n\n const indexId = ++this.indexCounter\n const singleRowRefProxy = createSingleRowRefProxy<T>()\n const indexExpression = indexCallback(singleRowRefProxy)\n const expression = toExpression(indexExpression)\n\n // Default to BTreeIndex if no type specified\n const resolver = config.indexType ?? (BTreeIndex as unknown as TResolver)\n\n // Create lazy wrapper\n const lazyIndex = new LazyIndexWrapper<TKey>(\n indexId,\n expression,\n config.name,\n resolver,\n config.options,\n this.entries()\n )\n\n this.lazyIndexes.set(indexId, lazyIndex)\n\n // For BTreeIndex, resolve immediately and synchronously\n if ((resolver as unknown) === BTreeIndex) {\n try {\n const resolvedIndex = lazyIndex.getResolved()\n this.resolvedIndexes.set(indexId, resolvedIndex)\n } catch (error) {\n console.warn(`Failed to resolve BTreeIndex:`, error)\n }\n } else if (typeof resolver === `function` && resolver.prototype) {\n // Other synchronous constructors - resolve immediately\n try {\n const resolvedIndex = lazyIndex.getResolved()\n this.resolvedIndexes.set(indexId, resolvedIndex)\n } catch {\n // Fallback to async resolution\n this.resolveSingleIndex(indexId, lazyIndex).catch((error) => {\n console.warn(`Failed to resolve single index:`, error)\n })\n }\n } else if (this.isIndexesResolved) {\n // Async loader but indexes are already resolved - resolve this one\n this.resolveSingleIndex(indexId, lazyIndex).catch((error) => {\n console.warn(`Failed to resolve single index:`, error)\n })\n }\n\n return new IndexProxy(indexId, lazyIndex)\n }\n\n /**\n * Resolve all lazy indexes (called when collection first syncs)\n * @private\n */\n private async resolveAllIndexes(): Promise<void> {\n if (this.isIndexesResolved) return\n\n const resolutionPromises = Array.from(this.lazyIndexes.entries()).map(\n async ([indexId, lazyIndex]) => {\n const resolvedIndex = await lazyIndex.resolve()\n\n // Build index with current data\n resolvedIndex.build(this.entries())\n\n this.resolvedIndexes.set(indexId, resolvedIndex)\n return { indexId, resolvedIndex }\n }\n )\n\n await Promise.all(resolutionPromises)\n this.isIndexesResolved = true\n }\n\n /**\n * Resolve a single index immediately\n * @private\n */\n private async resolveSingleIndex(\n indexId: number,\n lazyIndex: LazyIndexWrapper<TKey>\n ): Promise<BaseIndex<TKey>> {\n const resolvedIndex = await lazyIndex.resolve()\n resolvedIndex.build(this.entries())\n this.resolvedIndexes.set(indexId, resolvedIndex)\n return resolvedIndex\n }\n\n /**\n * Get resolved indexes for query optimization\n */\n get indexes(): Map<number, BaseIndex<TKey>> {\n return this.resolvedIndexes\n }\n\n /**\n * Updates all indexes when the collection changes\n * @private\n */\n private updateIndexes(changes: Array<ChangeMessage<T, TKey>>): void {\n for (const index of this.resolvedIndexes.values()) {\n for (const change of changes) {\n switch (change.type) {\n case `insert`:\n index.add(change.key, change.value)\n break\n case `update`:\n if (change.previousValue) {\n index.update(change.key, change.previousValue, change.value)\n } else {\n index.add(change.key, change.value)\n }\n break\n case `delete`:\n index.remove(change.key, change.value)\n break\n }\n }\n }\n }\n\n public validateData(\n data: unknown,\n type: `insert` | `update`,\n key?: TKey\n ): T | never {\n if (!this.config.schema) return data as T\n\n const standardSchema = this.ensureStandardSchema(this.config.schema)\n\n // For updates, we need to merge with the existing data before validation\n if (type === `update` && key) {\n // Get the existing data for this key\n const existingData = this.get(key)\n\n if (\n existingData &&\n data &&\n typeof data === `object` &&\n typeof existingData === `object`\n ) {\n // Merge the update with the existing data\n const mergedData = Object.assign({}, existingData, data)\n\n // Validate the merged data\n const result = standardSchema[`~standard`].validate(mergedData)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new SchemaMustBeSynchronousError()\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n // Return the original update data, not the merged data\n // We only used the merged data for validation\n return data as T\n }\n }\n\n // For inserts or updates without existing data, validate the data directly\n const result = standardSchema[`~standard`].validate(data)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new SchemaMustBeSynchronousError()\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n return result.value as T\n }\n\n /**\n * Inserts one or more items into the collection\n * @param items - Single item or array of items to insert\n * @param config - Optional configuration including metadata\n * @returns A Transaction object representing the insert operation(s)\n * @throws {SchemaValidationError} If the data fails schema validation\n * @example\n * // Insert a single todo (requires onInsert handler)\n * const tx = collection.insert({ id: \"1\", text: \"Buy milk\", completed: false })\n * await tx.isPersisted.promise\n *\n * @example\n * // Insert multiple todos at once\n * const tx = collection.insert([\n * { id: \"1\", text: \"Buy milk\", completed: false },\n * { id: \"2\", text: \"Walk dog\", completed: true }\n * ])\n * await tx.isPersisted.promise\n *\n * @example\n * // Insert with metadata\n * const tx = collection.insert({ id: \"1\", text: \"Buy groceries\" },\n * { metadata: { source: \"mobile-app\" } }\n * )\n * await tx.isPersisted.promise\n *\n * @example\n * // Handle errors\n * try {\n * const tx = collection.insert({ id: \"1\", text: \"New item\" })\n * await tx.isPersisted.promise\n * console.log('Insert successful')\n * } catch (error) {\n * console.log('Insert failed:', error)\n * }\n */\n insert = (\n data: TInsertInput | Array<TInsertInput>,\n config?: InsertConfig\n ) => {\n this.validateCollectionUsable(`insert`)\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onInsert handler early\n if (!ambientTransaction && !this.config.onInsert) {\n throw new MissingInsertHandlerError()\n }\n\n const items = Array.isArray(data) ? data : [data]\n const mutations: Array<PendingMutation<T>> = []\n\n // Create mutations for each item\n items.forEach((item) => {\n // Validate the data against the schema if one exists\n const validatedData = this.validateData(item, `insert`)\n\n // Check if an item with this ID already exists in the collection\n const key = this.getKeyFromItem(validatedData)\n if (this.has(key)) {\n throw new DuplicateKeyError(key)\n }\n const globalKey = this.generateGlobalKey(key, item)\n\n const mutation: PendingMutation<T, `insert`> = {\n mutationId: crypto.randomUUID(),\n original: {},\n modified: validatedData,\n // Pick the values from validatedData based on what's passed in - this is for cases\n // where a schema has default values. The validated data has the extra default\n // values but for changes, we just want to show the data that was actually passed in.\n changes: Object.fromEntries(\n Object.keys(item).map((k) => [\n k,\n validatedData[k as keyof typeof validatedData],\n ])\n ) as TInsertInput,\n globalKey,\n key,\n metadata: config?.metadata as unknown,\n syncMetadata: this.config.sync.getSyncMetadata?.() || {},\n optimistic: config?.optimistic ?? true,\n type: `insert`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n })\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.set(ambientTransaction.id, ambientTransaction)\n this.scheduleTransactionCleanup(ambientTransaction)\n this.recomputeOptimisticState(true)\n\n return ambientTransaction\n } else {\n // Create a new transaction with a mutation function that calls the onInsert handler\n const directOpTransaction = createTransaction<T>({\n mutationFn: async (params) => {\n // Call the onInsert handler with the transaction and collection\n return await this.config.onInsert!({\n transaction:\n params.transaction as unknown as TransactionWithMutations<\n TInsertInput,\n `insert`\n >,\n collection: this as unknown as Collection<T, TKey, TUtils>,\n })\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n this.transactions.set(directOpTransaction.id, directOpTransaction)\n this.scheduleTransactionCleanup(directOpTransaction)\n this.recomputeOptimisticState(true)\n\n return directOpTransaction\n }\n }\n\n /**\n * Updates one or more items in the collection using a callback function\n * @param keys - Single key or array of keys to update\n * @param configOrCallback - Either update configuration or update callback\n * @param maybeCallback - Update callback if config was provided\n * @returns A Transaction object representing the update operation(s)\n * @throws {SchemaValidationError} If the updated data fails schema validation\n * @example\n * // Update single item by key\n * const tx = collection.update(\"todo-1\", (draft) => {\n * draft.completed = true\n * })\n * await tx.isPersisted.promise\n *\n * @example\n * // Update multiple items\n * const tx = collection.update([\"todo-1\", \"todo-2\"], (drafts) => {\n * drafts.forEach(draft => { draft.completed = true })\n * })\n * await tx.isPersisted.promise\n *\n * @example\n * // Update with metadata\n * const tx = collection.update(\"todo-1\",\n * { metadata: { reason: \"user update\" } },\n * (draft) => { draft.text = \"Updated text\" }\n * )\n * await tx.isPersisted.promise\n *\n * @example\n * // Handle errors\n * try {\n * const tx = collection.update(\"item-1\", draft => { draft.value = \"new\" })\n * await tx.isPersisted.promise\n * console.log('Update successful')\n * } catch (error) {\n * console.log('Update failed:', error)\n * }\n */\n\n // Overload 1: Update multiple items with a callback\n update<TItem extends object = T>(\n key: Array<TKey | unknown>,\n callback: (drafts: Array<WritableDeep<TItem>>) => void\n ): TransactionType\n\n // Overload 2: Update multiple items with config and a callback\n update<TItem extends object = T>(\n keys: Array<TKey | unknown>,\n config: OperationConfig,\n callback: (drafts: Array<WritableDeep<TItem>>) => void\n ): TransactionType\n\n // Overload 3: Update a single item with a callback\n update<TItem extends object = T>(\n id: TKey | unknown,\n callback: (draft: WritableDeep<TItem>) => void\n ): TransactionType\n\n // Overload 4: Update a single item with config and a callback\n update<TItem extends object = T>(\n id: TKey | unknown,\n config: OperationConfig,\n callback: (draft: WritableDeep<TItem>) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n keys: (TKey | unknown) | Array<TKey | unknown>,\n configOrCallback:\n | ((draft: WritableDeep<TItem> | Array<WritableDeep<TItem>>) => void)\n | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof keys === `undefined`) {\n throw new MissingUpdateArgumentError()\n }\n\n this.validateCollectionUsable(`update`)\n\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onUpdate handler early\n if (!ambientTransaction && !this.config.onUpdate) {\n throw new MissingUpdateHandlerError()\n }\n\n const isArray = Array.isArray(keys)\n const keysArray = isArray ? keys : [keys]\n\n if (isArray && keysArray.length === 0) {\n throw new NoKeysPassedToUpdateError()\n }\n\n const callback =\n typeof configOrCallback === `function` ? configOrCallback : maybeCallback!\n const config =\n typeof configOrCallback === `function` ? {} : configOrCallback\n\n // Get the current objects or empty objects if they don't exist\n const currentObjects = keysArray.map((key) => {\n const item = this.get(key)\n if (!item) {\n throw new UpdateKeyNotFoundError(key)\n }\n\n return item\n }) as unknown as Array<TItem>\n\n let changesArray\n if (isArray) {\n // Use the proxy to track changes for all objects\n changesArray = withArrayChangeTracking(\n currentObjects,\n callback as (draft: Array<TItem>) => void\n )\n } else {\n const result = withChangeTracking(\n currentObjects[0]!,\n callback as (draft: TItem) => void\n )\n changesArray = [result]\n }\n\n // Create mutations for each object that has changes\n const mutations: Array<PendingMutation<T, `update`, this>> = keysArray\n .map((key, index) => {\n const itemChanges = changesArray[index] // User-provided changes for this specific item\n\n // Skip items with no changes\n if (!itemChanges || Object.keys(itemChanges).length === 0) {\n return null\n }\n\n const originalItem = currentObjects[index] as unknown as T\n // Validate the user-provided changes for this item\n const validatedUpdatePayload = this.validateData(\n itemChanges,\n `update`,\n key\n )\n\n // Construct the full modified item by applying the validated update payload to the original item\n const modifiedItem = Object.assign(\n {},\n originalItem,\n validatedUpdatePayload\n )\n\n // Check if the ID of the item is being changed\n const originalItemId = this.getKeyFromItem(originalItem)\n const modifiedItemId = this.getKeyFromItem(modifiedItem)\n\n if (originalItemId !== modifiedItemId) {\n throw new KeyUpdateNotAllowedError(originalItemId, modifiedItemId)\n }\n\n const globalKey = this.generateGlobalKey(modifiedItemId, modifiedItem)\n\n return {\n mutationId: crypto.randomUUID(),\n original: originalItem,\n modified: modifiedItem,\n changes: validatedUpdatePayload as Partial<T>,\n globalKey,\n key,\n metadata: config.metadata as unknown,\n syncMetadata: (this.syncedMetadata.get(key) || {}) as Record<\n string,\n unknown\n >,\n optimistic: config.optimistic ?? true,\n type: `update`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n })\n .filter(Boolean) as Array<PendingMutation<T, `update`, this>>\n\n // If no changes were made, return an empty transaction early\n if (mutations.length === 0) {\n const emptyTransaction = createTransaction({\n mutationFn: async () => {},\n })\n emptyTransaction.commit()\n // Schedule cleanup for empty transaction\n this.scheduleTransactionCleanup(emptyTransaction)\n return emptyTransaction\n }\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.set(ambientTransaction.id, ambientTransaction)\n this.scheduleTransactionCleanup(ambientTransaction)\n this.recomputeOptimisticState(true)\n\n return ambientTransaction\n }\n\n // No need to check for onUpdate handler here as we've already checked at the beginning\n\n // Create a new transaction with a mutation function that calls the onUpdate handler\n const directOpTransaction = createTransaction<T>({\n mutationFn: async (params) => {\n // Call the onUpdate handler with the transaction and collection\n return this.config.onUpdate!({\n transaction:\n params.transaction as unknown as TransactionWithMutations<\n T,\n `update`\n >,\n collection: this as unknown as Collection<T, TKey, TUtils>,\n })\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n\n this.transactions.set(directOpTransaction.id, directOpTransaction)\n this.scheduleTransactionCleanup(directOpTransaction)\n this.recomputeOptimisticState(true)\n\n return directOpTransaction\n }\n\n /**\n * Deletes one or more items from the collection\n * @param keys - Single key or array of keys to delete\n * @param config - Optional configuration including metadata\n * @returns A Transaction object representing the delete operation(s)\n * @example\n * // Delete a single item\n * const tx = collection.delete(\"todo-1\")\n * await tx.isPersisted.promise\n *\n * @example\n * // Delete multiple items\n * const tx = collection.delete([\"todo-1\", \"todo-2\"])\n * await tx.isPersisted.promise\n *\n * @example\n * // Delete with metadata\n * const tx = collection.delete(\"todo-1\", { metadata: { reason: \"completed\" } })\n * await tx.isPersisted.promise\n *\n * @example\n * // Handle errors\n * try {\n * const tx = collection.delete(\"item-1\")\n * await tx.isPersisted.promise\n * console.log('Delete successful')\n * } catch (error) {\n * console.log('Delete failed:', error)\n * }\n */\n delete = (\n keys: Array<TKey> | TKey,\n config?: OperationConfig\n ): TransactionType<any> => {\n this.validateCollectionUsable(`delete`)\n\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onDelete handler early\n if (!ambientTransaction && !this.config.onDelete) {\n throw new MissingDeleteHandlerError()\n }\n\n if (Array.isArray(keys) && keys.length === 0) {\n throw new NoKeysPassedToDeleteError()\n }\n\n const keysArray = Array.isArray(keys) ? keys : [keys]\n const mutations: Array<PendingMutation<T, `delete`, this>> = []\n\n for (const key of keysArray) {\n if (!this.has(key)) {\n throw new DeleteKeyNotFoundError(key)\n }\n const globalKey = this.generateGlobalKey(key, this.get(key)!)\n const mutation: PendingMutation<T, `delete`, this> = {\n mutationId: crypto.randomUUID(),\n original: this.get(key)!,\n modified: this.get(key)!,\n changes: this.get(key)!,\n globalKey,\n key,\n metadata: config?.metadata as unknown,\n syncMetadata: (this.syncedMetadata.get(key) || {}) as Record<\n string,\n unknown\n >,\n optimistic: config?.optimistic ?? true,\n type: `delete`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n }\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.set(ambientTransaction.id, ambientTransaction)\n this.scheduleTransactionCleanup(ambientTransaction)\n this.recomputeOptimisticState(true)\n\n return ambientTransaction\n }\n\n // Create a new transaction with a mutation function that calls the onDelete handler\n const directOpTransaction = createTransaction<T>({\n autoCommit: true,\n mutationFn: async (params) => {\n // Call the onDelete handler with the transaction and collection\n return this.config.onDelete!({\n transaction:\n params.transaction as unknown as TransactionWithMutations<\n T,\n `delete`\n >,\n collection: this as unknown as Collection<T, TKey, TUtils>,\n })\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n this.transactions.set(directOpTransaction.id, directOpTransaction)\n this.scheduleTransactionCleanup(directOpTransaction)\n this.recomputeOptimisticState(true)\n\n return directOpTransaction\n }\n\n /**\n * Gets the current state of the collection as a Map\n * @returns Map containing all items in the collection, with keys as identifiers\n * @example\n * const itemsMap = collection.state\n * console.log(`Collection has ${itemsMap.size} items`)\n *\n * for (const [key, item] of itemsMap) {\n * console.log(`${key}: ${item.title}`)\n * }\n *\n * // Check if specific item exists\n * if (itemsMap.has(\"todo-1\")) {\n * console.log(\"Todo 1 exists:\", itemsMap.get(\"todo-1\"))\n * }\n */\n get state() {\n const result = new Map<TKey, T>()\n for (const [key, value] of this.entries()) {\n result.set(key, value)\n }\n return result\n }\n\n /**\n * Gets the current state of the collection as a Map, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to a Map containing all items in the collection\n */\n stateWhenReady(): Promise<Map<TKey, T>> {\n // If we already have data or collection is ready, resolve immediately\n if (this.size > 0 || this.isReady()) {\n return Promise.resolve(this.state)\n }\n\n // Otherwise, wait for the collection to be ready\n return new Promise<Map<TKey, T>>((resolve) => {\n this.onFirstReady(() => {\n resolve(this.state)\n })\n })\n }\n\n /**\n * Gets the current state of the collection as an Array\n *\n * @returns An Array containing all items in the collection\n */\n get toArray() {\n return Array.from(this.values())\n }\n\n /**\n * Gets the current state of the collection as an Array, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to an Array containing all items in the collection\n */\n toArrayWhenReady(): Promise<Array<T>> {\n // If we already have data or collection is ready, resolve immediately\n if (this.size > 0 || this.isReady()) {\n return Promise.resolve(this.toArray)\n }\n\n // Otherwise, wait for the collection to be ready\n return new Promise<Array<T>>((resolve) => {\n this.onFirstReady(() => {\n resolve(this.toArray)\n })\n })\n }\n\n /**\n * Returns the current state of the collection as an array of changes\n * @param options - Options including optional where filter\n * @returns An array of changes\n * @example\n * // Get all items as changes\n * const allChanges = collection.currentStateAsChanges()\n *\n * // Get only items matching a condition\n * const activeChanges = collection.currentStateAsChanges({\n * where: (row) => row.status === 'active'\n * })\n *\n * // Get only items using a pre-compiled expression\n * const activeChanges = collection.currentStateAsChanges({\n * whereExpression: eq(row.status, 'active')\n * })\n */\n public currentStateAsChanges(\n options: CurrentStateAsChangesOptions<T> = {}\n ): Array<ChangeMessage<T>> {\n return currentStateAsChanges(this, options)\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - Function called when items change\n * @param options - Subscription options including includeInitialState and where filter\n * @returns Unsubscribe function - Call this to stop listening for changes\n * @example\n * // Basic subscription\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * changes.forEach(change => {\n * console.log(`${change.type}: ${change.key}`, change.value)\n * })\n * })\n *\n * // Later: unsubscribe()\n *\n * @example\n * // Include current state immediately\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * updateUI(changes)\n * }, { includeInitialState: true })\n *\n * @example\n * // Subscribe only to changes matching a condition\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * updateUI(changes)\n * }, {\n * includeInitialState: true,\n * where: (row) => row.status === 'active'\n * })\n *\n * @example\n * // Subscribe using a pre-compiled expression\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * updateUI(changes)\n * }, {\n * includeInitialState: true,\n * whereExpression: eq(row.status, 'active')\n * })\n */\n public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void,\n options: SubscribeChangesOptions<T> = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n // Auto-index for where expressions if enabled\n if (options.whereExpression) {\n ensureIndexForExpression(options.whereExpression, this)\n }\n\n // Create a filtered callback if where clause is provided\n const filteredCallback =\n options.where || options.whereExpression\n ? createFilteredCallback(callback, options)\n : callback\n\n if (options.includeInitialState) {\n // First send the current state as changes (filtered if needed)\n const initialChanges = this.currentStateAsChanges({\n where: options.where,\n whereExpression: options.whereExpression,\n })\n filteredCallback(initialChanges)\n }\n\n // Add to batched listeners\n this.changeListeners.add(filteredCallback)\n\n return () => {\n this.changeListeners.delete(filteredCallback)\n this.removeSubscriber()\n }\n }\n\n /**\n * Subscribe to changes for a specific key\n */\n public subscribeChangesKey(\n key: TKey,\n listener: ChangeListener<T, TKey>,\n { includeInitialState = false }: { includeInitialState?: boolean } = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n if (!this.changeKeyListeners.has(key)) {\n this.changeKeyListeners.set(key, new Set())\n }\n\n if (includeInitialState) {\n // First send the current state as changes\n listener([\n {\n type: `insert`,\n key,\n value: this.get(key)!,\n },\n ])\n }\n\n this.changeKeyListeners.get(key)!.add(listener)\n\n return () => {\n const listeners = this.changeKeyListeners.get(key)\n if (listeners) {\n listeners.delete(listener)\n if (listeners.size === 0) {\n this.changeKeyListeners.delete(key)\n }\n }\n this.removeSubscriber()\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 private capturePreSyncVisibleState(): void {\n if (this.pendingSyncedTransactions.length === 0) return\n\n // Clear any previous capture\n this.preSyncVisibleState.clear()\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 for (const key of syncedKeys) {\n const currentValue = this.get(key)\n if (currentValue !== undefined) {\n this.preSyncVisibleState.set(key, currentValue)\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.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"],"names":["config","result"],"mappings":"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"}
1
+ {"version":3,"file":"collection.js","sources":["../../src/collection.ts"],"sourcesContent":["import { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { deepEquals } from \"./utils\"\nimport { SortedMap } from \"./SortedMap\"\nimport {\n createSingleRowRefProxy,\n toExpression,\n} from \"./query/builder/ref-proxy\"\nimport { BTreeIndex } from \"./indexes/btree-index.js\"\nimport { IndexProxy, LazyIndexWrapper } from \"./indexes/lazy-index.js\"\nimport { ensureIndexForExpression } from \"./indexes/auto-index.js\"\nimport { createTransaction, getActiveTransaction } from \"./transactions\"\nimport {\n CollectionInErrorStateError,\n CollectionIsInErrorStateError,\n CollectionRequiresConfigError,\n CollectionRequiresSyncConfigError,\n DeleteKeyNotFoundError,\n DuplicateKeyError,\n DuplicateKeySyncError,\n InvalidCollectionStatusTransitionError,\n InvalidSchemaError,\n KeyUpdateNotAllowedError,\n MissingDeleteHandlerError,\n MissingInsertHandlerError,\n MissingUpdateArgumentError,\n MissingUpdateHandlerError,\n NegativeActiveSubscribersError,\n NoKeysPassedToDeleteError,\n NoKeysPassedToUpdateError,\n NoPendingSyncTransactionCommitError,\n NoPendingSyncTransactionWriteError,\n SchemaMustBeSynchronousError,\n SchemaValidationError,\n SyncCleanupError,\n SyncTransactionAlreadyCommittedError,\n SyncTransactionAlreadyCommittedWriteError,\n UndefinedKeyError,\n UpdateKeyNotFoundError,\n} from \"./errors\"\nimport { createFilteredCallback, currentStateAsChanges } from \"./change-events\"\nimport type { Transaction } from \"./transactions\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport type { SingleRowRefProxy } from \"./query/builder/ref-proxy\"\nimport type {\n ChangeListener,\n ChangeMessage,\n CollectionConfig,\n CollectionStatus,\n CurrentStateAsChangesOptions,\n Fn,\n InferSchemaInput,\n InferSchemaOutput,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n StandardSchema,\n SubscribeChangesOptions,\n Transaction as TransactionType,\n TransactionWithMutations,\n UtilsRecord,\n WritableDeep,\n} from \"./types\"\nimport type { IndexOptions } from \"./indexes/index-options.js\"\nimport type { BaseIndex, IndexResolver } from \"./indexes/base-index.js\"\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\n truncate?: boolean\n deletedKeys: Set<string | number>\n}\n\n/**\n * Enhanced Collection interface that includes both data type T and utilities TUtils\n * @template T - The type of items in the collection\n * @template TKey - The type of the key for the collection\n * @template TUtils - The utilities record type\n * @template TInsertInput - The type for insert operations (can be different from T for schemas with defaults)\n */\nexport interface Collection<\n T extends object = Record<string, unknown>,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TInsertInput extends object = T,\n> extends CollectionImpl<T, TKey, TUtils, TSchema, TInsertInput> {\n readonly utils: TUtils\n}\n\n/**\n * Creates a new Collection instance with the given configuration\n *\n * @template T - The schema type if a schema is provided, otherwise the type of items in the collection\n * @template TKey - The type of the key for the collection\n * @template TUtils - The utilities record type\n * @param options - Collection options with optional utilities\n * @returns A new Collection with utilities exposed both at top level and under .utils\n *\n * @example\n * // Pattern 1: With operation handlers (direct collection calls)\n * const todos = createCollection({\n * id: \"todos\",\n * getKey: (todo) => todo.id,\n * schema,\n * onInsert: async ({ transaction, collection }) => {\n * // Send to API\n * await api.createTodo(transaction.mutations[0].modified)\n * },\n * onUpdate: async ({ transaction, collection }) => {\n * await api.updateTodo(transaction.mutations[0].modified)\n * },\n * onDelete: async ({ transaction, collection }) => {\n * await api.deleteTodo(transaction.mutations[0].key)\n * },\n * sync: { sync: () => {} }\n * })\n *\n * // Direct usage (handlers manage transactions)\n * const tx = todos.insert({ id: \"1\", text: \"Buy milk\", completed: false })\n * await tx.isPersisted.promise\n *\n * @example\n * // Pattern 2: Manual transaction management\n * const todos = createCollection({\n * getKey: (todo) => todo.id,\n * schema: todoSchema,\n * sync: { sync: () => {} }\n * })\n *\n * // Explicit transaction usage\n * const tx = createTransaction({\n * mutationFn: async ({ transaction }) => {\n * // Handle all mutations in transaction\n * await api.saveChanges(transaction.mutations)\n * }\n * })\n *\n * tx.mutate(() => {\n * todos.insert({ id: \"1\", text: \"Buy milk\" })\n * todos.update(\"2\", draft => { draft.completed = true })\n * })\n *\n * await tx.isPersisted.promise\n *\n * @example\n * // Using schema for type inference (preferred as it also gives you client side validation)\n * const todoSchema = z.object({\n * id: z.string(),\n * title: z.string(),\n * completed: z.boolean()\n * })\n *\n * const todos = createCollection({\n * schema: todoSchema,\n * getKey: (todo) => todo.id,\n * sync: { sync: () => {} }\n * })\n *\n */\n\n// Overload for when schema is provided\nexport function createCollection<\n T extends StandardSchemaV1,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n>(\n options: CollectionConfig<InferSchemaOutput<T>, TKey, T> & {\n schema: T\n utils?: TUtils\n }\n): Collection<InferSchemaOutput<T>, TKey, TUtils, T, InferSchemaInput<T>>\n\n// Overload for when no schema is provided\n// the type T needs to be passed explicitly unless it can be inferred from the getKey function in the config\nexport function createCollection<\n T extends object,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n>(\n options: CollectionConfig<T, TKey, never> & {\n schema?: never // prohibit schema if an explicit type is provided\n utils?: TUtils\n }\n): Collection<T, TKey, TUtils, never, T>\n\n// Implementation\nexport function createCollection(\n options: CollectionConfig<any, string | number, any> & {\n schema?: StandardSchemaV1\n utils?: UtilsRecord\n }\n): Collection<any, string | number, UtilsRecord, any, any> {\n const collection = new CollectionImpl<any, string | number, any, any, any>(\n options\n )\n\n // Copy utils to both top level and .utils namespace\n if (options.utils) {\n collection.utils = { ...options.utils }\n } else {\n collection.utils = {}\n }\n\n return collection\n}\n\nexport class CollectionImpl<\n TOutput extends object = Record<string, unknown>,\n TKey extends string | number = string | number,\n TUtils extends UtilsRecord = {},\n TSchema extends StandardSchemaV1 = StandardSchemaV1,\n TInput extends object = TOutput,\n> {\n public config: CollectionConfig<TOutput, TKey, TSchema>\n\n // Core state - make public for testing\n public transactions: SortedMap<string, Transaction<any>>\n public pendingSyncedTransactions: Array<PendingSyncedTransaction<TOutput>> =\n []\n public syncedData: Map<TKey, TOutput> | 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 private _size = 0\n\n // Index storage\n private lazyIndexes = new Map<number, LazyIndexWrapper<TKey>>()\n private resolvedIndexes = new Map<number, BaseIndex<TKey>>()\n private isIndexesResolved = false\n private indexCounter = 0\n\n // Event system\n private changeListeners = new Set<ChangeListener<TOutput, TKey>>()\n private changeKeyListeners = new Map<\n TKey,\n Set<ChangeListener<TOutput, TKey>>\n >()\n\n // Utilities namespace\n // This is populated by createCollection\n public utils: Record<string, Fn> = {}\n\n // State used for computing the change events\n private syncedKeys = new Set<TKey>()\n private preSyncVisibleState = new Map<TKey, TOutput>()\n private recentlySyncedKeys = new Set<TKey>()\n private hasReceivedFirstCommit = false\n private isCommittingSyncTransactions = false\n\n // Array to store one-time ready listeners\n private onFirstReadyCallbacks: Array<() => void> = []\n private hasBeenReady = false\n\n // Event batching for preventing duplicate emissions during transaction flows\n private batchedEvents: Array<ChangeMessage<TOutput, TKey>> = []\n private shouldBatchEvents = false\n\n // Lifecycle management\n private _status: CollectionStatus = `idle`\n private activeSubscribersCount = 0\n private gcTimeoutId: ReturnType<typeof setTimeout> | null = null\n private preloadPromise: Promise<void> | null = null\n private syncCleanupFn: (() => void) | null = null\n\n /**\n * Register a callback to be executed when the collection first becomes ready\n * Useful for preloading collections\n * @param callback Function to call when the collection first becomes ready\n * @example\n * collection.onFirstReady(() => {\n * console.log('Collection is ready for the first time')\n * // Safe to access collection.state now\n * })\n */\n public onFirstReady(callback: () => void): void {\n // If already ready, call immediately\n if (this.hasBeenReady) {\n callback()\n return\n }\n\n this.onFirstReadyCallbacks.push(callback)\n }\n\n /**\n * Check if the collection is ready for use\n * Returns true if the collection has been marked as ready by its sync implementation\n * @returns true if the collection is ready, false otherwise\n * @example\n * if (collection.isReady()) {\n * console.log('Collection is ready, data is available')\n * // Safe to access collection.state\n * } else {\n * console.log('Collection is still loading')\n * }\n */\n public isReady(): boolean {\n return this._status === `ready`\n }\n\n /**\n * Mark the collection as ready for use\n * This is called by sync implementations to explicitly signal that the collection is ready,\n * providing a more intuitive alternative to using commits for readiness signaling\n * @private - Should only be called by sync implementations\n */\n private markReady(): void {\n // Can transition to ready from loading or initialCommit states\n if (this._status === `loading` || this._status === `initialCommit`) {\n this.setStatus(`ready`)\n\n // Call any registered first ready callbacks (only on first time becoming ready)\n if (!this.hasBeenReady) {\n this.hasBeenReady = true\n\n // Also mark as having received first commit for backwards compatibility\n if (!this.hasReceivedFirstCommit) {\n this.hasReceivedFirstCommit = true\n }\n\n const callbacks = [...this.onFirstReadyCallbacks]\n this.onFirstReadyCallbacks = []\n callbacks.forEach((callback) => callback())\n }\n }\n\n // Always notify dependents when markReady is called, after status is set\n // This ensures live queries get notified when their dependencies become ready\n if (this.changeListeners.size > 0) {\n this.emitEmptyReadyEvent()\n }\n }\n\n public id = ``\n\n /**\n * Gets the current status of the collection\n */\n public get status(): CollectionStatus {\n return this._status\n }\n\n /**\n * Validates that the collection is in a usable state for data operations\n * @private\n */\n private validateCollectionUsable(operation: string): void {\n switch (this._status) {\n case `error`:\n throw new CollectionInErrorStateError(operation, this.id)\n case `cleaned-up`:\n // Automatically restart the collection when operations are called on cleaned-up collections\n this.startSync()\n break\n }\n }\n\n /**\n * Validates state transitions to prevent invalid status changes\n * @private\n */\n private validateStatusTransition(\n from: CollectionStatus,\n to: CollectionStatus\n ): void {\n if (from === to) {\n // Allow same state transitions\n return\n }\n const validTransitions: Record<\n CollectionStatus,\n Array<CollectionStatus>\n > = {\n idle: [`loading`, `error`, `cleaned-up`],\n loading: [`initialCommit`, `ready`, `error`, `cleaned-up`],\n initialCommit: [`ready`, `error`, `cleaned-up`],\n ready: [`cleaned-up`, `error`],\n error: [`cleaned-up`, `idle`],\n \"cleaned-up\": [`loading`, `error`],\n }\n\n if (!validTransitions[from].includes(to)) {\n throw new InvalidCollectionStatusTransitionError(from, to, this.id)\n }\n }\n\n /**\n * Safely update the collection status with validation\n * @private\n */\n private setStatus(newStatus: CollectionStatus): void {\n this.validateStatusTransition(this._status, newStatus)\n this._status = newStatus\n\n // Resolve indexes when collection becomes ready\n if (newStatus === `ready` && !this.isIndexesResolved) {\n // Resolve indexes asynchronously without blocking\n this.resolveAllIndexes().catch((error) => {\n console.warn(`Failed to resolve indexes:`, error)\n })\n }\n }\n\n /**\n * Creates a new Collection instance\n *\n * @param config - Configuration object for the collection\n * @throws Error if sync config is missing\n */\n constructor(config: CollectionConfig<TOutput, TKey, TSchema>) {\n // eslint-disable-next-line\n if (!config) {\n throw new CollectionRequiresConfigError()\n }\n if (config.id) {\n this.id = config.id\n } else {\n this.id = crypto.randomUUID()\n }\n\n // eslint-disable-next-line\n if (!config.sync) {\n throw new CollectionRequiresSyncConfigError()\n }\n\n this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n a.compareCreatedAt(b)\n )\n\n // Set default values for optional config properties\n this.config = {\n ...config,\n autoIndex: config.autoIndex ?? `eager`,\n }\n\n // Set up data storage with optional comparison function\n if (this.config.compare) {\n this.syncedData = new SortedMap<TKey, TOutput>(this.config.compare)\n } else {\n this.syncedData = new Map<TKey, TOutput>()\n }\n\n // Only start sync immediately if explicitly enabled\n if (config.startSync === true) {\n this.startSync()\n }\n }\n\n /**\n * Start sync immediately - internal method for compiled queries\n * This bypasses lazy loading for special cases like live query results\n */\n public startSyncImmediate(): void {\n this.startSync()\n }\n\n /**\n * Start the sync process for this collection\n * This is called when the collection is first accessed or preloaded\n */\n private startSync(): void {\n if (this._status !== `idle` && this._status !== `cleaned-up`) {\n return // Already started or in progress\n }\n\n this.setStatus(`loading`)\n\n try {\n const cleanupFn = this.config.sync.sync({\n collection: this,\n begin: () => {\n this.pendingSyncedTransactions.push({\n committed: false,\n operations: [],\n deletedKeys: new Set(),\n })\n },\n write: (messageWithoutKey: Omit<ChangeMessage<TOutput>, `key`>) => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new NoPendingSyncTransactionWriteError()\n }\n if (pendingTransaction.committed) {\n throw new SyncTransactionAlreadyCommittedWriteError()\n }\n const key = this.getKeyFromItem(messageWithoutKey.value)\n\n // Check if an item with this key already exists when inserting\n if (messageWithoutKey.type === `insert`) {\n const insertingIntoExistingSynced = this.syncedData.has(key)\n const hasPendingDeleteForKey =\n pendingTransaction.deletedKeys.has(key)\n const isTruncateTransaction = pendingTransaction.truncate === true\n // Allow insert after truncate in the same transaction even if it existed in syncedData\n if (\n insertingIntoExistingSynced &&\n !hasPendingDeleteForKey &&\n !isTruncateTransaction\n ) {\n throw new DuplicateKeySyncError(key, this.id)\n }\n }\n\n const message: ChangeMessage<TOutput> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n\n if (messageWithoutKey.type === `delete`) {\n pendingTransaction.deletedKeys.add(key)\n }\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new NoPendingSyncTransactionCommitError()\n }\n if (pendingTransaction.committed) {\n throw new SyncTransactionAlreadyCommittedError()\n }\n\n pendingTransaction.committed = true\n\n // Update status to initialCommit when transitioning from loading\n // This indicates we're in the process of committing the first transaction\n if (this._status === `loading`) {\n this.setStatus(`initialCommit`)\n }\n\n this.commitPendingTransactions()\n },\n markReady: () => {\n this.markReady()\n },\n truncate: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new NoPendingSyncTransactionWriteError()\n }\n if (pendingTransaction.committed) {\n throw new SyncTransactionAlreadyCommittedWriteError()\n }\n\n // Clear all operations from the current transaction\n pendingTransaction.operations = []\n pendingTransaction.deletedKeys.clear()\n\n // Mark the transaction as a truncate operation. During commit, this triggers:\n // - Delete events for all previously synced keys (excluding optimistic-deleted keys)\n // - Clearing of syncedData/syncedMetadata\n // - Subsequent synced ops applied on the fresh base\n // - Finally, optimistic mutations re-applied on top (single batch)\n pendingTransaction.truncate = true\n },\n })\n\n // Store cleanup function if provided\n this.syncCleanupFn = typeof cleanupFn === `function` ? cleanupFn : null\n } catch (error) {\n this.setStatus(`error`)\n throw error\n }\n }\n\n /**\n * Preload the collection data by starting sync if not already started\n * Multiple concurrent calls will share the same promise\n */\n public preload(): Promise<void> {\n if (this.preloadPromise) {\n return this.preloadPromise\n }\n\n this.preloadPromise = new Promise<void>((resolve, reject) => {\n if (this._status === `ready`) {\n resolve()\n return\n }\n\n if (this._status === `error`) {\n reject(new CollectionIsInErrorStateError())\n return\n }\n\n // Register callback BEFORE starting sync to avoid race condition\n this.onFirstReady(() => {\n resolve()\n })\n\n // Start sync if collection hasn't started yet or was cleaned up\n if (this._status === `idle` || this._status === `cleaned-up`) {\n try {\n this.startSync()\n } catch (error) {\n reject(error)\n return\n }\n }\n })\n\n return this.preloadPromise\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 async cleanup(): Promise<void> {\n // Clear GC timeout\n if (this.gcTimeoutId) {\n clearTimeout(this.gcTimeoutId)\n this.gcTimeoutId = null\n }\n\n // Stop sync - wrap in try/catch since it's user-provided code\n try {\n if (this.syncCleanupFn) {\n this.syncCleanupFn()\n this.syncCleanupFn = null\n }\n } catch (error) {\n // Re-throw in a microtask to surface the error after cleanup completes\n queueMicrotask(() => {\n if (error instanceof Error) {\n // Preserve the original error and stack trace\n const wrappedError = new SyncCleanupError(this.id, error)\n wrappedError.cause = error\n wrappedError.stack = error.stack\n throw wrappedError\n } else {\n throw new SyncCleanupError(this.id, error as Error | string)\n }\n })\n }\n\n // Clear data\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 this.hasBeenReady = false\n this.onFirstReadyCallbacks = []\n this.preloadPromise = null\n this.batchedEvents = []\n this.shouldBatchEvents = false\n\n // Update status\n this.setStatus(`cleaned-up`)\n\n return Promise.resolve()\n }\n\n /**\n * Start the garbage collection timer\n * Called when the collection becomes inactive (no subscribers)\n */\n private startGCTimer(): void {\n if (this.gcTimeoutId) {\n clearTimeout(this.gcTimeoutId)\n }\n\n const gcTime = this.config.gcTime ?? 300000 // 5 minutes default\n\n // If gcTime is 0, GC is disabled\n if (gcTime === 0) {\n return\n }\n\n this.gcTimeoutId = setTimeout(() => {\n if (this.activeSubscribersCount === 0) {\n this.cleanup()\n }\n }, gcTime)\n }\n\n /**\n * Cancel the garbage collection timer\n * Called when the collection becomes active again\n */\n private cancelGCTimer(): void {\n if (this.gcTimeoutId) {\n clearTimeout(this.gcTimeoutId)\n this.gcTimeoutId = null\n }\n }\n\n /**\n * Increment the active subscribers count and start sync if needed\n */\n private addSubscriber(): void {\n this.activeSubscribersCount++\n this.cancelGCTimer()\n\n // Start sync if collection was cleaned up\n if (this._status === `cleaned-up` || this._status === `idle`) {\n this.startSync()\n }\n }\n\n /**\n * Decrement the active subscribers count and start GC timer if needed\n */\n private removeSubscriber(): void {\n this.activeSubscribersCount--\n\n if (this.activeSubscribersCount === 0) {\n this.startGCTimer()\n } else if (this.activeSubscribersCount < 0) {\n throw new NegativeActiveSubscribersError()\n }\n }\n\n /**\n * Recompute optimistic state from active transactions\n */\n private recomputeOptimisticState(\n triggeredByUserAction: boolean = false\n ): void {\n // Skip redundant recalculations when we're in the middle of committing sync transactions\n if (this.isCommittingSyncTransactions) {\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 (mutation.collection === this && 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) => m.collection === this && 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.updateIndexes(filteredEvents)\n }\n this.emitEvents(filteredEvents, triggeredByUserAction)\n } else {\n // Update indexes for all events\n if (filteredEventsBySyncStatus.length > 0) {\n this.updateIndexes(filteredEventsBySyncStatus)\n }\n // Emit all events if no pending sync transactions\n this.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 * Emit an empty ready event to notify subscribers that the collection is ready\n * This bypasses the normal empty array check in emitEvents\n */\n private emitEmptyReadyEvent(): void {\n // Emit empty array directly to all listeners\n for (const listener of this.changeListeners) {\n listener([])\n }\n // Emit to key-specific listeners\n for (const [_key, keyListeners] of this.changeKeyListeners) {\n for (const listener of keyListeners) {\n listener([])\n }\n }\n }\n\n /**\n * Emit events either immediately or batch them for later emission\n */\n private emitEvents(\n changes: Array<ChangeMessage<TOutput, TKey>>,\n forceEmit = false\n ): void {\n // Skip batching for user actions (forceEmit=true) to keep UI responsive\n if (this.shouldBatchEvents && !forceEmit) {\n // Add events to the batch\n this.batchedEvents.push(...changes)\n return\n }\n\n // Either we're not batching, or we're forcing emission (user action or ending batch cycle)\n let eventsToEmit = changes\n\n // If we have batched events and this is a forced emit, combine them\n if (this.batchedEvents.length > 0 && forceEmit) {\n eventsToEmit = [...this.batchedEvents, ...changes]\n this.batchedEvents = []\n this.shouldBatchEvents = false\n }\n\n if (eventsToEmit.length === 0) return\n\n // Emit to all listeners\n for (const listener of this.changeListeners) {\n listener(eventsToEmit)\n }\n\n // Emit to key-specific listeners\n if (this.changeKeyListeners.size > 0) {\n // Group changes by key, but only for keys that have listeners\n const changesByKey = new Map<TKey, Array<ChangeMessage<TOutput, TKey>>>()\n for (const change of eventsToEmit) {\n if (this.changeKeyListeners.has(change.key)) {\n if (!changesByKey.has(change.key)) {\n changesByKey.set(change.key, [])\n }\n changesByKey.get(change.key)!.push(change)\n }\n }\n\n // Emit batched changes to each key's listeners\n for (const [key, keyChanges] of changesByKey) {\n const keyListeners = this.changeKeyListeners.get(key)!\n for (const listener of keyListeners) {\n listener(keyChanges)\n }\n }\n }\n }\n\n /**\n * Get the current value for a key (virtual derived state)\n */\n public get(key: TKey): TOutput | undefined {\n // Check if optimistically deleted\n if (this.optimisticDeletes.has(key)) {\n return undefined\n }\n\n // Check optimistic upserts first\n if (this.optimisticUpserts.has(key)) {\n return this.optimisticUpserts.get(key)\n }\n\n // Fall back to synced data\n return this.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 // Check if optimistically deleted\n if (this.optimisticDeletes.has(key)) {\n return false\n }\n\n // Check optimistic upserts first\n if (this.optimisticUpserts.has(key)) {\n return true\n }\n\n // Fall back to synced data\n return this.syncedData.has(key)\n }\n\n /**\n * Get the current size of the collection (cached)\n */\n public get size(): number {\n return this._size\n }\n\n /**\n * Get all keys (virtual derived state)\n */\n public *keys(): IterableIterator<TKey> {\n // Yield keys from synced data, skipping any that are deleted.\n for (const key of this.syncedData.keys()) {\n if (!this.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 this.optimisticUpserts.keys()) {\n if (!this.syncedData.has(key) && !this.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 * 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 } = this.pendingSyncedTransactions.reduce(\n (acc, t) => {\n if (t.committed) {\n acc.committedSyncedTransactions.push(t)\n if (t.truncate === true) {\n acc.hasTruncateSync = true\n }\n } else {\n acc.uncommittedSyncedTransactions.push(t)\n }\n return acc\n },\n {\n committedSyncedTransactions: [] as Array<\n PendingSyncedTransaction<TOutput>\n >,\n uncommittedSyncedTransactions: [] as Array<\n PendingSyncedTransaction<TOutput>\n >,\n hasTruncateSync: false,\n }\n )\n\n if (!hasPersistingTransaction || hasTruncateSync) {\n // Set flag to prevent redundant optimistic state recalculations\n this.isCommittingSyncTransactions = true\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 currently-synced key 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 for (const key of this.syncedData.keys()) {\n if (this.optimisticDeletes.has(key)) continue\n const previousValue =\n this.optimisticUpserts.get(key) || 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\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 ACTIVE optimistic transactions against the new synced base\n // We do not copy maps; we compute intent directly from transactions to avoid drift.\n const reapplyUpserts = new Map<TKey, TOutput>()\n const reapplyDeletes = new Set<TKey>()\n\n for (const tx of this.transactions.values()) {\n if ([`completed`, `failed`].includes(tx.state)) continue\n for (const mutation of tx.mutations) {\n if (mutation.collection !== this || !mutation.optimistic) continue\n const key = mutation.key as TKey\n switch (mutation.type) {\n case `insert`:\n reapplyUpserts.set(key, mutation.modified as TOutput)\n reapplyDeletes.delete(key)\n break\n case `update`: {\n const base = this.syncedData.get(key)\n const next = base\n ? (Object.assign({}, base, mutation.changes) as TOutput)\n : (mutation.modified as TOutput)\n reapplyUpserts.set(key, next)\n reapplyDeletes.delete(key)\n break\n }\n case `delete`:\n reapplyUpserts.delete(key)\n reapplyDeletes.add(key)\n break\n }\n }\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.isReady()) {\n this.setStatus(`ready`)\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 for (const transaction of this.transactions.values()) {\n if (![`completed`, `failed`].includes(transaction.state)) {\n for (const mutation of transaction.mutations) {\n if (mutation.collection === this && 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\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 (mutation.collection === this && changedKeys.has(mutation.key)) {\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 const isRedundantSync =\n completedOp &&\n newVisibleValue !== undefined &&\n deepEquals(completedOp.value, newVisibleValue)\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.updateIndexes(events)\n }\n\n // End batching and emit all events (combines any batched events with sync events)\n this.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 // Call any registered one-time commit listeners\n if (!this.hasReceivedFirstCommit) {\n this.hasReceivedFirstCommit = true\n const callbacks = [...this.onFirstReadyCallbacks]\n this.onFirstReadyCallbacks = []\n callbacks.forEach((callback) => callback())\n }\n }\n }\n\n /**\n * Schedule cleanup of a transaction when it completes\n * @private\n */\n private 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 private ensureStandardSchema(schema: unknown): StandardSchema<TOutput> {\n // If the schema already implements the standard-schema interface, return it\n if (schema && `~standard` in (schema as {})) {\n return schema as StandardSchema<TOutput>\n }\n\n throw new InvalidSchemaError()\n }\n\n public getKeyFromItem(item: TOutput): TKey {\n return this.config.getKey(item)\n }\n\n public generateGlobalKey(key: any, item: any): string {\n if (typeof key === `undefined`) {\n throw new UndefinedKeyError(item)\n }\n\n return `KEY::${this.id}/${key}`\n }\n\n /**\n * Creates an index on a collection for faster queries.\n * Indexes significantly improve query performance by allowing constant time lookups\n * and logarithmic time range queries instead of full scans.\n *\n * @template TResolver - The type of the index resolver (constructor or async loader)\n * @param indexCallback - Function that extracts the indexed value from each item\n * @param config - Configuration including index type and type-specific options\n * @returns An index proxy that provides access to the index when ready\n *\n * @example\n * // Create a default B+ tree index\n * const ageIndex = collection.createIndex((row) => row.age)\n *\n * // Create a ordered index with custom options\n * const ageIndex = collection.createIndex((row) => row.age, {\n * indexType: BTreeIndex,\n * options: { compareFn: customComparator },\n * name: 'age_btree'\n * })\n *\n * // Create an async-loaded index\n * const textIndex = collection.createIndex((row) => row.content, {\n * indexType: async () => {\n * const { FullTextIndex } = await import('./indexes/fulltext.js')\n * return FullTextIndex\n * },\n * options: { language: 'en' }\n * })\n */\n public createIndex<TResolver extends IndexResolver<TKey> = typeof BTreeIndex>(\n indexCallback: (row: SingleRowRefProxy<TOutput>) => any,\n config: IndexOptions<TResolver> = {}\n ): IndexProxy<TKey> {\n this.validateCollectionUsable(`createIndex`)\n\n const indexId = ++this.indexCounter\n const singleRowRefProxy = createSingleRowRefProxy<TOutput>()\n const indexExpression = indexCallback(singleRowRefProxy)\n const expression = toExpression(indexExpression)\n\n // Default to BTreeIndex if no type specified\n const resolver = config.indexType ?? (BTreeIndex as unknown as TResolver)\n\n // Create lazy wrapper\n const lazyIndex = new LazyIndexWrapper<TKey>(\n indexId,\n expression,\n config.name,\n resolver,\n config.options,\n this.entries()\n )\n\n this.lazyIndexes.set(indexId, lazyIndex)\n\n // For BTreeIndex, resolve immediately and synchronously\n if ((resolver as unknown) === BTreeIndex) {\n try {\n const resolvedIndex = lazyIndex.getResolved()\n this.resolvedIndexes.set(indexId, resolvedIndex)\n } catch (error) {\n console.warn(`Failed to resolve BTreeIndex:`, error)\n }\n } else if (typeof resolver === `function` && resolver.prototype) {\n // Other synchronous constructors - resolve immediately\n try {\n const resolvedIndex = lazyIndex.getResolved()\n this.resolvedIndexes.set(indexId, resolvedIndex)\n } catch {\n // Fallback to async resolution\n this.resolveSingleIndex(indexId, lazyIndex).catch((error) => {\n console.warn(`Failed to resolve single index:`, error)\n })\n }\n } else if (this.isIndexesResolved) {\n // Async loader but indexes are already resolved - resolve this one\n this.resolveSingleIndex(indexId, lazyIndex).catch((error) => {\n console.warn(`Failed to resolve single index:`, error)\n })\n }\n\n return new IndexProxy(indexId, lazyIndex)\n }\n\n /**\n * Resolve all lazy indexes (called when collection first syncs)\n * @private\n */\n private async resolveAllIndexes(): Promise<void> {\n if (this.isIndexesResolved) return\n\n const resolutionPromises = Array.from(this.lazyIndexes.entries()).map(\n async ([indexId, lazyIndex]) => {\n const resolvedIndex = await lazyIndex.resolve()\n\n // Build index with current data\n resolvedIndex.build(this.entries())\n\n this.resolvedIndexes.set(indexId, resolvedIndex)\n return { indexId, resolvedIndex }\n }\n )\n\n await Promise.all(resolutionPromises)\n this.isIndexesResolved = true\n }\n\n /**\n * Resolve a single index immediately\n * @private\n */\n private async resolveSingleIndex(\n indexId: number,\n lazyIndex: LazyIndexWrapper<TKey>\n ): Promise<BaseIndex<TKey>> {\n const resolvedIndex = await lazyIndex.resolve()\n resolvedIndex.build(this.entries())\n this.resolvedIndexes.set(indexId, resolvedIndex)\n return resolvedIndex\n }\n\n /**\n * Get resolved indexes for query optimization\n */\n get indexes(): Map<number, BaseIndex<TKey>> {\n return this.resolvedIndexes\n }\n\n /**\n * Updates all indexes when the collection changes\n * @private\n */\n private updateIndexes(changes: Array<ChangeMessage<TOutput, TKey>>): void {\n for (const index of this.resolvedIndexes.values()) {\n for (const change of changes) {\n switch (change.type) {\n case `insert`:\n index.add(change.key, change.value)\n break\n case `update`:\n if (change.previousValue) {\n index.update(change.key, change.previousValue, change.value)\n } else {\n index.add(change.key, change.value)\n }\n break\n case `delete`:\n index.remove(change.key, change.value)\n break\n }\n }\n }\n }\n\n public validateData(\n data: unknown,\n type: `insert` | `update`,\n key?: TKey\n ): TOutput | never {\n if (!this.config.schema) return data as TOutput\n\n const standardSchema = this.ensureStandardSchema(this.config.schema)\n\n // For updates, we need to merge with the existing data before validation\n if (type === `update` && key) {\n // Get the existing data for this key\n const existingData = this.get(key)\n\n if (\n existingData &&\n data &&\n typeof data === `object` &&\n typeof existingData === `object`\n ) {\n // Merge the update with the existing data\n const mergedData = Object.assign({}, existingData, data)\n\n // Validate the merged data\n const result = standardSchema[`~standard`].validate(mergedData)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new SchemaMustBeSynchronousError()\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n // Extract only the modified keys from the validated result\n const validatedMergedData = result.value as TOutput\n const modifiedKeys = Object.keys(data)\n const extractedChanges = Object.fromEntries(\n modifiedKeys.map((k) => [k, validatedMergedData[k as keyof TOutput]])\n ) as TOutput\n\n return extractedChanges\n }\n }\n\n // For inserts or updates without existing data, validate the data directly\n const result = standardSchema[`~standard`].validate(data)\n\n // Ensure validation is synchronous\n if (result instanceof Promise) {\n throw new SchemaMustBeSynchronousError()\n }\n\n // If validation fails, throw a SchemaValidationError with the issues\n if (`issues` in result && result.issues) {\n const typedIssues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((p) => String(p)),\n }))\n throw new SchemaValidationError(type, typedIssues)\n }\n\n return result.value as TOutput\n }\n\n /**\n * Inserts one or more items into the collection\n * @param items - Single item or array of items to insert\n * @param config - Optional configuration including metadata\n * @returns A Transaction object representing the insert operation(s)\n * @throws {SchemaValidationError} If the data fails schema validation\n * @example\n * // Insert a single todo (requires onInsert handler)\n * const tx = collection.insert({ id: \"1\", text: \"Buy milk\", completed: false })\n * await tx.isPersisted.promise\n *\n * @example\n * // Insert multiple todos at once\n * const tx = collection.insert([\n * { id: \"1\", text: \"Buy milk\", completed: false },\n * { id: \"2\", text: \"Walk dog\", completed: true }\n * ])\n * await tx.isPersisted.promise\n *\n * @example\n * // Insert with metadata\n * const tx = collection.insert({ id: \"1\", text: \"Buy groceries\" },\n * { metadata: { source: \"mobile-app\" } }\n * )\n * await tx.isPersisted.promise\n *\n * @example\n * // Handle errors\n * try {\n * const tx = collection.insert({ id: \"1\", text: \"New item\" })\n * await tx.isPersisted.promise\n * console.log('Insert successful')\n * } catch (error) {\n * console.log('Insert failed:', error)\n * }\n */\n insert = (data: TInput | Array<TInput>, config?: InsertConfig) => {\n this.validateCollectionUsable(`insert`)\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onInsert handler early\n if (!ambientTransaction && !this.config.onInsert) {\n throw new MissingInsertHandlerError()\n }\n\n const items = Array.isArray(data) ? data : [data]\n const mutations: Array<PendingMutation<TOutput>> = []\n\n // Create mutations for each item\n items.forEach((item) => {\n // Validate the data against the schema if one exists\n const validatedData = this.validateData(item, `insert`)\n\n // Check if an item with this ID already exists in the collection\n const key = this.getKeyFromItem(validatedData)\n if (this.has(key)) {\n throw new DuplicateKeyError(key)\n }\n const globalKey = this.generateGlobalKey(key, item)\n\n const mutation: PendingMutation<TOutput, `insert`> = {\n mutationId: crypto.randomUUID(),\n original: {},\n modified: validatedData,\n // Pick the values from validatedData based on what's passed in - this is for cases\n // where a schema has default values. The validated data has the extra default\n // values but for changes, we just want to show the data that was actually passed in.\n changes: Object.fromEntries(\n Object.keys(item).map((k) => [\n k,\n validatedData[k as keyof typeof validatedData],\n ])\n ) as TInput,\n globalKey,\n key,\n metadata: config?.metadata as unknown,\n syncMetadata: this.config.sync.getSyncMetadata?.() || {},\n optimistic: config?.optimistic ?? true,\n type: `insert`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n })\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.set(ambientTransaction.id, ambientTransaction)\n this.scheduleTransactionCleanup(ambientTransaction)\n this.recomputeOptimisticState(true)\n\n return ambientTransaction\n } else {\n // Create a new transaction with a mutation function that calls the onInsert handler\n const directOpTransaction = createTransaction<TOutput>({\n mutationFn: async (params) => {\n // Call the onInsert handler with the transaction and collection\n return await this.config.onInsert!({\n transaction:\n params.transaction as unknown as TransactionWithMutations<\n TOutput,\n `insert`\n >,\n collection: this as unknown as Collection<TOutput, TKey, TUtils>,\n })\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n this.transactions.set(directOpTransaction.id, directOpTransaction)\n this.scheduleTransactionCleanup(directOpTransaction)\n this.recomputeOptimisticState(true)\n\n return directOpTransaction\n }\n }\n\n /**\n * Updates one or more items in the collection using a callback function\n * @param keys - Single key or array of keys to update\n * @param configOrCallback - Either update configuration or update callback\n * @param maybeCallback - Update callback if config was provided\n * @returns A Transaction object representing the update operation(s)\n * @throws {SchemaValidationError} If the updated data fails schema validation\n * @example\n * // Update single item by key\n * const tx = collection.update(\"todo-1\", (draft) => {\n * draft.completed = true\n * })\n * await tx.isPersisted.promise\n *\n * @example\n * // Update multiple items\n * const tx = collection.update([\"todo-1\", \"todo-2\"], (drafts) => {\n * drafts.forEach(draft => { draft.completed = true })\n * })\n * await tx.isPersisted.promise\n *\n * @example\n * // Update with metadata\n * const tx = collection.update(\"todo-1\",\n * { metadata: { reason: \"user update\" } },\n * (draft) => { draft.text = \"Updated text\" }\n * )\n * await tx.isPersisted.promise\n *\n * @example\n * // Handle errors\n * try {\n * const tx = collection.update(\"item-1\", draft => { draft.value = \"new\" })\n * await tx.isPersisted.promise\n * console.log('Update successful')\n * } catch (error) {\n * console.log('Update failed:', error)\n * }\n */\n\n // Overload 1: Update multiple items with a callback\n update(\n key: Array<TKey | unknown>,\n callback: (drafts: Array<WritableDeep<TInput>>) => void\n ): TransactionType\n\n // Overload 2: Update multiple items with config and a callback\n update(\n keys: Array<TKey | unknown>,\n config: OperationConfig,\n callback: (drafts: Array<WritableDeep<TInput>>) => void\n ): TransactionType\n\n // Overload 3: Update a single item with a callback\n update(\n id: TKey | unknown,\n callback: (draft: WritableDeep<TInput>) => void\n ): TransactionType\n\n // Overload 4: Update a single item with config and a callback\n update(\n id: TKey | unknown,\n config: OperationConfig,\n callback: (draft: WritableDeep<TInput>) => void\n ): TransactionType\n\n update(\n keys: (TKey | unknown) | Array<TKey | unknown>,\n configOrCallback:\n | ((draft: WritableDeep<TInput>) => void)\n | ((drafts: Array<WritableDeep<TInput>>) => void)\n | OperationConfig,\n maybeCallback?:\n | ((draft: WritableDeep<TInput>) => void)\n | ((drafts: Array<WritableDeep<TInput>>) => void)\n ) {\n if (typeof keys === `undefined`) {\n throw new MissingUpdateArgumentError()\n }\n\n this.validateCollectionUsable(`update`)\n\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onUpdate handler early\n if (!ambientTransaction && !this.config.onUpdate) {\n throw new MissingUpdateHandlerError()\n }\n\n const isArray = Array.isArray(keys)\n const keysArray = isArray ? keys : [keys]\n\n if (isArray && keysArray.length === 0) {\n throw new NoKeysPassedToUpdateError()\n }\n\n const callback =\n typeof configOrCallback === `function` ? configOrCallback : maybeCallback!\n const config =\n typeof configOrCallback === `function` ? {} : configOrCallback\n\n // Get the current objects or empty objects if they don't exist\n const currentObjects = keysArray.map((key) => {\n const item = this.get(key)\n if (!item) {\n throw new UpdateKeyNotFoundError(key)\n }\n\n return item\n }) as unknown as Array<TInput>\n\n let changesArray\n if (isArray) {\n // Use the proxy to track changes for all objects\n changesArray = withArrayChangeTracking(\n currentObjects,\n callback as (draft: Array<TInput>) => void\n )\n } else {\n const result = withChangeTracking(\n currentObjects[0]!,\n callback as (draft: TInput) => void\n )\n changesArray = [result]\n }\n\n // Create mutations for each object that has changes\n const mutations: Array<PendingMutation<TOutput, `update`, this>> = keysArray\n .map((key, index) => {\n const itemChanges = changesArray[index] // User-provided changes for this specific item\n\n // Skip items with no changes\n if (!itemChanges || Object.keys(itemChanges).length === 0) {\n return null\n }\n\n const originalItem = currentObjects[index] as unknown as TOutput\n // Validate the user-provided changes for this item\n const validatedUpdatePayload = this.validateData(\n itemChanges,\n `update`,\n key\n )\n\n // Construct the full modified item by applying the validated update payload to the original item\n const modifiedItem = Object.assign(\n {},\n originalItem,\n validatedUpdatePayload\n )\n\n // Check if the ID of the item is being changed\n const originalItemId = this.getKeyFromItem(originalItem)\n const modifiedItemId = this.getKeyFromItem(modifiedItem)\n\n if (originalItemId !== modifiedItemId) {\n throw new KeyUpdateNotAllowedError(originalItemId, modifiedItemId)\n }\n\n const globalKey = this.generateGlobalKey(modifiedItemId, modifiedItem)\n\n return {\n mutationId: crypto.randomUUID(),\n original: originalItem,\n modified: modifiedItem,\n // Pick the values from modifiedItem based on what's passed in - this is for cases\n // where a schema has default values or transforms. The modified data has the extra\n // default or transformed values but for changes, we just want to show the data that\n // was actually passed in.\n changes: Object.fromEntries(\n Object.keys(itemChanges).map((k) => [\n k,\n modifiedItem[k as keyof typeof modifiedItem],\n ])\n ) as TInput,\n globalKey,\n key,\n metadata: config.metadata as unknown,\n syncMetadata: (this.syncedMetadata.get(key) || {}) as Record<\n string,\n unknown\n >,\n optimistic: config.optimistic ?? true,\n type: `update`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n })\n .filter(Boolean) as Array<PendingMutation<TOutput, `update`, this>>\n\n // If no changes were made, return an empty transaction early\n if (mutations.length === 0) {\n const emptyTransaction = createTransaction({\n mutationFn: async () => {},\n })\n emptyTransaction.commit()\n // Schedule cleanup for empty transaction\n this.scheduleTransactionCleanup(emptyTransaction)\n return emptyTransaction\n }\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.set(ambientTransaction.id, ambientTransaction)\n this.scheduleTransactionCleanup(ambientTransaction)\n this.recomputeOptimisticState(true)\n\n return ambientTransaction\n }\n\n // No need to check for onUpdate handler here as we've already checked at the beginning\n\n // Create a new transaction with a mutation function that calls the onUpdate handler\n const directOpTransaction = createTransaction<TOutput>({\n mutationFn: async (params) => {\n // Call the onUpdate handler with the transaction and collection\n return this.config.onUpdate!({\n transaction:\n params.transaction as unknown as TransactionWithMutations<\n TOutput,\n `update`\n >,\n collection: this as unknown as Collection<TOutput, TKey, TUtils>,\n })\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n // Add the transaction to the collection's transactions store\n\n this.transactions.set(directOpTransaction.id, directOpTransaction)\n this.scheduleTransactionCleanup(directOpTransaction)\n this.recomputeOptimisticState(true)\n\n return directOpTransaction\n }\n\n /**\n * Deletes one or more items from the collection\n * @param keys - Single key or array of keys to delete\n * @param config - Optional configuration including metadata\n * @returns A Transaction object representing the delete operation(s)\n * @example\n * // Delete a single item\n * const tx = collection.delete(\"todo-1\")\n * await tx.isPersisted.promise\n *\n * @example\n * // Delete multiple items\n * const tx = collection.delete([\"todo-1\", \"todo-2\"])\n * await tx.isPersisted.promise\n *\n * @example\n * // Delete with metadata\n * const tx = collection.delete(\"todo-1\", { metadata: { reason: \"completed\" } })\n * await tx.isPersisted.promise\n *\n * @example\n * // Handle errors\n * try {\n * const tx = collection.delete(\"item-1\")\n * await tx.isPersisted.promise\n * console.log('Delete successful')\n * } catch (error) {\n * console.log('Delete failed:', error)\n * }\n */\n delete = (\n keys: Array<TKey> | TKey,\n config?: OperationConfig\n ): TransactionType<any> => {\n this.validateCollectionUsable(`delete`)\n\n const ambientTransaction = getActiveTransaction()\n\n // If no ambient transaction exists, check for an onDelete handler early\n if (!ambientTransaction && !this.config.onDelete) {\n throw new MissingDeleteHandlerError()\n }\n\n if (Array.isArray(keys) && keys.length === 0) {\n throw new NoKeysPassedToDeleteError()\n }\n\n const keysArray = Array.isArray(keys) ? keys : [keys]\n const mutations: Array<PendingMutation<TOutput, `delete`, this>> = []\n\n for (const key of keysArray) {\n if (!this.has(key)) {\n throw new DeleteKeyNotFoundError(key)\n }\n const globalKey = this.generateGlobalKey(key, this.get(key)!)\n const mutation: PendingMutation<TOutput, `delete`, this> = {\n mutationId: crypto.randomUUID(),\n original: this.get(key)!,\n modified: this.get(key)!,\n changes: this.get(key)!,\n globalKey,\n key,\n metadata: config?.metadata as unknown,\n syncMetadata: (this.syncedMetadata.get(key) || {}) as Record<\n string,\n unknown\n >,\n optimistic: config?.optimistic ?? true,\n type: `delete`,\n createdAt: new Date(),\n updatedAt: new Date(),\n collection: this,\n }\n\n mutations.push(mutation)\n }\n\n // If an ambient transaction exists, use it\n if (ambientTransaction) {\n ambientTransaction.applyMutations(mutations)\n\n this.transactions.set(ambientTransaction.id, ambientTransaction)\n this.scheduleTransactionCleanup(ambientTransaction)\n this.recomputeOptimisticState(true)\n\n return ambientTransaction\n }\n\n // Create a new transaction with a mutation function that calls the onDelete handler\n const directOpTransaction = createTransaction<TOutput>({\n autoCommit: true,\n mutationFn: async (params) => {\n // Call the onDelete handler with the transaction and collection\n return this.config.onDelete!({\n transaction:\n params.transaction as unknown as TransactionWithMutations<\n TOutput,\n `delete`\n >,\n collection: this as unknown as Collection<TOutput, TKey, TUtils>,\n })\n },\n })\n\n // Apply mutations to the new transaction\n directOpTransaction.applyMutations(mutations)\n directOpTransaction.commit()\n\n this.transactions.set(directOpTransaction.id, directOpTransaction)\n this.scheduleTransactionCleanup(directOpTransaction)\n this.recomputeOptimisticState(true)\n\n return directOpTransaction\n }\n\n /**\n * Gets the current state of the collection as a Map\n * @returns Map containing all items in the collection, with keys as identifiers\n * @example\n * const itemsMap = collection.state\n * console.log(`Collection has ${itemsMap.size} items`)\n *\n * for (const [key, item] of itemsMap) {\n * console.log(`${key}: ${item.title}`)\n * }\n *\n * // Check if specific item exists\n * if (itemsMap.has(\"todo-1\")) {\n * console.log(\"Todo 1 exists:\", itemsMap.get(\"todo-1\"))\n * }\n */\n get state() {\n const result = new Map<TKey, TOutput>()\n for (const [key, value] of this.entries()) {\n result.set(key, value)\n }\n return result\n }\n\n /**\n * Gets the current state of the collection as a Map, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to a Map containing all items in the collection\n */\n stateWhenReady(): Promise<Map<TKey, TOutput>> {\n // If we already have data or collection is ready, resolve immediately\n if (this.size > 0 || this.isReady()) {\n return Promise.resolve(this.state)\n }\n\n // Otherwise, wait for the collection to be ready\n return new Promise<Map<TKey, TOutput>>((resolve) => {\n this.onFirstReady(() => {\n resolve(this.state)\n })\n })\n }\n\n /**\n * Gets the current state of the collection as an Array\n *\n * @returns An Array containing all items in the collection\n */\n get toArray() {\n return Array.from(this.values())\n }\n\n /**\n * Gets the current state of the collection as an Array, but only resolves when data is available\n * Waits for the first sync commit to complete before resolving\n *\n * @returns Promise that resolves to an Array containing all items in the collection\n */\n toArrayWhenReady(): Promise<Array<TOutput>> {\n // If we already have data or collection is ready, resolve immediately\n if (this.size > 0 || this.isReady()) {\n return Promise.resolve(this.toArray)\n }\n\n // Otherwise, wait for the collection to be ready\n return new Promise<Array<TOutput>>((resolve) => {\n this.onFirstReady(() => {\n resolve(this.toArray)\n })\n })\n }\n\n /**\n * Returns the current state of the collection as an array of changes\n * @param options - Options including optional where filter\n * @returns An array of changes\n * @example\n * // Get all items as changes\n * const allChanges = collection.currentStateAsChanges()\n *\n * // Get only items matching a condition\n * const activeChanges = collection.currentStateAsChanges({\n * where: (row) => row.status === 'active'\n * })\n *\n * // Get only items using a pre-compiled expression\n * const activeChanges = collection.currentStateAsChanges({\n * whereExpression: eq(row.status, 'active')\n * })\n */\n public currentStateAsChanges(\n options: CurrentStateAsChangesOptions<TOutput> = {}\n ): Array<ChangeMessage<TOutput>> {\n return currentStateAsChanges(this, options)\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - Function called when items change\n * @param options - Subscription options including includeInitialState and where filter\n * @returns Unsubscribe function - Call this to stop listening for changes\n * @example\n * // Basic subscription\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * changes.forEach(change => {\n * console.log(`${change.type}: ${change.key}`, change.value)\n * })\n * })\n *\n * // Later: unsubscribe()\n *\n * @example\n * // Include current state immediately\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * updateUI(changes)\n * }, { includeInitialState: true })\n *\n * @example\n * // Subscribe only to changes matching a condition\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * updateUI(changes)\n * }, {\n * includeInitialState: true,\n * where: (row) => row.status === 'active'\n * })\n *\n * @example\n * // Subscribe using a pre-compiled expression\n * const unsubscribe = collection.subscribeChanges((changes) => {\n * updateUI(changes)\n * }, {\n * includeInitialState: true,\n * whereExpression: eq(row.status, 'active')\n * })\n */\n public subscribeChanges(\n callback: (changes: Array<ChangeMessage<TOutput>>) => void,\n options: SubscribeChangesOptions<TOutput> = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n // Auto-index for where expressions if enabled\n if (options.whereExpression) {\n ensureIndexForExpression(options.whereExpression, this)\n }\n\n // Create a filtered callback if where clause is provided\n const filteredCallback =\n options.where || options.whereExpression\n ? createFilteredCallback(callback, options)\n : callback\n\n if (options.includeInitialState) {\n // First send the current state as changes (filtered if needed)\n const initialChanges = this.currentStateAsChanges({\n where: options.where,\n whereExpression: options.whereExpression,\n })\n filteredCallback(initialChanges)\n }\n\n // Add to batched listeners\n this.changeListeners.add(filteredCallback)\n\n return () => {\n this.changeListeners.delete(filteredCallback)\n this.removeSubscriber()\n }\n }\n\n /**\n * Subscribe to changes for a specific key\n */\n public subscribeChangesKey(\n key: TKey,\n listener: ChangeListener<TOutput, TKey>,\n { includeInitialState = false }: { includeInitialState?: boolean } = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n if (!this.changeKeyListeners.has(key)) {\n this.changeKeyListeners.set(key, new Set())\n }\n\n if (includeInitialState) {\n // First send the current state as changes\n listener([\n {\n type: `insert`,\n key,\n value: this.get(key)!,\n },\n ])\n }\n\n this.changeKeyListeners.get(key)!.add(listener)\n\n return () => {\n const listeners = this.changeKeyListeners.get(key)\n if (listeners) {\n listeners.delete(listener)\n if (listeners.size === 0) {\n this.changeKeyListeners.delete(key)\n }\n }\n this.removeSubscriber()\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 private capturePreSyncVisibleState(): void {\n if (this.pendingSyncedTransactions.length === 0) return\n\n // Clear any previous capture\n this.preSyncVisibleState.clear()\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 for (const key of syncedKeys) {\n const currentValue = this.get(key)\n if (currentValue !== undefined) {\n this.preSyncVisibleState.set(key, currentValue)\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.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"],"names":["config","result"],"mappings":";;;;;;;;;;AA2LO,SAAS,iBACd,SAIyD;AACzD,QAAM,aAAa,IAAI;AAAA,IACrB;AAAA,EAAA;AAIF,MAAI,QAAQ,OAAO;AACjB,eAAW,QAAQ,EAAE,GAAG,QAAQ,MAAA;AAAA,EAClC,OAAO;AACL,eAAW,QAAQ,CAAA;AAAA,EACrB;AAEA,SAAO;AACT;AAEO,MAAM,eAMX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyMA,YAAY,QAAkD;AApM9D,SAAO,4BACL,CAAA;AAEF,SAAO,qCAAqB,IAAA;AAG5B,SAAO,wCAAwB,IAAA;AAC/B,SAAO,wCAAwB,IAAA;AAG/B,SAAQ,QAAQ;AAGhB,SAAQ,kCAAkB,IAAA;AAC1B,SAAQ,sCAAsB,IAAA;AAC9B,SAAQ,oBAAoB;AAC5B,SAAQ,eAAe;AAGvB,SAAQ,sCAAsB,IAAA;AAC9B,SAAQ,yCAAyB,IAAA;AAOjC,SAAO,QAA4B,CAAA;AAGnC,SAAQ,iCAAiB,IAAA;AACzB,SAAQ,0CAA0B,IAAA;AAClC,SAAQ,yCAAyB,IAAA;AACjC,SAAQ,yBAAyB;AACjC,SAAQ,+BAA+B;AAGvC,SAAQ,wBAA2C,CAAA;AACnD,SAAQ,eAAe;AAGvB,SAAQ,gBAAqD,CAAA;AAC7D,SAAQ,oBAAoB;AAG5B,SAAQ,UAA4B;AACpC,SAAQ,yBAAyB;AACjC,SAAQ,cAAoD;AAC5D,SAAQ,iBAAuC;AAC/C,SAAQ,gBAAqC;AAuE7C,SAAO,KAAK;AAgxBZ,SAAA,4BAA4B,MAAM;AAEhC,UAAI,2BAA2B;AAC/B,iBAAW,eAAe,KAAK,aAAa,OAAA,GAAU;AACpD,YAAI,YAAY,UAAU,cAAc;AACtC,qCAA2B;AAC3B;AAAA,QACF;AAAA,MACF;AAIA,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,MAAA,IACE,KAAK,0BAA0B;AAAA,QACjC,CAAC,KAAK,MAAM;AACV,cAAI,EAAE,WAAW;AACf,gBAAI,4BAA4B,KAAK,CAAC;AACtC,gBAAI,EAAE,aAAa,MAAM;AACvB,kBAAI,kBAAkB;AAAA,YACxB;AAAA,UACF,OAAO;AACL,gBAAI,8BAA8B,KAAK,CAAC;AAAA,UAC1C;AACA,iBAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,6BAA6B,CAAA;AAAA,UAG7B,+BAA+B,CAAA;AAAA,UAG/B,iBAAiB;AAAA,QAAA;AAAA,MACnB;AAGF,UAAI,CAAC,4BAA4B,iBAAiB;AAEhD,aAAK,+BAA+B;AAGpC,cAAM,kCAAkB,IAAA;AACxB,mBAAW,eAAe,6BAA6B;AACrD,qBAAW,aAAa,YAAY,YAAY;AAC9C,wBAAY,IAAI,UAAU,GAAW;AAAA,UACvC;AAAA,QACF;AAIA,YAAI,sBAAsB,KAAK;AAC/B,YAAI,oBAAoB,SAAS,GAAG;AAElC,oDAA0B,IAAA;AAC1B,qBAAW,OAAO,aAAa;AAC7B,kBAAM,eAAe,KAAK,IAAI,GAAG;AACjC,gBAAI,iBAAiB,QAAW;AAC9B,kCAAoB,IAAI,KAAK,YAAY;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AAEA,cAAM,SAA8C,CAAA;AACpD,cAAM,gBAAgB,KAAK,OAAO,KAAK,iBAAiB;AAExD,mBAAW,eAAe,6BAA6B;AAErD,cAAI,YAAY,UAAU;AAKxB,uBAAW,OAAO,KAAK,WAAW,KAAA,GAAQ;AACxC,kBAAI,KAAK,kBAAkB,IAAI,GAAG,EAAG;AACrC,oBAAM,gBACJ,KAAK,kBAAkB,IAAI,GAAG,KAAK,KAAK,WAAW,IAAI,GAAG;AAC5D,kBAAI,kBAAkB,QAAW;AAC/B,uBAAO,KAAK,EAAE,MAAM,UAAU,KAAK,OAAO,eAAe;AAAA,cAC3D;AAAA,YACF;AAIA,iBAAK,WAAW,MAAA;AAChB,iBAAK,eAAe,MAAA;AACpB,iBAAK,WAAW,MAAA;AAKhB,uBAAW,OAAO,aAAa;AAC7B,kCAAoB,OAAO,GAAG;AAAA,YAChC;AAAA,UACF;AAEA,qBAAW,aAAa,YAAY,YAAY;AAC9C,kBAAM,MAAM,UAAU;AACtB,iBAAK,WAAW,IAAI,GAAG;AAGvB,oBAAQ,UAAU,MAAA;AAAA,cAChB,KAAK;AACH,qBAAK,eAAe,IAAI,KAAK,UAAU,QAAQ;AAC/C;AAAA,cACF,KAAK;AACH,qBAAK,eAAe;AAAA,kBAClB;AAAA,kBACA,OAAO;AAAA,oBACL,CAAA;AAAA,oBACA,KAAK,eAAe,IAAI,GAAG;AAAA,oBAC3B,UAAU;AAAA,kBAAA;AAAA,gBACZ;AAEF;AAAA,cACF,KAAK;AACH,qBAAK,eAAe,OAAO,GAAG;AAC9B;AAAA,YAAA;AAIJ,oBAAQ,UAAU,MAAA;AAAA,cAChB,KAAK;AACH,qBAAK,WAAW,IAAI,KAAK,UAAU,KAAK;AACxC;AAAA,cACF,KAAK,UAAU;AACb,oBAAI,kBAAkB,WAAW;AAC/B,wBAAM,eAAe,OAAO;AAAA,oBAC1B,CAAA;AAAA,oBACA,KAAK,WAAW,IAAI,GAAG;AAAA,oBACvB,UAAU;AAAA,kBAAA;AAEZ,uBAAK,WAAW,IAAI,KAAK,YAAY;AAAA,gBACvC,OAAO;AACL,uBAAK,WAAW,IAAI,KAAK,UAAU,KAAK;AAAA,gBAC1C;AACA;AAAA,cACF;AAAA,cACA,KAAK;AACH,qBAAK,WAAW,OAAO,GAAG;AAC1B;AAAA,YAAA;AAAA,UAEN;AAAA,QACF;AAMA,YAAI,iBAAiB;AAEnB,gBAAM,kDAAkC,IAAA;AACxC,qBAAW,KAAK,6BAA6B;AAC3C,uBAAW,MAAM,EAAE,YAAY;AAC7B,kBAAI,GAAG,SAAS,YAAY,GAAG,SAAS,UAAU;AAChD,4CAA4B,IAAI,GAAG,GAAW;AAAA,cAChD;AAAA,YACF;AAAA,UACF;AAIA,gBAAM,qCAAqB,IAAA;AAC3B,gBAAM,qCAAqB,IAAA;AAE3B,qBAAW,MAAM,KAAK,aAAa,OAAA,GAAU;AAC3C,gBAAI,CAAC,aAAa,QAAQ,EAAE,SAAS,GAAG,KAAK,EAAG;AAChD,uBAAW,YAAY,GAAG,WAAW;AACnC,kBAAI,SAAS,eAAe,QAAQ,CAAC,SAAS,WAAY;AAC1D,oBAAM,MAAM,SAAS;AACrB,sBAAQ,SAAS,MAAA;AAAA,gBACf,KAAK;AACH,iCAAe,IAAI,KAAK,SAAS,QAAmB;AACpD,iCAAe,OAAO,GAAG;AACzB;AAAA,gBACF,KAAK,UAAU;AACb,wBAAM,OAAO,KAAK,WAAW,IAAI,GAAG;AACpC,wBAAM,OAAO,OACR,OAAO,OAAO,CAAA,GAAI,MAAM,SAAS,OAAO,IACxC,SAAS;AACd,iCAAe,IAAI,KAAK,IAAI;AAC5B,iCAAe,OAAO,GAAG;AACzB;AAAA,gBACF;AAAA,gBACA,KAAK;AACH,iCAAe,OAAO,GAAG;AACzB,iCAAe,IAAI,GAAG;AACtB;AAAA,cAAA;AAAA,YAEN;AAAA,UACF;AAKA,qBAAW,CAAC,KAAK,KAAK,KAAK,gBAAgB;AACzC,gBAAI,eAAe,IAAI,GAAG,EAAG;AAC7B,gBAAI,4BAA4B,IAAI,GAAG,GAAG;AACxC,kBAAI,cAAc;AAClB,uBAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,sBAAM,MAAM,OAAO,CAAC;AACpB,oBAAI,IAAI,QAAQ,OAAO,IAAI,SAAS,UAAU;AAC5C,sBAAI,QAAQ;AACZ,gCAAc;AACd;AAAA,gBACF;AAAA,cACF;AACA,kBAAI,CAAC,aAAa;AAChB,uBAAO,KAAK,EAAE,MAAM,UAAU,KAAK,OAAO;AAAA,cAC5C;AAAA,YACF,OAAO;AACL,qBAAO,KAAK,EAAE,MAAM,UAAU,KAAK,OAAO;AAAA,YAC5C;AAAA,UACF;AAGA,cAAI,OAAO,SAAS,KAAK,eAAe,OAAO,GAAG;AAChD,kBAAM,WAAgD,CAAA;AACtD,uBAAW,OAAO,QAAQ;AACxB,kBAAI,IAAI,SAAS,YAAY,eAAe,IAAI,IAAI,GAAG,GAAG;AACxD;AAAA,cACF;AACA,uBAAS,KAAK,GAAG;AAAA,YACnB;AACA,mBAAO,SAAS;AAChB,mBAAO,KAAK,GAAG,QAAQ;AAAA,UACzB;AAGA,cAAI,CAAC,KAAK,WAAW;AACnB,iBAAK,UAAU,OAAO;AAAA,UACxB;AAAA,QACF;AAKA,aAAK,kBAAkB,MAAA;AACvB,aAAK,kBAAkB,MAAA;AAGvB,aAAK,+BAA+B;AACpC,mBAAW,eAAe,KAAK,aAAa,OAAA,GAAU;AACpD,cAAI,CAAC,CAAC,aAAa,QAAQ,EAAE,SAAS,YAAY,KAAK,GAAG;AACxD,uBAAW,YAAY,YAAY,WAAW;AAC5C,kBAAI,SAAS,eAAe,QAAQ,SAAS,YAAY;AACvD,wBAAQ,SAAS,MAAA;AAAA,kBACf,KAAK;AAAA,kBACL,KAAK;AACH,yBAAK,kBAAkB;AAAA,sBACrB,SAAS;AAAA,sBACT,SAAS;AAAA,oBAAA;AAEX,yBAAK,kBAAkB,OAAO,SAAS,GAAG;AAC1C;AAAA,kBACF,KAAK;AACH,yBAAK,kBAAkB,OAAO,SAAS,GAAG;AAC1C,yBAAK,kBAAkB,IAAI,SAAS,GAAG;AACvC;AAAA,gBAAA;AAAA,cAEN;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAGA,cAAM,6CAA6B,IAAA;AAEnC,mBAAW,eAAe,KAAK,aAAa,OAAA,GAAU;AACpD,cAAI,YAAY,UAAU,aAAa;AACrC,uBAAW,YAAY,YAAY,WAAW;AAC5C,kBAAI,SAAS,eAAe,QAAQ,YAAY,IAAI,SAAS,GAAG,GAAG;AACjE,uCAAuB,IAAI,SAAS,KAAK;AAAA,kBACvC,MAAM,SAAS;AAAA,kBACf,OAAO,SAAS;AAAA,gBAAA,CACjB;AAAA,cACH;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAGA,mBAAW,OAAO,aAAa;AAC7B,gBAAM,uBAAuB,oBAAoB,IAAI,GAAG;AACxD,gBAAM,kBAAkB,KAAK,IAAI,GAAG;AAGpC,gBAAM,cAAc,uBAAuB,IAAI,GAAG;AAClD,gBAAM,kBACJ,eACA,oBAAoB,UACpB,WAAW,YAAY,OAAO,eAAe;AAE/C,cAAI,CAAC,iBAAiB;AACpB,gBACE,yBAAyB,UACzB,oBAAoB,QACpB;AACA,qBAAO,KAAK;AAAA,gBACV,MAAM;AAAA,gBACN;AAAA,gBACA,OAAO;AAAA,cAAA,CACR;AAAA,YACH,WACE,yBAAyB,UACzB,oBAAoB,QACpB;AACA,qBAAO,KAAK;AAAA,gBACV,MAAM;AAAA,gBACN;AAAA,gBACA,OAAO;AAAA,cAAA,CACR;AAAA,YACH,WACE,yBAAyB,UACzB,oBAAoB,UACpB,CAAC,WAAW,sBAAsB,eAAe,GACjD;AACA,qBAAO,KAAK;AAAA,gBACV,MAAM;AAAA,gBACN;AAAA,gBACA,OAAO;AAAA,gBACP,eAAe;AAAA,cAAA,CAChB;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAGA,aAAK,QAAQ,KAAK,cAAA;AAGlB,YAAI,OAAO,SAAS,GAAG;AACrB,eAAK,cAAc,MAAM;AAAA,QAC3B;AAGA,aAAK,WAAW,QAAQ,IAAI;AAE5B,aAAK,4BAA4B;AAGjC,aAAK,oBAAoB,MAAA;AAGzB,gBAAQ,UAAU,KAAK,MAAM;AAC3B,eAAK,mBAAmB,MAAA;AAAA,QAC1B,CAAC;AAGD,YAAI,CAAC,KAAK,wBAAwB;AAChC,eAAK,yBAAyB;AAC9B,gBAAM,YAAY,CAAC,GAAG,KAAK,qBAAqB;AAChD,eAAK,wBAAwB,CAAA;AAC7B,oBAAU,QAAQ,CAAC,aAAa,SAAA,CAAU;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAqTA,SAAA,SAAS,CAAC,MAA8BA,YAA0B;AAChE,WAAK,yBAAyB,QAAQ;AACtC,YAAM,qBAAqB,qBAAA;AAG3B,UAAI,CAAC,sBAAsB,CAAC,KAAK,OAAO,UAAU;AAChD,cAAM,IAAI,0BAAA;AAAA,MACZ;AAEA,YAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAChD,YAAM,YAA6C,CAAA;AAGnD,YAAM,QAAQ,CAAC,SAAS;;AAEtB,cAAM,gBAAgB,KAAK,aAAa,MAAM,QAAQ;AAGtD,cAAM,MAAM,KAAK,eAAe,aAAa;AAC7C,YAAI,KAAK,IAAI,GAAG,GAAG;AACjB,gBAAM,IAAI,kBAAkB,GAAG;AAAA,QACjC;AACA,cAAM,YAAY,KAAK,kBAAkB,KAAK,IAAI;AAElD,cAAM,WAA+C;AAAA,UACnD,YAAY,OAAO,WAAA;AAAA,UACnB,UAAU,CAAA;AAAA,UACV,UAAU;AAAA;AAAA;AAAA;AAAA,UAIV,SAAS,OAAO;AAAA,YACd,OAAO,KAAK,IAAI,EAAE,IAAI,CAAC,MAAM;AAAA,cAC3B;AAAA,cACA,cAAc,CAA+B;AAAA,YAAA,CAC9C;AAAA,UAAA;AAAA,UAEH;AAAA,UACA;AAAA,UACA,UAAUA,WAAA,gBAAAA,QAAQ;AAAA,UAClB,gBAAc,gBAAK,OAAO,MAAK,oBAAjB,gCAAwC,CAAA;AAAA,UACtD,aAAYA,WAAA,gBAAAA,QAAQ,eAAc;AAAA,UAClC,MAAM;AAAA,UACN,+BAAe,KAAA;AAAA,UACf,+BAAe,KAAA;AAAA,UACf,YAAY;AAAA,QAAA;AAGd,kBAAU,KAAK,QAAQ;AAAA,MACzB,CAAC;AAGD,UAAI,oBAAoB;AACtB,2BAAmB,eAAe,SAAS;AAE3C,aAAK,aAAa,IAAI,mBAAmB,IAAI,kBAAkB;AAC/D,aAAK,2BAA2B,kBAAkB;AAClD,aAAK,yBAAyB,IAAI;AAElC,eAAO;AAAA,MACT,OAAO;AAEL,cAAM,sBAAsB,kBAA2B;AAAA,UACrD,YAAY,OAAO,WAAW;AAE5B,mBAAO,MAAM,KAAK,OAAO,SAAU;AAAA,cACjC,aACE,OAAO;AAAA,cAIT,YAAY;AAAA,YAAA,CACb;AAAA,UACH;AAAA,QAAA,CACD;AAGD,4BAAoB,eAAe,SAAS;AAC5C,4BAAoB,OAAA;AAGpB,aAAK,aAAa,IAAI,oBAAoB,IAAI,mBAAmB;AACjE,aAAK,2BAA2B,mBAAmB;AACnD,aAAK,yBAAyB,IAAI;AAElC,eAAO;AAAA,MACT;AAAA,IACF;AAmRA,SAAA,SAAS,CACP,MACAA,YACyB;AACzB,WAAK,yBAAyB,QAAQ;AAEtC,YAAM,qBAAqB,qBAAA;AAG3B,UAAI,CAAC,sBAAsB,CAAC,KAAK,OAAO,UAAU;AAChD,cAAM,IAAI,0BAAA;AAAA,MACZ;AAEA,UAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,GAAG;AAC5C,cAAM,IAAI,0BAAA;AAAA,MACZ;AAEA,YAAM,YAAY,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AACpD,YAAM,YAA6D,CAAA;AAEnE,iBAAW,OAAO,WAAW;AAC3B,YAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,gBAAM,IAAI,uBAAuB,GAAG;AAAA,QACtC;AACA,cAAM,YAAY,KAAK,kBAAkB,KAAK,KAAK,IAAI,GAAG,CAAE;AAC5D,cAAM,WAAqD;AAAA,UACzD,YAAY,OAAO,WAAA;AAAA,UACnB,UAAU,KAAK,IAAI,GAAG;AAAA,UACtB,UAAU,KAAK,IAAI,GAAG;AAAA,UACtB,SAAS,KAAK,IAAI,GAAG;AAAA,UACrB;AAAA,UACA;AAAA,UACA,UAAUA,WAAA,gBAAAA,QAAQ;AAAA,UAClB,cAAe,KAAK,eAAe,IAAI,GAAG,KAAK,CAAA;AAAA,UAI/C,aAAYA,WAAA,gBAAAA,QAAQ,eAAc;AAAA,UAClC,MAAM;AAAA,UACN,+BAAe,KAAA;AAAA,UACf,+BAAe,KAAA;AAAA,UACf,YAAY;AAAA,QAAA;AAGd,kBAAU,KAAK,QAAQ;AAAA,MACzB;AAGA,UAAI,oBAAoB;AACtB,2BAAmB,eAAe,SAAS;AAE3C,aAAK,aAAa,IAAI,mBAAmB,IAAI,kBAAkB;AAC/D,aAAK,2BAA2B,kBAAkB;AAClD,aAAK,yBAAyB,IAAI;AAElC,eAAO;AAAA,MACT;AAGA,YAAM,sBAAsB,kBAA2B;AAAA,QACrD,YAAY;AAAA,QACZ,YAAY,OAAO,WAAW;AAE5B,iBAAO,KAAK,OAAO,SAAU;AAAA,YAC3B,aACE,OAAO;AAAA,YAIT,YAAY;AAAA,UAAA,CACb;AAAA,QACH;AAAA,MAAA,CACD;AAGD,0BAAoB,eAAe,SAAS;AAC5C,0BAAoB,OAAA;AAEpB,WAAK,aAAa,IAAI,oBAAoB,IAAI,mBAAmB;AACjE,WAAK,2BAA2B,mBAAmB;AACnD,WAAK,yBAAyB,IAAI;AAElC,aAAO;AAAA,IACT;AA1xDE,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,8BAAA;AAAA,IACZ;AACA,QAAI,OAAO,IAAI;AACb,WAAK,KAAK,OAAO;AAAA,IACnB,OAAO;AACL,WAAK,KAAK,OAAO,WAAA;AAAA,IACnB;AAGA,QAAI,CAAC,OAAO,MAAM;AAChB,YAAM,IAAI,kCAAA;AAAA,IACZ;AAEA,SAAK,eAAe,IAAI;AAAA,MAAoC,CAAC,GAAG,MAC9D,EAAE,iBAAiB,CAAC;AAAA,IAAA;AAItB,SAAK,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,WAAW,OAAO,aAAa;AAAA,IAAA;AAIjC,QAAI,KAAK,OAAO,SAAS;AACvB,WAAK,aAAa,IAAI,UAAyB,KAAK,OAAO,OAAO;AAAA,IACpE,OAAO;AACL,WAAK,iCAAiB,IAAA;AAAA,IACxB;AAGA,QAAI,OAAO,cAAc,MAAM;AAC7B,WAAK,UAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA5KO,aAAa,UAA4B;AAE9C,QAAI,KAAK,cAAc;AACrB,eAAA;AACA;AAAA,IACF;AAEA,SAAK,sBAAsB,KAAK,QAAQ;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcO,UAAmB;AACxB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAkB;AAExB,QAAI,KAAK,YAAY,aAAa,KAAK,YAAY,iBAAiB;AAClE,WAAK,UAAU,OAAO;AAGtB,UAAI,CAAC,KAAK,cAAc;AACtB,aAAK,eAAe;AAGpB,YAAI,CAAC,KAAK,wBAAwB;AAChC,eAAK,yBAAyB;AAAA,QAChC;AAEA,cAAM,YAAY,CAAC,GAAG,KAAK,qBAAqB;AAChD,aAAK,wBAAwB,CAAA;AAC7B,kBAAU,QAAQ,CAAC,aAAa,SAAA,CAAU;AAAA,MAC5C;AAAA,IACF;AAIA,QAAI,KAAK,gBAAgB,OAAO,GAAG;AACjC,WAAK,oBAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAOA,IAAW,SAA2B;AACpC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,yBAAyB,WAAyB;AACxD,YAAQ,KAAK,SAAA;AAAA,MACX,KAAK;AACH,cAAM,IAAI,4BAA4B,WAAW,KAAK,EAAE;AAAA,MAC1D,KAAK;AAEH,aAAK,UAAA;AACL;AAAA,IAAA;AAAA,EAEN;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,yBACN,MACA,IACM;AACN,QAAI,SAAS,IAAI;AAEf;AAAA,IACF;AACA,UAAM,mBAGF;AAAA,MACF,MAAM,CAAC,WAAW,SAAS,YAAY;AAAA,MACvC,SAAS,CAAC,iBAAiB,SAAS,SAAS,YAAY;AAAA,MACzD,eAAe,CAAC,SAAS,SAAS,YAAY;AAAA,MAC9C,OAAO,CAAC,cAAc,OAAO;AAAA,MAC7B,OAAO,CAAC,cAAc,MAAM;AAAA,MAC5B,cAAc,CAAC,WAAW,OAAO;AAAA,IAAA;AAGnC,QAAI,CAAC,iBAAiB,IAAI,EAAE,SAAS,EAAE,GAAG;AACxC,YAAM,IAAI,uCAAuC,MAAM,IAAI,KAAK,EAAE;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,WAAmC;AACnD,SAAK,yBAAyB,KAAK,SAAS,SAAS;AACrD,SAAK,UAAU;AAGf,QAAI,cAAc,WAAW,CAAC,KAAK,mBAAmB;AAEpD,WAAK,kBAAA,EAAoB,MAAM,CAAC,UAAU;AACxC,gBAAQ,KAAK,8BAA8B,KAAK;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAmDO,qBAA2B;AAChC,SAAK,UAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAkB;AACxB,QAAI,KAAK,YAAY,UAAU,KAAK,YAAY,cAAc;AAC5D;AAAA,IACF;AAEA,SAAK,UAAU,SAAS;AAExB,QAAI;AACF,YAAM,YAAY,KAAK,OAAO,KAAK,KAAK;AAAA,QACtC,YAAY;AAAA,QACZ,OAAO,MAAM;AACX,eAAK,0BAA0B,KAAK;AAAA,YAClC,WAAW;AAAA,YACX,YAAY,CAAA;AAAA,YACZ,iCAAiB,IAAA;AAAA,UAAI,CACtB;AAAA,QACH;AAAA,QACA,OAAO,CAAC,sBAA2D;AACjE,gBAAM,qBACJ,KAAK,0BACH,KAAK,0BAA0B,SAAS,CAC1C;AACF,cAAI,CAAC,oBAAoB;AACvB,kBAAM,IAAI,mCAAA;AAAA,UACZ;AACA,cAAI,mBAAmB,WAAW;AAChC,kBAAM,IAAI,0CAAA;AAAA,UACZ;AACA,gBAAM,MAAM,KAAK,eAAe,kBAAkB,KAAK;AAGvD,cAAI,kBAAkB,SAAS,UAAU;AACvC,kBAAM,8BAA8B,KAAK,WAAW,IAAI,GAAG;AAC3D,kBAAM,yBACJ,mBAAmB,YAAY,IAAI,GAAG;AACxC,kBAAM,wBAAwB,mBAAmB,aAAa;AAE9D,gBACE,+BACA,CAAC,0BACD,CAAC,uBACD;AACA,oBAAM,IAAI,sBAAsB,KAAK,KAAK,EAAE;AAAA,YAC9C;AAAA,UACF;AAEA,gBAAM,UAAkC;AAAA,YACtC,GAAG;AAAA,YACH;AAAA,UAAA;AAEF,6BAAmB,WAAW,KAAK,OAAO;AAE1C,cAAI,kBAAkB,SAAS,UAAU;AACvC,+BAAmB,YAAY,IAAI,GAAG;AAAA,UACxC;AAAA,QACF;AAAA,QACA,QAAQ,MAAM;AACZ,gBAAM,qBACJ,KAAK,0BACH,KAAK,0BAA0B,SAAS,CAC1C;AACF,cAAI,CAAC,oBAAoB;AACvB,kBAAM,IAAI,oCAAA;AAAA,UACZ;AACA,cAAI,mBAAmB,WAAW;AAChC,kBAAM,IAAI,qCAAA;AAAA,UACZ;AAEA,6BAAmB,YAAY;AAI/B,cAAI,KAAK,YAAY,WAAW;AAC9B,iBAAK,UAAU,eAAe;AAAA,UAChC;AAEA,eAAK,0BAAA;AAAA,QACP;AAAA,QACA,WAAW,MAAM;AACf,eAAK,UAAA;AAAA,QACP;AAAA,QACA,UAAU,MAAM;AACd,gBAAM,qBACJ,KAAK,0BACH,KAAK,0BAA0B,SAAS,CAC1C;AACF,cAAI,CAAC,oBAAoB;AACvB,kBAAM,IAAI,mCAAA;AAAA,UACZ;AACA,cAAI,mBAAmB,WAAW;AAChC,kBAAM,IAAI,0CAAA;AAAA,UACZ;AAGA,6BAAmB,aAAa,CAAA;AAChC,6BAAmB,YAAY,MAAA;AAO/B,6BAAmB,WAAW;AAAA,QAChC;AAAA,MAAA,CACD;AAGD,WAAK,gBAAgB,OAAO,cAAc,aAAa,YAAY;AAAA,IACrE,SAAS,OAAO;AACd,WAAK,UAAU,OAAO;AACtB,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,UAAyB;AAC9B,QAAI,KAAK,gBAAgB;AACvB,aAAO,KAAK;AAAA,IACd;AAEA,SAAK,iBAAiB,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3D,UAAI,KAAK,YAAY,SAAS;AAC5B,gBAAA;AACA;AAAA,MACF;AAEA,UAAI,KAAK,YAAY,SAAS;AAC5B,eAAO,IAAI,+BAA+B;AAC1C;AAAA,MACF;AAGA,WAAK,aAAa,MAAM;AACtB,gBAAA;AAAA,MACF,CAAC;AAGD,UAAI,KAAK,YAAY,UAAU,KAAK,YAAY,cAAc;AAC5D,YAAI;AACF,eAAK,UAAA;AAAA,QACP,SAAS,OAAO;AACd,iBAAO,KAAK;AACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,UAAyB;AAEpC,QAAI,KAAK,aAAa;AACpB,mBAAa,KAAK,WAAW;AAC7B,WAAK,cAAc;AAAA,IACrB;AAGA,QAAI;AACF,UAAI,KAAK,eAAe;AACtB,aAAK,cAAA;AACL,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF,SAAS,OAAO;AAEd,qBAAe,MAAM;AACnB,YAAI,iBAAiB,OAAO;AAE1B,gBAAM,eAAe,IAAI,iBAAiB,KAAK,IAAI,KAAK;AACxD,uBAAa,QAAQ;AACrB,uBAAa,QAAQ,MAAM;AAC3B,gBAAM;AAAA,QACR,OAAO;AACL,gBAAM,IAAI,iBAAiB,KAAK,IAAI,KAAuB;AAAA,QAC7D;AAAA,MACF,CAAC;AAAA,IACH;AAGA,SAAK,WAAW,MAAA;AAChB,SAAK,eAAe,MAAA;AACpB,SAAK,kBAAkB,MAAA;AACvB,SAAK,kBAAkB,MAAA;AACvB,SAAK,QAAQ;AACb,SAAK,4BAA4B,CAAA;AACjC,SAAK,WAAW,MAAA;AAChB,SAAK,yBAAyB;AAC9B,SAAK,eAAe;AACpB,SAAK,wBAAwB,CAAA;AAC7B,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,CAAA;AACrB,SAAK,oBAAoB;AAGzB,SAAK,UAAU,YAAY;AAE3B,WAAO,QAAQ,QAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAqB;AAC3B,QAAI,KAAK,aAAa;AACpB,mBAAa,KAAK,WAAW;AAAA,IAC/B;AAEA,UAAM,SAAS,KAAK,OAAO,UAAU;AAGrC,QAAI,WAAW,GAAG;AAChB;AAAA,IACF;AAEA,SAAK,cAAc,WAAW,MAAM;AAClC,UAAI,KAAK,2BAA2B,GAAG;AACrC,aAAK,QAAA;AAAA,MACP;AAAA,IACF,GAAG,MAAM;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAsB;AAC5B,QAAI,KAAK,aAAa;AACpB,mBAAa,KAAK,WAAW;AAC7B,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,SAAK;AACL,SAAK,cAAA;AAGL,QAAI,KAAK,YAAY,gBAAgB,KAAK,YAAY,QAAQ;AAC5D,WAAK,UAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAC/B,SAAK;AAEL,QAAI,KAAK,2BAA2B,GAAG;AACrC,WAAK,aAAA;AAAA,IACP,WAAW,KAAK,yBAAyB,GAAG;AAC1C,YAAM,IAAI,+BAAA;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,yBACN,wBAAiC,OAC3B;AAEN,QAAI,KAAK,8BAA8B;AACrC;AAAA,IACF;AAEA,UAAM,gBAAgB,IAAI,IAAI,KAAK,iBAAiB;AACpD,UAAM,kBAAkB,IAAI,IAAI,KAAK,iBAAiB;AAGtD,SAAK,kBAAkB,MAAA;AACvB,SAAK,kBAAkB,MAAA;AAEvB,UAAM,qBAA8C,CAAA;AAEpD,eAAW,eAAe,KAAK,aAAa,OAAA,GAAU;AACpD,UAAI,CAAC,CAAC,aAAa,QAAQ,EAAE,SAAS,YAAY,KAAK,GAAG;AACxD,2BAAmB,KAAK,WAAW;AAAA,MACrC;AAAA,IACF;AAGA,eAAW,eAAe,oBAAoB;AAC5C,iBAAW,YAAY,YAAY,WAAW;AAC5C,YAAI,SAAS,eAAe,QAAQ,SAAS,YAAY;AACvD,kBAAQ,SAAS,MAAA;AAAA,YACf,KAAK;AAAA,YACL,KAAK;AACH,mBAAK,kBAAkB;AAAA,gBACrB,SAAS;AAAA,gBACT,SAAS;AAAA,cAAA;AAEX,mBAAK,kBAAkB,OAAO,SAAS,GAAG;AAC1C;AAAA,YACF,KAAK;AACH,mBAAK,kBAAkB,OAAO,SAAS,GAAG;AAC1C,mBAAK,kBAAkB,IAAI,SAAS,GAAG;AACvC;AAAA,UAAA;AAAA,QAEN;AAAA,MACF;AAAA,IACF;AAGA,SAAK,QAAQ,KAAK,cAAA;AAGlB,UAAM,SAA8C,CAAA;AACpD,SAAK,yBAAyB,eAAe,iBAAiB,MAAM;AAKpE,UAAM,6BAA6B,OAAO,OAAO,CAAC,UAAU;AAC1D,UAAI,CAAC,KAAK,mBAAmB,IAAI,MAAM,GAAG,GAAG;AAC3C,eAAO;AAAA,MACT;AAGA,UAAI,uBAAuB;AACzB,eAAO;AAAA,MACT;AAGA,aAAO;AAAA,IACT,CAAC;AAKD,QAAI,KAAK,0BAA0B,SAAS,KAAK,CAAC,uBAAuB;AACvE,YAAM,sCAAsB,IAAA;AAG5B,iBAAW,eAAe,KAAK,2BAA2B;AACxD,mBAAW,aAAa,YAAY,YAAY;AAC9C,0BAAgB,IAAI,UAAU,GAAW;AAAA,QAC3C;AAAA,MACF;AAKA,YAAM,iBAAiB,2BAA2B,OAAO,CAAC,UAAU;AAClE,YAAI,MAAM,SAAS,YAAY,gBAAgB,IAAI,MAAM,GAAG,GAAG;AAG7D,gBAAM,8BAA8B,mBAAmB;AAAA,YAAK,CAAC,OAC3D,GAAG,UAAU;AAAA,cACX,CAAC,MAAM,EAAE,eAAe,QAAQ,EAAE,QAAQ,MAAM;AAAA,YAAA;AAAA,UAClD;AAGF,cAAI,CAAC,6BAA6B;AAChC,mBAAO;AAAA,UACT;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AAGD,UAAI,eAAe,SAAS,GAAG;AAC7B,aAAK,cAAc,cAAc;AAAA,MACnC;AACA,WAAK,WAAW,gBAAgB,qBAAqB;AAAA,IACvD,OAAO;AAEL,UAAI,2BAA2B,SAAS,GAAG;AACzC,aAAK,cAAc,0BAA0B;AAAA,MAC/C;AAEA,WAAK,WAAW,4BAA4B,qBAAqB;AAAA,IACnE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAwB;AAC9B,UAAM,aAAa,KAAK,WAAW;AACnC,UAAM,oBAAoB,MAAM,KAAK,KAAK,iBAAiB,EAAE;AAAA,MAC3D,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,KAAK,CAAC,KAAK,kBAAkB,IAAI,GAAG;AAAA,IAAA,EACpE;AACF,UAAM,qBAAqB,MAAM,KAAK,KAAK,kBAAkB,KAAA,CAAM,EAAE;AAAA,MACnE,CAAC,QAAQ,CAAC,KAAK,WAAW,IAAI,GAAG;AAAA,IAAA,EACjC;AAEF,WAAO,aAAa,oBAAoB;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKQ,yBACN,iBACA,iBACA,QACM;AACN,UAAM,8BAAc,IAAI;AAAA,MACtB,GAAG,gBAAgB,KAAA;AAAA,MACnB,GAAG,KAAK,kBAAkB,KAAA;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG,KAAK;AAAA,IAAA,CACT;AAED,eAAW,OAAO,SAAS;AACzB,YAAM,eAAe,KAAK,IAAI,GAAG;AACjC,YAAM,gBAAgB,KAAK;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAGF,UAAI,kBAAkB,UAAa,iBAAiB,QAAW;AAC7D,eAAO,KAAK,EAAE,MAAM,UAAU,KAAK,OAAO,eAAe;AAAA,MAC3D,WAAW,kBAAkB,UAAa,iBAAiB,QAAW;AACpE,eAAO,KAAK,EAAE,MAAM,UAAU,KAAK,OAAO,cAAc;AAAA,MAC1D,WACE,kBAAkB,UAClB,iBAAiB,UACjB,kBAAkB,cAClB;AACA,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN;AAAA,UACA,OAAO;AAAA,UACP;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBACN,KACA,iBACA,iBACqB;AACrB,QAAI,gBAAgB,IAAI,GAAG,GAAG;AAC5B,aAAO;AAAA,IACT;AACA,QAAI,gBAAgB,IAAI,GAAG,GAAG;AAC5B,aAAO,gBAAgB,IAAI,GAAG;AAAA,IAChC;AACA,WAAO,KAAK,WAAW,IAAI,GAAG;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAA4B;AAElC,eAAW,YAAY,KAAK,iBAAiB;AAC3C,eAAS,CAAA,CAAE;AAAA,IACb;AAEA,eAAW,CAAC,MAAM,YAAY,KAAK,KAAK,oBAAoB;AAC1D,iBAAW,YAAY,cAAc;AACnC,iBAAS,CAAA,CAAE;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,WACN,SACA,YAAY,OACN;AAEN,QAAI,KAAK,qBAAqB,CAAC,WAAW;AAExC,WAAK,cAAc,KAAK,GAAG,OAAO;AAClC;AAAA,IACF;AAGA,QAAI,eAAe;AAGnB,QAAI,KAAK,cAAc,SAAS,KAAK,WAAW;AAC9C,qBAAe,CAAC,GAAG,KAAK,eAAe,GAAG,OAAO;AACjD,WAAK,gBAAgB,CAAA;AACrB,WAAK,oBAAoB;AAAA,IAC3B;AAEA,QAAI,aAAa,WAAW,EAAG;AAG/B,eAAW,YAAY,KAAK,iBAAiB;AAC3C,eAAS,YAAY;AAAA,IACvB;AAGA,QAAI,KAAK,mBAAmB,OAAO,GAAG;AAEpC,YAAM,mCAAmB,IAAA;AACzB,iBAAW,UAAU,cAAc;AACjC,YAAI,KAAK,mBAAmB,IAAI,OAAO,GAAG,GAAG;AAC3C,cAAI,CAAC,aAAa,IAAI,OAAO,GAAG,GAAG;AACjC,yBAAa,IAAI,OAAO,KAAK,CAAA,CAAE;AAAA,UACjC;AACA,uBAAa,IAAI,OAAO,GAAG,EAAG,KAAK,MAAM;AAAA,QAC3C;AAAA,MACF;AAGA,iBAAW,CAAC,KAAK,UAAU,KAAK,cAAc;AAC5C,cAAM,eAAe,KAAK,mBAAmB,IAAI,GAAG;AACpD,mBAAW,YAAY,cAAc;AACnC,mBAAS,UAAU;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,IAAI,KAAgC;AAEzC,QAAI,KAAK,kBAAkB,IAAI,GAAG,GAAG;AACnC,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,kBAAkB,IAAI,GAAG,GAAG;AACnC,aAAO,KAAK,kBAAkB,IAAI,GAAG;AAAA,IACvC;AAGA,WAAO,KAAK,WAAW,IAAI,GAAG;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKO,IAAI,KAAoB;AAE7B,QAAI,KAAK,kBAAkB,IAAI,GAAG,GAAG;AACnC,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,kBAAkB,IAAI,GAAG,GAAG;AACnC,aAAO;AAAA,IACT;AAGA,WAAO,KAAK,WAAW,IAAI,GAAG;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,OAAe;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,CAAQ,OAA+B;AAErC,eAAW,OAAO,KAAK,WAAW,KAAA,GAAQ;AACxC,UAAI,CAAC,KAAK,kBAAkB,IAAI,GAAG,GAAG;AACpC,cAAM;AAAA,MACR;AAAA,IACF;AAEA,eAAW,OAAO,KAAK,kBAAkB,KAAA,GAAQ;AAC/C,UAAI,CAAC,KAAK,WAAW,IAAI,GAAG,KAAK,CAAC,KAAK,kBAAkB,IAAI,GAAG,GAAG;AAGjE,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,CAAQ,SAAoC;AAC1C,eAAW,OAAO,KAAK,QAAQ;AAC7B,YAAM,QAAQ,KAAK,IAAI,GAAG;AAC1B,UAAI,UAAU,QAAW;AACvB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,CAAQ,UAA6C;AACnD,eAAW,OAAO,KAAK,QAAQ;AAC7B,YAAM,QAAQ,KAAK,IAAI,GAAG;AAC1B,UAAI,UAAU,QAAW;AACvB,cAAM,CAAC,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,EAAS,OAAO,QAAQ,IAAuC;AAC7D,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,YAAM,CAAC,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,QACL,YACM;AACN,QAAI,QAAQ;AACZ,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,iBAAW,OAAO,KAAK,OAAO;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,IACL,YACU;AACV,UAAM,SAAmB,CAAA;AACzB,QAAI,QAAQ;AACZ,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,aAAO,KAAK,WAAW,OAAO,KAAK,OAAO,CAAC;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAkXQ,2BAA2B,aAAqC;AAEtE,QAAI,YAAY,UAAU,aAAa;AACrC,WAAK,aAAa,OAAO,YAAY,EAAE;AACvC;AAAA,IACF;AAGA,gBAAY,YAAY,QACrB,KAAK,MAAM;AAEV,WAAK,aAAa,OAAO,YAAY,EAAE;AAAA,IACzC,CAAC,EACA,MAAM,MAAM;AAAA,IAIb,CAAC;AAAA,EACL;AAAA,EAEQ,qBAAqB,QAA0C;AAErE,QAAI,UAAU,eAAgB,QAAe;AAC3C,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,mBAAA;AAAA,EACZ;AAAA,EAEO,eAAe,MAAqB;AACzC,WAAO,KAAK,OAAO,OAAO,IAAI;AAAA,EAChC;AAAA,EAEO,kBAAkB,KAAU,MAAmB;AACpD,QAAI,OAAO,QAAQ,aAAa;AAC9B,YAAM,IAAI,kBAAkB,IAAI;AAAA,IAClC;AAEA,WAAO,QAAQ,KAAK,EAAE,IAAI,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgCO,YACL,eACA,SAAkC,IAChB;AAClB,SAAK,yBAAyB,aAAa;AAE3C,UAAM,UAAU,EAAE,KAAK;AACvB,UAAM,oBAAoB,wBAAA;AAC1B,UAAM,kBAAkB,cAAc,iBAAiB;AACvD,UAAM,aAAa,aAAa,eAAe;AAG/C,UAAM,WAAW,OAAO,aAAc;AAGtC,UAAM,YAAY,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,OAAO;AAAA,MACP,KAAK,QAAA;AAAA,IAAQ;AAGf,SAAK,YAAY,IAAI,SAAS,SAAS;AAGvC,QAAK,aAAyB,YAAY;AACxC,UAAI;AACF,cAAM,gBAAgB,UAAU,YAAA;AAChC,aAAK,gBAAgB,IAAI,SAAS,aAAa;AAAA,MACjD,SAAS,OAAO;AACd,gBAAQ,KAAK,iCAAiC,KAAK;AAAA,MACrD;AAAA,IACF,WAAW,OAAO,aAAa,cAAc,SAAS,WAAW;AAE/D,UAAI;AACF,cAAM,gBAAgB,UAAU,YAAA;AAChC,aAAK,gBAAgB,IAAI,SAAS,aAAa;AAAA,MACjD,QAAQ;AAEN,aAAK,mBAAmB,SAAS,SAAS,EAAE,MAAM,CAAC,UAAU;AAC3D,kBAAQ,KAAK,mCAAmC,KAAK;AAAA,QACvD,CAAC;AAAA,MACH;AAAA,IACF,WAAW,KAAK,mBAAmB;AAEjC,WAAK,mBAAmB,SAAS,SAAS,EAAE,MAAM,CAAC,UAAU;AAC3D,gBAAQ,KAAK,mCAAmC,KAAK;AAAA,MACvD,CAAC;AAAA,IACH;AAEA,WAAO,IAAI,WAAW,SAAS,SAAS;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,oBAAmC;AAC/C,QAAI,KAAK,kBAAmB;AAE5B,UAAM,qBAAqB,MAAM,KAAK,KAAK,YAAY,QAAA,CAAS,EAAE;AAAA,MAChE,OAAO,CAAC,SAAS,SAAS,MAAM;AAC9B,cAAM,gBAAgB,MAAM,UAAU,QAAA;AAGtC,sBAAc,MAAM,KAAK,SAAS;AAElC,aAAK,gBAAgB,IAAI,SAAS,aAAa;AAC/C,eAAO,EAAE,SAAS,cAAA;AAAA,MACpB;AAAA,IAAA;AAGF,UAAM,QAAQ,IAAI,kBAAkB;AACpC,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBACZ,SACA,WAC0B;AAC1B,UAAM,gBAAgB,MAAM,UAAU,QAAA;AACtC,kBAAc,MAAM,KAAK,SAAS;AAClC,SAAK,gBAAgB,IAAI,SAAS,aAAa;AAC/C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAwC;AAC1C,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,SAAoD;AACxE,eAAW,SAAS,KAAK,gBAAgB,OAAA,GAAU;AACjD,iBAAW,UAAU,SAAS;AAC5B,gBAAQ,OAAO,MAAA;AAAA,UACb,KAAK;AACH,kBAAM,IAAI,OAAO,KAAK,OAAO,KAAK;AAClC;AAAA,UACF,KAAK;AACH,gBAAI,OAAO,eAAe;AACxB,oBAAM,OAAO,OAAO,KAAK,OAAO,eAAe,OAAO,KAAK;AAAA,YAC7D,OAAO;AACL,oBAAM,IAAI,OAAO,KAAK,OAAO,KAAK;AAAA,YACpC;AACA;AAAA,UACF,KAAK;AACH,kBAAM,OAAO,OAAO,KAAK,OAAO,KAAK;AACrC;AAAA,QAAA;AAAA,MAEN;AAAA,IACF;AAAA,EACF;AAAA,EAEO,aACL,MACA,MACA,KACiB;AACjB,QAAI,CAAC,KAAK,OAAO,OAAQ,QAAO;AAEhC,UAAM,iBAAiB,KAAK,qBAAqB,KAAK,OAAO,MAAM;AAGnE,QAAI,SAAS,YAAY,KAAK;AAE5B,YAAM,eAAe,KAAK,IAAI,GAAG;AAEjC,UACE,gBACA,QACA,OAAO,SAAS,YAChB,OAAO,iBAAiB,UACxB;AAEA,cAAM,aAAa,OAAO,OAAO,CAAA,GAAI,cAAc,IAAI;AAGvD,cAAMC,UAAS,eAAe,WAAW,EAAE,SAAS,UAAU;AAG9D,YAAIA,mBAAkB,SAAS;AAC7B,gBAAM,IAAI,6BAAA;AAAA,QACZ;AAGA,YAAI,YAAYA,WAAUA,QAAO,QAAQ;AACvC,gBAAM,cAAcA,QAAO,OAAO,IAAI,CAAC,UAAA;;AAAW;AAAA,cAChD,SAAS,MAAM;AAAA,cACf,OAAM,WAAM,SAAN,mBAAY,IAAI,CAAC,MAAM,OAAO,CAAC;AAAA,YAAC;AAAA,WACtC;AACF,gBAAM,IAAI,sBAAsB,MAAM,WAAW;AAAA,QACnD;AAGA,cAAM,sBAAsBA,QAAO;AACnC,cAAM,eAAe,OAAO,KAAK,IAAI;AACrC,cAAM,mBAAmB,OAAO;AAAA,UAC9B,aAAa,IAAI,CAAC,MAAM,CAAC,GAAG,oBAAoB,CAAkB,CAAC,CAAC;AAAA,QAAA;AAGtE,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,SAAS,eAAe,WAAW,EAAE,SAAS,IAAI;AAGxD,QAAI,kBAAkB,SAAS;AAC7B,YAAM,IAAI,6BAAA;AAAA,IACZ;AAGA,QAAI,YAAY,UAAU,OAAO,QAAQ;AACvC,YAAM,cAAc,OAAO,OAAO,IAAI,CAAC,UAAA;;AAAW;AAAA,UAChD,SAAS,MAAM;AAAA,UACf,OAAM,WAAM,SAAN,mBAAY,IAAI,CAAC,MAAM,OAAO,CAAC;AAAA,QAAC;AAAA,OACtC;AACF,YAAM,IAAI,sBAAsB,MAAM,WAAW;AAAA,IACnD;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA,EAiMA,OACE,MACA,kBAIA,eAGA;AACA,QAAI,OAAO,SAAS,aAAa;AAC/B,YAAM,IAAI,2BAAA;AAAA,IACZ;AAEA,SAAK,yBAAyB,QAAQ;AAEtC,UAAM,qBAAqB,qBAAA;AAG3B,QAAI,CAAC,sBAAsB,CAAC,KAAK,OAAO,UAAU;AAChD,YAAM,IAAI,0BAAA;AAAA,IACZ;AAEA,UAAM,UAAU,MAAM,QAAQ,IAAI;AAClC,UAAM,YAAY,UAAU,OAAO,CAAC,IAAI;AAExC,QAAI,WAAW,UAAU,WAAW,GAAG;AACrC,YAAM,IAAI,0BAAA;AAAA,IACZ;AAEA,UAAM,WACJ,OAAO,qBAAqB,aAAa,mBAAmB;AAC9D,UAAM,SACJ,OAAO,qBAAqB,aAAa,CAAA,IAAK;AAGhD,UAAM,iBAAiB,UAAU,IAAI,CAAC,QAAQ;AAC5C,YAAM,OAAO,KAAK,IAAI,GAAG;AACzB,UAAI,CAAC,MAAM;AACT,cAAM,IAAI,uBAAuB,GAAG;AAAA,MACtC;AAEA,aAAO;AAAA,IACT,CAAC;AAED,QAAI;AACJ,QAAI,SAAS;AAEX,qBAAe;AAAA,QACb;AAAA,QACA;AAAA,MAAA;AAAA,IAEJ,OAAO;AACL,YAAM,SAAS;AAAA,QACb,eAAe,CAAC;AAAA,QAChB;AAAA,MAAA;AAEF,qBAAe,CAAC,MAAM;AAAA,IACxB;AAGA,UAAM,YAA6D,UAChE,IAAI,CAAC,KAAK,UAAU;AACnB,YAAM,cAAc,aAAa,KAAK;AAGtC,UAAI,CAAC,eAAe,OAAO,KAAK,WAAW,EAAE,WAAW,GAAG;AACzD,eAAO;AAAA,MACT;AAEA,YAAM,eAAe,eAAe,KAAK;AAEzC,YAAM,yBAAyB,KAAK;AAAA,QAClC;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAIF,YAAM,eAAe,OAAO;AAAA,QAC1B,CAAA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAIF,YAAM,iBAAiB,KAAK,eAAe,YAAY;AACvD,YAAM,iBAAiB,KAAK,eAAe,YAAY;AAEvD,UAAI,mBAAmB,gBAAgB;AACrC,cAAM,IAAI,yBAAyB,gBAAgB,cAAc;AAAA,MACnE;AAEA,YAAM,YAAY,KAAK,kBAAkB,gBAAgB,YAAY;AAErE,aAAO;AAAA,QACL,YAAY,OAAO,WAAA;AAAA,QACnB,UAAU;AAAA,QACV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,QAKV,SAAS,OAAO;AAAA,UACd,OAAO,KAAK,WAAW,EAAE,IAAI,CAAC,MAAM;AAAA,YAClC;AAAA,YACA,aAAa,CAA8B;AAAA,UAAA,CAC5C;AAAA,QAAA;AAAA,QAEH;AAAA,QACA;AAAA,QACA,UAAU,OAAO;AAAA,QACjB,cAAe,KAAK,eAAe,IAAI,GAAG,KAAK,CAAA;AAAA,QAI/C,YAAY,OAAO,cAAc;AAAA,QACjC,MAAM;AAAA,QACN,+BAAe,KAAA;AAAA,QACf,+BAAe,KAAA;AAAA,QACf,YAAY;AAAA,MAAA;AAAA,IAEhB,CAAC,EACA,OAAO,OAAO;AAGjB,QAAI,UAAU,WAAW,GAAG;AAC1B,YAAM,mBAAmB,kBAAkB;AAAA,QACzC,YAAY,YAAY;AAAA,QAAC;AAAA,MAAA,CAC1B;AACD,uBAAiB,OAAA;AAEjB,WAAK,2BAA2B,gBAAgB;AAChD,aAAO;AAAA,IACT;AAGA,QAAI,oBAAoB;AACtB,yBAAmB,eAAe,SAAS;AAE3C,WAAK,aAAa,IAAI,mBAAmB,IAAI,kBAAkB;AAC/D,WAAK,2BAA2B,kBAAkB;AAClD,WAAK,yBAAyB,IAAI;AAElC,aAAO;AAAA,IACT;AAKA,UAAM,sBAAsB,kBAA2B;AAAA,MACrD,YAAY,OAAO,WAAW;AAE5B,eAAO,KAAK,OAAO,SAAU;AAAA,UAC3B,aACE,OAAO;AAAA,UAIT,YAAY;AAAA,QAAA,CACb;AAAA,MACH;AAAA,IAAA,CACD;AAGD,wBAAoB,eAAe,SAAS;AAC5C,wBAAoB,OAAA;AAIpB,SAAK,aAAa,IAAI,oBAAoB,IAAI,mBAAmB;AACjE,SAAK,2BAA2B,mBAAmB;AACnD,SAAK,yBAAyB,IAAI;AAElC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqIA,IAAI,QAAQ;AACV,UAAM,6BAAa,IAAA;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,WAAW;AACzC,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAA8C;AAE5C,QAAI,KAAK,OAAO,KAAK,KAAK,WAAW;AACnC,aAAO,QAAQ,QAAQ,KAAK,KAAK;AAAA,IACnC;AAGA,WAAO,IAAI,QAA4B,CAAC,YAAY;AAClD,WAAK,aAAa,MAAM;AACtB,gBAAQ,KAAK,KAAK;AAAA,MACpB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,UAAU;AACZ,WAAO,MAAM,KAAK,KAAK,OAAA,CAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAA4C;AAE1C,QAAI,KAAK,OAAO,KAAK,KAAK,WAAW;AACnC,aAAO,QAAQ,QAAQ,KAAK,OAAO;AAAA,IACrC;AAGA,WAAO,IAAI,QAAwB,CAAC,YAAY;AAC9C,WAAK,aAAa,MAAM;AACtB,gBAAQ,KAAK,OAAO;AAAA,MACtB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBO,sBACL,UAAiD,IAClB;AAC/B,WAAO,sBAAsB,MAAM,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyCO,iBACL,UACA,UAA4C,IAChC;AAEZ,SAAK,cAAA;AAGL,QAAI,QAAQ,iBAAiB;AAC3B,+BAAyB,QAAQ,iBAAiB,IAAI;AAAA,IACxD;AAGA,UAAM,mBACJ,QAAQ,SAAS,QAAQ,kBACrB,uBAAuB,UAAU,OAAO,IACxC;AAEN,QAAI,QAAQ,qBAAqB;AAE/B,YAAM,iBAAiB,KAAK,sBAAsB;AAAA,QAChD,OAAO,QAAQ;AAAA,QACf,iBAAiB,QAAQ;AAAA,MAAA,CAC1B;AACD,uBAAiB,cAAc;AAAA,IACjC;AAGA,SAAK,gBAAgB,IAAI,gBAAgB;AAEzC,WAAO,MAAM;AACX,WAAK,gBAAgB,OAAO,gBAAgB;AAC5C,WAAK,iBAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,oBACL,KACA,UACA,EAAE,sBAAsB,MAAA,IAA6C,IACzD;AAEZ,SAAK,cAAA;AAEL,QAAI,CAAC,KAAK,mBAAmB,IAAI,GAAG,GAAG;AACrC,WAAK,mBAAmB,IAAI,KAAK,oBAAI,KAAK;AAAA,IAC5C;AAEA,QAAI,qBAAqB;AAEvB,eAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN;AAAA,UACA,OAAO,KAAK,IAAI,GAAG;AAAA,QAAA;AAAA,MACrB,CACD;AAAA,IACH;AAEA,SAAK,mBAAmB,IAAI,GAAG,EAAG,IAAI,QAAQ;AAE9C,WAAO,MAAM;AACX,YAAM,YAAY,KAAK,mBAAmB,IAAI,GAAG;AACjD,UAAI,WAAW;AACb,kBAAU,OAAO,QAAQ;AACzB,YAAI,UAAU,SAAS,GAAG;AACxB,eAAK,mBAAmB,OAAO,GAAG;AAAA,QACpC;AAAA,MACF;AACA,WAAK,iBAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,6BAAmC;AACzC,QAAI,KAAK,0BAA0B,WAAW,EAAG;AAGjD,SAAK,oBAAoB,MAAA;AAGzB,UAAM,iCAAiB,IAAA;AACvB,eAAW,eAAe,KAAK,2BAA2B;AACxD,iBAAW,aAAa,YAAY,YAAY;AAC9C,mBAAW,IAAI,UAAU,GAAW;AAAA,MACtC;AAAA,IACF;AAGA,eAAW,OAAO,YAAY;AAC5B,WAAK,mBAAmB,IAAI,GAAG;AAAA,IACjC;AAIA,eAAW,OAAO,YAAY;AAC5B,YAAM,eAAe,KAAK,IAAI,GAAG;AACjC,UAAI,iBAAiB,QAAW;AAC9B,aAAK,oBAAoB,IAAI,KAAK,YAAY;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,2BAAiC;AAGtC,SAAK,oBAAoB,KAAK,0BAA0B,SAAS;AAGjE,SAAK,2BAAA;AAEL,SAAK,yBAAyB,KAAK;AAAA,EACrC;AACF;"}