@vue-skuilder/db 0.2.18 → 0.2.19

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.
@@ -514,14 +514,26 @@ interface UserDBReader {
514
514
  getUsername(): string;
515
515
  isLoggedIn(): boolean;
516
516
  /**
517
- * How far this device's local mirror of the user's data can be trusted.
517
+ * How far this device's local mirror of the user's data can be trusted,
518
+ * as of right now.
518
519
  *
519
520
  * Reads answer from the local mirror, so on a device that has never synced
520
521
  * this account "document not found" does not mean "no such data". Anything
521
522
  * that would otherwise interpret an empty read as a new user should check
522
523
  * for `failed` first. See {@link UserHydrationStatus}.
524
+ *
525
+ * Can return `hydrating`; use {@link awaitHydration} to decide on a settled
526
+ * answer instead of a snapshot.
523
527
  */
524
528
  hydrationStatus(): UserHydrationStatus;
529
+ /**
530
+ * The hydration status once settled — never `hydrating`.
531
+ *
532
+ * Resolves immediately unless a pull is in flight. Prefer this over
533
+ * hydrationStatus() wherever the answer gates behaviour, such as a route
534
+ * guard that may run while a login is still completing.
535
+ */
536
+ awaitHydration(): Promise<UserHydrationStatus>;
525
537
  /**
526
538
  * Get user configuration
527
539
  */
@@ -514,14 +514,26 @@ interface UserDBReader {
514
514
  getUsername(): string;
515
515
  isLoggedIn(): boolean;
516
516
  /**
517
- * How far this device's local mirror of the user's data can be trusted.
517
+ * How far this device's local mirror of the user's data can be trusted,
518
+ * as of right now.
518
519
  *
519
520
  * Reads answer from the local mirror, so on a device that has never synced
520
521
  * this account "document not found" does not mean "no such data". Anything
521
522
  * that would otherwise interpret an empty read as a new user should check
522
523
  * for `failed` first. See {@link UserHydrationStatus}.
524
+ *
525
+ * Can return `hydrating`; use {@link awaitHydration} to decide on a settled
526
+ * answer instead of a snapshot.
523
527
  */
524
528
  hydrationStatus(): UserHydrationStatus;
529
+ /**
530
+ * The hydration status once settled — never `hydrating`.
531
+ *
532
+ * Resolves immediately unless a pull is in flight. Prefer this over
533
+ * hydrationStatus() wherever the answer gates behaviour, such as a route
534
+ * guard that may run while a login is still completing.
535
+ */
536
+ awaitHydration(): Promise<UserHydrationStatus>;
525
537
  /**
526
538
  * Get user configuration
527
539
  */
@@ -1,6 +1,6 @@
1
- import { ab as LearnableWeight, M as UserOutcomeRecord, ac as OrchestrationContext, W as WeightedCard, U as UserDBInterface, C as CourseDBInterface, R as ReplanHints, a1 as StrategyContribution } from '../contentSource-CBqZCoGU.cjs';
2
- export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as AssignedContent, u as AssignedCourse, t as AssignedTag, a8 as CardGenerator, aa as CardGeneratorFactory, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, e as ContentNavigationStrategyData, f as ContentNavigator, q as ContentSourceID, d as CourseInfo, L as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, a9 as GeneratorContext, G as GeneratorResult, P as HYDRATION_MARKER_ID, Q as HydrationMarker, V as NavigatorConstructor, a4 as NavigatorRole, a5 as NavigatorRoles, a3 as Navigators, j as ScheduledCard, I as SessionTrackingData, i as StudentClassroomDBInterface, h as StudyContentSource, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, S as StudySessionItem, n as StudySessionNewItem, o as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, N as UserHydrationState, O as UserHydrationStatus, B as UsrCrsDataInterface, ad as computeDeviation, af as computeEffectiveWeight, ae as computeSpread, ag as createOrchestrationContext, a2 as getCardOrigin, Y as getRegisteredNavigator, $ as getRegisteredNavigatorNames, _ as getRegisteredNavigatorRole, r as getStudySource, Z as hasRegisteredNavigator, a0 as initializeNavigatorRegistry, a7 as isFilter, a6 as isGenerator, p as isReview, X as registerNavigator } from '../contentSource-CBqZCoGU.cjs';
3
- export { D as DataLayerProvider } from '../dataLayerProvider-BBA8tJNx.cjs';
1
+ import { ab as LearnableWeight, M as UserOutcomeRecord, ac as OrchestrationContext, W as WeightedCard, U as UserDBInterface, C as CourseDBInterface, R as ReplanHints, a1 as StrategyContribution } from '../contentSource-D-LQYFyx.cjs';
2
+ export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as AssignedContent, u as AssignedCourse, t as AssignedTag, a8 as CardGenerator, aa as CardGeneratorFactory, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, e as ContentNavigationStrategyData, f as ContentNavigator, q as ContentSourceID, d as CourseInfo, L as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, a9 as GeneratorContext, G as GeneratorResult, P as HYDRATION_MARKER_ID, Q as HydrationMarker, V as NavigatorConstructor, a4 as NavigatorRole, a5 as NavigatorRoles, a3 as Navigators, j as ScheduledCard, I as SessionTrackingData, i as StudentClassroomDBInterface, h as StudyContentSource, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, S as StudySessionItem, n as StudySessionNewItem, o as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, N as UserHydrationState, O as UserHydrationStatus, B as UsrCrsDataInterface, ad as computeDeviation, af as computeEffectiveWeight, ae as computeSpread, ag as createOrchestrationContext, a2 as getCardOrigin, Y as getRegisteredNavigator, $ as getRegisteredNavigatorNames, _ as getRegisteredNavigatorRole, r as getStudySource, Z as hasRegisteredNavigator, a0 as initializeNavigatorRegistry, a7 as isFilter, a6 as isGenerator, p as isReview, X as registerNavigator } from '../contentSource-D-LQYFyx.cjs';
3
+ export { D as DataLayerProvider } from '../dataLayerProvider-Dd2UcCif.cjs';
4
4
  import { D as DocType, d as QuestionRecord, b as DocTypePrefixes, C as CardHistory, c as CardRecord } from '../types-legacy-4tlwHnXo.cjs';
