@vue-skuilder/db 0.1.26 → 0.1.27

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