@vue-skuilder/db 0.1.25 → 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.
@@ -1719,7 +1719,7 @@ var init_hierarchyDefinition = __esm({
1719
1719
  /**
1720
1720
  * CardFilter.transform implementation.
1721
1721
  *
1722
- * Apply prerequisite gating to cards. Cards with locked tags receive score: 0.
1722
+ * Apply prerequisite gating to cards. Cards with locked tags receive score * 0.01.
1723
1723
  */
1724
1724
  async transform(cards, context) {
1725
1725
  const masteredTags = await this.getMasteredTags(context);
@@ -1732,7 +1732,8 @@ var init_hierarchyDefinition = __esm({
1732
1732
  unlockedTags,
1733
1733
  masteredTags
1734
1734
  );
1735
- const finalScore = isUnlocked ? card.score : 0;
1735
+ const LOCKED_PENALTY = 0.01;
1736
+ const finalScore = isUnlocked ? card.score : card.score * LOCKED_PENALTY;
1736
1737
  const action = isUnlocked ? "passed" : "penalized";
1737
1738
  gated.push({
1738
1739
  ...card,
@@ -5781,6 +5782,335 @@ var init_bulkImport = __esm({
5781
5782
  }
5782
5783
  });
5783
5784
 
5785
+ // src/core/UserDBDebugger.ts
5786
+ function getUserDB() {
5787
+ try {
5788
+ const provider = getDataLayer();
5789
+ return provider.getUserDB();
5790
+ } catch {
5791
+ logger.info("[UserDB Debug] Data layer not initialized yet.");
5792
+ return null;
5793
+ }
5794
+ }
5795
+ function getRawDB() {
5796
+ const userDB = getUserDB();
5797
+ if (!userDB) return null;
5798
+ const rawDB = userDB.localDB;
5799
+ if (!rawDB) {
5800
+ logger.info("[UserDB Debug] Unable to access raw database instance.");
5801
+ return null;
5802
+ }
5803
+ return rawDB;
5804
+ }
5805
+ function formatTimestamp(isoString) {
5806
+ const date = new Date(isoString);
5807
+ return date.toLocaleString();
5808
+ }
5809
+ function mountUserDBDebugger() {
5810
+ if (typeof window === "undefined") return;
5811
+ const win = window;
5812
+ win.skuilder = win.skuilder || {};
5813
+ win.skuilder.userdb = userDBDebugAPI;
5814
+ }
5815
+ var userDBDebugAPI;
5816
+ var init_UserDBDebugger = __esm({
5817
+ "src/core/UserDBDebugger.ts"() {
5818
+ "use strict";
5819
+ init_logger();
5820
+ init_factory();
5821
+ init_types_legacy();
5822
+ init_userDBHelpers();
5823
+ userDBDebugAPI = {
5824
+ /**
5825
+ * Show current user information
5826
+ */
5827
+ showUser() {
5828
+ const userDB = getUserDB();
5829
+ if (!userDB) return;
5830
+ console.group("\u{1F464} User Information");
5831
+ logger.info(`Username: ${userDB.getUsername()}`);
5832
+ logger.info(`Logged in: ${userDB.isLoggedIn() ? "Yes \u2705" : "No (Guest) \u274C"}`);
5833
+ userDB.getConfig().then((config) => {
5834
+ logger.info("Configuration:");
5835
+ logger.info(JSON.stringify(config, null, 2));
5836
+ }).catch((err) => {
5837
+ logger.info(`Error loading config: ${err.message}`);
5838
+ }).finally(() => {
5839
+ console.groupEnd();
5840
+ });
5841
+ },
5842
+ /**
5843
+ * Show scheduled reviews
5844
+ */
5845
+ async showScheduledReviews(courseId) {
5846
+ const userDB = getUserDB();
5847
+ if (!userDB) return;
5848
+ try {
5849
+ const reviews = await userDB.getPendingReviews(courseId);
5850
+ console.group(`\u{1F4C5} Scheduled Reviews${courseId ? ` (${courseId})` : ""}`);
5851
+ logger.info(`Total: ${reviews.length}`);
5852
+ if (reviews.length > 0) {
5853
+ const byCourse = /* @__PURE__ */ new Map();
5854
+ for (const review of reviews) {
5855
+ if (!byCourse.has(review.courseId)) {
5856
+ byCourse.set(review.courseId, []);
5857
+ }
5858
+ byCourse.get(review.courseId).push(review);
5859
+ }
5860
+ for (const [course, courseReviews] of byCourse) {
5861
+ console.group(`Course: ${course} (${courseReviews.length} reviews)`);
5862
+ const sorted = courseReviews.sort((a, b) => {
5863
+ const timeA = typeof a.reviewTime === "string" ? a.reviewTime : a.reviewTime.toISOString();
5864
+ const timeB = typeof b.reviewTime === "string" ? b.reviewTime : b.reviewTime.toISOString();
5865
+ return new Date(timeA).getTime() - new Date(timeB).getTime();
5866
+ });
5867
+ for (const review of sorted.slice(0, 10)) {
5868
+ const reviewTimeStr = typeof review.reviewTime === "string" ? review.reviewTime : review.reviewTime.toISOString();
5869
+ logger.info(
5870
+ ` ${review.cardId.slice(0, 12)}... @ ${formatTimestamp(reviewTimeStr)} [${review.scheduledFor}/${review.schedulingAgentId}]`
5871
+ );
5872
+ }
5873
+ if (sorted.length > 10) {
5874
+ logger.info(` ... and ${sorted.length - 10} more`);
5875
+ }
5876
+ console.groupEnd();
5877
+ }
5878
+ }
5879
+ console.groupEnd();
5880
+ } catch (err) {
5881
+ logger.info(`Error loading scheduled reviews: ${err.message}`);
5882
+ }
5883
+ },
5884
+ /**
5885
+ * Show course registrations
5886
+ */
5887
+ async showCourseRegistrations() {
5888
+ const userDB = getUserDB();
5889
+ if (!userDB) return;
5890
+ try {
5891
+ const registrations = await userDB.getActiveCourses();
5892
+ console.group("\u{1F4DA} Course Registrations");
5893
+ logger.info(`Total: ${registrations.length}`);
5894
+ if (registrations.length > 0) {
5895
+ console.table(
5896
+ registrations.map((reg) => ({
5897
+ courseId: reg.courseID,
5898
+ status: reg.status || "active",
5899
+ elo: typeof reg.elo === "number" ? reg.elo.toFixed(0) : reg.elo?.global?.score?.toFixed(0) || "N/A"
5900
+ }))
5901
+ );
5902
+ }
5903
+ console.groupEnd();
5904
+ } catch (err) {
5905
+ logger.info(`Error loading course registrations: ${err.message}`);
5906
+ }
5907
+ },
5908
+ /**
5909
+ * Show card history for a specific card
5910
+ */
5911
+ async showCardHistory(cardId) {
5912
+ const rawDB = getRawDB();
5913
+ if (!rawDB) return;
5914
+ try {
5915
+ const result = await filterAllDocsByPrefix(rawDB, DocTypePrefixes["CARDRECORD" /* CARDRECORD */]);
5916
+ const cardHistories = result.rows.filter((row) => row.doc && row.doc.cardID === cardId).map((row) => row.doc);
5917
+ console.group(`\u{1F3B4} Card History: ${cardId}`);
5918
+ logger.info(`Total interactions: ${cardHistories.length}`);
5919
+ if (cardHistories.length > 0) {
5920
+ const sorted = cardHistories.sort(
5921
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
5922
+ );
5923
+ console.table(
5924
+ sorted.slice(0, 20).map((doc) => ({
5925
+ time: formatTimestamp(doc.timestamp),
5926
+ outcome: doc.outcome || "N/A",
5927
+ duration: doc.duration ? `${(doc.duration / 1e3).toFixed(1)}s` : "N/A",
5928
+ courseId: doc.courseId
5929
+ }))
5930
+ );
5931
+ if (sorted.length > 20) {
5932
+ logger.info(`... and ${sorted.length - 20} more interactions`);
5933
+ }
5934
+ }
5935
+ console.groupEnd();
5936
+ } catch (err) {
5937
+ logger.info(`Error loading card history: ${err.message}`);
5938
+ }
5939
+ },
5940
+ /**
5941
+ * Query documents by type
5942
+ */
5943
+ async queryByType(docType, limit = 50) {
5944
+ const rawDB = getRawDB();
5945
+ if (!rawDB) return;
5946
+ try {
5947
+ const prefix = DocTypePrefixes[DocType[docType]];
5948
+ if (!prefix) {
5949
+ logger.info(`Unknown document type: ${docType}`);
5950
+ return;
5951
+ }
5952
+ const result = await filterAllDocsByPrefix(rawDB, prefix);
5953
+ console.group(`\u{1F4C4} Documents: ${docType}`);
5954
+ logger.info(`Total: ${result.rows.length}`);
5955
+ logger.info(`Prefix: ${prefix}`);
5956
+ if (result.rows.length > 0) {
5957
+ logger.info("Sample documents:");
5958
+ const samples = result.rows.slice(0, Math.min(limit, result.rows.length));
5959
+ for (const row of samples) {
5960
+ logger.info(`
5961
+ ${row.id}:`);
5962
+ logger.info(JSON.stringify(row.doc, null, 2));
5963
+ }
5964
+ if (result.rows.length > limit) {
5965
+ logger.info(`
5966
+ ... and ${result.rows.length - limit} more documents`);
5967
+ }
5968
+ }
5969
+ console.groupEnd();
5970
+ } catch (err) {
5971
+ logger.info(`Error querying documents: ${err.message}`);
5972
+ }
5973
+ },
5974
+ /**
5975
+ * Show database info and statistics
5976
+ */
5977
+ async dbInfo() {
5978
+ const rawDB = getRawDB();
5979
+ if (!rawDB) return;
5980
+ try {
5981
+ const info = await rawDB.info();
5982
+ console.group("\u2139\uFE0F Database Information");
5983
+ logger.info(`Database name: ${info.db_name}`);
5984
+ logger.info(`Total documents: ${info.doc_count}`);
5985
+ logger.info(`Update sequence: ${info.update_seq}`);
5986
+ if ("disk_size" in info) {
5987
+ logger.info(`Disk size: ${(info.disk_size || 0) / 1024 / 1024} MB`);
5988
+ }
5989
+ logger.info("\nDocument counts by type:");
5990
+ const allDocs = await rawDB.allDocs({ include_docs: false });
5991
+ const typeCounts = /* @__PURE__ */ new Map();
5992
+ for (const row of allDocs.rows) {
5993
+ let prefix = "other";
5994
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
5995
+ if (row.id.startsWith(typePrefix)) {
5996
+ prefix = type;
5997
+ break;
5998
+ }
5999
+ }
6000
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
6001
+ }
6002
+ console.table(
6003
+ Array.from(typeCounts.entries()).sort((a, b) => b[1] - a[1]).map(([type, count]) => ({ type, count }))
6004
+ );
6005
+ console.groupEnd();
6006
+ } catch (err) {
6007
+ logger.info(`Error getting database info: ${err.message}`);
6008
+ }
6009
+ },
6010
+ /**
6011
+ * List all document types
6012
+ */
6013
+ listDocTypes() {
6014
+ console.group("\u{1F4CB} Available Document Types");
6015
+ logger.info("Use with queryByType(type):");
6016
+ for (const [type, prefix] of Object.entries(DocTypePrefixes)) {
6017
+ logger.info(` ${type.padEnd(30)} \u2192 prefix: "${prefix}"`);
6018
+ }
6019
+ console.groupEnd();
6020
+ },
6021
+ /**
6022
+ * Export database contents (limited, for debugging)
6023
+ */
6024
+ async export(includeContent = false) {
6025
+ const rawDB = getRawDB();
6026
+ const userDB = getUserDB();
6027
+ if (!rawDB || !userDB) return "{}";
6028
+ try {
6029
+ const data = {
6030
+ username: userDB.getUsername(),
6031
+ loggedIn: userDB.isLoggedIn(),
6032
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
6033
+ };
6034
+ if (includeContent) {
6035
+ const allDocs = await rawDB.allDocs({ include_docs: true });
6036
+ data.documents = allDocs.rows.map((row) => ({
6037
+ id: row.id,
6038
+ doc: row.doc
6039
+ }));
6040
+ data.totalDocs = allDocs.rows.length;
6041
+ } else {
6042
+ const allDocs = await rawDB.allDocs({ include_docs: false });
6043
+ data.totalDocs = allDocs.rows.length;
6044
+ const typeCounts = /* @__PURE__ */ new Map();
6045
+ for (const row of allDocs.rows) {
6046
+ let prefix = "other";
6047
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
6048
+ if (row.id.startsWith(typePrefix)) {
6049
+ prefix = type;
6050
+ break;
6051
+ }
6052
+ }
6053
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
6054
+ }
6055
+ data.docCounts = Object.fromEntries(typeCounts);
6056
+ }
6057
+ const json = JSON.stringify(data, null, 2);
6058
+ logger.info("[UserDB Debug] Database info exported. Copy the returned string or use:");
6059
+ logger.info(" copy(window.skuilder.userdb.export())");
6060
+ if (!includeContent) {
6061
+ logger.info(" For full content export: window.skuilder.userdb.export(true)");
6062
+ }
6063
+ return json;
6064
+ } catch (err) {
6065
+ logger.info(`Error exporting database: ${err.message}`);
6066
+ return "{}";
6067
+ }
6068
+ },
6069
+ /**
6070
+ * Execute raw PouchDB query
6071
+ */
6072
+ async raw(queryFn) {
6073
+ const rawDB = getRawDB();
6074
+ if (!rawDB) return;
6075
+ try {
6076
+ const result = await queryFn(rawDB);
6077
+ logger.info("[UserDB Debug] Query result:");
6078
+ logger.info(result);
6079
+ } catch (err) {
6080
+ logger.info(`[UserDB Debug] Query error: ${err.message}`);
6081
+ }
6082
+ },
6083
+ /**
6084
+ * Show help
6085
+ */
6086
+ help() {
6087
+ logger.info(`
6088
+ \u{1F527} UserDB Debug API
6089
+
6090
+ Commands:
6091
+ .showUser() Show current user info and config
6092
+ .showScheduledReviews(courseId?) Show scheduled reviews (optionally filter by course)
6093
+ .showCourseRegistrations() Show all course registrations
6094
+ .showCardHistory(cardId) Show interaction history for a card
6095
+ .queryByType(docType, limit?) Query documents by type (e.g., 'SCHEDULED_CARD')
6096
+ .listDocTypes() List all available document types
6097
+ .dbInfo() Show database info and statistics
6098
+ .export(includeContent?) Export database info (true = include all docs)
6099
+ .raw(queryFn) Execute raw PouchDB query
6100
+ .help() Show this help message
6101
+
6102
+ Examples:
6103
+ window.skuilder.userdb.showUser()
6104
+ window.skuilder.userdb.showScheduledReviews('course123')
6105
+ window.skuilder.userdb.queryByType('SCHEDULED_CARD', 10)
6106
+ window.skuilder.userdb.raw(db => db.allDocs({ limit: 5 }))
6107
+ `);
6108
+ }
6109
+ };
6110
+ mountUserDBDebugger();
6111
+ }
6112
+ });
6113
+
5784
6114
  // src/core/index.ts
5785
6115
  var init_core = __esm({
5786
6116
  "src/core/index.ts"() {
@@ -5794,6 +6124,7 @@ var init_core = __esm({
5794
6124
  init_navigators();
5795
6125
  init_bulkImport();
5796
6126
  init_orchestration();
6127
+ init_UserDBDebugger();
5797
6128
  }
5798
6129
  });
5799
6130
  init_core();
@@ -5831,6 +6162,7 @@ export {
5831
6162
  isReview,
5832
6163
  log,
5833
6164
  mountPipelineDebugger,
6165
+ mountUserDBDebugger,
5834
6166
  parseCardHistoryID,
5835
6167
  pipelineDebugAPI,
5836
6168
  recordUserOutcome,
@@ -5839,6 +6171,7 @@ export {
5839
6171
  scoreAccuracyInZone,
5840
6172
  updateLearningState,
5841
6173
  updateStrategyWeight,
6174
+ userDBDebugAPI,
5842
6175
  validateProcessorConfig
5843
6176
  };
5844
6177
  //# sourceMappingURL=index.mjs.map