@anfenn/zync 0.1.10 → 0.1.12
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 +122 -2
- package/dist/index.cjs +25 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +25 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,126 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Zync
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@anfenn/zync)
|
|
4
|
+
|
|
5
|
+
Unopinionated, bullet-proof, offline-first sync middleware for Zustand.
|
|
6
|
+
|
|
7
|
+
## Benefits
|
|
8
|
+
|
|
9
|
+
- Uses the official persist middleware as the local storage (localStorage, IndexedDB, etc.)
|
|
10
|
+
- Zync's persistWithSync() is a drop-in replacement for Zustand's persist()
|
|
11
|
+
- Allows for idiomatic use of Zustand
|
|
12
|
+
- Leaves the api requests up to you (RESTful, GraphQL, etc.), just provide add(), update(), remove() and list()
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- 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 `nextLocalId()` returns a UUID, but you could use any unique value
|
|
17
|
+
- Server records must have:
|
|
18
|
+
- `id`: Server assigned unique identifier (any datatype)
|
|
19
|
+
- `updated_at`: Server assigned (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
|
|
20
|
+
- `deleted`: Boolean, used for soft deletes, to allow other clients to download deleted records to keep their local records in sync
|
|
21
|
+
|
|
22
|
+
## Quickstart
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @anfenn/zync
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Zustand store creation:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { SyncAction, UseStoreWithSync, persistWithSync } from '@anfenn/zync';
|
|
32
|
+
import { create } from 'zustand';
|
|
33
|
+
import { createJSONStorage } from 'zustand/middleware';
|
|
34
|
+
import { useShallow } from 'zustand/react/shallow';
|
|
35
|
+
|
|
36
|
+
type Store = {
|
|
37
|
+
facts: Fact[];
|
|
38
|
+
addFact: (item: Fact) => void;
|
|
39
|
+
updateFact: (localId: string, changes: Partial<Fact>) => void;
|
|
40
|
+
removeFact: (localId: string) => void;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const useStore = create<any>()(
|
|
44
|
+
persistWithSync<Store>(
|
|
45
|
+
(set, get, queueToSync) => ({
|
|
46
|
+
// Standard Zustand state and mutation functions with new queueToSync() function
|
|
47
|
+
|
|
48
|
+
facts: [],
|
|
49
|
+
addFact: (item: Fact) => {
|
|
50
|
+
const updated_at = new Date().toISOString();
|
|
51
|
+
const newItem = { ...item, created_at: updated_at, updated_at };
|
|
52
|
+
|
|
53
|
+
set((state: Store) => ({
|
|
54
|
+
facts: [...state.facts, newItem],
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
queueToSync(SyncAction.CreateOrUpdate, item._localId, 'facts');
|
|
58
|
+
},
|
|
59
|
+
updateFact: (localId: string, changes: Partial<Fact>) => {
|
|
60
|
+
set((state: Store) => ({
|
|
61
|
+
facts: state.facts.map((item) => (item._localId === localId ? { ...item, ...changes } : item)),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
queueToSync(SyncAction.CreateOrUpdate, localId, 'facts');
|
|
65
|
+
},
|
|
66
|
+
removeFact: (localId: string) => {
|
|
67
|
+
queueToSync(SyncAction.Remove, 'facts', localId);
|
|
68
|
+
|
|
69
|
+
set((state: Store) => ({
|
|
70
|
+
facts: state.facts.filter((item) => item._localId !== localId),
|
|
71
|
+
}));
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
{
|
|
75
|
+
// Standard Zustand persist options
|
|
76
|
+
|
|
77
|
+
name: 'store',
|
|
78
|
+
storage: createJSONStorage(() => localStorage),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
// State-to-API map to enable syncing. Must implement the full CRUD API:
|
|
82
|
+
//
|
|
83
|
+
// add: (item: any) => Promise<any | undefined>
|
|
84
|
+
// update: (id: any, changes: any) => Promise<boolean>
|
|
85
|
+
// remove: (id: any) => Promise<void>
|
|
86
|
+
// list: (lastUpdatedAt: Date) => Promise<any[]>
|
|
87
|
+
// firstLoad: (lastId: any) => Promise<any[]> (Optional)
|
|
88
|
+
|
|
89
|
+
facts: factApi,
|
|
90
|
+
},
|
|
91
|
+
),
|
|
92
|
+
) as UseStoreWithSync<Store>;
|
|
93
|
+
|
|
94
|
+
const useFacts = () =>
|
|
95
|
+
useStore(
|
|
96
|
+
useShallow(({ facts, addFact, updateFact, removeFact }) => ({
|
|
97
|
+
facts,
|
|
98
|
+
addFact,
|
|
99
|
+
updateFact,
|
|
100
|
+
removeFact,
|
|
101
|
+
})),
|
|
102
|
+
);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### In your component:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// Your state
|
|
109
|
+
const { facts, addFact } = useFacts();
|
|
110
|
+
|
|
111
|
+
// Zync's internal sync state
|
|
112
|
+
const syncState = useStore((state) => state.syncState);
|
|
113
|
+
// syncState.status // 'hydrating' | 'syncing' | 'idle'
|
|
114
|
+
// syncState.error
|
|
115
|
+
// syncState.enabled
|
|
116
|
+
// syncState.firstLoadDone
|
|
117
|
+
// syncState.pendingChanges
|
|
118
|
+
// syncState.lastPulled
|
|
119
|
+
|
|
120
|
+
// Zync's control api
|
|
121
|
+
useStore.sync.enable(true | false);
|
|
122
|
+
useStore.sync.startFirstLoad();
|
|
123
|
+
```
|
|
4
124
|
|
|
5
125
|
## Optional IndexedDB storage
|
|
6
126
|
|
package/dist/index.cjs
CHANGED
|
@@ -354,7 +354,7 @@ function findApi(stateKey, syncApi) {
|
|
|
354
354
|
async function pull(set, get, stateKey, api, logger) {
|
|
355
355
|
const lastPulled = get().syncState.lastPulled || {};
|
|
356
356
|
const lastPulledAt = new Date(lastPulled[stateKey] || /* @__PURE__ */ new Date(0));
|
|
357
|
-
logger.debug(`[
|
|
357
|
+
logger.debug(`[zync] pull:start stateKey=${stateKey} since=${lastPulledAt.toISOString()}`);
|
|
358
358
|
const serverData = await api.list(lastPulledAt);
|
|
359
359
|
if (!serverData?.length) return;
|
|
360
360
|
let newest = lastPulledAt;
|
|
@@ -368,14 +368,14 @@ async function pull(set, get, stateKey, api, logger) {
|
|
|
368
368
|
const remoteUpdated = new Date(remote.updated_at);
|
|
369
369
|
if (remoteUpdated > newest) newest = remoteUpdated;
|
|
370
370
|
if (pendingRemovalById.has(remote.id)) {
|
|
371
|
-
logger.debug(`[
|
|
371
|
+
logger.debug(`[zync] pull:skip-pending-remove stateKey=${stateKey} id=${remote.id}`);
|
|
372
372
|
continue;
|
|
373
373
|
}
|
|
374
374
|
const localItem = localById.get(remote.id);
|
|
375
375
|
if (remote.deleted) {
|
|
376
376
|
if (localItem) {
|
|
377
377
|
nextItems = nextItems.filter((i) => i.id !== remote.id);
|
|
378
|
-
logger.debug(`[
|
|
378
|
+
logger.debug(`[zync] pull:remove stateKey=${stateKey} id=${remote.id}`);
|
|
379
379
|
}
|
|
380
380
|
continue;
|
|
381
381
|
}
|
|
@@ -387,10 +387,10 @@ async function pull(set, get, stateKey, api, logger) {
|
|
|
387
387
|
_localId: localItem._localId
|
|
388
388
|
};
|
|
389
389
|
nextItems = nextItems.map((i) => i._localId === localItem._localId ? merged : i);
|
|
390
|
-
logger.debug(`[
|
|
390
|
+
logger.debug(`[zync] pull:merge stateKey=${stateKey} id=${remote.id}`);
|
|
391
391
|
} else if (!localItem) {
|
|
392
392
|
nextItems = [...nextItems, { ...remote, _localId: nextLocalId() }];
|
|
393
|
-
logger.debug(`[
|
|
393
|
+
logger.debug(`[zync] pull:add stateKey=${stateKey} id=${remote.id}`);
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
return {
|
|
@@ -409,12 +409,12 @@ async function pull(set, get, stateKey, api, logger) {
|
|
|
409
409
|
// src/push.ts
|
|
410
410
|
var SYNC_FIELDS = ["id", "_localId", "updated_at", "deleted"];
|
|
411
411
|
async function pushOne(set, get, change, api, logger, queueToSync, missingStrategy, onMissingRemoteRecordDuringUpdate, onAfterRemoteAdd) {
|
|
412
|
-
logger.debug(`[
|
|
412
|
+
logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);
|
|
413
413
|
const { action, stateKey, localId, id, version } = change;
|
|
414
414
|
switch (action) {
|
|
415
415
|
case "remove" /* Remove */:
|
|
416
416
|
await api.remove(id);
|
|
417
|
-
logger.debug(`[
|
|
417
|
+
logger.debug(`[zync] push:remove:success ${stateKey} ${localId} ${id}`);
|
|
418
418
|
removeFromPendingChanges(set, localId, stateKey);
|
|
419
419
|
break;
|
|
420
420
|
case "createOrUpdate" /* CreateOrUpdate */: {
|
|
@@ -422,7 +422,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
422
422
|
const items = state[stateKey] || [];
|
|
423
423
|
const item = items.find((i) => i._localId === localId);
|
|
424
424
|
if (!item) {
|
|
425
|
-
logger.warn(`[
|
|
425
|
+
logger.warn(`[zync] push:create-or-update:no-local-item`, {
|
|
426
426
|
stateKey,
|
|
427
427
|
localId
|
|
428
428
|
});
|
|
@@ -433,7 +433,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
433
433
|
if (item.id) {
|
|
434
434
|
const changed = await api.update(item.id, omittedItem);
|
|
435
435
|
if (changed) {
|
|
436
|
-
logger.debug("[
|
|
436
|
+
logger.debug("[zync] push:update:success", {
|
|
437
437
|
stateKey,
|
|
438
438
|
localId,
|
|
439
439
|
id: item.id
|
|
@@ -443,7 +443,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
443
443
|
}
|
|
444
444
|
return;
|
|
445
445
|
} else {
|
|
446
|
-
logger.warn("[
|
|
446
|
+
logger.warn("[zync] push:update:missing-remote", {
|
|
447
447
|
stateKey,
|
|
448
448
|
localId,
|
|
449
449
|
id: item.id
|
|
@@ -471,7 +471,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
471
471
|
}
|
|
472
472
|
const result = await api.add(omittedItem);
|
|
473
473
|
if (result) {
|
|
474
|
-
logger.debug("[
|
|
474
|
+
logger.debug("[zync] push:create:success", {
|
|
475
475
|
stateKey,
|
|
476
476
|
localId,
|
|
477
477
|
id: result.id
|
|
@@ -487,7 +487,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
487
487
|
...result
|
|
488
488
|
});
|
|
489
489
|
} else {
|
|
490
|
-
logger.warn("[
|
|
490
|
+
logger.warn("[zync] push:create:no-result", {
|
|
491
491
|
stateKey,
|
|
492
492
|
localId
|
|
493
493
|
});
|
|
@@ -599,13 +599,13 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
599
599
|
const wrappedPersistOptions = {
|
|
600
600
|
...persistOptions,
|
|
601
601
|
onRehydrateStorage: () => {
|
|
602
|
-
logger.debug("[
|
|
602
|
+
logger.debug("[zync] rehydration:start");
|
|
603
603
|
return (state, error) => {
|
|
604
604
|
if (error) {
|
|
605
|
-
logger.error("[
|
|
605
|
+
logger.error("[zync] rehydration:failed", error);
|
|
606
606
|
} else {
|
|
607
607
|
baseOnRehydrate?.(state, error);
|
|
608
|
-
logger.debug("[
|
|
608
|
+
logger.debug("[zync] rehydration:complete", state);
|
|
609
609
|
}
|
|
610
610
|
};
|
|
611
611
|
},
|
|
@@ -651,7 +651,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
651
651
|
await pull(set, get, stateKey, api, logger);
|
|
652
652
|
} catch (err) {
|
|
653
653
|
syncError = syncError ?? err;
|
|
654
|
-
logger.error(`[
|
|
654
|
+
logger.error(`[zync] pull:error stateKey=${stateKey}`, err);
|
|
655
655
|
}
|
|
656
656
|
}
|
|
657
657
|
const snapshot = [...get().syncState.pendingChanges || []];
|
|
@@ -672,7 +672,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
672
672
|
);
|
|
673
673
|
} catch (err) {
|
|
674
674
|
syncError = syncError ?? err;
|
|
675
|
-
logger.error(`[
|
|
675
|
+
logger.error(`[zync] push:error change=${change}`, err);
|
|
676
676
|
}
|
|
677
677
|
}
|
|
678
678
|
set((state2) => ({
|
|
@@ -690,7 +690,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
690
690
|
let syncError;
|
|
691
691
|
for (const stateKey of Object.keys(syncApi)) {
|
|
692
692
|
try {
|
|
693
|
-
logger.info(`[
|
|
693
|
+
logger.info(`[zync] firstLoad:start stateKey=${stateKey}`);
|
|
694
694
|
const api = findApi(stateKey, syncApi);
|
|
695
695
|
let lastId;
|
|
696
696
|
while (true) {
|
|
@@ -734,10 +734,10 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
734
734
|
});
|
|
735
735
|
lastId = batch[batch.length - 1].id;
|
|
736
736
|
}
|
|
737
|
-
logger.info(`[
|
|
737
|
+
logger.info(`[zync] firstLoad:done stateKey=${stateKey}`);
|
|
738
738
|
} catch (err) {
|
|
739
739
|
syncError = syncError ?? err;
|
|
740
|
-
logger.error(`[
|
|
740
|
+
logger.error(`[zync] firstLoad:error stateKey=${stateKey}`, err);
|
|
741
741
|
}
|
|
742
742
|
}
|
|
743
743
|
set((state) => ({
|
|
@@ -754,10 +754,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
754
754
|
for (const localId of localIds) {
|
|
755
755
|
const item = state[stateKey].find((i) => i._localId === localId);
|
|
756
756
|
if (!item) {
|
|
757
|
-
logger.error(
|
|
758
|
-
stateKey,
|
|
759
|
-
localId
|
|
760
|
-
});
|
|
757
|
+
logger.error(`[zync] queueToSync:no-local-item localId=${localId}`);
|
|
761
758
|
continue;
|
|
762
759
|
}
|
|
763
760
|
const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);
|
|
@@ -767,10 +764,10 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
767
764
|
queueItem.action = "remove" /* Remove */;
|
|
768
765
|
queueItem.id = item.id;
|
|
769
766
|
}
|
|
770
|
-
logger.debug(`[
|
|
767
|
+
logger.debug(`[zync] queueToSync:adjusted v=${queueItem.version} action=${action} localId=${localId}`);
|
|
771
768
|
} else {
|
|
772
769
|
pendingChanges.push({ action, stateKey, localId, id: item.id, version: 1 });
|
|
773
|
-
logger.debug(`[
|
|
770
|
+
logger.debug(`[zync] queueToSync:added action=${action} localId=${localId}`);
|
|
774
771
|
}
|
|
775
772
|
}
|
|
776
773
|
return {
|
|
@@ -817,10 +814,10 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
817
814
|
}
|
|
818
815
|
function onVisibilityChange() {
|
|
819
816
|
if (document.visibilityState === "visible") {
|
|
820
|
-
logger.debug("[
|
|
817
|
+
logger.debug("[zync] sync:start-in-foreground");
|
|
821
818
|
enableSyncTimer(true);
|
|
822
819
|
} else {
|
|
823
|
-
logger.debug("[
|
|
820
|
+
logger.debug("[zync] sync:pause-in-background");
|
|
824
821
|
enableSyncTimer(false);
|
|
825
822
|
}
|
|
826
823
|
}
|
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/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, nextLocalId } from './helpers';\nimport type {\n ApiFunctions,\n MissingRemoteRecordDuringUpdateStrategy,\n SyncOptions,\n SyncState,\n SyncedStateCreator,\n PendingChange,\n UseStoreWithSync,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\n\nexport { createIndexedDBStorage } from './indexedDBStorage';\nexport { nextLocalId } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n CreateOrUpdate = 'createOrUpdate',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 5000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_ON_UPDATE_STRATEGY: MissingRemoteRecordDuringUpdateStrategy = 'ignore';\n\n/**\n * Zync creates a standard persisted Zustand store with optional background sync (e.g. via RESTful, GraphQL, etc.).\n * It provides a `queueToSync()` method to enqueue changes for syncing, which are processed on an interval.\n *\n * This is a drop-in replacement for Zustand's `persist()` middleware that wires in background sync. It's usage mirrors\n * `persist(stateCreator, options)` with optional syncing per state key.\n *\n * Can be used with any storage that Zustand Persist supports. Options include localStorage if its syncronous access doesn't\n * cause blocking issues like UI freezes, or IndexedDB with its asynchronous access for improved performance.\n *\n * When using IndexedDB the whole store is saved under one key, which means indexes cannot be used to accelerate querying. However, if this\n * 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\n * provide the syntax for high performance queries.\n *\n * Zync's api is:\n * - `syncState` object for reactive access to internal state i.e.: const syncState = useStore((state) => state.syncState);\n * - `sync` object for control methods e.g.: useStore.sync.enable(true|false);\n *\n * Synced objects will have the client only field `_localId`, which provides a stable identifier for the object.\n * It is ideal for use as JSX keys.\n *\n * Synced objects are expected to have the following server fields:\n *\n * - id: The unique identifier from the server.\n * - updated_at: A timestamp indicating when the object was last updated.\n * This field is used to determine if the object needs to be re-fetched from the server.\n * It must be set at the server (e.g. via sql trigger or in the api code).\n * Ensure the server sets a timestamp with millisecond precision, not microsecond like PostgreSQL's timestampz,\n * as Javascript's Date object is based on milliseconds, and this will be used during sync.\n * Although the client can set this locally, it is only to give a good UX, as it won't be sent\n * to the server and will be overwritten on the client during sync. The client clock is never\n * used to check for changes as it can't be guaranteed to be in sync with the server clock. Instead any item\n * that is added, updated or deleted locally is added to a queue.\n * - deleted: A boolean flag indicating whether the object has been deleted. This use of soft deletes or similar\n * is how all clients are told about deletions during sync.\n *\n * Design principles:\n *\n * - Always pull (list) first each sync cycle to enable future conflict resolution. Currently last-write-wins, although any queued client changes\n * for an item will prevent it being overwritten during a pull, even if the server has a newer version.\n * - Then push queued changes in order (Create -> Update -> Remove).\n * - Queue coalescing: (Create + Update*) => single Create (merged changes); (Create + Remove) => drop both; (Update + Update) => merge; (Update + Remove) => Remove.\n *\n *\n * @param stateCreator - The function to create the initial state.\n * @param persistOptions - Standard Zustand options for persisting the store.\n * @param syncApi - Remote API functions for syncing state. Use the same key name as the state key.\n * e.g. if your state key is called `fish`, the syncApi should be `fish: { list, add, update, remove }`\n * If you don't provide a key for a state field, it won't be synced, but will be persisted as expected.\n * @param syncOptions - Syncing options (Optional).\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_ON_UPDATE_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 started');\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 },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly ascynchronously 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 syncIntervalId: any;\n\n async function syncOnce() {\n const state: SyncState = get();\n if (!state.syncState.enabled || state.syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let syncError: 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);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[Zync] Pull error for stateKey: ${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const snapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen early\n snapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of snapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n queueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[Zync] Push error for change: ${change}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'idle',\n error: syncError,\n },\n }));\n\n if (get().syncState.pendingChanges.length > 0 && !syncError) {\n // If there are pending changes and no sync error, we can sync again\n await syncOnce();\n }\n }\n\n async function startFirstLoad() {\n let syncError: Error | undefined;\n\n for (const stateKey of Object.keys(syncApi)) {\n try {\n logger.info(`[Zync] firstLoad:start for 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 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: nextLocalId(),\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 lastId = batch[batch.length - 1].id;\n }\n\n logger.info(`[Zync] firstLoad:done for stateKey: ${stateKey}`);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[Zync] First load pull error for 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\n function queueToSync(action: any, stateKey: string, ...localIds: string[]) {\n set((state: any) => {\n const pendingChanges: any[] = state.syncState.pendingChanges || [];\n\n for (const localId of localIds) {\n const item = state[stateKey].find((i: any) => i._localId === localId);\n if (!item) {\n logger.error('[Zync] queueToSync:no-local-item', {\n stateKey,\n localId,\n });\n continue;\n }\n\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n if (queueItem) {\n queueItem.version += 1;\n\n if (queueItem.action === SyncAction.CreateOrUpdate && action === SyncAction.Remove && item.id) {\n queueItem.action = SyncAction.Remove;\n queueItem.id = item.id;\n }\n logger.debug(`[Zync] queueToSync:adjusted ${queueItem.version} ${action} ${item.id} ${stateKey} ${localId}`);\n } else {\n pendingChanges.push({ action, stateKey, localId, id: item.id, version: 1 });\n logger.debug(`[Zync] queueToSync:added ${action} ${item.id} ${stateKey} ${localId}`);\n }\n }\n\n return {\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n },\n };\n });\n syncOnce();\n }\n\n function setAndSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => ({ ...partial(state) }));\n } else {\n set(partial);\n }\n syncOnce();\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n enabled,\n },\n }));\n\n enableSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function enableSyncTimer(enabled: boolean) {\n clearInterval(syncIntervalId);\n syncIntervalId = undefined;\n if (enabled) {\n syncIntervalId = setInterval(syncOnce, syncInterval);\n syncOnce();\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 started now app is in foreground');\n enableSyncTimer(true);\n } else {\n logger.debug('[Zync] Sync paused now app is in background');\n enableSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad,\n };\n\n const userState = stateCreator(setAndSync, get, queueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n enabled: false,\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, PendingChange } from './types';\n\nexport function nextLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.CreateOrUpdate:\n return 1;\n case SyncAction.Remove:\n return 2;\n }\n}\n\nexport function omitSyncFields(item: any, fields: readonly string[]) {\n const result = { ...item };\n for (const k of fields) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const q: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = q.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 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","import type { ApiFunctions, PendingChange, SyncedRecord } from './types';\nimport { SyncAction } from './index';\nimport { nextLocalId } from './helpers';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: any) {\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 set((state: any) => {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items by 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 flicker\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 const pending = localItem && pendingChanges.some((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (localItem && !pending) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[Zync] pull:merge stateKey=${stateKey} id=${remote.id}`);\n } else if (!localItem) {\n // Add remote item (no local or pending collisions)\n nextItems = [...nextItems, { ...remote, _localId: nextLocalId() }];\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 lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { removeFromPendingChanges, omitSyncFields, samePendingVersion } from './helpers';\nimport { SyncAction } from './index';\nimport type { ApiFunctions } from './types';\n\nconst SYNC_FIELDS = ['id', '_localId', 'updated_at', 'deleted'] as const;\n\nexport async function pushOne(\n set: any,\n get: any,\n change: any,\n api: ApiFunctions,\n logger: any,\n queueToSync: any,\n missingStrategy: string,\n onMissingRemoteRecordDuringUpdate?: any,\n onAfterRemoteAdd?: any,\n) {\n logger.debug(`[Zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version } = change;\n\n switch (action) {\n case SyncAction.Remove:\n await api.remove(id);\n logger.debug(`[Zync] push:remove:success ${stateKey} ${localId} ${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.CreateOrUpdate: {\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:${action}:no-local-item`, {\n stateKey,\n localId,\n });\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n const omittedItem = omitSyncFields(item, SYNC_FIELDS);\n if (item.id) {\n // Update\n const changed = await api.update(item.id, omittedItem);\n if (changed) {\n logger.debug('[Zync] push:update:success', {\n stateKey,\n localId,\n id: item.id,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n return;\n } else {\n logger.warn('[Zync] push:update:missingRemote', {\n stateKey,\n localId,\n id: item.id,\n });\n\n switch (missingStrategy) {\n case 'deleteLocalRecord':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n break;\n\n case 'insertNewRemoteRecord': {\n omittedItem._localId = crypto.randomUUID();\n omittedItem.updated_at = new Date().toISOString();\n\n // replace old with new copy without id so it becomes a Create\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? omittedItem : i)),\n }));\n\n queueToSync(SyncAction.CreateOrUpdate, stateKey, omittedItem._localId);\n break;\n }\n }\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, omittedItem, omittedItem._localId);\n }\n return;\n }\n\n // Create\n const result = await api.add(omittedItem);\n if (result) {\n logger.debug('[Zync] push:create:success', {\n stateKey,\n localId,\n id: result.id,\n });\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 if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, queueToSync, stateKey, {\n ...item,\n ...result,\n });\n } else {\n logger.warn('[Zync] push:create:no-result', {\n stateKey,\n localId,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\n }\n }\n}\n","import type { IDBPDatabase } from 'idb';\n\nexport function createIndexedDBStorage(options: { dbName: string; storeName: string }) {\n const dbName = options.dbName;\n const storeName = options.storeName;\n\n // dbPromise is created lazily by initDB() to avoid pulling `idb` into bundles\n let dbPromise: Promise<IDBPDatabase<any>> | null = null;\n\n async function initDB(): Promise<IDBPDatabase<any>> {\n if (dbPromise) return dbPromise;\n try {\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, 1, {\n upgrade(db: IDBPDatabase<any>) {\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName);\n }\n },\n });\n return dbPromise;\n } catch (_e) {\n throw new Error('Missing optional dependency \"idb\". Install it to use IndexedDB storage: npm install idb');\n }\n }\n\n async function ensureStore(): Promise<void> {\n const db = await initDB();\n if (db.objectStoreNames.contains(storeName)) return;\n const nextVersion = (db.version || 0) + 1;\n try {\n db.close();\n } catch (_e) {\n // ignore\n }\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, nextVersion, {\n upgrade(upg: IDBPDatabase<any>) {\n if (!upg.objectStoreNames.contains(storeName)) upg.createObjectStore(storeName);\n },\n });\n await dbPromise;\n }\n\n async function withRetry<T>(fn: (db: IDBPDatabase<any>) => Promise<T>): Promise<T> {\n try {\n const db = await initDB();\n return await fn(db);\n } catch (err: any) {\n const msg = String(err && err.message ? err.message : err);\n if (err && (err.name === 'NotFoundError' || /objectStore/i.test(msg))) {\n await ensureStore();\n const db2 = await initDB();\n return await fn(db2);\n }\n throw err;\n }\n }\n\n return {\n getItem: async (name: string): Promise<string | null> => {\n return withRetry(async (db) => {\n let v = await db.get(storeName, name);\n v = v ?? null; // Zustand expects null for missing keys\n return v;\n });\n },\n setItem: async (name: string, value: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.put(storeName, value, name);\n });\n },\n removeItem: async (name: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.delete(storeName, name);\n });\n },\n };\n}\n"],"mappings":"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","names":["target","SyncAction","state"]}
|
|
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/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, nextLocalId } from './helpers';\nimport type {\n ApiFunctions,\n MissingRemoteRecordDuringUpdateStrategy,\n SyncOptions,\n SyncState,\n SyncedStateCreator,\n PendingChange,\n UseStoreWithSync,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\n\nexport { createIndexedDBStorage } from './indexedDBStorage';\nexport { nextLocalId } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n CreateOrUpdate = 'createOrUpdate',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 5000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_ON_UPDATE_STRATEGY: MissingRemoteRecordDuringUpdateStrategy = 'ignore';\n\n/**\n * Zync creates a standard persisted Zustand store with optional background sync (e.g. via RESTful, GraphQL, etc.).\n * It provides a `queueToSync()` method to enqueue changes for syncing, which are processed on an interval.\n *\n * This is a drop-in replacement for Zustand's `persist()` middleware that wires in background sync. It's usage mirrors\n * `persist(stateCreator, options)` with optional syncing per state key.\n *\n * Can be used with any storage that Zustand Persist supports. Options include localStorage if its syncronous access doesn't\n * cause blocking issues like UI freezes, or IndexedDB with its asynchronous access for improved performance.\n *\n * When using IndexedDB the whole store is saved under one key, which means indexes cannot be used to accelerate querying. However, if this\n * 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\n * provide the syntax for high performance queries.\n *\n * Zync's api is:\n * - `syncState` object for reactive access to internal state i.e.: const syncState = useStore((state) => state.syncState);\n * - `sync` object for control methods e.g.: useStore.sync.enable(true|false);\n *\n * Synced objects will have the client only field `_localId`, which provides a stable identifier for the object.\n * It is ideal for use as JSX keys.\n *\n * Synced objects are expected to have the following server fields:\n *\n * - id: The unique identifier from the server.\n * - updated_at: A timestamp indicating when the object was last updated.\n * This field is used to determine if the object needs to be re-fetched from the server.\n * It must be set at the server (e.g. via sql trigger or in the api code).\n * Ensure the server sets a timestamp with millisecond precision, not microsecond like PostgreSQL's timestampz,\n * as Javascript's Date object is based on milliseconds, and this will be used during sync.\n * Although the client can set this locally, it is only to give a good UX, as it won't be sent\n * to the server and will be overwritten on the client during sync. The client clock is never\n * used to check for changes as it can't be guaranteed to be in sync with the server clock. Instead any item\n * that is added, updated or deleted locally is added to a queue.\n * - deleted: A boolean flag indicating whether the object has been deleted. This use of soft deletes or similar\n * is how all clients are told about deletions during sync.\n *\n * Design principles:\n *\n * - Always pull (list) first each sync cycle to enable future conflict resolution. Currently last-write-wins, although any queued client changes\n * for an item will prevent it being overwritten during a pull, even if the server has a newer version.\n * - Then push queued changes in order (Create -> Update -> Remove).\n * - Queue coalescing: (Create + Update*) => single Create (merged changes); (Create + Remove) => drop both; (Update + Update) => merge; (Update + Remove) => Remove.\n *\n *\n * @param stateCreator - The function to create the initial state.\n * @param persistOptions - Standard Zustand options for persisting the store.\n * @param syncApi - Remote API functions for syncing state. Use the same key name as the state key.\n * e.g. if your state key is called `fish`, the syncApi should be `fish: { list, add, update, remove }`\n * If you don't provide a key for a state field, it won't be synced, but will be persisted as expected.\n * @param syncOptions - Syncing options (Optional).\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_ON_UPDATE_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 },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly ascynchronously 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 syncIntervalId: any;\n\n async function syncOnce() {\n const state: SyncState = get();\n if (!state.syncState.enabled || state.syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let syncError: 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);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[zync] pull:error stateKey=${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const snapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen early\n snapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of snapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n queueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n syncError = syncError ?? (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: syncError,\n },\n }));\n\n if (get().syncState.pendingChanges.length > 0 && !syncError) {\n // If there are pending changes and no sync error, we can sync again\n await syncOnce();\n }\n }\n\n async function startFirstLoad() {\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 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: nextLocalId(),\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 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\n function queueToSync(action: any, stateKey: string, ...localIds: string[]) {\n set((state: any) => {\n const pendingChanges: any[] = state.syncState.pendingChanges || [];\n\n for (const localId of localIds) {\n const item = state[stateKey].find((i: any) => i._localId === localId);\n if (!item) {\n logger.error(`[zync] queueToSync:no-local-item localId=${localId}`);\n continue;\n }\n\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n if (queueItem) {\n queueItem.version += 1;\n\n if (queueItem.action === SyncAction.CreateOrUpdate && action === SyncAction.Remove && item.id) {\n queueItem.action = SyncAction.Remove;\n queueItem.id = item.id;\n }\n logger.debug(`[zync] queueToSync:adjusted v=${queueItem.version} action=${action} localId=${localId}`);\n } else {\n pendingChanges.push({ action, stateKey, localId, id: item.id, version: 1 });\n logger.debug(`[zync] queueToSync:added action=${action} localId=${localId}`);\n }\n }\n\n return {\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n },\n };\n });\n syncOnce();\n }\n\n function setAndSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => ({ ...partial(state) }));\n } else {\n set(partial);\n }\n syncOnce();\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n enabled,\n },\n }));\n\n enableSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function enableSyncTimer(enabled: boolean) {\n clearInterval(syncIntervalId);\n syncIntervalId = undefined;\n if (enabled) {\n syncIntervalId = setInterval(syncOnce, syncInterval);\n syncOnce();\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 enableSyncTimer(true);\n } else {\n logger.debug('[zync] sync:pause-in-background');\n enableSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad,\n };\n\n const userState = stateCreator(setAndSync, get, queueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n enabled: false,\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, PendingChange } from './types';\n\nexport function nextLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.CreateOrUpdate:\n return 1;\n case SyncAction.Remove:\n return 2;\n }\n}\n\nexport function omitSyncFields(item: any, fields: readonly string[]) {\n const result = { ...item };\n for (const k of fields) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const q: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = q.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 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","import type { ApiFunctions, PendingChange, SyncedRecord } from './types';\nimport { SyncAction } from './index';\nimport { nextLocalId } from './helpers';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: any) {\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 set((state: any) => {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items by 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 flicker\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 const pending = localItem && pendingChanges.some((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (localItem && !pending) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[zync] pull:merge stateKey=${stateKey} id=${remote.id}`);\n } else if (!localItem) {\n // Add remote item (no local or pending collisions)\n nextItems = [...nextItems, { ...remote, _localId: nextLocalId() }];\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 lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { removeFromPendingChanges, omitSyncFields, samePendingVersion } from './helpers';\nimport { SyncAction } from './index';\nimport type { ApiFunctions } from './types';\n\nconst SYNC_FIELDS = ['id', '_localId', 'updated_at', 'deleted'] as const;\n\nexport async function pushOne(\n set: any,\n get: any,\n change: any,\n api: ApiFunctions,\n logger: any,\n queueToSync: any,\n missingStrategy: string,\n onMissingRemoteRecordDuringUpdate?: any,\n onAfterRemoteAdd?: any,\n) {\n logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version } = change;\n\n switch (action) {\n case SyncAction.Remove:\n await api.remove(id);\n logger.debug(`[zync] push:remove:success ${stateKey} ${localId} ${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.CreateOrUpdate: {\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:create-or-update:no-local-item`, {\n stateKey,\n localId,\n });\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n const omittedItem = omitSyncFields(item, SYNC_FIELDS);\n if (item.id) {\n // Update\n const changed = await api.update(item.id, omittedItem);\n if (changed) {\n logger.debug('[zync] push:update:success', {\n stateKey,\n localId,\n id: item.id,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n return;\n } else {\n logger.warn('[zync] push:update:missing-remote', {\n stateKey,\n localId,\n id: item.id,\n });\n\n switch (missingStrategy) {\n case 'deleteLocalRecord':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n break;\n\n case 'insertNewRemoteRecord': {\n omittedItem._localId = crypto.randomUUID();\n omittedItem.updated_at = new Date().toISOString();\n\n // replace old with new copy without id so it becomes a Create\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? omittedItem : i)),\n }));\n\n queueToSync(SyncAction.CreateOrUpdate, stateKey, omittedItem._localId);\n break;\n }\n }\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, omittedItem, omittedItem._localId);\n }\n return;\n }\n\n // Create\n const result = await api.add(omittedItem);\n if (result) {\n logger.debug('[zync] push:create:success', {\n stateKey,\n localId,\n id: result.id,\n });\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 if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, queueToSync, stateKey, {\n ...item,\n ...result,\n });\n } else {\n logger.warn('[zync] push:create:no-result', {\n stateKey,\n localId,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\n }\n }\n}\n","import type { IDBPDatabase } from 'idb';\n\nexport function createIndexedDBStorage(options: { dbName: string; storeName: string }) {\n const dbName = options.dbName;\n const storeName = options.storeName;\n\n // dbPromise is created lazily by initDB() to avoid pulling `idb` into bundles\n let dbPromise: Promise<IDBPDatabase<any>> | null = null;\n\n async function initDB(): Promise<IDBPDatabase<any>> {\n if (dbPromise) return dbPromise;\n try {\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, 1, {\n upgrade(db: IDBPDatabase<any>) {\n if (!db.objectStoreNames.contains(storeName)) {\n db.createObjectStore(storeName);\n }\n },\n });\n return dbPromise;\n } catch (_e) {\n throw new Error('Missing optional dependency \"idb\". Install it to use IndexedDB storage: npm install idb');\n }\n }\n\n async function ensureStore(): Promise<void> {\n const db = await initDB();\n if (db.objectStoreNames.contains(storeName)) return;\n const nextVersion = (db.version || 0) + 1;\n try {\n db.close();\n } catch (_e) {\n // ignore\n }\n const idb = await import(/* webpackChunkName: \"idb\" */ 'idb');\n dbPromise = idb.openDB(dbName, nextVersion, {\n upgrade(upg: IDBPDatabase<any>) {\n if (!upg.objectStoreNames.contains(storeName)) upg.createObjectStore(storeName);\n },\n });\n await dbPromise;\n }\n\n async function withRetry<T>(fn: (db: IDBPDatabase<any>) => Promise<T>): Promise<T> {\n try {\n const db = await initDB();\n return await fn(db);\n } catch (err: any) {\n const msg = String(err && err.message ? err.message : err);\n if (err && (err.name === 'NotFoundError' || /objectStore/i.test(msg))) {\n await ensureStore();\n const db2 = await initDB();\n return await fn(db2);\n }\n throw err;\n }\n }\n\n return {\n getItem: async (name: string): Promise<string | null> => {\n return withRetry(async (db) => {\n let v = await db.get(storeName, name);\n v = v ?? null; // Zustand expects null for missing keys\n return v;\n });\n },\n setItem: async (name: string, value: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.put(storeName, value, name);\n });\n },\n removeItem: async (name: string): Promise<void> => {\n return withRetry(async (db) => {\n await db.delete(storeName, name);\n });\n },\n };\n}\n"],"mappings":"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","names":["target","SyncAction","state"]}
|
package/dist/index.js
CHANGED
|
@@ -66,7 +66,7 @@ function findApi(stateKey, syncApi) {
|
|
|
66
66
|
async function pull(set, get, stateKey, api, logger) {
|
|
67
67
|
const lastPulled = get().syncState.lastPulled || {};
|
|
68
68
|
const lastPulledAt = new Date(lastPulled[stateKey] || /* @__PURE__ */ new Date(0));
|
|
69
|
-
logger.debug(`[
|
|
69
|
+
logger.debug(`[zync] pull:start stateKey=${stateKey} since=${lastPulledAt.toISOString()}`);
|
|
70
70
|
const serverData = await api.list(lastPulledAt);
|
|
71
71
|
if (!serverData?.length) return;
|
|
72
72
|
let newest = lastPulledAt;
|
|
@@ -80,14 +80,14 @@ async function pull(set, get, stateKey, api, logger) {
|
|
|
80
80
|
const remoteUpdated = new Date(remote.updated_at);
|
|
81
81
|
if (remoteUpdated > newest) newest = remoteUpdated;
|
|
82
82
|
if (pendingRemovalById.has(remote.id)) {
|
|
83
|
-
logger.debug(`[
|
|
83
|
+
logger.debug(`[zync] pull:skip-pending-remove stateKey=${stateKey} id=${remote.id}`);
|
|
84
84
|
continue;
|
|
85
85
|
}
|
|
86
86
|
const localItem = localById.get(remote.id);
|
|
87
87
|
if (remote.deleted) {
|
|
88
88
|
if (localItem) {
|
|
89
89
|
nextItems = nextItems.filter((i) => i.id !== remote.id);
|
|
90
|
-
logger.debug(`[
|
|
90
|
+
logger.debug(`[zync] pull:remove stateKey=${stateKey} id=${remote.id}`);
|
|
91
91
|
}
|
|
92
92
|
continue;
|
|
93
93
|
}
|
|
@@ -99,10 +99,10 @@ async function pull(set, get, stateKey, api, logger) {
|
|
|
99
99
|
_localId: localItem._localId
|
|
100
100
|
};
|
|
101
101
|
nextItems = nextItems.map((i) => i._localId === localItem._localId ? merged : i);
|
|
102
|
-
logger.debug(`[
|
|
102
|
+
logger.debug(`[zync] pull:merge stateKey=${stateKey} id=${remote.id}`);
|
|
103
103
|
} else if (!localItem) {
|
|
104
104
|
nextItems = [...nextItems, { ...remote, _localId: nextLocalId() }];
|
|
105
|
-
logger.debug(`[
|
|
105
|
+
logger.debug(`[zync] pull:add stateKey=${stateKey} id=${remote.id}`);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
return {
|
|
@@ -121,12 +121,12 @@ async function pull(set, get, stateKey, api, logger) {
|
|
|
121
121
|
// src/push.ts
|
|
122
122
|
var SYNC_FIELDS = ["id", "_localId", "updated_at", "deleted"];
|
|
123
123
|
async function pushOne(set, get, change, api, logger, queueToSync, missingStrategy, onMissingRemoteRecordDuringUpdate, onAfterRemoteAdd) {
|
|
124
|
-
logger.debug(`[
|
|
124
|
+
logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);
|
|
125
125
|
const { action, stateKey, localId, id, version } = change;
|
|
126
126
|
switch (action) {
|
|
127
127
|
case "remove" /* Remove */:
|
|
128
128
|
await api.remove(id);
|
|
129
|
-
logger.debug(`[
|
|
129
|
+
logger.debug(`[zync] push:remove:success ${stateKey} ${localId} ${id}`);
|
|
130
130
|
removeFromPendingChanges(set, localId, stateKey);
|
|
131
131
|
break;
|
|
132
132
|
case "createOrUpdate" /* CreateOrUpdate */: {
|
|
@@ -134,7 +134,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
134
134
|
const items = state[stateKey] || [];
|
|
135
135
|
const item = items.find((i) => i._localId === localId);
|
|
136
136
|
if (!item) {
|
|
137
|
-
logger.warn(`[
|
|
137
|
+
logger.warn(`[zync] push:create-or-update:no-local-item`, {
|
|
138
138
|
stateKey,
|
|
139
139
|
localId
|
|
140
140
|
});
|
|
@@ -145,7 +145,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
145
145
|
if (item.id) {
|
|
146
146
|
const changed = await api.update(item.id, omittedItem);
|
|
147
147
|
if (changed) {
|
|
148
|
-
logger.debug("[
|
|
148
|
+
logger.debug("[zync] push:update:success", {
|
|
149
149
|
stateKey,
|
|
150
150
|
localId,
|
|
151
151
|
id: item.id
|
|
@@ -155,7 +155,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
155
155
|
}
|
|
156
156
|
return;
|
|
157
157
|
} else {
|
|
158
|
-
logger.warn("[
|
|
158
|
+
logger.warn("[zync] push:update:missing-remote", {
|
|
159
159
|
stateKey,
|
|
160
160
|
localId,
|
|
161
161
|
id: item.id
|
|
@@ -183,7 +183,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
183
183
|
}
|
|
184
184
|
const result = await api.add(omittedItem);
|
|
185
185
|
if (result) {
|
|
186
|
-
logger.debug("[
|
|
186
|
+
logger.debug("[zync] push:create:success", {
|
|
187
187
|
stateKey,
|
|
188
188
|
localId,
|
|
189
189
|
id: result.id
|
|
@@ -199,7 +199,7 @@ async function pushOne(set, get, change, api, logger, queueToSync, missingStrate
|
|
|
199
199
|
...result
|
|
200
200
|
});
|
|
201
201
|
} else {
|
|
202
|
-
logger.warn("[
|
|
202
|
+
logger.warn("[zync] push:create:no-result", {
|
|
203
203
|
stateKey,
|
|
204
204
|
localId
|
|
205
205
|
});
|
|
@@ -317,13 +317,13 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
317
317
|
const wrappedPersistOptions = {
|
|
318
318
|
...persistOptions,
|
|
319
319
|
onRehydrateStorage: () => {
|
|
320
|
-
logger.debug("[
|
|
320
|
+
logger.debug("[zync] rehydration:start");
|
|
321
321
|
return (state, error) => {
|
|
322
322
|
if (error) {
|
|
323
|
-
logger.error("[
|
|
323
|
+
logger.error("[zync] rehydration:failed", error);
|
|
324
324
|
} else {
|
|
325
325
|
baseOnRehydrate?.(state, error);
|
|
326
|
-
logger.debug("[
|
|
326
|
+
logger.debug("[zync] rehydration:complete", state);
|
|
327
327
|
}
|
|
328
328
|
};
|
|
329
329
|
},
|
|
@@ -369,7 +369,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
369
369
|
await pull(set, get, stateKey, api, logger);
|
|
370
370
|
} catch (err) {
|
|
371
371
|
syncError = syncError ?? err;
|
|
372
|
-
logger.error(`[
|
|
372
|
+
logger.error(`[zync] pull:error stateKey=${stateKey}`, err);
|
|
373
373
|
}
|
|
374
374
|
}
|
|
375
375
|
const snapshot = [...get().syncState.pendingChanges || []];
|
|
@@ -390,7 +390,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
390
390
|
);
|
|
391
391
|
} catch (err) {
|
|
392
392
|
syncError = syncError ?? err;
|
|
393
|
-
logger.error(`[
|
|
393
|
+
logger.error(`[zync] push:error change=${change}`, err);
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
set((state2) => ({
|
|
@@ -408,7 +408,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
408
408
|
let syncError;
|
|
409
409
|
for (const stateKey of Object.keys(syncApi)) {
|
|
410
410
|
try {
|
|
411
|
-
logger.info(`[
|
|
411
|
+
logger.info(`[zync] firstLoad:start stateKey=${stateKey}`);
|
|
412
412
|
const api = findApi(stateKey, syncApi);
|
|
413
413
|
let lastId;
|
|
414
414
|
while (true) {
|
|
@@ -452,10 +452,10 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
452
452
|
});
|
|
453
453
|
lastId = batch[batch.length - 1].id;
|
|
454
454
|
}
|
|
455
|
-
logger.info(`[
|
|
455
|
+
logger.info(`[zync] firstLoad:done stateKey=${stateKey}`);
|
|
456
456
|
} catch (err) {
|
|
457
457
|
syncError = syncError ?? err;
|
|
458
|
-
logger.error(`[
|
|
458
|
+
logger.error(`[zync] firstLoad:error stateKey=${stateKey}`, err);
|
|
459
459
|
}
|
|
460
460
|
}
|
|
461
461
|
set((state) => ({
|
|
@@ -472,10 +472,7 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
472
472
|
for (const localId of localIds) {
|
|
473
473
|
const item = state[stateKey].find((i) => i._localId === localId);
|
|
474
474
|
if (!item) {
|
|
475
|
-
logger.error(
|
|
476
|
-
stateKey,
|
|
477
|
-
localId
|
|
478
|
-
});
|
|
475
|
+
logger.error(`[zync] queueToSync:no-local-item localId=${localId}`);
|
|
479
476
|
continue;
|
|
480
477
|
}
|
|
481
478
|
const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);
|
|
@@ -485,10 +482,10 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
485
482
|
queueItem.action = "remove" /* Remove */;
|
|
486
483
|
queueItem.id = item.id;
|
|
487
484
|
}
|
|
488
|
-
logger.debug(`[
|
|
485
|
+
logger.debug(`[zync] queueToSync:adjusted v=${queueItem.version} action=${action} localId=${localId}`);
|
|
489
486
|
} else {
|
|
490
487
|
pendingChanges.push({ action, stateKey, localId, id: item.id, version: 1 });
|
|
491
|
-
logger.debug(`[
|
|
488
|
+
logger.debug(`[zync] queueToSync:added action=${action} localId=${localId}`);
|
|
492
489
|
}
|
|
493
490
|
}
|
|
494
491
|
return {
|
|
@@ -535,10 +532,10 @@ function persistWithSync(stateCreator, persistOptions, syncApi, syncOptions = {}
|
|
|
535
532
|
}
|
|
536
533
|
function onVisibilityChange() {
|
|
537
534
|
if (document.visibilityState === "visible") {
|
|
538
|
-
logger.debug("[
|
|
535
|
+
logger.debug("[zync] sync:start-in-foreground");
|
|
539
536
|
enableSyncTimer(true);
|
|
540
537
|
} else {
|
|
541
|
-
logger.debug("[
|
|
538
|
+
logger.debug("[zync] sync:pause-in-background");
|
|
542
539
|
enableSyncTimer(false);
|
|
543
540
|
}
|
|
544
541
|
}
|
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/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, nextLocalId } from './helpers';\nimport type {\n ApiFunctions,\n MissingRemoteRecordDuringUpdateStrategy,\n SyncOptions,\n SyncState,\n SyncedStateCreator,\n PendingChange,\n UseStoreWithSync,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\n\nexport { createIndexedDBStorage } from './indexedDBStorage';\nexport { nextLocalId } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n CreateOrUpdate = 'createOrUpdate',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 5000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_ON_UPDATE_STRATEGY: MissingRemoteRecordDuringUpdateStrategy = 'ignore';\n\n/**\n * Zync creates a standard persisted Zustand store with optional background sync (e.g. via RESTful, GraphQL, etc.).\n * It provides a `queueToSync()` method to enqueue changes for syncing, which are processed on an interval.\n *\n * This is a drop-in replacement for Zustand's `persist()` middleware that wires in background sync. It's usage mirrors\n * `persist(stateCreator, options)` with optional syncing per state key.\n *\n * Can be used with any storage that Zustand Persist supports. Options include localStorage if its syncronous access doesn't\n * cause blocking issues like UI freezes, or IndexedDB with its asynchronous access for improved performance.\n *\n * When using IndexedDB the whole store is saved under one key, which means indexes cannot be used to accelerate querying. However, if this\n * 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\n * provide the syntax for high performance queries.\n *\n * Zync's api is:\n * - `syncState` object for reactive access to internal state i.e.: const syncState = useStore((state) => state.syncState);\n * - `sync` object for control methods e.g.: useStore.sync.enable(true|false);\n *\n * Synced objects will have the client only field `_localId`, which provides a stable identifier for the object.\n * It is ideal for use as JSX keys.\n *\n * Synced objects are expected to have the following server fields:\n *\n * - id: The unique identifier from the server.\n * - updated_at: A timestamp indicating when the object was last updated.\n * This field is used to determine if the object needs to be re-fetched from the server.\n * It must be set at the server (e.g. via sql trigger or in the api code).\n * Ensure the server sets a timestamp with millisecond precision, not microsecond like PostgreSQL's timestampz,\n * as Javascript's Date object is based on milliseconds, and this will be used during sync.\n * Although the client can set this locally, it is only to give a good UX, as it won't be sent\n * to the server and will be overwritten on the client during sync. The client clock is never\n * used to check for changes as it can't be guaranteed to be in sync with the server clock. Instead any item\n * that is added, updated or deleted locally is added to a queue.\n * - deleted: A boolean flag indicating whether the object has been deleted. This use of soft deletes or similar\n * is how all clients are told about deletions during sync.\n *\n * Design principles:\n *\n * - Always pull (list) first each sync cycle to enable future conflict resolution. Currently last-write-wins, although any queued client changes\n * for an item will prevent it being overwritten during a pull, even if the server has a newer version.\n * - Then push queued changes in order (Create -> Update -> Remove).\n * - Queue coalescing: (Create + Update*) => single Create (merged changes); (Create + Remove) => drop both; (Update + Update) => merge; (Update + Remove) => Remove.\n *\n *\n * @param stateCreator - The function to create the initial state.\n * @param persistOptions - Standard Zustand options for persisting the store.\n * @param syncApi - Remote API functions for syncing state. Use the same key name as the state key.\n * e.g. if your state key is called `fish`, the syncApi should be `fish: { list, add, update, remove }`\n * If you don't provide a key for a state field, it won't be synced, but will be persisted as expected.\n * @param syncOptions - Syncing options (Optional).\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_ON_UPDATE_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 started');\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 },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly ascynchronously 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 syncIntervalId: any;\n\n async function syncOnce() {\n const state: SyncState = get();\n if (!state.syncState.enabled || state.syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let syncError: 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);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[Zync] Pull error for stateKey: ${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const snapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen early\n snapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of snapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n queueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[Zync] Push error for change: ${change}`, err);\n }\n }\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'idle',\n error: syncError,\n },\n }));\n\n if (get().syncState.pendingChanges.length > 0 && !syncError) {\n // If there are pending changes and no sync error, we can sync again\n await syncOnce();\n }\n }\n\n async function startFirstLoad() {\n let syncError: Error | undefined;\n\n for (const stateKey of Object.keys(syncApi)) {\n try {\n logger.info(`[Zync] firstLoad:start for 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 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: nextLocalId(),\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 lastId = batch[batch.length - 1].id;\n }\n\n logger.info(`[Zync] firstLoad:done for stateKey: ${stateKey}`);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[Zync] First load pull error for 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\n function queueToSync(action: any, stateKey: string, ...localIds: string[]) {\n set((state: any) => {\n const pendingChanges: any[] = state.syncState.pendingChanges || [];\n\n for (const localId of localIds) {\n const item = state[stateKey].find((i: any) => i._localId === localId);\n if (!item) {\n logger.error('[Zync] queueToSync:no-local-item', {\n stateKey,\n localId,\n });\n continue;\n }\n\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n if (queueItem) {\n queueItem.version += 1;\n\n if (queueItem.action === SyncAction.CreateOrUpdate && action === SyncAction.Remove && item.id) {\n queueItem.action = SyncAction.Remove;\n queueItem.id = item.id;\n }\n logger.debug(`[Zync] queueToSync:adjusted ${queueItem.version} ${action} ${item.id} ${stateKey} ${localId}`);\n } else {\n pendingChanges.push({ action, stateKey, localId, id: item.id, version: 1 });\n logger.debug(`[Zync] queueToSync:added ${action} ${item.id} ${stateKey} ${localId}`);\n }\n }\n\n return {\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n },\n };\n });\n syncOnce();\n }\n\n function setAndSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => ({ ...partial(state) }));\n } else {\n set(partial);\n }\n syncOnce();\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n enabled,\n },\n }));\n\n enableSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function enableSyncTimer(enabled: boolean) {\n clearInterval(syncIntervalId);\n syncIntervalId = undefined;\n if (enabled) {\n syncIntervalId = setInterval(syncOnce, syncInterval);\n syncOnce();\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 started now app is in foreground');\n enableSyncTimer(true);\n } else {\n logger.debug('[Zync] Sync paused now app is in background');\n enableSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad,\n };\n\n const userState = stateCreator(setAndSync, get, queueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n enabled: false,\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, PendingChange } from './types';\n\nexport function nextLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.CreateOrUpdate:\n return 1;\n case SyncAction.Remove:\n return 2;\n }\n}\n\nexport function omitSyncFields(item: any, fields: readonly string[]) {\n const result = { ...item };\n for (const k of fields) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const q: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = q.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 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","import type { ApiFunctions, PendingChange, SyncedRecord } from './types';\nimport { SyncAction } from './index';\nimport { nextLocalId } from './helpers';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: any) {\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 set((state: any) => {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items by 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 flicker\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 const pending = localItem && pendingChanges.some((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (localItem && !pending) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[Zync] pull:merge stateKey=${stateKey} id=${remote.id}`);\n } else if (!localItem) {\n // Add remote item (no local or pending collisions)\n nextItems = [...nextItems, { ...remote, _localId: nextLocalId() }];\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 lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { removeFromPendingChanges, omitSyncFields, samePendingVersion } from './helpers';\nimport { SyncAction } from './index';\nimport type { ApiFunctions } from './types';\n\nconst SYNC_FIELDS = ['id', '_localId', 'updated_at', 'deleted'] as const;\n\nexport async function pushOne(\n set: any,\n get: any,\n change: any,\n api: ApiFunctions,\n logger: any,\n queueToSync: any,\n missingStrategy: string,\n onMissingRemoteRecordDuringUpdate?: any,\n onAfterRemoteAdd?: any,\n) {\n logger.debug(`[Zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version } = change;\n\n switch (action) {\n case SyncAction.Remove:\n await api.remove(id);\n logger.debug(`[Zync] push:remove:success ${stateKey} ${localId} ${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.CreateOrUpdate: {\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:${action}:no-local-item`, {\n stateKey,\n localId,\n });\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n const omittedItem = omitSyncFields(item, SYNC_FIELDS);\n if (item.id) {\n // Update\n const changed = await api.update(item.id, omittedItem);\n if (changed) {\n logger.debug('[Zync] push:update:success', {\n stateKey,\n localId,\n id: item.id,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n return;\n } else {\n logger.warn('[Zync] push:update:missingRemote', {\n stateKey,\n localId,\n id: item.id,\n });\n\n switch (missingStrategy) {\n case 'deleteLocalRecord':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n break;\n\n case 'insertNewRemoteRecord': {\n omittedItem._localId = crypto.randomUUID();\n omittedItem.updated_at = new Date().toISOString();\n\n // replace old with new copy without id so it becomes a Create\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? omittedItem : i)),\n }));\n\n queueToSync(SyncAction.CreateOrUpdate, stateKey, omittedItem._localId);\n break;\n }\n }\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, omittedItem, omittedItem._localId);\n }\n return;\n }\n\n // Create\n const result = await api.add(omittedItem);\n if (result) {\n logger.debug('[Zync] push:create:success', {\n stateKey,\n localId,\n id: result.id,\n });\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 if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, queueToSync, stateKey, {\n ...item,\n ...result,\n });\n } else {\n logger.warn('[Zync] push:create:no-result', {\n stateKey,\n localId,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\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","state"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/logger.ts","../src/helpers.ts","../src/pull.ts","../src/push.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, nextLocalId } from './helpers';\nimport type {\n ApiFunctions,\n MissingRemoteRecordDuringUpdateStrategy,\n SyncOptions,\n SyncState,\n SyncedStateCreator,\n PendingChange,\n UseStoreWithSync,\n} from './types';\nimport { pull } from './pull';\nimport { pushOne } from './push';\n\nexport { createIndexedDBStorage } from './indexedDBStorage';\nexport { nextLocalId } from './helpers';\nexport type { ApiFunctions, UseStoreWithSync, SyncState } from './types';\n\nexport enum SyncAction {\n CreateOrUpdate = 'createOrUpdate',\n Remove = 'remove',\n}\n\nconst DEFAULT_SYNC_INTERVAL_MILLIS = 5000;\nconst DEFAULT_LOGGER: Logger = console;\nconst DEFAULT_MIN_LOG_LEVEL: LogLevel = 'debug';\nconst DEFAULT_MISSING_REMOTE_RECORD_ON_UPDATE_STRATEGY: MissingRemoteRecordDuringUpdateStrategy = 'ignore';\n\n/**\n * Zync creates a standard persisted Zustand store with optional background sync (e.g. via RESTful, GraphQL, etc.).\n * It provides a `queueToSync()` method to enqueue changes for syncing, which are processed on an interval.\n *\n * This is a drop-in replacement for Zustand's `persist()` middleware that wires in background sync. It's usage mirrors\n * `persist(stateCreator, options)` with optional syncing per state key.\n *\n * Can be used with any storage that Zustand Persist supports. Options include localStorage if its syncronous access doesn't\n * cause blocking issues like UI freezes, or IndexedDB with its asynchronous access for improved performance.\n *\n * When using IndexedDB the whole store is saved under one key, which means indexes cannot be used to accelerate querying. However, if this\n * 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\n * provide the syntax for high performance queries.\n *\n * Zync's api is:\n * - `syncState` object for reactive access to internal state i.e.: const syncState = useStore((state) => state.syncState);\n * - `sync` object for control methods e.g.: useStore.sync.enable(true|false);\n *\n * Synced objects will have the client only field `_localId`, which provides a stable identifier for the object.\n * It is ideal for use as JSX keys.\n *\n * Synced objects are expected to have the following server fields:\n *\n * - id: The unique identifier from the server.\n * - updated_at: A timestamp indicating when the object was last updated.\n * This field is used to determine if the object needs to be re-fetched from the server.\n * It must be set at the server (e.g. via sql trigger or in the api code).\n * Ensure the server sets a timestamp with millisecond precision, not microsecond like PostgreSQL's timestampz,\n * as Javascript's Date object is based on milliseconds, and this will be used during sync.\n * Although the client can set this locally, it is only to give a good UX, as it won't be sent\n * to the server and will be overwritten on the client during sync. The client clock is never\n * used to check for changes as it can't be guaranteed to be in sync with the server clock. Instead any item\n * that is added, updated or deleted locally is added to a queue.\n * - deleted: A boolean flag indicating whether the object has been deleted. This use of soft deletes or similar\n * is how all clients are told about deletions during sync.\n *\n * Design principles:\n *\n * - Always pull (list) first each sync cycle to enable future conflict resolution. Currently last-write-wins, although any queued client changes\n * for an item will prevent it being overwritten during a pull, even if the server has a newer version.\n * - Then push queued changes in order (Create -> Update -> Remove).\n * - Queue coalescing: (Create + Update*) => single Create (merged changes); (Create + Remove) => drop both; (Update + Update) => merge; (Update + Remove) => Remove.\n *\n *\n * @param stateCreator - The function to create the initial state.\n * @param persistOptions - Standard Zustand options for persisting the store.\n * @param syncApi - Remote API functions for syncing state. Use the same key name as the state key.\n * e.g. if your state key is called `fish`, the syncApi should be `fish: { list, add, update, remove }`\n * If you don't provide a key for a state field, it won't be synced, but will be persisted as expected.\n * @param syncOptions - Syncing options (Optional).\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_ON_UPDATE_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 },\n };\n },\n merge: (persisted: any, current: any) => {\n // Here after hydration.\n // `persisted` is state from storage that's just loaded (possibly ascynchronously 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 syncIntervalId: any;\n\n async function syncOnce() {\n const state: SyncState = get();\n if (!state.syncState.enabled || state.syncState.status !== 'idle') return;\n\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n status: 'syncing',\n },\n }));\n\n let syncError: 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);\n } catch (err) {\n syncError = syncError ?? (err as Error);\n logger.error(`[zync] pull:error stateKey=${stateKey}`, err);\n }\n }\n\n // 2) PUSH queued changes\n const snapshot: PendingChange[] = [...(get().syncState.pendingChanges || [])];\n\n // Deterministic ordering: Create -> Update -> Remove so dependencies (e.g. id assignment) happen early\n snapshot.sort((a, b) => orderFor(a.action) - orderFor(b.action));\n\n for (const change of snapshot) {\n try {\n const api = findApi(change.stateKey, syncApi);\n await pushOne(\n set,\n get,\n change,\n api,\n logger,\n queueToSync,\n missingStrategy,\n syncOptions.onMissingRemoteRecordDuringUpdate,\n syncOptions.onAfterRemoteAdd,\n );\n } catch (err) {\n syncError = syncError ?? (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: syncError,\n },\n }));\n\n if (get().syncState.pendingChanges.length > 0 && !syncError) {\n // If there are pending changes and no sync error, we can sync again\n await syncOnce();\n }\n }\n\n async function startFirstLoad() {\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 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: nextLocalId(),\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 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\n function queueToSync(action: any, stateKey: string, ...localIds: string[]) {\n set((state: any) => {\n const pendingChanges: any[] = state.syncState.pendingChanges || [];\n\n for (const localId of localIds) {\n const item = state[stateKey].find((i: any) => i._localId === localId);\n if (!item) {\n logger.error(`[zync] queueToSync:no-local-item localId=${localId}`);\n continue;\n }\n\n const queueItem = pendingChanges.find((p) => p.localId === localId && p.stateKey === stateKey);\n if (queueItem) {\n queueItem.version += 1;\n\n if (queueItem.action === SyncAction.CreateOrUpdate && action === SyncAction.Remove && item.id) {\n queueItem.action = SyncAction.Remove;\n queueItem.id = item.id;\n }\n logger.debug(`[zync] queueToSync:adjusted v=${queueItem.version} action=${action} localId=${localId}`);\n } else {\n pendingChanges.push({ action, stateKey, localId, id: item.id, version: 1 });\n logger.debug(`[zync] queueToSync:added action=${action} localId=${localId}`);\n }\n }\n\n return {\n syncState: {\n ...(state.syncState || {}),\n pendingChanges,\n },\n };\n });\n syncOnce();\n }\n\n function setAndSync(partial: any) {\n if (typeof partial === 'function') {\n set((state: any) => ({ ...partial(state) }));\n } else {\n set(partial);\n }\n syncOnce();\n }\n\n function enable(enabled: boolean) {\n set((state: any) => ({\n syncState: {\n ...(state.syncState || {}),\n enabled,\n },\n }));\n\n enableSyncTimer(enabled);\n addVisibilityChangeListener(enabled);\n }\n\n function enableSyncTimer(enabled: boolean) {\n clearInterval(syncIntervalId);\n syncIntervalId = undefined;\n if (enabled) {\n syncIntervalId = setInterval(syncOnce, syncInterval);\n syncOnce();\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 enableSyncTimer(true);\n } else {\n logger.debug('[zync] sync:pause-in-background');\n enableSyncTimer(false);\n }\n }\n\n // public useStore.sync api, similar in principle to useStore.persist\n storeApi.sync = {\n enable,\n startFirstLoad,\n };\n\n const userState = stateCreator(setAndSync, get, queueToSync) as TStore;\n\n return {\n ...userState,\n syncState: {\n // set defaults\n status: 'hydrating',\n error: undefined,\n enabled: false,\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, PendingChange } from './types';\n\nexport function nextLocalId(): string {\n return crypto.randomUUID();\n}\n\nexport function orderFor(a: SyncAction): number {\n switch (a) {\n case SyncAction.CreateOrUpdate:\n return 1;\n case SyncAction.Remove:\n return 2;\n }\n}\n\nexport function omitSyncFields(item: any, fields: readonly string[]) {\n const result = { ...item };\n for (const k of fields) delete result[k];\n return result;\n}\n\nexport function samePendingVersion(get: any, stateKey: string, localId: string, version: number): boolean {\n const q: PendingChange[] = get().syncState.pendingChanges || [];\n const curChange = q.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 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","import type { ApiFunctions, PendingChange, SyncedRecord } from './types';\nimport { SyncAction } from './index';\nimport { nextLocalId } from './helpers';\n\nexport async function pull(set: any, get: any, stateKey: string, api: ApiFunctions, logger: any) {\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 set((state: any) => {\n const pendingChanges: PendingChange[] = state.syncState.pendingChanges || [];\n const localItems: any[] = state[stateKey] || [];\n let nextItems = [...localItems];\n const localById = new Map<any, any>(localItems.filter((l) => l.id).map((l) => [l.id, l]));\n // prevent resurrecting deleted items by 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 flicker\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 const pending = localItem && pendingChanges.some((p: any) => p.stateKey === stateKey && p.localId === localItem._localId);\n if (localItem && !pending) {\n const merged = {\n ...localItem,\n ...remote,\n _localId: localItem._localId,\n };\n nextItems = nextItems.map((i: any) => (i._localId === localItem._localId ? merged : i));\n logger.debug(`[zync] pull:merge stateKey=${stateKey} id=${remote.id}`);\n } else if (!localItem) {\n // Add remote item (no local or pending collisions)\n nextItems = [...nextItems, { ...remote, _localId: nextLocalId() }];\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 lastPulled: {\n ...(state.syncState.lastPulled || {}),\n [stateKey]: newest.toISOString(),\n },\n },\n };\n });\n}\n","import { removeFromPendingChanges, omitSyncFields, samePendingVersion } from './helpers';\nimport { SyncAction } from './index';\nimport type { ApiFunctions } from './types';\n\nconst SYNC_FIELDS = ['id', '_localId', 'updated_at', 'deleted'] as const;\n\nexport async function pushOne(\n set: any,\n get: any,\n change: any,\n api: ApiFunctions,\n logger: any,\n queueToSync: any,\n missingStrategy: string,\n onMissingRemoteRecordDuringUpdate?: any,\n onAfterRemoteAdd?: any,\n) {\n logger.debug(`[zync] push:attempt action=${change.action} stateKey=${change.stateKey} localId=${change.localId}`);\n\n const { action, stateKey, localId, id, version } = change;\n\n switch (action) {\n case SyncAction.Remove:\n await api.remove(id);\n logger.debug(`[zync] push:remove:success ${stateKey} ${localId} ${id}`);\n removeFromPendingChanges(set, localId, stateKey);\n break;\n\n case SyncAction.CreateOrUpdate: {\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:create-or-update:no-local-item`, {\n stateKey,\n localId,\n });\n removeFromPendingChanges(set, localId, stateKey);\n return;\n }\n\n const omittedItem = omitSyncFields(item, SYNC_FIELDS);\n if (item.id) {\n // Update\n const changed = await api.update(item.id, omittedItem);\n if (changed) {\n logger.debug('[zync] push:update:success', {\n stateKey,\n localId,\n id: item.id,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n return;\n } else {\n logger.warn('[zync] push:update:missing-remote', {\n stateKey,\n localId,\n id: item.id,\n });\n\n switch (missingStrategy) {\n case 'deleteLocalRecord':\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).filter((i: any) => i._localId !== localId),\n }));\n break;\n\n case 'insertNewRemoteRecord': {\n omittedItem._localId = crypto.randomUUID();\n omittedItem.updated_at = new Date().toISOString();\n\n // replace old with new copy without id so it becomes a Create\n set((s: any) => ({\n [stateKey]: (s[stateKey] || []).map((i: any) => (i._localId === localId ? omittedItem : i)),\n }));\n\n queueToSync(SyncAction.CreateOrUpdate, stateKey, omittedItem._localId);\n break;\n }\n }\n removeFromPendingChanges(set, localId, stateKey);\n // Call hook so userland can alert the user etc.\n onMissingRemoteRecordDuringUpdate?.(missingStrategy, omittedItem, omittedItem._localId);\n }\n return;\n }\n\n // Create\n const result = await api.add(omittedItem);\n if (result) {\n logger.debug('[zync] push:create:success', {\n stateKey,\n localId,\n id: result.id,\n });\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 if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n // Call hook so userland can perform any cascading adjustments\n onAfterRemoteAdd?.(set, get, queueToSync, stateKey, {\n ...item,\n ...result,\n });\n } else {\n logger.warn('[zync] push:create:no-result', {\n stateKey,\n localId,\n });\n if (samePendingVersion(get, stateKey, localId, version)) {\n removeFromPendingChanges(set, localId, stateKey);\n }\n }\n break;\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","state"]}
|