@anfenn/zync 0.4.0 → 0.4.2
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 +15 -17
- package/dist/index.cjs +17 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +17 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,30 +12,31 @@ Simple, unopinionated, bullet-proof, offline-first sync middleware for Zustand.
|
|
|
12
12
|
- **"It just works"** philosophy
|
|
13
13
|
- Optimistic UI updates
|
|
14
14
|
- Conflict resolution:
|
|
15
|
-
- '
|
|
16
|
-
- 'try-shallow-merge' allows the user to choose between
|
|
17
|
-
- Missing remote record during update strategy, to prevent accidental server deletion from losing
|
|
18
|
-
- 'ignore' | 'delete-local-record' | 'insert-remote-record'
|
|
15
|
+
- `'local-wins'` | `'remote-wins'` | `'try-shallow-merge'`
|
|
16
|
+
- `'try-shallow-merge'` allows the user to choose between local and remote changes if conflicts occur
|
|
17
|
+
- Missing remote record during update strategy, to prevent accidental server deletion from losing local data:
|
|
18
|
+
- `'ignore'` | `'delete-local-record'` | `'insert-remote-record'`
|
|
19
19
|
- Batteries optionally included:
|
|
20
20
|
- IndexedDB helper (based on [idb](https://www.npmjs.com/package/idb)): `createIndexedDBStorage()`
|
|
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.)
|
|
24
|
-
- Zync's persistWithSync() is a drop-in replacement for Zustand's persist()
|
|
24
|
+
- Zync's `persistWithSync()` is a drop-in replacement for Zustand's `persist()`
|
|
25
25
|
- Allows for idiomatic use of Zustand
|
|
26
|
-
- Leaves the api requests up to you (RESTful, GraphQL, etc.), just provide add()
|
|
26
|
+
- Leaves the api requests up to you (RESTful, GraphQL, etc.), just provide `add()`, `update()`, `remove()` and `list()`
|
|
27
27
|
- Client or server assigned primary key, of any datatype
|
|
28
|
-
- Fully tested on `localstorage` and `IndexedDB` (>80% code coverage)
|
|
28
|
+
- Fully tested on `localstorage` and `IndexedDB` (>80% code coverage, including stress tests)
|
|
29
29
|
- Client schema migrations are a breeze using Zustand's [migrate](https://zustand.docs.pmnd.rs/middlewares/persist#persisting-a-state-through-versioning-and-migrations) hook
|
|
30
30
|
- All Zync's internal state is accessible via the reactive `state.syncState` object
|
|
31
|
+
- Zero boilerplate code
|
|
31
32
|
|
|
32
33
|
## Requirements
|
|
33
34
|
|
|
34
35
|
- Client records will have a `_localId` field which is stable and never sent to the server. It is ideal for use as a key in JSX. The provided helper function `createLocalId()` returns a UUID, but you could use any unique value
|
|
35
36
|
- Server records must have:
|
|
36
37
|
|
|
37
|
-
- `id`: Any datatype, can be
|
|
38
|
-
- `updated_at`: Server assigned **_millisecond_** timestamp (db trigger or api layer). The client will never send this as the client clock is unlikely to be in sync with the server, so is never used for change detection. If it has a higher precision than millisecond, like PostgreSQL's microsecond timestampz, updates could be ignored.
|
|
38
|
+
- `id`: Any datatype, can be client OR server assigned
|
|
39
|
+
- `updated_at`: Server assigned **_millisecond_** timestamp (e.g. via db trigger or api layer). The client will never send this as the client clock is unlikely to be in sync with the server, so is never used for change detection. If it has a higher precision than millisecond, like PostgreSQL's microsecond timestampz, updates could be ignored.
|
|
39
40
|
- `deleted`: Boolean, used for soft deletes, to allow other clients to download deleted records to keep their local records in sync
|
|
40
41
|
|
|
41
42
|
**_TIP: If your endpoint doesn't have the same names as the 3 fields above, you can easily rename them in your `api.ts` file using the included `changeKeysFrom()` & `changeKeysTo()`_**
|
|
@@ -113,7 +114,7 @@ export const useStore = create<any>()(
|
|
|
113
114
|
// Triggered by the api.update() returning true or false confirming the existence of the remote record after an update
|
|
114
115
|
missingRemoteRecordDuringUpdateStrategy: 'ignore',
|
|
115
116
|
|
|
116
|
-
// Options: '
|
|
117
|
+
// Options: 'local-wins' | 'remote-wins' | 'try-shallow-merge'
|
|
117
118
|
// Default: 'try-shallow-merge' (Conflicts are listed in syncState.conflicts)
|
|
118
119
|
conflictResolutionStrategy: 'try-shallow-merge',
|
|
119
120
|
},
|
|
@@ -158,7 +159,7 @@ function App() {
|
|
|
158
159
|
// Zync's control api
|
|
159
160
|
useStore.sync.enable(true); // Defaults to false, enable to start syncing
|
|
160
161
|
//useStore.sync.startFirstLoad(); // Batch loads from server
|
|
161
|
-
//useStore.sync.resolveConflict(localId, true); // Keep
|
|
162
|
+
//useStore.sync.resolveConflict(localId, true); // Keep local or remote changes for a specific record
|
|
162
163
|
}, []);
|
|
163
164
|
|
|
164
165
|
return (
|
|
@@ -166,10 +167,7 @@ function App() {
|
|
|
166
167
|
<div>Sync Status: {syncState.status}</div>
|
|
167
168
|
<button
|
|
168
169
|
onClick={() =>
|
|
169
|
-
addFact({
|
|
170
|
-
_localId: createLocalId(),
|
|
171
|
-
title: 'New fact ' + Date.now(),
|
|
172
|
-
})
|
|
170
|
+
addFact({ _localId: createLocalId(), title: 'Fact ' + Date.now() })
|
|
173
171
|
}
|
|
174
172
|
>
|
|
175
173
|
Add Fact
|
|
@@ -270,7 +268,7 @@ async function firstLoad(lastId: any) {
|
|
|
270
268
|
|
|
271
269
|
## Optional IndexedDB storage
|
|
272
270
|
|
|
273
|
-
Using
|
|
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.
|
|
274
272
|
|
|
275
273
|
If you want to use the bundled `createIndexedDBStorage()` 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.
|
|
276
274
|
|
|
@@ -280,7 +278,7 @@ If you want to use the bundled `createIndexedDBStorage()` helper, install `idb`
|
|
|
280
278
|
npm install idb
|
|
281
279
|
```
|
|
282
280
|
|
|
283
|
-
When using IndexedDB Zustand saves the whole store under one key, which means indexes cannot be used to accelerate querying. However, if this becomes a performance issue due to the size of the store, then libraries like dexie.js instead of Zustand would be a better solution and provide the syntax for high performance queries.
|
|
281
|
+
When using IndexedDB Zustand saves the whole store under one key, which means indexes cannot be used to accelerate querying. However, if this becomes a performance issue due to the size of the store, then libraries like `dexie.js` instead of Zustand would be a better solution and provide the syntax for high performance queries.
|
|
284
282
|
|
|
285
283
|
From testing I've found Zustand and Zync are lightening fast even with 100,000 average sized state objects.
|
|
286
284
|
|
package/dist/index.cjs
CHANGED
|
@@ -398,7 +398,7 @@ function tryAddToPendingChanges(pendingChanges, stateKey, changes) {
|
|
|
398
398
|
queueItem.changes = { ...queueItem.changes, ...omittedItem };
|
|
399
399
|
}
|
|
400
400
|
} else if (action === "remove" /* Remove */ || hasChanges) {
|
|
401
|
-
pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem,
|
|
401
|
+
pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem, before: omitSyncFields(change.currentItem) });
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
}
|
|
@@ -410,6 +410,13 @@ function setPendingChangeToUpdate(get, stateKey, localId, id) {
|
|
|
410
410
|
if (id) change.id = id;
|
|
411
411
|
}
|
|
412
412
|
}
|
|
413
|
+
function setPendingChangeBefore(get, stateKey, localId, before) {
|
|
414
|
+
const pendingChanges = get().syncState.pendingChanges || [];
|
|
415
|
+
const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);
|
|
416
|
+
if (change) {
|
|
417
|
+
change.before = { ...change.before, ...before };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
413
420
|
function tryUpdateConflicts(pendingChanges, conflicts) {
|
|
414
421
|
if (!conflicts) return conflicts;
|
|
415
422
|
const newConflicts = { ...conflicts };
|
|
@@ -549,9 +556,9 @@ async function pull(set, get, stateKey, api, logger, conflictResolutionStrategy)
|
|
|
549
556
|
if (pendingChange) {
|
|
550
557
|
logger.debug(`[zync] pull:conflict-strategy:${conflictResolutionStrategy} stateKey=${stateKey} id=${remote.id}`);
|
|
551
558
|
switch (conflictResolutionStrategy) {
|
|
552
|
-
case "
|
|
559
|
+
case "local-wins":
|
|
553
560
|
break;
|
|
554
|
-
case "
|
|
561
|
+
case "remote-wins": {
|
|
555
562
|
const merged = { ...remote, _localId: localItem._localId };
|
|
556
563
|
nextItems = nextItems.map((i) => i._localId === localItem._localId ? merged : i);
|
|
557
564
|
pendingChanges = pendingChanges.filter((p) => !(p.stateKey === stateKey && p.localId === localItem._localId));
|
|
@@ -559,8 +566,8 @@ async function pull(set, get, stateKey, api, logger, conflictResolutionStrategy)
|
|
|
559
566
|
}
|
|
560
567
|
case "try-shallow-merge": {
|
|
561
568
|
const changes = pendingChange.changes || {};
|
|
562
|
-
const
|
|
563
|
-
const fields = Object.entries(changes).filter(([k, localValue]) => k in
|
|
569
|
+
const before = pendingChange.before || {};
|
|
570
|
+
const fields = Object.entries(changes).filter(([k, localValue]) => k in before && k in remote && before[k] !== remote[k] && localValue !== remote[k]).map(([key, localValue]) => ({ key, localValue, remoteValue: remote[key] }));
|
|
564
571
|
if (fields.length > 0) {
|
|
565
572
|
logger.warn(`[zync] pull:${conflictResolutionStrategy}:conflicts-found`, JSON.stringify(fields, null, 4));
|
|
566
573
|
conflicts[localItem._localId] = { stateKey, fields };
|
|
@@ -606,7 +613,6 @@ async function pull(set, get, stateKey, api, logger, conflictResolutionStrategy)
|
|
|
606
613
|
async function pushOne(set, get, change, api, logger, setAndQueueToSync, missingStrategy, onMissingRemoteRecordDuringUpdate, onAfterRemoteAdd) {
|
|
607
614
|
logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);
|
|
608
615
|
const { action, stateKey, localId, id, version, changes } = change;
|
|
609
|
-
const changesClone = { ...changes };
|
|
610
616
|
switch (action) {
|
|
611
617
|
case "remove" /* Remove */:
|
|
612
618
|
if (!id) {
|
|
@@ -623,11 +629,13 @@ async function pushOne(set, get, change, api, logger, setAndQueueToSync, missing
|
|
|
623
629
|
logger.warn(`[zync] push:update:skipping-with-conflicts stateKey=${stateKey} localId=${localId} id=${id}`);
|
|
624
630
|
return;
|
|
625
631
|
}
|
|
626
|
-
const exists = await api.update(id,
|
|
632
|
+
const exists = await api.update(id, changes);
|
|
627
633
|
if (exists) {
|
|
628
634
|
logger.debug(`[zync] push:update:success stateKey=${stateKey} localId=${localId} id=${id}`);
|
|
629
635
|
if (samePendingVersion(get, stateKey, localId, version)) {
|
|
630
636
|
removeFromPendingChanges(set, localId, stateKey);
|
|
637
|
+
} else {
|
|
638
|
+
setPendingChangeBefore(get, stateKey, localId, changes);
|
|
631
639
|
}
|
|
632
640
|
return;
|
|
633
641
|
} else {
|
|
@@ -671,7 +679,7 @@ async function pushOne(set, get, change, api, logger, setAndQueueToSync, missing
|
|
|
671
679
|
break;
|
|
672
680
|
}
|
|
673
681
|
case "create" /* Create */: {
|
|
674
|
-
const result = await api.add(
|
|
682
|
+
const result = await api.add(changes);
|
|
675
683
|
if (result) {
|
|
676
684
|
logger.debug(`[zync] push:create:success stateKey=${stateKey} localId=${localId} id=${id}`);
|
|
677
685
|
set((s) => ({
|
|
@@ -846,7 +854,7 @@ var DEFAULT_SYNC_INTERVAL_MILLIS = 2e3;
|
|
|
846
854
|
var DEFAULT_LOGGER = console;
|
|
847
855
|
var DEFAULT_MIN_LOG_LEVEL = "debug";
|
|
848
856
|
var DEFAULT_MISSING_REMOTE_RECORD_STRATEGY = "ignore";
|
|
849
|
-
var DEFAULT_CONFLICT_RESOLUTION_STRATEGY = "
|
|
857
|
+
var DEFAULT_CONFLICT_RESOLUTION_STRATEGY = "local-wins";
|
|
850
858
|
function createWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}) {
|
|
851
859
|
const store = (0, import_zustand.create)(persistWithSync(stateCreator, persistOptions, syncApi, syncOptions));
|
|
852
860
|
return new Promise((resolve) => {
|
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 = 'client-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, current: 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 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 'client-wins':\n // Ignore remote changes, keep local\n break;\n\n case 'server-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 current = pendingChange.current || {};\n const fields: FieldConflict[] = Object.entries(changes)\n .filter(([k, localValue]) => k in current && k in remote && current[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, 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 const changesClone = { ...changes }; // TODO: Test if needed\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, changesClone);\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 }\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(changesClone);\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":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,SAAS,uBAAuB;AAC5B,SAAQ,sBACH,oBAAoB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AACR;AAEA,SAAS,0BAA0B;AAC/B,SAAQ,yBACH,uBAAuB;AAAA,IACpB,UAAU,UAAU;AAAA,IACpB,UAAU,UAAU;AAAA,IACpB,UAAU,UAAU;AAAA,EACxB;AACR;AAIA,SAAS,iBAAiB,SAAS;AAC/B,QAAM,UAAU,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC7C,UAAM,WAAW,MAAM;AACnB,cAAQ,oBAAoB,WAAW,OAAO;AAC9C,cAAQ,oBAAoB,SAAS,KAAK;AAAA,IAC9C;AACA,UAAM,UAAU,MAAM;AAClB,cAAQ,KAAK,QAAQ,MAAM,CAAC;AAC5B,eAAS;AAAA,IACb;AACA,UAAM,QAAQ,MAAM;AAChB,aAAO,QAAQ,KAAK;AACpB,eAAS;AAAA,IACb;AACA,YAAQ,iBAAiB,WAAW,OAAO;AAC3C,YAAQ,iBAAiB,SAAS,KAAK;AAAA,EAC3C,CAAC;AAGD,wBAAsB,IAAI,SAAS,OAAO;AAC1C,SAAO;AACX;AACA,SAAS,+BAA+B,IAAI;AAExC,MAAI,mBAAmB,IAAI,EAAE;AACzB;AACJ,QAAM,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC1C,UAAM,WAAW,MAAM;AACnB,SAAG,oBAAoB,YAAY,QAAQ;AAC3C,SAAG,oBAAoB,SAAS,KAAK;AACrC,SAAG,oBAAoB,SAAS,KAAK;AAAA,IACzC;AACA,UAAM,WAAW,MAAM;AACnB,cAAQ;AACR,eAAS;AAAA,IACb;AACA,UAAM,QAAQ,MAAM;AAChB,aAAO,GAAG,SAAS,IAAI,aAAa,cAAc,YAAY,CAAC;AAC/D,eAAS;AAAA,IACb;AACA,OAAG,iBAAiB,YAAY,QAAQ;AACxC,OAAG,iBAAiB,SAAS,KAAK;AAClC,OAAG,iBAAiB,SAAS,KAAK;AAAA,EACtC,CAAC;AAED,qBAAmB,IAAI,IAAI,IAAI;AACnC;AA6BA,SAAS,aAAa,UAAU;AAC5B,kBAAgB,SAAS,aAAa;AAC1C;AACA,SAAS,aAAa,MAAM;AAQxB,MAAI,wBAAwB,EAAE,SAAS,IAAI,GAAG;AAC1C,WAAO,YAAa,MAAM;AAGtB,WAAK,MAAM,OAAO,IAAI,GAAG,IAAI;AAC7B,aAAO,KAAK,KAAK,OAAO;AAAA,IAC5B;AAAA,EACJ;AACA,SAAO,YAAa,MAAM;AAGtB,WAAO,KAAK,KAAK,MAAM,OAAO,IAAI,GAAG,IAAI,CAAC;AAAA,EAC9C;AACJ;AACA,SAAS,uBAAuB,OAAO;AACnC,MAAI,OAAO,UAAU;AACjB,WAAO,aAAa,KAAK;AAG7B,MAAI,iBAAiB;AACjB,mCAA+B,KAAK;AACxC,MAAI,cAAc,OAAO,qBAAqB,CAAC;AAC3C,WAAO,IAAI,MAAM,OAAO,aAAa;AAEzC,SAAO;AACX;AACA,SAAS,KAAK,OAAO;AAGjB,MAAI,iBAAiB;AACjB,WAAO,iBAAiB,KAAK;AAGjC,MAAI,eAAe,IAAI,KAAK;AACxB,WAAO,eAAe,IAAI,KAAK;AACnC,QAAM,WAAW,uBAAuB,KAAK;AAG7C,MAAI,aAAa,OAAO;AACpB,mBAAe,IAAI,OAAO,QAAQ;AAClC,0BAAsB,IAAI,UAAU,KAAK;AAAA,EAC7C;AACA,SAAO;AACX;AAUA,SAAS,OAAO,MAAM,SAAS,EAAE,SAAS,SAAS,UAAU,WAAW,IAAI,CAAC,GAAG;AAC5E,QAAM,UAAU,UAAU,KAAK,MAAM,OAAO;AAC5C,QAAM,cAAc,KAAK,OAAO;AAChC,MAAI,SAAS;AACT,YAAQ,iBAAiB,iBAAiB,CAAC,UAAU;AACjD,cAAQ,KAAK,QAAQ,MAAM,GAAG,MAAM,YAAY,MAAM,YAAY,KAAK,QAAQ,WAAW,GAAG,KAAK;AAAA,IACtG,CAAC;AAAA,EACL;AACA,MAAI,SAAS;AACT,YAAQ,iBAAiB,WAAW,CAAC,UAAU;AAAA;AAAA,MAE/C,MAAM;AAAA,MAAY,MAAM;AAAA,MAAY;AAAA,IAAK,CAAC;AAAA,EAC9C;AACA,cACK,KAAK,CAAC,OAAO;AACd,QAAI;AACA,SAAG,iBAAiB,SAAS,MAAM,WAAW,CAAC;AACnD,QAAI,UAAU;AACV,SAAG,iBAAiB,iBAAiB,CAAC,UAAU,SAAS,MAAM,YAAY,MAAM,YAAY,KAAK,CAAC;AAAA,IACvG;AAAA,EACJ,CAAC,EACI,MAAM,MAAM;AAAA,EAAE,CAAC;AACpB,SAAO;AACX;AAMA,SAAS,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC,GAAG;AACtC,QAAM,UAAU,UAAU,eAAe,IAAI;AAC7C,MAAI,SAAS;AACT,YAAQ,iBAAiB,WAAW,CAAC,UAAU;AAAA;AAAA,MAE/C,MAAM;AAAA,MAAY;AAAA,IAAK,CAAC;AAAA,EAC5B;AACA,SAAO,KAAK,OAAO,EAAE,KAAK,MAAM,MAAS;AAC7C;AAKA,SAAS,UAAU,QAAQ,MAAM;AAC7B,MAAI,EAAE,kBAAkB,eACpB,EAAE,QAAQ,WACV,OAAO,SAAS,WAAW;AAC3B;AAAA,EACJ;AACA,MAAI,cAAc,IAAI,IAAI;AACtB,WAAO,cAAc,IAAI,IAAI;AACjC,QAAM,iBAAiB,KAAK,QAAQ,cAAc,EAAE;AACpD,QAAM,WAAW,SAAS;AAC1B,QAAM,UAAU,aAAa,SAAS,cAAc;AACpD;AAAA;AAAA,IAEA,EAAE,mBAAmB,WAAW,WAAW,gBAAgB,cACvD,EAAE,WAAW,YAAY,SAAS,cAAc;AAAA,IAAI;AACpD;AAAA,EACJ;AACA,QAAM,SAAS,eAAgB,cAAc,MAAM;AAE/C,UAAM,KAAK,KAAK,YAAY,WAAW,UAAU,cAAc,UAAU;AACzE,QAAIA,UAAS,GAAG;AAChB,QAAI;AACA,MAAAA,UAASA,QAAO,MAAM,KAAK,MAAM,CAAC;AAMtC,YAAQ,MAAM,QAAQ,IAAI;AAAA,MACtBA,QAAO,cAAc,EAAE,GAAG,IAAI;AAAA,MAC9B,WAAW,GAAG;AAAA,IAClB,CAAC,GAAG,CAAC;AAAA,EACT;AACA,gBAAc,IAAI,MAAM,MAAM;AAC9B,SAAO;AACX;AAwBA,gBAAgB,WAAW,MAAM;AAE7B,MAAI,SAAS;AACb,MAAI,EAAE,kBAAkB,YAAY;AAChC,aAAS,MAAM,OAAO,WAAW,GAAG,IAAI;AAAA,EAC5C;AACA,MAAI,CAAC;AACD;AACJ,WAAS;AACT,QAAM,gBAAgB,IAAI,MAAM,QAAQ,mBAAmB;AAC3D,mCAAiC,IAAI,eAAe,MAAM;AAE1D,wBAAsB,IAAI,eAAe,OAAO,MAAM,CAAC;AACvD,SAAO,QAAQ;AACX,UAAM;AAEN,aAAS,OAAO,eAAe,IAAI,aAAa,KAAK,OAAO,SAAS;AACrE,mBAAe,OAAO,aAAa;AAAA,EACvC;AACJ;AACA,SAAS,eAAe,QAAQ,MAAM;AAClC,SAAS,SAAS,OAAO,iBACrB,cAAc,QAAQ,CAAC,UAAU,gBAAgB,SAAS,CAAC,KAC1D,SAAS,aAAa,cAAc,QAAQ,CAAC,UAAU,cAAc,CAAC;AAC/E;AAnSA,IAAM,eAEF,mBACA,sBAqBE,oBACA,gBACA,uBAgDF,eAmFE,QAgDA,aACA,cACA,eA2CA,oBACA,WACA,gBACA,kCACA;AA9PN;AAAA;AAAA;AAAA,IAAM,gBAAgB,CAAC,QAAQ,iBAAiB,aAAa,KAAK,CAAC,MAAM,kBAAkB,CAAC;AAwB5F,IAAM,qBAAqB,oBAAI,QAAQ;AACvC,IAAM,iBAAiB,oBAAI,QAAQ;AACnC,IAAM,wBAAwB,oBAAI,QAAQ;AAgD1C,IAAI,gBAAgB;AAAA,MAChB,IAAI,QAAQ,MAAM,UAAU;AACxB,YAAI,kBAAkB,gBAAgB;AAElC,cAAI,SAAS;AACT,mBAAO,mBAAmB,IAAI,MAAM;AAExC,cAAI,SAAS,SAAS;AAClB,mBAAO,SAAS,iBAAiB,CAAC,IAC5B,SACA,SAAS,YAAY,SAAS,iBAAiB,CAAC,CAAC;AAAA,UAC3D;AAAA,QACJ;AAEA,eAAO,KAAK,OAAO,IAAI,CAAC;AAAA,MAC5B;AAAA,MACA,IAAI,QAAQ,MAAM,OAAO;AACrB,eAAO,IAAI,IAAI;AACf,eAAO;AAAA,MACX;AAAA,MACA,IAAI,QAAQ,MAAM;AACd,YAAI,kBAAkB,mBACjB,SAAS,UAAU,SAAS,UAAU;AACvC,iBAAO;AAAA,QACX;AACA,eAAO,QAAQ;AAAA,MACnB;AAAA,IACJ;AAwDA,IAAM,SAAS,CAAC,UAAU,sBAAsB,IAAI,KAAK;AAgDzD,IAAM,cAAc,CAAC,OAAO,UAAU,UAAU,cAAc,OAAO;AACrE,IAAM,eAAe,CAAC,OAAO,OAAO,UAAU,OAAO;AACrD,IAAM,gBAAgB,oBAAI,IAAI;AAqC9B,iBAAa,CAAC,cAAc;AAAA,MACxB,GAAG;AAAA,MACH,KAAK,CAAC,QAAQ,MAAM,aAAa,UAAU,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC/F,KAAK,CAAC,QAAQ,SAAS,CAAC,CAAC,UAAU,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,IAAI;AAAA,IACjF,EAAE;AAEF,IAAM,qBAAqB,CAAC,YAAY,sBAAsB,SAAS;AACvE,IAAM,YAAY,CAAC;AACnB,IAAM,iBAAiB,oBAAI,QAAQ;AACnC,IAAM,mCAAmC,oBAAI,QAAQ;AACrD,IAAM,sBAAsB;AAAA,MACxB,IAAI,QAAQ,MAAM;AACd,YAAI,CAAC,mBAAmB,SAAS,IAAI;AACjC,iBAAO,OAAO,IAAI;AACtB,YAAI,aAAa,UAAU,IAAI;AAC/B,YAAI,CAAC,YAAY;AACb,uBAAa,UAAU,IAAI,IAAI,YAAa,MAAM;AAC9C,2BAAe,IAAI,MAAM,iCAAiC,IAAI,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;AAAA,UACtF;AAAA,QACJ;AACA,eAAO;AAAA,MACX;AAAA,IACJ;AA0BA,iBAAa,CAAC,cAAc;AAAA,MACxB,GAAG;AAAA,MACH,IAAI,QAAQ,MAAM,UAAU;AACxB,YAAI,eAAe,QAAQ,IAAI;AAC3B,iBAAO;AACX,eAAO,SAAS,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC9C;AAAA,MACA,IAAI,QAAQ,MAAM;AACd,eAAO,eAAe,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,IAAI;AAAA,MACpE;AAAA,IACJ,EAAE;AAAA;AAAA;;;AC9SF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0C;AAC1C,wBAAwB;;;ACQjB,SAAS,UAAU,MAAc,KAAuB;AAC3D,QAAM,QAAkC;AAAA,IACpC,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACV;AACA,QAAM,YAAY,MAAM,GAAG;AAC3B,QAAM,UAAU,CAAC,QAAkB,MAAM,GAAG,KAAK;AACjD,SAAO;AAAA,IACH,OAAO,IAAI,MAAa,QAAQ,OAAO,KAAK,KAAK,QAAQ,GAAG,CAAC;AAAA,IAC7D,MAAM,IAAI,MAAa,QAAQ,MAAM,KAAK,KAAK,OAAO,GAAG,CAAC;AAAA,IAC1D,MAAM,IAAI,MAAa,QAAQ,MAAM,KAAK,KAAK,OAAO,GAAG,CAAC;AAAA,IAC1D,OAAO,IAAI,MAAa,QAAQ,OAAO,KAAK,KAAK,QAAQ,GAAG,CAAC;AAAA,EACjE;AACJ;;;ACtBA,IAAM,cAAc,CAAC,YAAY,cAAc,SAAS;AAEjD,SAAS,gBAAwB;AACpC,SAAO,OAAO,WAAW;AAC7B;AAEO,SAAS,MAAM,IAA2B;AAC7C,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAC3D;AAEO,SAAS,aAAa,OAAoB,SAAiB,gBAAwB,cAAsB;AAC5G,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,QAAM,UAAU,UAAU,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS;AACrD,UAAM,EAAE,IAAI,YAAY,SAAS,GAAG,KAAK,IAAI;AAC7C,WAAO;AAAA,MACH,CAAC,OAAO,GAAG;AAAA,MACX,CAAC,cAAc,GAAG;AAAA,MAClB,CAAC,YAAY,GAAG;AAAA,MAChB,GAAG;AAAA,IACP;AAAA,EACJ,CAAC;AACD,SAAO,UAAU,SAAS,OAAO,CAAC;AACtC;AAEO,SAAS,eAAe,OAAoB,WAAmB,kBAA0B,gBAAwB;AACpH,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,QAAM,UAAU,UAAU,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS;AACrD,UAAM,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,cAAc,GAAG,SAAS,GAAG,KAAK,IAAI;AAChG,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACP;AAAA,EACJ,CAAC;AACD,SAAO,UAAU,SAAS,OAAO,CAAC;AACtC;AAEO,SAAS,SAAS,GAAuB;AAC5C,UAAQ,GAAG;AAAA,IACP;AACI,aAAO;AAAA,IACX;AACI,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EACf;AACJ;AAEO,SAAS,eAAe,MAAW;AACtC,QAAM,SAAS,EAAE,GAAG,KAAK;AACzB,aAAW,KAAK,YAAa,QAAO,OAAO,CAAC;AAC5C,SAAO;AACX;AAEO,SAAS,mBAAmB,KAAU,UAAkB,SAAiB,SAA0B;AACtG,QAAM,UAA2B,IAAI,EAAE,UAAU,kBAAkB,CAAC;AACpE,QAAM,YAAY,QAAQ,KAAK,CAAC,MAAM,EAAE,YAAY,WAAW,EAAE,aAAa,QAAQ;AACtF,SAAO,WAAW,YAAY;AAClC;AAEO,SAAS,yBAAyB,KAAU,SAAiB,UAAkB;AAClF,MAAI,CAAC,MAAW;AACZ,UAAM,SAA0B,EAAE,UAAU,kBAAkB,CAAC,GAAG,OAAO,CAAC,MAAqB,EAAE,EAAE,YAAY,WAAW,EAAE,aAAa,SAAS;AAClJ,WAAO;AAAA,MACH,WAAW;AAAA,QACP,GAAI,EAAE,aAAa,CAAC;AAAA,QACpB,gBAAgB;AAAA,MACpB;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAEO,SAAS,uBAAuB,gBAAiC,UAAkB,SAAoC;AAC1H,aAAW,CAAC,SAAS,MAAM,KAAK,SAAS;AACrC,QAAI,cAAc,eAAe,OAAO,OAAO;AAC/C,UAAM,YAAY,eAAe,KAAK,CAAC,MAAM,EAAE,YAAY,WAAW,EAAE,aAAa,QAAQ;AAC7F,UAAM,aAAa,OAAO,KAAK,WAAW,EAAE,SAAS;AACrD,UAAM,SAAS,OAAO,gBAAgB,+BAA2B,OAAO,gBAAgB;AAExF,QAAI,oCAAgC,OAAO,eAAe,OAAO,eAAe,OAAO,YAAY,aAAa,OAAO,YAAY,UAAU;AAEzI,oBAAc,eAAe,OAAO,WAAW;AAAA,IACnD;AAEA,QAAI,WAAW;AACX,UAAI,UAAU,kCAA8B;AAExC;AAAA,MACJ;AAEA,gBAAU,WAAW;AAErB,UAAI,kCAA8B;AAC9B,kBAAU;AAAA,MACd,WAAW,YAAY;AAEnB,kBAAU,UAAU,EAAE,GAAG,UAAU,SAAS,GAAG,YAAY;AAAA,MAC/D;AAAA,IACJ,WAAW,oCAAgC,YAAY;AACnD,qBAAe,KAAK,EAAE,QAAQ,UAAU,SAAS,IAAI,OAAO,IAAI,SAAS,GAAG,SAAS,aAAa,SAAS,eAAe,OAAO,WAAW,EAAE,CAAC;AAAA,IACnJ;AAAA,EACJ;AACJ;AAEO,SAAS,yBAAyB,KAAU,UAAkB,SAAiB,IAAU;AAE5F,QAAM,iBAAkC,IAAI,EAAE,UAAU,kBAAkB,CAAC;AAC3E,QAAM,SAAS,eAAe,KAAK,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE,YAAY,OAAO;AAC1F,MAAI,QAAQ;AACR,WAAO;AACP,QAAI,GAAI,QAAO,KAAK;AAAA,EACxB;AACJ;AAEO,SAAS,mBAAmB,gBAAiC,WAA4E;AAC5I,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,eAAe,EAAE,GAAG,UAAU;AAEpC,aAAW,UAAU,gBAAgB;AACjC,UAAM,WAAW,aAAa,OAAO,OAAO;AAC5C,QAAI,YAAY,OAAO,SAAS;AAE5B,YAAM,YAAY,SAAS,OAAO,IAAI,CAAC,MAAM;AACzC,YAAI,EAAE,OAAO,OAAO,SAAS;AACzB,iBAAO,EAAE,GAAG,GAAG,YAAY,OAAO,QAAQ,EAAE,GAAG,EAAE;AAAA,QACrD;AACA,eAAO;AAAA,MACX,CAAC;AAED,mBAAa,OAAO,OAAO,IAAI,EAAE,UAAU,SAAS,UAAU,QAAQ,UAAU;AAAA,IACpF;AAAA,EACJ;AAEA,SAAO;AACX;AAEO,SAAS,QAAQ,UAAkB,SAAuC;AAC7E,QAAM,MAAM,QAAQ,QAAQ;AAC5B,MAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,QAAQ,CAAC,IAAI,WAAW;AAC/E,UAAM,IAAI,MAAM,0CAA0C,QAAQ,GAAG;AAAA,EACzE;AACA,SAAO;AACX;AAgBO,SAAS,YAAY,SAAgB,SAA2C;AACnF,QAAM,aAAa,oBAAI,IAAiB;AACxC,aAAW,QAAQ,SAAS;AACxB,QAAI,QAAQ,KAAK,UAAU;AACvB,iBAAW,IAAI,KAAK,UAAU,EAAE,GAAG,KAAK,CAAC;AAAA,IAC7C;AAAA,EACJ;AAEA,QAAM,aAAa,oBAAI,IAA0B;AAGjD,aAAW,UAAU,SAAS;AAC1B,UAAM,OAAO,EAAE,GAAG,OAAO;AACzB,QAAI,QAAQ,KAAK,UAAU;AACvB,YAAM,OAAO,WAAW,IAAI,KAAK,QAAQ;AACzC,UAAI,MAAM;AACN,cAAM,OAAY,CAAC;AACnB,mBAAW,OAAO,MAAM;AACpB,cAAI,QAAQ,cAAc,KAAK,GAAG,MAAM,KAAK,GAAG,GAAG;AAC/C,iBAAK,GAAG,IAAI,KAAK,GAAG;AAAA,UACxB;AAAA,QACJ;AACA,YAAI,OAAO,KAAK,IAAI,EAAE,SAAS,GAAG;AAE9B,qBAAW,IAAI,KAAK,UAAU,EAAE,aAAa,MAAM,aAAa,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,QACjH;AAAA,MACJ,OAAO;AAEH,mBAAW,IAAI,KAAK,UAAU,EAAE,aAAa,MAAM,aAAa,MAAM,SAAS,MAAM,IAAI,KAAK,GAAG,CAAC;AAAA,MACtG;AAAA,IACJ;AAAA,EACJ;AAGA,aAAW,CAAC,SAAS,IAAI,KAAK,YAAY;AACtC,QAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,KAAK,EAAE,aAAa,OAAO,GAAG;AACnD,iBAAW,IAAI,SAAS,EAAE,aAAa,MAAM,aAAa,MAAM,SAAS,MAAM,IAAI,KAAK,GAAG,CAAC;AAAA,IAChG;AAAA,EACJ;AAEA,SAAO;AACX;AAEO,SAAS,mBAAmB,KAAe;AAC9C,SAAO,OAAO,KAAK,GAAG,EAAE,WAAW,IAAI,SAAY;AACvD;AAEO,SAAS,aAAa,KAAU,SAA0B;AAC7D,QAAM,QAAQ,IAAI;AAClB,MAAI,MAAM,UAAU,WAAW;AAC3B,WAAO,CAAC,CAAC,MAAM,UAAU,UAAU,OAAO;AAAA,EAC9C;AACA,SAAO;AACX;AAEO,SAAS,gBAAgB,KAAU,SAAiB,iBAA0B;AACjF,MAAI,CAAC,UAAe;AAChB,UAAM,YAAoC,MAAM,aAAa,CAAC;AAC9D,UAAM,YAAsC,UAAU,aAAa,CAAC;AACpE,UAAM,WAAW,UAAU,OAAO;AAClC,QAAI,UAAU;AACV,YAAM,QAAQ,MAAM,SAAS,QAAQ;AACrC,YAAM,OAAO,MAAM,KAAK,CAAC,MAAW,EAAE,aAAa,OAAO;AAC1D,UAAI,CAAC,MAAM;AACP,eAAO;AAAA,MACX;AAEA,YAAM,WAAgB,EAAE,GAAG,KAAK;AAChC,UAAI,iBAAiB,CAAC,GAAG,UAAU,cAAc;AAEjD,UAAI,CAAC,iBAAiB;AAElB,mBAAW,SAAS,SAAS,QAAQ;AACjC,mBAAS,MAAM,GAAG,IAAI,MAAM;AAAA,QAChC;AAGA,yBAAiB,eAAe,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,SAAS,YAAY,EAAE,YAAY,QAAQ;AAAA,MAC9G;AAGA,YAAM,YAAY,MAAM,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,CAAE;AAC/E,YAAM,gBAAgB,EAAE,GAAG,UAAU;AACrC,aAAO,cAAc,OAAO;AAE5B,aAAO;AAAA,QACH,CAAC,SAAS,QAAQ,GAAG;AAAA,QACrB,WAAW;AAAA,UACP,GAAG;AAAA,UACH;AAAA,UACA,WAAW,mBAAmB,aAAa;AAAA,QAC/C;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX,CAAC;AACL;;;AChQA,eAAsB,KAAK,KAAU,KAAU,UAAkB,KAAmB,QAAgB,4BAAwD;AACxJ,QAAM,aAAqC,IAAI,EAAE,UAAU,cAAc,CAAC;AAC1E,QAAM,eAAe,IAAI,KAAK,WAAW,QAAQ,KAAK,oBAAI,KAAK,CAAC,CAAC;AAEjE,SAAO,MAAM,8BAA8B,QAAQ,UAAU,aAAa,YAAY,CAAC,EAAE;AAEzF,QAAM,aAAc,MAAM,IAAI,KAAK,YAAY;AAC/C,MAAI,CAAC,YAAY,OAAQ;AAEzB,MAAI,SAAS;AAEb,MAAI,CAAC,UAAe;AAChB,QAAI,iBAAiB,CAAC,GAAI,MAAM,UAAU,cAAkC;AAC5E,UAAM,YAAY,EAAE,GAAG,MAAM,UAAU,UAAU;AACjD,UAAM,aAAoB,MAAM,QAAQ,KAAK,CAAC;AAC9C,QAAI,YAAY,CAAC,GAAG,UAAU;AAE9B,UAAM,YAAY,IAAI,IAAc,WAAW,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAExF,UAAM,qBAAqB,IAAI,IAAI,eAAe,OAAO,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE,gCAA4B,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAE3I,eAAW,UAAU,YAAY;AAC7B,YAAM,gBAAgB,IAAI,KAAK,OAAO,UAAU;AAChD,UAAI,gBAAgB,OAAQ,UAAS;AAGrC,UAAI,mBAAmB,IAAI,OAAO,EAAE,GAAG;AACnC,eAAO,MAAM,4CAA4C,QAAQ,OAAO,OAAO,EAAE,EAAE;AACnF;AAAA,MACJ;AAEA,YAAM,YAAY,UAAU,IAAI,OAAO,EAAE;AACzC,UAAI,OAAO,SAAS;AAChB,YAAI,WAAW;AACX,sBAAY,UAAU,OAAO,CAAC,MAAW,EAAE,OAAO,OAAO,EAAE;AAC3D,iBAAO,MAAM,+BAA+B,QAAQ,OAAO,OAAO,EAAE,EAAE;AAAA,QAC1E;AACA;AAAA,MACJ;AAEA,aAAO,OAAO;AAEd,UAAI,WAAW;AACX,cAAM,gBAAgB,eAAe,KAAK,CAAC,MAAW,EAAE,aAAa,YAAY,EAAE,YAAY,UAAU,QAAQ;AACjH,YAAI,eAAe;AACf,iBAAO,MAAM,iCAAiC,0BAA0B,aAAa,QAAQ,OAAO,OAAO,EAAE,EAAE;AAE/G,kBAAQ,4BAA4B;AAAA,YAChC,KAAK;AAED;AAAA,YAEJ,KAAK,eAAe;AAEhB,oBAAM,SAAS,EAAE,GAAG,QAAQ,UAAU,UAAU,SAAS;AACzD,0BAAY,UAAU,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,SAAS,CAAE;AAEtF,+BAAiB,eAAe,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,YAAY,EAAE,YAAY,UAAU,SAAS;AAC5G;AAAA,YACJ;AAAA,YAEA,KAAK,qBAAqB;AAEtB,oBAAM,UAAU,cAAc,WAAW,CAAC;AAC1C,oBAAM,UAAU,cAAc,WAAW,CAAC;AAC1C,oBAAM,SAA0B,OAAO,QAAQ,OAAO,EACjD,OAAO,CAAC,CAAC,GAAG,UAAU,MAAM,KAAK,WAAW,KAAK,UAAU,QAAQ,CAAC,MAAM,OAAO,CAAC,KAAK,eAAe,OAAO,CAAC,CAAC,EAC/G,IAAI,CAAC,CAAC,KAAK,UAAU,OAAO,EAAE,KAAK,YAAY,aAAa,OAAO,GAAG,EAAE,EAAE;AAE/E,kBAAI,OAAO,SAAS,GAAG;AACnB,uBAAO,KAAK,eAAe,0BAA0B,oBAAoB,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AACxG,0BAAU,UAAU,QAAQ,IAAI,EAAE,UAAU,OAAO;AAAA,cACvD,OAAO;AAGH,sBAAM,mBAAmB,OAAO,KAAK,OAAO;AAC5C,sBAAM,iBAAsB,EAAE,UAAU,UAAU,SAAS;AAC3D,2BAAW,KAAK,kBAAkB;AAC9B,sBAAI,KAAK,UAAW,gBAAe,CAAC,IAAI,UAAU,CAAC;AAAA,gBACvD;AAEA,sBAAM,SAAS,EAAE,GAAG,QAAQ,GAAG,eAAe;AAC9C,4BAAY,UAAU,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,SAAS,CAAE;AAEtF,uBAAO,UAAU,UAAU,QAAQ;AAAA,cACvC;AACA;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAEH,gBAAM,SAAS,EAAE,GAAG,WAAW,GAAG,OAAO;AACzC,sBAAY,UAAU,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,SAAS,CAAE;AACtF,iBAAO,MAAM,qCAAqC,QAAQ,OAAO,OAAO,EAAE,EAAE;AAAA,QAChF;AAAA,MACJ,OAAO;AAEH,oBAAY,CAAC,GAAG,WAAW,EAAE,GAAG,QAAQ,UAAU,cAAc,EAAE,CAAC;AACnE,eAAO,MAAM,4BAA4B,QAAQ,OAAO,OAAO,EAAE,EAAE;AAAA,MACvE;AAAA,IACJ;AAEA,WAAO;AAAA,MACH,CAAC,QAAQ,GAAG;AAAA,MACZ,WAAW;AAAA,QACP,GAAI,MAAM,aAAa,CAAC;AAAA,QACxB;AAAA,QACA,WAAW,mBAAmB,SAAS;AAAA,QACvC,YAAY;AAAA,UACR,GAAI,MAAM,UAAU,cAAc,CAAC;AAAA,UACnC,CAAC,QAAQ,GAAG,OAAO,YAAY;AAAA,QACnC;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;;;AC5GA,eAAsB,QAClB,KACA,KACA,QACA,KACA,QACA,mBACA,iBACA,mCACA,kBACF;AACE,SAAO,MAAM,8BAA8B,OAAO,MAAM,aAAa,OAAO,QAAQ,YAAY,OAAO,OAAO,EAAE;AAEhH,QAAM,EAAE,QAAQ,UAAU,SAAS,IAAI,SAAS,QAAQ,IAAI;AAC5D,QAAM,eAAe,EAAE,GAAG,QAAQ;AAElC,UAAQ,QAAQ;AAAA,IACZ;AACI,UAAI,CAAC,IAAI;AACL,eAAO,KAAK,qCAAqC,QAAQ,YAAY,OAAO,EAAE;AAC9E,iCAAyB,KAAK,SAAS,QAAQ;AAC/C;AAAA,MACJ;AAEA,YAAM,IAAI,OAAO,EAAE;AACnB,aAAO,MAAM,uCAAuC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAC1F,+BAAyB,KAAK,SAAS,QAAQ;AAC/C;AAAA,IAEJ,4BAAwB;AACpB,UAAI,aAAa,KAAK,OAAO,OAAO,GAAG;AACnC,eAAO,KAAK,uDAAuD,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AACzG;AAAA,MACJ;AAEA,YAAM,SAAS,MAAM,IAAI,OAAO,IAAI,YAAY;AAChD,UAAI,QAAQ;AACR,eAAO,MAAM,uCAAuC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAC1F,YAAI,mBAAmB,KAAK,UAAU,SAAS,OAAO,GAAG;AACrD,mCAAyB,KAAK,SAAS,QAAQ;AAAA,QACnD;AACA;AAAA,MACJ,OAAO;AACH,cAAM,QAAQ,IAAI;AAClB,cAAM,QAAe,MAAM,QAAQ,KAAK,CAAC;AACzC,cAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,aAAa,OAAO;AACrD,YAAI,CAAC,MAAM;AACP,iBAAO,KAAK,qDAAqD,QAAQ,YAAY,OAAO,EAAE;AAC9F,mCAAyB,KAAK,SAAS,QAAQ;AAC/C;AAAA,QACJ;AAEA,gBAAQ,iBAAiB;AAAA,UACrB,KAAK;AACD,gBAAI,CAAC,OAAY;AAAA,cACb,CAAC,QAAQ,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,MAAW,EAAE,aAAa,OAAO;AAAA,YAC7E,EAAE;AACF,mBAAO,MAAM,8BAA8B,eAAe,aAAa,QAAQ,OAAO,KAAK,EAAE,EAAE;AAC/F;AAAA,UAEJ,KAAK,wBAAwB;AACzB,kBAAM,UAAU;AAAA,cACZ,GAAG;AAAA,cACH,UAAU,cAAc;AAAA,cACxB,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,YACvC;AAGA,8BAAkB,CAAC,OAAY;AAAA,cAC3B,CAAC,QAAQ,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,UAAU,CAAE;AAAA,YAC1F,EAAE;AAEF,mBAAO,MAAM,8BAA8B,eAAe,aAAa,QAAQ,OAAO,QAAQ,EAAE,EAAE;AAClG;AAAA,UACJ;AAAA,UAEA,KAAK;AACD,mBAAO,MAAM,8BAA8B,eAAe,aAAa,QAAQ,OAAO,KAAK,EAAE,EAAE;AAC/F;AAAA,UAEJ;AACI,mBAAO,MAAM,wDAAwD,QAAQ,OAAO,KAAK,EAAE,aAAa,eAAe,EAAE;AACzH;AAAA,QACR;AAEA,iCAAyB,KAAK,SAAS,QAAQ;AAE/C,4CAAoC,iBAAiB,IAAI;AAAA,MAC7D;AACA;AAAA,IACJ;AAAA,IAEA,4BAAwB;AACpB,YAAM,SAAS,MAAM,IAAI,IAAI,YAAY;AACzC,UAAI,QAAQ;AACR,eAAO,MAAM,uCAAuC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAG1F,YAAI,CAAC,OAAY;AAAA,UACb,CAAC,QAAQ,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,EAAE,GAAG,GAAG,GAAG,OAAO,IAAI,CAAE;AAAA,QACtG,EAAE;AAEF,YAAI,mBAAmB,KAAK,UAAU,SAAS,OAAO,GAAG;AACrD,mCAAyB,KAAK,SAAS,QAAQ;AAAA,QACnD,OAAO;AAEH,mCAAyB,KAAK,UAAU,SAAS,OAAO,EAAE;AAAA,QAC9D;AAEA,cAAM,YAAY,EAAE,GAAG,SAAS,GAAG,QAAQ,UAAU,QAAQ;AAG7D,2BAAmB,KAAK,KAAK,mBAAmB,UAAU,SAAS;AAAA,MACvE,OAAO;AACH,eAAO,KAAK,yCAAyC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAC3F,YAAI,mBAAmB,KAAK,UAAU,SAAS,OAAO,GAAG;AACrD,mCAAyB,KAAK,SAAS,QAAQ;AAAA,QACnD;AAAA,MACJ;AACA;AAAA,IACJ;AAAA,EACJ;AACJ;;;AClIA,eAAsB,eAAe,KAAU,SAAuC,QAAgB;AAClG,MAAI;AAEJ,aAAW,YAAY,OAAO,KAAK,OAAO,GAAG;AACzC,QAAI;AACA,aAAO,KAAK,mCAAmC,QAAQ,EAAE;AAEzD,YAAM,MAAM,QAAQ,UAAU,OAAO;AACrC,UAAI;AAGJ,aAAO,MAAM;AACT,cAAM,QAAQ,MAAM,IAAI,UAAU,MAAM;AACxC,YAAI,CAAC,OAAO,OAAQ;AAGpB,YAAI,CAAC,UAAe;AAChB,gBAAM,QAAe,MAAM,QAAQ,KAAK,CAAC;AACzC,gBAAM,YAAY,IAAI,IAAc,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEnF,cAAI,SAAS,IAAI,KAAK,MAAM,UAAU,WAAW,QAAQ,KAAK,CAAC;AAC/D,gBAAM,OAAO,CAAC,GAAG,KAAK;AACtB,qBAAW,UAAU,OAAO;AACxB,kBAAM,gBAAgB,IAAI,KAAK,OAAO,cAAc,CAAC;AACrD,gBAAI,gBAAgB,OAAQ,UAAS;AAErC,gBAAI,OAAO,QAAS;AAEpB,mBAAO,OAAO;AAEd,kBAAM,YAAY,OAAO,KAAK,UAAU,IAAI,OAAO,EAAE,IAAI;AACzD,gBAAI,WAAW;AACX,oBAAM,SAAS;AAAA,gBACX,GAAG;AAAA,gBACH,GAAG;AAAA,gBACH,UAAU,UAAU;AAAA,cACxB;AACA,oBAAM,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,aAAa,UAAU,QAAQ;AACnE,kBAAI,OAAO,EAAG,MAAK,GAAG,IAAI;AAAA,YAC9B,OAAO;AACH,mBAAK,KAAK;AAAA,gBACN,GAAG;AAAA,gBACH,UAAU,cAAc;AAAA,cAC5B,CAAC;AAAA,YACL;AAAA,UACJ;AAEA,iBAAO;AAAA,YACH,CAAC,QAAQ,GAAG;AAAA,YACZ,WAAW;AAAA,cACP,GAAI,MAAM,aAAa,CAAC;AAAA,cACxB,YAAY;AAAA,gBACR,GAAI,MAAM,UAAU,cAAc,CAAC;AAAA,gBACnC,CAAC,QAAQ,GAAG,OAAO,YAAY;AAAA,cACnC;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,CAAC;AAED,YAAI,WAAW,UAAa,WAAW,MAAM,MAAM,SAAS,CAAC,EAAE,IAAI;AAC/D,gBAAM,IAAI,MAAM,iEAAiE;AAAA,QACrF;AAEA,iBAAS,MAAM,MAAM,SAAS,CAAC,EAAE;AAAA,MACrC;AAEA,aAAO,KAAK,kCAAkC,QAAQ,EAAE;AAAA,IAC5D,SAAS,KAAK;AACV,kBAAY,aAAc;AAC1B,aAAO,MAAM,mCAAmC,QAAQ,IAAI,GAAG;AAAA,IACnE;AAAA,EACJ;AAEA,MAAI,CAAC,WAAgB;AAAA,IACjB,WAAW;AAAA,MACP,GAAI,MAAM,aAAa,CAAC;AAAA,MACxB,eAAe;AAAA,MACf,OAAO;AAAA,IACX;AAAA,EACJ,EAAE;AACN;;;AClFO,SAAS,uBAAuB,SAAgD;AACnF,QAAM,SAAS,QAAQ;AACvB,QAAM,YAAY,QAAQ;AAG1B,MAAI,YAA+C;AAEnD,iBAAe,SAAqC;AAChD,QAAI,UAAW,QAAO;AACtB,QAAI;AACA,YAAM,MAAM,MAAM;AAClB,kBAAY,IAAI,OAAO,QAAQ,GAAG;AAAA,QAC9B,QAAQ,IAAuB;AAC3B,cAAI,CAAC,GAAG,iBAAiB,SAAS,SAAS,GAAG;AAC1C,eAAG,kBAAkB,SAAS;AAAA,UAClC;AAAA,QACJ;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,IACX,SAAS,IAAI;AACT,YAAM,IAAI,MAAM,yFAAyF;AAAA,IAC7G;AAAA,EACJ;AAEA,iBAAe,cAA6B;AACxC,UAAM,KAAK,MAAM,OAAO;AACxB,QAAI,GAAG,iBAAiB,SAAS,SAAS,EAAG;AAC7C,UAAM,eAAe,GAAG,WAAW,KAAK;AACxC,QAAI;AACA,SAAG,MAAM;AAAA,IACb,SAAS,IAAI;AAAA,IAEb;AACA,UAAM,MAAM,MAAM;AAClB,gBAAY,IAAI,OAAO,QAAQ,aAAa;AAAA,MACxC,QAAQ,KAAwB;AAC5B,YAAI,CAAC,IAAI,iBAAiB,SAAS,SAAS,EAAG,KAAI,kBAAkB,SAAS;AAAA,MAClF;AAAA,IACJ,CAAC;AACD,UAAM;AAAA,EACV;AAEA,iBAAe,UAAa,IAAuD;AAC/E,QAAI;AACA,YAAM,KAAK,MAAM,OAAO;AACxB,aAAO,MAAM,GAAG,EAAE;AAAA,IACtB,SAAS,KAAU;AACf,YAAM,MAAM,OAAO,OAAO,IAAI,UAAU,IAAI,UAAU,GAAG;AACzD,UAAI,QAAQ,IAAI,SAAS,mBAAmB,eAAe,KAAK,GAAG,IAAI;AACnE,cAAM,YAAY;AAClB,cAAM,MAAM,MAAM,OAAO;AACzB,eAAO,MAAM,GAAG,GAAG;AAAA,MACvB;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,SAAS,OAAO,SAAyC;AACrD,aAAO,UAAU,OAAO,OAAO;AAC3B,YAAI,IAAI,MAAM,GAAG,IAAI,WAAW,IAAI;AACpC,YAAI,KAAK;AACT,eAAO;AAAA,MACX,CAAC;AAAA,IACL;AAAA,IACA,SAAS,OAAO,MAAc,UAAiC;AAC3D,aAAO,UAAU,OAAO,OAAO;AAC3B,cAAM,GAAG,IAAI,WAAW,OAAO,IAAI;AAAA,MACvC,CAAC;AAAA,IACL;AAAA,IACA,YAAY,OAAO,SAAgC;AAC/C,aAAO,UAAU,OAAO,OAAO;AAC3B,cAAM,GAAG,OAAO,WAAW,IAAI;AAAA,MACnC,CAAC;AAAA,IACL;AAAA,EACJ;AACJ;;;ANxDO,IAAK,aAAL,kBAAKC,gBAAL;AACH,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,YAAS;AAHD,SAAAA;AAAA,GAAA;AAMZ,IAAM,+BAA+B;AACrC,IAAM,iBAAyB;AAC/B,IAAM,wBAAkC;AACxC,IAAM,yCAAsE;AAC5E,IAAM,uCAAmE;AAElE,SAAS,eACZ,cACA,gBACA,SACA,cAA2B,CAAC,GACK;AACjC,QAAM,YAAQ,uBAAO,gBAAgB,cAAc,gBAAgB,SAAS,WAAW,CAAC;AAExF,SAAO,IAAI,QAAkC,CAAC,YAAY;AACtD,UAAM,QAAQ,kBAAkB,CAAC,WAAW;AACxC,cAAQ,KAAK;AAAA,IACjB,CAAC;AAAA,EACL,CAAC;AACL;AAEO,SAAS,gBACZ,cACA,gBACA,SACA,cAA2B,CAAC,GAC9B;AACE,QAAM,eAAe,YAAY,gBAAgB;AACjD,QAAM,kBAAkB,YAAY,2CAA2C;AAC/E,QAAM,6BAA6B,YAAY,8BAA8B;AAC7E,QAAM,SAAS,UAAU,YAAY,UAAU,gBAAgB,YAAY,eAAe,qBAAqB;AAE/G,QAAM,kBAAkB,gBAAgB;AACxC,QAAM,iBAAiB,gBAAgB;AAEvC,QAAM,wBAAwB;AAAA,IAC1B,GAAG;AAAA,IACH,oBAAoB,MAAM;AACtB,aAAO,MAAM,0BAA0B;AAEvC,aAAO,CAAC,OAAY,UAAe;AAC/B,YAAI,OAAO;AACP,iBAAO,MAAM,6BAA6B,KAAK;AAAA,QACnD,OAAO;AACH,4BAAkB,OAAO,KAAK;AAC9B,iBAAO,MAAM,+BAA+B,KAAK;AAAA,QACrD;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,YAAY,CAAC,MAAW;AAGpB,YAAM,OAAO,iBAAiB,eAAe,CAAC,IAAI;AAClD,YAAM,EAAE,WAAW,GAAG,KAAK,IAAI,QAAQ,CAAC;AACxC,aAAO;AAAA,QACH,GAAG;AAAA,QACH,WAAW;AAAA,UACP,eAAe,UAAU;AAAA,UACzB,gBAAgB,UAAU;AAAA,UAC1B,YAAY,UAAU;AAAA,UACtB,WAAW,UAAU;AAAA,QACzB;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,CAAC,WAAgB,YAAiB;AAOrC,YAAM,QAAQ,EAAE,GAAG,SAAS,GAAG,UAAU;AAEzC,aAAO;AAAA,QACH,GAAG;AAAA,QACH,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ;AAAA;AAAA,QACZ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,UAAoD,CAAC,KAAU,KAAU,aAAkB;AAC7F,QAAI,mBAAmB;AAEvB,mBAAe,WAAW;AACtB,UAAI,IAAI,EAAE,UAAU,WAAW,OAAQ;AAEvC,UAAI,CAAC,WAAgB;AAAA,QACjB,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ;AAAA,QACZ;AAAA,MACJ,EAAE;AAEF,UAAI;AAGJ,iBAAW,YAAY,OAAO,KAAK,OAAO,GAAG;AACzC,YAAI;AACA,gBAAM,MAAM,QAAQ,UAAU,OAAO;AACrC,gBAAM,KAAK,KAAK,KAAK,UAAU,KAAK,QAAQ,0BAA0B;AAAA,QAC1E,SAAS,KAAK;AACV,2BAAiB,kBAAmB;AACpC,iBAAO,MAAM,8BAA8B,QAAQ,IAAI,GAAG;AAAA,QAC9D;AAAA,MACJ;AAGA,YAAM,kBAAmC,CAAC,GAAI,IAAI,EAAE,UAAU,kBAAkB,CAAC,CAAE;AAGnF,sBAAgB,KAAK,CAAC,GAAG,MAAM,SAAS,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,CAAC;AAEtE,iBAAW,UAAU,iBAAiB;AAClC,YAAI;AACA,gBAAM,MAAM,QAAQ,OAAO,UAAU,OAAO;AAC5C,gBAAM;AAAA,YACF;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAY;AAAA,YACZ,YAAY;AAAA,UAChB;AAAA,QACJ,SAAS,KAAK;AACV,2BAAiB,kBAAmB;AACpC,iBAAO,MAAM,4BAA4B,MAAM,IAAI,GAAG;AAAA,QAC1D;AAAA,MACJ;AAEA,UAAI,CAAC,WAAgB;AAAA,QACjB,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ;AAAA,UACR,OAAO;AAAA,QACX;AAAA,MACJ,EAAE;AAAA,IACN;AAEA,aAAS,kBAAkB,SAAc;AACrC,UAAI,OAAO,YAAY,YAAY;AAC/B,YAAI,CAAC,UAAe,aAAa,OAAO,QAAQ,KAAK,CAAC,CAAC;AAAA,MAC3D,OAAO;AACH,YAAI,CAAC,UAAe,aAAa,OAAO,OAAO,CAAC;AAAA,MACpD;AAAA,IACJ;AAEA,aAAS,aAAa,OAAY,SAAc;AAC5C,YAAM,iBAAkC,MAAM,UAAU,kBAAkB,CAAC;AAE3E,aAAO,KAAK,OAAO,EAAE,IAAI,CAAC,aAAa;AACnC,cAAM,UAAU,MAAM,QAAQ;AAC9B,cAAM,UAAU,QAAQ,QAAQ;AAChC,cAAM,UAAU,YAAY,SAAS,OAAO;AAC5C,+BAAuB,gBAAgB,UAAU,OAAO;AAAA,MAC5D,CAAC;AAGD,YAAM,YAAY,mBAAmB,gBAAgB,MAAM,UAAU,SAAS;AAE9E,aAAO;AAAA,QACH,GAAG;AAAA,QACH,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB;AAAA,UACA;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,aAAS,OAAO,SAAkB;AAC9B,UAAI,CAAC,WAAgB;AAAA,QACjB,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ,UAAU,SAAS;AAAA,QAC/B;AAAA,MACJ,EAAE;AAEF,qBAAe,OAAO;AACtB,kCAA4B,OAAO;AAAA,IACvC;AAEA,aAAS,eAAe,OAAgB;AACpC,UAAI,OAAO;AACP,iBAAS;AAAA,MACb,OAAO;AACH,2BAAmB;AAAA,MACvB;AAAA,IACJ;AAEA,mBAAe,WAAW;AACtB,UAAI,iBAAkB;AACtB,yBAAmB;AAEnB,aAAO,MAAM;AACT,YAAI,CAAC,iBAAkB;AACvB,cAAM,SAAS;AACf,cAAM,MAAM,YAAY;AAAA,MAC5B;AAAA,IACJ;AAEA,aAAS,4BAA4B,KAAc;AAC/C,UAAI,KAAK;AACL,iBAAS,iBAAiB,oBAAoB,kBAAkB;AAAA,MACpE,OAAO;AACH,iBAAS,oBAAoB,oBAAoB,kBAAkB;AAAA,MACvE;AAAA,IACJ;AAEA,aAAS,qBAAqB;AAC1B,UAAI,SAAS,oBAAoB,WAAW;AACxC,eAAO,MAAM,iCAAiC;AAC9C,uBAAe,IAAI;AAAA,MACvB,OAAO;AACH,eAAO,MAAM,iCAAiC;AAC9C,uBAAe,KAAK;AAAA,MACxB;AAAA,IACJ;AAGA,aAAS,OAAO;AAAA,MACZ;AAAA,MACA,gBAAgB,MAAM,eAAe,KAAK,SAAS,MAAM;AAAA,MACzD,iBAAiB,CAAC,SAAiB,cAAuB,gBAAgB,KAAK,SAAS,SAAS;AAAA,IACrG;AAEA,UAAM,YAAY,aAAa,KAAK,KAAK,iBAAiB;AAE1D,WAAO;AAAA,MACH,GAAG;AAAA,MACH,WAAW;AAAA;AAAA,QAEP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,WAAW;AAAA,QACX,eAAe;AAAA,QACf,gBAAgB,CAAC;AAAA,QACjB,YAAY,CAAC;AAAA,MACjB;AAAA,IACJ;AAAA,EACJ;AAEA,aAAO,2BAAQ,SAAS,qBAAqB;AACjD;","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 { 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":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,SAAS,uBAAuB;AAC5B,SAAQ,sBACH,oBAAoB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AACR;AAEA,SAAS,0BAA0B;AAC/B,SAAQ,yBACH,uBAAuB;AAAA,IACpB,UAAU,UAAU;AAAA,IACpB,UAAU,UAAU;AAAA,IACpB,UAAU,UAAU;AAAA,EACxB;AACR;AAIA,SAAS,iBAAiB,SAAS;AAC/B,QAAM,UAAU,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC7C,UAAM,WAAW,MAAM;AACnB,cAAQ,oBAAoB,WAAW,OAAO;AAC9C,cAAQ,oBAAoB,SAAS,KAAK;AAAA,IAC9C;AACA,UAAM,UAAU,MAAM;AAClB,cAAQ,KAAK,QAAQ,MAAM,CAAC;AAC5B,eAAS;AAAA,IACb;AACA,UAAM,QAAQ,MAAM;AAChB,aAAO,QAAQ,KAAK;AACpB,eAAS;AAAA,IACb;AACA,YAAQ,iBAAiB,WAAW,OAAO;AAC3C,YAAQ,iBAAiB,SAAS,KAAK;AAAA,EAC3C,CAAC;AAGD,wBAAsB,IAAI,SAAS,OAAO;AAC1C,SAAO;AACX;AACA,SAAS,+BAA+B,IAAI;AAExC,MAAI,mBAAmB,IAAI,EAAE;AACzB;AACJ,QAAM,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC1C,UAAM,WAAW,MAAM;AACnB,SAAG,oBAAoB,YAAY,QAAQ;AAC3C,SAAG,oBAAoB,SAAS,KAAK;AACrC,SAAG,oBAAoB,SAAS,KAAK;AAAA,IACzC;AACA,UAAM,WAAW,MAAM;AACnB,cAAQ;AACR,eAAS;AAAA,IACb;AACA,UAAM,QAAQ,MAAM;AAChB,aAAO,GAAG,SAAS,IAAI,aAAa,cAAc,YAAY,CAAC;AAC/D,eAAS;AAAA,IACb;AACA,OAAG,iBAAiB,YAAY,QAAQ;AACxC,OAAG,iBAAiB,SAAS,KAAK;AAClC,OAAG,iBAAiB,SAAS,KAAK;AAAA,EACtC,CAAC;AAED,qBAAmB,IAAI,IAAI,IAAI;AACnC;AA6BA,SAAS,aAAa,UAAU;AAC5B,kBAAgB,SAAS,aAAa;AAC1C;AACA,SAAS,aAAa,MAAM;AAQxB,MAAI,wBAAwB,EAAE,SAAS,IAAI,GAAG;AAC1C,WAAO,YAAa,MAAM;AAGtB,WAAK,MAAM,OAAO,IAAI,GAAG,IAAI;AAC7B,aAAO,KAAK,KAAK,OAAO;AAAA,IAC5B;AAAA,EACJ;AACA,SAAO,YAAa,MAAM;AAGtB,WAAO,KAAK,KAAK,MAAM,OAAO,IAAI,GAAG,IAAI,CAAC;AAAA,EAC9C;AACJ;AACA,SAAS,uBAAuB,OAAO;AACnC,MAAI,OAAO,UAAU;AACjB,WAAO,aAAa,KAAK;AAG7B,MAAI,iBAAiB;AACjB,mCAA+B,KAAK;AACxC,MAAI,cAAc,OAAO,qBAAqB,CAAC;AAC3C,WAAO,IAAI,MAAM,OAAO,aAAa;AAEzC,SAAO;AACX;AACA,SAAS,KAAK,OAAO;AAGjB,MAAI,iBAAiB;AACjB,WAAO,iBAAiB,KAAK;AAGjC,MAAI,eAAe,IAAI,KAAK;AACxB,WAAO,eAAe,IAAI,KAAK;AACnC,QAAM,WAAW,uBAAuB,KAAK;AAG7C,MAAI,aAAa,OAAO;AACpB,mBAAe,IAAI,OAAO,QAAQ;AAClC,0BAAsB,IAAI,UAAU,KAAK;AAAA,EAC7C;AACA,SAAO;AACX;AAUA,SAAS,OAAO,MAAM,SAAS,EAAE,SAAS,SAAS,UAAU,WAAW,IAAI,CAAC,GAAG;AAC5E,QAAM,UAAU,UAAU,KAAK,MAAM,OAAO;AAC5C,QAAM,cAAc,KAAK,OAAO;AAChC,MAAI,SAAS;AACT,YAAQ,iBAAiB,iBAAiB,CAAC,UAAU;AACjD,cAAQ,KAAK,QAAQ,MAAM,GAAG,MAAM,YAAY,MAAM,YAAY,KAAK,QAAQ,WAAW,GAAG,KAAK;AAAA,IACtG,CAAC;AAAA,EACL;AACA,MAAI,SAAS;AACT,YAAQ,iBAAiB,WAAW,CAAC,UAAU;AAAA;AAAA,MAE/C,MAAM;AAAA,MAAY,MAAM;AAAA,MAAY;AAAA,IAAK,CAAC;AAAA,EAC9C;AACA,cACK,KAAK,CAAC,OAAO;AACd,QAAI;AACA,SAAG,iBAAiB,SAAS,MAAM,WAAW,CAAC;AACnD,QAAI,UAAU;AACV,SAAG,iBAAiB,iBAAiB,CAAC,UAAU,SAAS,MAAM,YAAY,MAAM,YAAY,KAAK,CAAC;AAAA,IACvG;AAAA,EACJ,CAAC,EACI,MAAM,MAAM;AAAA,EAAE,CAAC;AACpB,SAAO;AACX;AAMA,SAAS,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC,GAAG;AACtC,QAAM,UAAU,UAAU,eAAe,IAAI;AAC7C,MAAI,SAAS;AACT,YAAQ,iBAAiB,WAAW,CAAC,UAAU;AAAA;AAAA,MAE/C,MAAM;AAAA,MAAY;AAAA,IAAK,CAAC;AAAA,EAC5B;AACA,SAAO,KAAK,OAAO,EAAE,KAAK,MAAM,MAAS;AAC7C;AAKA,SAAS,UAAU,QAAQ,MAAM;AAC7B,MAAI,EAAE,kBAAkB,eACpB,EAAE,QAAQ,WACV,OAAO,SAAS,WAAW;AAC3B;AAAA,EACJ;AACA,MAAI,cAAc,IAAI,IAAI;AACtB,WAAO,cAAc,IAAI,IAAI;AACjC,QAAM,iBAAiB,KAAK,QAAQ,cAAc,EAAE;AACpD,QAAM,WAAW,SAAS;AAC1B,QAAM,UAAU,aAAa,SAAS,cAAc;AACpD;AAAA;AAAA,IAEA,EAAE,mBAAmB,WAAW,WAAW,gBAAgB,cACvD,EAAE,WAAW,YAAY,SAAS,cAAc;AAAA,IAAI;AACpD;AAAA,EACJ;AACA,QAAM,SAAS,eAAgB,cAAc,MAAM;AAE/C,UAAM,KAAK,KAAK,YAAY,WAAW,UAAU,cAAc,UAAU;AACzE,QAAIA,UAAS,GAAG;AAChB,QAAI;AACA,MAAAA,UAASA,QAAO,MAAM,KAAK,MAAM,CAAC;AAMtC,YAAQ,MAAM,QAAQ,IAAI;AAAA,MACtBA,QAAO,cAAc,EAAE,GAAG,IAAI;AAAA,MAC9B,WAAW,GAAG;AAAA,IAClB,CAAC,GAAG,CAAC;AAAA,EACT;AACA,gBAAc,IAAI,MAAM,MAAM;AAC9B,SAAO;AACX;AAwBA,gBAAgB,WAAW,MAAM;AAE7B,MAAI,SAAS;AACb,MAAI,EAAE,kBAAkB,YAAY;AAChC,aAAS,MAAM,OAAO,WAAW,GAAG,IAAI;AAAA,EAC5C;AACA,MAAI,CAAC;AACD;AACJ,WAAS;AACT,QAAM,gBAAgB,IAAI,MAAM,QAAQ,mBAAmB;AAC3D,mCAAiC,IAAI,eAAe,MAAM;AAE1D,wBAAsB,IAAI,eAAe,OAAO,MAAM,CAAC;AACvD,SAAO,QAAQ;AACX,UAAM;AAEN,aAAS,OAAO,eAAe,IAAI,aAAa,KAAK,OAAO,SAAS;AACrE,mBAAe,OAAO,aAAa;AAAA,EACvC;AACJ;AACA,SAAS,eAAe,QAAQ,MAAM;AAClC,SAAS,SAAS,OAAO,iBACrB,cAAc,QAAQ,CAAC,UAAU,gBAAgB,SAAS,CAAC,KAC1D,SAAS,aAAa,cAAc,QAAQ,CAAC,UAAU,cAAc,CAAC;AAC/E;AAnSA,IAAM,eAEF,mBACA,sBAqBE,oBACA,gBACA,uBAgDF,eAmFE,QAgDA,aACA,cACA,eA2CA,oBACA,WACA,gBACA,kCACA;AA9PN;AAAA;AAAA;AAAA,IAAM,gBAAgB,CAAC,QAAQ,iBAAiB,aAAa,KAAK,CAAC,MAAM,kBAAkB,CAAC;AAwB5F,IAAM,qBAAqB,oBAAI,QAAQ;AACvC,IAAM,iBAAiB,oBAAI,QAAQ;AACnC,IAAM,wBAAwB,oBAAI,QAAQ;AAgD1C,IAAI,gBAAgB;AAAA,MAChB,IAAI,QAAQ,MAAM,UAAU;AACxB,YAAI,kBAAkB,gBAAgB;AAElC,cAAI,SAAS;AACT,mBAAO,mBAAmB,IAAI,MAAM;AAExC,cAAI,SAAS,SAAS;AAClB,mBAAO,SAAS,iBAAiB,CAAC,IAC5B,SACA,SAAS,YAAY,SAAS,iBAAiB,CAAC,CAAC;AAAA,UAC3D;AAAA,QACJ;AAEA,eAAO,KAAK,OAAO,IAAI,CAAC;AAAA,MAC5B;AAAA,MACA,IAAI,QAAQ,MAAM,OAAO;AACrB,eAAO,IAAI,IAAI;AACf,eAAO;AAAA,MACX;AAAA,MACA,IAAI,QAAQ,MAAM;AACd,YAAI,kBAAkB,mBACjB,SAAS,UAAU,SAAS,UAAU;AACvC,iBAAO;AAAA,QACX;AACA,eAAO,QAAQ;AAAA,MACnB;AAAA,IACJ;AAwDA,IAAM,SAAS,CAAC,UAAU,sBAAsB,IAAI,KAAK;AAgDzD,IAAM,cAAc,CAAC,OAAO,UAAU,UAAU,cAAc,OAAO;AACrE,IAAM,eAAe,CAAC,OAAO,OAAO,UAAU,OAAO;AACrD,IAAM,gBAAgB,oBAAI,IAAI;AAqC9B,iBAAa,CAAC,cAAc;AAAA,MACxB,GAAG;AAAA,MACH,KAAK,CAAC,QAAQ,MAAM,aAAa,UAAU,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC/F,KAAK,CAAC,QAAQ,SAAS,CAAC,CAAC,UAAU,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,IAAI;AAAA,IACjF,EAAE;AAEF,IAAM,qBAAqB,CAAC,YAAY,sBAAsB,SAAS;AACvE,IAAM,YAAY,CAAC;AACnB,IAAM,iBAAiB,oBAAI,QAAQ;AACnC,IAAM,mCAAmC,oBAAI,QAAQ;AACrD,IAAM,sBAAsB;AAAA,MACxB,IAAI,QAAQ,MAAM;AACd,YAAI,CAAC,mBAAmB,SAAS,IAAI;AACjC,iBAAO,OAAO,IAAI;AACtB,YAAI,aAAa,UAAU,IAAI;AAC/B,YAAI,CAAC,YAAY;AACb,uBAAa,UAAU,IAAI,IAAI,YAAa,MAAM;AAC9C,2BAAe,IAAI,MAAM,iCAAiC,IAAI,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;AAAA,UACtF;AAAA,QACJ;AACA,eAAO;AAAA,MACX;AAAA,IACJ;AA0BA,iBAAa,CAAC,cAAc;AAAA,MACxB,GAAG;AAAA,MACH,IAAI,QAAQ,MAAM,UAAU;AACxB,YAAI,eAAe,QAAQ,IAAI;AAC3B,iBAAO;AACX,eAAO,SAAS,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC9C;AAAA,MACA,IAAI,QAAQ,MAAM;AACd,eAAO,eAAe,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,IAAI;AAAA,MACpE;AAAA,IACJ,EAAE;AAAA;AAAA;;;AC9SF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0C;AAC1C,wBAAwB;;;ACQjB,SAAS,UAAU,MAAc,KAAuB;AAC3D,QAAM,QAAkC;AAAA,IACpC,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACV;AACA,QAAM,YAAY,MAAM,GAAG;AAC3B,QAAM,UAAU,CAAC,QAAkB,MAAM,GAAG,KAAK;AACjD,SAAO;AAAA,IACH,OAAO,IAAI,MAAa,QAAQ,OAAO,KAAK,KAAK,QAAQ,GAAG,CAAC;AAAA,IAC7D,MAAM,IAAI,MAAa,QAAQ,MAAM,KAAK,KAAK,OAAO,GAAG,CAAC;AAAA,IAC1D,MAAM,IAAI,MAAa,QAAQ,MAAM,KAAK,KAAK,OAAO,GAAG,CAAC;AAAA,IAC1D,OAAO,IAAI,MAAa,QAAQ,OAAO,KAAK,KAAK,QAAQ,GAAG,CAAC;AAAA,EACjE;AACJ;;;ACtBA,IAAM,cAAc,CAAC,YAAY,cAAc,SAAS;AAEjD,SAAS,gBAAwB;AACpC,SAAO,OAAO,WAAW;AAC7B;AAEO,SAAS,MAAM,IAA2B;AAC7C,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAC3D;AAEO,SAAS,aAAa,OAAoB,SAAiB,gBAAwB,cAAsB;AAC5G,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,QAAM,UAAU,UAAU,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS;AACrD,UAAM,EAAE,IAAI,YAAY,SAAS,GAAG,KAAK,IAAI;AAC7C,WAAO;AAAA,MACH,CAAC,OAAO,GAAG;AAAA,MACX,CAAC,cAAc,GAAG;AAAA,MAClB,CAAC,YAAY,GAAG;AAAA,MAChB,GAAG;AAAA,IACP;AAAA,EACJ,CAAC;AACD,SAAO,UAAU,SAAS,OAAO,CAAC;AACtC;AAEO,SAAS,eAAe,OAAoB,WAAmB,kBAA0B,gBAAwB;AACpH,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,QAAM,UAAU,UAAU,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS;AACrD,UAAM,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,cAAc,GAAG,SAAS,GAAG,KAAK,IAAI;AAChG,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACP;AAAA,EACJ,CAAC;AACD,SAAO,UAAU,SAAS,OAAO,CAAC;AACtC;AAEO,SAAS,SAAS,GAAuB;AAC5C,UAAQ,GAAG;AAAA,IACP;AACI,aAAO;AAAA,IACX;AACI,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EACf;AACJ;AAEO,SAAS,eAAe,MAAW;AACtC,QAAM,SAAS,EAAE,GAAG,KAAK;AACzB,aAAW,KAAK,YAAa,QAAO,OAAO,CAAC;AAC5C,SAAO;AACX;AAEO,SAAS,mBAAmB,KAAU,UAAkB,SAAiB,SAA0B;AACtG,QAAM,UAA2B,IAAI,EAAE,UAAU,kBAAkB,CAAC;AACpE,QAAM,YAAY,QAAQ,KAAK,CAAC,MAAM,EAAE,YAAY,WAAW,EAAE,aAAa,QAAQ;AACtF,SAAO,WAAW,YAAY;AAClC;AAEO,SAAS,yBAAyB,KAAU,SAAiB,UAAkB;AAClF,MAAI,CAAC,MAAW;AACZ,UAAM,SAA0B,EAAE,UAAU,kBAAkB,CAAC,GAAG,OAAO,CAAC,MAAqB,EAAE,EAAE,YAAY,WAAW,EAAE,aAAa,SAAS;AAClJ,WAAO;AAAA,MACH,WAAW;AAAA,QACP,GAAI,EAAE,aAAa,CAAC;AAAA,QACpB,gBAAgB;AAAA,MACpB;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAEO,SAAS,uBAAuB,gBAAiC,UAAkB,SAAoC;AAC1H,aAAW,CAAC,SAAS,MAAM,KAAK,SAAS;AACrC,QAAI,cAAc,eAAe,OAAO,OAAO;AAC/C,UAAM,YAAY,eAAe,KAAK,CAAC,MAAM,EAAE,YAAY,WAAW,EAAE,aAAa,QAAQ;AAC7F,UAAM,aAAa,OAAO,KAAK,WAAW,EAAE,SAAS;AACrD,UAAM,SAAS,OAAO,gBAAgB,+BAA2B,OAAO,gBAAgB;AAExF,QAAI,oCAAgC,OAAO,eAAe,OAAO,eAAe,OAAO,YAAY,aAAa,OAAO,YAAY,UAAU;AAEzI,oBAAc,eAAe,OAAO,WAAW;AAAA,IACnD;AAEA,QAAI,WAAW;AACX,UAAI,UAAU,kCAA8B;AAExC;AAAA,MACJ;AAEA,gBAAU,WAAW;AAErB,UAAI,kCAA8B;AAC9B,kBAAU;AAAA,MACd,WAAW,YAAY;AAEnB,kBAAU,UAAU,EAAE,GAAG,UAAU,SAAS,GAAG,YAAY;AAAA,MAC/D;AAAA,IACJ,WAAW,oCAAgC,YAAY;AACnD,qBAAe,KAAK,EAAE,QAAQ,UAAU,SAAS,IAAI,OAAO,IAAI,SAAS,GAAG,SAAS,aAAa,QAAQ,eAAe,OAAO,WAAW,EAAE,CAAC;AAAA,IAClJ;AAAA,EACJ;AACJ;AAEO,SAAS,yBAAyB,KAAU,UAAkB,SAAiB,IAAU;AAE5F,QAAM,iBAAkC,IAAI,EAAE,UAAU,kBAAkB,CAAC;AAC3E,QAAM,SAAS,eAAe,KAAK,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE,YAAY,OAAO;AAC1F,MAAI,QAAQ;AACR,WAAO;AACP,QAAI,GAAI,QAAO,KAAK;AAAA,EACxB;AACJ;AAEO,SAAS,uBAAuB,KAAU,UAAkB,SAAiB,QAAa;AAC7F,QAAM,iBAAkC,IAAI,EAAE,UAAU,kBAAkB,CAAC;AAC3E,QAAM,SAAS,eAAe,KAAK,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE,YAAY,OAAO;AAC1F,MAAI,QAAQ;AACR,WAAO,SAAS,EAAE,GAAG,OAAO,QAAQ,GAAG,OAAO;AAAA,EAClD;AACJ;AAEO,SAAS,mBAAmB,gBAAiC,WAA4E;AAC5I,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,eAAe,EAAE,GAAG,UAAU;AAEpC,aAAW,UAAU,gBAAgB;AACjC,UAAM,WAAW,aAAa,OAAO,OAAO;AAC5C,QAAI,YAAY,OAAO,SAAS;AAE5B,YAAM,YAAY,SAAS,OAAO,IAAI,CAAC,MAAM;AACzC,YAAI,EAAE,OAAO,OAAO,SAAS;AACzB,iBAAO,EAAE,GAAG,GAAG,YAAY,OAAO,QAAQ,EAAE,GAAG,EAAE;AAAA,QACrD;AACA,eAAO;AAAA,MACX,CAAC;AAED,mBAAa,OAAO,OAAO,IAAI,EAAE,UAAU,SAAS,UAAU,QAAQ,UAAU;AAAA,IACpF;AAAA,EACJ;AAEA,SAAO;AACX;AAEO,SAAS,QAAQ,UAAkB,SAAuC;AAC7E,QAAM,MAAM,QAAQ,QAAQ;AAC5B,MAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,UAAU,CAAC,IAAI,QAAQ,CAAC,IAAI,WAAW;AAC/E,UAAM,IAAI,MAAM,0CAA0C,QAAQ,GAAG;AAAA,EACzE;AACA,SAAO;AACX;AAgBO,SAAS,YAAY,SAAgB,SAA2C;AACnF,QAAM,aAAa,oBAAI,IAAiB;AACxC,aAAW,QAAQ,SAAS;AACxB,QAAI,QAAQ,KAAK,UAAU;AACvB,iBAAW,IAAI,KAAK,UAAU,EAAE,GAAG,KAAK,CAAC;AAAA,IAC7C;AAAA,EACJ;AAEA,QAAM,aAAa,oBAAI,IAA0B;AAGjD,aAAW,UAAU,SAAS;AAC1B,UAAM,OAAO,EAAE,GAAG,OAAO;AACzB,QAAI,QAAQ,KAAK,UAAU;AACvB,YAAM,OAAO,WAAW,IAAI,KAAK,QAAQ;AACzC,UAAI,MAAM;AACN,cAAM,OAAY,CAAC;AACnB,mBAAW,OAAO,MAAM;AACpB,cAAI,QAAQ,cAAc,KAAK,GAAG,MAAM,KAAK,GAAG,GAAG;AAC/C,iBAAK,GAAG,IAAI,KAAK,GAAG;AAAA,UACxB;AAAA,QACJ;AACA,YAAI,OAAO,KAAK,IAAI,EAAE,SAAS,GAAG;AAE9B,qBAAW,IAAI,KAAK,UAAU,EAAE,aAAa,MAAM,aAAa,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,QACjH;AAAA,MACJ,OAAO;AAEH,mBAAW,IAAI,KAAK,UAAU,EAAE,aAAa,MAAM,aAAa,MAAM,SAAS,MAAM,IAAI,KAAK,GAAG,CAAC;AAAA,MACtG;AAAA,IACJ;AAAA,EACJ;AAGA,aAAW,CAAC,SAAS,IAAI,KAAK,YAAY;AACtC,QAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,KAAK,EAAE,aAAa,OAAO,GAAG;AACnD,iBAAW,IAAI,SAAS,EAAE,aAAa,MAAM,aAAa,MAAM,SAAS,MAAM,IAAI,KAAK,GAAG,CAAC;AAAA,IAChG;AAAA,EACJ;AAEA,SAAO;AACX;AAEO,SAAS,mBAAmB,KAAe;AAC9C,SAAO,OAAO,KAAK,GAAG,EAAE,WAAW,IAAI,SAAY;AACvD;AAEO,SAAS,aAAa,KAAU,SAA0B;AAC7D,QAAM,QAAQ,IAAI;AAClB,MAAI,MAAM,UAAU,WAAW;AAC3B,WAAO,CAAC,CAAC,MAAM,UAAU,UAAU,OAAO;AAAA,EAC9C;AACA,SAAO;AACX;AAEO,SAAS,gBAAgB,KAAU,SAAiB,iBAA0B;AACjF,MAAI,CAAC,UAAe;AAChB,UAAM,YAAoC,MAAM,aAAa,CAAC;AAC9D,UAAM,YAAsC,UAAU,aAAa,CAAC;AACpE,UAAM,WAAW,UAAU,OAAO;AAClC,QAAI,UAAU;AACV,YAAM,QAAQ,MAAM,SAAS,QAAQ;AACrC,YAAM,OAAO,MAAM,KAAK,CAAC,MAAW,EAAE,aAAa,OAAO;AAC1D,UAAI,CAAC,MAAM;AACP,eAAO;AAAA,MACX;AAEA,YAAM,WAAgB,EAAE,GAAG,KAAK;AAChC,UAAI,iBAAiB,CAAC,GAAG,UAAU,cAAc;AAEjD,UAAI,CAAC,iBAAiB;AAElB,mBAAW,SAAS,SAAS,QAAQ;AACjC,mBAAS,MAAM,GAAG,IAAI,MAAM;AAAA,QAChC;AAGA,yBAAiB,eAAe,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,SAAS,YAAY,EAAE,YAAY,QAAQ;AAAA,MAC9G;AAGA,YAAM,YAAY,MAAM,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,CAAE;AAC/E,YAAM,gBAAgB,EAAE,GAAG,UAAU;AACrC,aAAO,cAAc,OAAO;AAE5B,aAAO;AAAA,QACH,CAAC,SAAS,QAAQ,GAAG;AAAA,QACrB,WAAW;AAAA,UACP,GAAG;AAAA,UACH;AAAA,UACA,WAAW,mBAAmB,aAAa;AAAA,QAC/C;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX,CAAC;AACL;;;ACxQA,eAAsB,KAAK,KAAU,KAAU,UAAkB,KAAmB,QAAgB,4BAAwD;AACxJ,QAAM,aAAqC,IAAI,EAAE,UAAU,cAAc,CAAC;AAC1E,QAAM,eAAe,IAAI,KAAK,WAAW,QAAQ,KAAK,oBAAI,KAAK,CAAC,CAAC;AAEjE,SAAO,MAAM,8BAA8B,QAAQ,UAAU,aAAa,YAAY,CAAC,EAAE;AAEzF,QAAM,aAAc,MAAM,IAAI,KAAK,YAAY;AAC/C,MAAI,CAAC,YAAY,OAAQ;AAEzB,MAAI,SAAS;AAEb,MAAI,CAAC,UAAe;AAChB,QAAI,iBAAiB,CAAC,GAAI,MAAM,UAAU,cAAkC;AAC5E,UAAM,YAAY,EAAE,GAAG,MAAM,UAAU,UAAU;AACjD,UAAM,aAAoB,MAAM,QAAQ,KAAK,CAAC;AAC9C,QAAI,YAAY,CAAC,GAAG,UAAU;AAE9B,UAAM,YAAY,IAAI,IAAc,WAAW,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAExF,UAAM,qBAAqB,IAAI,IAAI,eAAe,OAAO,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE,gCAA4B,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAE3I,eAAW,UAAU,YAAY;AAC7B,YAAM,gBAAgB,IAAI,KAAK,OAAO,UAAU;AAChD,UAAI,gBAAgB,OAAQ,UAAS;AAGrC,UAAI,mBAAmB,IAAI,OAAO,EAAE,GAAG;AACnC,eAAO,MAAM,4CAA4C,QAAQ,OAAO,OAAO,EAAE,EAAE;AACnF;AAAA,MACJ;AAEA,YAAM,YAAY,UAAU,IAAI,OAAO,EAAE;AACzC,UAAI,OAAO,SAAS;AAChB,YAAI,WAAW;AACX,sBAAY,UAAU,OAAO,CAAC,MAAW,EAAE,OAAO,OAAO,EAAE;AAC3D,iBAAO,MAAM,+BAA+B,QAAQ,OAAO,OAAO,EAAE,EAAE;AAAA,QAC1E;AACA;AAAA,MACJ;AAEA,aAAO,OAAO;AAEd,UAAI,WAAW;AACX,cAAM,gBAAgB,eAAe,KAAK,CAAC,MAAW,EAAE,aAAa,YAAY,EAAE,YAAY,UAAU,QAAQ;AACjH,YAAI,eAAe;AACf,iBAAO,MAAM,iCAAiC,0BAA0B,aAAa,QAAQ,OAAO,OAAO,EAAE,EAAE;AAE/G,kBAAQ,4BAA4B;AAAA,YAChC,KAAK;AAED;AAAA,YAEJ,KAAK,eAAe;AAEhB,oBAAM,SAAS,EAAE,GAAG,QAAQ,UAAU,UAAU,SAAS;AACzD,0BAAY,UAAU,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,SAAS,CAAE;AAEtF,+BAAiB,eAAe,OAAO,CAAC,MAAM,EAAE,EAAE,aAAa,YAAY,EAAE,YAAY,UAAU,SAAS;AAC5G;AAAA,YACJ;AAAA,YAEA,KAAK,qBAAqB;AAEtB,oBAAM,UAAU,cAAc,WAAW,CAAC;AAC1C,oBAAM,SAAS,cAAc,UAAU,CAAC;AACxC,oBAAM,SAA0B,OAAO,QAAQ,OAAO,EACjD,OAAO,CAAC,CAAC,GAAG,UAAU,MAAM,KAAK,UAAU,KAAK,UAAU,OAAO,CAAC,MAAM,OAAO,CAAC,KAAK,eAAe,OAAO,CAAC,CAAC,EAC7G,IAAI,CAAC,CAAC,KAAK,UAAU,OAAO,EAAE,KAAK,YAAY,aAAa,OAAO,GAAG,EAAE,EAAE;AAE/E,kBAAI,OAAO,SAAS,GAAG;AACnB,uBAAO,KAAK,eAAe,0BAA0B,oBAAoB,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AACxG,0BAAU,UAAU,QAAQ,IAAI,EAAE,UAAU,OAAO;AAAA,cACvD,OAAO;AAGH,sBAAM,mBAAmB,OAAO,KAAK,OAAO;AAC5C,sBAAM,iBAAsB,EAAE,UAAU,UAAU,SAAS;AAC3D,2BAAW,KAAK,kBAAkB;AAC9B,sBAAI,KAAK,UAAW,gBAAe,CAAC,IAAI,UAAU,CAAC;AAAA,gBACvD;AAEA,sBAAM,SAAS,EAAE,GAAG,QAAQ,GAAG,eAAe;AAC9C,4BAAY,UAAU,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,SAAS,CAAE;AAEtF,uBAAO,UAAU,UAAU,QAAQ;AAAA,cACvC;AACA;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAEH,gBAAM,SAAS,EAAE,GAAG,WAAW,GAAG,OAAO;AACzC,sBAAY,UAAU,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,WAAW,SAAS,CAAE;AACtF,iBAAO,MAAM,qCAAqC,QAAQ,OAAO,OAAO,EAAE,EAAE;AAAA,QAChF;AAAA,MACJ,OAAO;AAEH,oBAAY,CAAC,GAAG,WAAW,EAAE,GAAG,QAAQ,UAAU,cAAc,EAAE,CAAC;AACnE,eAAO,MAAM,4BAA4B,QAAQ,OAAO,OAAO,EAAE,EAAE;AAAA,MACvE;AAAA,IACJ;AAEA,WAAO;AAAA,MACH,CAAC,QAAQ,GAAG;AAAA,MACZ,WAAW;AAAA,QACP,GAAI,MAAM,aAAa,CAAC;AAAA,QACxB;AAAA,QACA,WAAW,mBAAmB,SAAS;AAAA,QACvC,YAAY;AAAA,UACR,GAAI,MAAM,UAAU,cAAc,CAAC;AAAA,UACnC,CAAC,QAAQ,GAAG,OAAO,YAAY;AAAA,QACnC;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;;;AC5GA,eAAsB,QAClB,KACA,KACA,QACA,KACA,QACA,mBACA,iBACA,mCACA,kBACF;AACE,SAAO,MAAM,8BAA8B,OAAO,MAAM,aAAa,OAAO,QAAQ,YAAY,OAAO,OAAO,EAAE;AAEhH,QAAM,EAAE,QAAQ,UAAU,SAAS,IAAI,SAAS,QAAQ,IAAI;AAE5D,UAAQ,QAAQ;AAAA,IACZ;AACI,UAAI,CAAC,IAAI;AACL,eAAO,KAAK,qCAAqC,QAAQ,YAAY,OAAO,EAAE;AAC9E,iCAAyB,KAAK,SAAS,QAAQ;AAC/C;AAAA,MACJ;AAEA,YAAM,IAAI,OAAO,EAAE;AACnB,aAAO,MAAM,uCAAuC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAC1F,+BAAyB,KAAK,SAAS,QAAQ;AAC/C;AAAA,IAEJ,4BAAwB;AACpB,UAAI,aAAa,KAAK,OAAO,OAAO,GAAG;AACnC,eAAO,KAAK,uDAAuD,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AACzG;AAAA,MACJ;AAEA,YAAM,SAAS,MAAM,IAAI,OAAO,IAAI,OAAO;AAC3C,UAAI,QAAQ;AACR,eAAO,MAAM,uCAAuC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAC1F,YAAI,mBAAmB,KAAK,UAAU,SAAS,OAAO,GAAG;AACrD,mCAAyB,KAAK,SAAS,QAAQ;AAAA,QACnD,OAAO;AAEH,iCAAuB,KAAK,UAAU,SAAS,OAAO;AAAA,QAC1D;AACA;AAAA,MACJ,OAAO;AACH,cAAM,QAAQ,IAAI;AAClB,cAAM,QAAe,MAAM,QAAQ,KAAK,CAAC;AACzC,cAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,aAAa,OAAO;AACrD,YAAI,CAAC,MAAM;AACP,iBAAO,KAAK,qDAAqD,QAAQ,YAAY,OAAO,EAAE;AAC9F,mCAAyB,KAAK,SAAS,QAAQ;AAC/C;AAAA,QACJ;AAEA,gBAAQ,iBAAiB;AAAA,UACrB,KAAK;AACD,gBAAI,CAAC,OAAY;AAAA,cACb,CAAC,QAAQ,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,MAAW,EAAE,aAAa,OAAO;AAAA,YAC7E,EAAE;AACF,mBAAO,MAAM,8BAA8B,eAAe,aAAa,QAAQ,OAAO,KAAK,EAAE,EAAE;AAC/F;AAAA,UAEJ,KAAK,wBAAwB;AACzB,kBAAM,UAAU;AAAA,cACZ,GAAG;AAAA,cACH,UAAU,cAAc;AAAA,cACxB,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,YACvC;AAGA,8BAAkB,CAAC,OAAY;AAAA,cAC3B,CAAC,QAAQ,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,UAAU,CAAE;AAAA,YAC1F,EAAE;AAEF,mBAAO,MAAM,8BAA8B,eAAe,aAAa,QAAQ,OAAO,QAAQ,EAAE,EAAE;AAClG;AAAA,UACJ;AAAA,UAEA,KAAK;AACD,mBAAO,MAAM,8BAA8B,eAAe,aAAa,QAAQ,OAAO,KAAK,EAAE,EAAE;AAC/F;AAAA,UAEJ;AACI,mBAAO,MAAM,wDAAwD,QAAQ,OAAO,KAAK,EAAE,aAAa,eAAe,EAAE;AACzH;AAAA,QACR;AAEA,iCAAyB,KAAK,SAAS,QAAQ;AAE/C,4CAAoC,iBAAiB,IAAI;AAAA,MAC7D;AACA;AAAA,IACJ;AAAA,IAEA,4BAAwB;AACpB,YAAM,SAAS,MAAM,IAAI,IAAI,OAAO;AACpC,UAAI,QAAQ;AACR,eAAO,MAAM,uCAAuC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAG1F,YAAI,CAAC,OAAY;AAAA,UACb,CAAC,QAAQ,IAAI,EAAE,QAAQ,KAAK,CAAC,GAAG,IAAI,CAAC,MAAY,EAAE,aAAa,UAAU,EAAE,GAAG,GAAG,GAAG,OAAO,IAAI,CAAE;AAAA,QACtG,EAAE;AAEF,YAAI,mBAAmB,KAAK,UAAU,SAAS,OAAO,GAAG;AACrD,mCAAyB,KAAK,SAAS,QAAQ;AAAA,QACnD,OAAO;AAEH,mCAAyB,KAAK,UAAU,SAAS,OAAO,EAAE;AAAA,QAC9D;AAEA,cAAM,YAAY,EAAE,GAAG,SAAS,GAAG,QAAQ,UAAU,QAAQ;AAG7D,2BAAmB,KAAK,KAAK,mBAAmB,UAAU,SAAS;AAAA,MACvE,OAAO;AACH,eAAO,KAAK,yCAAyC,QAAQ,YAAY,OAAO,OAAO,EAAE,EAAE;AAC3F,YAAI,mBAAmB,KAAK,UAAU,SAAS,OAAO,GAAG;AACrD,mCAAyB,KAAK,SAAS,QAAQ;AAAA,QACnD;AAAA,MACJ;AACA;AAAA,IACJ;AAAA,EACJ;AACJ;;;ACpIA,eAAsB,eAAe,KAAU,SAAuC,QAAgB;AAClG,MAAI;AAEJ,aAAW,YAAY,OAAO,KAAK,OAAO,GAAG;AACzC,QAAI;AACA,aAAO,KAAK,mCAAmC,QAAQ,EAAE;AAEzD,YAAM,MAAM,QAAQ,UAAU,OAAO;AACrC,UAAI;AAGJ,aAAO,MAAM;AACT,cAAM,QAAQ,MAAM,IAAI,UAAU,MAAM;AACxC,YAAI,CAAC,OAAO,OAAQ;AAGpB,YAAI,CAAC,UAAe;AAChB,gBAAM,QAAe,MAAM,QAAQ,KAAK,CAAC;AACzC,gBAAM,YAAY,IAAI,IAAc,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEnF,cAAI,SAAS,IAAI,KAAK,MAAM,UAAU,WAAW,QAAQ,KAAK,CAAC;AAC/D,gBAAM,OAAO,CAAC,GAAG,KAAK;AACtB,qBAAW,UAAU,OAAO;AACxB,kBAAM,gBAAgB,IAAI,KAAK,OAAO,cAAc,CAAC;AACrD,gBAAI,gBAAgB,OAAQ,UAAS;AAErC,gBAAI,OAAO,QAAS;AAEpB,mBAAO,OAAO;AAEd,kBAAM,YAAY,OAAO,KAAK,UAAU,IAAI,OAAO,EAAE,IAAI;AACzD,gBAAI,WAAW;AACX,oBAAM,SAAS;AAAA,gBACX,GAAG;AAAA,gBACH,GAAG;AAAA,gBACH,UAAU,UAAU;AAAA,cACxB;AACA,oBAAM,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,aAAa,UAAU,QAAQ;AACnE,kBAAI,OAAO,EAAG,MAAK,GAAG,IAAI;AAAA,YAC9B,OAAO;AACH,mBAAK,KAAK;AAAA,gBACN,GAAG;AAAA,gBACH,UAAU,cAAc;AAAA,cAC5B,CAAC;AAAA,YACL;AAAA,UACJ;AAEA,iBAAO;AAAA,YACH,CAAC,QAAQ,GAAG;AAAA,YACZ,WAAW;AAAA,cACP,GAAI,MAAM,aAAa,CAAC;AAAA,cACxB,YAAY;AAAA,gBACR,GAAI,MAAM,UAAU,cAAc,CAAC;AAAA,gBACnC,CAAC,QAAQ,GAAG,OAAO,YAAY;AAAA,cACnC;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,CAAC;AAED,YAAI,WAAW,UAAa,WAAW,MAAM,MAAM,SAAS,CAAC,EAAE,IAAI;AAC/D,gBAAM,IAAI,MAAM,iEAAiE;AAAA,QACrF;AAEA,iBAAS,MAAM,MAAM,SAAS,CAAC,EAAE;AAAA,MACrC;AAEA,aAAO,KAAK,kCAAkC,QAAQ,EAAE;AAAA,IAC5D,SAAS,KAAK;AACV,kBAAY,aAAc;AAC1B,aAAO,MAAM,mCAAmC,QAAQ,IAAI,GAAG;AAAA,IACnE;AAAA,EACJ;AAEA,MAAI,CAAC,WAAgB;AAAA,IACjB,WAAW;AAAA,MACP,GAAI,MAAM,aAAa,CAAC;AAAA,MACxB,eAAe;AAAA,MACf,OAAO;AAAA,IACX;AAAA,EACJ,EAAE;AACN;;;AClFO,SAAS,uBAAuB,SAAgD;AACnF,QAAM,SAAS,QAAQ;AACvB,QAAM,YAAY,QAAQ;AAG1B,MAAI,YAA+C;AAEnD,iBAAe,SAAqC;AAChD,QAAI,UAAW,QAAO;AACtB,QAAI;AACA,YAAM,MAAM,MAAM;AAClB,kBAAY,IAAI,OAAO,QAAQ,GAAG;AAAA,QAC9B,QAAQ,IAAuB;AAC3B,cAAI,CAAC,GAAG,iBAAiB,SAAS,SAAS,GAAG;AAC1C,eAAG,kBAAkB,SAAS;AAAA,UAClC;AAAA,QACJ;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,IACX,SAAS,IAAI;AACT,YAAM,IAAI,MAAM,yFAAyF;AAAA,IAC7G;AAAA,EACJ;AAEA,iBAAe,cAA6B;AACxC,UAAM,KAAK,MAAM,OAAO;AACxB,QAAI,GAAG,iBAAiB,SAAS,SAAS,EAAG;AAC7C,UAAM,eAAe,GAAG,WAAW,KAAK;AACxC,QAAI;AACA,SAAG,MAAM;AAAA,IACb,SAAS,IAAI;AAAA,IAEb;AACA,UAAM,MAAM,MAAM;AAClB,gBAAY,IAAI,OAAO,QAAQ,aAAa;AAAA,MACxC,QAAQ,KAAwB;AAC5B,YAAI,CAAC,IAAI,iBAAiB,SAAS,SAAS,EAAG,KAAI,kBAAkB,SAAS;AAAA,MAClF;AAAA,IACJ,CAAC;AACD,UAAM;AAAA,EACV;AAEA,iBAAe,UAAa,IAAuD;AAC/E,QAAI;AACA,YAAM,KAAK,MAAM,OAAO;AACxB,aAAO,MAAM,GAAG,EAAE;AAAA,IACtB,SAAS,KAAU;AACf,YAAM,MAAM,OAAO,OAAO,IAAI,UAAU,IAAI,UAAU,GAAG;AACzD,UAAI,QAAQ,IAAI,SAAS,mBAAmB,eAAe,KAAK,GAAG,IAAI;AACnE,cAAM,YAAY;AAClB,cAAM,MAAM,MAAM,OAAO;AACzB,eAAO,MAAM,GAAG,GAAG;AAAA,MACvB;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAEA,SAAO;AAAA,IACH,SAAS,OAAO,SAAyC;AACrD,aAAO,UAAU,OAAO,OAAO;AAC3B,YAAI,IAAI,MAAM,GAAG,IAAI,WAAW,IAAI;AACpC,YAAI,KAAK;AACT,eAAO;AAAA,MACX,CAAC;AAAA,IACL;AAAA,IACA,SAAS,OAAO,MAAc,UAAiC;AAC3D,aAAO,UAAU,OAAO,OAAO;AAC3B,cAAM,GAAG,IAAI,WAAW,OAAO,IAAI;AAAA,MACvC,CAAC;AAAA,IACL;AAAA,IACA,YAAY,OAAO,SAAgC;AAC/C,aAAO,UAAU,OAAO,OAAO;AAC3B,cAAM,GAAG,OAAO,WAAW,IAAI;AAAA,MACnC,CAAC;AAAA,IACL;AAAA,EACJ;AACJ;;;ANxDO,IAAK,aAAL,kBAAKC,gBAAL;AACH,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,YAAS;AACT,EAAAA,YAAA,YAAS;AAHD,SAAAA;AAAA,GAAA;AAMZ,IAAM,+BAA+B;AACrC,IAAM,iBAAyB;AAC/B,IAAM,wBAAkC;AACxC,IAAM,yCAAsE;AAC5E,IAAM,uCAAmE;AAElE,SAAS,eACZ,cACA,gBACA,SACA,cAA2B,CAAC,GACK;AACjC,QAAM,YAAQ,uBAAO,gBAAgB,cAAc,gBAAgB,SAAS,WAAW,CAAC;AAExF,SAAO,IAAI,QAAkC,CAAC,YAAY;AACtD,UAAM,QAAQ,kBAAkB,CAAC,WAAW;AACxC,cAAQ,KAAK;AAAA,IACjB,CAAC;AAAA,EACL,CAAC;AACL;AAEO,SAAS,gBACZ,cACA,gBACA,SACA,cAA2B,CAAC,GAC9B;AACE,QAAM,eAAe,YAAY,gBAAgB;AACjD,QAAM,kBAAkB,YAAY,2CAA2C;AAC/E,QAAM,6BAA6B,YAAY,8BAA8B;AAC7E,QAAM,SAAS,UAAU,YAAY,UAAU,gBAAgB,YAAY,eAAe,qBAAqB;AAE/G,QAAM,kBAAkB,gBAAgB;AACxC,QAAM,iBAAiB,gBAAgB;AAEvC,QAAM,wBAAwB;AAAA,IAC1B,GAAG;AAAA,IACH,oBAAoB,MAAM;AACtB,aAAO,MAAM,0BAA0B;AAEvC,aAAO,CAAC,OAAY,UAAe;AAC/B,YAAI,OAAO;AACP,iBAAO,MAAM,6BAA6B,KAAK;AAAA,QACnD,OAAO;AACH,4BAAkB,OAAO,KAAK;AAC9B,iBAAO,MAAM,+BAA+B,KAAK;AAAA,QACrD;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,YAAY,CAAC,MAAW;AAGpB,YAAM,OAAO,iBAAiB,eAAe,CAAC,IAAI;AAClD,YAAM,EAAE,WAAW,GAAG,KAAK,IAAI,QAAQ,CAAC;AACxC,aAAO;AAAA,QACH,GAAG;AAAA,QACH,WAAW;AAAA,UACP,eAAe,UAAU;AAAA,UACzB,gBAAgB,UAAU;AAAA,UAC1B,YAAY,UAAU;AAAA,UACtB,WAAW,UAAU;AAAA,QACzB;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,CAAC,WAAgB,YAAiB;AAOrC,YAAM,QAAQ,EAAE,GAAG,SAAS,GAAG,UAAU;AAEzC,aAAO;AAAA,QACH,GAAG;AAAA,QACH,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ;AAAA;AAAA,QACZ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,UAAoD,CAAC,KAAU,KAAU,aAAkB;AAC7F,QAAI,mBAAmB;AAEvB,mBAAe,WAAW;AACtB,UAAI,IAAI,EAAE,UAAU,WAAW,OAAQ;AAEvC,UAAI,CAAC,WAAgB;AAAA,QACjB,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ;AAAA,QACZ;AAAA,MACJ,EAAE;AAEF,UAAI;AAGJ,iBAAW,YAAY,OAAO,KAAK,OAAO,GAAG;AACzC,YAAI;AACA,gBAAM,MAAM,QAAQ,UAAU,OAAO;AACrC,gBAAM,KAAK,KAAK,KAAK,UAAU,KAAK,QAAQ,0BAA0B;AAAA,QAC1E,SAAS,KAAK;AACV,2BAAiB,kBAAmB;AACpC,iBAAO,MAAM,8BAA8B,QAAQ,IAAI,GAAG;AAAA,QAC9D;AAAA,MACJ;AAGA,YAAM,kBAAmC,CAAC,GAAI,IAAI,EAAE,UAAU,kBAAkB,CAAC,CAAE;AAGnF,sBAAgB,KAAK,CAAC,GAAG,MAAM,SAAS,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,CAAC;AAEtE,iBAAW,UAAU,iBAAiB;AAClC,YAAI;AACA,gBAAM,MAAM,QAAQ,OAAO,UAAU,OAAO;AAC5C,gBAAM;AAAA,YACF;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAY;AAAA,YACZ,YAAY;AAAA,UAChB;AAAA,QACJ,SAAS,KAAK;AACV,2BAAiB,kBAAmB;AACpC,iBAAO,MAAM,4BAA4B,MAAM,IAAI,GAAG;AAAA,QAC1D;AAAA,MACJ;AAEA,UAAI,CAAC,WAAgB;AAAA,QACjB,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ;AAAA,UACR,OAAO;AAAA,QACX;AAAA,MACJ,EAAE;AAAA,IACN;AAEA,aAAS,kBAAkB,SAAc;AACrC,UAAI,OAAO,YAAY,YAAY;AAC/B,YAAI,CAAC,UAAe,aAAa,OAAO,QAAQ,KAAK,CAAC,CAAC;AAAA,MAC3D,OAAO;AACH,YAAI,CAAC,UAAe,aAAa,OAAO,OAAO,CAAC;AAAA,MACpD;AAAA,IACJ;AAEA,aAAS,aAAa,OAAY,SAAc;AAC5C,YAAM,iBAAkC,MAAM,UAAU,kBAAkB,CAAC;AAE3E,aAAO,KAAK,OAAO,EAAE,IAAI,CAAC,aAAa;AACnC,cAAM,UAAU,MAAM,QAAQ;AAC9B,cAAM,UAAU,QAAQ,QAAQ;AAChC,cAAM,UAAU,YAAY,SAAS,OAAO;AAC5C,+BAAuB,gBAAgB,UAAU,OAAO;AAAA,MAC5D,CAAC;AAGD,YAAM,YAAY,mBAAmB,gBAAgB,MAAM,UAAU,SAAS;AAE9E,aAAO;AAAA,QACH,GAAG;AAAA,QACH,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB;AAAA,UACA;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,aAAS,OAAO,SAAkB;AAC9B,UAAI,CAAC,WAAgB;AAAA,QACjB,WAAW;AAAA,UACP,GAAI,MAAM,aAAa,CAAC;AAAA,UACxB,QAAQ,UAAU,SAAS;AAAA,QAC/B;AAAA,MACJ,EAAE;AAEF,qBAAe,OAAO;AACtB,kCAA4B,OAAO;AAAA,IACvC;AAEA,aAAS,eAAe,OAAgB;AACpC,UAAI,OAAO;AACP,iBAAS;AAAA,MACb,OAAO;AACH,2BAAmB;AAAA,MACvB;AAAA,IACJ;AAEA,mBAAe,WAAW;AACtB,UAAI,iBAAkB;AACtB,yBAAmB;AAEnB,aAAO,MAAM;AACT,YAAI,CAAC,iBAAkB;AACvB,cAAM,SAAS;AACf,cAAM,MAAM,YAAY;AAAA,MAC5B;AAAA,IACJ;AAEA,aAAS,4BAA4B,KAAc;AAC/C,UAAI,KAAK;AACL,iBAAS,iBAAiB,oBAAoB,kBAAkB;AAAA,MACpE,OAAO;AACH,iBAAS,oBAAoB,oBAAoB,kBAAkB;AAAA,MACvE;AAAA,IACJ;AAEA,aAAS,qBAAqB;AAC1B,UAAI,SAAS,oBAAoB,WAAW;AACxC,eAAO,MAAM,iCAAiC;AAC9C,uBAAe,IAAI;AAAA,MACvB,OAAO;AACH,eAAO,MAAM,iCAAiC;AAC9C,uBAAe,KAAK;AAAA,MACxB;AAAA,IACJ;AAGA,aAAS,OAAO;AAAA,MACZ;AAAA,MACA,gBAAgB,MAAM,eAAe,KAAK,SAAS,MAAM;AAAA,MACzD,iBAAiB,CAAC,SAAiB,cAAuB,gBAAgB,KAAK,SAAS,SAAS;AAAA,IACrG;AAEA,UAAM,YAAY,aAAa,KAAK,KAAK,iBAAiB;AAE1D,WAAO;AAAA,MACH,GAAG;AAAA,MACH,WAAW;AAAA;AAAA,QAEP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,WAAW;AAAA,QACX,eAAe;AAAA,QACf,gBAAgB,CAAC;AAAA,QACjB,YAAY,CAAC;AAAA,MACjB;AAAA,IACJ;AAAA,EACJ;AAEA,aAAO,2BAAQ,SAAS,qBAAqB;AACjD;","names":["target","SyncAction"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -18,7 +18,7 @@ interface ApiFunctions {
|
|
|
18
18
|
firstLoad: (lastId: any) => Promise<any[]>;
|
|
19
19
|
}
|
|
20
20
|
type MissingRemoteRecordStrategy = 'ignore' | 'delete-local-record' | 'insert-remote-record';
|
|
21
|
-
type ConflictResolutionStrategy = '
|
|
21
|
+
type ConflictResolutionStrategy = 'local-wins' | 'remote-wins' | 'try-shallow-merge';
|
|
22
22
|
type AfterRemoteAddCallback = (set: any, get: any, setAndSync: SetAndSyncCallback, stateKey: string, item: SyncedRecord) => void;
|
|
23
23
|
type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
24
24
|
interface SyncOptions {
|
|
@@ -49,7 +49,7 @@ interface PendingChange {
|
|
|
49
49
|
id?: any;
|
|
50
50
|
version: number;
|
|
51
51
|
changes?: any;
|
|
52
|
-
|
|
52
|
+
before?: any;
|
|
53
53
|
}
|
|
54
54
|
type UseStoreWithSync<T> = UseBoundStore<StoreApi<T & SyncState> & {
|
|
55
55
|
sync: {
|
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ interface ApiFunctions {
|
|
|
18
18
|
firstLoad: (lastId: any) => Promise<any[]>;
|
|
19
19
|
}
|
|
20
20
|
type MissingRemoteRecordStrategy = 'ignore' | 'delete-local-record' | 'insert-remote-record';
|
|
21
|
-
type ConflictResolutionStrategy = '
|
|
21
|
+
type ConflictResolutionStrategy = 'local-wins' | 'remote-wins' | 'try-shallow-merge';
|
|
22
22
|
type AfterRemoteAddCallback = (set: any, get: any, setAndSync: SetAndSyncCallback, stateKey: string, item: SyncedRecord) => void;
|
|
23
23
|
type MissingRemoteRecordDuringUpdateCallback = (strategy: MissingRemoteRecordStrategy, item: SyncedRecord) => void;
|
|
24
24
|
interface SyncOptions {
|
|
@@ -49,7 +49,7 @@ interface PendingChange {
|
|
|
49
49
|
id?: any;
|
|
50
50
|
version: number;
|
|
51
51
|
changes?: any;
|
|
52
|
-
|
|
52
|
+
before?: any;
|
|
53
53
|
}
|
|
54
54
|
type UseStoreWithSync<T> = UseBoundStore<StoreApi<T & SyncState> & {
|
|
55
55
|
sync: {
|
package/dist/index.js
CHANGED
|
@@ -108,7 +108,7 @@ function tryAddToPendingChanges(pendingChanges, stateKey, changes) {
|
|
|
108
108
|
queueItem.changes = { ...queueItem.changes, ...omittedItem };
|
|
109
109
|
}
|
|
110
110
|
} else if (action === "remove" /* Remove */ || hasChanges) {
|
|
111
|
-
pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem,
|
|
111
|
+
pendingChanges.push({ action, stateKey, localId, id: change.id, version: 1, changes: omittedItem, before: omitSyncFields(change.currentItem) });
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -120,6 +120,13 @@ function setPendingChangeToUpdate(get, stateKey, localId, id) {
|
|
|
120
120
|
if (id) change.id = id;
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
+
function setPendingChangeBefore(get, stateKey, localId, before) {
|
|
124
|
+
const pendingChanges = get().syncState.pendingChanges || [];
|
|
125
|
+
const change = pendingChanges.find((p) => p.stateKey === stateKey && p.localId === localId);
|
|
126
|
+
if (change) {
|
|
127
|
+
change.before = { ...change.before, ...before };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
123
130
|
function tryUpdateConflicts(pendingChanges, conflicts) {
|
|
124
131
|
if (!conflicts) return conflicts;
|
|
125
132
|
const newConflicts = { ...conflicts };
|
|
@@ -259,9 +266,9 @@ async function pull(set, get, stateKey, api, logger, conflictResolutionStrategy)
|
|
|
259
266
|
if (pendingChange) {
|
|
260
267
|
logger.debug(`[zync] pull:conflict-strategy:${conflictResolutionStrategy} stateKey=${stateKey} id=${remote.id}`);
|
|
261
268
|
switch (conflictResolutionStrategy) {
|
|
262
|
-
case "
|
|
269
|
+
case "local-wins":
|
|
263
270
|
break;
|
|
264
|
-
case "
|
|
271
|
+
case "remote-wins": {
|
|
265
272
|
const merged = { ...remote, _localId: localItem._localId };
|
|
266
273
|
nextItems = nextItems.map((i) => i._localId === localItem._localId ? merged : i);
|
|
267
274
|
pendingChanges = pendingChanges.filter((p) => !(p.stateKey === stateKey && p.localId === localItem._localId));
|
|
@@ -269,8 +276,8 @@ async function pull(set, get, stateKey, api, logger, conflictResolutionStrategy)
|
|
|
269
276
|
}
|
|
270
277
|
case "try-shallow-merge": {
|
|
271
278
|
const changes = pendingChange.changes || {};
|
|
272
|
-
const
|
|
273
|
-
const fields = Object.entries(changes).filter(([k, localValue]) => k in
|
|
279
|
+
const before = pendingChange.before || {};
|
|
280
|
+
const fields = Object.entries(changes).filter(([k, localValue]) => k in before && k in remote && before[k] !== remote[k] && localValue !== remote[k]).map(([key, localValue]) => ({ key, localValue, remoteValue: remote[key] }));
|
|
274
281
|
if (fields.length > 0) {
|
|
275
282
|
logger.warn(`[zync] pull:${conflictResolutionStrategy}:conflicts-found`, JSON.stringify(fields, null, 4));
|
|
276
283
|
conflicts[localItem._localId] = { stateKey, fields };
|
|
@@ -316,7 +323,6 @@ async function pull(set, get, stateKey, api, logger, conflictResolutionStrategy)
|
|
|
316
323
|
async function pushOne(set, get, change, api, logger, setAndQueueToSync, missingStrategy, onMissingRemoteRecordDuringUpdate, onAfterRemoteAdd) {
|
|
317
324
|
logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);
|
|
318
325
|
const { action, stateKey, localId, id, version, changes } = change;
|
|
319
|
-
const changesClone = { ...changes };
|
|
320
326
|
switch (action) {
|
|
321
327
|
case "remove" /* Remove */:
|
|
322
328
|
if (!id) {
|
|
@@ -333,11 +339,13 @@ async function pushOne(set, get, change, api, logger, setAndQueueToSync, missing
|
|
|
333
339
|
logger.warn(`[zync] push:update:skipping-with-conflicts stateKey=${stateKey} localId=${localId} id=${id}`);
|
|
334
340
|
return;
|
|
335
341
|
}
|
|
336
|
-
const exists = await api.update(id,
|
|
342
|
+
const exists = await api.update(id, changes);
|
|
337
343
|
if (exists) {
|
|
338
344
|
logger.debug(`[zync] push:update:success stateKey=${stateKey} localId=${localId} id=${id}`);
|
|
339
345
|
if (samePendingVersion(get, stateKey, localId, version)) {
|
|
340
346
|
removeFromPendingChanges(set, localId, stateKey);
|
|
347
|
+
} else {
|
|
348
|
+
setPendingChangeBefore(get, stateKey, localId, changes);
|
|
341
349
|
}
|
|
342
350
|
return;
|
|
343
351
|
} else {
|
|
@@ -381,7 +389,7 @@ async function pushOne(set, get, change, api, logger, setAndQueueToSync, missing
|
|
|
381
389
|
break;
|
|
382
390
|
}
|
|
383
391
|
case "create" /* Create */: {
|
|
384
|
-
const result = await api.add(
|
|
392
|
+
const result = await api.add(changes);
|
|
385
393
|
if (result) {
|
|
386
394
|
logger.debug(`[zync] push:create:success stateKey=${stateKey} localId=${localId} id=${id}`);
|
|
387
395
|
set((s) => ({
|
|
@@ -562,7 +570,7 @@ var DEFAULT_SYNC_INTERVAL_MILLIS = 2e3;
|
|
|
562
570
|
var DEFAULT_LOGGER = console;
|
|
563
571
|
var DEFAULT_MIN_LOG_LEVEL = "debug";
|
|
564
572
|
var DEFAULT_MISSING_REMOTE_RECORD_STRATEGY = "ignore";
|
|
565
|
-
var DEFAULT_CONFLICT_RESOLUTION_STRATEGY = "
|
|
573
|
+
var DEFAULT_CONFLICT_RESOLUTION_STRATEGY = "local-wins";
|
|
566
574
|
function createWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}) {
|
|
567
575
|
const store = create(persistWithSync(stateCreator, persistOptions, syncApi, syncOptions));
|
|
568
576
|
return new Promise((resolve) => {
|
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 = 'client-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, current: 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 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 'client-wins':\n // Ignore remote changes, keep local\n break;\n\n case 'server-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 current = pendingChange.current || {};\n const fields: FieldConflict[] = Object.entries(changes)\n .filter(([k, localValue]) => k in current && k in remote && current[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, 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 const changesClone = { ...changes }; // TODO: Test if needed\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, changesClone);\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 }\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(changesClone);\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 { 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"]}
|