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 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`