@vue-skuilder/db 0.2.19 → 0.2.20

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
@@ -7380,22 +7380,60 @@ var init_CouchDBSyncStrategy = __esm({
7380
7380
  * before we know what the remote already has, which is the conflict-leaf
7381
7381
  * problem hydration exists to avoid. Local changes go up when startSync()
7382
7382
  * takes over.
7383
+ *
7384
+ * Into an EMPTY local DB this skips deleted documents, because a mirror that
7385
+ * never held a document does not need to be told it was removed. That
7386
+ * matters more than it sounds: scheduled reviews (`card_review_*`) are
7387
+ * created and deleted once per review completed, so the changes feed is
7388
+ * dominated by tombstones and grows without bound, while the durable record
7389
+ * lives in card history. One real account measured 385 live documents behind
7390
+ * 8,370 deletions — an unfiltered pull moved 9,520 documents and took ~20s,
7391
+ * blowing the hydration timeout on a phone; filtered, the same pull moves
7392
+ * 404 and takes ~2s, reaching a byte-identical local state.
7393
+ *
7394
+ * The filter runs server-side, so `last_seq` still reports the source's true
7395
+ * sequence. Returning it lets startSync() begin the live pull from there
7396
+ * instead of re-walking the same history in the background — without that,
7397
+ * the cost is merely deferred, not removed.
7383
7398
  */
7384
7399
  async hydrate(localDB, remoteDB) {
7385
- const replication = pouchdb_setup_default.replicate(remoteDB, localDB, {});
7400
+ const pristine = (await localDB.info()).doc_count === 0;
7401
+ const replication = pouchdb_setup_default.replicate(
7402
+ remoteDB,
7403
+ localDB,
7404
+ pristine ? { selector: { _deleted: { $exists: false } } } : {}
7405
+ );
7386
7406
  this.hydrationHandle = replication;
7387
7407
  try {
7388
7408
  const info = await replication;
7389
- return { docsWritten: info.docs_written };
7409
+ return {
7410
+ docsWritten: info.docs_written,
7411
+ // Only a pristine pull is a trustworthy starting point for the live
7412
+ // sync; otherwise leave startSync() to its own checkpoint.
7413
+ lastSeq: pristine ? info.last_seq : void 0
7414
+ };
7390
7415
  } finally {
7391
7416
  this.hydrationHandle = void 0;
7392
7417
  }
7393
7418
  }
7394
- startSync(localDB, remoteDB) {
7419
+ startSync(localDB, remoteDB, since) {
7395
7420
  if (localDB.name !== remoteDB.name) {
7396
7421
  this.syncHandle = pouchdb_setup_default.sync(localDB, remoteDB, {
7397
7422
  live: true,
7398
- retry: true
7423
+ retry: true,
7424
+ // `since` applies to the pull only, and only when hydrate() just
7425
+ // established that local matches remote at that sequence. Without it,
7426
+ // a filtered hydration leaves the pull with no usable checkpoint (the
7427
+ // filter changes the replication id), so it restarts from zero and
7428
+ // re-walks in the background exactly the tombstone history hydration
7429
+ // just skipped — same work, now competing with the study session.
7430
+ //
7431
+ // Deliberately NOT persisted across launches: on later boots hydration
7432
+ // is skipped and the pull's own checkpoint is the correct resume
7433
+ // point, so a stored sequence could only be stale. If the app dies
7434
+ // before that first checkpoint is written, the next launch simply
7435
+ // walks the full feed once.
7436
+ ...since !== void 0 ? { pull: { since } } : {}
7399
7437
  });
7400
7438
  }
7401
7439
  }
@@ -7917,6 +7955,14 @@ var init_BaseUserDB = __esm({
7917
7955
  _hydration = { state: "not-required" };
7918
7956
  /** In-flight hydration, so concurrent callers can wait for a real answer. */
7919
7957
  _hydrationPromise = null;
7958
+ /**
7959
+ * Sequence the local mirror was filled to by a hydration that succeeded in
7960
+ * THIS init(), handed to startSync() so the live pull can skip history it
7961
+ * would otherwise re-walk. Undefined whenever there is no such guarantee —
7962
+ * hydration skipped, not required, or failed. Never persisted; see the
7963
+ * `since` note in CouchDBSyncStrategy.startSync().
7964
+ */
7965
+ _hydratedSeq;
7920
7966
  /**
7921
7967
  * How far the local mirror can be trusted, RIGHT NOW. See
7922
7968
  * {@link UserHydrationStatus}.
@@ -8403,7 +8449,7 @@ Currently logged-in as ${this._username}.`
8403
8449
  this.setDBandQ();
8404
8450
  this._hydrationPromise = this.hydrateLocalMirror();
8405
8451
  await this._hydrationPromise;
8406
- this.syncStrategy.startSync(this.localDB, this.remoteDB);
8452
+ this.syncStrategy.startSync(this.localDB, this.remoteDB, this._hydratedSeq);
8407
8453
  this.applyDesignDocs().catch((error) => {
8408
8454
  log4(`Error in applyDesignDocs background task: ${error}`);
8409
8455
  if (error && typeof error === "object") {
@@ -8431,6 +8477,7 @@ Currently logged-in as ${this._username}.`
8431
8477
  * ceiling). Callers decide what a failure means for them.
8432
8478
  */
8433
8479
  async hydrateLocalMirror() {
8480
+ this._hydratedSeq = void 0;
8434
8481
  if (this.localDB.name === this.remoteDB.name || !this.syncStrategy.hydrate) {
8435
8482
  this._hydration = { state: "not-required" };
8436
8483
  return;
@@ -8442,11 +8489,12 @@ Currently logged-in as ${this._username}.`
8442
8489
  this._hydration = { state: "hydrating" };
8443
8490
  const start = Date.now();
8444
8491
  try {
8445
- const { docsWritten } = await withTimeout(
8492
+ const { docsWritten, lastSeq } = await withTimeout(
8446
8493
  this.syncStrategy.hydrate(this.localDB, this.remoteDB),
8447
8494
  HYDRATION_TIMEOUT_MS,
8448
8495
  `Hydration of local mirror for ${this._username}`
8449
8496
  );
8497
+ this._hydratedSeq = lastSeq;
8450
8498
  await this.writeHydrationMarker();
8451
8499
  this._hydration = {
8452
8500
  state: "hydrated",