5
5
  export { e as CardData, f as CourseListData, h as DataShapeData, g as DisplayableData, F as Field, G as GuestUsername, Q as QualifiedCardID, i as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-4tlwHnXo.cjs';
6
6
  import { DataShape, ParsedCard } from '@vue-skuilder/common';
@@ -1,6 +1,6 @@
1
- import { ab as LearnableWeight, M as UserOutcomeRecord, ac as OrchestrationContext, W as WeightedCard, U as UserDBInterface, C as CourseDBInterface, R as ReplanHints, a1 as StrategyContribution } from '../contentSource-CudEz5Tm.js';
2
- export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as AssignedContent, u as AssignedCourse, t as AssignedTag, a8 as CardGenerator, aa as CardGeneratorFactory, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, e as ContentNavigationStrategyData, f as ContentNavigator, q as ContentSourceID, d as CourseInfo, L as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, a9 as GeneratorContext, G as GeneratorResult, P as HYDRATION_MARKER_ID, Q as HydrationMarker, V as NavigatorConstructor, a4 as NavigatorRole, a5 as NavigatorRoles, a3 as Navigators, j as ScheduledCard, I as SessionTrackingData, i as StudentClassroomDBInterface, h as StudyContentSource, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, S as StudySessionItem, n as StudySessionNewItem, o as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, N as UserHydrationState, O as UserHydrationStatus, B as UsrCrsDataInterface, ad as computeDeviation, af as computeEffectiveWeight, ae as computeSpread, ag as createOrchestrationContext, a2 as getCardOrigin, Y as getRegisteredNavigator, $ as getRegisteredNavigatorNames, _ as getRegisteredNavigatorRole, r as getStudySource, Z as hasRegisteredNavigator, a0 as initializeNavigatorRegistry, a7 as isFilter, a6 as isGenerator, p as isReview, X as registerNavigator } from '../contentSource-CudEz5Tm.js';
3
- export { D as DataLayerProvider } from '../dataLayerProvider-C9WgkBzR.js';
1
+ import { ab as LearnableWeight, M as UserOutcomeRecord, ac as OrchestrationContext, W as WeightedCard, U as UserDBInterface, C as CourseDBInterface, R as ReplanHints, a1 as StrategyContribution } from '../contentSource-BDRX_YYJ.js';
2
+ export { K as ActivityRecord, A as AdminDBInterface, v as AssignedCard, g as AssignedContent, u as AssignedCourse, t as AssignedTag, a8 as CardGenerator, aa as CardGeneratorFactory, c as ClassroomDBInterface, F as ClassroomRegistration, E as ClassroomRegistrationDesignation, H as ClassroomRegistrationDoc, e as ContentNavigationStrategyData, f as ContentNavigator, q as ContentSourceID, d as CourseInfo, L as CourseRegistration, s as CourseRegistrationDoc, b as CoursesDBInterface, a9 as GeneratorContext, G as GeneratorResult, P as HYDRATION_MARKER_ID, Q as HydrationMarker, V as NavigatorConstructor, a4 as NavigatorRole, a5 as NavigatorRoles, a3 as Navigators, j as ScheduledCard, I as SessionTrackingData, i as StudentClassroomDBInterface, h as StudyContentSource, k as StudySessionFailedItem, l as StudySessionFailedNewItem, m as StudySessionFailedReviewItem, S as StudySessionItem, n as StudySessionNewItem, o as StudySessionReviewItem, T as TeacherClassroomDBInterface, J as UserConfig, z as UserCourseSetting, y as UserCourseSettings, x as UserDBAuthenticator, a as UserDBReader, w as UserDBWriter, N as UserHydrationState, O as UserHydrationStatus, B as UsrCrsDataInterface, ad as computeDeviation, af as computeEffectiveWeight, ae as computeSpread, ag as createOrchestrationContext, a2 as getCardOrigin, Y as getRegisteredNavigator, $ as getRegisteredNavigatorNames, _ as getRegisteredNavigatorRole, r as getStudySource, Z as hasRegisteredNavigator, a0 as initializeNavigatorRegistry, a7 as isFilter, a6 as isGenerator, p as isReview, X as registerNavigator } from '../contentSource-BDRX_YYJ.js';
3
+ export { D as DataLayerProvider } from '../dataLayerProvider-Dpshuql4.js';
4
4
  import { D as DocType, d as QuestionRecord, b as DocTypePrefixes, C as CardHistory, c as CardRecord } from '../types-legacy-4tlwHnXo.js';
