@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
@@ -279,7 +279,9 @@ var init_updateQueue = __esm({
279
279
  async applyUpdates(id) {
280
280
  logger.debug(`Applying updates on doc: ${id}`);
281
281
  if (this.inprogressUpdates[id]) {
282
- await this.readDB.info();
282
+ while (this.inprogressUpdates[id]) {
283
+ await new Promise((resolve) => setTimeout(resolve, Math.random() * 50));
284
+ }
283
285
  return this.applyUpdates(id);
284
286
  } else {
285
287
  if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
@@ -315,6 +317,9 @@ var init_updateQueue = __esm({
315
317
  if (e.name === "conflict" && i < MAX_RETRIES - 1) {
316
318
  logger.warn(`Conflict on update for doc ${id}, retry #${i + 1}`);
317
319
  await new Promise((res) => setTimeout(res, 50 * Math.random()));
320
+ } else if (e.name === "not_found" && i === 0) {
321
+ logger.warn(`Update failed for ${id} - does not exist. Throwing to caller.`);
322
+ throw e;
318
323
  } else {
319
324
  delete this.inprogressUpdates[id];
320
325
  if (this.pendingUpdates[id]) {
@@ -510,12 +515,74 @@ var init_elo = __esm({
510
515
  }
511
516
  });
512
517
 
518
+ // src/core/navigators/hardcodedOrder.ts
519
+ var hardcodedOrder_exports = {};
520
+ __export(hardcodedOrder_exports, {
521
+ default: () => HardcodedOrderNavigator
522
+ });
523
+ var HardcodedOrderNavigator;
524
+ var init_hardcodedOrder = __esm({
525
+ "src/core/navigators/hardcodedOrder.ts"() {
526
+ "use strict";
527
+ init_navigators();
528
+ init_logger();
529
+ HardcodedOrderNavigator = class extends ContentNavigator {
530
+ orderedCardIds = [];
531
+ user;
532
+ course;
533
+ constructor(user, course, strategyData) {
534
+ super();
535
+ this.user = user;
536
+ this.course = course;
537
+ if (strategyData.serializedData) {
538
+ try {
539
+ this.orderedCardIds = JSON.parse(strategyData.serializedData);
540
+ } catch (e) {
541
+ logger.error("Failed to parse serializedData for HardcodedOrderNavigator", e);
542
+ }
543
+ }
544
+ }
545
+ async getPendingReviews() {
546
+ const reviews = await this.user.getPendingReviews(this.course.getCourseID());
547
+ return reviews.map((r) => {
548
+ return {
549
+ ...r,
550
+ contentSourceType: "course",
551
+ contentSourceID: this.course.getCourseID(),
552
+ cardID: r.cardId,
553
+ courseID: r.courseId,
554
+ reviewID: r._id,
555
+ status: "review"
556
+ };
557
+ });
558
+ }
559
+ async getNewCards(limit = 99) {
560
+ const activeCardIds = (await this.user.getActiveCards()).map((c) => c.cardID);
561
+ const newCardIds = this.orderedCardIds.filter(
562
+ (cardId) => !activeCardIds.includes(cardId)
563
+ );
564
+ const cardsToReturn = newCardIds.slice(0, limit);
565
+ return cardsToReturn.map((cardId) => {
566
+ return {
567
+ cardID: cardId,
568
+ courseID: this.course.getCourseID(),
569
+ contentSourceType: "course",
570
+ contentSourceID: this.course.getCourseID(),
571
+ status: "new"
572
+ };
573
+ });
574
+ }
575
+ };
576
+ }
577
+ });
578
+
513
579
  // import("./**/*") in src/core/navigators/index.ts
514
580
  var globImport;
515
581
  var init_ = __esm({
516
582
  'import("./**/*") in src/core/navigators/index.ts'() {
517
583
  globImport = __glob({
518
584
  "./elo.ts": () => Promise.resolve().then(() => (init_elo(), elo_exports)),
585
+ "./hardcodedOrder.ts": () => Promise.resolve().then(() => (init_hardcodedOrder(), hardcodedOrder_exports)),
519
586
  "./index.ts": () => Promise.resolve().then(() => (init_navigators(), navigators_exports))
520
587
  });
521
588
  }
@@ -535,6 +602,7 @@ var init_navigators = __esm({
535
602
  init_();
536
603
  Navigators = /* @__PURE__ */ ((Navigators2) => {
537
604
  Navigators2["ELO"] = "elo";
605
+ Navigators2["HARDCODED"] = "hardcodedOrder";
538
606
  return Navigators2;
539
607
  })(Navigators || {});
540
608
  ContentNavigator = class {
@@ -1369,17 +1437,21 @@ Currently logged-in as ${this._username}.`
1369
1437
  } catch (e) {
1370
1438
  const reason = e;
1371
1439
  if (reason.status === 404) {
1372
- const initCardHistory = {
1373
- _id: cardHistoryID,
1374
- cardID: record.cardID,
1375
- courseID: record.courseID,
1376
- records: [record],
1377
- lapses: 0,
1378
- streak: 0,
1379
- bestInterval: 0
1380
- };
1381
- const putResult = await this.writeDB.put(initCardHistory);
1382
- return { ...initCardHistory, _rev: putResult.rev };
1440
+ try {
1441
+ const initCardHistory = {
1442
+ _id: cardHistoryID,
1443
+ cardID: record.cardID,
1444
+ courseID: record.courseID,
1445
+ records: [record],
1446
+ lapses: 0,
1447
+ streak: 0,
1448
+ bestInterval: 0
1449
+ };
1450
+ const putResult = await this.writeDB.put(initCardHistory);
1451
+ return { ...initCardHistory, _rev: putResult.rev };
1452
+ } catch (creationError) {
1453
+ throw new Error(`Failed to create CardHistory for ${cardHistoryID}. Reason: ${creationError}`);
1454
+ }
1383
1455
  } else {
1384
1456
  throw new Error(`putCardRecord failed because of:
1385
1457
  name:${reason.name}
@@ -2167,16 +2239,20 @@ var init_courseDB3 = __esm({
2167
2239
  async updateCardElo(cardId, _elo) {
2168
2240
  return { ok: true, id: cardId, rev: "1-static" };
2169
2241
  }
2170
- async getNewCards(limit) {
2171
- const cardIds = await this.unpacker.queryByElo(1e3, limit || 10);
2172
- return cardIds.map((cardId) => ({
2173
- status: "new",
2174
- qualifiedID: `${this.courseId}-${cardId}`,
2175
- cardID: cardId,
2176
- contentSourceType: "course",
2177
- contentSourceID: this.courseId,
2178
- courseID: this.courseId
2179
- }));
2242
+ async getNewCards(limit = 99) {
2243
+ const activeCards = await this.userDB.getActiveCards();
2244
+ return (await this.getCardsCenteredAtELO({ limit, elo: "user" }, (c) => {
2245
+ if (activeCards.some((ac) => c.cardID === ac.cardID)) {
2246
+ return false;
2247
+ } else {
2248
+ return true;
2249
+ }
2250
+ })).map((c) => {
2251
+ return {
2252
+ ...c,
2253
+ status: "new"
2254
+ };
2255
+ });
2180
2256
  }
2181
2257
  async getCardsCenteredAtELO(options, filter) {
2182
2258
  let targetElo = typeof options.elo === "number" ? options.elo : 1e3;
@@ -2357,7 +2433,7 @@ var init_courseDB3 = __esm({
2357
2433
  // Navigation Strategy Manager implementation
2358
2434
  async getNavigationStrategy(_id) {
2359
2435
  return {
2360
- id: "ELO",
2436
+ _id: "NAVIGATION_STRATEGY-ELO",
2361
2437
  docType: "NAVIGATION_STRATEGY" /* NAVIGATION_STRATEGY */,
2362
2438
  name: "ELO",
2363
2439
  description: "ELO-based navigation strategy",
@@ -2422,11 +2498,17 @@ var init_coursesDB = __esm({
2422
2498
  this.manifests = manifests;
2423
2499
  }
2424
2500
  async getCourseConfig(courseId) {
2425
- if (!this.manifests[courseId]) {
2426
- logger.warn(`Course ${courseId} not found`);
2427
- return {};
2501
+ const manifest = this.manifests[courseId];
2502
+ if (!manifest) {
2503
+ logger.warn(`Course manifest for ${courseId} not found`);
2504
+ throw new Error(`Course ${courseId} not found`);
2505
+ }
2506
+ if (manifest.courseConfig) {
2507
+ return manifest.courseConfig;
2508
+ } else {
2509
+ logger.warn(`Course config not found in manifest for course ${courseId}`);
2510
+ throw new Error(`Course config not found for course ${courseId}`);
2428
2511
  }
2429
- return {};
2430
2512
  }
2431
2513
  async getCourseList() {
2432
2514
  return Object.keys(this.manifests).map(
@@ -2514,23 +2596,49 @@ var init_StaticDataLayerProvider = __esm({
2514
2596
  config;
2515
2597
  initialized = false;
2516
2598
  courseUnpackers = /* @__PURE__ */ new Map();
2599
+ manifests = {};
2517
2600
  constructor(config) {
2518
2601
  this.config = {
2519
- staticContentPath: config.staticContentPath || "/static-courses",
2520
2602
  localStoragePrefix: config.localStoragePrefix || "skuilder-static",
2521
- manifests: config.manifests || {}
2603
+ rootManifest: config.rootManifest || { dependencies: {} },
2604
+ rootManifestUrl: config.rootManifestUrl || "/"
2522
2605
  };
2523
2606
  }
2607
+ async resolveCourseDependencies() {
2608
+ logger.info("[StaticDataLayerProvider] Starting course dependency resolution...");
2609
+ const rootManifest = this.config.rootManifest;
2610
+ for (const [courseName, courseUrl] of Object.entries(rootManifest.dependencies || {})) {
2611
+ try {
2612
+ logger.debug(`[StaticDataLayerProvider] Resolving dependency: ${courseName} from ${courseUrl}`);
2613
+ const courseManifestUrl = new URL(courseUrl, this.config.rootManifestUrl).href;
2614
+ const courseJsonResponse = await fetch(courseManifestUrl);
2615
+ if (!courseJsonResponse.ok) {
2616
+ throw new Error(`Failed to fetch course manifest for ${courseName}`);
2617
+ }
2618
+ const courseJson = await courseJsonResponse.json();
2619
+ if (courseJson.content && courseJson.content.manifest) {
2620
+ const baseUrl = new URL(".", courseManifestUrl).href;
2621
+ const finalManifestUrl = new URL(courseJson.content.manifest, courseManifestUrl).href;
2622
+ const finalManifestResponse = await fetch(finalManifestUrl);
2623
+ if (!finalManifestResponse.ok) {
2624
+ throw new Error(`Failed to fetch final content manifest for ${courseName} at ${finalManifestUrl}`);
2625
+ }
2626
+ const finalManifest = await finalManifestResponse.json();
2627
+ this.manifests[courseName] = finalManifest;
2628
+ const unpacker = new StaticDataUnpacker(finalManifest, baseUrl);
2629
+ this.courseUnpackers.set(courseName, unpacker);
2630
+ logger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${courseName}`);
2631
+ }
2632
+ } catch (e) {
2633
+ logger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${courseName}:`, e);
2634
+ }
2635
+ }
2636
+ logger.info("[StaticDataLayerProvider] Course dependency resolution complete.");
2637
+ }
2524
2638
  async initialize() {
2525
2639
  if (this.initialized) return;
2526
2640
  logger.info("Initializing static data layer provider");
2527
- for (const [courseId, manifest] of Object.entries(this.config.manifests)) {
2528
- const unpacker = new StaticDataUnpacker(
2529
- manifest,
2530
- `${this.config.staticContentPath}/${courseId}`
2531
- );
2532
- this.courseUnpackers.set(courseId, unpacker);
2533
- }
2641
+ await this.resolveCourseDependencies();
2534
2642
  this.initialized = true;
2535
2643
  }
2536
2644
  async teardown() {
@@ -2544,13 +2652,13 @@ var init_StaticDataLayerProvider = __esm({
2544
2652
  getCourseDB(courseId) {
2545
2653
  const unpacker = this.courseUnpackers.get(courseId);
2546
2654
  if (!unpacker) {
2547
- throw new Error(`Course ${courseId} not found in static data`);
2655
+ throw new Error(`Course ${courseId} not found or failed to initialize in static data layer.`);
2548
2656
  }
2549
- const manifest = this.config.manifests[courseId];
2657
+ const manifest = this.manifests[courseId];
2550
2658
  return new StaticCourseDB(courseId, unpacker, this.getUserDB(), manifest);
2551
2659
  }
2552
2660
  getCoursesDB() {
2553
- return new StaticCoursesDB(this.config.manifests);
2661
+ return new StaticCoursesDB(this.manifests);
2554
2662
  }
2555
2663
  async getClassroomDB(_classId, _type) {
2556
2664
  throw new Error("Classrooms not supported in static mode");