@vue-skuilder/db 0.1.26 → 0.1.28

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.
@@ -263,7 +263,7 @@ var init_updateQueue = __esm({
263
263
  });
264
264
 
265
265
  // src/core/types/types-legacy.ts
266
- var GuestUsername, log, DocTypePrefixes;
266
+ var GuestUsername, log, DocType, DocTypePrefixes;
267
267
  var init_types_legacy = __esm({
268
268
  "src/core/types/types-legacy.ts"() {
269
269
  "use strict";
@@ -272,6 +272,22 @@ var init_types_legacy = __esm({
272
272
  log = (message) => {
273
273
  logger.log(message);
274
274
  };
275
+ DocType = /* @__PURE__ */ ((DocType2) => {
276
+ DocType2["DISPLAYABLE_DATA"] = "DISPLAYABLE_DATA";
277
+ DocType2["CARD"] = "CARD";
278
+ DocType2["DATASHAPE"] = "DATASHAPE";
279
+ DocType2["QUESTIONTYPE"] = "QUESTION";
280
+ DocType2["VIEW"] = "VIEW";
281
+ DocType2["PEDAGOGY"] = "PEDAGOGY";
282
+ DocType2["CARDRECORD"] = "CARDRECORD";
283
+ DocType2["SCHEDULED_CARD"] = "SCHEDULED_CARD";
284
+ DocType2["TAG"] = "TAG";
285
+ DocType2["NAVIGATION_STRATEGY"] = "NAVIGATION_STRATEGY";
286
+ DocType2["STRATEGY_STATE"] = "STRATEGY_STATE";
287
+ DocType2["USER_OUTCOME"] = "USER_OUTCOME";
288
+ DocType2["STRATEGY_LEARNING_STATE"] = "STRATEGY_LEARNING_STATE";
289
+ return DocType2;
290
+ })(DocType || {});
275
291
  DocTypePrefixes = {
276
292
  ["CARD" /* CARD */]: "c",
277
293
  ["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]: "dd",
@@ -1650,7 +1666,7 @@ var init_hierarchyDefinition = __esm({
1650
1666
  /**
1651
1667
  * CardFilter.transform implementation.
1652
1668
  *
1653
- * Apply prerequisite gating to cards. Cards with locked tags receive score: 0.
1669
+ * Apply prerequisite gating to cards. Cards with locked tags receive score * 0.01.
1654
1670
  */
1655
1671
  async transform(cards, context) {
1656
1672
  const masteredTags = await this.getMasteredTags(context);
@@ -1663,7 +1679,8 @@ var init_hierarchyDefinition = __esm({
1663
1679
  unlockedTags,
1664
1680
  masteredTags
1665
1681
  );
1666
- const finalScore = isUnlocked ? card.score : 0;
1682
+ const LOCKED_PENALTY = 0.01;
1683
+ const finalScore = isUnlocked ? card.score : card.score * LOCKED_PENALTY;
1667
1684
  const action = isUnlocked ? "passed" : "penalized";
1668
1685
  gated.push({
1669
1686
  ...card,
@@ -4413,23 +4430,6 @@ var init_bulkImport = __esm({
4413
4430
  }
4414
4431
  });
4415
4432
 
4416
- // src/core/index.ts
4417
- var init_core = __esm({
4418
- "src/core/index.ts"() {
4419
- "use strict";
4420
- init_interfaces();
4421
- init_types_legacy();
4422
- init_user();
4423
- init_strategyState();
4424
- init_userOutcome();
4425
- init_Loggable();
4426
- init_util();
4427
- init_navigators();
4428
- init_bulkImport();
4429
- init_orchestration();
4430
- }
4431
- });
4432
-
4433
4433
  // src/util/dataDirectory.ts
4434
4434
  function getAppDataDirectory() {
4435
4435
  if (ENV.LOCAL_STORAGE_PREFIX) {
@@ -4544,6 +4544,353 @@ var init_userDBHelpers = __esm({
4544
4544
  }
4545
4545
  });
4546
4546
 
4547
+ // src/core/UserDBDebugger.ts
4548
+ function getUserDB() {
4549
+ try {
4550
+ const provider = getDataLayer();
4551
+ return provider.getUserDB();
4552
+ } catch {
4553
+ logger.info("[UserDB Debug] Data layer not initialized yet.");
4554
+ return null;
4555
+ }
4556
+ }
4557
+ function getRawDB() {
4558
+ const userDB = getUserDB();
4559
+ if (!userDB) return null;
4560
+ const rawDB = userDB.localDB;
4561
+ if (!rawDB) {
4562
+ logger.info("[UserDB Debug] Unable to access raw database instance.");
4563
+ return null;
4564
+ }
4565
+ return rawDB;
4566
+ }
4567
+ function formatTimestamp(isoString) {
4568
+ const date = new Date(isoString);
4569
+ return date.toLocaleString();
4570
+ }
4571
+ function mountUserDBDebugger() {
4572
+ if (typeof window === "undefined") return;
4573
+ const win = window;
4574
+ win.skuilder = win.skuilder || {};
4575
+ win.skuilder.userdb = userDBDebugAPI;
4576
+ }
4577
+ var userDBDebugAPI;
4578
+ var init_UserDBDebugger = __esm({
4579
+ "src/core/UserDBDebugger.ts"() {
4580
+ "use strict";
4581
+ init_logger();
4582
+ init_factory();
4583
+ init_types_legacy();
4584
+ init_userDBHelpers();
4585
+ userDBDebugAPI = {
4586
+ /**
4587
+ * Show current user information
4588
+ */
4589
+ showUser() {
4590
+ const userDB = getUserDB();
4591
+ if (!userDB) return;
4592
+ console.group("\u{1F464} User Information");
4593
+ logger.info(`Username: ${userDB.getUsername()}`);
4594
+ logger.info(`Logged in: ${userDB.isLoggedIn() ? "Yes \u2705" : "No (Guest) \u274C"}`);
4595
+ userDB.getConfig().then((config) => {
4596
+ logger.info("Configuration:");
4597
+ logger.info(JSON.stringify(config, null, 2));
4598
+ }).catch((err) => {
4599
+ logger.info(`Error loading config: ${err.message}`);
4600
+ }).finally(() => {
4601
+ console.groupEnd();
4602
+ });
4603
+ },
4604
+ /**
4605
+ * Show scheduled reviews
4606
+ */
4607
+ async showScheduledReviews(courseId) {
4608
+ const userDB = getUserDB();
4609
+ if (!userDB) return;
4610
+ try {
4611
+ const reviews = await userDB.getPendingReviews(courseId);
4612
+ console.group(`\u{1F4C5} Scheduled Reviews${courseId ? ` (${courseId})` : ""}`);
4613
+ logger.info(`Total: ${reviews.length}`);
4614
+ if (reviews.length > 0) {
4615
+ const byCourse = /* @__PURE__ */ new Map();
4616
+ for (const review of reviews) {
4617
+ if (!byCourse.has(review.courseId)) {
4618
+ byCourse.set(review.courseId, []);
4619
+ }
4620
+ byCourse.get(review.courseId).push(review);
4621
+ }
4622
+ for (const [course, courseReviews] of byCourse) {
4623
+ console.group(`Course: ${course} (${courseReviews.length} reviews)`);
4624
+ const sorted = courseReviews.sort((a, b) => {
4625
+ const timeA = typeof a.reviewTime === "string" ? a.reviewTime : a.reviewTime.toISOString();
4626
+ const timeB = typeof b.reviewTime === "string" ? b.reviewTime : b.reviewTime.toISOString();
4627
+ return new Date(timeA).getTime() - new Date(timeB).getTime();
4628
+ });
4629
+ for (const review of sorted.slice(0, 10)) {
4630
+ const reviewTimeStr = typeof review.reviewTime === "string" ? review.reviewTime : review.reviewTime.toISOString();
4631
+ logger.info(
4632
+ ` ${review.cardId.slice(0, 12)}... @ ${formatTimestamp(reviewTimeStr)} [${review.scheduledFor}/${review.schedulingAgentId}]`
4633
+ );
4634
+ }
4635
+ if (sorted.length > 10) {
4636
+ logger.info(` ... and ${sorted.length - 10} more`);
4637
+ }
4638
+ console.groupEnd();
4639
+ }
4640
+ }
4641
+ console.groupEnd();
4642
+ } catch (err) {
4643
+ logger.info(`Error loading scheduled reviews: ${err.message}`);
4644
+ }
4645
+ },
4646
+ /**
4647
+ * Show course registrations
4648
+ */
4649
+ async showCourseRegistrations() {
4650
+ const userDB = getUserDB();
4651
+ if (!userDB) return;
4652
+ try {
4653
+ const registrations = await userDB.getActiveCourses();
4654
+ console.group("\u{1F4DA} Course Registrations");
4655
+ logger.info(`Total: ${registrations.length}`);
4656
+ if (registrations.length > 0) {
4657
+ console.table(
4658
+ registrations.map((reg) => ({
4659
+ courseId: reg.courseID,
4660
+ status: reg.status || "active",
4661
+ elo: typeof reg.elo === "number" ? reg.elo.toFixed(0) : reg.elo?.global?.score?.toFixed(0) || "N/A"
4662
+ }))
4663
+ );
4664
+ }
4665
+ console.groupEnd();
4666
+ } catch (err) {
4667
+ logger.info(`Error loading course registrations: ${err.message}`);
4668
+ }
4669
+ },
4670
+ /**
4671
+ * Show card history for a specific card
4672
+ */
4673
+ async showCardHistory(cardId) {
4674
+ const rawDB = getRawDB();
4675
+ if (!rawDB) return;
4676
+ try {
4677
+ const result = await filterAllDocsByPrefix2(rawDB, DocTypePrefixes["CARDRECORD" /* CARDRECORD */]);
4678
+ const cardHistories = result.rows.filter((row) => row.doc && row.doc.cardID === cardId).map((row) => row.doc);
4679
+ console.group(`\u{1F3B4} Card History: ${cardId}`);
4680
+ logger.info(`Total interactions: ${cardHistories.length}`);
4681
+ if (cardHistories.length > 0) {
4682
+ const sorted = cardHistories.sort(
4683
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
4684
+ );
4685
+ console.table(
4686
+ sorted.slice(0, 20).map((doc) => ({
4687
+ time: formatTimestamp(doc.timestamp),
4688
+ outcome: doc.outcome || "N/A",
4689
+ duration: doc.duration ? `${(doc.duration / 1e3).toFixed(1)}s` : "N/A",
4690
+ courseId: doc.courseId
4691
+ }))
4692
+ );
4693
+ if (sorted.length > 20) {
4694
+ logger.info(`... and ${sorted.length - 20} more interactions`);
4695
+ }
4696
+ }
4697
+ console.groupEnd();
4698
+ } catch (err) {
4699
+ logger.info(`Error loading card history: ${err.message}`);
4700
+ }
4701
+ },
4702
+ /**
4703
+ * Query documents by type
4704
+ */
4705
+ async queryByType(docType, limit = 50) {
4706
+ const rawDB = getRawDB();
4707
+ if (!rawDB) return;
4708
+ try {
4709
+ const prefix = DocTypePrefixes[DocType[docType]];
4710
+ if (!prefix) {
4711
+ logger.info(`Unknown document type: ${docType}`);
4712
+ return;
4713
+ }
4714
+ const result = await filterAllDocsByPrefix2(rawDB, prefix);
4715
+ console.group(`\u{1F4C4} Documents: ${docType}`);
4716
+ logger.info(`Total: ${result.rows.length}`);
4717
+ logger.info(`Prefix: ${prefix}`);
4718
+ if (result.rows.length > 0) {
4719
+ logger.info("Sample documents:");
4720
+ const samples = result.rows.slice(0, Math.min(limit, result.rows.length));
4721
+ for (const row of samples) {
4722
+ logger.info(`
4723
+ ${row.id}:`);
4724
+ logger.info(JSON.stringify(row.doc, null, 2));
4725
+ }
4726
+ if (result.rows.length > limit) {
4727
+ logger.info(`
4728
+ ... and ${result.rows.length - limit} more documents`);
4729
+ }
4730
+ }
4731
+ console.groupEnd();
4732
+ } catch (err) {
4733
+ logger.info(`Error querying documents: ${err.message}`);
4734
+ }
4735
+ },
4736
+ /**
4737
+ * Show database info and statistics
4738
+ */
4739
+ async dbInfo() {
4740
+ const rawDB = getRawDB();
4741
+ if (!rawDB) return;
4742
+ try {
4743
+ const info = await rawDB.info();
4744
+ console.group("\u2139\uFE0F Database Information");
4745
+ logger.info(`Database name: ${info.db_name}`);
4746
+ logger.info(`Total documents: ${info.doc_count}`);
4747
+ logger.info(`Update sequence: ${info.update_seq}`);
4748
+ if ("disk_size" in info) {
4749
+ logger.info(`Disk size: ${(info.disk_size || 0) / 1024 / 1024} MB`);
4750
+ }
4751
+ logger.info("\nDocument counts by type:");
4752
+ const allDocs = await rawDB.allDocs({ include_docs: false });
4753
+ const typeCounts = /* @__PURE__ */ new Map();
4754
+ for (const row of allDocs.rows) {
4755
+ let prefix = "other";
4756
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
4757
+ if (row.id.startsWith(typePrefix)) {
4758
+ prefix = type;
4759
+ break;
4760
+ }
4761
+ }
4762
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
4763
+ }
4764
+ console.table(
4765
+ Array.from(typeCounts.entries()).sort((a, b) => b[1] - a[1]).map(([type, count]) => ({ type, count }))
4766
+ );
4767
+ console.groupEnd();
4768
+ } catch (err) {
4769
+ logger.info(`Error getting database info: ${err.message}`);
4770
+ }
4771
+ },
4772
+ /**
4773
+ * List all document types
4774
+ */
4775
+ listDocTypes() {
4776
+ console.group("\u{1F4CB} Available Document Types");
4777
+ logger.info("Use with queryByType(type):");
4778
+ for (const [type, prefix] of Object.entries(DocTypePrefixes)) {
4779
+ logger.info(` ${type.padEnd(30)} \u2192 prefix: "${prefix}"`);
4780
+ }
4781
+ console.groupEnd();
4782
+ },
4783
+ /**
4784
+ * Export database contents (limited, for debugging)
4785
+ */
4786
+ async export(includeContent = false) {
4787
+ const rawDB = getRawDB();
4788
+ const userDB = getUserDB();
4789
+ if (!rawDB || !userDB) return "{}";
4790
+ try {
4791
+ const data = {
4792
+ username: userDB.getUsername(),
4793
+ loggedIn: userDB.isLoggedIn(),
4794
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4795
+ };
4796
+ if (includeContent) {
4797
+ const allDocs = await rawDB.allDocs({ include_docs: true });
4798
+ data.documents = allDocs.rows.map((row) => ({
4799
+ id: row.id,
4800
+ doc: row.doc
4801
+ }));
4802
+ data.totalDocs = allDocs.rows.length;
4803
+ } else {
4804
+ const allDocs = await rawDB.allDocs({ include_docs: false });
4805
+ data.totalDocs = allDocs.rows.length;
4806
+ const typeCounts = /* @__PURE__ */ new Map();
4807
+ for (const row of allDocs.rows) {
4808
+ let prefix = "other";
4809
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
4810
+ if (row.id.startsWith(typePrefix)) {
4811
+ prefix = type;
4812
+ break;
4813
+ }
4814
+ }
4815
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
4816
+ }
4817
+ data.docCounts = Object.fromEntries(typeCounts);
4818
+ }
4819
+ const json = JSON.stringify(data, null, 2);
4820
+ logger.info("[UserDB Debug] Database info exported. Copy the returned string or use:");
4821
+ logger.info(" copy(window.skuilder.userdb.export())");
4822
+ if (!includeContent) {
4823
+ logger.info(" For full content export: window.skuilder.userdb.export(true)");
4824
+ }
4825
+ return json;
4826
+ } catch (err) {
4827
+ logger.info(`Error exporting database: ${err.message}`);
4828
+ return "{}";
4829
+ }
4830
+ },
4831
+ /**
4832
+ * Execute raw PouchDB query
4833
+ */
4834
+ async raw(queryFn) {
4835
+ const rawDB = getRawDB();
4836
+ if (!rawDB) return;
4837
+ try {
4838
+ const result = await queryFn(rawDB);
4839
+ logger.info("[UserDB Debug] Query result:");
4840
+ logger.info(result);
4841
+ } catch (err) {
4842
+ logger.info(`[UserDB Debug] Query error: ${err.message}`);
4843
+ }
4844
+ },
4845
+ /**
4846
+ * Show help
4847
+ */
4848
+ help() {
4849
+ logger.info(`
4850
+ \u{1F527} UserDB Debug API
4851
+
4852
+ Commands:
4853
+ .showUser() Show current user info and config
4854
+ .showScheduledReviews(courseId?) Show scheduled reviews (optionally filter by course)
4855
+ .showCourseRegistrations() Show all course registrations
4856
+ .showCardHistory(cardId) Show interaction history for a card
4857
+ .queryByType(docType, limit?) Query documents by type (e.g., 'SCHEDULED_CARD')
4858
+ .listDocTypes() List all available document types
4859
+ .dbInfo() Show database info and statistics
4860
+ .export(includeContent?) Export database info (true = include all docs)
4861
+ .raw(queryFn) Execute raw PouchDB query
4862
+ .help() Show this help message
4863
+
4864
+ Examples:
4865
+ window.skuilder.userdb.showUser()
4866
+ window.skuilder.userdb.showScheduledReviews('course123')
4867
+ window.skuilder.userdb.queryByType('SCHEDULED_CARD', 10)
4868
+ window.skuilder.userdb.raw(db => db.allDocs({ limit: 5 }))
4869
+ `);
4870
+ }
4871
+ };
4872
+ mountUserDBDebugger();
4873
+ }
4874
+ });
4875
+
4876
+ // src/core/index.ts
4877
+ var init_core = __esm({
4878
+ "src/core/index.ts"() {
4879
+ "use strict";
4880
+ init_interfaces();
4881
+ init_types_legacy();
4882
+ init_user();
4883
+ init_strategyState();
4884
+ init_userOutcome();
4885
+ init_Loggable();
4886
+ init_util();
4887
+ init_navigators();
4888
+ init_bulkImport();
4889
+ init_orchestration();
4890
+ init_UserDBDebugger();
4891
+ }
4892
+ });
4893
+
4547
4894
  // src/impl/couch/user-course-relDB.ts
4548
4895
  var import_moment4, UsrCrsData;
4549
4896
  var init_user_course_relDB = __esm({