@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.
package/dist/index.d.cts CHANGED
@@ -4,7 +4,7 @@ import { D as DataLayerProvider } from './dataLayerProvider-BeRXVMs5.cjs';
4
4
  import { C as CardHistory, c as CardRecord } from './types-legacy-JXDxinpU.cjs';
5
5
  export { d as CardData, e as CourseListData, g as DataShapeData, f as DisplayableData, D as DocType, b as DocTypePrefixes, F as Field, G as GuestUsername, Q as QualifiedCardID, h as QuestionData, i as QuestionRecord, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from './types-legacy-JXDxinpU.cjs';
6
6
  import { Loggable } from './core/index.cjs';
7
- export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, CardGenerator, CardGeneratorFactory, FilterContext, FilterImpact, GeneratorContext, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, validateProcessorConfig } from './core/index.cjs';
7
+ export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, CardGenerator, CardGeneratorFactory, FilterContext, FilterImpact, GeneratorContext, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig } from './core/index.cjs';
8
8
  import { TaggedPerformance, TagFilter, DataShape, CourseConfig } from '@vue-skuilder/common';
9
9
  import { S as StaticCourseManifest } from './types-W8n-B6HG.cjs';
10
10
  export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-W8n-B6HG.cjs';
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { D as DataLayerProvider } from './dataLayerProvider-CG9GfaAY.js';
4
4
  import { C as CardHistory, c as CardRecord } from './types-legacy-JXDxinpU.js';
5
5
  export { d as CardData, e as CourseListData, g as DataShapeData, f as DisplayableData, D as DocType, b as DocTypePrefixes, F as Field, G as GuestUsername, Q as QualifiedCardID, h as QuestionData, i as QuestionRecord, S as SkuilderCourseData, a as Tag, T as TagStub, l as log } from './types-legacy-JXDxinpU.js';
6
6
  import { Loggable } from './core/index.js';
7
- export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, CardGenerator, CardGeneratorFactory, FilterContext, FilterImpact, GeneratorContext, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, validateProcessorConfig } from './core/index.js';
7
+ export { BulkCardProcessorConfig, CardFilter, CardFilterFactory, CardGenerator, CardGeneratorFactory, FilterContext, FilterImpact, GeneratorContext, GeneratorSummary, GradientObservation, GradientResult, ImportResult, PeriodUpdateInput, PeriodUpdateResult, PipelineRunReport, SignalConfig, StrategyLearningState, StrategyStateDoc, StrategyStateId, aggregateOutcomesForGradient, areQuestionRecords, buildStrategyStateId, computeOutcomeSignal, computeStrategyGradient, docIsDeleted, getCardHistoryID, getDefaultLearnableWeight, importParsedCards, isQuestionRecord, mountPipelineDebugger, mountUserDBDebugger, parseCardHistoryID, pipelineDebugAPI, recordUserOutcome, runPeriodUpdate, scoreAccuracyInZone, updateLearningState, updateStrategyWeight, userDBDebugAPI, validateProcessorConfig } from './core/index.js';
8
8
  import { TaggedPerformance, TagFilter, DataShape, CourseConfig } from '@vue-skuilder/common';
9
9
  import { S as StaticCourseManifest } from './types-CJrLM1Ew.js';
10
10
  export { A as AttachmentData, C as ChunkMetadata, D as DesignDocument, I as IndexMetadata, a as PackedCourseData, P as PackerConfig } from './types-CJrLM1Ew.js';
