@anfenn/zync 0.4.2 → 0.4.4
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/README.md +3 -3
- package/dist/index.cjs +3 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -5
- package/dist/index.d.ts +2 -5
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Simple, unopinionated, bullet-proof, offline-first sync middleware for Zustand.
|
|
|
17
17
|
- Missing remote record during update strategy, to prevent accidental server deletion from losing local data:
|
|
18
18
|
- `'ignore'` | `'delete-local-record'` | `'insert-remote-record'`
|
|
19
19
|
- Batteries optionally included:
|
|
20
|
-
- IndexedDB helper (based on [idb](https://www.npmjs.com/package/idb)): `
|
|
20
|
+
- IndexedDB helper (based on [idb](https://www.npmjs.com/package/idb)): `createIndexedDB()`
|
|
21
21
|
- UUID helper: `createLocalId()`
|
|
22
22
|
- Object|Array key rename helpers to map endpoint fields to Zync: `changeKeysFrom()` & `changeKeysTo()`
|
|
23
23
|
- Uses the official persist middleware as the local storage (localStorage, IndexedDB, etc.)
|
|
@@ -95,7 +95,7 @@ export const useStore = create<any>()(
|
|
|
95
95
|
|
|
96
96
|
name: 'store',
|
|
97
97
|
storage: createJSONStorage(() => localStorage),
|
|
98
|
-
// OR storage: createJSONStorage(() =>
|
|
98
|
+
// OR storage: createJSONStorage(() => createIndexedDB('my-app', 'my-store')),
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
101
|
// State-to-API map to enable syncing. Must implement the full CRUD API:
|
|
@@ -270,7 +270,7 @@ async function firstLoad(lastId: any) {
|
|
|
270
270
|
|
|
271
271
|
Using **_async_** IndexedDB over **_sync_** localStorage gives the advantage of a responsive UI when reading/writing a very large store, as IndexedDB is running in it's own thread.
|
|
272
272
|
|
|
273
|
-
If you want to use the bundled `
|
|
273
|
+
If you want to use the bundled `createIndexedDB()` helper, install `idb` in your project. It's intentionally optional so projects that don't use IndexedDB won't pull the dependency into their bundles.
|
|
274
274
|
|
|
275
275
|
[idb](https://www.npmjs.com/package/idb) is an extremely popular and lightweight wrapper to simplify IndexedDB's verbose events based api into a simple Promise based one. It also handles the inconsistencies found when running in different browsers.
|
|
276
276
|
|
package/dist/index.cjs
CHANGED
|
@@ -283,7 +283,7 @@ __export(index_exports, {
|
|
|
283
283
|
SyncAction: () => SyncAction,
|
|
284
284
|
changeKeysFrom: () => changeKeysFrom,
|
|
285
285
|
changeKeysTo: () => changeKeysTo,
|
|
286
|
-
|
|
286
|
+
createIndexedDB: () => createIndexedDB,
|
|
287
287
|
createLocalId: () => createLocalId,
|
|
288
288
|
createWithSync: () => createWithSync,
|
|
289
289
|
persistWithSync: () => persistWithSync
|
|
@@ -772,9 +772,7 @@ async function startFirstLoad(set, syncApi, logger) {
|
|
|
772
772
|
}
|
|
773
773
|
|
|
774
774
|
// src/indexedDBStorage.ts
|
|
775
|
-
function
|
|
776
|
-
const dbName = options.dbName;
|
|
777
|
-
const storeName = options.storeName;
|
|
775
|
+
function createIndexedDB(dbName, storeName) {
|
|
778
776
|
let dbPromise = null;
|
|
779
777
|
async function initDB() {
|
|
780
778
|
if (dbPromise) return dbPromise;
|
|
@@ -1050,7 +1048,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
1050
1048
|
SyncAction,
|
|
1051
1049
|
changeKeysFrom,
|
|
1052
1050
|
changeKeysTo,
|
|
1053
|
-
|
|
1051
|
+
createIndexedDB,
|
|
1054
1052
|
createLocalId,
|
|
1055
1053
|
createWithSync,
|
|
1056
1054
|
persistWithSync
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/.pnpm/idb@8.0.3/node_modules/idb/build/index.js","../src/index.ts","../src/logger.ts","../src/helpers.ts","../src/pull.ts","../src/push.ts","../src/firstLoad.ts","../src/indexedDBStorage.ts"],"sourcesContent":["const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey,\n ]));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event.newVersion, event));\n }\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking) {\n db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event));\n }\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function (...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n },\n};\nasync function* iterate(...args) {\n // tslint:disable-next-line:no-this-assignment\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n // Map this double-proxy back to the original, so other cursor methods work.\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n // If one of the advancing methods was not called, call continue().\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return ((prop === Symbol.asyncIterator &&\n instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","import { create, type StateCreator } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport { newLogger, type Logger, type LogLevel } from './logger';\nimport { orderFor, findApi, findChanges, tryAddToPendingChanges, tryUpdateConflicts, resolveConflict, sleep } from './helpers';\nimport {\n type ApiFunctions,\n type SyncOptions,\n type SyncState,\n type SyncedStateCreator,\n type PendingChange,\n type UseStoreWithSync,\n type MissingRemoteRecordStrategy,\n type ConflictResolutionStrategy,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\nimport { startFirstLoad } from './firstLoad';\n\nexport { createIndexedDBStorage } from './indexedDBStorage';\nexport { createLocalId, changeKeysTo, changeKeysFrom } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n Create = 'create',\n Update = 'update',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 2000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_STRATEGY: MissingRemoteRecordStrategy = 'ignore';\nconst DEFAULT_CONFLICT_RESOLUTION_STRATEGY: ConflictResolutionStrategy = 'local-wins';\n\nexport function createWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n): Promise<UseStoreWithSync<TStore>> {\n const store = create(persistWithSync(stateCreator, persistOptions, syncApi, syncOptions)) as UseStoreWithSync<TStore>;\n\n return new Promise<UseStoreWithSync<TStore>>((resolve) => {\n store.persist.onFinishHydration((_state) => {\n resolve(store);\n });\n });\n}\n\nexport function persistWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n) {\n const syncInterval = syncOptions.syncInterval ?? DEFAULT_SYNC_INTERVAL_MILLIS;\n const missingStrategy = syncOptions.missingRemoteRecordDuringUpdateStrategy ?? DEFAULT_MISSING_REMOTE_RECORD_STRATEGY;\n const conflictResolutionStrategy = syncOptions.conflictResolutionStrategy ?? DEFAULT_CONFLICT_RESOLUTION_STRATEGY;\n const logger = newLogger(syncOptions.logger ?? DEFAULT_LOGGER, syncOptions.minLogLevel ?? DEFAULT_MIN_LOG_LEVEL);\n\n const baseOnRehydrate = persistOptions?.onRehydrateStorage;\n const basePartialize = persistOptions?.partialize;\n\n const wrappedPersistOptions = {\n ...persistOptions,\n onRehydrateStorage: () => {\n logger.debug('[zync] rehydration:start');\n\n return (state: any, error: any) => {\n if (error) {\n logger.error('[zync] rehydration:failed', error);\n } else {\n baseOnRehydrate?.(state, error);\n logger.debug('[zync] rehydration:complete', state);\n }\n };\n },\n partialize: (s: any) => {\n // Select state to be persisted\n\n const base = basePartialize ? basePartialize(s) : s;\n const { syncState, ...rest } = base || {};\n return {\n ...rest,\n syncState: {\n firstLoadDone: syncState.firstLoadDone,\n pendingChanges: syncState.pendingChanges,\n lastPulled: syncState.lastPulled,\n conflicts: syncState.conflicts,\n },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly asynchronously e.g. IndexedDB)\n // `current` is what the user has defined (they may have added or removed state keys)\n // Zync is designed to not be used until hydration is complete, so we don't expect to have to\n // merge user mutated state (i.e. current) into persisted. So we do the Zustand recommended pattern of\n // shallow copy where persisted keys win:\n const state = { ...current, ...persisted };\n\n return {\n ...state,\n syncState: {\n ...(state.syncState || {}),\n status: 'idle', // this confirms 'hydrating' is done\n },\n };\n },\n };\n\n const creator: StateCreator<TStore & SyncState, [], []> = (set: any, get: any, storeApi: any) => {\n let syncTimerStarted = false;\n\n async function syncOnce() {\n if (get().syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let firstSyncError: Error | undefined;\n\n // 1) PULL for each stateKey\n for (const stateKey of Object.keys(syncApi)) {\n try {\n const api = findApi(stateKey, syncApi);\n await pull(set, get, stateKey, api, logger, conflictResolutionStrategy);\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] pull:error stateKey=${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const changesSnapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen first\n changesSnapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of changesSnapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n setAndQueueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] push:error change=${change}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'idle',\n error: firstSyncError,\n } as SyncState['syncState'],\n }));\n }\n\n function setAndQueueToSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => newSyncState(state, partial(state)));\n } else {\n set((state: any) => newSyncState(state, partial));\n }\n }\n\n function newSyncState(state: any, partial: any) {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n\n Object.keys(partial).map((stateKey) => {\n const current = state[stateKey];\n const updated = partial[stateKey];\n const changes = findChanges(current, updated); // find additions, deletions & updates\n tryAddToPendingChanges(pendingChanges, stateKey, changes);\n });\n\n // Prevent stale conflicts reporting old values to user\n const conflicts = tryUpdateConflicts(pendingChanges, state.syncState.conflicts);\n\n return {\n ...partial,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts,\n } as SyncState['syncState'],\n };\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: enabled ? 'idle' : 'disabled',\n },\n }));\n\n startSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function startSyncTimer(start: boolean) {\n if (start) {\n tryStart(); // Unawaited async\n } else {\n syncTimerStarted = false;\n }\n }\n\n async function tryStart() {\n if (syncTimerStarted) return;\n syncTimerStarted = true;\n\n while (true) {\n if (!syncTimerStarted) break;\n await syncOnce();\n await sleep(syncInterval);\n }\n }\n\n function addVisibilityChangeListener(add: boolean) {\n if (add) {\n document.addEventListener('visibilitychange', onVisibilityChange);\n } else {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n }\n }\n\n function onVisibilityChange() {\n if (document.visibilityState === 'visible') {\n logger.debug('[zync] sync:start-in-foreground');\n startSyncTimer(true);\n } else {\n logger.debug('[zync] sync:pause-in-background');\n startSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad: () => startFirstLoad(set, syncApi, logger),\n resolveConflict: (localId: string, keepLocal: boolean) => resolveConflict(set, localId, keepLocal),\n };\n\n const userState = stateCreator(set, get, setAndQueueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n conflicts: undefined,\n firstLoadDone: false,\n pendingChanges: [],\n lastPulled: {},\n },\n } as TStore & SyncState;\n };\n\n return persist(creator, wrappedPersistOptions);\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\nexport interface Logger {\n debug: (...args: any[]) => void;\n info: (...args: any[]) => void;\n warn: (...args: any[]) => void;\n error: (...args: any[]) => void;\n}\n\nexport function newLogger(base: Logger, min: LogLevel): Logger {\n const order: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n none: 100,\n };\n const threshold = order[min];\n const enabled = (lvl: LogLevel) => order[lvl] >= threshold;\n return {\n debug: (...a: any[]) => enabled('debug') && base.debug?.(...a),\n info: (...a: any[]) => enabled('info') && base.info?.(...a),\n warn: (...a: any[]) => enabled('warn') && base.warn?.(...a),\n error: (...a: any[]) => enabled('error') && base.error?.(...a),\n };\n}\n","import { SyncAction } from './index';\nimport type { ApiFunctions, Conflict, FieldConflict, PendingChange, SyncState } from './types';\n\nconst SYNC_FIELDS = ['_localId', 'updated_at', 'deleted'] as const;\n\nexport function createLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function changeKeysTo(input: any | any[], toIdKey: string, toUpdatedAtKey: string, toDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { id, updated_at, deleted, ...rest } = item;\n return {\n [toIdKey]: id,\n [toUpdatedAtKey]: updated_at,\n [toDeletedKey]: deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function changeKeysFrom(input: any | any[], fromIdKey: string, fromUpdatedAtKey: string, fromDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { [fromIdKey]: id, [fromUpdatedAtKey]: updated_at, [fromDeletedKey]: deleted, ...rest } = item;\n return {\n id,\n updated_at,\n deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.Create:\n return 1;\n case SyncAction.Update:\n return 2;\n case SyncAction.Remove:\n return 3;\n }\n}\n\nexport function omitSyncFields(item: any) {\n const result = { ...item };\n for (const k of SYNC_FIELDS) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const pending: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = pending.find((p) => p.localId === localId && p.stateKey === stateKey);\n return curChange?.version === version;\n}\n\nexport function removeFromPendingChanges(set: any, localId: string, stateKey: string) {\n set((s: any) => {\n const queue: PendingChange[] = (s.syncState.pendingChanges || []).filter((p: PendingChange) => !(p.localId === localId && p.stateKey === stateKey));\n return {\n syncState: {\n ...(s.syncState || {}),\n pendingChanges: queue,\n },\n };\n });\n}\n\nexport function tryAddToPendingChanges(pendingChanges: PendingChange[], stateKey: string, changes: Map<string, ChangeRecord>) {\n for (const [localId, change] of changes) {\n let omittedItem = omitSyncFields(change.changes);\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n const hasChanges = Object.keys(omittedItem).length > 0;\n const action = change.updatedItem === null ? SyncAction.Remove : change.currentItem === null ? SyncAction.Create : SyncAction.Update;\n\n if (action === SyncAction.Update && change.updatedItem && change.currentItem && change.currentItem._localId !== change.updatedItem._localId) {\n // Here when insert-remote-record swaps local remotely deleted item with a fresh copy to push up\n omittedItem = omitSyncFields(change.updatedItem);\n }\n\n if (queueItem) {\n if (queueItem.action === SyncAction.Remove) {\n // Once a Remove is queued, it stays a Remove\n continue;\n }\n\n queueItem.version += 1;\n\n if (action === SyncAction.Remove) {\n queueItem.action = SyncAction.Remove;\n } else if (hasChanges) {\n // Never change the action here, it stays Create or Update and is removed when synced\n queueItem.changes = { ...queueItem.changes, ...omittedItem };\n }\n } else if (action === SyncAction.Remove || hasChanges) {\n pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem, before: omitSyncFields(change.currentItem) });\n }\n }\n}\n\nexport function setPendingChangeToUpdate(get: any, stateKey: string, localId: string, id?: any) {\n // id is optional as the user may client assign the id, but not return it from the api\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.action = SyncAction.Update;\n if (id) change.id = id;\n }\n}\n\nexport function setPendingChangeBefore(get: any, stateKey: string, localId: string, before: any) {\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.before = { ...change.before, ...before };\n }\n}\n\nexport function tryUpdateConflicts(pendingChanges: PendingChange[], conflicts?: Record<string, Conflict>): Record<string, Conflict> | undefined {\n if (!conflicts) return conflicts;\n\n const newConflicts = { ...conflicts };\n\n for (const change of pendingChanges) {\n const conflict = newConflicts[change.localId];\n if (conflict && change.changes) {\n // Loop changed fields and update their old possibly stale value to the current local value\n const newFields = conflict.fields.map((f) => {\n if (f.key in change.changes) {\n return { ...f, localValue: change.changes[f.key] } as FieldConflict;\n }\n return f;\n });\n\n newConflicts[change.localId] = { stateKey: conflict.stateKey, fields: newFields };\n }\n }\n\n return newConflicts;\n}\n\nexport function findApi(stateKey: string, syncApi: Record<string, ApiFunctions>) {\n const api = syncApi[stateKey];\n if (!api || !api.add || !api.update || !api.remove || !api.list || !api.firstLoad) {\n throw new Error(`Missing API function(s) for state key: ${stateKey}.`);\n }\n return api;\n}\n\ntype ChangeRecord = {\n currentItem?: any;\n updatedItem?: any;\n changes: any;\n id?: any;\n};\n\n/**\n * Compares the top-level keys of items in `current` and `updated` arrays (assumed to have `_localId`).\n * Returns a Map where the key is `_localId` and the value is an object with:\n * - `currentItem`: The item from `current` (or `null` for additions).\n * - `updatedItem`: The item from `updated` (or `null` for deletions).\n * - `changes`: An object with differing top-level keys and their values (or the full item for additions, or `null` for deletions).\n */\nexport function findChanges(current: any[], updated: any[]): Map<string, ChangeRecord> {\n const currentMap = new Map<string, any>();\n for (const item of current) {\n if (item && item._localId) {\n currentMap.set(item._localId, { ...item });\n }\n }\n\n const changesMap = new Map<string, ChangeRecord>();\n\n // Check for changes and additions\n for (const update of updated) {\n const item = { ...update };\n if (item && item._localId) {\n const curr = currentMap.get(item._localId);\n if (curr) {\n const diff: any = {};\n for (const key in curr) {\n if (key !== '_localId' && curr[key] !== item[key]) {\n diff[key] = item[key];\n }\n }\n if (Object.keys(diff).length > 0) {\n // Changes\n changesMap.set(item._localId, { currentItem: curr, updatedItem: item, changes: diff, id: curr.id ?? item.id });\n }\n } else {\n // Addition\n changesMap.set(item._localId, { currentItem: null, updatedItem: item, changes: item, id: item.id });\n }\n }\n }\n\n // Check for deletions\n for (const [localId, curr] of currentMap) {\n if (!updated.some((u) => u && u._localId === localId)) {\n changesMap.set(localId, { currentItem: curr, updatedItem: null, changes: null, id: curr.id });\n }\n }\n\n return changesMap;\n}\n\nexport function hasKeysOrUndefined(obj: any): any {\n return Object.keys(obj).length === 0 ? undefined : obj;\n}\n\nexport function hasConflicts(get: any, localId: string): boolean {\n const state = get() as SyncState;\n if (state.syncState.conflicts) {\n return !!state.syncState.conflicts[localId];\n }\n return false;\n}\n\nexport function resolveConflict(set: any, localId: string, keepLocalFields: boolean) {\n set((state: any) => {\n const syncState: SyncState['syncState'] = state.syncState || {};\n const conflicts: Record<string, Conflict> = syncState.conflicts || {};\n const conflict = conflicts[localId];\n if (conflict) {\n const items = state[conflict.stateKey];\n const item = items.find((i: any) => i._localId === localId);\n if (!item) {\n return state;\n }\n\n const resolved: any = { ...item };\n let pendingChanges = [...syncState.pendingChanges];\n\n if (!keepLocalFields) {\n // Use remote value(s)\n for (const field of conflict.fields) {\n resolved[field.key] = field.remoteValue;\n }\n\n // Remove resolved pending change\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === conflict.stateKey && p.localId === localId));\n }\n\n // Replace with resolved item\n const nextItems = items.map((i: any) => (i._localId === localId ? resolved : i));\n const nextConflicts = { ...conflicts };\n delete nextConflicts[localId];\n\n return {\n [conflict.stateKey]: nextItems,\n syncState: {\n ...syncState,\n pendingChanges,\n conflicts: hasKeysOrUndefined(nextConflicts),\n },\n };\n }\n return state;\n });\n}\n","import { type ApiFunctions, type FieldConflict, type ConflictResolutionStrategy, type SyncedRecord, type PendingChange } from './types';\nimport { SyncAction } from './index';\nimport { createLocalId, hasKeysOrUndefined } from './helpers';\nimport type { Logger } from './logger';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: Logger, conflictResolutionStrategy: ConflictResolutionStrategy) {\n const lastPulled: Record<string, string> = get().syncState.lastPulled || {};\n const lastPulledAt = new Date(lastPulled[stateKey] || new Date(0));\n\n logger.debug(`[zync] pull:start stateKey=${stateKey} since=${lastPulledAt.toISOString()}`);\n\n const serverData = (await api.list(lastPulledAt)) as SyncedRecord[];\n if (!serverData?.length) return;\n\n let newest = lastPulledAt;\n\n set((state: any) => {\n let pendingChanges = [...(state.syncState.pendingChanges as PendingChange[])];\n const conflicts = { ...state.syncState.conflicts };\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items when pulling them again\n const pendingRemovalById = new Set(pendingChanges.filter((p) => p.stateKey === stateKey && p.action === SyncAction.Remove).map((p) => p.id));\n\n for (const remote of serverData) {\n const remoteUpdated = new Date(remote.updated_at);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n // If a Remove is pending for this localId, skip merging/adding to avoid briefly resurrecting the item\n if (pendingRemovalById.has(remote.id)) {\n logger.debug(`[zync] pull:skip-pending-remove stateKey=${stateKey} id=${remote.id}`);\n continue;\n }\n\n const localItem = localById.get(remote.id);\n if (remote.deleted) {\n if (localItem) {\n nextItems = nextItems.filter((i: any) => i.id !== remote.id);\n logger.debug(`[zync] pull:remove stateKey=${stateKey} id=${remote.id}`);\n }\n continue;\n }\n\n delete remote.deleted;\n\n if (localItem) {\n const pendingChange = pendingChanges.find((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (pendingChange) {\n logger.debug(`[zync] pull:conflict-strategy:${conflictResolutionStrategy} stateKey=${stateKey} id=${remote.id}`);\n\n switch (conflictResolutionStrategy) {\n case 'local-wins':\n // Ignore remote changes, keep local\n break;\n\n case 'remote-wins': {\n // Ignore local changes, keep remote\n const merged = { ...remote, _localId: localItem._localId };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Remove pending change so it isn't pushed after pull\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === stateKey && p.localId === localItem._localId));\n break;\n }\n\n case 'try-shallow-merge': {\n // List fields that local and remote have changed\n const changes = pendingChange.changes || {};\n const before = pendingChange.before || {};\n const fields: FieldConflict[] = Object.entries(changes)\n .filter(([k, localValue]) => k in before && k in remote && before[k] !== remote[k] && localValue !== remote[k])\n .map(([key, localValue]) => ({ key, localValue, remoteValue: remote[key] }));\n\n if (fields.length > 0) {\n logger.warn(`[zync] pull:${conflictResolutionStrategy}:conflicts-found`, JSON.stringify(fields, null, 4));\n conflicts[localItem._localId] = { stateKey, fields };\n } else {\n // No conflicts, merge remote into local but only preserve fields that were\n // actually changed locally\n const localChangedKeys = Object.keys(changes);\n const preservedLocal: any = { _localId: localItem._localId };\n for (const k of localChangedKeys) {\n if (k in localItem) preservedLocal[k] = localItem[k];\n }\n\n const merged = { ...remote, ...preservedLocal };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Merge now resolved, drop pending and conflict\n delete conflicts[localItem._localId];\n }\n break;\n }\n }\n } else {\n // No pending changes, merge remote into local\n const merged = { ...localItem, ...remote };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[zync] pull:merge-remote stateKey=${stateKey} id=${remote.id}`);\n }\n } else {\n // Add remote item (no local item)\n nextItems = [...nextItems, { ...remote, _localId: createLocalId() }];\n logger.debug(`[zync] pull:add stateKey=${stateKey} id=${remote.id}`);\n }\n }\n\n return {\n [stateKey]: nextItems,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts: hasKeysOrUndefined(conflicts),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { hasConflicts, removeFromPendingChanges, samePendingVersion, setPendingChangeBefore, setPendingChangeToUpdate } from './helpers';\nimport { createLocalId, SyncAction } from './index';\nimport type { Logger } from './logger';\nimport type {\n AfterRemoteAddCallback,\n ApiFunctions,\n MissingRemoteRecordStrategy,\n MissingRemoteRecordDuringUpdateCallback,\n PendingChange,\n SetAndSyncCallback,\n} from './types';\n\nexport async function pushOne(\n set: any,\n get: any,\n change: PendingChange,\n api: ApiFunctions,\n logger: Logger,\n setAndQueueToSync: SetAndSyncCallback,\n missingStrategy: MissingRemoteRecordStrategy,\n onMissingRemoteRecordDuringUpdate?: MissingRemoteRecordDuringUpdateCallback,\n onAfterRemoteAdd?: AfterRemoteAddCallback,\n) {\n logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version, changes } = change;\n\n switch (action) {\n case SyncAction.Remove:\n if (!id) {\n logger.warn(`[zync] push:remove:no-id stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n await api.remove(id);\n logger.debug(`[zync] push:remove:success stateKey=${stateKey} localId=${localId} id=${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.Update: {\n if (hasConflicts(get, change.localId)) {\n logger.warn(`[zync] push:update:skipping-with-conflicts stateKey=${stateKey} localId=${localId} id=${id}`);\n return;\n }\n\n const exists = await api.update(id, changes);\n if (exists) {\n logger.debug(`[zync] push:update:success stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure pending.before is not stale for conflict resolution\n setPendingChangeBefore(get, stateKey, localId, changes);\n }\n return;\n } else {\n const state = get();\n const items: any[] = state[stateKey] || [];\n const item = items.find((i) => i._localId === localId);\n if (!item) {\n logger.warn(`[zync] push:missing-remote:no-local-item stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n switch (missingStrategy) {\n case 'delete-local-record':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n case 'insert-remote-record': {\n const newItem = {\n ...item,\n _localId: createLocalId(),\n updated_at: new Date().toISOString(),\n };\n\n // replace old with modified and queue Create\n setAndQueueToSync((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? newItem : i)),\n }));\n\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${newItem.id}`);\n break;\n }\n\n case 'ignore':\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n default:\n logger.error(`[zync] push:missing-remote:unknown-strategy stateKey=${stateKey} id=${item.id} strategy=${missingStrategy}`);\n break;\n }\n\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, item);\n }\n break;\n }\n\n case SyncAction.Create: {\n const result = await api.add(changes);\n if (result) {\n logger.debug(`[zync] push:create:success stateKey=${stateKey} localId=${localId} id=${id}`);\n\n // Merge server-assigned fields (id, updated_at, etc) directly into local entity\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? { ...i, ...result } : i)),\n }));\n\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure any pendingChanges entry has id and is now an Update\n setPendingChangeToUpdate(get, stateKey, localId, result.id);\n }\n\n const finalItem = { ...changes, ...result, _localId: localId };\n\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, setAndQueueToSync, stateKey, finalItem);\n } else {\n logger.warn(`[zync] push:create:no-result stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\n }\n }\n}\n","import { findApi, createLocalId } from './helpers';\nimport type { Logger } from './logger';\nimport type { ApiFunctions } from './types';\n\nexport async function startFirstLoad(set: any, syncApi: Record<string, ApiFunctions>, logger: Logger) {\n let syncError: Error | undefined;\n\n for (const stateKey of Object.keys(syncApi)) {\n try {\n logger.info(`[zync] firstLoad:start stateKey=${stateKey}`);\n\n const api = findApi(stateKey, syncApi);\n let lastId; // Start as undefined to allow the userland api code to set the initial value+type\n\n // Batch until empty\n while (true) {\n const batch = await api.firstLoad(lastId);\n if (!batch?.length) break;\n\n // Merge batch\n set((state: any) => {\n const local: any[] = state[stateKey] || [];\n const localById = new Map<any, any>(local.filter((l) => l.id).map((l) => [l.id, l]));\n\n let newest = new Date(state.syncState.lastPulled[stateKey] || 0);\n const next = [...local];\n for (const remote of batch) {\n const remoteUpdated = new Date(remote.updated_at || 0);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n if (remote.deleted) continue;\n\n delete remote.deleted;\n\n const localItem = remote.id ? localById.get(remote.id) : undefined;\n if (localItem) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n const idx = next.findIndex((i) => i._localId === localItem._localId);\n if (idx >= 0) next[idx] = merged;\n } else {\n next.push({\n ...remote,\n _localId: createLocalId(),\n });\n }\n }\n\n return {\n [stateKey]: next,\n syncState: {\n ...(state.syncState || {}),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n\n if (lastId !== undefined && lastId === batch[batch.length - 1].id) {\n throw new Error(`Duplicate records downloaded, stopping to prevent infinite loop`);\n }\n\n lastId = batch[batch.length - 1].id;\n }\n\n logger.info(`[zync] firstLoad:done stateKey=${stateKey}`);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[zync] firstLoad:error stateKey=${stateKey}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n firstLoadDone: true,\n error: syncError,\n },\n }));\n}\n","import type { IDBPDatabase } from 'idb';\n\nexport function createIndexedDBStorage(options: { dbName: string; storeName: string }) {\n const dbName = options.dbName;\n const storeName = options.storeName;\n\n // dbPromise is created lazily by initDB() to avoid pulling `idb` into bundles\n let dbPromise: Promise<IDBPDatabase<any>> | null = null;\n\n async function initDB(): Promise<IDBPDatabase<any>> {\n if (dbPromise) return dbPromise;\n try {\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, 1, {\n upgrade(db: IDBPDatabase<any>) {\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName);\n }\n },\n });\n return dbPromise;\n } catch (_e) {\n throw new Error('Missing optional dependency \"idb\". Install it to use IndexedDB storage: npm install idb');\n }\n }\n\n async function ensureStore(): Promise<void> {\n const db = await initDB();\n if (db.objectStoreNames.contains(storeName)) return;\n const nextVersion = (db.version || 0) + 1;\n try {\n db.close();\n } catch (_e) {\n // ignore\n }\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, nextVersion, {\n upgrade(upg: IDBPDatabase<any>) {\n if (!upg.objectStoreNames.contains(storeName)) upg.createObjectStore(storeName);\n },\n });\n await dbPromise;\n }\n\n async function withRetry<T>(fn: (db: IDBPDatabase<any>) => Promise<T>): Promise<T> {\n try {\n const db = await initDB();\n return await fn(db);\n } catch (err: any) {\n const msg = String(err && err.message ? err.message : err);\n if (err && (err.name === 'NotFoundError' || /objectStore/i.test(msg))) {\n await ensureStore();\n const db2 = await initDB();\n return await fn(db2);\n }\n throw err;\n }\n }\n\n return {\n getItem: async (name: string): Promise<string | null> => {\n return withRetry(async (db) => {\n let v = await db.get(storeName, name);\n v = v ?? null; // Zustand expects null for missing keys\n return v;\n });\n },\n setItem: async (name: string, value: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.put(storeName, value, name);\n });\n },\n removeItem: async (name: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.delete(storeName, name);\n });\n },\n };\n}\n"],"mappings":"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","names":["target","SyncAction"]}
|
|
1
|
+
{"version":3,"sources":["../node_modules/.pnpm/idb@8.0.3/node_modules/idb/build/index.js","../src/index.ts","../src/logger.ts","../src/helpers.ts","../src/pull.ts","../src/push.ts","../src/firstLoad.ts","../src/indexedDBStorage.ts"],"sourcesContent":["const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey,\n ]));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event.newVersion, event));\n }\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking) {\n db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event));\n }\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function (...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n },\n};\nasync function* iterate(...args) {\n // tslint:disable-next-line:no-this-assignment\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n // Map this double-proxy back to the original, so other cursor methods work.\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n // If one of the advancing methods was not called, call continue().\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return ((prop === Symbol.asyncIterator &&\n instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","import { create, type StateCreator } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport { newLogger, type Logger, type LogLevel } from './logger';\nimport { orderFor, findApi, findChanges, tryAddToPendingChanges, tryUpdateConflicts, resolveConflict, sleep } from './helpers';\nimport {\n type ApiFunctions,\n type SyncOptions,\n type SyncState,\n type SyncedStateCreator,\n type PendingChange,\n type UseStoreWithSync,\n type MissingRemoteRecordStrategy,\n type ConflictResolutionStrategy,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\nimport { startFirstLoad } from './firstLoad';\n\nexport { createIndexedDB } from './indexedDBStorage';\nexport { createLocalId, changeKeysTo, changeKeysFrom } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n Create = 'create',\n Update = 'update',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 2000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_STRATEGY: MissingRemoteRecordStrategy = 'ignore';\nconst DEFAULT_CONFLICT_RESOLUTION_STRATEGY: ConflictResolutionStrategy = 'local-wins';\n\nexport function createWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n): Promise<UseStoreWithSync<TStore>> {\n const store = create(persistWithSync(stateCreator, persistOptions, syncApi, syncOptions)) as UseStoreWithSync<TStore>;\n\n return new Promise<UseStoreWithSync<TStore>>((resolve) => {\n store.persist.onFinishHydration((_state) => {\n resolve(store);\n });\n });\n}\n\nexport function persistWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n) {\n const syncInterval = syncOptions.syncInterval ?? DEFAULT_SYNC_INTERVAL_MILLIS;\n const missingStrategy = syncOptions.missingRemoteRecordDuringUpdateStrategy ?? DEFAULT_MISSING_REMOTE_RECORD_STRATEGY;\n const conflictResolutionStrategy = syncOptions.conflictResolutionStrategy ?? DEFAULT_CONFLICT_RESOLUTION_STRATEGY;\n const logger = newLogger(syncOptions.logger ?? DEFAULT_LOGGER, syncOptions.minLogLevel ?? DEFAULT_MIN_LOG_LEVEL);\n\n const baseOnRehydrate = persistOptions?.onRehydrateStorage;\n const basePartialize = persistOptions?.partialize;\n\n const wrappedPersistOptions = {\n ...persistOptions,\n onRehydrateStorage: () => {\n logger.debug('[zync] rehydration:start');\n\n return (state: any, error: any) => {\n if (error) {\n logger.error('[zync] rehydration:failed', error);\n } else {\n baseOnRehydrate?.(state, error);\n logger.debug('[zync] rehydration:complete', state);\n }\n };\n },\n partialize: (s: any) => {\n // Select state to be persisted\n\n const base = basePartialize ? basePartialize(s) : s;\n const { syncState, ...rest } = base || {};\n return {\n ...rest,\n syncState: {\n firstLoadDone: syncState.firstLoadDone,\n pendingChanges: syncState.pendingChanges,\n lastPulled: syncState.lastPulled,\n conflicts: syncState.conflicts,\n },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly asynchronously e.g. IndexedDB)\n // `current` is what the user has defined (they may have added or removed state keys)\n // Zync is designed to not be used until hydration is complete, so we don't expect to have to\n // merge user mutated state (i.e. current) into persisted. So we do the Zustand recommended pattern of\n // shallow copy where persisted keys win:\n const state = { ...current, ...persisted };\n\n return {\n ...state,\n syncState: {\n ...(state.syncState || {}),\n status: 'idle', // this confirms 'hydrating' is done\n },\n };\n },\n };\n\n const creator: StateCreator<TStore & SyncState, [], []> = (set: any, get: any, storeApi: any) => {\n let syncTimerStarted = false;\n\n async function syncOnce() {\n if (get().syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let firstSyncError: Error | undefined;\n\n // 1) PULL for each stateKey\n for (const stateKey of Object.keys(syncApi)) {\n try {\n const api = findApi(stateKey, syncApi);\n await pull(set, get, stateKey, api, logger, conflictResolutionStrategy);\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] pull:error stateKey=${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const changesSnapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen first\n changesSnapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of changesSnapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n setAndQueueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] push:error change=${change}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'idle',\n error: firstSyncError,\n } as SyncState['syncState'],\n }));\n }\n\n function setAndQueueToSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => newSyncState(state, partial(state)));\n } else {\n set((state: any) => newSyncState(state, partial));\n }\n }\n\n function newSyncState(state: any, partial: any) {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n\n Object.keys(partial).map((stateKey) => {\n const current = state[stateKey];\n const updated = partial[stateKey];\n const changes = findChanges(current, updated); // find additions, deletions & updates\n tryAddToPendingChanges(pendingChanges, stateKey, changes);\n });\n\n // Prevent stale conflicts reporting old values to user\n const conflicts = tryUpdateConflicts(pendingChanges, state.syncState.conflicts);\n\n return {\n ...partial,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts,\n } as SyncState['syncState'],\n };\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: enabled ? 'idle' : 'disabled',\n },\n }));\n\n startSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function startSyncTimer(start: boolean) {\n if (start) {\n tryStart(); // Unawaited async\n } else {\n syncTimerStarted = false;\n }\n }\n\n async function tryStart() {\n if (syncTimerStarted) return;\n syncTimerStarted = true;\n\n while (true) {\n if (!syncTimerStarted) break;\n await syncOnce();\n await sleep(syncInterval);\n }\n }\n\n function addVisibilityChangeListener(add: boolean) {\n if (add) {\n document.addEventListener('visibilitychange', onVisibilityChange);\n } else {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n }\n }\n\n function onVisibilityChange() {\n if (document.visibilityState === 'visible') {\n logger.debug('[zync] sync:start-in-foreground');\n startSyncTimer(true);\n } else {\n logger.debug('[zync] sync:pause-in-background');\n startSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad: () => startFirstLoad(set, syncApi, logger),\n resolveConflict: (localId: string, keepLocal: boolean) => resolveConflict(set, localId, keepLocal),\n };\n\n const userState = stateCreator(set, get, setAndQueueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n conflicts: undefined,\n firstLoadDone: false,\n pendingChanges: [],\n lastPulled: {},\n },\n } as TStore & SyncState;\n };\n\n return persist(creator, wrappedPersistOptions);\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\nexport interface Logger {\n debug: (...args: any[]) => void;\n info: (...args: any[]) => void;\n warn: (...args: any[]) => void;\n error: (...args: any[]) => void;\n}\n\nexport function newLogger(base: Logger, min: LogLevel): Logger {\n const order: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n none: 100,\n };\n const threshold = order[min];\n const enabled = (lvl: LogLevel) => order[lvl] >= threshold;\n return {\n debug: (...a: any[]) => enabled('debug') && base.debug?.(...a),\n info: (...a: any[]) => enabled('info') && base.info?.(...a),\n warn: (...a: any[]) => enabled('warn') && base.warn?.(...a),\n error: (...a: any[]) => enabled('error') && base.error?.(...a),\n };\n}\n","import { SyncAction } from './index';\nimport type { ApiFunctions, Conflict, FieldConflict, PendingChange, SyncState } from './types';\n\nconst SYNC_FIELDS = ['_localId', 'updated_at', 'deleted'] as const;\n\nexport function createLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function changeKeysTo(input: any | any[], toIdKey: string, toUpdatedAtKey: string, toDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { id, updated_at, deleted, ...rest } = item;\n return {\n [toIdKey]: id,\n [toUpdatedAtKey]: updated_at,\n [toDeletedKey]: deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function changeKeysFrom(input: any | any[], fromIdKey: string, fromUpdatedAtKey: string, fromDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { [fromIdKey]: id, [fromUpdatedAtKey]: updated_at, [fromDeletedKey]: deleted, ...rest } = item;\n return {\n id,\n updated_at,\n deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.Create:\n return 1;\n case SyncAction.Update:\n return 2;\n case SyncAction.Remove:\n return 3;\n }\n}\n\nexport function omitSyncFields(item: any) {\n const result = { ...item };\n for (const k of SYNC_FIELDS) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const pending: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = pending.find((p) => p.localId === localId && p.stateKey === stateKey);\n return curChange?.version === version;\n}\n\nexport function removeFromPendingChanges(set: any, localId: string, stateKey: string) {\n set((s: any) => {\n const queue: PendingChange[] = (s.syncState.pendingChanges || []).filter((p: PendingChange) => !(p.localId === localId && p.stateKey === stateKey));\n return {\n syncState: {\n ...(s.syncState || {}),\n pendingChanges: queue,\n },\n };\n });\n}\n\nexport function tryAddToPendingChanges(pendingChanges: PendingChange[], stateKey: string, changes: Map<string, ChangeRecord>) {\n for (const [localId, change] of changes) {\n let omittedItem = omitSyncFields(change.changes);\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n const hasChanges = Object.keys(omittedItem).length > 0;\n const action = change.updatedItem === null ? SyncAction.Remove : change.currentItem === null ? SyncAction.Create : SyncAction.Update;\n\n if (action === SyncAction.Update && change.updatedItem && change.currentItem && change.currentItem._localId !== change.updatedItem._localId) {\n // Here when insert-remote-record swaps local remotely deleted item with a fresh copy to push up\n omittedItem = omitSyncFields(change.updatedItem);\n }\n\n if (queueItem) {\n if (queueItem.action === SyncAction.Remove) {\n // Once a Remove is queued, it stays a Remove\n continue;\n }\n\n queueItem.version += 1;\n\n if (action === SyncAction.Remove) {\n queueItem.action = SyncAction.Remove;\n } else if (hasChanges) {\n // Never change the action here, it stays Create or Update and is removed when synced\n queueItem.changes = { ...queueItem.changes, ...omittedItem };\n }\n } else if (action === SyncAction.Remove || hasChanges) {\n pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem, before: omitSyncFields(change.currentItem) });\n }\n }\n}\n\nexport function setPendingChangeToUpdate(get: any, stateKey: string, localId: string, id?: any) {\n // id is optional as the user may client assign the id, but not return it from the api\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.action = SyncAction.Update;\n if (id) change.id = id;\n }\n}\n\nexport function setPendingChangeBefore(get: any, stateKey: string, localId: string, before: any) {\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.before = { ...change.before, ...before };\n }\n}\n\nexport function tryUpdateConflicts(pendingChanges: PendingChange[], conflicts?: Record<string, Conflict>): Record<string, Conflict> | undefined {\n if (!conflicts) return conflicts;\n\n const newConflicts = { ...conflicts };\n\n for (const change of pendingChanges) {\n const conflict = newConflicts[change.localId];\n if (conflict && change.changes) {\n // Loop changed fields and update their old possibly stale value to the current local value\n const newFields = conflict.fields.map((f) => {\n if (f.key in change.changes) {\n return { ...f, localValue: change.changes[f.key] } as FieldConflict;\n }\n return f;\n });\n\n newConflicts[change.localId] = { stateKey: conflict.stateKey, fields: newFields };\n }\n }\n\n return newConflicts;\n}\n\nexport function findApi(stateKey: string, syncApi: Record<string, ApiFunctions>) {\n const api = syncApi[stateKey];\n if (!api || !api.add || !api.update || !api.remove || !api.list || !api.firstLoad) {\n throw new Error(`Missing API function(s) for state key: ${stateKey}.`);\n }\n return api;\n}\n\ntype ChangeRecord = {\n currentItem?: any;\n updatedItem?: any;\n changes: any;\n id?: any;\n};\n\n/**\n * Compares the top-level keys of items in `current` and `updated` arrays (assumed to have `_localId`).\n * Returns a Map where the key is `_localId` and the value is an object with:\n * - `currentItem`: The item from `current` (or `null` for additions).\n * - `updatedItem`: The item from `updated` (or `null` for deletions).\n * - `changes`: An object with differing top-level keys and their values (or the full item for additions, or `null` for deletions).\n */\nexport function findChanges(current: any[], updated: any[]): Map<string, ChangeRecord> {\n const currentMap = new Map<string, any>();\n for (const item of current) {\n if (item && item._localId) {\n currentMap.set(item._localId, { ...item });\n }\n }\n\n const changesMap = new Map<string, ChangeRecord>();\n\n // Check for changes and additions\n for (const update of updated) {\n const item = { ...update };\n if (item && item._localId) {\n const curr = currentMap.get(item._localId);\n if (curr) {\n const diff: any = {};\n for (const key in curr) {\n if (key !== '_localId' && curr[key] !== item[key]) {\n diff[key] = item[key];\n }\n }\n if (Object.keys(diff).length > 0) {\n // Changes\n changesMap.set(item._localId, { currentItem: curr, updatedItem: item, changes: diff, id: curr.id ?? item.id });\n }\n } else {\n // Addition\n changesMap.set(item._localId, { currentItem: null, updatedItem: item, changes: item, id: item.id });\n }\n }\n }\n\n // Check for deletions\n for (const [localId, curr] of currentMap) {\n if (!updated.some((u) => u && u._localId === localId)) {\n changesMap.set(localId, { currentItem: curr, updatedItem: null, changes: null, id: curr.id });\n }\n }\n\n return changesMap;\n}\n\nexport function hasKeysOrUndefined(obj: any): any {\n return Object.keys(obj).length === 0 ? undefined : obj;\n}\n\nexport function hasConflicts(get: any, localId: string): boolean {\n const state = get() as SyncState;\n if (state.syncState.conflicts) {\n return !!state.syncState.conflicts[localId];\n }\n return false;\n}\n\nexport function resolveConflict(set: any, localId: string, keepLocalFields: boolean) {\n set((state: any) => {\n const syncState: SyncState['syncState'] = state.syncState || {};\n const conflicts: Record<string, Conflict> = syncState.conflicts || {};\n const conflict = conflicts[localId];\n if (conflict) {\n const items = state[conflict.stateKey];\n const item = items.find((i: any) => i._localId === localId);\n if (!item) {\n return state;\n }\n\n const resolved: any = { ...item };\n let pendingChanges = [...syncState.pendingChanges];\n\n if (!keepLocalFields) {\n // Use remote value(s)\n for (const field of conflict.fields) {\n resolved[field.key] = field.remoteValue;\n }\n\n // Remove resolved pending change\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === conflict.stateKey && p.localId === localId));\n }\n\n // Replace with resolved item\n const nextItems = items.map((i: any) => (i._localId === localId ? resolved : i));\n const nextConflicts = { ...conflicts };\n delete nextConflicts[localId];\n\n return {\n [conflict.stateKey]: nextItems,\n syncState: {\n ...syncState,\n pendingChanges,\n conflicts: hasKeysOrUndefined(nextConflicts),\n },\n };\n }\n return state;\n });\n}\n","import { type ApiFunctions, type FieldConflict, type ConflictResolutionStrategy, type SyncedRecord, type PendingChange } from './types';\nimport { SyncAction } from './index';\nimport { createLocalId, hasKeysOrUndefined } from './helpers';\nimport type { Logger } from './logger';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: Logger, conflictResolutionStrategy: ConflictResolutionStrategy) {\n const lastPulled: Record<string, string> = get().syncState.lastPulled || {};\n const lastPulledAt = new Date(lastPulled[stateKey] || new Date(0));\n\n logger.debug(`[zync] pull:start stateKey=${stateKey} since=${lastPulledAt.toISOString()}`);\n\n const serverData = (await api.list(lastPulledAt)) as SyncedRecord[];\n if (!serverData?.length) return;\n\n let newest = lastPulledAt;\n\n set((state: any) => {\n let pendingChanges = [...(state.syncState.pendingChanges as PendingChange[])];\n const conflicts = { ...state.syncState.conflicts };\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items when pulling them again\n const pendingRemovalById = new Set(pendingChanges.filter((p) => p.stateKey === stateKey && p.action === SyncAction.Remove).map((p) => p.id));\n\n for (const remote of serverData) {\n const remoteUpdated = new Date(remote.updated_at);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n // If a Remove is pending for this localId, skip merging/adding to avoid briefly resurrecting the item\n if (pendingRemovalById.has(remote.id)) {\n logger.debug(`[zync] pull:skip-pending-remove stateKey=${stateKey} id=${remote.id}`);\n continue;\n }\n\n const localItem = localById.get(remote.id);\n if (remote.deleted) {\n if (localItem) {\n nextItems = nextItems.filter((i: any) => i.id !== remote.id);\n logger.debug(`[zync] pull:remove stateKey=${stateKey} id=${remote.id}`);\n }\n continue;\n }\n\n delete remote.deleted;\n\n if (localItem) {\n const pendingChange = pendingChanges.find((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (pendingChange) {\n logger.debug(`[zync] pull:conflict-strategy:${conflictResolutionStrategy} stateKey=${stateKey} id=${remote.id}`);\n\n switch (conflictResolutionStrategy) {\n case 'local-wins':\n // Ignore remote changes, keep local\n break;\n\n case 'remote-wins': {\n // Ignore local changes, keep remote\n const merged = { ...remote, _localId: localItem._localId };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Remove pending change so it isn't pushed after pull\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === stateKey && p.localId === localItem._localId));\n break;\n }\n\n case 'try-shallow-merge': {\n // List fields that local and remote have changed\n const changes = pendingChange.changes || {};\n const before = pendingChange.before || {};\n const fields: FieldConflict[] = Object.entries(changes)\n .filter(([k, localValue]) => k in before && k in remote && before[k] !== remote[k] && localValue !== remote[k])\n .map(([key, localValue]) => ({ key, localValue, remoteValue: remote[key] }));\n\n if (fields.length > 0) {\n logger.warn(`[zync] pull:${conflictResolutionStrategy}:conflicts-found`, JSON.stringify(fields, null, 4));\n conflicts[localItem._localId] = { stateKey, fields };\n } else {\n // No conflicts, merge remote into local but only preserve fields that were\n // actually changed locally\n const localChangedKeys = Object.keys(changes);\n const preservedLocal: any = { _localId: localItem._localId };\n for (const k of localChangedKeys) {\n if (k in localItem) preservedLocal[k] = localItem[k];\n }\n\n const merged = { ...remote, ...preservedLocal };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Merge now resolved, drop pending and conflict\n delete conflicts[localItem._localId];\n }\n break;\n }\n }\n } else {\n // No pending changes, merge remote into local\n const merged = { ...localItem, ...remote };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[zync] pull:merge-remote stateKey=${stateKey} id=${remote.id}`);\n }\n } else {\n // Add remote item (no local item)\n nextItems = [...nextItems, { ...remote, _localId: createLocalId() }];\n logger.debug(`[zync] pull:add stateKey=${stateKey} id=${remote.id}`);\n }\n }\n\n return {\n [stateKey]: nextItems,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts: hasKeysOrUndefined(conflicts),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { hasConflicts, removeFromPendingChanges, samePendingVersion, setPendingChangeBefore, setPendingChangeToUpdate } from './helpers';\nimport { createLocalId, SyncAction } from './index';\nimport type { Logger } from './logger';\nimport type {\n AfterRemoteAddCallback,\n ApiFunctions,\n MissingRemoteRecordStrategy,\n MissingRemoteRecordDuringUpdateCallback,\n PendingChange,\n SetAndSyncCallback,\n} from './types';\n\nexport async function pushOne(\n set: any,\n get: any,\n change: PendingChange,\n api: ApiFunctions,\n logger: Logger,\n setAndQueueToSync: SetAndSyncCallback,\n missingStrategy: MissingRemoteRecordStrategy,\n onMissingRemoteRecordDuringUpdate?: MissingRemoteRecordDuringUpdateCallback,\n onAfterRemoteAdd?: AfterRemoteAddCallback,\n) {\n logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version, changes } = change;\n\n switch (action) {\n case SyncAction.Remove:\n if (!id) {\n logger.warn(`[zync] push:remove:no-id stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n await api.remove(id);\n logger.debug(`[zync] push:remove:success stateKey=${stateKey} localId=${localId} id=${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.Update: {\n if (hasConflicts(get, change.localId)) {\n logger.warn(`[zync] push:update:skipping-with-conflicts stateKey=${stateKey} localId=${localId} id=${id}`);\n return;\n }\n\n const exists = await api.update(id, changes);\n if (exists) {\n logger.debug(`[zync] push:update:success stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure pending.before is not stale for conflict resolution\n setPendingChangeBefore(get, stateKey, localId, changes);\n }\n return;\n } else {\n const state = get();\n const items: any[] = state[stateKey] || [];\n const item = items.find((i) => i._localId === localId);\n if (!item) {\n logger.warn(`[zync] push:missing-remote:no-local-item stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n switch (missingStrategy) {\n case 'delete-local-record':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n case 'insert-remote-record': {\n const newItem = {\n ...item,\n _localId: createLocalId(),\n updated_at: new Date().toISOString(),\n };\n\n // replace old with modified and queue Create\n setAndQueueToSync((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? newItem : i)),\n }));\n\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${newItem.id}`);\n break;\n }\n\n case 'ignore':\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n default:\n logger.error(`[zync] push:missing-remote:unknown-strategy stateKey=${stateKey} id=${item.id} strategy=${missingStrategy}`);\n break;\n }\n\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, item);\n }\n break;\n }\n\n case SyncAction.Create: {\n const result = await api.add(changes);\n if (result) {\n logger.debug(`[zync] push:create:success stateKey=${stateKey} localId=${localId} id=${id}`);\n\n // Merge server-assigned fields (id, updated_at, etc) directly into local entity\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? { ...i, ...result } : i)),\n }));\n\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure any pendingChanges entry has id and is now an Update\n setPendingChangeToUpdate(get, stateKey, localId, result.id);\n }\n\n const finalItem = { ...changes, ...result, _localId: localId };\n\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, setAndQueueToSync, stateKey, finalItem);\n } else {\n logger.warn(`[zync] push:create:no-result stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\n }\n }\n}\n","import { findApi, createLocalId } from './helpers';\nimport type { Logger } from './logger';\nimport type { ApiFunctions } from './types';\n\nexport async function startFirstLoad(set: any, syncApi: Record<string, ApiFunctions>, logger: Logger) {\n let syncError: Error | undefined;\n\n for (const stateKey of Object.keys(syncApi)) {\n try {\n logger.info(`[zync] firstLoad:start stateKey=${stateKey}`);\n\n const api = findApi(stateKey, syncApi);\n let lastId; // Start as undefined to allow the userland api code to set the initial value+type\n\n // Batch until empty\n while (true) {\n const batch = await api.firstLoad(lastId);\n if (!batch?.length) break;\n\n // Merge batch\n set((state: any) => {\n const local: any[] = state[stateKey] || [];\n const localById = new Map<any, any>(local.filter((l) => l.id).map((l) => [l.id, l]));\n\n let newest = new Date(state.syncState.lastPulled[stateKey] || 0);\n const next = [...local];\n for (const remote of batch) {\n const remoteUpdated = new Date(remote.updated_at || 0);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n if (remote.deleted) continue;\n\n delete remote.deleted;\n\n const localItem = remote.id ? localById.get(remote.id) : undefined;\n if (localItem) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n const idx = next.findIndex((i) => i._localId === localItem._localId);\n if (idx >= 0) next[idx] = merged;\n } else {\n next.push({\n ...remote,\n _localId: createLocalId(),\n });\n }\n }\n\n return {\n [stateKey]: next,\n syncState: {\n ...(state.syncState || {}),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n\n if (lastId !== undefined && lastId === batch[batch.length - 1].id) {\n throw new Error(`Duplicate records downloaded, stopping to prevent infinite loop`);\n }\n\n lastId = batch[batch.length - 1].id;\n }\n\n logger.info(`[zync] firstLoad:done stateKey=${stateKey}`);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[zync] firstLoad:error stateKey=${stateKey}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n firstLoadDone: true,\n error: syncError,\n },\n }));\n}\n","import type { IDBPDatabase } from 'idb';\n\nexport function createIndexedDB(dbName: string, storeName: string) {\n // dbPromise is created lazily by initDB() to avoid pulling `idb` into bundles\n let dbPromise: Promise<IDBPDatabase<any>> | null = null;\n\n async function initDB(): Promise<IDBPDatabase<any>> {\n if (dbPromise) return dbPromise;\n try {\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, 1, {\n upgrade(db: IDBPDatabase<any>) {\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName);\n }\n },\n });\n return dbPromise;\n } catch (_e) {\n throw new Error('Missing optional dependency \"idb\". Install it to use IndexedDB storage: npm install idb');\n }\n }\n\n async function ensureStore(): Promise<void> {\n const db = await initDB();\n if (db.objectStoreNames.contains(storeName)) return;\n const nextVersion = (db.version || 0) + 1;\n try {\n db.close();\n } catch (_e) {\n // ignore\n }\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, nextVersion, {\n upgrade(upg: IDBPDatabase<any>) {\n if (!upg.objectStoreNames.contains(storeName)) upg.createObjectStore(storeName);\n },\n });\n await dbPromise;\n }\n\n async function withRetry<T>(fn: (db: IDBPDatabase<any>) => Promise<T>): Promise<T> {\n try {\n const db = await initDB();\n return await fn(db);\n } catch (err: any) {\n const msg = String(err && err.message ? err.message : err);\n if (err && (err.name === 'NotFoundError' || /objectStore/i.test(msg))) {\n await ensureStore();\n const db2 = await initDB();\n return await fn(db2);\n }\n throw err;\n }\n }\n\n return {\n getItem: async (name: string): Promise<string | null> => {\n return withRetry(async (db) => {\n let v = await db.get(storeName, name);\n v = v ?? null; // Zustand expects null for missing keys\n return v;\n });\n },\n setItem: async (name: string, value: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.put(storeName, value, name);\n });\n },\n removeItem: async (name: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.delete(storeName, name);\n });\n },\n };\n}\n"],"mappings":"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","names":["target","SyncAction"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -77,10 +77,7 @@ interface FieldConflict {
|
|
|
77
77
|
remoteValue: any;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
declare function
|
|
81
|
-
dbName: string;
|
|
82
|
-
storeName: string;
|
|
83
|
-
}): {
|
|
80
|
+
declare function createIndexedDB(dbName: string, storeName: string): {
|
|
84
81
|
getItem: (name: string) => Promise<string | null>;
|
|
85
82
|
setItem: (name: string, value: string) => Promise<void>;
|
|
86
83
|
removeItem: (name: string) => Promise<void>;
|
|
@@ -98,4 +95,4 @@ declare enum SyncAction {
|
|
|
98
95
|
declare function createWithSync<TStore extends object>(stateCreator: SyncedStateCreator<TStore>, persistOptions: any, syncApi: Record<string, ApiFunctions>, syncOptions?: SyncOptions): Promise<UseStoreWithSync<TStore>>;
|
|
99
96
|
declare function persistWithSync<TStore extends object>(stateCreator: SyncedStateCreator<TStore>, persistOptions: any, syncApi: Record<string, ApiFunctions>, syncOptions?: SyncOptions): StateCreator<TStore & SyncState, [], [["zustand/persist", TStore & SyncState]]>;
|
|
100
97
|
|
|
101
|
-
export { type ApiFunctions, SyncAction, type SyncState, type UseStoreWithSync, changeKeysFrom, changeKeysTo,
|
|
98
|
+
export { type ApiFunctions, SyncAction, type SyncState, type UseStoreWithSync, changeKeysFrom, changeKeysTo, createIndexedDB, createLocalId, createWithSync, persistWithSync };
|
package/dist/index.d.ts
CHANGED
|
@@ -77,10 +77,7 @@ interface FieldConflict {
|
|
|
77
77
|
remoteValue: any;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
declare function
|
|
81
|
-
dbName: string;
|
|
82
|
-
storeName: string;
|
|
83
|
-
}): {
|
|
80
|
+
declare function createIndexedDB(dbName: string, storeName: string): {
|
|
84
81
|
getItem: (name: string) => Promise<string | null>;
|
|
85
82
|
setItem: (name: string, value: string) => Promise<void>;
|
|
86
83
|
removeItem: (name: string) => Promise<void>;
|
|
@@ -98,4 +95,4 @@ declare enum SyncAction {
|
|
|
98
95
|
declare function createWithSync<TStore extends object>(stateCreator: SyncedStateCreator<TStore>, persistOptions: any, syncApi: Record<string, ApiFunctions>, syncOptions?: SyncOptions): Promise<UseStoreWithSync<TStore>>;
|
|
99
96
|
declare function persistWithSync<TStore extends object>(stateCreator: SyncedStateCreator<TStore>, persistOptions: any, syncApi: Record<string, ApiFunctions>, syncOptions?: SyncOptions): StateCreator<TStore & SyncState, [], [["zustand/persist", TStore & SyncState]]>;
|
|
100
97
|
|
|
101
|
-
export { type ApiFunctions, SyncAction, type SyncState, type UseStoreWithSync, changeKeysFrom, changeKeysTo,
|
|
98
|
+
export { type ApiFunctions, SyncAction, type SyncState, type UseStoreWithSync, changeKeysFrom, changeKeysTo, createIndexedDB, createLocalId, createWithSync, persistWithSync };
|
package/dist/index.js
CHANGED
|
@@ -482,9 +482,7 @@ async function startFirstLoad(set, syncApi, logger) {
|
|
|
482
482
|
}
|
|
483
483
|
|
|
484
484
|
// src/indexedDBStorage.ts
|
|
485
|
-
function
|
|
486
|
-
const dbName = options.dbName;
|
|
487
|
-
const storeName = options.storeName;
|
|
485
|
+
function createIndexedDB(dbName, storeName) {
|
|
488
486
|
let dbPromise = null;
|
|
489
487
|
async function initDB() {
|
|
490
488
|
if (dbPromise) return dbPromise;
|
|
@@ -765,7 +763,7 @@ export {
|
|
|
765
763
|
SyncAction,
|
|
766
764
|
changeKeysFrom,
|
|
767
765
|
changeKeysTo,
|
|
768
|
-
|
|
766
|
+
createIndexedDB,
|
|
769
767
|
createLocalId,
|
|
770
768
|
createWithSync,
|
|
771
769
|
persistWithSync
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/logger.ts","../src/helpers.ts","../src/pull.ts","../src/push.ts","../src/firstLoad.ts","../src/indexedDBStorage.ts"],"sourcesContent":["import { create, type StateCreator } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport { newLogger, type Logger, type LogLevel } from './logger';\nimport { orderFor, findApi, findChanges, tryAddToPendingChanges, tryUpdateConflicts, resolveConflict, sleep } from './helpers';\nimport {\n type ApiFunctions,\n type SyncOptions,\n type SyncState,\n type SyncedStateCreator,\n type PendingChange,\n type UseStoreWithSync,\n type MissingRemoteRecordStrategy,\n type ConflictResolutionStrategy,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\nimport { startFirstLoad } from './firstLoad';\n\nexport { createIndexedDBStorage } from './indexedDBStorage';\nexport { createLocalId, changeKeysTo, changeKeysFrom } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n Create = 'create',\n Update = 'update',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 2000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_STRATEGY: MissingRemoteRecordStrategy = 'ignore';\nconst DEFAULT_CONFLICT_RESOLUTION_STRATEGY: ConflictResolutionStrategy = 'local-wins';\n\nexport function createWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n): Promise<UseStoreWithSync<TStore>> {\n const store = create(persistWithSync(stateCreator, persistOptions, syncApi, syncOptions)) as UseStoreWithSync<TStore>;\n\n return new Promise<UseStoreWithSync<TStore>>((resolve) => {\n store.persist.onFinishHydration((_state) => {\n resolve(store);\n });\n });\n}\n\nexport function persistWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n) {\n const syncInterval = syncOptions.syncInterval ?? DEFAULT_SYNC_INTERVAL_MILLIS;\n const missingStrategy = syncOptions.missingRemoteRecordDuringUpdateStrategy ?? DEFAULT_MISSING_REMOTE_RECORD_STRATEGY;\n const conflictResolutionStrategy = syncOptions.conflictResolutionStrategy ?? DEFAULT_CONFLICT_RESOLUTION_STRATEGY;\n const logger = newLogger(syncOptions.logger ?? DEFAULT_LOGGER, syncOptions.minLogLevel ?? DEFAULT_MIN_LOG_LEVEL);\n\n const baseOnRehydrate = persistOptions?.onRehydrateStorage;\n const basePartialize = persistOptions?.partialize;\n\n const wrappedPersistOptions = {\n ...persistOptions,\n onRehydrateStorage: () => {\n logger.debug('[zync] rehydration:start');\n\n return (state: any, error: any) => {\n if (error) {\n logger.error('[zync] rehydration:failed', error);\n } else {\n baseOnRehydrate?.(state, error);\n logger.debug('[zync] rehydration:complete', state);\n }\n };\n },\n partialize: (s: any) => {\n // Select state to be persisted\n\n const base = basePartialize ? basePartialize(s) : s;\n const { syncState, ...rest } = base || {};\n return {\n ...rest,\n syncState: {\n firstLoadDone: syncState.firstLoadDone,\n pendingChanges: syncState.pendingChanges,\n lastPulled: syncState.lastPulled,\n conflicts: syncState.conflicts,\n },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly asynchronously e.g. IndexedDB)\n // `current` is what the user has defined (they may have added or removed state keys)\n // Zync is designed to not be used until hydration is complete, so we don't expect to have to\n // merge user mutated state (i.e. current) into persisted. So we do the Zustand recommended pattern of\n // shallow copy where persisted keys win:\n const state = { ...current, ...persisted };\n\n return {\n ...state,\n syncState: {\n ...(state.syncState || {}),\n status: 'idle', // this confirms 'hydrating' is done\n },\n };\n },\n };\n\n const creator: StateCreator<TStore & SyncState, [], []> = (set: any, get: any, storeApi: any) => {\n let syncTimerStarted = false;\n\n async function syncOnce() {\n if (get().syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let firstSyncError: Error | undefined;\n\n // 1) PULL for each stateKey\n for (const stateKey of Object.keys(syncApi)) {\n try {\n const api = findApi(stateKey, syncApi);\n await pull(set, get, stateKey, api, logger, conflictResolutionStrategy);\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] pull:error stateKey=${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const changesSnapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen first\n changesSnapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of changesSnapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n setAndQueueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] push:error change=${change}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'idle',\n error: firstSyncError,\n } as SyncState['syncState'],\n }));\n }\n\n function setAndQueueToSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => newSyncState(state, partial(state)));\n } else {\n set((state: any) => newSyncState(state, partial));\n }\n }\n\n function newSyncState(state: any, partial: any) {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n\n Object.keys(partial).map((stateKey) => {\n const current = state[stateKey];\n const updated = partial[stateKey];\n const changes = findChanges(current, updated); // find additions, deletions & updates\n tryAddToPendingChanges(pendingChanges, stateKey, changes);\n });\n\n // Prevent stale conflicts reporting old values to user\n const conflicts = tryUpdateConflicts(pendingChanges, state.syncState.conflicts);\n\n return {\n ...partial,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts,\n } as SyncState['syncState'],\n };\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: enabled ? 'idle' : 'disabled',\n },\n }));\n\n startSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function startSyncTimer(start: boolean) {\n if (start) {\n tryStart(); // Unawaited async\n } else {\n syncTimerStarted = false;\n }\n }\n\n async function tryStart() {\n if (syncTimerStarted) return;\n syncTimerStarted = true;\n\n while (true) {\n if (!syncTimerStarted) break;\n await syncOnce();\n await sleep(syncInterval);\n }\n }\n\n function addVisibilityChangeListener(add: boolean) {\n if (add) {\n document.addEventListener('visibilitychange', onVisibilityChange);\n } else {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n }\n }\n\n function onVisibilityChange() {\n if (document.visibilityState === 'visible') {\n logger.debug('[zync] sync:start-in-foreground');\n startSyncTimer(true);\n } else {\n logger.debug('[zync] sync:pause-in-background');\n startSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad: () => startFirstLoad(set, syncApi, logger),\n resolveConflict: (localId: string, keepLocal: boolean) => resolveConflict(set, localId, keepLocal),\n };\n\n const userState = stateCreator(set, get, setAndQueueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n conflicts: undefined,\n firstLoadDone: false,\n pendingChanges: [],\n lastPulled: {},\n },\n } as TStore & SyncState;\n };\n\n return persist(creator, wrappedPersistOptions);\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\nexport interface Logger {\n debug: (...args: any[]) => void;\n info: (...args: any[]) => void;\n warn: (...args: any[]) => void;\n error: (...args: any[]) => void;\n}\n\nexport function newLogger(base: Logger, min: LogLevel): Logger {\n const order: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n none: 100,\n };\n const threshold = order[min];\n const enabled = (lvl: LogLevel) => order[lvl] >= threshold;\n return {\n debug: (...a: any[]) => enabled('debug') && base.debug?.(...a),\n info: (...a: any[]) => enabled('info') && base.info?.(...a),\n warn: (...a: any[]) => enabled('warn') && base.warn?.(...a),\n error: (...a: any[]) => enabled('error') && base.error?.(...a),\n };\n}\n","import { SyncAction } from './index';\nimport type { ApiFunctions, Conflict, FieldConflict, PendingChange, SyncState } from './types';\n\nconst SYNC_FIELDS = ['_localId', 'updated_at', 'deleted'] as const;\n\nexport function createLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function changeKeysTo(input: any | any[], toIdKey: string, toUpdatedAtKey: string, toDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { id, updated_at, deleted, ...rest } = item;\n return {\n [toIdKey]: id,\n [toUpdatedAtKey]: updated_at,\n [toDeletedKey]: deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function changeKeysFrom(input: any | any[], fromIdKey: string, fromUpdatedAtKey: string, fromDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { [fromIdKey]: id, [fromUpdatedAtKey]: updated_at, [fromDeletedKey]: deleted, ...rest } = item;\n return {\n id,\n updated_at,\n deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.Create:\n return 1;\n case SyncAction.Update:\n return 2;\n case SyncAction.Remove:\n return 3;\n }\n}\n\nexport function omitSyncFields(item: any) {\n const result = { ...item };\n for (const k of SYNC_FIELDS) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const pending: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = pending.find((p) => p.localId === localId && p.stateKey === stateKey);\n return curChange?.version === version;\n}\n\nexport function removeFromPendingChanges(set: any, localId: string, stateKey: string) {\n set((s: any) => {\n const queue: PendingChange[] = (s.syncState.pendingChanges || []).filter((p: PendingChange) => !(p.localId === localId && p.stateKey === stateKey));\n return {\n syncState: {\n ...(s.syncState || {}),\n pendingChanges: queue,\n },\n };\n });\n}\n\nexport function tryAddToPendingChanges(pendingChanges: PendingChange[], stateKey: string, changes: Map<string, ChangeRecord>) {\n for (const [localId, change] of changes) {\n let omittedItem = omitSyncFields(change.changes);\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n const hasChanges = Object.keys(omittedItem).length > 0;\n const action = change.updatedItem === null ? SyncAction.Remove : change.currentItem === null ? SyncAction.Create : SyncAction.Update;\n\n if (action === SyncAction.Update && change.updatedItem && change.currentItem && change.currentItem._localId !== change.updatedItem._localId) {\n // Here when insert-remote-record swaps local remotely deleted item with a fresh copy to push up\n omittedItem = omitSyncFields(change.updatedItem);\n }\n\n if (queueItem) {\n if (queueItem.action === SyncAction.Remove) {\n // Once a Remove is queued, it stays a Remove\n continue;\n }\n\n queueItem.version += 1;\n\n if (action === SyncAction.Remove) {\n queueItem.action = SyncAction.Remove;\n } else if (hasChanges) {\n // Never change the action here, it stays Create or Update and is removed when synced\n queueItem.changes = { ...queueItem.changes, ...omittedItem };\n }\n } else if (action === SyncAction.Remove || hasChanges) {\n pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem, before: omitSyncFields(change.currentItem) });\n }\n }\n}\n\nexport function setPendingChangeToUpdate(get: any, stateKey: string, localId: string, id?: any) {\n // id is optional as the user may client assign the id, but not return it from the api\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.action = SyncAction.Update;\n if (id) change.id = id;\n }\n}\n\nexport function setPendingChangeBefore(get: any, stateKey: string, localId: string, before: any) {\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.before = { ...change.before, ...before };\n }\n}\n\nexport function tryUpdateConflicts(pendingChanges: PendingChange[], conflicts?: Record<string, Conflict>): Record<string, Conflict> | undefined {\n if (!conflicts) return conflicts;\n\n const newConflicts = { ...conflicts };\n\n for (const change of pendingChanges) {\n const conflict = newConflicts[change.localId];\n if (conflict && change.changes) {\n // Loop changed fields and update their old possibly stale value to the current local value\n const newFields = conflict.fields.map((f) => {\n if (f.key in change.changes) {\n return { ...f, localValue: change.changes[f.key] } as FieldConflict;\n }\n return f;\n });\n\n newConflicts[change.localId] = { stateKey: conflict.stateKey, fields: newFields };\n }\n }\n\n return newConflicts;\n}\n\nexport function findApi(stateKey: string, syncApi: Record<string, ApiFunctions>) {\n const api = syncApi[stateKey];\n if (!api || !api.add || !api.update || !api.remove || !api.list || !api.firstLoad) {\n throw new Error(`Missing API function(s) for state key: ${stateKey}.`);\n }\n return api;\n}\n\ntype ChangeRecord = {\n currentItem?: any;\n updatedItem?: any;\n changes: any;\n id?: any;\n};\n\n/**\n * Compares the top-level keys of items in `current` and `updated` arrays (assumed to have `_localId`).\n * Returns a Map where the key is `_localId` and the value is an object with:\n * - `currentItem`: The item from `current` (or `null` for additions).\n * - `updatedItem`: The item from `updated` (or `null` for deletions).\n * - `changes`: An object with differing top-level keys and their values (or the full item for additions, or `null` for deletions).\n */\nexport function findChanges(current: any[], updated: any[]): Map<string, ChangeRecord> {\n const currentMap = new Map<string, any>();\n for (const item of current) {\n if (item && item._localId) {\n currentMap.set(item._localId, { ...item });\n }\n }\n\n const changesMap = new Map<string, ChangeRecord>();\n\n // Check for changes and additions\n for (const update of updated) {\n const item = { ...update };\n if (item && item._localId) {\n const curr = currentMap.get(item._localId);\n if (curr) {\n const diff: any = {};\n for (const key in curr) {\n if (key !== '_localId' && curr[key] !== item[key]) {\n diff[key] = item[key];\n }\n }\n if (Object.keys(diff).length > 0) {\n // Changes\n changesMap.set(item._localId, { currentItem: curr, updatedItem: item, changes: diff, id: curr.id ?? item.id });\n }\n } else {\n // Addition\n changesMap.set(item._localId, { currentItem: null, updatedItem: item, changes: item, id: item.id });\n }\n }\n }\n\n // Check for deletions\n for (const [localId, curr] of currentMap) {\n if (!updated.some((u) => u && u._localId === localId)) {\n changesMap.set(localId, { currentItem: curr, updatedItem: null, changes: null, id: curr.id });\n }\n }\n\n return changesMap;\n}\n\nexport function hasKeysOrUndefined(obj: any): any {\n return Object.keys(obj).length === 0 ? undefined : obj;\n}\n\nexport function hasConflicts(get: any, localId: string): boolean {\n const state = get() as SyncState;\n if (state.syncState.conflicts) {\n return !!state.syncState.conflicts[localId];\n }\n return false;\n}\n\nexport function resolveConflict(set: any, localId: string, keepLocalFields: boolean) {\n set((state: any) => {\n const syncState: SyncState['syncState'] = state.syncState || {};\n const conflicts: Record<string, Conflict> = syncState.conflicts || {};\n const conflict = conflicts[localId];\n if (conflict) {\n const items = state[conflict.stateKey];\n const item = items.find((i: any) => i._localId === localId);\n if (!item) {\n return state;\n }\n\n const resolved: any = { ...item };\n let pendingChanges = [...syncState.pendingChanges];\n\n if (!keepLocalFields) {\n // Use remote value(s)\n for (const field of conflict.fields) {\n resolved[field.key] = field.remoteValue;\n }\n\n // Remove resolved pending change\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === conflict.stateKey && p.localId === localId));\n }\n\n // Replace with resolved item\n const nextItems = items.map((i: any) => (i._localId === localId ? resolved : i));\n const nextConflicts = { ...conflicts };\n delete nextConflicts[localId];\n\n return {\n [conflict.stateKey]: nextItems,\n syncState: {\n ...syncState,\n pendingChanges,\n conflicts: hasKeysOrUndefined(nextConflicts),\n },\n };\n }\n return state;\n });\n}\n","import { type ApiFunctions, type FieldConflict, type ConflictResolutionStrategy, type SyncedRecord, type PendingChange } from './types';\nimport { SyncAction } from './index';\nimport { createLocalId, hasKeysOrUndefined } from './helpers';\nimport type { Logger } from './logger';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: Logger, conflictResolutionStrategy: ConflictResolutionStrategy) {\n const lastPulled: Record<string, string> = get().syncState.lastPulled || {};\n const lastPulledAt = new Date(lastPulled[stateKey] || new Date(0));\n\n logger.debug(`[zync] pull:start stateKey=${stateKey} since=${lastPulledAt.toISOString()}`);\n\n const serverData = (await api.list(lastPulledAt)) as SyncedRecord[];\n if (!serverData?.length) return;\n\n let newest = lastPulledAt;\n\n set((state: any) => {\n let pendingChanges = [...(state.syncState.pendingChanges as PendingChange[])];\n const conflicts = { ...state.syncState.conflicts };\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items when pulling them again\n const pendingRemovalById = new Set(pendingChanges.filter((p) => p.stateKey === stateKey && p.action === SyncAction.Remove).map((p) => p.id));\n\n for (const remote of serverData) {\n const remoteUpdated = new Date(remote.updated_at);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n // If a Remove is pending for this localId, skip merging/adding to avoid briefly resurrecting the item\n if (pendingRemovalById.has(remote.id)) {\n logger.debug(`[zync] pull:skip-pending-remove stateKey=${stateKey} id=${remote.id}`);\n continue;\n }\n\n const localItem = localById.get(remote.id);\n if (remote.deleted) {\n if (localItem) {\n nextItems = nextItems.filter((i: any) => i.id !== remote.id);\n logger.debug(`[zync] pull:remove stateKey=${stateKey} id=${remote.id}`);\n }\n continue;\n }\n\n delete remote.deleted;\n\n if (localItem) {\n const pendingChange = pendingChanges.find((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (pendingChange) {\n logger.debug(`[zync] pull:conflict-strategy:${conflictResolutionStrategy} stateKey=${stateKey} id=${remote.id}`);\n\n switch (conflictResolutionStrategy) {\n case 'local-wins':\n // Ignore remote changes, keep local\n break;\n\n case 'remote-wins': {\n // Ignore local changes, keep remote\n const merged = { ...remote, _localId: localItem._localId };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Remove pending change so it isn't pushed after pull\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === stateKey && p.localId === localItem._localId));\n break;\n }\n\n case 'try-shallow-merge': {\n // List fields that local and remote have changed\n const changes = pendingChange.changes || {};\n const before = pendingChange.before || {};\n const fields: FieldConflict[] = Object.entries(changes)\n .filter(([k, localValue]) => k in before && k in remote && before[k] !== remote[k] && localValue !== remote[k])\n .map(([key, localValue]) => ({ key, localValue, remoteValue: remote[key] }));\n\n if (fields.length > 0) {\n logger.warn(`[zync] pull:${conflictResolutionStrategy}:conflicts-found`, JSON.stringify(fields, null, 4));\n conflicts[localItem._localId] = { stateKey, fields };\n } else {\n // No conflicts, merge remote into local but only preserve fields that were\n // actually changed locally\n const localChangedKeys = Object.keys(changes);\n const preservedLocal: any = { _localId: localItem._localId };\n for (const k of localChangedKeys) {\n if (k in localItem) preservedLocal[k] = localItem[k];\n }\n\n const merged = { ...remote, ...preservedLocal };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Merge now resolved, drop pending and conflict\n delete conflicts[localItem._localId];\n }\n break;\n }\n }\n } else {\n // No pending changes, merge remote into local\n const merged = { ...localItem, ...remote };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[zync] pull:merge-remote stateKey=${stateKey} id=${remote.id}`);\n }\n } else {\n // Add remote item (no local item)\n nextItems = [...nextItems, { ...remote, _localId: createLocalId() }];\n logger.debug(`[zync] pull:add stateKey=${stateKey} id=${remote.id}`);\n }\n }\n\n return {\n [stateKey]: nextItems,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts: hasKeysOrUndefined(conflicts),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { hasConflicts, removeFromPendingChanges, samePendingVersion, setPendingChangeBefore, setPendingChangeToUpdate } from './helpers';\nimport { createLocalId, SyncAction } from './index';\nimport type { Logger } from './logger';\nimport type {\n AfterRemoteAddCallback,\n ApiFunctions,\n MissingRemoteRecordStrategy,\n MissingRemoteRecordDuringUpdateCallback,\n PendingChange,\n SetAndSyncCallback,\n} from './types';\n\nexport async function pushOne(\n set: any,\n get: any,\n change: PendingChange,\n api: ApiFunctions,\n logger: Logger,\n setAndQueueToSync: SetAndSyncCallback,\n missingStrategy: MissingRemoteRecordStrategy,\n onMissingRemoteRecordDuringUpdate?: MissingRemoteRecordDuringUpdateCallback,\n onAfterRemoteAdd?: AfterRemoteAddCallback,\n) {\n logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version, changes } = change;\n\n switch (action) {\n case SyncAction.Remove:\n if (!id) {\n logger.warn(`[zync] push:remove:no-id stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n await api.remove(id);\n logger.debug(`[zync] push:remove:success stateKey=${stateKey} localId=${localId} id=${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.Update: {\n if (hasConflicts(get, change.localId)) {\n logger.warn(`[zync] push:update:skipping-with-conflicts stateKey=${stateKey} localId=${localId} id=${id}`);\n return;\n }\n\n const exists = await api.update(id, changes);\n if (exists) {\n logger.debug(`[zync] push:update:success stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure pending.before is not stale for conflict resolution\n setPendingChangeBefore(get, stateKey, localId, changes);\n }\n return;\n } else {\n const state = get();\n const items: any[] = state[stateKey] || [];\n const item = items.find((i) => i._localId === localId);\n if (!item) {\n logger.warn(`[zync] push:missing-remote:no-local-item stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n switch (missingStrategy) {\n case 'delete-local-record':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n case 'insert-remote-record': {\n const newItem = {\n ...item,\n _localId: createLocalId(),\n updated_at: new Date().toISOString(),\n };\n\n // replace old with modified and queue Create\n setAndQueueToSync((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? newItem : i)),\n }));\n\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${newItem.id}`);\n break;\n }\n\n case 'ignore':\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n default:\n logger.error(`[zync] push:missing-remote:unknown-strategy stateKey=${stateKey} id=${item.id} strategy=${missingStrategy}`);\n break;\n }\n\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, item);\n }\n break;\n }\n\n case SyncAction.Create: {\n const result = await api.add(changes);\n if (result) {\n logger.debug(`[zync] push:create:success stateKey=${stateKey} localId=${localId} id=${id}`);\n\n // Merge server-assigned fields (id, updated_at, etc) directly into local entity\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? { ...i, ...result } : i)),\n }));\n\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure any pendingChanges entry has id and is now an Update\n setPendingChangeToUpdate(get, stateKey, localId, result.id);\n }\n\n const finalItem = { ...changes, ...result, _localId: localId };\n\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, setAndQueueToSync, stateKey, finalItem);\n } else {\n logger.warn(`[zync] push:create:no-result stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\n }\n }\n}\n","import { findApi, createLocalId } from './helpers';\nimport type { Logger } from './logger';\nimport type { ApiFunctions } from './types';\n\nexport async function startFirstLoad(set: any, syncApi: Record<string, ApiFunctions>, logger: Logger) {\n let syncError: Error | undefined;\n\n for (const stateKey of Object.keys(syncApi)) {\n try {\n logger.info(`[zync] firstLoad:start stateKey=${stateKey}`);\n\n const api = findApi(stateKey, syncApi);\n let lastId; // Start as undefined to allow the userland api code to set the initial value+type\n\n // Batch until empty\n while (true) {\n const batch = await api.firstLoad(lastId);\n if (!batch?.length) break;\n\n // Merge batch\n set((state: any) => {\n const local: any[] = state[stateKey] || [];\n const localById = new Map<any, any>(local.filter((l) => l.id).map((l) => [l.id, l]));\n\n let newest = new Date(state.syncState.lastPulled[stateKey] || 0);\n const next = [...local];\n for (const remote of batch) {\n const remoteUpdated = new Date(remote.updated_at || 0);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n if (remote.deleted) continue;\n\n delete remote.deleted;\n\n const localItem = remote.id ? localById.get(remote.id) : undefined;\n if (localItem) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n const idx = next.findIndex((i) => i._localId === localItem._localId);\n if (idx >= 0) next[idx] = merged;\n } else {\n next.push({\n ...remote,\n _localId: createLocalId(),\n });\n }\n }\n\n return {\n [stateKey]: next,\n syncState: {\n ...(state.syncState || {}),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n\n if (lastId !== undefined && lastId === batch[batch.length - 1].id) {\n throw new Error(`Duplicate records downloaded, stopping to prevent infinite loop`);\n }\n\n lastId = batch[batch.length - 1].id;\n }\n\n logger.info(`[zync] firstLoad:done stateKey=${stateKey}`);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[zync] firstLoad:error stateKey=${stateKey}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n firstLoadDone: true,\n error: syncError,\n },\n }));\n}\n","import type { IDBPDatabase } from 'idb';\n\nexport function createIndexedDBStorage(options: { dbName: string; storeName: string }) {\n const dbName = options.dbName;\n const storeName = options.storeName;\n\n // dbPromise is created lazily by initDB() to avoid pulling `idb` into bundles\n let dbPromise: Promise<IDBPDatabase<any>> | null = null;\n\n async function initDB(): Promise<IDBPDatabase<any>> {\n if (dbPromise) return dbPromise;\n try {\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, 1, {\n upgrade(db: IDBPDatabase<any>) {\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName);\n }\n },\n });\n return dbPromise;\n } catch (_e) {\n throw new Error('Missing optional dependency \"idb\". Install it to use IndexedDB storage: npm install idb');\n }\n }\n\n async function ensureStore(): Promise<void> {\n const db = await initDB();\n if (db.objectStoreNames.contains(storeName)) return;\n const nextVersion = (db.version || 0) + 1;\n try {\n db.close();\n } catch (_e) {\n // ignore\n }\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, nextVersion, {\n upgrade(upg: IDBPDatabase<any>) {\n if (!upg.objectStoreNames.contains(storeName)) upg.createObjectStore(storeName);\n },\n });\n await dbPromise;\n }\n\n async function withRetry<T>(fn: (db: IDBPDatabase<any>) => Promise<T>): Promise<T> {\n try {\n const db = await initDB();\n return await fn(db);\n } catch (err: any) {\n const msg = String(err && err.message ? err.message : err);\n if (err && (err.name === 'NotFoundError' || /objectStore/i.test(msg))) {\n await ensureStore();\n const db2 = await initDB();\n return await fn(db2);\n }\n throw err;\n }\n }\n\n return {\n getItem: async (name: string): Promise<string | null> => {\n return withRetry(async (db) => {\n let v = await db.get(storeName, name);\n v = v ?? null; // Zustand expects null for missing keys\n return v;\n });\n },\n setItem: async (name: string, value: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.put(storeName, value, name);\n });\n },\n removeItem: async (name: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.delete(storeName, name);\n });\n },\n };\n}\n"],"mappings":"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","names":["SyncAction"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/logger.ts","../src/helpers.ts","../src/pull.ts","../src/push.ts","../src/firstLoad.ts","../src/indexedDBStorage.ts"],"sourcesContent":["import { create, type StateCreator } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport { newLogger, type Logger, type LogLevel } from './logger';\nimport { orderFor, findApi, findChanges, tryAddToPendingChanges, tryUpdateConflicts, resolveConflict, sleep } from './helpers';\nimport {\n type ApiFunctions,\n type SyncOptions,\n type SyncState,\n type SyncedStateCreator,\n type PendingChange,\n type UseStoreWithSync,\n type MissingRemoteRecordStrategy,\n type ConflictResolutionStrategy,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\nimport { startFirstLoad } from './firstLoad';\n\nexport { createIndexedDB } from './indexedDBStorage';\nexport { createLocalId, changeKeysTo, changeKeysFrom } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n Create = 'create',\n Update = 'update',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 2000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_STRATEGY: MissingRemoteRecordStrategy = 'ignore';\nconst DEFAULT_CONFLICT_RESOLUTION_STRATEGY: ConflictResolutionStrategy = 'local-wins';\n\nexport function createWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n): Promise<UseStoreWithSync<TStore>> {\n const store = create(persistWithSync(stateCreator, persistOptions, syncApi, syncOptions)) as UseStoreWithSync<TStore>;\n\n return new Promise<UseStoreWithSync<TStore>>((resolve) => {\n store.persist.onFinishHydration((_state) => {\n resolve(store);\n });\n });\n}\n\nexport function persistWithSync<TStore extends object>(\n stateCreator: SyncedStateCreator<TStore>,\n persistOptions: any,\n syncApi: Record<string, ApiFunctions>,\n syncOptions: SyncOptions = {},\n) {\n const syncInterval = syncOptions.syncInterval ?? DEFAULT_SYNC_INTERVAL_MILLIS;\n const missingStrategy = syncOptions.missingRemoteRecordDuringUpdateStrategy ?? DEFAULT_MISSING_REMOTE_RECORD_STRATEGY;\n const conflictResolutionStrategy = syncOptions.conflictResolutionStrategy ?? DEFAULT_CONFLICT_RESOLUTION_STRATEGY;\n const logger = newLogger(syncOptions.logger ?? DEFAULT_LOGGER, syncOptions.minLogLevel ?? DEFAULT_MIN_LOG_LEVEL);\n\n const baseOnRehydrate = persistOptions?.onRehydrateStorage;\n const basePartialize = persistOptions?.partialize;\n\n const wrappedPersistOptions = {\n ...persistOptions,\n onRehydrateStorage: () => {\n logger.debug('[zync] rehydration:start');\n\n return (state: any, error: any) => {\n if (error) {\n logger.error('[zync] rehydration:failed', error);\n } else {\n baseOnRehydrate?.(state, error);\n logger.debug('[zync] rehydration:complete', state);\n }\n };\n },\n partialize: (s: any) => {\n // Select state to be persisted\n\n const base = basePartialize ? basePartialize(s) : s;\n const { syncState, ...rest } = base || {};\n return {\n ...rest,\n syncState: {\n firstLoadDone: syncState.firstLoadDone,\n pendingChanges: syncState.pendingChanges,\n lastPulled: syncState.lastPulled,\n conflicts: syncState.conflicts,\n },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly asynchronously e.g. IndexedDB)\n // `current` is what the user has defined (they may have added or removed state keys)\n // Zync is designed to not be used until hydration is complete, so we don't expect to have to\n // merge user mutated state (i.e. current) into persisted. So we do the Zustand recommended pattern of\n // shallow copy where persisted keys win:\n const state = { ...current, ...persisted };\n\n return {\n ...state,\n syncState: {\n ...(state.syncState || {}),\n status: 'idle', // this confirms 'hydrating' is done\n },\n };\n },\n };\n\n const creator: StateCreator<TStore & SyncState, [], []> = (set: any, get: any, storeApi: any) => {\n let syncTimerStarted = false;\n\n async function syncOnce() {\n if (get().syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let firstSyncError: Error | undefined;\n\n // 1) PULL for each stateKey\n for (const stateKey of Object.keys(syncApi)) {\n try {\n const api = findApi(stateKey, syncApi);\n await pull(set, get, stateKey, api, logger, conflictResolutionStrategy);\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] pull:error stateKey=${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const changesSnapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen first\n changesSnapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of changesSnapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n setAndQueueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n firstSyncError = firstSyncError ?? (err as Error);\n logger.error(`[zync] push:error change=${change}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'idle',\n error: firstSyncError,\n } as SyncState['syncState'],\n }));\n }\n\n function setAndQueueToSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => newSyncState(state, partial(state)));\n } else {\n set((state: any) => newSyncState(state, partial));\n }\n }\n\n function newSyncState(state: any, partial: any) {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n\n Object.keys(partial).map((stateKey) => {\n const current = state[stateKey];\n const updated = partial[stateKey];\n const changes = findChanges(current, updated); // find additions, deletions & updates\n tryAddToPendingChanges(pendingChanges, stateKey, changes);\n });\n\n // Prevent stale conflicts reporting old values to user\n const conflicts = tryUpdateConflicts(pendingChanges, state.syncState.conflicts);\n\n return {\n ...partial,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts,\n } as SyncState['syncState'],\n };\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: enabled ? 'idle' : 'disabled',\n },\n }));\n\n startSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function startSyncTimer(start: boolean) {\n if (start) {\n tryStart(); // Unawaited async\n } else {\n syncTimerStarted = false;\n }\n }\n\n async function tryStart() {\n if (syncTimerStarted) return;\n syncTimerStarted = true;\n\n while (true) {\n if (!syncTimerStarted) break;\n await syncOnce();\n await sleep(syncInterval);\n }\n }\n\n function addVisibilityChangeListener(add: boolean) {\n if (add) {\n document.addEventListener('visibilitychange', onVisibilityChange);\n } else {\n document.removeEventListener('visibilitychange', onVisibilityChange);\n }\n }\n\n function onVisibilityChange() {\n if (document.visibilityState === 'visible') {\n logger.debug('[zync] sync:start-in-foreground');\n startSyncTimer(true);\n } else {\n logger.debug('[zync] sync:pause-in-background');\n startSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad: () => startFirstLoad(set, syncApi, logger),\n resolveConflict: (localId: string, keepLocal: boolean) => resolveConflict(set, localId, keepLocal),\n };\n\n const userState = stateCreator(set, get, setAndQueueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n conflicts: undefined,\n firstLoadDone: false,\n pendingChanges: [],\n lastPulled: {},\n },\n } as TStore & SyncState;\n };\n\n return persist(creator, wrappedPersistOptions);\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\nexport interface Logger {\n debug: (...args: any[]) => void;\n info: (...args: any[]) => void;\n warn: (...args: any[]) => void;\n error: (...args: any[]) => void;\n}\n\nexport function newLogger(base: Logger, min: LogLevel): Logger {\n const order: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n none: 100,\n };\n const threshold = order[min];\n const enabled = (lvl: LogLevel) => order[lvl] >= threshold;\n return {\n debug: (...a: any[]) => enabled('debug') && base.debug?.(...a),\n info: (...a: any[]) => enabled('info') && base.info?.(...a),\n warn: (...a: any[]) => enabled('warn') && base.warn?.(...a),\n error: (...a: any[]) => enabled('error') && base.error?.(...a),\n };\n}\n","import { SyncAction } from './index';\nimport type { ApiFunctions, Conflict, FieldConflict, PendingChange, SyncState } from './types';\n\nconst SYNC_FIELDS = ['_localId', 'updated_at', 'deleted'] as const;\n\nexport function createLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function changeKeysTo(input: any | any[], toIdKey: string, toUpdatedAtKey: string, toDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { id, updated_at, deleted, ...rest } = item;\n return {\n [toIdKey]: id,\n [toUpdatedAtKey]: updated_at,\n [toDeletedKey]: deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function changeKeysFrom(input: any | any[], fromIdKey: string, fromUpdatedAtKey: string, fromDeletedKey: string) {\n if (!input) return input;\n const isArray = Array.isArray(input);\n const result = (isArray ? input : [input]).map((item) => {\n const { [fromIdKey]: id, [fromUpdatedAtKey]: updated_at, [fromDeletedKey]: deleted, ...rest } = item;\n return {\n id,\n updated_at,\n deleted,\n ...rest,\n };\n });\n return isArray ? result : result[0];\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.Create:\n return 1;\n case SyncAction.Update:\n return 2;\n case SyncAction.Remove:\n return 3;\n }\n}\n\nexport function omitSyncFields(item: any) {\n const result = { ...item };\n for (const k of SYNC_FIELDS) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const pending: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = pending.find((p) => p.localId === localId && p.stateKey === stateKey);\n return curChange?.version === version;\n}\n\nexport function removeFromPendingChanges(set: any, localId: string, stateKey: string) {\n set((s: any) => {\n const queue: PendingChange[] = (s.syncState.pendingChanges || []).filter((p: PendingChange) => !(p.localId === localId && p.stateKey === stateKey));\n return {\n syncState: {\n ...(s.syncState || {}),\n pendingChanges: queue,\n },\n };\n });\n}\n\nexport function tryAddToPendingChanges(pendingChanges: PendingChange[], stateKey: string, changes: Map<string, ChangeRecord>) {\n for (const [localId, change] of changes) {\n let omittedItem = omitSyncFields(change.changes);\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n const hasChanges = Object.keys(omittedItem).length > 0;\n const action = change.updatedItem === null ? SyncAction.Remove : change.currentItem === null ? SyncAction.Create : SyncAction.Update;\n\n if (action === SyncAction.Update && change.updatedItem && change.currentItem && change.currentItem._localId !== change.updatedItem._localId) {\n // Here when insert-remote-record swaps local remotely deleted item with a fresh copy to push up\n omittedItem = omitSyncFields(change.updatedItem);\n }\n\n if (queueItem) {\n if (queueItem.action === SyncAction.Remove) {\n // Once a Remove is queued, it stays a Remove\n continue;\n }\n\n queueItem.version += 1;\n\n if (action === SyncAction.Remove) {\n queueItem.action = SyncAction.Remove;\n } else if (hasChanges) {\n // Never change the action here, it stays Create or Update and is removed when synced\n queueItem.changes = { ...queueItem.changes, ...omittedItem };\n }\n } else if (action === SyncAction.Remove || hasChanges) {\n pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem, before: omitSyncFields(change.currentItem) });\n }\n }\n}\n\nexport function setPendingChangeToUpdate(get: any, stateKey: string, localId: string, id?: any) {\n // id is optional as the user may client assign the id, but not return it from the api\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.action = SyncAction.Update;\n if (id) change.id = id;\n }\n}\n\nexport function setPendingChangeBefore(get: any, stateKey: string, localId: string, before: any) {\n const pendingChanges: PendingChange[] = get().syncState.pendingChanges || [];\n const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);\n if (change) {\n change.before = { ...change.before, ...before };\n }\n}\n\nexport function tryUpdateConflicts(pendingChanges: PendingChange[], conflicts?: Record<string, Conflict>): Record<string, Conflict> | undefined {\n if (!conflicts) return conflicts;\n\n const newConflicts = { ...conflicts };\n\n for (const change of pendingChanges) {\n const conflict = newConflicts[change.localId];\n if (conflict && change.changes) {\n // Loop changed fields and update their old possibly stale value to the current local value\n const newFields = conflict.fields.map((f) => {\n if (f.key in change.changes) {\n return { ...f, localValue: change.changes[f.key] } as FieldConflict;\n }\n return f;\n });\n\n newConflicts[change.localId] = { stateKey: conflict.stateKey, fields: newFields };\n }\n }\n\n return newConflicts;\n}\n\nexport function findApi(stateKey: string, syncApi: Record<string, ApiFunctions>) {\n const api = syncApi[stateKey];\n if (!api || !api.add || !api.update || !api.remove || !api.list || !api.firstLoad) {\n throw new Error(`Missing API function(s) for state key: ${stateKey}.`);\n }\n return api;\n}\n\ntype ChangeRecord = {\n currentItem?: any;\n updatedItem?: any;\n changes: any;\n id?: any;\n};\n\n/**\n * Compares the top-level keys of items in `current` and `updated` arrays (assumed to have `_localId`).\n * Returns a Map where the key is `_localId` and the value is an object with:\n * - `currentItem`: The item from `current` (or `null` for additions).\n * - `updatedItem`: The item from `updated` (or `null` for deletions).\n * - `changes`: An object with differing top-level keys and their values (or the full item for additions, or `null` for deletions).\n */\nexport function findChanges(current: any[], updated: any[]): Map<string, ChangeRecord> {\n const currentMap = new Map<string, any>();\n for (const item of current) {\n if (item && item._localId) {\n currentMap.set(item._localId, { ...item });\n }\n }\n\n const changesMap = new Map<string, ChangeRecord>();\n\n // Check for changes and additions\n for (const update of updated) {\n const item = { ...update };\n if (item && item._localId) {\n const curr = currentMap.get(item._localId);\n if (curr) {\n const diff: any = {};\n for (const key in curr) {\n if (key !== '_localId' && curr[key] !== item[key]) {\n diff[key] = item[key];\n }\n }\n if (Object.keys(diff).length > 0) {\n // Changes\n changesMap.set(item._localId, { currentItem: curr, updatedItem: item, changes: diff, id: curr.id ?? item.id });\n }\n } else {\n // Addition\n changesMap.set(item._localId, { currentItem: null, updatedItem: item, changes: item, id: item.id });\n }\n }\n }\n\n // Check for deletions\n for (const [localId, curr] of currentMap) {\n if (!updated.some((u) => u && u._localId === localId)) {\n changesMap.set(localId, { currentItem: curr, updatedItem: null, changes: null, id: curr.id });\n }\n }\n\n return changesMap;\n}\n\nexport function hasKeysOrUndefined(obj: any): any {\n return Object.keys(obj).length === 0 ? undefined : obj;\n}\n\nexport function hasConflicts(get: any, localId: string): boolean {\n const state = get() as SyncState;\n if (state.syncState.conflicts) {\n return !!state.syncState.conflicts[localId];\n }\n return false;\n}\n\nexport function resolveConflict(set: any, localId: string, keepLocalFields: boolean) {\n set((state: any) => {\n const syncState: SyncState['syncState'] = state.syncState || {};\n const conflicts: Record<string, Conflict> = syncState.conflicts || {};\n const conflict = conflicts[localId];\n if (conflict) {\n const items = state[conflict.stateKey];\n const item = items.find((i: any) => i._localId === localId);\n if (!item) {\n return state;\n }\n\n const resolved: any = { ...item };\n let pendingChanges = [...syncState.pendingChanges];\n\n if (!keepLocalFields) {\n // Use remote value(s)\n for (const field of conflict.fields) {\n resolved[field.key] = field.remoteValue;\n }\n\n // Remove resolved pending change\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === conflict.stateKey && p.localId === localId));\n }\n\n // Replace with resolved item\n const nextItems = items.map((i: any) => (i._localId === localId ? resolved : i));\n const nextConflicts = { ...conflicts };\n delete nextConflicts[localId];\n\n return {\n [conflict.stateKey]: nextItems,\n syncState: {\n ...syncState,\n pendingChanges,\n conflicts: hasKeysOrUndefined(nextConflicts),\n },\n };\n }\n return state;\n });\n}\n","import { type ApiFunctions, type FieldConflict, type ConflictResolutionStrategy, type SyncedRecord, type PendingChange } from './types';\nimport { SyncAction } from './index';\nimport { createLocalId, hasKeysOrUndefined } from './helpers';\nimport type { Logger } from './logger';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: Logger, conflictResolutionStrategy: ConflictResolutionStrategy) {\n const lastPulled: Record<string, string> = get().syncState.lastPulled || {};\n const lastPulledAt = new Date(lastPulled[stateKey] || new Date(0));\n\n logger.debug(`[zync] pull:start stateKey=${stateKey} since=${lastPulledAt.toISOString()}`);\n\n const serverData = (await api.list(lastPulledAt)) as SyncedRecord[];\n if (!serverData?.length) return;\n\n let newest = lastPulledAt;\n\n set((state: any) => {\n let pendingChanges = [...(state.syncState.pendingChanges as PendingChange[])];\n const conflicts = { ...state.syncState.conflicts };\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items when pulling them again\n const pendingRemovalById = new Set(pendingChanges.filter((p) => p.stateKey === stateKey && p.action === SyncAction.Remove).map((p) => p.id));\n\n for (const remote of serverData) {\n const remoteUpdated = new Date(remote.updated_at);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n // If a Remove is pending for this localId, skip merging/adding to avoid briefly resurrecting the item\n if (pendingRemovalById.has(remote.id)) {\n logger.debug(`[zync] pull:skip-pending-remove stateKey=${stateKey} id=${remote.id}`);\n continue;\n }\n\n const localItem = localById.get(remote.id);\n if (remote.deleted) {\n if (localItem) {\n nextItems = nextItems.filter((i: any) => i.id !== remote.id);\n logger.debug(`[zync] pull:remove stateKey=${stateKey} id=${remote.id}`);\n }\n continue;\n }\n\n delete remote.deleted;\n\n if (localItem) {\n const pendingChange = pendingChanges.find((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (pendingChange) {\n logger.debug(`[zync] pull:conflict-strategy:${conflictResolutionStrategy} stateKey=${stateKey} id=${remote.id}`);\n\n switch (conflictResolutionStrategy) {\n case 'local-wins':\n // Ignore remote changes, keep local\n break;\n\n case 'remote-wins': {\n // Ignore local changes, keep remote\n const merged = { ...remote, _localId: localItem._localId };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Remove pending change so it isn't pushed after pull\n pendingChanges = pendingChanges.filter((p) => !(p.stateKey === stateKey && p.localId === localItem._localId));\n break;\n }\n\n case 'try-shallow-merge': {\n // List fields that local and remote have changed\n const changes = pendingChange.changes || {};\n const before = pendingChange.before || {};\n const fields: FieldConflict[] = Object.entries(changes)\n .filter(([k, localValue]) => k in before && k in remote && before[k] !== remote[k] && localValue !== remote[k])\n .map(([key, localValue]) => ({ key, localValue, remoteValue: remote[key] }));\n\n if (fields.length > 0) {\n logger.warn(`[zync] pull:${conflictResolutionStrategy}:conflicts-found`, JSON.stringify(fields, null, 4));\n conflicts[localItem._localId] = { stateKey, fields };\n } else {\n // No conflicts, merge remote into local but only preserve fields that were\n // actually changed locally\n const localChangedKeys = Object.keys(changes);\n const preservedLocal: any = { _localId: localItem._localId };\n for (const k of localChangedKeys) {\n if (k in localItem) preservedLocal[k] = localItem[k];\n }\n\n const merged = { ...remote, ...preservedLocal };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n // Merge now resolved, drop pending and conflict\n delete conflicts[localItem._localId];\n }\n break;\n }\n }\n } else {\n // No pending changes, merge remote into local\n const merged = { ...localItem, ...remote };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[zync] pull:merge-remote stateKey=${stateKey} id=${remote.id}`);\n }\n } else {\n // Add remote item (no local item)\n nextItems = [...nextItems, { ...remote, _localId: createLocalId() }];\n logger.debug(`[zync] pull:add stateKey=${stateKey} id=${remote.id}`);\n }\n }\n\n return {\n [stateKey]: nextItems,\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n conflicts: hasKeysOrUndefined(conflicts),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { hasConflicts, removeFromPendingChanges, samePendingVersion, setPendingChangeBefore, setPendingChangeToUpdate } from './helpers';\nimport { createLocalId, SyncAction } from './index';\nimport type { Logger } from './logger';\nimport type {\n AfterRemoteAddCallback,\n ApiFunctions,\n MissingRemoteRecordStrategy,\n MissingRemoteRecordDuringUpdateCallback,\n PendingChange,\n SetAndSyncCallback,\n} from './types';\n\nexport async function pushOne(\n set: any,\n get: any,\n change: PendingChange,\n api: ApiFunctions,\n logger: Logger,\n setAndQueueToSync: SetAndSyncCallback,\n missingStrategy: MissingRemoteRecordStrategy,\n onMissingRemoteRecordDuringUpdate?: MissingRemoteRecordDuringUpdateCallback,\n onAfterRemoteAdd?: AfterRemoteAddCallback,\n) {\n logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version, changes } = change;\n\n switch (action) {\n case SyncAction.Remove:\n if (!id) {\n logger.warn(`[zync] push:remove:no-id stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n await api.remove(id);\n logger.debug(`[zync] push:remove:success stateKey=${stateKey} localId=${localId} id=${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.Update: {\n if (hasConflicts(get, change.localId)) {\n logger.warn(`[zync] push:update:skipping-with-conflicts stateKey=${stateKey} localId=${localId} id=${id}`);\n return;\n }\n\n const exists = await api.update(id, changes);\n if (exists) {\n logger.debug(`[zync] push:update:success stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure pending.before is not stale for conflict resolution\n setPendingChangeBefore(get, stateKey, localId, changes);\n }\n return;\n } else {\n const state = get();\n const items: any[] = state[stateKey] || [];\n const item = items.find((i) => i._localId === localId);\n if (!item) {\n logger.warn(`[zync] push:missing-remote:no-local-item stateKey=${stateKey} localId=${localId}`);\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n switch (missingStrategy) {\n case 'delete-local-record':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n case 'insert-remote-record': {\n const newItem = {\n ...item,\n _localId: createLocalId(),\n updated_at: new Date().toISOString(),\n };\n\n // replace old with modified and queue Create\n setAndQueueToSync((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? newItem : i)),\n }));\n\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${newItem.id}`);\n break;\n }\n\n case 'ignore':\n logger.debug(`[zync] push:missing-remote:${missingStrategy} stateKey=${stateKey} id=${item.id}`);\n break;\n\n default:\n logger.error(`[zync] push:missing-remote:unknown-strategy stateKey=${stateKey} id=${item.id} strategy=${missingStrategy}`);\n break;\n }\n\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, item);\n }\n break;\n }\n\n case SyncAction.Create: {\n const result = await api.add(changes);\n if (result) {\n logger.debug(`[zync] push:create:success stateKey=${stateKey} localId=${localId} id=${id}`);\n\n // Merge server-assigned fields (id, updated_at, etc) directly into local entity\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? { ...i, ...result } : i)),\n }));\n\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n } else {\n // Item changed during request, ensure any pendingChanges entry has id and is now an Update\n setPendingChangeToUpdate(get, stateKey, localId, result.id);\n }\n\n const finalItem = { ...changes, ...result, _localId: localId };\n\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, setAndQueueToSync, stateKey, finalItem);\n } else {\n logger.warn(`[zync] push:create:no-result stateKey=${stateKey} localId=${localId} id=${id}`);\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\n }\n }\n}\n","import { findApi, createLocalId } from './helpers';\nimport type { Logger } from './logger';\nimport type { ApiFunctions } from './types';\n\nexport async function startFirstLoad(set: any, syncApi: Record<string, ApiFunctions>, logger: Logger) {\n let syncError: Error | undefined;\n\n for (const stateKey of Object.keys(syncApi)) {\n try {\n logger.info(`[zync] firstLoad:start stateKey=${stateKey}`);\n\n const api = findApi(stateKey, syncApi);\n let lastId; // Start as undefined to allow the userland api code to set the initial value+type\n\n // Batch until empty\n while (true) {\n const batch = await api.firstLoad(lastId);\n if (!batch?.length) break;\n\n // Merge batch\n set((state: any) => {\n const local: any[] = state[stateKey] || [];\n const localById = new Map<any, any>(local.filter((l) => l.id).map((l) => [l.id, l]));\n\n let newest = new Date(state.syncState.lastPulled[stateKey] || 0);\n const next = [...local];\n for (const remote of batch) {\n const remoteUpdated = new Date(remote.updated_at || 0);\n if (remoteUpdated > newest) newest = remoteUpdated;\n\n if (remote.deleted) continue;\n\n delete remote.deleted;\n\n const localItem = remote.id ? localById.get(remote.id) : undefined;\n if (localItem) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n const idx = next.findIndex((i) => i._localId === localItem._localId);\n if (idx >= 0) next[idx] = merged;\n } else {\n next.push({\n ...remote,\n _localId: createLocalId(),\n });\n }\n }\n\n return {\n [stateKey]: next,\n syncState: {\n ...(state.syncState || {}),\n lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n\n if (lastId !== undefined && lastId === batch[batch.length - 1].id) {\n throw new Error(`Duplicate records downloaded, stopping to prevent infinite loop`);\n }\n\n lastId = batch[batch.length - 1].id;\n }\n\n logger.info(`[zync] firstLoad:done stateKey=${stateKey}`);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[zync] firstLoad:error stateKey=${stateKey}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n firstLoadDone: true,\n error: syncError,\n },\n }));\n}\n","import type { IDBPDatabase } from 'idb';\n\nexport function createIndexedDB(dbName: string, storeName: string) {\n // dbPromise is created lazily by initDB() to avoid pulling `idb` into bundles\n let dbPromise: Promise<IDBPDatabase<any>> | null = null;\n\n async function initDB(): Promise<IDBPDatabase<any>> {\n if (dbPromise) return dbPromise;\n try {\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, 1, {\n upgrade(db: IDBPDatabase<any>) {\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName);\n }\n },\n });\n return dbPromise;\n } catch (_e) {\n throw new Error('Missing optional dependency \"idb\". Install it to use IndexedDB storage: npm install idb');\n }\n }\n\n async function ensureStore(): Promise<void> {\n const db = await initDB();\n if (db.objectStoreNames.contains(storeName)) return;\n const nextVersion = (db.version || 0) + 1;\n try {\n db.close();\n } catch (_e) {\n // ignore\n }\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, nextVersion, {\n upgrade(upg: IDBPDatabase<any>) {\n if (!upg.objectStoreNames.contains(storeName)) upg.createObjectStore(storeName);\n },\n });\n await dbPromise;\n }\n\n async function withRetry<T>(fn: (db: IDBPDatabase<any>) => Promise<T>): Promise<T> {\n try {\n const db = await initDB();\n return await fn(db);\n } catch (err: any) {\n const msg = String(err && err.message ? err.message : err);\n if (err && (err.name === 'NotFoundError' || /objectStore/i.test(msg))) {\n await ensureStore();\n const db2 = await initDB();\n return await fn(db2);\n }\n throw err;\n }\n }\n\n return {\n getItem: async (name: string): Promise<string | null> => {\n return withRetry(async (db) => {\n let v = await db.get(storeName, name);\n v = v ?? null; // Zustand expects null for missing keys\n return v;\n });\n },\n setItem: async (name: string, value: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.put(storeName, value, name);\n });\n },\n removeItem: async (name: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.delete(storeName, name);\n });\n },\n };\n}\n"],"mappings":"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","names":["SyncAction"]}
|