{"version":3,"file":"index.mjs","sources":["../src/utils/debounce.ts","../src/utils/PromiseQueue.ts","../src/computeChanges.ts","../src/getSnapshot.ts","../src/applyChanges.ts","../src/sync.ts","../src/SyncManager.ts"],"sourcesContent":["/**\n * Debounces a function.\n * @param fn Function to debounce\n * @param wait Time to wait before calling the function.\n * @param [options] Debounce options\n * @param [options.leading] Whether to call the function on the leading edge of the wait interval.\n * @param [options.trailing] Whether to call the function on the trailing edge of the wait interval.\n * @returns The debounced function.\n */\nexport default function debounce(fn, wait, options = {}) {\n    let timeout;\n    let result;\n    const { leading = false, trailing = true } = options;\n    /**\n     * The debounced function that will be returned.\n     * @param this The context to bind the function to.\n     * @param args The arguments to pass to the function.\n     * @returns The result of the debounced function.\n     */\n    function debounced(...args) {\n        const shouldCallImmediately = leading && !timeout;\n        const shouldCallTrailing = trailing && !timeout;\n        if (timeout) {\n            clearTimeout(timeout);\n        }\n        timeout = setTimeout(() => {\n            timeout = null;\n            if (trailing && !shouldCallImmediately) {\n                result = fn.apply(this, args);\n            }\n        }, wait);\n        if (shouldCallImmediately) {\n            result = fn.apply(this, args);\n        }\n        else if (!shouldCallTrailing) {\n            result = null;\n        }\n        return result;\n    }\n    return debounced;\n}\n","/**\n * Class for queuing promises to be executed one after the other.\n * This is useful for tasks that should not be executed in parallel.\n * @example\n * const queue = new PromiseQueue();\n * queue.add(() => fetch('https://example.com/api/endpoint1'));\n * queue.add(() => fetch('https://example.com/api/endpoint2'));\n * // The second fetch will only be executed after the first one is done.\n */\nexport default class PromiseQueue {\n    queue = [];\n    pendingPromise = false;\n    /**\n     * Method to add a new promise to the queue and returns a promise that resolves when this task is done\n     * @param task Function that returns a promise that will be added to the queue\n     * @returns Promise that resolves when the task is done\n     */\n    add(task) {\n        return new Promise((resolve, reject) => {\n            // Wrap the task with the resolve and reject to control its completion from the outside\n            this.queue.push(() => task()\n                .then(resolve)\n                .catch((error) => {\n                reject(error);\n                throw error;\n            }));\n            this.dequeue();\n        });\n    }\n    /**\n     * Method to check if there is a pending promise in the queue\n     * @returns True if there is a pending promise, false otherwise\n     */\n    hasPendingPromise() {\n        return this.pendingPromise;\n    }\n    /**\n     * Method to process the queue\n     */\n    dequeue() {\n        if (this.pendingPromise || this.queue.length === 0) {\n            return;\n        }\n        const task = this.queue.shift();\n        if (!task)\n            return;\n        this.pendingPromise = true;\n        task()\n            .then(() => {\n            this.pendingPromise = false;\n            this.dequeue();\n        })\n            .catch(() => {\n            this.pendingPromise = false;\n            this.dequeue();\n        });\n    }\n}\n","import { isEqual } from '@signaldb/core';\n/**\n * Computes the modified fields between two items recursively.\n * @param oldItem The old item\n * @param newItem The new item\n * @returns The modified fields\n */\nexport function computeModifiedFields(oldItem, newItem) {\n    const modifiedFields = [];\n    const oldKeys = Object.keys(oldItem);\n    const newKeys = Object.keys(newItem);\n    const allKeys = new Set([...oldKeys, ...newKeys]);\n    for (const key of allKeys) {\n        if (newItem[key] !== oldItem[key]) {\n            if (typeof newItem[key] === 'object' && typeof oldItem[key] === 'object' && newItem[key] != null && oldItem[key] != null) {\n                const nestedModifiedFields = computeModifiedFields(oldItem[key], newItem[key]);\n                for (const nestedField of nestedModifiedFields) {\n                    modifiedFields.push(`${key}.${nestedField}`);\n                }\n            }\n            else {\n                modifiedFields.push(key);\n            }\n        }\n    }\n    return modifiedFields;\n}\n/**\n * Compute changes between two arrays of items.\n * @param oldItems Array of the old items\n * @param newItems Array of the new items\n * @returns The changeset\n */\nexport default function computeChanges(oldItems, newItems) {\n    const added = [];\n    const modified = [];\n    const modifiedFields = new Map();\n    const removed = [];\n    const oldItemsMap = new Map(oldItems.map(item => [item.id, item]));\n    const newItemsMap = new Map(newItems.map(item => [item.id, item]));\n    for (const [id, oldItem] of oldItemsMap) {\n        const newItem = newItemsMap.get(id);\n        if (!newItem) {\n            removed.push(oldItem);\n        }\n        else if (!isEqual(newItem, oldItem)) {\n            modifiedFields.set(newItem.id, computeModifiedFields(oldItem, newItem));\n            modified.push(newItem);\n        }\n    }\n    for (const [id, newItem] of newItemsMap) {\n        if (!oldItemsMap.has(id)) {\n            added.push(newItem);\n        }\n    }\n    return {\n        added,\n        modified,\n        modifiedFields,\n        removed,\n    };\n}\n","/**\n * Gets the snapshot of items from the last snapshot and the changes.\n * @param lastSnapshot The last snapshot of items\n * @param data The changes to apply to the last snapshot\n * @returns The new snapshot of items\n */\nexport default function getSnapshot(lastSnapshot, data) {\n    if (data.items != null)\n        return data.items;\n    const items = lastSnapshot || [];\n    data.changes.added.forEach((item) => {\n        const index = items.findIndex(i => i.id === item.id);\n        if (index === -1) {\n            items.push(item);\n        }\n        else {\n            items[index] = item;\n        }\n    });\n    data.changes.modified.forEach((item) => {\n        const index = items.findIndex(i => i.id === item.id);\n        if (index === -1) {\n            items.push(item);\n        }\n        else {\n            items[index] = item;\n        }\n    });\n    data.changes.removed.forEach((item) => {\n        const index = items.findIndex(i => i.id === item.id);\n        if (index !== -1)\n            items.splice(index, 1);\n    });\n    return items;\n}\n","import { modify } from '@signaldb/core';\n/**\n * applies changes to a collection of items\n * @param items The items to apply the changes to\n * @param changes The changes to apply to the items\n * @returns The new items after applying the changes\n */\nexport default function applyChanges(items, changes) {\n    // Create initial map of items by ID\n    const itemMap = new Map(items.map(item => [item.id, item]));\n    changes.forEach((change) => {\n        if (change.type === 'remove') {\n            itemMap.delete(change.data);\n        }\n        else if (change.type === 'insert') {\n            const existingItem = itemMap.get(change.data.id);\n            itemMap.set(change.data.id, existingItem ? { ...existingItem, ...change.data } : change.data);\n        }\n        else { // change.type === 'update'\n            const existingItem = itemMap.get(change.data.id);\n            itemMap.set(change.data.id, existingItem\n                ? modify(existingItem, change.data.modifier)\n                : modify({ id: change.data.id }, change.data.modifier));\n        }\n    });\n    // Convert map back to array\n    return [...itemMap.values()];\n}\n","import computeChanges from './computeChanges';\nimport getSnapshot from './getSnapshot';\nimport applyChanges from './applyChanges';\n/**\n * Checks if there are any changes in the given changeset.\n * @param changes The changeset to check.\n * @returns True if there are changes, false otherwise.\n */\nfunction hasChanges(changes) {\n    return changes.added.length > 0\n        || changes.modified.length > 0\n        || changes.removed.length > 0;\n}\n/**\n * Checks if there is a difference between the old items and the new items.\n * @param oldItems The old items.\n * @param newItems The new items.\n * @returns True if there is a difference, false otherwise.\n */\nfunction hasDifference(oldItems, newItems) {\n    return hasChanges(computeChanges(oldItems, newItems));\n}\n/**\n * Does a sync operation based on the provided options. If changes are supplied, these will be rebased on the new data.\n * Afterwards the push method will be called with the remaining changes. A new snapshot will be created and returned.\n * @param options Sync options\n * @param options.changes Changes to call the push method with\n * @param [options.lastSnapshot] The last snapshot\n * @param options.data The new data\n * @param options.pull Method to pull new data\n * @param options.push Method to push changes\n * @param options.insert Method to insert an item\n * @param options.update Method to update an item\n * @param options.remove Method to remove an item\n * @param options.batch Method to batch multiple operations\n * @returns The new snapshot\n */\nexport default async function sync({ changes, lastSnapshot, data, pull, push, insert, update, remove, batch, }) {\n    let newData = data;\n    let previousSnapshot = lastSnapshot || [];\n    let newSnapshot = getSnapshot(lastSnapshot, newData);\n    if (changes.length > 0) {\n        // apply changes on last snapshot and check if there is a difference\n        const lastSnapshotWithChanges = applyChanges(previousSnapshot, changes);\n        if (hasDifference(previousSnapshot, lastSnapshotWithChanges)) {\n            // if yes, apply the changes on the newSnapshot and check if there is a difference\n            const newSnapshotWithChanges = applyChanges(newSnapshot, changes);\n            const changesToPush = computeChanges(newSnapshot, newSnapshotWithChanges);\n            if (hasChanges(changesToPush)) {\n                // if yes, push the changes to the server\n                await push(changesToPush);\n                // pull new data afterwards to ensure that all server changes are applied\n                newData = await pull();\n                newSnapshot = getSnapshot(newSnapshot, newData);\n            }\n            previousSnapshot = lastSnapshotWithChanges;\n        }\n    }\n    // apply the new changes on the collection\n    const newChanges = newData.changes == null\n        ? computeChanges(previousSnapshot, newData.items)\n        : newData.changes;\n    batch(() => {\n        newChanges.added.forEach(item => insert(item));\n        newChanges.modified.forEach(item => update(item.id, { $set: item }));\n        newChanges.removed.forEach(item => remove(item.id));\n    });\n    return newSnapshot;\n}\n","import { Collection, randomId, createIndex } from '@signaldb/core';\nimport debounce from './utils/debounce';\nimport PromiseQueue from './utils/PromiseQueue';\nimport sync from './sync';\n/**\n * Class to manage syncing of collections.\n * @template CollectionOptions\n * @template ItemType\n * @template IdType\n * @example\n * const syncManager = new SyncManager({\n *    pull: async (collectionOptions) => {\n *      const response = await fetch(`/api/collections/${collectionOptions.name}`)\n *      return await response.json()\n *    },\n *    push: async (collectionOptions, { changes }) => {\n *      await fetch(`/api/collections/${collectionOptions.name}`, {\n *        method: 'POST',\n *        body: JSON.stringify(changes),\n *      })\n *    },\n *  })\n *\n *  const collection = new Collection()\n *  syncManager.addCollection(collection, {\n *    name: 'todos',\n *  })\n *\n *  syncManager.sync('todos')\n */\nexport default class SyncManager {\n    options;\n    collections = new Map();\n    changes;\n    snapshots;\n    syncOperations;\n    scheduledPushes = new Set();\n    remoteChanges = [];\n    syncQueues = new Map();\n    persistenceReady;\n    isDisposed = false;\n    instanceId = randomId();\n    id;\n    debouncedFlush;\n    /**\n     * @param options Collection options\n     * @param options.pull Function to pull data from remote source.\n     * @param options.push Function to push data to remote source.\n     * @param [options.registerRemoteChange] Function to register a callback for remote changes.\n     * @param [options.id] Unique identifier for this sync manager. Only nessesary if you have multiple sync managers.\n     * @param [options.persistenceAdapter] Persistence adapter to use for storing changes, snapshots and sync operations.\n     * @param [options.reactivity] Reactivity adapter to use for reactivity.\n     * @param [options.onError] Function to handle errors that occur async during syncing.\n     * @param [options.autostart] Whether to automatically start syncing new collections.\n     * @param [options.debounceTime] The time in milliseconds to debounce push operations.\n     */\n    constructor(options) {\n        this.options = {\n            autostart: true,\n            ...options,\n        };\n        this.id = this.options.id || 'default-sync-manager';\n        const { reactivity } = this.options;\n        const changesPersistence = this.createPersistenceAdapter('changes');\n        const snapshotsPersistence = this.createPersistenceAdapter('snapshots');\n        const syncOperationsPersistence = this.createPersistenceAdapter('sync-operations');\n        this.changes = new Collection({\n            name: `${this.options.id}-changes`,\n            persistence: changesPersistence?.adapter,\n            indices: [createIndex('collectionName')],\n            reactivity,\n        });\n        this.snapshots = new Collection({\n            name: `${this.options.id}-snapshots`,\n            persistence: snapshotsPersistence?.adapter,\n            indices: [createIndex('collectionName')],\n            reactivity,\n        });\n        this.syncOperations = new Collection({\n            name: `${this.options.id}-sync-operations`,\n            persistence: syncOperationsPersistence?.adapter,\n            indices: [createIndex('collectionName'), createIndex('status')],\n            reactivity,\n        });\n        this.changes.on('persistence.error', error => changesPersistence?.handler(error));\n        this.snapshots.on('persistence.error', error => snapshotsPersistence?.handler(error));\n        this.syncOperations.on('persistence.error', error => syncOperationsPersistence?.handler(error));\n        this.persistenceReady = Promise.all([\n            this.syncOperations.isReady(),\n            this.changes.isReady(),\n            this.snapshots.isReady(),\n        ]).then(() => { });\n        this.changes.setMaxListeners(1000);\n        this.snapshots.setMaxListeners(1000);\n        this.syncOperations.setMaxListeners(1000);\n        this.debouncedFlush = debounce(this.flushScheduledPushes, this.options.debounceTime ?? 100);\n    }\n    createPersistenceAdapter(name) {\n        if (this.options.persistenceAdapter == null)\n            return;\n        let errorHandler = () => { };\n        const adapter = this.options.persistenceAdapter(`${this.id}-${name}`, (handler) => {\n            errorHandler = handler;\n        });\n        return {\n            adapter,\n            handler: (error) => errorHandler(error),\n        };\n    }\n    getSyncQueue(name) {\n        if (this.syncQueues.get(name) == null) {\n            this.syncQueues.set(name, new PromiseQueue());\n        }\n        return this.syncQueues.get(name);\n    }\n    /**\n     * Clears all internal data structures\n     */\n    async dispose() {\n        this.collections.clear();\n        this.syncQueues.clear();\n        this.remoteChanges.splice(0);\n        await Promise.all([\n            this.changes.dispose(),\n            this.snapshots.dispose(),\n            this.syncOperations.dispose(),\n        ]);\n        this.isDisposed = true;\n    }\n    /**\n     * Gets a collection with it's options by name\n     * @deprecated Use getCollectionProperties instead.\n     * @param name Name of the collection\n     * @throws Will throw an error if the name wasn't found\n     * @returns Tuple of collection and options\n     */\n    getCollection(name) {\n        const { collection, options } = this.getCollectionProperties(name);\n        return [collection, options];\n    }\n    /**\n     * Gets collection options by name\n     * @param name Name of the collection\n     * @throws Will throw an error if the name wasn't found\n     * @returns An object of all properties of the collection\n     */\n    getCollectionProperties(name) {\n        const collectionParameters = this.collections.get(name);\n        if (collectionParameters == null)\n            throw new Error(`Collection with id '${name}' not found`);\n        return collectionParameters;\n    }\n    /**\n     * Adds a collection to the sync manager.\n     * @param collection Collection to add\n     * @param options Options for the collection. The object needs at least a `name` property.\n     * @param options.name Unique name of the collection\n     */\n    addCollection(collection, options) {\n        if (this.isDisposed)\n            throw new Error('SyncManager is disposed');\n        this.collections.set(options.name, {\n            collection,\n            options,\n            readyPromise: collection.isReady(),\n            syncPaused: true, // always start paused as the autostart will start it\n        });\n        const hasRemoteChange = (change) => {\n            for (const remoteChange of this.remoteChanges) {\n                if (remoteChange == null)\n                    continue;\n                if (remoteChange.collectionName !== change.collectionName)\n                    continue;\n                if (remoteChange.type !== change.type)\n                    continue;\n                if (change.type === 'remove' && remoteChange.data !== change.data)\n                    continue;\n                if (remoteChange.data.id !== change.data.id)\n                    continue;\n                return true;\n            }\n            return false;\n        };\n        const removeRemoteChanges = (collectionName, id) => {\n            const newRemoteChanges = [...this.remoteChanges];\n            for (let i = 0; i < newRemoteChanges.length; i += 1) {\n                const item = newRemoteChanges[i];\n                if (item == null)\n                    continue;\n                if (item.collectionName !== collectionName)\n                    continue;\n                if (item.type === 'remove' && item.data !== id)\n                    continue;\n                if (item.data.id !== id)\n                    continue;\n                newRemoteChanges[i] = null;\n            }\n            this.remoteChanges = newRemoteChanges.filter(item => item != null);\n        };\n        collection.on('added', (item) => {\n            // skip the change if it was a remote change\n            if (hasRemoteChange({ collectionName: options.name, type: 'insert', data: item })) {\n                removeRemoteChanges(options.name, item.id);\n                return;\n            }\n            this.changes.insert({\n                collectionName: options.name,\n                time: Date.now(),\n                type: 'insert',\n                data: item,\n            });\n            if (this.getCollectionProperties(options.name).syncPaused)\n                return;\n            this.schedulePush(options.name);\n        });\n        collection.on('changed', ({ id }, modifier) => {\n            const data = { id, modifier };\n            // skip the change if it was a remote change\n            if (hasRemoteChange({ collectionName: options.name, type: 'update', data })) {\n                removeRemoteChanges(options.name, id);\n                return;\n            }\n            this.changes.insert({\n                collectionName: options.name,\n                time: Date.now(),\n                type: 'update',\n                data,\n            });\n            if (this.getCollectionProperties(options.name).syncPaused)\n                return;\n            this.schedulePush(options.name);\n        });\n        collection.on('removed', ({ id }) => {\n            // skip the change if it was a remote change\n            if (hasRemoteChange({ collectionName: options.name, type: 'remove', data: id })) {\n                removeRemoteChanges(options.name, id);\n                return;\n            }\n            this.changes.insert({\n                collectionName: options.name,\n                time: Date.now(),\n                type: 'remove',\n                data: id,\n            });\n            if (this.getCollectionProperties(options.name).syncPaused)\n                return;\n            this.schedulePush(options.name);\n        });\n        if (this.options.autostart) {\n            this.startSync(options.name)\n                .catch((error) => {\n                if (!this.options.onError)\n                    return;\n                this.options.onError(this.getCollectionProperties(options.name).options, error);\n            });\n        }\n    }\n    flushScheduledPushes() {\n        this.scheduledPushes.forEach((name) => {\n            this.pushChanges(name).catch(() => { });\n        });\n        this.scheduledPushes.clear();\n    }\n    schedulePush(name) {\n        this.scheduledPushes.add(name);\n        this.debouncedFlush();\n    }\n    /**\n     * Setup all collections to be synced with remote changes\n     * and enable automatic pushing changes to the remote source.\n     */\n    async startAll() {\n        await Promise.all([...this.collections.keys()].map(id => this.startSync(id)));\n    }\n    /**\n     * Setup a collection to be synced with remote changes\n     * and enable automatic pushing changes to the remote source.\n     * @param name Name of the collection\n     */\n    async startSync(name) {\n        const collectionParameters = this.getCollectionProperties(name);\n        if (!collectionParameters.syncPaused)\n            return; // already started\n        this.schedulePush(name); // push changes that were made while paused\n        const cleanupFunction = this.options.registerRemoteChange\n            ? await this.options.registerRemoteChange(collectionParameters.options, async (data) => {\n                if (data == null) {\n                    await this.sync(name);\n                }\n                else {\n                    const syncTime = Date.now();\n                    const syncId = this.syncOperations.insert({\n                        start: syncTime,\n                        collectionName: name,\n                        instanceId: this.instanceId,\n                        status: 'active',\n                    });\n                    await this.syncWithData(name, data)\n                        .then(() => {\n                        // clean up old sync operations\n                        this.syncOperations.removeMany({\n                            id: { $ne: syncId },\n                            collectionName: name,\n                            $or: [\n                                { end: { $lte: syncTime } },\n                                { status: 'active' },\n                            ],\n                        });\n                        // update sync operation status to done after everthing was finished\n                        this.syncOperations.updateOne({ id: syncId }, {\n                            $set: { status: 'done', end: Date.now() },\n                        });\n                    })\n                        .catch((error) => {\n                        if (this.options.onError) {\n                            this.options.onError(this.getCollectionProperties(name).options, error);\n                        }\n                        this.syncOperations.updateOne({ id: syncId }, {\n                            $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n                        });\n                        throw error;\n                    });\n                }\n            })\n            : undefined;\n        this.collections.set(name, {\n            ...collectionParameters,\n            syncPaused: false,\n            cleanupFunction,\n        });\n    }\n    /**\n     * Pauses the sync process for all collections.\n     * This means that the collections will not be synced with remote changes\n     * and changes will not automatically be pushed to the remote source.\n     */\n    async pauseAll() {\n        await Promise.all([...this.collections.keys()].map(id => this.pauseSync(id)));\n    }\n    /**\n     * Pauses the sync process for a collection.\n     * This means that the collection will not be synced with remote changes\n     * and changes will not automatically be pushed to the remote source.\n     * @param name Name of the collection\n     */\n    async pauseSync(name) {\n        const collectionParameters = this.getCollectionProperties(name);\n        if (collectionParameters.syncPaused)\n            return; // already paused\n        if (collectionParameters.cleanupFunction)\n            await collectionParameters.cleanupFunction();\n        this.collections.set(name, {\n            ...collectionParameters,\n            cleanupFunction: undefined,\n            syncPaused: true,\n        });\n    }\n    /**\n     * Starts the sync process for all collections\n     */\n    async syncAll() {\n        if (this.isDisposed)\n            throw new Error('SyncManager is disposed');\n        const errors = [];\n        await Promise.all([...this.collections.keys()].map(id => this.sync(id).catch((error) => {\n            errors.push({ id, error });\n        })));\n        if (errors.length > 0)\n            throw new Error(`Error while syncing collections:\\n${errors.map(error => `${error.id}: ${error.error.message}`).join('\\n\\n')}`);\n    }\n    /**\n     * Checks if a collection is currently beeing synced\n     * @param [name] Name of the collection. If not provided, it will check if any collection is currently beeing synced.\n     * @returns True if the collection is currently beeing synced, false otherwise.\n     */\n    isSyncing(name) {\n        return this.syncOperations.findOne({\n            ...name ? { collectionName: name } : {},\n            status: 'active',\n        }, { fields: { status: 1 } }) != null;\n    }\n    /**\n     * Checks if the sync manager is ready to sync.\n     * @returns A promise that resolves when the sync manager is ready to sync.\n     */\n    async isReady() {\n        await this.persistenceReady;\n    }\n    /**\n     * Starts the sync process for a collection\n     * @param name Name of the collection\n     * @param options Options for the sync process.\n     * @param options.force If true, the sync process will be started even if there are no changes and onlyWithChanges is true.\n     * @param options.onlyWithChanges If true, the sync process will only be started if there are changes.\n     */\n    async sync(name, options = {}) {\n        if (this.isDisposed)\n            throw new Error('SyncManager is disposed');\n        await this.isReady();\n        const { options: collectionOptions, readyPromise } = this.getCollectionProperties(name);\n        await readyPromise;\n        const hasActiveSyncs = this.syncOperations.find({\n            collectionName: name,\n            instanceId: this.instanceId,\n            status: 'active',\n        }, {\n            reactive: false,\n        }).count() > 0;\n        const syncTime = Date.now();\n        let syncId = null;\n        // schedule for next tick to allow other tasks to run first\n        await new Promise((resolve) => {\n            setTimeout(resolve, 0);\n        });\n        const doSync = async () => {\n            const lastFinishedSync = this.syncOperations.findOne({\n                collectionName: name,\n                status: 'done',\n            }, {\n                sort: { end: -1 },\n                reactive: false,\n            });\n            if (options?.onlyWithChanges) {\n                const currentChanges = this.changes.find({\n                    collectionName: name,\n                    time: { $lte: syncTime },\n                }, {\n                    sort: { time: 1 },\n                    reactive: false,\n                }).count();\n                if (currentChanges === 0)\n                    return;\n            }\n            if (!hasActiveSyncs) {\n                syncId = this.syncOperations.insert({\n                    start: syncTime,\n                    collectionName: name,\n                    instanceId: this.instanceId,\n                    status: 'active',\n                });\n            }\n            const data = await this.options.pull(collectionOptions, {\n                lastFinishedSyncStart: lastFinishedSync?.start,\n                lastFinishedSyncEnd: lastFinishedSync?.end,\n            });\n            await this.syncWithData(name, data);\n        };\n        await (options?.force ? doSync() : this.getSyncQueue(name).add(doSync))\n            .catch((error) => {\n            if (syncId != null) {\n                if (this.options.onError)\n                    this.options.onError(collectionOptions, error);\n                this.syncOperations.updateOne({ id: syncId }, {\n                    $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n                });\n            }\n            throw error;\n        });\n        if (syncId != null) {\n            // clean up old sync operations\n            this.syncOperations.removeMany({\n                id: { $ne: syncId },\n                collectionName: name,\n                $or: [\n                    { end: { $lte: syncTime } },\n                    { status: 'active' },\n                ],\n            });\n            // update sync operation status to done after everthing was finished\n            this.syncOperations.updateOne({ id: syncId }, {\n                $set: { status: 'done', end: Date.now() },\n            });\n        }\n    }\n    /**\n     * Starts the push process for a collection (sync process but only if there are changes)\n     * @param name Name of the collection\n     */\n    async pushChanges(name) {\n        await this.sync(name, {\n            onlyWithChanges: true,\n        });\n    }\n    async syncWithData(name, data) {\n        const { collection, options: collectionOptions } = this.getCollectionProperties(name);\n        const syncTime = Date.now();\n        const lastFinishedSync = this.syncOperations.findOne({\n            collectionName: name,\n            status: 'done',\n        }, {\n            sort: { end: -1 },\n            reactive: false,\n        });\n        const lastSnapshot = this.snapshots.findOne({\n            collectionName: name,\n        }, {\n            sort: { time: -1 },\n            reactive: false,\n        });\n        const currentChanges = this.changes.find({\n            collectionName: name,\n            time: { $lte: syncTime },\n        }, {\n            sort: { time: 1 },\n            reactive: false,\n        }).fetch();\n        await sync({\n            changes: currentChanges,\n            lastSnapshot: lastSnapshot?.items,\n            data,\n            pull: () => this.options.pull(collectionOptions, {\n                lastFinishedSyncStart: lastFinishedSync?.start,\n                lastFinishedSyncEnd: lastFinishedSync?.end,\n            }),\n            push: changes => this.options.push(collectionOptions, {\n                changes,\n                rawChanges: currentChanges,\n            }),\n            insert: (item) => {\n                // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n                this.remoteChanges.push({\n                    collectionName: name,\n                    type: 'insert',\n                    data: item,\n                }, {\n                    collectionName: name,\n                    type: 'update',\n                    data: { id: item.id, modifier: { $set: item } },\n                });\n                // replace the item\n                collection.replaceOne({ id: item.id }, item, { upsert: true });\n            },\n            update: (itemId, modifier) => {\n                // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n                this.remoteChanges.push({\n                    collectionName: name,\n                    type: 'insert',\n                    data: { id: itemId, ...modifier.$set },\n                }, {\n                    collectionName: name,\n                    type: 'update',\n                    data: { id: itemId, modifier },\n                });\n                collection.updateOne({ id: itemId }, {\n                    ...modifier,\n                    $setOnInsert: { id: itemId },\n                }, { upsert: true });\n            },\n            remove: (itemId) => {\n                const itemExists = !!collection.findOne({\n                    id: itemId,\n                }, { reactive: false });\n                if (!itemExists)\n                    return;\n                this.remoteChanges.push({\n                    collectionName: name,\n                    type: 'remove',\n                    data: itemId,\n                });\n                collection.removeOne({ id: itemId });\n            },\n            batch: (fn) => {\n                collection.batch(() => {\n                    fn();\n                });\n            },\n        })\n            .then(async (snapshot) => {\n            // clean up old snapshots\n            this.snapshots.removeMany({\n                collectionName: name,\n                time: { $lte: syncTime },\n            });\n            // clean up processed changes\n            this.changes.removeMany({\n                collectionName: name,\n                id: { $in: currentChanges.map(c => c.id) },\n            });\n            // insert new snapshot\n            this.snapshots.insert({\n                time: syncTime,\n                collectionName: name,\n                items: snapshot,\n            });\n            // delay sync operation update to next tick to allow other tasks to run first\n            await new Promise((resolve) => {\n                setTimeout(resolve, 0);\n            });\n            const hasChanges = this.changes.find({\n                collectionName: name,\n            }, { reactive: false }).count() > 0;\n            if (hasChanges) {\n                // check if there are unsynced changes to push\n                // and sync again if there are any\n                await this.sync(name, {\n                    force: true,\n                    onlyWithChanges: true,\n                });\n                return;\n            }\n            // if there are no unsynced changes apply the last snapshot\n            // to make sure that collection and snapshot are in sync\n            // find all items that are not in the snapshot\n            const nonExistingItemIds = collection.find({\n                id: { $nin: snapshot.map(item => item.id) },\n            }, {\n                reactive: false,\n            }).map(item => item.id);\n            collection.batch(() => {\n                // update all items that are in the snapshot\n                snapshot.forEach((item) => {\n                    // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n                    this.remoteChanges.push({\n                        collectionName: name,\n                        type: 'insert',\n                        data: item,\n                    }, {\n                        collectionName: name,\n                        type: 'update',\n                        data: { id: item.id, modifier: { $set: item } },\n                    });\n                    // replace the item\n                    collection.replaceOne({ id: item.id }, item, { upsert: true });\n                });\n                // remove all items that are not in the snapshot\n                nonExistingItemIds.forEach((id) => {\n                    collection.removeOne({ id });\n                });\n            });\n        });\n    }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","__publicField","task","resolve","reject","error","computeModifiedFields","oldItem","newItem","modifiedFields","oldKeys","newKeys","allKeys","key","nestedModifiedFields","nestedField","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","itemMap","change","existingItem","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","reactivity","changesPersistence","snapshotsPersistence","syncOperationsPersistence","Collection","createIndex","name","errorHandler","handler","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChanges","collectionName","newRemoteChanges","modifier","cleanupFunction","syncTime","syncId","errors","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds"],"mappings":"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"}