package/dist/index.js CHANGED
@@ -1895,7 +1895,7 @@ var init_hierarchyDefinition = __esm({
1895
1895
  /**
1896
1896
  * CardFilter.transform implementation.
1897
1897
  *
1898
- * Apply prerequisite gating to cards. Cards with locked tags receive score: 0.
1898
+ * Apply prerequisite gating to cards. Cards with locked tags receive score * 0.01.
1899
1899
  */
1900
1900
  async transform(cards, context) {
1901
1901
  const masteredTags = await this.getMasteredTags(context);
@@ -1908,7 +1908,8 @@ var init_hierarchyDefinition = __esm({
1908
1908
  unlockedTags,
1909
1909
  masteredTags
1910
1910
  );
1911
- const finalScore = isUnlocked ? card.score : 0;
1911
+ const LOCKED_PENALTY = 0.01;
1912
+ const finalScore = isUnlocked ? card.score : card.score * LOCKED_PENALTY;
1912
1913
  const action = isUnlocked ? "passed" : "penalized";
1913
1914
  gated.push({
1914
1915
  ...card,
@@ -7608,6 +7609,335 @@ var init_bulkImport = __esm({
7608
7609
  }
7609
7610
  });
7610
7611
 
7612
+ // src/core/UserDBDebugger.ts
7613
+ function getUserDB() {
7614
+ try {
7615
+ const provider = getDataLayer();
7616
+ return provider.getUserDB();
7617
+ } catch {
7618
+ logger.info("[UserDB Debug] Data layer not initialized yet.");
7619
+ return null;
7620
+ }
7621
+ }
7622
+ function getRawDB() {
7623
+ const userDB = getUserDB();
7624
+ if (!userDB) return null;
7625
+ const rawDB = userDB.localDB;
7626
+ if (!rawDB) {
7627
+ logger.info("[UserDB Debug] Unable to access raw database instance.");
7628
+ return null;
7629
+ }
7630
+ return rawDB;
7631
+ }
7632
+ function formatTimestamp(isoString) {
7633
+ const date = new Date(isoString);
7634
+ return date.toLocaleString();
7635
+ }
7636
+ function mountUserDBDebugger() {
7637
+ if (typeof window === "undefined") return;
7638
+ const win = window;
7639
+ win.skuilder = win.skuilder || {};
7640
+ win.skuilder.userdb = userDBDebugAPI;
7641
+ }
7642
+ var userDBDebugAPI;
7643
+ var init_UserDBDebugger = __esm({
7644
+ "src/core/UserDBDebugger.ts"() {
7645
+ "use strict";
7646
+ init_logger();
7647
+ init_factory();
7648
+ init_types_legacy();
7649
+ init_userDBHelpers();
7650
+ userDBDebugAPI = {
7651
+ /**
7652
+ * Show current user information
7653
+ */
7654
+ showUser() {
7655
+ const userDB = getUserDB();
7656
+ if (!userDB) return;
7657
+ console.group("\u{1F464} User Information");
7658
+ logger.info(`Username: ${userDB.getUsername()}`);
7659
+ logger.info(`Logged in: ${userDB.isLoggedIn() ? "Yes \u2705" : "No (Guest) \u274C"}`);
7660
+ userDB.getConfig().then((config) => {
7661
+ logger.info("Configuration:");
7662
+ logger.info(JSON.stringify(config, null, 2));
7663
+ }).catch((err) => {
7664
+ logger.info(`Error loading config: ${err.message}`);
7665
+ }).finally(() => {
7666
+ console.groupEnd();
7667
+ });
7668
+ },
7669
+ /**
7670
+ * Show scheduled reviews
7671
+ */
7672
+ async showScheduledReviews(courseId) {
7673
+ const userDB = getUserDB();
7674
+ if (!userDB) return;
7675
+ try {
7676
+ const reviews = await userDB.getPendingReviews(courseId);
7677
+ console.group(`\u{1F4C5} Scheduled Reviews${courseId ? ` (${courseId})` : ""}`);
7678
+ logger.info(`Total: ${reviews.length}`);
7679
+ if (reviews.length > 0) {
7680
+ const byCourse = /* @__PURE__ */ new Map();
7681
+ for (const review of reviews) {
7682
+ if (!byCourse.has(review.courseId)) {
7683
+ byCourse.set(review.courseId, []);
7684
+ }
7685
+ byCourse.get(review.courseId).push(review);
7686
+ }
7687
+ for (const [course, courseReviews] of byCourse) {
7688
+ console.group(`Course: ${course} (${courseReviews.length} reviews)`);
7689
+ const sorted = courseReviews.sort((a, b) => {
7690
+ const timeA = typeof a.reviewTime === "string" ? a.reviewTime : a.reviewTime.toISOString();
7691
+ const timeB = typeof b.reviewTime === "string" ? b.reviewTime : b.reviewTime.toISOString();
7692
+ return new Date(timeA).getTime() - new Date(timeB).getTime();
7693
+ });
7694
+ for (const review of sorted.slice(0, 10)) {
7695
+ const reviewTimeStr = typeof review.reviewTime === "string" ? review.reviewTime : review.reviewTime.toISOString();
7696
+ logger.info(
7697
+ ` ${review.cardId.slice(0, 12)}... @ ${formatTimestamp(reviewTimeStr)} [${review.scheduledFor}/${review.schedulingAgentId}]`
7698
+ );
7699
+ }
7700
+ if (sorted.length > 10) {
7701
+ logger.info(` ... and ${sorted.length - 10} more`);
7702
+ }
7703
+ console.groupEnd();
7704
+ }
7705
+ }
7706
+ console.groupEnd();
7707
+ } catch (err) {
7708
+ logger.info(`Error loading scheduled reviews: ${err.message}`);
7709
+ }
7710
+ },
7711
+ /**
7712
+ * Show course registrations
7713
+ */
7714
+ async showCourseRegistrations() {
7715
+ const userDB = getUserDB();
7716
+ if (!userDB) return;
7717
+ try {
7718
+ const registrations = await userDB.getActiveCourses();
7719
+ console.group("\u{1F4DA} Course Registrations");
7720
+ logger.info(`Total: ${registrations.length}`);
7721
+ if (registrations.length > 0) {
7722
+ console.table(
7723
+ registrations.map((reg) => ({
7724
+ courseId: reg.courseID,
7725
+ status: reg.status || "active",
7726
+ elo: typeof reg.elo === "number" ? reg.elo.toFixed(0) : reg.elo?.global?.score?.toFixed(0) || "N/A"
7727
+ }))
7728
+ );
7729
+ }
7730
+ console.groupEnd();
7731
+ } catch (err) {
7732
+ logger.info(`Error loading course registrations: ${err.message}`);
7733
+ }
7734
+ },
7735
+ /**
7736
+ * Show card history for a specific card
7737
+ */
7738
+ async showCardHistory(cardId) {
7739
+ const rawDB = getRawDB();
7740
+ if (!rawDB) return;
7741
+ try {
7742
+ const result = await filterAllDocsByPrefix(rawDB, DocTypePrefixes["CARDRECORD" /* CARDRECORD */]);
7743
+ const cardHistories = result.rows.filter((row) => row.doc && row.doc.cardID === cardId).map((row) => row.doc);
7744
+ console.group(`\u{1F3B4} Card History: ${cardId}`);
7745
+ logger.info(`Total interactions: ${cardHistories.length}`);
7746
+ if (cardHistories.length > 0) {
7747
+ const sorted = cardHistories.sort(
7748
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
7749
+ );
7750
+ console.table(
7751
+ sorted.slice(0, 20).map((doc) => ({
7752
+ time: formatTimestamp(doc.timestamp),
7753
+ outcome: doc.outcome || "N/A",
7754
+ duration: doc.duration ? `${(doc.duration / 1e3).toFixed(1)}s` : "N/A",
7755
+ courseId: doc.courseId
7756
+ }))
7757
+ );
7758
+ if (sorted.length > 20) {
7759
+ logger.info(`... and ${sorted.length - 20} more interactions`);
7760
+ }
7761
+ }
7762
+ console.groupEnd();
7763
+ } catch (err) {
7764
+ logger.info(`Error loading card history: ${err.message}`);
7765
+ }
7766
+ },
7767
+ /**
7768
+ * Query documents by type
7769
+ */
7770
+ async queryByType(docType, limit = 50) {
7771
+ const rawDB = getRawDB();
7772
+ if (!rawDB) return;
7773
+ try {
7774
+ const prefix = DocTypePrefixes[DocType[docType]];
7775
+ if (!prefix) {
7776
+ logger.info(`Unknown document type: ${docType}`);
7777
+ return;
7778
+ }
7779
+ const result = await filterAllDocsByPrefix(rawDB, prefix);
7780
+ console.group(`\u{1F4C4} Documents: ${docType}`);
7781
+ logger.info(`Total: ${result.rows.length}`);
7782
+ logger.info(`Prefix: ${prefix}`);
7783
+ if (result.rows.length > 0) {
7784
+ logger.info("Sample documents:");
7785
+ const samples = result.rows.slice(0, Math.min(limit, result.rows.length));
7786
+ for (const row of samples) {
7787
+ logger.info(`
7788
+ ${row.id}:`);
7789
+ logger.info(JSON.stringify(row.doc, null, 2));
7790
+ }
7791
+ if (result.rows.length > limit) {
7792
+ logger.info(`
7793
+ ... and ${result.rows.length - limit} more documents`);
7794
+ }
7795
+ }
7796
+ console.groupEnd();
7797
+ } catch (err) {
7798
+ logger.info(`Error querying documents: ${err.message}`);
7799
+ }
7800
+ },
7801
+ /**
7802
+ * Show database info and statistics
7803
+ */
7804
+ async dbInfo() {
7805
+ const rawDB = getRawDB();
7806
+ if (!rawDB) return;
7807
+ try {
7808
+ const info = await rawDB.info();
7809
+ console.group("\u2139\uFE0F Database Information");
7810
+ logger.info(`Database name: ${info.db_name}`);
7811
+ logger.info(`Total documents: ${info.doc_count}`);
7812
+ logger.info(`Update sequence: ${info.update_seq}`);
7813
+ if ("disk_size" in info) {
7814
+ logger.info(`Disk size: ${(info.disk_size || 0) / 1024 / 1024} MB`);
7815
+ }
7816
+ logger.info("\nDocument counts by type:");
7817
+ const allDocs = await rawDB.allDocs({ include_docs: false });
7818
+ const typeCounts = /* @__PURE__ */ new Map();
7819
+ for (const row of allDocs.rows) {
7820
+ let prefix = "other";
7821
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
7822
+ if (row.id.startsWith(typePrefix)) {
7823
+ prefix = type;
7824
+ break;
7825
+ }
7826
+ }
7827
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
7828
+ }
7829
+ console.table(
7830
+ Array.from(typeCounts.entries()).sort((a, b) => b[1] - a[1]).map(([type, count]) => ({ type, count }))
7831
+ );
7832
+ console.groupEnd();
7833
+ } catch (err) {
7834
+ logger.info(`Error getting database info: ${err.message}`);
7835
+ }
7836
+ },
7837
+ /**
7838
+ * List all document types
7839
+ */
7840
+ listDocTypes() {
7841
+ console.group("\u{1F4CB} Available Document Types");
7842
+ logger.info("Use with queryByType(type):");
7843
+ for (const [type, prefix] of Object.entries(DocTypePrefixes)) {
7844
+ logger.info(` ${type.padEnd(30)} \u2192 prefix: "${prefix}"`);
7845
+ }
7846
+ console.groupEnd();
7847
+ },
7848
+ /**
7849
+ * Export database contents (limited, for debugging)
7850
+ */
7851
+ async export(includeContent = false) {
7852
+ const rawDB = getRawDB();
7853
+ const userDB = getUserDB();
7854
+ if (!rawDB || !userDB) return "{}";
7855
+ try {
7856
+ const data = {
7857
+ username: userDB.getUsername(),
7858
+ loggedIn: userDB.isLoggedIn(),
7859
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7860
+ };
7861
+ if (includeContent) {
7862
+ const allDocs = await rawDB.allDocs({ include_docs: true });
7863
+ data.documents = allDocs.rows.map((row) => ({
7864
+ id: row.id,
7865
+ doc: row.doc
7866
+ }));
7867
+ data.totalDocs = allDocs.rows.length;
7868
+ } else {
7869
+ const allDocs = await rawDB.allDocs({ include_docs: false });
7870
+ data.totalDocs = allDocs.rows.length;
7871
+ const typeCounts = /* @__PURE__ */ new Map();
7872
+ for (const row of allDocs.rows) {
7873
+ let prefix = "other";
7874
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
7875
+ if (row.id.startsWith(typePrefix)) {
7876
+ prefix = type;
7877
+ break;
7878
+ }
7879
+ }
7880
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
7881
+ }
7882
+ data.docCounts = Object.fromEntries(typeCounts);
7883
+ }
7884
+ const json = JSON.stringify(data, null, 2);
7885
+ logger.info("[UserDB Debug] Database info exported. Copy the returned string or use:");
7886
+ logger.info(" copy(window.skuilder.userdb.export())");
7887
+ if (!includeContent) {
7888
+ logger.info(" For full content export: window.skuilder.userdb.export(true)");
7889
+ }
7890
+ return json;
7891
+ } catch (err) {
7892
+ logger.info(`Error exporting database: ${err.message}`);
7893
+ return "{}";
7894
+ }
7895
+ },
7896
+ /**
7897
+ * Execute raw PouchDB query
7898
+ */
7899
+ async raw(queryFn) {
7900
+ const rawDB = getRawDB();
7901
+ if (!rawDB) return;
7902
+ try {
7903
+ const result = await queryFn(rawDB);
7904
+ logger.info("[UserDB Debug] Query result:");
7905
+ logger.info(result);
7906
+ } catch (err) {
7907
+ logger.info(`[UserDB Debug] Query error: ${err.message}`);
7908
+ }
7909
+ },
7910
+ /**
7911
+ * Show help
7912
+ */
7913
+ help() {
7914
+ logger.info(`
7915
+ \u{1F527} UserDB Debug API
7916
+
7917
+ Commands:
7918
+ .showUser() Show current user info and config
7919
+ .showScheduledReviews(courseId?) Show scheduled reviews (optionally filter by course)
7920
+ .showCourseRegistrations() Show all course registrations
7921
+ .showCardHistory(cardId) Show interaction history for a card
7922
+ .queryByType(docType, limit?) Query documents by type (e.g., 'SCHEDULED_CARD')
7923
+ .listDocTypes() List all available document types
7924
+ .dbInfo() Show database info and statistics
7925
+ .export(includeContent?) Export database info (true = include all docs)
7926
+ .raw(queryFn) Execute raw PouchDB query
7927
+ .help() Show this help message
7928
+
7929
+ Examples:
7930
+ window.skuilder.userdb.showUser()
7931
+ window.skuilder.userdb.showScheduledReviews('course123')
7932
+ window.skuilder.userdb.queryByType('SCHEDULED_CARD', 10)
7933
+ window.skuilder.userdb.raw(db => db.allDocs({ limit: 5 }))
7934
+ `);
7935
+ }
7936
+ };
7937
+ mountUserDBDebugger();
7938
+ }
7939
+ });
7940
+
7611
7941
  // src/core/index.ts
7612
7942
  var init_core = __esm({
7613
7943
  "src/core/index.ts"() {
@@ -7622,6 +7952,7 @@ var init_core = __esm({
7622
7952
  init_navigators();
7623
7953
  init_bulkImport();
7624
7954
  init_orchestration();
7955
+ init_UserDBDebugger();
7625
7956
  }
7626
7957
  });
7627
7958
 
@@ -7685,6 +8016,7 @@ __export(index_exports, {
7685
8016
  mountMixerDebugger: () => mountMixerDebugger,
7686
8017
  mountPipelineDebugger: () => mountPipelineDebugger,
7687
8018
  mountSessionDebugger: () => mountSessionDebugger,
8019
+ mountUserDBDebugger: () => mountUserDBDebugger,
7688
8020
  newInterval: () => newInterval,
7689
8021
  parseCardHistoryID: () => parseCardHistoryID,
7690
8022
  pipelineDebugAPI: () => pipelineDebugAPI,
@@ -7707,6 +8039,7 @@ __export(index_exports, {
7707
8039
  startSessionTracking: () => startSessionTracking,
7708
8040
  updateLearningState: () => updateLearningState,
7709
8041
  updateStrategyWeight: () => updateStrategyWeight,
8042
+ userDBDebugAPI: () => userDBDebugAPI,
7710
8043
  validateMigration: () => validateMigration,
7711
8044
  validateProcessorConfig: () => validateProcessorConfig,
7712
8045
  validateStaticCourse: () => validateStaticCourse
@@ -11350,6 +11683,7 @@ init_factory();
11350
11683
  mountMixerDebugger,
11351
11684
  mountPipelineDebugger,
11352
11685
  mountSessionDebugger,
11686
+ mountUserDBDebugger,
11353
11687
  newInterval,
11354
11688
  parseCardHistoryID,
11355
11689
  pipelineDebugAPI,
@@ -11372,6 +11706,7 @@ init_factory();
11372
11706
  startSessionTracking,
11373
11707
  updateLearningState,
11374
11708
  updateStrategyWeight,
11709
+ userDBDebugAPI,
11375
11710
  validateMigration,
11376
11711
  validateProcessorConfig,
11377
11712
  validateStaticCourse