cry-synced-db-client 0.1.170 → 0.1.172
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/CHANGELOG.md +96 -0
- package/dist/index.js +242 -115
- package/dist/src/db/SyncedDb.d.ts +30 -1
- package/dist/src/db/managers/LeaderElectionManager.d.ts +13 -0
- package/dist/src/db/types/managers.d.ts +4 -0
- package/dist/src/types/I_SyncedDb.d.ts +67 -0
- package/dist/src/utils/computeDiff.d.ts +9 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,102 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
### Runtime collection registration (`addCollectionToSync`, `replaceSyncCollection`)
|
|
6
|
+
|
|
7
|
+
Two methods to install / replace collection configs at runtime; both load the
|
|
8
|
+
Dexie cursor into the sync-meta cache, hydrate in-mem from Dexie, extend an
|
|
9
|
+
active `syncOnlyTheseCollections` filter, and fire a one-shot **targeted**
|
|
10
|
+
download for just that collection (`syncCollectionForFind` →
|
|
11
|
+
`processCollectionServerData`, cursor advances inline). Other collections
|
|
12
|
+
are not re-fetched.
|
|
13
|
+
|
|
14
|
+
**`addCollectionToSync(spec)` — safe, idempotent** (Promise<void>)
|
|
15
|
+
|
|
16
|
+
| Existing config | Action |
|
|
17
|
+
|---|---|
|
|
18
|
+
| permanent (`temporaryConfig !== true`) | no-op |
|
|
19
|
+
| temporary (`temporaryConfig === true`) | replaced |
|
|
20
|
+
| none | added |
|
|
21
|
+
|
|
22
|
+
**`replaceSyncCollection(spec)` — explicit re-config** (Promise<boolean>)
|
|
23
|
+
|
|
24
|
+
| Existing | New | Result |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| none | any | install, returns `true` |
|
|
27
|
+
| temporary | any | replace, returns `true` |
|
|
28
|
+
| permanent | permanent | replace, returns `true` |
|
|
29
|
+
| permanent | temporary | **blocked, returns `false`** (no-op) |
|
|
30
|
+
|
|
31
|
+
The only blocked transition is permanent → temporary (cannot downgrade an
|
|
32
|
+
established config to provisional).
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// Boot with a provisional config so the Dexie schema includes the
|
|
36
|
+
// collection but the real query/conflict-resolver is deferred.
|
|
37
|
+
new SyncedDb({ collections: [{ name: "obravnave", temporaryConfig: true }] });
|
|
38
|
+
|
|
39
|
+
// Idempotent install after login:
|
|
40
|
+
await syncedDb.addCollectionToSync({
|
|
41
|
+
name: "obravnave",
|
|
42
|
+
syncConfig: { query: () => ({ lokacija_id: currentLokacijaId }) },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Later, user switches lokacija — explicit re-config:
|
|
46
|
+
const ok = await syncedDb.replaceSyncCollection({
|
|
47
|
+
name: "obravnave",
|
|
48
|
+
syncConfig: { query: () => ({ lokacija_id: newLokacijaId }) },
|
|
49
|
+
});
|
|
50
|
+
// ok === true (replacement of permanent with permanent allowed)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `flushToServer()` + automatic flush on `visibilitychange:hidden`
|
|
54
|
+
|
|
55
|
+
`SyncedDb.flushToServer(calledFrom?)` pushes dirty data to the server
|
|
56
|
+
immediately, bypassing `debounceRestWritesMs`. Flow: cancel REST upload
|
|
57
|
+
debounce → `flushAll()` (pending Dexie writes) → `awaitRestUpload()`
|
|
58
|
+
(in-flight upload) → `uploadDirtyItems(calledFrom)`. No-op when offline,
|
|
59
|
+
forced offline, or pre-`init`.
|
|
60
|
+
|
|
61
|
+
A `visibilitychange` listener fires `flushToServer("visibility-hidden")`
|
|
62
|
+
automatically when the tab becomes `hidden`. Browser may throttle or
|
|
63
|
+
suspend a hidden tab shortly after the event, so the debounced upload
|
|
64
|
+
could otherwise never run.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Manual flush (e.g. before navigation)
|
|
68
|
+
await syncedDb.flushToServer("pre-navigate");
|
|
69
|
+
|
|
70
|
+
// Automatic: no caller action required. Listener registered in init(),
|
|
71
|
+
// cleaned up in close().
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Upload itself is **not gated on `isLeader`** — `PendingChangesManager`
|
|
75
|
+
guards only on `canSync()` — so followers also drain their dirty queue
|
|
76
|
+
on hidden. Cancelling the timer cancels only the *current* pending burst:
|
|
77
|
+
subsequent writes schedule a new timer and the auto-sync interval still
|
|
78
|
+
fires. To permanently stop uploads, call `close()` or `forceOffline(true)`.
|
|
79
|
+
|
|
80
|
+
### Leadership transition timestamps (`leaderSince` / `followerSince`)
|
|
81
|
+
|
|
82
|
+
Two new getters on `SyncedDb` (and `I_LeaderElectionManager`):
|
|
83
|
+
|
|
84
|
+
- `leaderSince(): Date | undefined` — when this tab acquired the Web Locks
|
|
85
|
+
leader lock; `undefined` while a follower
|
|
86
|
+
- `followerSince(): Date | undefined` — when this tab transitioned to
|
|
87
|
+
follower (or, for tabs that never claimed leadership, the construction
|
|
88
|
+
timestamp); `undefined` while the leader
|
|
89
|
+
|
|
90
|
+
Exactly one of the two is defined at any time after construction. Useful
|
|
91
|
+
for heartbeat payloads / debug overlays (`Date.now() - leaderSince()` =
|
|
92
|
+
"time in current leadership state").
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const isLeader = syncedDb.isLeaderTab();
|
|
96
|
+
const sinceMs = isLeader
|
|
97
|
+
? Date.now() - syncedDb.leaderSince()!.getTime()
|
|
98
|
+
: Date.now() - syncedDb.followerSince()!.getTime();
|
|
99
|
+
```
|
|
100
|
+
|
|
5
101
|
### `onServerSyncWrite` callback
|
|
6
102
|
|
|
7
103
|
Single-shot callback that fires once per `restInterface.updateCollections`
|