@vue-skuilder/db 0.1.11 → 0.1.12

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.
Files changed (53) hide show
  1. package/dist/core/index.d.mts +7 -6
  2. package/dist/core/index.d.ts +7 -6
  3. package/dist/core/index.js +146 -37
  4. package/dist/core/index.js.map +1 -1
  5. package/dist/core/index.mjs +146 -37
  6. package/dist/core/index.mjs.map +1 -1
  7. package/dist/{dataLayerProvider-VieuAAkV.d.mts → dataLayerProvider-BiP3kWix.d.mts} +1 -1
  8. package/dist/{dataLayerProvider-juuqUHOP.d.ts → dataLayerProvider-DSdeyRT3.d.ts} +1 -1
  9. package/dist/impl/couch/index.d.mts +3 -3
  10. package/dist/impl/couch/index.d.ts +3 -3
  11. package/dist/impl/couch/index.js +146 -37
  12. package/dist/impl/couch/index.js.map +1 -1
  13. package/dist/impl/couch/index.mjs +146 -37
  14. package/dist/impl/couch/index.mjs.map +1 -1
  15. package/dist/impl/static/index.d.mts +14 -6
  16. package/dist/impl/static/index.d.ts +14 -6
  17. package/dist/impl/static/index.js +147 -39
  18. package/dist/impl/static/index.js.map +1 -1
  19. package/dist/impl/static/index.mjs +147 -39
  20. package/dist/impl/static/index.mjs.map +1 -1
  21. package/dist/{index-DZyxHCcf.d.mts → index-Bmll7Xse.d.mts} +1 -1
  22. package/dist/{index-CWY6yhkV.d.ts → index-CD8BZz2k.d.ts} +1 -1
  23. package/dist/index.d.mts +119 -24
  24. package/dist/index.d.ts +119 -24
  25. package/dist/index.js +785 -261
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +789 -265
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/{types-DtoI27Xh.d.ts → types-CewsN87z.d.ts} +1 -1
  30. package/dist/{types-Che4wTwA.d.mts → types-Dbp5DaRR.d.mts} +1 -1
  31. package/dist/{types-legacy-B8ahaCbj.d.mts → types-legacy-6ettoclI.d.mts} +13 -2
  32. package/dist/{types-legacy-B8ahaCbj.d.ts → types-legacy-6ettoclI.d.ts} +13 -2
  33. package/dist/{userDB-DJ8HMw83.d.mts → userDB-C4yyAnpp.d.mts} +3 -3
  34. package/dist/{userDB-B7zTQ123.d.ts → userDB-CD6s6ZCp.d.ts} +3 -3
  35. package/dist/util/packer/index.d.mts +3 -3
  36. package/dist/util/packer/index.d.ts +3 -3
  37. package/package.json +3 -3
  38. package/src/core/navigators/hardcodedOrder.ts +64 -0
  39. package/src/core/navigators/index.ts +1 -0
  40. package/src/core/types/contentNavigationStrategy.ts +2 -1
  41. package/src/core/types/types-legacy.ts +2 -2
  42. package/src/impl/common/BaseUserDB.ts +15 -11
  43. package/src/impl/couch/courseDB.ts +74 -27
  44. package/src/impl/couch/updateQueue.ts +8 -3
  45. package/src/impl/static/StaticDataLayerProvider.ts +57 -17
  46. package/src/impl/static/courseDB.ts +17 -12
  47. package/src/impl/static/coursesDB.ts +10 -6
  48. package/src/study/ItemQueue.ts +58 -0
  49. package/src/study/SessionController.ts +132 -178
  50. package/src/study/services/CardHydrationService.ts +153 -0
  51. package/src/study/services/EloService.ts +85 -0
  52. package/src/study/services/ResponseProcessor.ts +224 -0
  53. package/src/study/services/SrsService.ts +44 -0
@@ -1,21 +1,29 @@
1
- import { U as UserDBInterface, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface, a as UserDBReader, d as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, e as ContentNavigationStrategyData, f as StudySessionReviewItem, g as ScheduledCard } from '../../userDB-DJ8HMw83.mjs';
2
- import { D as DataLayerProvider } from '../../dataLayerProvider-VieuAAkV.mjs';
3
- import { S as StaticCourseManifest } from '../../types-Che4wTwA.mjs';
1
+ import { U as UserDBInterface, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface, a as UserDBReader, d as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, e as ContentNavigationStrategyData, f as StudySessionReviewItem, g as ScheduledCard } from '../../userDB-C4yyAnpp.mjs';
2
+ import { D as DataLayerProvider } from '../../dataLayerProvider-BiP3kWix.mjs';
3
+ import { S as StaticCourseManifest } from '../../types-Dbp5DaRR.mjs';
4
4
  import { CourseConfig, CourseElo, DataShape } from '@vue-skuilder/common';
