@vue-skuilder/db 0.2.19 → 0.2.21
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/{SyncStrategy-BJMZq3WO.d.cts → SyncStrategy-CCU1H81I.d.cts} +8 -2
- package/dist/{SyncStrategy-BJMZq3WO.d.ts → SyncStrategy-CCU1H81I.d.ts} +8 -2
- package/dist/{contentSource-D-LQYFyx.d.cts → contentSource-BMxsujRu.d.cts} +5 -0
- package/dist/{contentSource-BDRX_YYJ.d.ts → contentSource-Bazgkf4C.d.ts} +5 -0
- package/dist/core/index.d.cts +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +12 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +12 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-Dpshuql4.d.ts → dataLayerProvider-Bt-D6xas.d.ts} +1 -1
- package/dist/{dataLayerProvider-Dd2UcCif.d.cts → dataLayerProvider-DifVCcIS.d.cts} +1 -1
- package/dist/impl/couch/index.d.cts +20 -4
- package/dist/impl/couch/index.d.ts +20 -4
- package/dist/impl/couch/index.js +54 -6
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +54 -6
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.cts +3 -3
- package/dist/impl/static/index.d.ts +3 -3
- package/dist/impl/static/index.js +12 -2
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +12 -2
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +54 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +54 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/core/types/user.ts +6 -1
- package/src/impl/common/BaseUserDB.ts +19 -2
- package/src/impl/common/SyncStrategy.ts +17 -4
- package/src/impl/couch/CouchDBSyncStrategy.ts +52 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as UserDBInterface, a as UserDBReader, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface } from './contentSource-
|
|
1
|
+
import { U as UserDBInterface, a as UserDBReader, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface } from './contentSource-Bazgkf4C.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Main factory interface for data access
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as UserDBInterface, a as UserDBReader, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface } from './contentSource-
|
|
1
|
+
import { U as UserDBInterface, a as UserDBReader, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface } from './contentSource-BMxsujRu.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Main factory interface for data access
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { T as TagStub, a as Tag, S as SkuilderCourseData, Q as QualifiedCardID } from '../../types-legacy-4tlwHnXo.cjs';
|
|
2
2
|
import { Moment } from 'moment';
|
|
3
|
-
import { A as AdminDBInterface, g as AssignedContent, h as StudyContentSource, i as StudentClassroomDBInterface, U as UserDBInterface, G as GeneratorResult, T as TeacherClassroomDBInterface, b as CoursesDBInterface, C as CourseDBInterface, d as CourseInfo, D as DataLayerResult, e as ContentNavigationStrategyData, f as ContentNavigator, R as ReplanHints, S as StudySessionItem, j as ScheduledCard } from '../../contentSource-
|
|
4
|
-
export { q as ContentSourceID, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, n as StudySessionNewItem, o as StudySessionReviewItem, r as getStudySource, p as isReview } from '../../contentSource-
|
|
3
|
+
import { A as AdminDBInterface, g as AssignedContent, h as StudyContentSource, i as StudentClassroomDBInterface, U as UserDBInterface, G as GeneratorResult, T as TeacherClassroomDBInterface, b as CoursesDBInterface, C as CourseDBInterface, d as CourseInfo, D as DataLayerResult, e as ContentNavigationStrategyData, f as ContentNavigator, R as ReplanHints, S as StudySessionItem, j as ScheduledCard } from '../../contentSource-BMxsujRu.cjs';
|
|
4
|
+
export { q as ContentSourceID, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, n as StudySessionNewItem, o as StudySessionReviewItem, r as getStudySource, p as isReview } from '../../contentSource-BMxsujRu.cjs';
|
|
5
5
|
import * as _vue_skuilder_common from '@vue-skuilder/common';
|
|
6
6
|
import { ClassroomConfig, DataShape, CourseElo, CourseConfig as CourseConfig$1 } from '@vue-skuilder/common';
|
|
7
|
-
import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-
|
|
7
|
+
import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-CCU1H81I.cjs';
|
|
8
8
|
|
|
9
9
|
type NamespacedDatashape = string;
|
|
10
10
|
interface DataShape55 {
|
|
@@ -508,11 +508,27 @@ declare class CouchDBSyncStrategy implements SyncStrategy {
|
|
|
508
508
|
* before we know what the remote already has, which is the conflict-leaf
|
|
509
509
|
* problem hydration exists to avoid. Local changes go up when startSync()
|
|
510
510
|
* takes over.
|
|
511
|
+
*
|
|
512
|
+
* Into an EMPTY local DB this skips deleted documents, because a mirror that
|
|
513
|
+
* never held a document does not need to be told it was removed. That
|
|
514
|
+
* matters more than it sounds: scheduled reviews (`card_review_*`) are
|
|
515
|
+
* created and deleted once per review completed, so the changes feed is
|
|
516
|
+
* dominated by tombstones and grows without bound, while the durable record
|
|
517
|
+
* lives in card history. One real account measured 385 live documents behind
|
|
518
|
+
* 8,370 deletions — an unfiltered pull moved 9,520 documents and took ~20s,
|
|
519
|
+
* blowing the hydration timeout on a phone; filtered, the same pull moves
|
|
520
|
+
* 404 and takes ~2s, reaching a byte-identical local state.
|
|
521
|
+
*
|
|
522
|
+
* The filter runs server-side, so `last_seq` still reports the source's true
|
|
523
|
+
* sequence. Returning it lets startSync() begin the live pull from there
|
|
524
|
+
* instead of re-walking the same history in the background — without that,
|
|
525
|
+
* the cost is merely deferred, not removed.
|
|
511
526
|
*/
|
|
512
527
|
hydrate(localDB: PouchDB.Database, remoteDB: PouchDB.Database): Promise<{
|
|
513
528
|
docsWritten: number;
|
|
529
|
+
lastSeq?: string | number;
|
|
514
530
|
}>;
|
|
515
|
-
startSync(localDB: PouchDB.Database, remoteDB: PouchDB.Database): void;
|
|
531
|
+
startSync(localDB: PouchDB.Database, remoteDB: PouchDB.Database, since?: string | number): void;
|
|
516
532
|
stopSync?(): void;
|
|
517
533
|
canCreateAccount(): boolean;
|
|
518
534
|
canAuthenticate(): boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { T as TagStub, a as Tag, S as SkuilderCourseData, Q as QualifiedCardID } from '../../types-legacy-4tlwHnXo.js';
|
|
2
2
|
import { Moment } from 'moment';
|
|
3
|
-
import { A as AdminDBInterface, g as AssignedContent, h as StudyContentSource, i as StudentClassroomDBInterface, U as UserDBInterface, G as GeneratorResult, T as TeacherClassroomDBInterface, b as CoursesDBInterface, C as CourseDBInterface, d as CourseInfo, D as DataLayerResult, e as ContentNavigationStrategyData, f as ContentNavigator, R as ReplanHints, S as StudySessionItem, j as ScheduledCard } from '../../contentSource-
|
|
4
|
-
export { q as ContentSourceID, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, n as StudySessionNewItem, o as StudySessionReviewItem, r as getStudySource, p as isReview } from '../../contentSource-
|
|
3
|
+
import { A as AdminDBInterface, g as AssignedContent, h as StudyContentSource, i as StudentClassroomDBInterface, U as UserDBInterface, G as GeneratorResult, T as TeacherClassroomDBInterface, b as CoursesDBInterface, C as CourseDBInterface, d as CourseInfo, D as DataLayerResult, e as ContentNavigationStrategyData, f as ContentNavigator, R as ReplanHints, S as StudySessionItem, j as ScheduledCard } from '../../contentSource-Bazgkf4C.js';
|
|
4
|
+
export { q as ContentSourceID, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, n as StudySessionNewItem, o as StudySessionReviewItem, r as getStudySource, p as isReview } from '../../contentSource-Bazgkf4C.js';
|
|
5
5
|
import * as _vue_skuilder_common from '@vue-skuilder/common';
|
|
6
6
|
import { ClassroomConfig, DataShape, CourseElo, CourseConfig as CourseConfig$1 } from '@vue-skuilder/common';
|
|
7
|
-
import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-
|
|
7
|
+
import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-CCU1H81I.js';
|
|
8
8
|
|
|
9
9
|
type NamespacedDatashape = string;
|
|
10
10
|
interface DataShape55 {
|
|
@@ -508,11 +508,27 @@ declare class CouchDBSyncStrategy implements SyncStrategy {
|
|
|
508
508
|
* before we know what the remote already has, which is the conflict-leaf
|
|
509
509
|
* problem hydration exists to avoid. Local changes go up when startSync()
|
|
510
510
|
* takes over.
|
|
511
|
+
*
|
|
512
|
+
* Into an EMPTY local DB this skips deleted documents, because a mirror that
|
|
513
|
+
* never held a document does not need to be told it was removed. That
|
|
514
|
+
* matters more than it sounds: scheduled reviews (`card_review_*`) are
|
|
515
|
+
* created and deleted once per review completed, so the changes feed is
|
|
516
|
+
* dominated by tombstones and grows without bound, while the durable record
|
|
517
|
+
* lives in card history. One real account measured 385 live documents behind
|
|
518
|
+
* 8,370 deletions — an unfiltered pull moved 9,520 documents and took ~20s,
|
|
519
|
+
* blowing the hydration timeout on a phone; filtered, the same pull moves
|
|
520
|
+
* 404 and takes ~2s, reaching a byte-identical local state.
|
|
521
|
+
*
|
|
522
|
+
* The filter runs server-side, so `last_seq` still reports the source's true
|
|
523
|
+
* sequence. Returning it lets startSync() begin the live pull from there
|
|
524
|
+
* instead of re-walking the same history in the background — without that,
|
|
525
|
+
* the cost is merely deferred, not removed.
|
|
511
526
|
*/
|
|
512
527
|
hydrate(localDB: PouchDB.Database, remoteDB: PouchDB.Database): Promise<{
|
|
513
528
|
docsWritten: number;
|
|
529
|
+
lastSeq?: string | number;
|
|
514
530
|
}>;
|
|
515
|
-
startSync(localDB: PouchDB.Database, remoteDB: PouchDB.Database): void;
|
|
531
|
+
startSync(localDB: PouchDB.Database, remoteDB: PouchDB.Database, since?: string | number): void;
|
|
516
532
|
stopSync?(): void;
|
|
517
533
|
canCreateAccount(): boolean;
|
|
518
534
|
canAuthenticate(): boolean;
|
package/dist/impl/couch/index.js
CHANGED
|
@@ -7563,6 +7563,14 @@ var init_BaseUserDB = __esm({
|
|
|
7563
7563
|
_hydration = { state: "not-required" };
|
|
7564
7564
|
/** In-flight hydration, so concurrent callers can wait for a real answer. */
|
|
7565
7565
|
_hydrationPromise = null;
|
|
7566
|
+
/**
|
|
7567
|
+
* Sequence the local mirror was filled to by a hydration that succeeded in
|
|
7568
|
+
* THIS init(), handed to startSync() so the live pull can skip history it
|
|
7569
|
+
* would otherwise re-walk. Undefined whenever there is no such guarantee —
|
|
7570
|
+
* hydration skipped, not required, or failed. Never persisted; see the
|
|
7571
|
+
* `since` note in CouchDBSyncStrategy.startSync().
|
|
7572
|
+
*/
|
|
7573
|
+
_hydratedSeq;
|
|
7566
7574
|
/**
|
|
7567
7575
|
* How far the local mirror can be trusted, RIGHT NOW. See
|
|
7568
7576
|
* {@link UserHydrationStatus}.
|
|
@@ -8049,7 +8057,7 @@ Currently logged-in as ${this._username}.`
|
|
|
8049
8057
|
this.setDBandQ();
|
|
8050
8058
|
this._hydrationPromise = this.hydrateLocalMirror();
|
|
8051
8059
|
await this._hydrationPromise;
|
|
8052
|
-
this.syncStrategy.startSync(this.localDB, this.remoteDB);
|
|
8060
|
+
this.syncStrategy.startSync(this.localDB, this.remoteDB, this._hydratedSeq);
|
|
8053
8061
|
this.applyDesignDocs().catch((error) => {
|
|
8054
8062
|
log3(`Error in applyDesignDocs background task: ${error}`);
|
|
8055
8063
|
if (error && typeof error === "object") {
|
|
@@ -8077,6 +8085,7 @@ Currently logged-in as ${this._username}.`
|
|
|
8077
8085
|
* ceiling). Callers decide what a failure means for them.
|
|
8078
8086
|
*/
|
|
8079
8087
|
async hydrateLocalMirror() {
|
|
8088
|
+
this._hydratedSeq = void 0;
|
|
8080
8089
|
if (this.localDB.name === this.remoteDB.name || !this.syncStrategy.hydrate) {
|
|
8081
8090
|
this._hydration = { state: "not-required" };
|
|
8082
8091
|
return;
|
|
@@ -8088,11 +8097,12 @@ Currently logged-in as ${this._username}.`
|
|
|
8088
8097
|
this._hydration = { state: "hydrating" };
|
|
8089
8098
|
const start = Date.now();
|
|
8090
8099
|
try {
|
|
8091
|
-
const { docsWritten } = await withTimeout(
|
|
8100
|
+
const { docsWritten, lastSeq } = await withTimeout(
|
|
8092
8101
|
this.syncStrategy.hydrate(this.localDB, this.remoteDB),
|
|
8093
8102
|
HYDRATION_TIMEOUT_MS,
|
|
8094
8103
|
`Hydration of local mirror for ${this._username}`
|
|
8095
8104
|
);
|
|
8105
|
+
this._hydratedSeq = lastSeq;
|
|
8096
8106
|
await this.writeHydrationMarker();
|
|
8097
8107
|
this._hydration = {
|
|
8098
8108
|
state: "hydrated",
|
|
@@ -9031,22 +9041,60 @@ var init_CouchDBSyncStrategy = __esm({
|
|
|
9031
9041
|
* before we know what the remote already has, which is the conflict-leaf
|
|
9032
9042
|
* problem hydration exists to avoid. Local changes go up when startSync()
|
|
9033
9043
|
* takes over.
|
|
9044
|
+
*
|
|
9045
|
+
* Into an EMPTY local DB this skips deleted documents, because a mirror that
|
|
9046
|
+
* never held a document does not need to be told it was removed. That
|
|
9047
|
+
* matters more than it sounds: scheduled reviews (`card_review_*`) are
|
|
9048
|
+
* created and deleted once per review completed, so the changes feed is
|
|
9049
|
+
* dominated by tombstones and grows without bound, while the durable record
|
|
9050
|
+
* lives in card history. One real account measured 385 live documents behind
|
|
9051
|
+
* 8,370 deletions — an unfiltered pull moved 9,520 documents and took ~20s,
|
|
9052
|
+
* blowing the hydration timeout on a phone; filtered, the same pull moves
|
|
9053
|
+
* 404 and takes ~2s, reaching a byte-identical local state.
|
|
9054
|
+
*
|
|
9055
|
+
* The filter runs server-side, so `last_seq` still reports the source's true
|
|
9056
|
+
* sequence. Returning it lets startSync() begin the live pull from there
|
|
9057
|
+
* instead of re-walking the same history in the background — without that,
|
|
9058
|
+
* the cost is merely deferred, not removed.
|
|
9034
9059
|
*/
|
|
9035
9060
|
async hydrate(localDB, remoteDB) {
|
|
9036
|
-
const
|
|
9061
|
+
const pristine = (await localDB.info()).doc_count === 0;
|
|
9062
|
+
const replication = pouchdb_setup_default.replicate(
|
|
9063
|
+
remoteDB,
|
|
9064
|
+
localDB,
|
|
9065
|
+
pristine ? { selector: { _deleted: { $exists: false } } } : {}
|
|
9066
|
+
);
|
|
9037
9067
|
this.hydrationHandle = replication;
|
|
9038
9068
|
try {
|
|
9039
9069
|
const info = await replication;
|
|
9040
|
-
return {
|
|
9070
|
+
return {
|
|
9071
|
+
docsWritten: info.docs_written,
|
|
9072
|
+
// Only a pristine pull is a trustworthy starting point for the live
|
|
9073
|
+
// sync; otherwise leave startSync() to its own checkpoint.
|
|
9074
|
+
lastSeq: pristine ? info.last_seq : void 0
|
|
9075
|
+
};
|
|
9041
9076
|
} finally {
|
|
9042
9077
|
this.hydrationHandle = void 0;
|
|
9043
9078
|
}
|
|
9044
9079
|
}
|
|
9045
|
-
startSync(localDB, remoteDB) {
|
|
9080
|
+
startSync(localDB, remoteDB, since) {
|
|
9046
9081
|
if (localDB.name !== remoteDB.name) {
|
|
9047
9082
|
this.syncHandle = pouchdb_setup_default.sync(localDB, remoteDB, {
|
|
9048
9083
|
live: true,
|
|
9049
|
-
retry: true
|
|
9084
|
+
retry: true,
|
|
9085
|
+
// `since` applies to the pull only, and only when hydrate() just
|
|
9086
|
+
// established that local matches remote at that sequence. Without it,
|
|
9087
|
+
// a filtered hydration leaves the pull with no usable checkpoint (the
|
|
9088
|
+
// filter changes the replication id), so it restarts from zero and
|
|
9089
|
+
// re-walks in the background exactly the tombstone history hydration
|
|
9090
|
+
// just skipped — same work, now competing with the study session.
|
|
9091
|
+
//
|
|
9092
|
+
// Deliberately NOT persisted across launches: on later boots hydration
|
|
9093
|
+
// is skipped and the pull's own checkpoint is the correct resume
|
|
9094
|
+
// point, so a stored sequence could only be stale. If the app dies
|
|
9095
|
+
// before that first checkpoint is written, the next launch simply
|
|
9096
|
+
// walks the full feed once.
|
|
9097
|
+
...since !== void 0 ? { pull: { since } } : {}
|
|
9050
9098
|
});
|
|
9051
9099
|
}
|
|
9052
9100
|
}
|