5
5
  export { e as CardData, f as CourseListData, h as DataShapeData, g as DisplayableData, F as Field, G as GuestUsername, Q as QualifiedCardID, i as QuestionData, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from '../types-legacy-4tlwHnXo.js';
6
6
  import { DataShape, ParsedCard } from '@vue-skuilder/common';
@@ -6919,16 +6919,36 @@ var init_BaseUserDB = __esm({
6919
6919
  // Database to use for write operations (local-first approach)
6920
6920
  updateQueue;
6921
6921
  _hydration = { state: "not-required" };
6922
+ /** In-flight hydration, so concurrent callers can wait for a real answer. */
6923
+ _hydrationPromise = null;
6922
6924
  /**
6923
- * How far the local mirror can be trusted. See {@link UserHydrationStatus}.
6925
+ * How far the local mirror can be trusted, RIGHT NOW. See
6926
+ * {@link UserHydrationStatus}.
6924
6927
  *
6925
- * Consumers that would otherwise read a 404 as "new user" — onboarding
6926
- * gates, first-run experiences, progress dashboards should check for
6927
- * `failed` and present a retry affordance rather than an empty state.
6928
+ * This is a snapshot, and during login it can legitimately read
6929
+ * `hydrating` prefer awaitHydration() anywhere a decision hangs on the
6930
+ * answer.
6928
6931
  */
6929
6932
  hydrationStatus() {
6930
6933
  return { ...this._hydration };
6931
6934
  }
6935
+ /**
6936
+ * The hydration status once it has settled — never `hydrating`.
6937
+ *
6938
+ * Resolves immediately unless a pull is in flight. Exists for callers that
6939
+ * must decide something (a route guard, a first-run branch) and would
6940
+ * otherwise sample `hydrating` and guess. Since init() is awaited by both
6941
+ * app startup and login(), that only happens when something navigates
6942
+ * concurrently with a login still in progress — a window that stretches to
6943
+ * HYDRATION_TIMEOUT_MS on a slow connection.
6944
+ */
6945
+ async awaitHydration() {
6946
+ try {
6947
+ await this._hydrationPromise;
6948
+ } catch {
6949
+ }
6950
+ return this.hydrationStatus();
6951
+ }
6932
6952
  /**
6933
6953
  * Whether a missing document may be treated as genuinely absent, allowing
6934
6954
  * callers to create it with defaults.
@@ -7385,7 +7405,8 @@ Currently logged-in as ${this._username}.`
7385
7405
  }
7386
7406
  this.syncStrategy.stopSync?.();
7387
7407
  this.setDBandQ();
7388
- await this.hydrateLocalMirror();
7408
+ this._hydrationPromise = this.hydrateLocalMirror();
7409
+ await this._hydrationPromise;
7389
7410
  this.syncStrategy.startSync(this.localDB, this.remoteDB);
7390
7411
  this.applyDesignDocs().catch((error) => {
7391
7412
  log3(`Error in applyDesignDocs background task: ${error}`);