5
- import { S as SkuilderCourseData, Q as QualifiedCardID, T as TagStub, a as Tag } from '../../types-legacy-B8ahaCbj.mjs';
5
+ import { S as SkuilderCourseData, Q as QualifiedCardID, T as TagStub, a as Tag } from '../../types-legacy-6ettoclI.mjs';
6
6
  import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-CyATpyLQ.mjs';
7
7
  import 'moment';
8
8
 
9
+ interface SkuilderManifest {
10
+ name?: string;
11
+ version?: string;
12
+ description?: string;
13
+ dependencies?: Record<string, string>;
14
+ }
9
15
  interface StaticDataLayerConfig {
10
- staticContentPath: string;
11
16
  localStoragePrefix?: string;
12
- manifests: Record<string, StaticCourseManifest>;
17
+ rootManifest: SkuilderManifest;
18
+ rootManifestUrl: string;
13
19
  }
14
20
  declare class StaticDataLayerProvider implements DataLayerProvider {
15
21
  private config;
16
22
  private initialized;
17
23
  private courseUnpackers;
24
+ private manifests;
18
25
  constructor(config: Partial<StaticDataLayerConfig>);
26
+ private resolveCourseDependencies;
19
27
  initialize(): Promise<void>;
20
28
  teardown(): Promise<void>;
21
29
  getUserDB(): UserDBInterface;
@@ -1,21 +1,29 @@
1
- import { U as UserDBInterface, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface, a as UserDBReader, d as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, e as ContentNavigationStrategyData, f as StudySessionReviewItem, g as ScheduledCard } from '../../userDB-B7zTQ123.js';
2
- import { D as DataLayerProvider } from '../../dataLayerProvider-juuqUHOP.js';
3
- import { S as StaticCourseManifest } from '../../types-DtoI27Xh.js';
1
+ import { U as UserDBInterface, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface, a as UserDBReader, d as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, e as ContentNavigationStrategyData, f as StudySessionReviewItem, g as ScheduledCard } from '../../userDB-CD6s6ZCp.js';
2
+ import { D as DataLayerProvider } from '../../dataLayerProvider-DSdeyRT3.js';
3
+ import { S as StaticCourseManifest } from '../../types-CewsN87z.js';
4
4
  import { CourseConfig, CourseElo, DataShape } from '@vue-skuilder/common';
5
- import { S as SkuilderCourseData, Q as QualifiedCardID, T as TagStub, a as Tag } from '../../types-legacy-B8ahaCbj.js';
5
+ import { S as SkuilderCourseData, Q as QualifiedCardID, T as TagStub, a as Tag } from '../../types-legacy-6ettoclI.js';
6
6
  import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-CyATpyLQ.js';
7
7
  import 'moment';
8
8
 
9
+ interface SkuilderManifest {
10
+ name?: string;
11
+ version?: string;
12
+ description?: string;
13
+ dependencies?: Record<string, string>;
14
+ }
9
15
  interface StaticDataLayerConfig {
10
- staticContentPath: string;
11
16
  localStoragePrefix?: string;
12
- manifests: Record<string, StaticCourseManifest>;
17
+ rootManifest: SkuilderManifest;
18
+ rootManifestUrl: string;
13
19
  }
14
20
  declare class StaticDataLayerProvider implements DataLayerProvider {
15
21
  private config;
16
22
  private initialized;
17
23
  private courseUnpackers;
24
+ private manifests;
18
25
  constructor(config: Partial<StaticDataLayerConfig>);
26
+ private resolveCourseDependencies;
19
27
  initialize(): Promise<void>;
20
28
  teardown(): Promise<void>;
21
29
  getUserDB(): UserDBInterface;
@@ -302,7 +302,9 @@ var init_updateQueue = __esm({
302
302
  async applyUpdates(id) {
303
303
  logger.debug(`Applying updates on doc: ${id}`);
304
304
  if (this.inprogressUpdates[id]) {
305
- await this.readDB.info();
305
+ while (this.inprogressUpdates[id]) {
306
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 50));
307
+ }
306
308
  return this.applyUpdates(id);
307
309
  } else {
308
310
  if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
@@ -338,6 +340,9 @@ var init_updateQueue = __esm({
338
340
  if (e.name === "conflict" && i < MAX_RETRIES - 1) {
339
341
  logger.warn(`Conflict on update for doc ${id}, retry #${i + 1}`);
340
342
  await new Promise((res) => setTimeout(res, 50 * Math.random()));
343
+ } else if (e.name === "not_found" && i === 0) {
344
+ logger.warn(`Update failed for ${id} - does not exist. Throwing to caller.`);
345
+ throw e;
341
346
  } else {
342
347
  delete this.inprogressUpdates[id];
343
348
  if (this.pendingUpdates[id]) {
@@ -534,12 +539,74 @@ var init_elo = __esm({
534
539
  }
535
540
  });
536
541
 
542
+ // src/core/navigators/hardcodedOrder.ts
543
+ var hardcodedOrder_exports = {};
544
+ __export(hardcodedOrder_exports, {
545
+ default: () => HardcodedOrderNavigator
546
+ });
547
+ var HardcodedOrderNavigator;
548
+ var init_hardcodedOrder = __esm({
549
+ "src/core/navigators/hardcodedOrder.ts"() {
550
+ "use strict";
551
+ init_navigators();
552
+ init_logger();
553
+ HardcodedOrderNavigator = class extends ContentNavigator {
554
+ orderedCardIds = [];
555
+ user;
556
+ course;
557
+ constructor(user, course, strategyData) {
558
+ super();
559
+ this.user = user;
560
+ this.course = course;
561
+ if (strategyData.serializedData) {
562
+ try {
563
+ this.orderedCardIds = JSON.parse(strategyData.serializedData);
564
+ } catch (e) {
565
+ logger.error("Failed to parse serializedData for HardcodedOrderNavigator", e);
566
+ }
567
+ }
568
+ }
569
+ async getPendingReviews() {
570
+ const reviews = await this.user.getPendingReviews(this.course.getCourseID());
571
+ return reviews.map((r) => {
572
+ return {
573
+ ...r,
574
+ contentSourceType: "course",
575
+ contentSourceID: this.course.getCourseID(),
576
+ cardID: r.cardId,
577
+ courseID: r.courseId,
578
+ reviewID: r._id,
579
+ status: "review"
580
+ };
581
+ });
582
+ }
583
+ async getNewCards(limit = 99) {
584
+ const activeCardIds = (await this.user.getActiveCards()).map((c) => c.cardID);
585
+ const newCardIds = this.orderedCardIds.filter(
586
+ (cardId) => !activeCardIds.includes(cardId)
587
+ );
588
+ const cardsToReturn = newCardIds.slice(0, limit);
589
+ return cardsToReturn.map((cardId) => {
590
+ return {
591
+ cardID: cardId,
592
+ courseID: this.course.getCourseID(),
593
+ contentSourceType: "course",
594
+ contentSourceID: this.course.getCourseID(),
595
+ status: "new"
596
+ };
597
+ });
598
+ }
599
+ };
600
+ }
601
+ });
602
+
537
603
  // import("./**/*") in src/core/navigators/index.ts
538
604
  var globImport;
539
605
  var init_ = __esm({
540
606
  'import("./**/*") in src/core/navigators/index.ts'() {
541
607
  globImport = __glob({
542
608
  "./elo.ts": () => Promise.resolve().then(() => (init_elo(), elo_exports)),
609
+ "./hardcodedOrder.ts": () => Promise.resolve().then(() => (init_hardcodedOrder(), hardcodedOrder_exports)),
543
610
  "./index.ts": () => Promise.resolve().then(() => (init_navigators(), navigators_exports))
544
611
  });
545
612
  }
@@ -559,6 +626,7 @@ var init_navigators = __esm({
559
626
  init_();
560
627
  Navigators = /* @__PURE__ */ ((Navigators2) => {
561
628
  Navigators2["ELO"] = "elo";
629
+ Navigators2["HARDCODED"] = "hardcodedOrder";
562
630
  return Navigators2;
563
631
  })(Navigators || {});
564
632
  ContentNavigator = class {
@@ -1392,17 +1460,21 @@ Currently logged-in as ${this._username}.`
1392
1460
  } catch (e) {
1393
1461
  const reason = e;
1394
1462
  if (reason.status === 404) {
1395
- const initCardHistory = {
1396
- _id: cardHistoryID,
1397
- cardID: record.cardID,
1398
- courseID: record.courseID,
1399
- records: [record],
1400
- lapses: 0,
1401
- streak: 0,
1402
- bestInterval: 0
1403
- };
1404
- const putResult = await this.writeDB.put(initCardHistory);
1405
- return { ...initCardHistory, _rev: putResult.rev };
1463
+ try {
1464
+ const initCardHistory = {
1465
+ _id: cardHistoryID,
1466
+ cardID: record.cardID,
1467
+ courseID: record.courseID,
1468
+ records: [record],
1469
+ lapses: 0,
1470
+ streak: 0,
1471
+ bestInterval: 0
1472
+ };
1473
+ const putResult = await this.writeDB.put(initCardHistory);
1474
+ return { ...initCardHistory, _rev: putResult.rev };
1475
+ } catch (creationError) {
1476
+ throw new Error(`Failed to create CardHistory for ${cardHistoryID}. Reason: ${creationError}`);
1477
+ }
1406
1478
  } else {
1407
1479
  throw new Error(`putCardRecord failed because of:
1408
1480
  name:${reason.name}
@@ -2191,16 +2263,20 @@ var init_courseDB3 = __esm({
2191
2263
  async updateCardElo(cardId, _elo) {
2192
2264
  return { ok: true, id: cardId, rev: "1-static" };
2193
2265
  }
2194
- async getNewCards(limit) {
2195
- const cardIds = await this.unpacker.queryByElo(1e3, limit || 10);
2196
- return cardIds.map((cardId) => ({
2197
- status: "new",
2198
- qualifiedID: `${this.courseId}-${cardId}`,
2199
- cardID: cardId,
2200
- contentSourceType: "course",
2201
- contentSourceID: this.courseId,
2202
- courseID: this.courseId
2203
- }));
2266
+ async getNewCards(limit = 99) {
2267
+ const activeCards = await this.userDB.getActiveCards();
2268
+ return (await this.getCardsCenteredAtELO({ limit, elo: "user" }, (c) => {
2269
+ if (activeCards.some((ac) => c.cardID === ac.cardID)) {
2270
+ return false;
2271
+ } else {
2272
+ return true;
2273
+ }
2274
+ })).map((c) => {
2275
+ return {
2276
+ ...c,
2277
+ status: "new"
2278
+ };
2279
+ });
2204
2280
  }
2205
2281
  async getCardsCenteredAtELO(options, filter) {
2206
2282
  let targetElo = typeof options.elo === "number" ? options.elo : 1e3;
@@ -2381,7 +2457,7 @@ var init_courseDB3 = __esm({
2381
2457
  // Navigation Strategy Manager implementation
2382
2458
  async getNavigationStrategy(_id) {
2383
2459
  return {
2384
- id: "ELO",
2460
+ _id: "NAVIGATION_STRATEGY-ELO",
2385
2461
  docType: "NAVIGATION_STRATEGY" /* NAVIGATION_STRATEGY */,
2386
2462
  name: "ELO",
2387
2463
  description: "ELO-based navigation strategy",
@@ -2446,11 +2522,17 @@ var init_coursesDB = __esm({
2446
2522
  this.manifests = manifests;
2447
2523
  }
2448
2524
  async getCourseConfig(courseId) {
2449
- if (!this.manifests[courseId]) {
2450
- logger.warn(`Course ${courseId} not found`);
2451
- return {};
2525
+ const manifest = this.manifests[courseId];
2526
+ if (!manifest) {
2527
+ logger.warn(`Course manifest for ${courseId} not found`);
2528
+ throw new Error(`Course ${courseId} not found`);
2529
+ }
2530
+ if (manifest.courseConfig) {
2531
+ return manifest.courseConfig;
2532
+ } else {
2533
+ logger.warn(`Course config not found in manifest for course ${courseId}`);
2534
+ throw new Error(`Course config not found for course ${courseId}`);
2452
2535
  }
2453
- return {};
2454
2536
  }
2455
2537
  async getCourseList() {
2456
2538
  return Object.keys(this.manifests).map(
@@ -2538,23 +2620,49 @@ var init_StaticDataLayerProvider = __esm({
2538
2620
  config;
2539
2621
  initialized = false;
2540
2622
  courseUnpackers = /* @__PURE__ */ new Map();
2623
+ manifests = {};
2541
2624
  constructor(config) {
2542
2625
  this.config = {
2543
- staticContentPath: config.staticContentPath || "/static-courses",
2544
2626
  localStoragePrefix: config.localStoragePrefix || "skuilder-static",
2545
- manifests: config.manifests || {}
2627
+ rootManifest: config.rootManifest || { dependencies: {} },
2628
+ rootManifestUrl: config.rootManifestUrl || "/"
2546
2629
  };
2547
2630
  }
2631
+ async resolveCourseDependencies() {
2632
+ logger.info("[StaticDataLayerProvider] Starting course dependency resolution...");
2633
+ const rootManifest = this.config.rootManifest;
2634
+ for (const [courseName, courseUrl] of Object.entries(rootManifest.dependencies || {})) {
2635
+ try {
2636
+ logger.debug(`[StaticDataLayerProvider] Resolving dependency: ${courseName} from ${courseUrl}`);
2637
+ const courseManifestUrl = new URL(courseUrl, this.config.rootManifestUrl).href;
2638
+ const courseJsonResponse = await fetch(courseManifestUrl);
2639
+ if (!courseJsonResponse.ok) {
2640
+ throw new Error(`Failed to fetch course manifest for ${courseName}`);
2641
+ }
2642
+ const courseJson = await courseJsonResponse.json();
2643
+ if (courseJson.content && courseJson.content.manifest) {
2644
+ const baseUrl = new URL(".", courseManifestUrl).href;
2645
+ const finalManifestUrl = new URL(courseJson.content.manifest, courseManifestUrl).href;
2646
+ const finalManifestResponse = await fetch(finalManifestUrl);
2647
+ if (!finalManifestResponse.ok) {
2648
+ throw new Error(`Failed to fetch final content manifest for ${courseName} at ${finalManifestUrl}`);
2649
+ }
2650
+ const finalManifest = await finalManifestResponse.json();
2651
+ this.manifests[courseName] = finalManifest;
2652
+ const unpacker = new StaticDataUnpacker(finalManifest, baseUrl);
2653
+ this.courseUnpackers.set(courseName, unpacker);
2654
+ logger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${courseName}`);
2655
+ }
2656
+ } catch (e) {
2657
+ logger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${courseName}:`, e);
2658
+ }
2659
+ }
2660
+ logger.info("[StaticDataLayerProvider] Course dependency resolution complete.");
2661
+ }
2548
2662
  async initialize() {
2549
2663
  if (this.initialized) return;
2550
2664
  logger.info("Initializing static data layer provider");
2551
- for (const [courseId, manifest] of Object.entries(this.config.manifests)) {
2552
- const unpacker = new StaticDataUnpacker(
2553
- manifest,
2554
- `${this.config.staticContentPath}/${courseId}`
2555
- );
2556
- this.courseUnpackers.set(courseId, unpacker);
2557
- }
2665
+ await this.resolveCourseDependencies();
2558
2666
  this.initialized = true;
2559
2667
  }
2560
2668
  async teardown() {
@@ -2568,13 +2676,13 @@ var init_StaticDataLayerProvider = __esm({
2568
2676
  getCourseDB(courseId) {
2569
2677
  const unpacker = this.courseUnpackers.get(courseId);
2570
2678
  if (!unpacker) {
2571
- throw new Error(`Course ${courseId} not found in static data`);
2679
+ throw new Error(`Course ${courseId} not found or failed to initialize in static data layer.`);
2572
2680
  }
2573
- const manifest = this.config.manifests[courseId];
2681
+ const manifest = this.manifests[courseId];
2574
2682
  return new StaticCourseDB(courseId, unpacker, this.getUserDB(), manifest);
2575
2683
  }
2576
2684
  getCoursesDB() {
2577
- return new StaticCoursesDB(this.config.manifests);
2685
+ return new StaticCoursesDB(this.manifests);
2578
2686
  }
2579
2687
  async getClassroomDB(_classId, _type) {
2580
2688
  throw new Error("Classrooms not supported in static mode");