@tanstack/db 0.0.25 → 0.0.27
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.
package/dist/cjs/collection.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const proxy = require("./proxy.cjs");
|
|
4
|
-
const transactions = require("./transactions.cjs");
|
|
5
4
|
const SortedMap = require("./SortedMap.cjs");
|
|
5
|
+
const transactions = require("./transactions.cjs");
|
|
6
6
|
const collectionsStore = /* @__PURE__ */ new Map();
|
|
7
7
|
function createCollection(options) {
|
|
8
8
|
const collection = new CollectionImpl(options);
|
|
@@ -928,12 +928,10 @@ class CollectionImpl {
|
|
|
928
928
|
return result;
|
|
929
929
|
}
|
|
930
930
|
ensureStandardSchema(schema) {
|
|
931
|
-
if (schema &&
|
|
931
|
+
if (schema && `~standard` in schema) {
|
|
932
932
|
return schema;
|
|
933
933
|
}
|
|
934
|
-
throw new Error(
|
|
935
|
-
`Schema must either implement the standard-schema interface or be a Zod schema`
|
|
936
|
-
);
|
|
934
|
+
throw new Error(`Schema must implement the standard-schema interface`);
|
|
937
935
|
}
|
|
938
936
|
getKeyFromItem(item) {
|
|
939
937
|
return this.config.getKey(item);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.cjs","sources":["../../src/collection.ts"],"sourcesContent":["import { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { createTransaction, getActiveTransaction } from \"./transactions\"\nimport { SortedMap } from \"./SortedMap\"\nimport type { Transaction } from \"./transactions\"\nimport type {\n ChangeListener,\n ChangeMessage,\n CollectionConfig,\n CollectionStatus,\n Fn,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n ResolveInsertInput,\n ResolveType,\n StandardSchema,\n Transaction as TransactionType,\n TransactionWithMutations,\n UtilsRecord,\n} from \"./types\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n// Store collections in memory\nexport const collectionsStore = new Map<string, CollectionImpl<any, any, any>>()\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\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 must provide either an explicit type or a schema, but not both.\n */\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\n/**\n * Custom error class for schema validation errors\n */\nexport class SchemaValidationError extends Error {\n type: `insert` | `update`\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>\n\n constructor(\n type: `insert` | `update`,\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>,\n message?: string\n ) {\n const defaultMessage = `${type === `insert` ? `Insert` : `Update`} validation failed: ${issues\n .map((issue) => `\\n- ${issue.message} - path: ${issue.path}`)\n .join(``)}`\n\n super(message || defaultMessage)\n this.name = `SchemaValidationError`\n this.type = type\n this.issues = issues\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 // 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\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 Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection is in error state. ` +\n `Try calling cleanup() and restarting the collection.`\n )\n case `cleaned-up`:\n throw new Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection has been cleaned up. ` +\n `The collection will automatically restart on next access.`\n )\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 Error(\n `Invalid collection status transition from \"${from}\" to \"${to}\" for collection \"${this.id}\"`\n )\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\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 Error(`Collection requires a config`)\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 Error(`Collection requires a sync config`)\n }\n\n this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n a.compareCreatedAt(b)\n )\n\n this.config = config\n\n // Store in global collections store\n collectionsStore.set(this.id, this)\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 })\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 Error(`No pending sync transaction to write to`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't still write to it.`\n )\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 if (\n this.syncedData.has(key) &&\n !pendingTransaction.operations.some(\n (op) => op.key === key && op.type === `delete`\n )\n ) {\n throw new Error(\n `Cannot insert document with key \"${key}\" from sync because it already exists in the collection \"${this.id}\"`\n )\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to commit`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't commit it again.`\n )\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 })\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 Error(`Collection is in error state`))\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 Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${error.message}`\n )\n wrappedError.cause = error\n wrappedError.stack = error.stack\n throw wrappedError\n } else {\n throw new Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${String(error)}`\n )\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 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.activeSubscribersCount = 0\n this.startGCTimer()\n } else if (this.activeSubscribersCount < 0) {\n throw new Error(\n `Active subscribers count is negative - this should never happen`\n )\n }\n }\n\n /**\n * Recompute optimistic state from active transactions\n */\n private recomputeOptimisticState(): 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 const completedTransactions: Array<Transaction<any>> = []\n\n for (const transaction of this.transactions.values()) {\n if (transaction.state === `completed`) {\n completedTransactions.push(transaction)\n } else 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 const filteredEventsBySyncStatus = events.filter(\n (event) => !this.recentlySyncedKeys.has(event.key)\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 if (this.pendingSyncedTransactions.length > 0) {\n const pendingSyncKeys = new Set<TKey>()\n const completedTransactionMutations = new Set<string>()\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 // Collect mutation IDs from completed transactions\n for (const tx of completedTransactions) {\n for (const mutation of tx.mutations) {\n if (mutation.collection === this) {\n completedTransactionMutations.add(mutation.mutationId)\n }\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 this.emitEvents(filteredEvents)\n } else {\n // Emit all events if no pending sync transactions\n this.emitEvents(filteredEventsBySyncStatus)\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 events either immediately or batch them for later emission\n */\n private emitEvents(\n changes: Array<ChangeMessage<T, TKey>>,\n endBatching = false\n ): void {\n if (this.shouldBatchEvents && !endBatching) {\n // Add events to the batch\n this.batchedEvents.push(...changes)\n return\n }\n\n // Either we're not batching, or we're ending the batching cycle\n let eventsToEmit = changes\n\n if (endBatching) {\n // End batching: combine any batched events with new events and clean up state\n if (this.batchedEvents.length > 0) {\n eventsToEmit = [...this.batchedEvents, ...changes]\n }\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 if (!hasPersistingTransaction) {\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 this.pendingSyncedTransactions) {\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 this.pendingSyncedTransactions) {\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 // Clear optimistic state since sync operations will now provide the authoritative data\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 this.deepEqual(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 !this.deepEqual(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 // End batching and emit all events (combines any batched events with sync events)\n this.emitEvents(events, true)\n\n this.pendingSyncedTransactions = []\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 private ensureStandardSchema(schema: unknown): StandardSchema<T> {\n // If the schema already implements the standard-schema interface, return it\n if (schema && typeof schema === `object` && `~standard` in schema) {\n return schema as StandardSchema<T>\n }\n\n throw new Error(\n `Schema must either implement the standard-schema interface or be a Zod schema`\n )\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 Error(\n `An object was created without a defined key: ${JSON.stringify(item)}`\n )\n }\n\n return `KEY::${this.id}/${key}`\n }\n\n private deepEqual(a: any, b: any): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n\n if (typeof a === `object`) {\n if (Array.isArray(a) !== Array.isArray(b)) return false\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n if (keysA.length !== keysB.length) return false\n\n const keysBSet = new Set(keysB)\n for (const key of keysA) {\n if (!keysBSet.has(key)) return false\n if (!this.deepEqual(a[key], b[key])) return false\n }\n return true\n }\n\n return false\n }\n\n private 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 TypeError(`Schema validation must be synchronous`)\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 TypeError(`Schema validation must be synchronous`)\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 Error(\n `Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`\n )\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 `Cannot insert document with ID \"${key}\" because it already exists in the collection`\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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<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<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: 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: TItem) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n keys: (TKey | unknown) | Array<TKey | unknown>,\n configOrCallback: ((draft: TItem | Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof keys === `undefined`) {\n throw new Error(`The first argument to update is missing`)\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 Error(\n `Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`\n )\n }\n\n const isArray = Array.isArray(keys)\n const keysArray = isArray ? keys : [keys]\n\n if (isArray && keysArray.length === 0) {\n throw new Error(`No keys were passed to update`)\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 Error(\n `The key \"${key}\" was passed to update but an object for this key was not found in the collection`\n )\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 Error(\n `Updating the key of an item is not allowed. Original key: \"${originalItemId}\", Attempted new key: \"${modifiedItemId}\". Please delete the old item and create a new one if a key change is necessary.`\n )\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 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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 Error(\n `Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`\n )\n }\n\n if (Array.isArray(keys) && keys.length === 0) {\n throw new Error(`No keys were passed to delete`)\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 Error(\n `Collection.delete was called with key '${key}' but there is no item in the collection with this key`\n )\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 * @returns An array of changes\n */\n public currentStateAsChanges(): Array<ChangeMessage<T>> {\n return Array.from(this.entries()).map(([key, value]) => ({\n type: `insert`,\n key,\n value,\n }))\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - Function called when items change\n * @param options.includeInitialState - If true, immediately calls callback with current data\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 public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void,\n { includeInitialState = false }: { includeInitialState?: boolean } = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n if (includeInitialState) {\n // First send the current state as changes\n callback(this.currentStateAsChanges())\n }\n\n // Add to batched listeners\n this.changeListeners.add(callback)\n\n return () => {\n this.changeListeners.delete(callback)\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()\n }\n}\n"],"names":["config","getActiveTransaction","createTransaction","SortedMap","result","withArrayChangeTracking","withChangeTracking"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collection.cjs","sources":["../../src/collection.ts"],"sourcesContent":["import { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { SortedMap } from \"./SortedMap\"\nimport { createTransaction, getActiveTransaction } from \"./transactions\"\nimport type { Transaction } from \"./transactions\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport type {\n ChangeListener,\n ChangeMessage,\n CollectionConfig,\n CollectionStatus,\n Fn,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n ResolveInsertInput,\n ResolveType,\n StandardSchema,\n Transaction as TransactionType,\n TransactionWithMutations,\n UtilsRecord,\n} from \"./types\"\n\n// Store collections in memory\nexport const collectionsStore = new Map<string, CollectionImpl<any, any, any>>()\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\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 must provide either an explicit type or a schema, but not both.\n */\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\n/**\n * Custom error class for schema validation errors\n */\nexport class SchemaValidationError extends Error {\n type: `insert` | `update`\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>\n\n constructor(\n type: `insert` | `update`,\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>,\n message?: string\n ) {\n const defaultMessage = `${type === `insert` ? `Insert` : `Update`} validation failed: ${issues\n .map((issue) => `\\n- ${issue.message} - path: ${issue.path}`)\n .join(``)}`\n\n super(message || defaultMessage)\n this.name = `SchemaValidationError`\n this.type = type\n this.issues = issues\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 // 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\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 Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection is in error state. ` +\n `Try calling cleanup() and restarting the collection.`\n )\n case `cleaned-up`:\n throw new Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection has been cleaned up. ` +\n `The collection will automatically restart on next access.`\n )\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 Error(\n `Invalid collection status transition from \"${from}\" to \"${to}\" for collection \"${this.id}\"`\n )\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\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 Error(`Collection requires a config`)\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 Error(`Collection requires a sync config`)\n }\n\n this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n a.compareCreatedAt(b)\n )\n\n this.config = config\n\n // Store in global collections store\n collectionsStore.set(this.id, this)\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 })\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 Error(`No pending sync transaction to write to`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't still write to it.`\n )\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 if (\n this.syncedData.has(key) &&\n !pendingTransaction.operations.some(\n (op) => op.key === key && op.type === `delete`\n )\n ) {\n throw new Error(\n `Cannot insert document with key \"${key}\" from sync because it already exists in the collection \"${this.id}\"`\n )\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to commit`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't commit it again.`\n )\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 })\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 Error(`Collection is in error state`))\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 Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${error.message}`\n )\n wrappedError.cause = error\n wrappedError.stack = error.stack\n throw wrappedError\n } else {\n throw new Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${String(error)}`\n )\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 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.activeSubscribersCount = 0\n this.startGCTimer()\n } else if (this.activeSubscribersCount < 0) {\n throw new Error(\n `Active subscribers count is negative - this should never happen`\n )\n }\n }\n\n /**\n * Recompute optimistic state from active transactions\n */\n private recomputeOptimisticState(): 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 const completedTransactions: Array<Transaction<any>> = []\n\n for (const transaction of this.transactions.values()) {\n if (transaction.state === `completed`) {\n completedTransactions.push(transaction)\n } else 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 const filteredEventsBySyncStatus = events.filter(\n (event) => !this.recentlySyncedKeys.has(event.key)\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 if (this.pendingSyncedTransactions.length > 0) {\n const pendingSyncKeys = new Set<TKey>()\n const completedTransactionMutations = new Set<string>()\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 // Collect mutation IDs from completed transactions\n for (const tx of completedTransactions) {\n for (const mutation of tx.mutations) {\n if (mutation.collection === this) {\n completedTransactionMutations.add(mutation.mutationId)\n }\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 this.emitEvents(filteredEvents)\n } else {\n // Emit all events if no pending sync transactions\n this.emitEvents(filteredEventsBySyncStatus)\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 events either immediately or batch them for later emission\n */\n private emitEvents(\n changes: Array<ChangeMessage<T, TKey>>,\n endBatching = false\n ): void {\n if (this.shouldBatchEvents && !endBatching) {\n // Add events to the batch\n this.batchedEvents.push(...changes)\n return\n }\n\n // Either we're not batching, or we're ending the batching cycle\n let eventsToEmit = changes\n\n if (endBatching) {\n // End batching: combine any batched events with new events and clean up state\n if (this.batchedEvents.length > 0) {\n eventsToEmit = [...this.batchedEvents, ...changes]\n }\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 if (!hasPersistingTransaction) {\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 this.pendingSyncedTransactions) {\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 this.pendingSyncedTransactions) {\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 // Clear optimistic state since sync operations will now provide the authoritative data\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 this.deepEqual(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 !this.deepEqual(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 // End batching and emit all events (combines any batched events with sync events)\n this.emitEvents(events, true)\n\n this.pendingSyncedTransactions = []\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 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 Error(`Schema must implement the standard-schema interface`)\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 Error(\n `An object was created without a defined key: ${JSON.stringify(item)}`\n )\n }\n\n return `KEY::${this.id}/${key}`\n }\n\n private deepEqual(a: any, b: any): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n\n if (typeof a === `object`) {\n if (Array.isArray(a) !== Array.isArray(b)) return false\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n if (keysA.length !== keysB.length) return false\n\n const keysBSet = new Set(keysB)\n for (const key of keysA) {\n if (!keysBSet.has(key)) return false\n if (!this.deepEqual(a[key], b[key])) return false\n }\n return true\n }\n\n return false\n }\n\n private 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 TypeError(`Schema validation must be synchronous`)\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 TypeError(`Schema validation must be synchronous`)\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 Error(\n `Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`\n )\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 `Cannot insert document with ID \"${key}\" because it already exists in the collection`\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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<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<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: 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: TItem) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n keys: (TKey | unknown) | Array<TKey | unknown>,\n configOrCallback: ((draft: TItem | Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof keys === `undefined`) {\n throw new Error(`The first argument to update is missing`)\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 Error(\n `Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`\n )\n }\n\n const isArray = Array.isArray(keys)\n const keysArray = isArray ? keys : [keys]\n\n if (isArray && keysArray.length === 0) {\n throw new Error(`No keys were passed to update`)\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 Error(\n `The key \"${key}\" was passed to update but an object for this key was not found in the collection`\n )\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 Error(\n `Updating the key of an item is not allowed. Original key: \"${originalItemId}\", Attempted new key: \"${modifiedItemId}\". Please delete the old item and create a new one if a key change is necessary.`\n )\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 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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 Error(\n `Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`\n )\n }\n\n if (Array.isArray(keys) && keys.length === 0) {\n throw new Error(`No keys were passed to delete`)\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 Error(\n `Collection.delete was called with key '${key}' but there is no item in the collection with this key`\n )\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 * @returns An array of changes\n */\n public currentStateAsChanges(): Array<ChangeMessage<T>> {\n return Array.from(this.entries()).map(([key, value]) => ({\n type: `insert`,\n key,\n value,\n }))\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - Function called when items change\n * @param options.includeInitialState - If true, immediately calls callback with current data\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 public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void,\n { includeInitialState = false }: { includeInitialState?: boolean } = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n if (includeInitialState) {\n // First send the current state as changes\n callback(this.currentStateAsChanges())\n }\n\n // Add to batched listeners\n this.changeListeners.add(callback)\n\n return () => {\n this.changeListeners.delete(callback)\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()\n }\n}\n"],"names":["config","getActiveTransaction","createTransaction","SortedMap","result","withArrayChangeTracking","withChangeTracking"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SortedMap } from './SortedMap.cjs';
|
|
2
2
|
import { Transaction } from './transactions.cjs';
|
|
3
|
-
import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, ResolveInsertInput, ResolveType, Transaction as TransactionType, UtilsRecord } from './types.cjs';
|
|
4
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
|
+
import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, ResolveInsertInput, ResolveType, Transaction as TransactionType, UtilsRecord } from './types.cjs';
|
|
5
5
|
export declare const collectionsStore: Map<string, CollectionImpl<any, any, any, StandardSchemaV1<unknown, unknown>, any>>;
|
|
6
6
|
interface PendingSyncedTransaction<T extends object = Record<string, unknown>> {
|
|
7
7
|
committed: boolean;
|
package/dist/esm/collection.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SortedMap } from './SortedMap.js';
|
|
2
2
|
import { Transaction } from './transactions.js';
|
|
3
|
-
import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, ResolveInsertInput, ResolveType, Transaction as TransactionType, UtilsRecord } from './types.js';
|
|
4
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
|
+
import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, ResolveInsertInput, ResolveType, Transaction as TransactionType, UtilsRecord } from './types.js';
|
|
5
5
|
export declare const collectionsStore: Map<string, CollectionImpl<any, any, any, StandardSchemaV1<unknown, unknown>, any>>;
|
|
6
6
|
interface PendingSyncedTransaction<T extends object = Record<string, unknown>> {
|
|
7
7
|
committed: boolean;
|
package/dist/esm/collection.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { withArrayChangeTracking, withChangeTracking } from "./proxy.js";
|
|
2
|
-
import { getActiveTransaction, createTransaction } from "./transactions.js";
|
|
3
2
|
import { SortedMap } from "./SortedMap.js";
|
|
3
|
+
import { getActiveTransaction, createTransaction } from "./transactions.js";
|
|
4
4
|
const collectionsStore = /* @__PURE__ */ new Map();
|
|
5
5
|
function createCollection(options) {
|
|
6
6
|
const collection = new CollectionImpl(options);
|
|
@@ -926,12 +926,10 @@ class CollectionImpl {
|
|
|
926
926
|
return result;
|
|
927
927
|
}
|
|
928
928
|
ensureStandardSchema(schema) {
|
|
929
|
-
if (schema &&
|
|
929
|
+
if (schema && `~standard` in schema) {
|
|
930
930
|
return schema;
|
|
931
931
|
}
|
|
932
|
-
throw new Error(
|
|
933
|
-
`Schema must either implement the standard-schema interface or be a Zod schema`
|
|
934
|
-
);
|
|
932
|
+
throw new Error(`Schema must implement the standard-schema interface`);
|
|
935
933
|
}
|
|
936
934
|
getKeyFromItem(item) {
|
|
937
935
|
return this.config.getKey(item);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection.js","sources":["../../src/collection.ts"],"sourcesContent":["import { withArrayChangeTracking, withChangeTracking } from \"./proxy\"\nimport { createTransaction, getActiveTransaction } from \"./transactions\"\nimport { SortedMap } from \"./SortedMap\"\nimport type { Transaction } from \"./transactions\"\nimport type {\n ChangeListener,\n ChangeMessage,\n CollectionConfig,\n CollectionStatus,\n Fn,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n ResolveInsertInput,\n ResolveType,\n StandardSchema,\n Transaction as TransactionType,\n TransactionWithMutations,\n UtilsRecord,\n} from \"./types\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n// Store collections in memory\nexport const collectionsStore = new Map<string, CollectionImpl<any, any, any>>()\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\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 must provide either an explicit type or a schema, but not both.\n */\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\n/**\n * Custom error class for schema validation errors\n */\nexport class SchemaValidationError extends Error {\n type: `insert` | `update`\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>\n\n constructor(\n type: `insert` | `update`,\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>,\n message?: string\n ) {\n const defaultMessage = `${type === `insert` ? `Insert` : `Update`} validation failed: ${issues\n .map((issue) => `\\n- ${issue.message} - path: ${issue.path}`)\n .join(``)}`\n\n super(message || defaultMessage)\n this.name = `SchemaValidationError`\n this.type = type\n this.issues = issues\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 // 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\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 Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection is in error state. ` +\n `Try calling cleanup() and restarting the collection.`\n )\n case `cleaned-up`:\n throw new Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection has been cleaned up. ` +\n `The collection will automatically restart on next access.`\n )\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 Error(\n `Invalid collection status transition from \"${from}\" to \"${to}\" for collection \"${this.id}\"`\n )\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\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 Error(`Collection requires a config`)\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 Error(`Collection requires a sync config`)\n }\n\n this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n a.compareCreatedAt(b)\n )\n\n this.config = config\n\n // Store in global collections store\n collectionsStore.set(this.id, this)\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 })\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 Error(`No pending sync transaction to write to`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't still write to it.`\n )\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 if (\n this.syncedData.has(key) &&\n !pendingTransaction.operations.some(\n (op) => op.key === key && op.type === `delete`\n )\n ) {\n throw new Error(\n `Cannot insert document with key \"${key}\" from sync because it already exists in the collection \"${this.id}\"`\n )\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to commit`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't commit it again.`\n )\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 })\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 Error(`Collection is in error state`))\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 Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${error.message}`\n )\n wrappedError.cause = error\n wrappedError.stack = error.stack\n throw wrappedError\n } else {\n throw new Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${String(error)}`\n )\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 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.activeSubscribersCount = 0\n this.startGCTimer()\n } else if (this.activeSubscribersCount < 0) {\n throw new Error(\n `Active subscribers count is negative - this should never happen`\n )\n }\n }\n\n /**\n * Recompute optimistic state from active transactions\n */\n private recomputeOptimisticState(): 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 const completedTransactions: Array<Transaction<any>> = []\n\n for (const transaction of this.transactions.values()) {\n if (transaction.state === `completed`) {\n completedTransactions.push(transaction)\n } else 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 const filteredEventsBySyncStatus = events.filter(\n (event) => !this.recentlySyncedKeys.has(event.key)\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 if (this.pendingSyncedTransactions.length > 0) {\n const pendingSyncKeys = new Set<TKey>()\n const completedTransactionMutations = new Set<string>()\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 // Collect mutation IDs from completed transactions\n for (const tx of completedTransactions) {\n for (const mutation of tx.mutations) {\n if (mutation.collection === this) {\n completedTransactionMutations.add(mutation.mutationId)\n }\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 this.emitEvents(filteredEvents)\n } else {\n // Emit all events if no pending sync transactions\n this.emitEvents(filteredEventsBySyncStatus)\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 events either immediately or batch them for later emission\n */\n private emitEvents(\n changes: Array<ChangeMessage<T, TKey>>,\n endBatching = false\n ): void {\n if (this.shouldBatchEvents && !endBatching) {\n // Add events to the batch\n this.batchedEvents.push(...changes)\n return\n }\n\n // Either we're not batching, or we're ending the batching cycle\n let eventsToEmit = changes\n\n if (endBatching) {\n // End batching: combine any batched events with new events and clean up state\n if (this.batchedEvents.length > 0) {\n eventsToEmit = [...this.batchedEvents, ...changes]\n }\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 if (!hasPersistingTransaction) {\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 this.pendingSyncedTransactions) {\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 this.pendingSyncedTransactions) {\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 // Clear optimistic state since sync operations will now provide the authoritative data\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 this.deepEqual(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 !this.deepEqual(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 // End batching and emit all events (combines any batched events with sync events)\n this.emitEvents(events, true)\n\n this.pendingSyncedTransactions = []\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 private ensureStandardSchema(schema: unknown): StandardSchema<T> {\n // If the schema already implements the standard-schema interface, return it\n if (schema && typeof schema === `object` && `~standard` in schema) {\n return schema as StandardSchema<T>\n }\n\n throw new Error(\n `Schema must either implement the standard-schema interface or be a Zod schema`\n )\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 Error(\n `An object was created without a defined key: ${JSON.stringify(item)}`\n )\n }\n\n return `KEY::${this.id}/${key}`\n }\n\n private deepEqual(a: any, b: any): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n\n if (typeof a === `object`) {\n if (Array.isArray(a) !== Array.isArray(b)) return false\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n if (keysA.length !== keysB.length) return false\n\n const keysBSet = new Set(keysB)\n for (const key of keysA) {\n if (!keysBSet.has(key)) return false\n if (!this.deepEqual(a[key], b[key])) return false\n }\n return true\n }\n\n return false\n }\n\n private 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 TypeError(`Schema validation must be synchronous`)\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 TypeError(`Schema validation must be synchronous`)\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 Error(\n `Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`\n )\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 `Cannot insert document with ID \"${key}\" because it already exists in the collection`\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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<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<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: 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: TItem) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n keys: (TKey | unknown) | Array<TKey | unknown>,\n configOrCallback: ((draft: TItem | Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof keys === `undefined`) {\n throw new Error(`The first argument to update is missing`)\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 Error(\n `Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`\n )\n }\n\n const isArray = Array.isArray(keys)\n const keysArray = isArray ? keys : [keys]\n\n if (isArray && keysArray.length === 0) {\n throw new Error(`No keys were passed to update`)\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 Error(\n `The key \"${key}\" was passed to update but an object for this key was not found in the collection`\n )\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 Error(\n `Updating the key of an item is not allowed. Original key: \"${originalItemId}\", Attempted new key: \"${modifiedItemId}\". Please delete the old item and create a new one if a key change is necessary.`\n )\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 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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 Error(\n `Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`\n )\n }\n\n if (Array.isArray(keys) && keys.length === 0) {\n throw new Error(`No keys were passed to delete`)\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 Error(\n `Collection.delete was called with key '${key}' but there is no item in the collection with this key`\n )\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 * @returns An array of changes\n */\n public currentStateAsChanges(): Array<ChangeMessage<T>> {\n return Array.from(this.entries()).map(([key, value]) => ({\n type: `insert`,\n key,\n value,\n }))\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - Function called when items change\n * @param options.includeInitialState - If true, immediately calls callback with current data\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 public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void,\n { includeInitialState = false }: { includeInitialState?: boolean } = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n if (includeInitialState) {\n // First send the current state as changes\n callback(this.currentStateAsChanges())\n }\n\n // Add to batched listeners\n this.changeListeners.add(callback)\n\n return () => {\n this.changeListeners.delete(callback)\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()\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 { SortedMap } from \"./SortedMap\"\nimport { createTransaction, getActiveTransaction } from \"./transactions\"\nimport type { Transaction } from \"./transactions\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport type {\n ChangeListener,\n ChangeMessage,\n CollectionConfig,\n CollectionStatus,\n Fn,\n InsertConfig,\n OperationConfig,\n OptimisticChangeMessage,\n PendingMutation,\n ResolveInsertInput,\n ResolveType,\n StandardSchema,\n Transaction as TransactionType,\n TransactionWithMutations,\n UtilsRecord,\n} from \"./types\"\n\n// Store collections in memory\nexport const collectionsStore = new Map<string, CollectionImpl<any, any, any>>()\n\ninterface PendingSyncedTransaction<T extends object = Record<string, unknown>> {\n committed: boolean\n operations: Array<OptimisticChangeMessage<T>>\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 must provide either an explicit type or a schema, but not both.\n */\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\n/**\n * Custom error class for schema validation errors\n */\nexport class SchemaValidationError extends Error {\n type: `insert` | `update`\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>\n\n constructor(\n type: `insert` | `update`,\n issues: ReadonlyArray<{\n message: string\n path?: ReadonlyArray<string | number | symbol>\n }>,\n message?: string\n ) {\n const defaultMessage = `${type === `insert` ? `Insert` : `Update`} validation failed: ${issues\n .map((issue) => `\\n- ${issue.message} - path: ${issue.path}`)\n .join(``)}`\n\n super(message || defaultMessage)\n this.name = `SchemaValidationError`\n this.type = type\n this.issues = issues\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 // 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\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 Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection is in error state. ` +\n `Try calling cleanup() and restarting the collection.`\n )\n case `cleaned-up`:\n throw new Error(\n `Cannot perform ${operation} on collection \"${this.id}\" - collection has been cleaned up. ` +\n `The collection will automatically restart on next access.`\n )\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 Error(\n `Invalid collection status transition from \"${from}\" to \"${to}\" for collection \"${this.id}\"`\n )\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\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 Error(`Collection requires a config`)\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 Error(`Collection requires a sync config`)\n }\n\n this.transactions = new SortedMap<string, Transaction<any>>((a, b) =>\n a.compareCreatedAt(b)\n )\n\n this.config = config\n\n // Store in global collections store\n collectionsStore.set(this.id, this)\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 })\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 Error(`No pending sync transaction to write to`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't still write to it.`\n )\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 if (\n this.syncedData.has(key) &&\n !pendingTransaction.operations.some(\n (op) => op.key === key && op.type === `delete`\n )\n ) {\n throw new Error(\n `Cannot insert document with key \"${key}\" from sync because it already exists in the collection \"${this.id}\"`\n )\n }\n }\n\n const message: ChangeMessage<T> = {\n ...messageWithoutKey,\n key,\n }\n pendingTransaction.operations.push(message)\n },\n commit: () => {\n const pendingTransaction =\n this.pendingSyncedTransactions[\n this.pendingSyncedTransactions.length - 1\n ]\n if (!pendingTransaction) {\n throw new Error(`No pending sync transaction to commit`)\n }\n if (pendingTransaction.committed) {\n throw new Error(\n `The pending sync transaction is already committed, you can't commit it again.`\n )\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 })\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 Error(`Collection is in error state`))\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 Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${error.message}`\n )\n wrappedError.cause = error\n wrappedError.stack = error.stack\n throw wrappedError\n } else {\n throw new Error(\n `Collection \"${this.id}\" sync cleanup function threw an error: ${String(error)}`\n )\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 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.activeSubscribersCount = 0\n this.startGCTimer()\n } else if (this.activeSubscribersCount < 0) {\n throw new Error(\n `Active subscribers count is negative - this should never happen`\n )\n }\n }\n\n /**\n * Recompute optimistic state from active transactions\n */\n private recomputeOptimisticState(): 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 const completedTransactions: Array<Transaction<any>> = []\n\n for (const transaction of this.transactions.values()) {\n if (transaction.state === `completed`) {\n completedTransactions.push(transaction)\n } else 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 const filteredEventsBySyncStatus = events.filter(\n (event) => !this.recentlySyncedKeys.has(event.key)\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 if (this.pendingSyncedTransactions.length > 0) {\n const pendingSyncKeys = new Set<TKey>()\n const completedTransactionMutations = new Set<string>()\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 // Collect mutation IDs from completed transactions\n for (const tx of completedTransactions) {\n for (const mutation of tx.mutations) {\n if (mutation.collection === this) {\n completedTransactionMutations.add(mutation.mutationId)\n }\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 this.emitEvents(filteredEvents)\n } else {\n // Emit all events if no pending sync transactions\n this.emitEvents(filteredEventsBySyncStatus)\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 events either immediately or batch them for later emission\n */\n private emitEvents(\n changes: Array<ChangeMessage<T, TKey>>,\n endBatching = false\n ): void {\n if (this.shouldBatchEvents && !endBatching) {\n // Add events to the batch\n this.batchedEvents.push(...changes)\n return\n }\n\n // Either we're not batching, or we're ending the batching cycle\n let eventsToEmit = changes\n\n if (endBatching) {\n // End batching: combine any batched events with new events and clean up state\n if (this.batchedEvents.length > 0) {\n eventsToEmit = [...this.batchedEvents, ...changes]\n }\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 if (!hasPersistingTransaction) {\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 this.pendingSyncedTransactions) {\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 this.pendingSyncedTransactions) {\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 // Clear optimistic state since sync operations will now provide the authoritative data\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 this.deepEqual(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 !this.deepEqual(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 // End batching and emit all events (combines any batched events with sync events)\n this.emitEvents(events, true)\n\n this.pendingSyncedTransactions = []\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 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 Error(`Schema must implement the standard-schema interface`)\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 Error(\n `An object was created without a defined key: ${JSON.stringify(item)}`\n )\n }\n\n return `KEY::${this.id}/${key}`\n }\n\n private deepEqual(a: any, b: any): boolean {\n if (a === b) return true\n if (a == null || b == null) return false\n if (typeof a !== typeof b) return false\n\n if (typeof a === `object`) {\n if (Array.isArray(a) !== Array.isArray(b)) return false\n\n const keysA = Object.keys(a)\n const keysB = Object.keys(b)\n if (keysA.length !== keysB.length) return false\n\n const keysBSet = new Set(keysB)\n for (const key of keysA) {\n if (!keysBSet.has(key)) return false\n if (!this.deepEqual(a[key], b[key])) return false\n }\n return true\n }\n\n return false\n }\n\n private 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 TypeError(`Schema validation must be synchronous`)\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 TypeError(`Schema validation must be synchronous`)\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 Error(\n `Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`\n )\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 `Cannot insert document with ID \"${key}\" because it already exists in the collection`\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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<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<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: 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: TItem) => void\n ): TransactionType\n\n update<TItem extends object = T>(\n keys: (TKey | unknown) | Array<TKey | unknown>,\n configOrCallback: ((draft: TItem | Array<TItem>) => void) | OperationConfig,\n maybeCallback?: (draft: TItem | Array<TItem>) => void\n ) {\n if (typeof keys === `undefined`) {\n throw new Error(`The first argument to update is missing`)\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 Error(\n `Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`\n )\n }\n\n const isArray = Array.isArray(keys)\n const keysArray = isArray ? keys : [keys]\n\n if (isArray && keysArray.length === 0) {\n throw new Error(`No keys were passed to update`)\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 Error(\n `The key \"${key}\" was passed to update but an object for this key was not found in the collection`\n )\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 Error(\n `Updating the key of an item is not allowed. Original key: \"${originalItemId}\", Attempted new key: \"${modifiedItemId}\". Please delete the old item and create a new one if a key change is necessary.`\n )\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 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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 Error(\n `Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`\n )\n }\n\n if (Array.isArray(keys) && keys.length === 0) {\n throw new Error(`No keys were passed to delete`)\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 Error(\n `Collection.delete was called with key '${key}' but there is no item in the collection with this key`\n )\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.recomputeOptimisticState()\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.recomputeOptimisticState()\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 * @returns An array of changes\n */\n public currentStateAsChanges(): Array<ChangeMessage<T>> {\n return Array.from(this.entries()).map(([key, value]) => ({\n type: `insert`,\n key,\n value,\n }))\n }\n\n /**\n * Subscribe to changes in the collection\n * @param callback - Function called when items change\n * @param options.includeInitialState - If true, immediately calls callback with current data\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 public subscribeChanges(\n callback: (changes: Array<ChangeMessage<T>>) => void,\n { includeInitialState = false }: { includeInitialState?: boolean } = {}\n ): () => void {\n // Start sync and track subscriber\n this.addSubscriber()\n\n if (includeInitialState) {\n // First send the current state as changes\n callback(this.currentStateAsChanges())\n }\n\n // Add to batched listeners\n this.changeListeners.add(callback)\n\n return () => {\n this.changeListeners.delete(callback)\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()\n }\n}\n"],"names":["config","result"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/db",
|
|
3
3
|
"description": "A reactive client store for building super fast apps on sync",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.27",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@electric-sql/d2mini": "^0.1.7",
|
|
7
7
|
"@standard-schema/spec": "^1.0.0"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"@vitest/coverage-istanbul": "^3.0.9"
|
|
10
|
+
"@vitest/coverage-istanbul": "^3.0.9",
|
|
11
|
+
"arktype": "^2.1.20"
|
|
11
12
|
},
|
|
12
13
|
"exports": {
|
|
13
14
|
".": {
|
package/src/collection.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { withArrayChangeTracking, withChangeTracking } from "./proxy"
|
|
2
|
-
import { createTransaction, getActiveTransaction } from "./transactions"
|
|
3
2
|
import { SortedMap } from "./SortedMap"
|
|
3
|
+
import { createTransaction, getActiveTransaction } from "./transactions"
|
|
4
4
|
import type { Transaction } from "./transactions"
|
|
5
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec"
|
|
5
6
|
import type {
|
|
6
7
|
ChangeListener,
|
|
7
8
|
ChangeMessage,
|
|
@@ -19,7 +20,6 @@ import type {
|
|
|
19
20
|
TransactionWithMutations,
|
|
20
21
|
UtilsRecord,
|
|
21
22
|
} from "./types"
|
|
22
|
-
import type { StandardSchemaV1 } from "@standard-schema/spec"
|
|
23
23
|
|
|
24
24
|
// Store collections in memory
|
|
25
25
|
export const collectionsStore = new Map<string, CollectionImpl<any, any, any>>()
|
|
@@ -1242,13 +1242,11 @@ export class CollectionImpl<
|
|
|
1242
1242
|
|
|
1243
1243
|
private ensureStandardSchema(schema: unknown): StandardSchema<T> {
|
|
1244
1244
|
// If the schema already implements the standard-schema interface, return it
|
|
1245
|
-
if (schema &&
|
|
1245
|
+
if (schema && `~standard` in (schema as {})) {
|
|
1246
1246
|
return schema as StandardSchema<T>
|
|
1247
1247
|
}
|
|
1248
1248
|
|
|
1249
|
-
throw new Error(
|
|
1250
|
-
`Schema must either implement the standard-schema interface or be a Zod schema`
|
|
1251
|
-
)
|
|
1249
|
+
throw new Error(`Schema must implement the standard-schema interface`)
|
|
1252
1250
|
}
|
|
1253
1251
|
|
|
1254
1252
|
public getKeyFromItem(item: T): TKey {
|