cry-synced-db-client 0.1.145 → 0.1.146
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 +30 -0
- package/dist/index.js +20 -0
- package/dist/src/db/SyncedDb.d.ts +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -108,6 +108,36 @@ Signature is identical. No other callback changes.
|
|
|
108
108
|
- Noop when offline or on writeOnly collections.
|
|
109
109
|
- Ignored on `find` / `findOne` (use `referToServer` there).
|
|
110
110
|
|
|
111
|
+
## 0.1.146 (2026-04-25)
|
|
112
|
+
|
|
113
|
+
### Fix: INITIAL SYNC re-fetched whole dataset on every reload (cursor race)
|
|
114
|
+
|
|
115
|
+
`syncMetaCache` was populated lazily inside `loadCollectionToInMem` — one
|
|
116
|
+
collection at a time, only after that collection's records finished hydrating
|
|
117
|
+
into in-memory state. When `ConnectionManager.tryGoOnline` fired
|
|
118
|
+
`sync("INITIAL SYNC")` on WS connect (or `setSyncOnlyTheseCollections`
|
|
119
|
+
expanded the allowed set under a fresh login), the sync engine read
|
|
120
|
+
`syncMetaCache.get(collection)?.lastSyncTs` for each collection — and for
|
|
121
|
+
collections whose hydration hadn't completed yet, it found nothing and fell
|
|
122
|
+
back to `timestamp: 0` (`SyncEngine.ts:94`). The server then returned every
|
|
123
|
+
matching row since epoch, not a delta.
|
|
124
|
+
|
|
125
|
+
In one observed reproducer with 62 sync'd collections, 58 of them arrived at
|
|
126
|
+
the server with `timestamp: 0` and the server replied with 60 131 rows on a
|
|
127
|
+
session that already had 58 745 rows cached locally — i.e. ~full re-fetch
|
|
128
|
+
every reload, regardless of how recently the client had synced.
|
|
129
|
+
|
|
130
|
+
`init()` now eagerly preloads sync cursors for every registered collection
|
|
131
|
+
into `syncMetaCache` before `connectionManager.startTimers()` runs, via a
|
|
132
|
+
parallel fan-out of `getSyncMeta` reads. Cursor cache availability is
|
|
133
|
+
decoupled from in-mem record hydration: a sync triggered the moment WS comes
|
|
134
|
+
up reads a fully populated cache, regardless of where hydration is. One Dexie
|
|
135
|
+
point-lookup per registered collection — cheap.
|
|
136
|
+
|
|
137
|
+
The lazy populate inside `loadCollectionToInMem` is retained as a defensive
|
|
138
|
+
overwrite for collections registered after init (e.g. via dynamic
|
|
139
|
+
`addCollection`).
|
|
140
|
+
|
|
111
141
|
## 0.1.145 (2026-04-25)
|
|
112
142
|
|
|
113
143
|
### Fix: `onSyncProgress` back-track during initial sync
|
package/dist/index.js
CHANGED
|
@@ -3801,6 +3801,7 @@ var _SyncedDb = class _SyncedDb {
|
|
|
3801
3801
|
}
|
|
3802
3802
|
}
|
|
3803
3803
|
await this.pendingChanges.recoverPendingWrites();
|
|
3804
|
+
await this.preloadAllSyncMetas();
|
|
3804
3805
|
const allowedColls = [...this.collections.keys()].filter((n) => this.isSyncAllowed(n));
|
|
3805
3806
|
await this.loadCollectionsToInMem(allowedColls, "init");
|
|
3806
3807
|
this.leaderElection.init();
|
|
@@ -5019,6 +5020,25 @@ var _SyncedDb = class _SyncedDb {
|
|
|
5019
5020
|
}
|
|
5020
5021
|
return allItems.length;
|
|
5021
5022
|
}
|
|
5023
|
+
/**
|
|
5024
|
+
* Bulk-read sync cursors for every registered collection into syncMetaCache.
|
|
5025
|
+
* Called once during init() before sync can fire. Decouples cursor cache
|
|
5026
|
+
* availability from in-mem record hydration, eliminating the race where a
|
|
5027
|
+
* sync triggered by ConnectionManager.tryGoOnline (or by setSyncOnlyTheseCollections
|
|
5028
|
+
* expanding the allowed set) reads an unpopulated cache and sends timestamp:0
|
|
5029
|
+
* for un-hydrated collections.
|
|
5030
|
+
*/
|
|
5031
|
+
async preloadAllSyncMetas() {
|
|
5032
|
+
const names = [...this.collections.keys()];
|
|
5033
|
+
const results = await Promise.all(
|
|
5034
|
+
names.map(
|
|
5035
|
+
(name) => this.dexieDb.getSyncMeta(name).then((meta) => ({ name, meta }))
|
|
5036
|
+
)
|
|
5037
|
+
);
|
|
5038
|
+
for (const { name, meta } of results) {
|
|
5039
|
+
if (meta) this.syncMetaCache.set(name, meta);
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5022
5042
|
assertCollection(name) {
|
|
5023
5043
|
if (!this.collections.has(name)) {
|
|
5024
5044
|
throw new Error(`SyncedDb: Collection "${(name == null ? void 0 : name.toString()) || "?"}" not configured`);
|
|
@@ -291,6 +291,15 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
291
291
|
*/
|
|
292
292
|
private loadCollectionsToInMem;
|
|
293
293
|
private loadCollectionToInMem;
|
|
294
|
+
/**
|
|
295
|
+
* Bulk-read sync cursors for every registered collection into syncMetaCache.
|
|
296
|
+
* Called once during init() before sync can fire. Decouples cursor cache
|
|
297
|
+
* availability from in-mem record hydration, eliminating the race where a
|
|
298
|
+
* sync triggered by ConnectionManager.tryGoOnline (or by setSyncOnlyTheseCollections
|
|
299
|
+
* expanding the allowed set) reads an unpopulated cache and sends timestamp:0
|
|
300
|
+
* for un-hydrated collections.
|
|
301
|
+
*/
|
|
302
|
+
private preloadAllSyncMetas;
|
|
294
303
|
private assertCollection;
|
|
295
304
|
private static readonly STRINGIFIED_FALSY;
|
|
296
305
|
/** Stringify an Id parameter (ObjectId → hex string). */
|