@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.
package/dist/index.mjs CHANGED
@@ -1872,7 +1872,7 @@ var init_hierarchyDefinition = __esm({
1872
1872
  /**
1873
1873
  * CardFilter.transform implementation.
1874
1874
  *
1875
- * Apply prerequisite gating to cards. Cards with locked tags receive score: 0.
1875
+ * Apply prerequisite gating to cards. Cards with locked tags receive score * 0.01.
1876
1876
  */
1877
1877
  async transform(cards, context) {
1878
1878
  const masteredTags = await this.getMasteredTags(context);
@@ -1885,7 +1885,8 @@ var init_hierarchyDefinition = __esm({
1885
1885
  unlockedTags,
1886
1886
  masteredTags
1887
1887
  );
1888
- const finalScore = isUnlocked ? card.score : 0;
1888
+ const LOCKED_PENALTY = 0.01;
1889
+ const finalScore = isUnlocked ? card.score : card.score * LOCKED_PENALTY;
1889
1890
  const action = isUnlocked ? "passed" : "penalized";
1890
1891
  gated.push({
1891
1892
  ...card,
@@ -7587,6 +7588,335 @@ var init_bulkImport = __esm({
7587
7588
  }
7588
7589
  });
7589
7590
 
7591
+ // src/core/UserDBDebugger.ts
7592
+ function getUserDB() {
7593
+ try {
7594
+ const provider = getDataLayer();
7595
+ return provider.getUserDB();
7596
+ } catch {
7597
+ logger.info("[UserDB Debug] Data layer not initialized yet.");
7598
+ return null;
7599
+ }
7600
+ }
7601
+ function getRawDB() {
7602
+ const userDB = getUserDB();
7603
+ if (!userDB) return null;
7604
+ const rawDB = userDB.localDB;
7605
+ if (!rawDB) {
7606
+ logger.info("[UserDB Debug] Unable to access raw database instance.");
7607
+ return null;
7608
+ }
7609
+ return rawDB;
7610
+ }
7611
+ function formatTimestamp(isoString) {
7612
+ const date = new Date(isoString);
7613
+ return date.toLocaleString();
7614
+ }
7615
+ function mountUserDBDebugger() {
7616
+ if (typeof window === "undefined") return;
7617
+ const win = window;
7618
+ win.skuilder = win.skuilder || {};
7619
+ win.skuilder.userdb = userDBDebugAPI;
7620
+ }
7621
+ var userDBDebugAPI;
7622
+ var init_UserDBDebugger = __esm({
7623
+ "src/core/UserDBDebugger.ts"() {
7624
+ "use strict";
7625
+ init_logger();
7626
+ init_factory();
7627
+ init_types_legacy();
7628
+ init_userDBHelpers();
7629
+ userDBDebugAPI = {
7630
+ /**
7631
+ * Show current user information
7632
+ */
7633
+ showUser() {
7634
+ const userDB = getUserDB();
7635
+ if (!userDB) return;
7636
+ console.group("\u{1F464} User Information");
7637
+ logger.info(`Username: ${userDB.getUsername()}`);
7638
+ logger.info(`Logged in: ${userDB.isLoggedIn() ? "Yes \u2705" : "No (Guest) \u274C"}`);
7639
+ userDB.getConfig().then((config) => {
7640
+ logger.info("Configuration:");
7641
+ logger.info(JSON.stringify(config, null, 2));
7642
+ }).catch((err) => {
7643
+ logger.info(`Error loading config: ${err.message}`);
7644
+ }).finally(() => {
7645
+ console.groupEnd();
7646
+ });
7647
+ },
7648
+ /**
7649
+ * Show scheduled reviews
7650
+ */
7651
+ async showScheduledReviews(courseId) {
7652
+ const userDB = getUserDB();
7653
+ if (!userDB) return;
7654
+ try {
7655
+ const reviews = await userDB.getPendingReviews(courseId);
7656
+ console.group(`\u{1F4C5} Scheduled Reviews${courseId ? ` (${courseId})` : ""}`);
7657
+ logger.info(`Total: ${reviews.length}`);
7658
+ if (reviews.length > 0) {
7659
+ const byCourse = /* @__PURE__ */ new Map();
7660
+ for (const review of reviews) {
7661
+ if (!byCourse.has(review.courseId)) {
7662
+ byCourse.set(review.courseId, []);
7663
+ }
7664
+ byCourse.get(review.courseId).push(review);
7665
+ }
7666
+ for (const [course, courseReviews] of byCourse) {
7667
+ console.group(`Course: ${course} (${courseReviews.length} reviews)`);
7668
+ const sorted = courseReviews.sort((a, b) => {
7669
+ const timeA = typeof a.reviewTime === "string" ? a.reviewTime : a.reviewTime.toISOString();
7670
+ const timeB = typeof b.reviewTime === "string" ? b.reviewTime : b.reviewTime.toISOString();
7671
+ return new Date(timeA).getTime() - new Date(timeB).getTime();
7672
+ });
7673
+ for (const review of sorted.slice(0, 10)) {
7674
+ const reviewTimeStr = typeof review.reviewTime === "string" ? review.reviewTime : review.reviewTime.toISOString();
7675
+ logger.info(
7676
+ ` ${review.cardId.slice(0, 12)}... @ ${formatTimestamp(reviewTimeStr)} [${review.scheduledFor}/${review.schedulingAgentId}]`
7677
+ );
7678
+ }
7679
+ if (sorted.length > 10) {
7680
+ logger.info(` ... and ${sorted.length - 10} more`);
7681
+ }
7682
+ console.groupEnd();
7683
+ }
7684
+ }
7685
+ console.groupEnd();
7686
+ } catch (err) {
7687
+ logger.info(`Error loading scheduled reviews: ${err.message}`);
7688
+ }
7689
+ },
7690
+ /**
7691
+ * Show course registrations
7692
+ */
7693
+ async showCourseRegistrations() {
7694
+ const userDB = getUserDB();
7695
+ if (!userDB) return;
7696
+ try {
7697
+ const registrations = await userDB.getActiveCourses();
7698
+ console.group("\u{1F4DA} Course Registrations");
7699
+ logger.info(`Total: ${registrations.length}`);
7700
+ if (registrations.length > 0) {
7701
+ console.table(
7702
+ registrations.map((reg) => ({
7703
+ courseId: reg.courseID,
7704
+ status: reg.status || "active",
7705
+ elo: typeof reg.elo === "number" ? reg.elo.toFixed(0) : reg.elo?.global?.score?.toFixed(0) || "N/A"
7706
+ }))
7707
+ );
7708
+ }
7709
+ console.groupEnd();
7710
+ } catch (err) {
7711
+ logger.info(`Error loading course registrations: ${err.message}`);
7712
+ }
7713
+ },
7714
+ /**
7715
+ * Show card history for a specific card
7716
+ */
7717
+ async showCardHistory(cardId) {
7718
+ const rawDB = getRawDB();
7719
+ if (!rawDB) return;
7720
+ try {
7721
+ const result = await filterAllDocsByPrefix(rawDB, DocTypePrefixes["CARDRECORD" /* CARDRECORD */]);
7722
+ const cardHistories = result.rows.filter((row) => row.doc && row.doc.cardID === cardId).map((row) => row.doc);
7723
+ console.group(`\u{1F3B4} Card History: ${cardId}`);
7724
+ logger.info(`Total interactions: ${cardHistories.length}`);
7725
+ if (cardHistories.length > 0) {
7726
+ const sorted = cardHistories.sort(
7727
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
7728
+ );
7729
+ console.table(
7730
+ sorted.slice(0, 20).map((doc) => ({
7731
+ time: formatTimestamp(doc.timestamp),
7732
+ outcome: doc.outcome || "N/A",
7733
+ duration: doc.duration ? `${(doc.duration / 1e3).toFixed(1)}s` : "N/A",
7734
+ courseId: doc.courseId
7735
+ }))
7736
+ );
7737
+ if (sorted.length > 20) {
7738
+ logger.info(`... and ${sorted.length - 20} more interactions`);
7739
+ }
7740
+ }
7741
+ console.groupEnd();
7742
+ } catch (err) {
7743
+ logger.info(`Error loading card history: ${err.message}`);
7744
+ }
7745
+ },
7746
+ /**
7747
+ * Query documents by type
7748
+ */
7749
+ async queryByType(docType, limit = 50) {
7750
+ const rawDB = getRawDB();
7751
+ if (!rawDB) return;
7752
+ try {
7753
+ const prefix = DocTypePrefixes[DocType[docType]];
7754
+ if (!prefix) {
7755
+ logger.info(`Unknown document type: ${docType}`);
7756
+ return;
7757
+ }
7758
+ const result = await filterAllDocsByPrefix(rawDB, prefix);
7759
+ console.group(`\u{1F4C4} Documents: ${docType}`);
7760
+ logger.info(`Total: ${result.rows.length}`);
7761
+ logger.info(`Prefix: ${prefix}`);
7762
+ if (result.rows.length > 0) {
7763
+ logger.info("Sample documents:");
7764
+ const samples = result.rows.slice(0, Math.min(limit, result.rows.length));
7765
+ for (const row of samples) {
7766
+ logger.info(`
7767
+ ${row.id}:`);
7768
+ logger.info(JSON.stringify(row.doc, null, 2));
7769
+ }
7770
+ if (result.rows.length > limit) {
7771
+ logger.info(`
7772
+ ... and ${result.rows.length - limit} more documents`);
7773
+ }
7774
+ }
7775
+ console.groupEnd();
7776
+ } catch (err) {
7777
+ logger.info(`Error querying documents: ${err.message}`);
7778
+ }
7779
+ },
7780
+ /**
7781
+ * Show database info and statistics
7782
+ */
7783
+ async dbInfo() {
7784
+ const rawDB = getRawDB();
7785
+ if (!rawDB) return;
7786
+ try {
7787
+ const info = await rawDB.info();
7788
+ console.group("\u2139\uFE0F Database Information");
7789
+ logger.info(`Database name: ${info.db_name}`);
7790
+ logger.info(`Total documents: ${info.doc_count}`);
7791
+ logger.info(`Update sequence: ${info.update_seq}`);
7792
+ if ("disk_size" in info) {
7793
+ logger.info(`Disk size: ${(info.disk_size || 0) / 1024 / 1024} MB`);
7794
+ }
7795
+ logger.info("\nDocument counts by type:");
7796
+ const allDocs = await rawDB.allDocs({ include_docs: false });
7797
+ const typeCounts = /* @__PURE__ */ new Map();
7798
+ for (const row of allDocs.rows) {
7799
+ let prefix = "other";
7800
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
7801
+ if (row.id.startsWith(typePrefix)) {
7802
+ prefix = type;
7803
+ break;
7804
+ }
7805
+ }
7806
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
7807
+ }
7808
+ console.table(
7809
+ Array.from(typeCounts.entries()).sort((a, b) => b[1] - a[1]).map(([type, count]) => ({ type, count }))
7810
+ );
7811
+ console.groupEnd();
7812
+ } catch (err) {
7813
+ logger.info(`Error getting database info: ${err.message}`);
7814
+ }
7815
+ },
7816
+ /**
7817
+ * List all document types
7818
+ */
7819
+ listDocTypes() {
7820
+ console.group("\u{1F4CB} Available Document Types");
7821
+ logger.info("Use with queryByType(type):");
7822
+ for (const [type, prefix] of Object.entries(DocTypePrefixes)) {
7823
+ logger.info(` ${type.padEnd(30)} \u2192 prefix: "${prefix}"`);
7824
+ }
7825
+ console.groupEnd();
7826
+ },
7827
+ /**
7828
+ * Export database contents (limited, for debugging)
7829
+ */
7830
+ async export(includeContent = false) {
7831
+ const rawDB = getRawDB();
7832
+ const userDB = getUserDB();
7833
+ if (!rawDB || !userDB) return "{}";
7834
+ try {
7835
+ const data = {
7836
+ username: userDB.getUsername(),
7837
+ loggedIn: userDB.isLoggedIn(),
7838
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7839
+ };
7840
+ if (includeContent) {
7841
+ const allDocs = await rawDB.allDocs({ include_docs: true });
7842
+ data.documents = allDocs.rows.map((row) => ({
7843
+ id: row.id,
7844
+ doc: row.doc
7845
+ }));
7846
+ data.totalDocs = allDocs.rows.length;
7847
+ } else {
7848
+ const allDocs = await rawDB.allDocs({ include_docs: false });
7849
+ data.totalDocs = allDocs.rows.length;
7850
+ const typeCounts = /* @__PURE__ */ new Map();
7851
+ for (const row of allDocs.rows) {
7852
+ let prefix = "other";
7853
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
7854
+ if (row.id.startsWith(typePrefix)) {
7855
+ prefix = type;
7856
+ break;
7857
+ }
7858
+ }
7859
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
7860
+ }
7861
+ data.docCounts = Object.fromEntries(typeCounts);
7862
+ }
7863
+ const json = JSON.stringify(data, null, 2);
7864
+ logger.info("[UserDB Debug] Database info exported. Copy the returned string or use:");
7865
+ logger.info(" copy(window.skuilder.userdb.export())");
7866
+ if (!includeContent) {
7867
+ logger.info(" For full content export: window.skuilder.userdb.export(true)");
7868
+ }
7869
+ return json;
7870
+ } catch (err) {
7871
+ logger.info(`Error exporting database: ${err.message}`);
7872
+ return "{}";
7873
+ }
7874
+ },
7875
+ /**
7876
+ * Execute raw PouchDB query
7877
+ */
7878
+ async raw(queryFn) {
7879
+ const rawDB = getRawDB();
7880
+ if (!rawDB) return;
7881
+ try {
7882
+ const result = await queryFn(rawDB);
7883
+ logger.info("[UserDB Debug] Query result:");
7884
+ logger.info(result);
7885
+ } catch (err) {
7886
+ logger.info(`[UserDB Debug] Query error: ${err.message}`);
7887
+ }
7888
+ },
7889
+ /**
7890
+ * Show help
7891
+ */
7892
+ help() {
7893
+ logger.info(`
7894
+ \u{1F527} UserDB Debug API
7895
+
7896
+ Commands:
7897
+ .showUser() Show current user info and config
7898
+ .showScheduledReviews(courseId?) Show scheduled reviews (optionally filter by course)
7899
+ .showCourseRegistrations() Show all course registrations
7900
+ .showCardHistory(cardId) Show interaction history for a card
7901
+ .queryByType(docType, limit?) Query documents by type (e.g., 'SCHEDULED_CARD')
7902
+ .listDocTypes() List all available document types
7903
+ .dbInfo() Show database info and statistics
7904
+ .export(includeContent?) Export database info (true = include all docs)
7905
+ .raw(queryFn) Execute raw PouchDB query
7906
+ .help() Show this help message
7907
+
7908
+ Examples:
7909
+ window.skuilder.userdb.showUser()
7910
+ window.skuilder.userdb.showScheduledReviews('course123')
7911
+ window.skuilder.userdb.queryByType('SCHEDULED_CARD', 10)
7912
+ window.skuilder.userdb.raw(db => db.allDocs({ limit: 5 }))
7913
+ `);
7914
+ }
7915
+ };
7916
+ mountUserDBDebugger();
7917
+ }
7918
+ });
7919
+
7590
7920
  // src/core/index.ts
7591
7921
  var init_core = __esm({
7592
7922
  "src/core/index.ts"() {
@@ -7601,6 +7931,7 @@ var init_core = __esm({
7601
7931
  init_navigators();
7602
7932
  init_bulkImport();
7603
7933
  init_orchestration();
7934
+ init_UserDBDebugger();
7604
7935
  }
7605
7936
  });
7606
7937
 
@@ -11250,6 +11581,7 @@ export {
11250
11581
  mountMixerDebugger,
11251
11582
  mountPipelineDebugger,
11252
11583
  mountSessionDebugger,
11584
+ mountUserDBDebugger,
11253
11585
  newInterval,
11254
11586
  parseCardHistoryID,
11255
11587
  pipelineDebugAPI,
@@ -11272,6 +11604,7 @@ export {
11272
11604
  startSessionTracking,
11273
11605
  updateLearningState,
11274
11606
  updateStrategyWeight,
11607
+ userDBDebugAPI,
11275
11608
  validateMigration,
11276
11609
  validateProcessorConfig,
11277
11610
  validateStaticCourse