cry-synced-db-client 0.1.200 → 0.1.201

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
@@ -1,5 +1,25 @@
1
1
  # Versions
2
2
 
3
+ ## 0.1.201 (2026-06-14)
4
+
5
+ ### `onBeforeDirtyClearAll` callback zdaj prejme `DirtyChange[]` (ne samo `DirtyMeta[]`)
6
+
7
+ `BeforeDirtyClearAllInfo.items` je nadgrajen iz `DirtyMeta[]` v `DirtyChange[]` —
8
+ callback dobi poleg metapodatkov (`id`, `collection`, `stuckSince`, ...) tudi
9
+ `changes` payload z dejanskimi field-level spremembami.
10
+
11
+ **Affected paths:**
12
+ - `clearDirty()` clear-all path: fetcha `DirtyChange[]` prek `getDirtyChangesBatch`
13
+ - `discardStuckItems()`: zamenja `getDirty` + `find` (ki je vračal
14
+ `Partial<LocalDbEntity>[]`) z `getDirtyChangesBatch` za pravilne `DirtyChange[]`
15
+
16
+ **Type change (backward-compatible):**
17
+ - `items` v `BeforeDirtyClearAllInfo`: `DirtyMeta[]` → `DirtyChange[]`
18
+ - `DirtyChange` je superset of `DirtyMeta`; vsa obstoječa polja (`id`,
19
+ `collection`, `createdAt`, `updatedAt`, `stuckSince`, ...) so še vedno na voljo
20
+
21
+ 876 pass, 0 fail.
22
+
3
23
  ## 0.1.200 (2026-06-14)
4
24
 
5
25
  ### `preprocessDirtyItem` skip/throw zdaj incrementa `numUploadAttempts`
