cry-synced-db-client 2.0.8 → 2.0.10

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/dist/index.js CHANGED
@@ -3592,6 +3592,42 @@ var SyncEngine = class {
3592
3592
  }
3593
3593
  return out;
3594
3594
  }
3595
+ /**
3596
+ * Diagnostic guard for the ACK writeback path: after pending writes have
3597
+ * been flushed and the row re-read, every plain scalar top-level field of
3598
+ * the just-uploaded delta should already be present with the uploaded
3599
+ * value. A mismatch means the re-read row still lags the server-confirmed
3600
+ * write — either a legitimate NEWER local edit landed after the upload
3601
+ * snapshot was taken (its own pending write will re-assert it), or a
3602
+ * residual race in the flush/re-fetch ordering. Either way, stamping the
3603
+ * new _rev onto such a row is exactly the mechanism that canonized stale
3604
+ * content in the 2026-07-17 vbptuj/obravnave incident, so it must be
3605
+ * observable in production logs. Comparison is deliberately limited to
3606
+ * plain scalar top-level keys: dot/bracket paths and object/array values
3607
+ * are skipped (deep-equality cost + mongo key-order make them unreliable
3608
+ * for a hot-path check).
3609
+ */
3610
+ warnIfRowLagsUploadedDelta(collection, freshItem, uploaded) {
3611
+ if (!uploaded) return;
3612
+ const mismatches = [];
3613
+ for (const key of Object.keys(uploaded)) {
3614
+ if (key === "_id" || key === "_lastUpdaterId") continue;
3615
+ if (key.includes(".") || key.includes("[")) continue;
3616
+ const up = uploaded[key];
3617
+ if (up !== null && typeof up === "object") continue;
3618
+ const local = freshItem[key];
3619
+ if (local !== up) {
3620
+ mismatches.push(
3621
+ `${key} (local=${JSON.stringify(local)}, uploaded=${JSON.stringify(up)})`
3622
+ );
3623
+ }
3624
+ }
3625
+ if (mismatches.length > 0) {
3626
+ console.warn(
3627
+ `[SyncEngine] ACK writeback: re-read row lags uploaded delta for ${collection}:${String(freshItem._id)} \u2014 ${mismatches.join(", ")}`
3628
+ );
3629
+ }
3630
+ }
3595
3631
  /**
3596
3632
  * Upload dirty items for all collections.
3597
3633
  */
@@ -3803,6 +3839,7 @@ var SyncEngine = class {
3803
3839
  }
3804
3840
  throw err;
3805
3841
  }
3842
+ await this.deps.flushAllPendingChanges();
3806
3843
  let sentCount = 0;
3807
3844
  const collectionSentCounts = {};
3808
3845
  for (const result of results) {
@@ -3914,10 +3951,16 @@ var SyncEngine = class {
3914
3951
  const inMemUpdateBatch = [];
3915
3952
  if (saveIds.length > 0) {
3916
3953
  const freshItems = await this.dexieDb.getByIds(collection, saveIds);
3954
+ const uploadedById = this.uploadedSnapshotFor(collectionBatches, collection);
3917
3955
  for (const freshItem of freshItems) {
3918
3956
  if (!freshItem) continue;
3919
3957
  const revTs = revById.get(String(freshItem._id));
3920
3958
  if (!revTs) continue;
3959
+ this.warnIfRowLagsUploadedDelta(
3960
+ collection,
3961
+ freshItem,
3962
+ uploadedById.get(String(freshItem._id))
3963
+ );
3921
3964
  freshItem._rev = revTs.rev;
3922
3965
  freshItem._ts = revTs.ts;
3923
3966
  dexieSaveBatch.push(freshItem);
@@ -5979,12 +6022,26 @@ var _SyncedDb = class _SyncedDb {
5979
6022
  * @param calledFrom Diagnostic tag threaded through to upload callbacks
5980
6023
  */
5981
6024
  async flushToServer(calledFrom) {
5982
- if (!this.initialized) return;
5983
- if (!this.connectionManager.canSync()) return;
5984
- this.pendingChanges.cancelRestUploadTimer();
5985
- await this.pendingChanges.flushAll();
5986
- await this.pendingChanges.awaitRestUpload();
5987
- await this.syncEngine.uploadDirtyItems(calledFrom);
6025
+ try {
6026
+ if (!this.initialized) return;
6027
+ if (!this.connectionManager.canSync()) return;
6028
+ this.pendingChanges.cancelRestUploadTimer();
6029
+ await this.pendingChanges.flushAll();
6030
+ await this.pendingChanges.awaitRestUpload();
6031
+ await this.syncEngine.uploadDirtyItems(calledFrom);
6032
+ } catch (err) {
6033
+ console.error(`[SyncedDb] flushToServer ${(err == null ? void 0 : err.rejectMessage) || (err == null ? void 0 : err.message) || ""}`, {
6034
+ err,
6035
+ calledFrom,
6036
+ callstack: (() => {
6037
+ try {
6038
+ return new Error().stack;
6039
+ } catch (e) {
6040
+ return void 0;
6041
+ }
6042
+ })()
6043
+ });
6044
+ }
5988
6045
  }
5989
6046
  /**
5990
6047
  * Returns when all collections were last successfully synced
@@ -54,6 +54,22 @@ export declare class SyncEngine implements I_SyncEngine {
54
54
  * server-reconciled paths from local edits made during the round-trip.
55
55
  */
56
56
  private uploadedSnapshotFor;
57
+ /**
58
+ * Diagnostic guard for the ACK writeback path: after pending writes have
59
+ * been flushed and the row re-read, every plain scalar top-level field of
60
+ * the just-uploaded delta should already be present with the uploaded
61
+ * value. A mismatch means the re-read row still lags the server-confirmed
62
+ * write — either a legitimate NEWER local edit landed after the upload
63
+ * snapshot was taken (its own pending write will re-assert it), or a
64
+ * residual race in the flush/re-fetch ordering. Either way, stamping the
65
+ * new _rev onto such a row is exactly the mechanism that canonized stale
66
+ * content in the 2026-07-17 vbptuj/obravnave incident, so it must be
67
+ * observable in production logs. Comparison is deliberately limited to
68
+ * plain scalar top-level keys: dot/bracket paths and object/array values
69
+ * are skipped (deep-equality cost + mongo key-order make them unreliable
70
+ * for a hot-path check).
71
+ */
72
+ private warnIfRowLagsUploadedDelta;
57
73
  /**
58
74
  * Upload dirty items for all collections.
59
75
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cry-synced-db-client",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",