package/dist/index.js CHANGED
@@ -4902,7 +4902,8 @@ var _SyncedDb = class _SyncedDb {
4902
4902
  this.evictOnWake = (_g = config.evictOnWake) != null ? _g : false;
4903
4903
  for (const col of config.collections) {
4904
4904
  this.collections.set(col.name, col);
4905
- if (!col.writeOnly) this.preloadStatusMap.set(col.name, { state: "pending", itemCount: 0 });
4905
+ if (!col.writeOnly)
4906
+ this.preloadStatusMap.set(col.name, { state: "pending", itemCount: 0 });
4906
4907
  }
4907
4908
  this.inMemManager = new InMemManager({
4908
4909
  inMemDb: this.inMemDb,
@@ -4916,14 +4917,20 @@ var _SyncedDb = class _SyncedDb {
4916
4917
  onBecameLeader: () => {
4917
4918
  if (this.initialized && !this.connectionManager.isOnline() && !this.connectionManager.isForcedOffline()) {
4918
4919
  this.connectionManager.tryGoOnline().catch((err) => {
4919
- networkError(`[SyncedDb] tryGoOnline on becameLeader failed: ${err}`, err);
4920
+ networkError(
4921
+ `[SyncedDb] tryGoOnline on becameLeader failed: ${err}`,
4922
+ err
4923
+ );
4920
4924
  });
4921
4925
  }
4922
4926
  if (config.onBecameLeader) {
4923
4927
  try {
4924
4928
  config.onBecameLeader();
4925
4929
  } catch (err) {
4926
- console.error(`[SyncedDb] onBecameLeader callback failed: ${err}`, err);
4930
+ console.error(
4931
+ `[SyncedDb] onBecameLeader callback failed: ${err}`,
4932
+ err
4933
+ );
4927
4934
  }
4928
4935
  }
4929
4936
  },
@@ -5026,7 +5033,9 @@ var _SyncedDb = class _SyncedDb {
5026
5033
  restInterface: this.restInterface,
5027
5034
  preprocessDirtyItem: config.preprocessDirtyItem,
5028
5035
  callbacks: {
5029
- onSyncStart: config.onSyncStart ? (info) => config.onSyncStart(__spreadProps(__spreadValues({}, info), { initialSync: !this._lastFullSyncDate })) : void 0,
5036
+ onSyncStart: config.onSyncStart ? (info) => config.onSyncStart(__spreadProps(__spreadValues({}, info), {
5037
+ initialSync: !this._lastFullSyncDate
5038
+ })) : void 0,
5030
5039
  onSyncEnd: config.onSyncEnd,
5031
5040
  onSyncProgress: config.onSyncProgress,
5032
5041
  onServerSyncStart: config.onServerSyncStart,
@@ -5168,7 +5177,12 @@ var _SyncedDb = class _SyncedDb {
5168
5177
  "[SyncedDb] callWorker: no serverUpdateNotifier or notifier does not support callWorker"
5169
5178
  );
5170
5179
  }
5171
- return fn.call(this.serverUpdateNotifier, service, payload, options);
5180
+ return fn.call(
5181
+ this.serverUpdateNotifier,
5182
+ service,
5183
+ payload,
5184
+ options
5185
+ );
5172
5186
  }
5173
5187
  /**
5174
5188
  * Register a collection for sync at runtime. See `I_SyncedDb.addCollectionToSync`.
@@ -5205,7 +5219,10 @@ var _SyncedDb = class _SyncedDb {
5205
5219
  if (existing && !existing.temporaryConfig) continue;
5206
5220
  this.collections.set(spec.name, spec);
5207
5221
  if (!spec.writeOnly && !this.preloadStatusMap.has(spec.name)) {
5208
- this.preloadStatusMap.set(spec.name, { state: "pending", itemCount: 0 });
5222
+ this.preloadStatusMap.set(spec.name, {
5223
+ state: "pending",
5224
+ itemCount: 0
5225
+ });
5209
5226
  }
5210
5227
  if (this.syncOnlyCollections) {
5211
5228
  this.syncOnlyCollections.add(spec.name);
@@ -5267,7 +5284,11 @@ var _SyncedDb = class _SyncedDb {
5267
5284
  if (!data || data.length === 0) continue;
5268
5285
  const source = plan.wasFirstTime ? "initial" : "incremental";
5269
5286
  try {
5270
- await this.syncEngine.processCollectionServerData(plan.spec.name, data, { source });
5287
+ await this.syncEngine.processCollectionServerData(
5288
+ plan.spec.name,
5289
+ data,
5290
+ { source }
5291
+ );
5271
5292
  } catch (err) {
5272
5293
  console.error(
5273
5294
  `[SyncedDb] addCollectionsToSync: processCollectionServerData failed for "${plan.spec.name}":`,
@@ -5306,7 +5327,9 @@ var _SyncedDb = class _SyncedDb {
5306
5327
  if (!spec.writeOnly && this.connectionManager.canSync()) {
5307
5328
  const rawQuery = (_a = spec.syncConfig) == null ? void 0 : _a.query;
5308
5329
  const query = typeof rawQuery === "function" ? rawQuery() : rawQuery;
5309
- await this.syncCollectionForFind(spec.name, query, { returnDeleted: true });
5330
+ await this.syncCollectionForFind(spec.name, query, {
5331
+ returnDeleted: true
5332
+ });
5310
5333
  }
5311
5334
  }
5312
5335
  /**
@@ -5332,7 +5355,10 @@ var _SyncedDb = class _SyncedDb {
5332
5355
  }
5333
5356
  this.emitPreloadStatusChange();
5334
5357
  if (newlyAllowed.length > 0) {
5335
- await this.loadCollectionsToInMem(newlyAllowed, "setSyncOnlyTheseCollections");
5358
+ await this.loadCollectionsToInMem(
5359
+ newlyAllowed,
5360
+ "setSyncOnlyTheseCollections"
5361
+ );
5336
5362
  }
5337
5363
  if (newlyAllowed.length > 0 && this.connectionManager.canSync()) {
5338
5364
  this.sync("setSyncOnlyTheseCollections").catch(() => {
@@ -5374,12 +5400,17 @@ var _SyncedDb = class _SyncedDb {
5374
5400
  try {
5375
5401
  this.onDatabaseCreated();
5376
5402
  } catch (err) {
5377
- console.error(`[SyncedDb] onDatabaseCreated callback failed: ${err}`, err);
5403
+ console.error(
5404
+ `[SyncedDb] onDatabaseCreated callback failed: ${err}`,
5405
+ err
5406
+ );
5378
5407
  }
5379
5408
  }
5380
5409
  await this.pendingChanges.recoverPendingWrites();
5381
5410
  await this.preloadAllSyncMetas();
5382
- const allowedColls = [...this.collections.keys()].filter((n) => this.isSyncAllowed(n));
5411
+ const allowedColls = [...this.collections.keys()].filter(
5412
+ (n) => this.isSyncAllowed(n)
5413
+ );
5383
5414
  await this.loadCollectionsToInMem(allowedColls, "init");
5384
5415
  this.leaderElection.init();
5385
5416
  this.crossTabSync.init();
@@ -5410,7 +5441,9 @@ var _SyncedDb = class _SyncedDb {
5410
5441
  console.log(`[SyncedDb] SyncedDb: ebus-proxy connected to ${ep}`);
5411
5442
  } catch (err) {
5412
5443
  const ep = (_d = this.serverUpdateNotifier.endpoint) != null ? _d : "unknown";
5413
- console.warn(`[SyncedDb] SyncedDb: ebus-proxy connection to ${ep} failed`);
5444
+ console.warn(
5445
+ `[SyncedDb] SyncedDb: ebus-proxy connection to ${ep} failed`
5446
+ );
5414
5447
  this.connectionManager.reportInfrastructureError(
5415
5448
  "WEBSOCKET_CONNECTION_FAILED",
5416
5449
  `WebSocket connection to ${ep} failed during initialization`,
@@ -5432,10 +5465,16 @@ var _SyncedDb = class _SyncedDb {
5432
5465
  this.visibilityFlushHandler = () => {
5433
5466
  if (document.visibilityState !== "hidden") return;
5434
5467
  this.flushToServer("visibility-hidden").catch((err) => {
5435
- console.warn(`[SyncedDb] flushToServer on visibility-hidden failed: ${err == null ? void 0 : err.message}`, err);
5468
+ console.warn(
5469
+ `[SyncedDb] flushToServer on visibility-hidden failed: ${err == null ? void 0 : err.message}`,
5470
+ err
5471
+ );
5436
5472
  });
5437
5473
  };
5438
- document.addEventListener("visibilitychange", this.visibilityFlushHandler);
5474
+ document.addEventListener(
5475
+ "visibilitychange",
5476
+ this.visibilityFlushHandler
5477
+ );
5439
5478
  }
5440
5479
  this._checkForceFullResyncThreshold("init");
5441
5480
  this._startForceResyncCheckTimer();
@@ -5548,7 +5587,10 @@ var _SyncedDb = class _SyncedDb {
5548
5587
  });
5549
5588
  if (this.connectionManager.canSync()) {
5550
5589
  this.sync(`force-full-resync:${reason}`).catch((err) => {
5551
- console.error(`[SyncedDb] force full resync sync() failed: ${err}`, err);
5590
+ console.error(
5591
+ `[SyncedDb] force full resync sync() failed: ${err}`,
5592
+ err
5593
+ );
5552
5594
  });
5553
5595
  }
5554
5596
  }
@@ -5622,7 +5664,10 @@ var _SyncedDb = class _SyncedDb {
5622
5664
  this.beforeUnloadHandler = void 0;
5623
5665
  }
5624
5666
  if (typeof document !== "undefined" && this.visibilityFlushHandler) {
5625
- document.removeEventListener("visibilitychange", this.visibilityFlushHandler);
5667
+ document.removeEventListener(
5668
+ "visibilitychange",
5669
+ this.visibilityFlushHandler
5670
+ );
5626
5671
  this.visibilityFlushHandler = void 0;
5627
5672
  }
5628
5673
  this.syncMetaCache.clear();
@@ -5702,7 +5747,12 @@ var _SyncedDb = class _SyncedDb {
5702
5747
  if (serverItem) {
5703
5748
  await this.dexieDb.saveMany(collection, [serverItem]);
5704
5749
  if (!serverItem._deleted && !serverItem._archived) {
5705
- this.inMemManager.writeBatch(collection, [serverItem], "upsert", { source: "incremental" });
5750
+ this.inMemManager.writeBatch(
5751
+ collection,
5752
+ [serverItem],
5753
+ "upsert",
5754
+ { source: "incremental" }
5755
+ );
5706
5756
  }
5707
5757
  }
5708
5758
  } catch (e) {
@@ -5775,9 +5825,16 @@ var _SyncedDb = class _SyncedDb {
5775
5825
  );
5776
5826
  if (serverItems && serverItems.length > 0) {
5777
5827
  await this.dexieDb.saveMany(collection, serverItems);
5778
- const toInMem = serverItems.filter((s) => !s._deleted && !s._archived);
5828
+ const toInMem = serverItems.filter(
5829
+ (s) => !s._deleted && !s._archived
5830
+ );
5779
5831
  if (toInMem.length > 0) {
5780
- this.inMemManager.writeBatch(collection, toInMem, "upsert", { source: "incremental" });
5832
+ this.inMemManager.writeBatch(
5833
+ collection,
5834
+ toInMem,
5835
+ "upsert",
5836
+ { source: "incremental" }
5837
+ );
5781
5838
  }
5782
5839
  }
5783
5840
  } catch (e) {
@@ -5818,11 +5875,16 @@ var _SyncedDb = class _SyncedDb {
5818
5875
  filtered.push(item);
5819
5876
  }
5820
5877
  if (filtered.length === 0) {
5821
- if ((opts == null ? void 0 : opts.referToServer) && this.isOnline()) this.referToServerSync(collection, query);
5878
+ if ((opts == null ? void 0 : opts.referToServer) && this.isOnline())
5879
+ this.referToServerSync(collection, query);
5822
5880
  return null;
5823
5881
  }
5824
- const sorted = applyQueryOpts(filtered, { sort: opts.sort, project: opts == null ? void 0 : opts.project });
5825
- if ((opts == null ? void 0 : opts.referToServer) && this.isOnline()) this.referToServerSync(collection, query);
5882
+ const sorted = applyQueryOpts(filtered, {
5883
+ sort: opts.sort,
5884
+ project: opts == null ? void 0 : opts.project
5885
+ });
5886
+ if ((opts == null ? void 0 : opts.referToServer) && this.isOnline())
5887
+ this.referToServerSync(collection, query);
5826
5888
  return (_b = sorted[0]) != null ? _b : null;
5827
5889
  } else {
5828
5890
  let result = null;
@@ -5836,7 +5898,8 @@ var _SyncedDb = class _SyncedDb {
5836
5898
  if (result && (opts == null ? void 0 : opts.project)) {
5837
5899
  result = projectItem(result, opts.project);
5838
5900
  }
5839
- if ((opts == null ? void 0 : opts.referToServer) && this.isOnline()) this.referToServerSync(collection, query);
5901
+ if ((opts == null ? void 0 : opts.referToServer) && this.isOnline())
5902
+ this.referToServerSync(collection, query);
5840
5903
  return result;
5841
5904
  }
5842
5905
  }
@@ -5889,15 +5952,24 @@ var _SyncedDb = class _SyncedDb {
5889
5952
  const timestamp = (meta == null ? void 0 : meta.lastSyncTs) || 0;
5890
5953
  try {
5891
5954
  const serverData = await this.connectionManager.withRestTimeout(
5892
- this.restInterface.findNewer(collection, timestamp, query, {
5893
- returnDeleted: (opts == null ? void 0 : opts.returnDeleted) || false,
5894
- returnArchived: (opts == null ? void 0 : opts.returnArchived) || false
5895
- }),
5955
+ this.restInterface.findNewer(
5956
+ collection,
5957
+ timestamp,
5958
+ query,
5959
+ {
5960
+ returnDeleted: (opts == null ? void 0 : opts.returnDeleted) || false,
5961
+ returnArchived: (opts == null ? void 0 : opts.returnArchived) || false
5962
+ }
5963
+ ),
5896
5964
  "syncCollectionForFind"
5897
5965
  );
5898
5966
  if (serverData.length > 0) {
5899
5967
  const source = timestamp === 0 ? "initial" : "incremental";
5900
- await this.syncEngine.processCollectionServerData(collection, serverData, { source });
5968
+ await this.syncEngine.processCollectionServerData(
5969
+ collection,
5970
+ serverData,
5971
+ { source }
5972
+ );
5901
5973
  }
5902
5974
  } catch (e) {
5903
5975
  }
@@ -5911,11 +5983,17 @@ var _SyncedDb = class _SyncedDb {
5911
5983
  */
5912
5984
  referToServerSync(collection, query) {
5913
5985
  this.connectionManager.withRestTimeout(
5914
- this.restInterface.findNewer(collection, 0, query, { returnDeleted: true }),
5986
+ this.restInterface.findNewer(collection, 0, query, {
5987
+ returnDeleted: true
5988
+ }),
5915
5989
  "referToServer"
5916
5990
  ).then(async (serverData) => {
5917
5991
  if (serverData.length > 0) {
5918
- await this.syncEngine.processCollectionServerData(collection, serverData, { source: "refresh" });
5992
+ await this.syncEngine.processCollectionServerData(
5993
+ collection,
5994
+ serverData,
5995
+ { source: "refresh" }
5996
+ );
5919
5997
  }
5920
5998
  }).catch((err) => {
5921
5999
  networkError(`[SyncedDb] referToServer failed for ${collection}:`, err);
@@ -5943,7 +6021,10 @@ var _SyncedDb = class _SyncedDb {
5943
6021
  for (const item of serverItems) {
5944
6022
  serverById.set(String(item._id), item);
5945
6023
  }
5946
- const localItems = await this.dexieDb.getByIds(collection, ids);
6024
+ const localItems = await this.dexieDb.getByIds(
6025
+ collection,
6026
+ ids
6027
+ );
5947
6028
  const dirtyMap = await this.dexieDb.getDirtyChangesBatch(collection, ids);
5948
6029
  const toSaveDexie = [];
5949
6030
  const toSaveInMem = [];
@@ -5971,10 +6052,16 @@ var _SyncedDb = class _SyncedDb {
5971
6052
  await this.dexieDb.saveMany(collection, toSaveDexie);
5972
6053
  }
5973
6054
  if (toSaveInMem.length > 0) {
5974
- this.inMemManager.writeBatch(collection, toSaveInMem, "upsert", { source: "incremental" });
6055
+ this.inMemManager.writeBatch(collection, toSaveInMem, "upsert", {
6056
+ source: "incremental"
6057
+ });
5975
6058
  }
5976
6059
  if (dirtyServerItems.length > 0) {
5977
- await this.syncEngine.processCollectionServerData(collection, dirtyServerItems, { source: "incremental" });
6060
+ await this.syncEngine.processCollectionServerData(
6061
+ collection,
6062
+ dirtyServerItems,
6063
+ { source: "incremental" }
6064
+ );
5978
6065
  }
5979
6066
  }
5980
6067
  /**
@@ -6002,9 +6089,16 @@ var _SyncedDb = class _SyncedDb {
6002
6089
  "refreshInBackground"
6003
6090
  ).then(async (serverItems) => {
6004
6091
  if (!serverItems || serverItems.length === 0) return;
6005
- await this.syncEngine.processCollectionServerData(collection, serverItems, { source: "incremental" });
6092
+ await this.syncEngine.processCollectionServerData(
6093
+ collection,
6094
+ serverItems,
6095
+ { source: "incremental" }
6096
+ );
6006
6097
  }).catch((err) => {
6007
- networkError(`[SyncedDb] refreshInBackground failed for ${collection}:`, err);
6098
+ networkError(
6099
+ `[SyncedDb] refreshInBackground failed for ${collection}:`,
6100
+ err
6101
+ );
6008
6102
  });
6009
6103
  }
6010
6104
  async ensureItemsAreLoaded(collection, ids, withDeleted) {
@@ -6032,7 +6126,9 @@ var _SyncedDb = class _SyncedDb {
6032
6126
  await this.dexieDb.saveMany(collection, toSaveDexie);
6033
6127
  }
6034
6128
  if (toSaveInMem.length > 0) {
6035
- this.inMemManager.writeBatch(collection, toSaveInMem, "upsert", { source: "incremental" });
6129
+ this.inMemManager.writeBatch(collection, toSaveInMem, "upsert", {
6130
+ source: "incremental"
6131
+ });
6036
6132
  }
6037
6133
  }
6038
6134
  // ==================== Write Operations ====================
@@ -6077,12 +6173,10 @@ var _SyncedDb = class _SyncedDb {
6077
6173
  }
6078
6174
  const fullChanges = __spreadProps(__spreadValues({}, update), { _lastUpdaterId: this.updaterId });
6079
6175
  const diff = computeObjDiff(existing, fullChanges);
6080
- await this.dexieDb.addDirtyChange(
6081
- collection,
6082
- id,
6083
- diff,
6084
- { _ts: existing == null ? void 0 : existing._ts, _rev: existing == null ? void 0 : existing._rev }
6085
- );
6176
+ await this.dexieDb.addDirtyChange(collection, id, diff, {
6177
+ _ts: existing == null ? void 0 : existing._ts,
6178
+ _rev: existing == null ? void 0 : existing._rev
6179
+ });
6086
6180
  const isWriteOnly = (_b = this.collections.get(collection)) == null ? void 0 : _b.writeOnly;
6087
6181
  const currentMem = isWriteOnly ? null : this.inMemDb.getById(collection, id);
6088
6182
  const merged = applyObjDiff(
@@ -6091,9 +6185,17 @@ var _SyncedDb = class _SyncedDb {
6091
6185
  id,
6092
6186
  collection
6093
6187
  );
6094
- this.pendingChanges.schedule(collection, id, merged, 0, "save");
6188
+ this.pendingChanges.schedule(
6189
+ collection,
6190
+ id,
6191
+ merged,
6192
+ 0,
6193
+ "save"
6194
+ );
6095
6195
  if (!isWriteOnly && !(existing == null ? void 0 : existing._deleted) && !(existing == null ? void 0 : existing._archived)) {
6096
- this.inMemManager.writeBatch(collection, [merged], "upsert", { source: "incremental" });
6196
+ this.inMemManager.writeBatch(collection, [merged], "upsert", {
6197
+ source: "incremental"
6198
+ });
6097
6199
  }
6098
6200
  return merged;
6099
6201
  }
@@ -6138,7 +6240,12 @@ var _SyncedDb = class _SyncedDb {
6138
6240
  for (const path of unsetPaths) deleteByPath(newData, path);
6139
6241
  this.pendingChanges.schedule(collection, id, newData, 0, "insert");
6140
6242
  if (!((_a = this.collections.get(collection)) == null ? void 0 : _a.writeOnly)) {
6141
- this.inMemManager.writeBatch(collection, [newData], "upsert", { source: "incremental" });
6243
+ this.inMemManager.writeBatch(
6244
+ collection,
6245
+ [newData],
6246
+ "upsert",
6247
+ { source: "incremental" }
6248
+ );
6142
6249
  }
6143
6250
  return newData;
6144
6251
  }
@@ -6162,7 +6269,12 @@ var _SyncedDb = class _SyncedDb {
6162
6269
  };
6163
6270
  this.pendingChanges.schedule(collection, id, deleteUpdate, 0, "deleteOne");
6164
6271
  if (!((_a = this.collections.get(collection)) == null ? void 0 : _a.writeOnly)) {
6165
- this.inMemManager.writeBatch(collection, [{ _id: id }], "delete", { source: "incremental" });
6272
+ this.inMemManager.writeBatch(
6273
+ collection,
6274
+ [{ _id: id }],
6275
+ "delete",
6276
+ { source: "incremental" }
6277
+ );
6166
6278
  }
6167
6279
  return existing;
6168
6280
  }
@@ -6172,7 +6284,10 @@ var _SyncedDb = class _SyncedDb {
6172
6284
  const items = await this.find(collection, query);
6173
6285
  if (items.length === 0) return 0;
6174
6286
  const ids = items.map((item) => item._id);
6175
- const existingItems = await this.dexieDb.getByIds(collection, ids);
6287
+ const existingItems = await this.dexieDb.getByIds(
6288
+ collection,
6289
+ ids
6290
+ );
6176
6291
  const now = /* @__PURE__ */ new Date();
6177
6292
  const dirtyChangesBatch = [];
6178
6293
  const idsToDelete = [];
@@ -6189,7 +6304,13 @@ var _SyncedDb = class _SyncedDb {
6189
6304
  _deleted: now,
6190
6305
  _lastUpdaterId: this.updaterId
6191
6306
  };
6192
- this.pendingChanges.schedule(collection, item._id, deleteUpdate, 0, "deleteMany");
6307
+ this.pendingChanges.schedule(
6308
+ collection,
6309
+ item._id,
6310
+ deleteUpdate,
6311
+ 0,
6312
+ "deleteMany"
6313
+ );
6193
6314
  idsToDelete.push(item._id);
6194
6315
  }
6195
6316
  if (dirtyChangesBatch.length > 0) {
@@ -6217,11 +6338,19 @@ var _SyncedDb = class _SyncedDb {
6217
6338
  return null;
6218
6339
  }
6219
6340
  await this.connectionManager.withRestTimeout(
6220
- this.restInterface.call("hardDeleteOne", { collection, query: { _id: id } }),
6341
+ this.restInterface.call("hardDeleteOne", {
6342
+ collection,
6343
+ query: { _id: id }
6344
+ }),
6221
6345
  "hardDeleteOne"
6222
6346
  );
6223
6347
  await this.dexieDb.deleteOne(collection, id);
6224
- this.inMemManager.writeBatch(collection, [{ _id: id }], "delete", { source: "incremental" });
6348
+ this.inMemManager.writeBatch(
6349
+ collection,
6350
+ [{ _id: id }],
6351
+ "delete",
6352
+ { source: "incremental" }
6353
+ );
6225
6354
  return existing;
6226
6355
  }
6227
6356
  async hardDelete(collection, query) {
@@ -6233,7 +6362,9 @@ var _SyncedDb = class _SyncedDb {
6233
6362
  const items = await this.find(collection, query);
6234
6363
  if (items.length === 0) return 0;
6235
6364
  const existingItems = await Promise.all(
6236
- items.map((item) => this.dexieDb.getById(collection, item._id))
6365
+ items.map(
6366
+ (item) => this.dexieDb.getById(collection, item._id)
6367
+ )
6237
6368
  );
6238
6369
  const toDelete = [];
6239
6370
  for (let i = 0; i < items.length; i++) {
@@ -6248,24 +6379,38 @@ var _SyncedDb = class _SyncedDb {
6248
6379
  const queue = [...toDelete];
6249
6380
  const results = [];
6250
6381
  await Promise.all(
6251
- Array.from({ length: Math.min(maxConcurrency, queue.length) }, async () => {
6252
- while (queue.length > 0) {
6253
- const item = queue.pop();
6254
- if (!item) break;
6255
- try {
6256
- await this.connectionManager.withRestTimeout(
6257
- this.restInterface.call("hardDeleteOne", { collection, query: { _id: item.id } }),
6258
- "hardDelete"
6259
- );
6260
- await this.dexieDb.deleteOne(collection, item.id);
6261
- this.inMemManager.writeBatch(collection, [{ _id: item.id }], "delete", { source: "incremental" });
6262
- results.push(true);
6263
- } catch (err) {
6264
- networkError(`[SyncedDb] Failed to hard delete ${String(item.id)}:`, err);
6265
- results.push(false);
6382
+ Array.from(
6383
+ { length: Math.min(maxConcurrency, queue.length) },
6384
+ async () => {
6385
+ while (queue.length > 0) {
6386
+ const item = queue.pop();
6387
+ if (!item) break;
6388
+ try {
6389
+ await this.connectionManager.withRestTimeout(
6390
+ this.restInterface.call("hardDeleteOne", {
6391
+ collection,
6392
+ query: { _id: item.id }
6393
+ }),
6394
+ "hardDelete"
6395
+ );
6396
+ await this.dexieDb.deleteOne(collection, item.id);
6397
+ this.inMemManager.writeBatch(
6398
+ collection,
6399
+ [{ _id: item.id }],
6400
+ "delete",
6401
+ { source: "incremental" }
6402
+ );
6403
+ results.push(true);
6404
+ } catch (err) {
6405
+ networkError(
6406
+ `[SyncedDb] Failed to hard delete ${String(item.id)}:`,
6407
+ err
6408
+ );
6409
+ results.push(false);
6410
+ }
6266
6411
  }
6267
6412
  }
6268
- })
6413
+ )
6269
6414
  );
6270
6415
  return results.filter(Boolean).length;
6271
6416
  }
@@ -6317,11 +6462,17 @@ var _SyncedDb = class _SyncedDb {
6317
6462
  const now = /* @__PURE__ */ new Date();
6318
6463
  if (!this._lastFullSyncDate) {
6319
6464
  this._setLastInitialSync(now).catch((err) => {
6320
- console.error(`[SyncedDb] Failed to persist lastInitialSync: ${err}`, err);
6465
+ console.error(
6466
+ `[SyncedDb] Failed to persist lastInitialSync: ${err}`,
6467
+ err
6468
+ );
6321
6469
  });
6322
6470
  }
6323
6471
  this._setLastFullSync(now).catch((err) => {
6324
- console.error(`[SyncedDb] Failed to persist lastFullSync: ${err}`, err);
6472
+ console.error(
6473
+ `[SyncedDb] Failed to persist lastFullSync: ${err}`,
6474
+ err
6475
+ );
6325
6476
  });
6326
6477
  if (consumingPendingFullResync) this._pendingFullResync = false;
6327
6478
  }
@@ -6475,10 +6626,18 @@ var _SyncedDb = class _SyncedDb {
6475
6626
  for (const [name] of this.collections) {
6476
6627
  const metas2 = await this.dexieDb.getDirtyMeta(name);
6477
6628
  if (metas2.length === 0) continue;
6629
+ const ids2 = metas2.map((m) => m.id);
6630
+ const changesMap = await this.dexieDb.getDirtyChangesBatch(name, ids2);
6631
+ const items = metas2.map(
6632
+ (m) => {
6633
+ var _a;
6634
+ return (_a = changesMap.get(m.id)) != null ? _a : __spreadProps(__spreadValues({}, m), { changes: {} });
6635
+ }
6636
+ );
6478
6637
  this.safeCallback(this.onBeforeDirtyClearAll, {
6479
6638
  reason: calledFrom != null ? calledFrom : "manual",
6480
6639
  collection: name,
6481
- items: metas2,
6640
+ items,
6482
6641
  calledFrom,
6483
6642
  timestamp: /* @__PURE__ */ new Date()
6484
6643
  });
@@ -6541,10 +6700,19 @@ var _SyncedDb = class _SyncedDb {
6541
6700
  const metas = await this.dexieDb.getDirtyMeta(collectionName);
6542
6701
  const stuck = metas.filter((m) => m.stuckSince !== void 0);
6543
6702
  if (stuck.length === 0) continue;
6703
+ const stuckIds = stuck.map((m) => m.id);
6704
+ const changesMap = await this.dexieDb.getDirtyChangesBatch(
6705
+ collectionName,
6706
+ stuckIds
6707
+ );
6708
+ const content = stuck.map((m) => {
6709
+ const entry = changesMap.get(m.id);
6710
+ return entry != null ? entry : __spreadProps(__spreadValues({}, m), { changes: {} });
6711
+ });
6544
6712
  this.safeCallback(this.onBeforeDirtyClearAll, {
6545
6713
  reason: "discard-stuck",
6546
6714
  collection: collectionName,
6547
- items: stuck,
6715
+ items: content,
6548
6716
  calledFrom,
6549
6717
  timestamp: /* @__PURE__ */ new Date()
6550
6718
  });
@@ -6590,7 +6758,9 @@ var _SyncedDb = class _SyncedDb {
6590
6758
  }
6591
6759
  async dropDatabase(force = false) {
6592
6760
  if (!force && (this.connectionManager.isForcedOffline() || !this.connectionManager.isOnline())) {
6593
- throw new Error("Cannot drop database: database is offline. Use force=true to drop anyway.");
6761
+ throw new Error(
6762
+ "Cannot drop database: database is offline. Use force=true to drop anyway."
6763
+ );
6594
6764
  }
6595
6765
  await this.pendingChanges.flushAll();
6596
6766
  const collectionNames = Array.from(this.collections.keys());
@@ -6598,7 +6768,10 @@ var _SyncedDb = class _SyncedDb {
6598
6768
  for (const collectionName of collectionNames) {
6599
6769
  const dirtyItems = await this.dexieDb.getDirty(collectionName);
6600
6770
  if (dirtyItems.length > 0) {
6601
- dirtyCollections.push({ name: collectionName, count: dirtyItems.length });
6771
+ dirtyCollections.push({
6772
+ name: collectionName,
6773
+ count: dirtyItems.length
6774
+ });
6602
6775
  }
6603
6776
  }
6604
6777
  if (dirtyCollections.length > 0) {
@@ -6876,7 +7049,11 @@ var _SyncedDb = class _SyncedDb {
6876
7049
  );
6877
7050
  serverRounds = 1;
6878
7051
  for (const [specId, items] of Object.entries(results)) {
6879
- this._applyScopeExitChunkToPlan(plan, specId, items);
7052
+ this._applyScopeExitChunkToPlan(
7053
+ plan,
7054
+ specId,
7055
+ items
7056
+ );
6880
7057
  }
6881
7058
  } catch (err) {
6882
7059
  serverFailed = true;
@@ -7179,7 +7356,8 @@ var _SyncedDb = class _SyncedDb {
7179
7356
  const config = this.collections.get(collection);
7180
7357
  if (!config) return false;
7181
7358
  if (config.writeOnly) return false;
7182
- if (this.syncOnlyCollections && !this.syncOnlyCollections.has(collection)) return false;
7359
+ if (this.syncOnlyCollections && !this.syncOnlyCollections.has(collection))
7360
+ return false;
7183
7361
  return true;
7184
7362
  }
7185
7363
  /**
@@ -7254,7 +7432,11 @@ var _SyncedDb = class _SyncedDb {
7254
7432
  var _a;
7255
7433
  try {
7256
7434
  const count = await this._hydrateCollectionFromDexie(name);
7257
- this.preloadStatusMap.set(name, { state: "hydrated", itemCount: count, hydratedAt: /* @__PURE__ */ new Date() });
7435
+ this.preloadStatusMap.set(name, {
7436
+ state: "hydrated",
7437
+ itemCount: count,
7438
+ hydratedAt: /* @__PURE__ */ new Date()
7439
+ });
7258
7440
  this.emitPreloadStatusChange();
7259
7441
  return count;
7260
7442
  } catch (err) {
@@ -7281,7 +7463,10 @@ var _SyncedDb = class _SyncedDb {
7281
7463
  let pendingCount = 0;
7282
7464
  for (const name of this.collections.keys()) {
7283
7465
  if (!this.isSyncAllowed(name)) continue;
7284
- const rec = (_a = this.preloadStatusMap.get(name)) != null ? _a : { state: "pending", itemCount: 0 };
7466
+ const rec = (_a = this.preloadStatusMap.get(name)) != null ? _a : {
7467
+ state: "pending",
7468
+ itemCount: 0
7469
+ };
7285
7470
  const everDownloaded = !!((_b = this.syncMetaCache.get(name)) == null ? void 0 : _b.lastSyncTs);
7286
7471
  const ready = rec.state === "hydrated";
7287
7472
  if (rec.state === "failed") failedCount++;
@@ -7303,22 +7488,34 @@ var _SyncedDb = class _SyncedDb {
7303
7488
  else if (readyCount === expectedCount) aggregate = "full";
7304
7489
  else if (failedCount === expectedCount) aggregate = "failed";
7305
7490
  else aggregate = "partial";
7306
- return { aggregate, collections, expectedCount, readyCount, failedCount, pendingCount };
7491
+ return {
7492
+ aggregate,
7493
+ collections,
7494
+ expectedCount,
7495
+ readyCount,
7496
+ failedCount,
7497
+ pendingCount
7498
+ };
7307
7499
  }
7308
7500
  /** Emit onPreloadStatusChange with a fresh snapshot (skips computation when no listener). */
7309
7501
  emitPreloadStatusChange() {
7310
- if (this.onPreloadStatusChange) this.safeCallback(this.onPreloadStatusChange, this.getPreloadStatus());
7502
+ if (this.onPreloadStatusChange)
7503
+ this.safeCallback(this.onPreloadStatusChange, this.getPreloadStatus());
7311
7504
  }
7312
7505
  async _hydrateCollectionFromDexie(name) {
7313
7506
  const allItems = [];
7314
- await this.dexieDb.forEachBatch(name, 2e3, async (chunk) => {
7315
- for (let i = 0; i < chunk.length; i++) {
7316
- const item = chunk[i];
7317
- if (!item._deleted && !item._archived) {
7318
- allItems.push(item);
7507
+ await this.dexieDb.forEachBatch(
7508
+ name,
7509
+ 2e3,
7510
+ async (chunk) => {
7511
+ for (let i = 0; i < chunk.length; i++) {
7512
+ const item = chunk[i];
7513
+ if (!item._deleted && !item._archived) {
7514
+ allItems.push(item);
7515
+ }
7319
7516
  }
7320
7517
  }
7321
- });
7518
+ );
7322
7519
  const dirty = await this.dexieDb.getDirty(name);
7323
7520
  if (dirty.length > 0) {
7324
7521
  const itemById = /* @__PURE__ */ new Map();
@@ -7387,7 +7584,9 @@ var _SyncedDb = class _SyncedDb {
7387
7584
  }
7388
7585
  assertCollection(name) {
7389
7586
  if (!this.collections.has(name)) {
7390
- throw new Error(`SyncedDb: Collection "${(name == null ? void 0 : name.toString()) || "?"}" not configured`);
7587
+ throw new Error(
7588
+ `SyncedDb: Collection "${(name == null ? void 0 : name.toString()) || "?"}" not configured`
7589
+ );
7391
7590
  }
7392
7591
  }
7393
7592
  /**
@@ -7517,7 +7716,8 @@ var _SyncedDb = class _SyncedDb {
7517
7716
  if (_SyncedDb.isObjectIdLike(data)) return String(data);
7518
7717
  if (typeof data !== "object") return data;
7519
7718
  if (data instanceof Date) return data;
7520
- if (Array.isArray(data)) return data.map((v) => _SyncedDb.stringifyObjectIds(v));
7719
+ if (Array.isArray(data))
7720
+ return data.map((v) => _SyncedDb.stringifyObjectIds(v));
7521
7721
  const result = {};
7522
7722
  for (const key of Object.keys(data)) {
7523
7723
  result[key] = _SyncedDb.stringifyObjectIds(data[key]);
@@ -121,8 +121,8 @@ export interface BeforeDirtyClearAllInfo {
121
121
  reason: string;
122
122
  /** Collection whose dirty entries are about to be deleted. */
123
123
  collection: string;
124
- /** Meta of every dirty entry in this collection (no `changes` payload). */
125
- items: import("./I_DexieDb").DirtyMeta[];
124
+ /** Every dirty entry in this collection includes both metadata and the `changes` payload. */
125
+ items: import("./I_DexieDb").DirtyChange[];
126
126
  /** Optional caller tag passed through `clearDirty(undefined, undefined, calledFrom)`. */
127
127
  calledFrom?: string;
128
128
  /** Timestamp when the callback fires. */
@@ -648,7 +648,7 @@ export interface SyncedDbConfig {
648
648
  * `loaded`/`total` are scoped to the phase that emitted the event.
649
649
  */
650
650
  onSyncProgress?: (info: {
651
- phase: 'dexie' | 'server';
651
+ phase: "dexie" | "server";
652
652
  collection: string;
653
653
  loaded: number;
654
654
  total: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cry-synced-db-client",
3
- "version": "0.1.200",
3
+ "version": "0.1.201",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",