@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.
@@ -80,12 +80,28 @@ var init_SyncStrategy = __esm({
80
80
  });
81
81
 
82
82
  // src/core/types/types-legacy.ts
83
- var GuestUsername, DocTypePrefixes;
83
+ var GuestUsername, DocType, DocTypePrefixes;
84
84
  var init_types_legacy = __esm({
85
85
  "src/core/types/types-legacy.ts"() {
86
86
  "use strict";
87
87
  init_logger();
88
88
  GuestUsername = "sk-guest-";
89
+ DocType = /* @__PURE__ */ ((DocType3) => {
90
+ DocType3["DISPLAYABLE_DATA"] = "DISPLAYABLE_DATA";
91
+ DocType3["CARD"] = "CARD";
92
+ DocType3["DATASHAPE"] = "DATASHAPE";
93
+ DocType3["QUESTIONTYPE"] = "QUESTION";
94
+ DocType3["VIEW"] = "VIEW";
95
+ DocType3["PEDAGOGY"] = "PEDAGOGY";
96
+ DocType3["CARDRECORD"] = "CARDRECORD";
97
+ DocType3["SCHEDULED_CARD"] = "SCHEDULED_CARD";
98
+ DocType3["TAG"] = "TAG";
99
+ DocType3["NAVIGATION_STRATEGY"] = "NAVIGATION_STRATEGY";
100
+ DocType3["STRATEGY_STATE"] = "STRATEGY_STATE";
101
+ DocType3["USER_OUTCOME"] = "USER_OUTCOME";
102
+ DocType3["STRATEGY_LEARNING_STATE"] = "STRATEGY_LEARNING_STATE";
103
+ return DocType3;
104
+ })(DocType || {});
89
105
  DocTypePrefixes = {
90
106
  ["CARD" /* CARD */]: "c",
91
107
  ["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]: "dd",
@@ -1505,7 +1521,7 @@ var init_hierarchyDefinition = __esm({
1505
1521
  /**
1506
1522
  * CardFilter.transform implementation.
1507
1523
  *
1508
- * Apply prerequisite gating to cards. Cards with locked tags receive score: 0.
1524
+ * Apply prerequisite gating to cards. Cards with locked tags receive score * 0.01.
1509
1525
  */
1510
1526
  async transform(cards, context) {
1511
1527
  const masteredTags = await this.getMasteredTags(context);
@@ -1518,7 +1534,8 @@ var init_hierarchyDefinition = __esm({
1518
1534
  unlockedTags,
1519
1535
  masteredTags
1520
1536
  );
1521
- const finalScore = isUnlocked ? card.score : 0;
1537
+ const LOCKED_PENALTY = 0.01;
1538
+ const finalScore = isUnlocked ? card.score : card.score * LOCKED_PENALTY;
1522
1539
  const action = isUnlocked ? "passed" : "penalized";
1523
1540
  gated.push({
1524
1541
  ...card,
@@ -4150,7 +4167,13 @@ var init_common = __esm({
4150
4167
  });
4151
4168
 
4152
4169
  // src/factory.ts
4153
- var NOT_SET, ENV;
4170
+ function getDataLayer() {
4171
+ if (!dataLayerInstance) {
4172
+ throw new Error("Data layer not initialized. Call initializeDataLayer first.");
4173
+ }
4174
+ return dataLayerInstance;
4175
+ }
4176
+ var NOT_SET, ENV, dataLayerInstance;
4154
4177
  var init_factory = __esm({
4155
4178
  "src/factory.ts"() {
4156
4179
  "use strict";
@@ -4163,6 +4186,7 @@ var init_factory = __esm({
4163
4186
  COUCHDB_SERVER_URL: NOT_SET,
4164
4187
  LOCAL_STORAGE_PREFIX: ""
4165
4188
  };
4189
+ dataLayerInstance = null;
4166
4190
  }
4167
4191
  });
4168
4192
 
@@ -4270,6 +4294,335 @@ var init_bulkImport = __esm({
4270
4294
  }
4271
4295
  });
4272
4296
 
4297
+ // src/core/UserDBDebugger.ts
4298
+ function getUserDB() {
4299
+ try {
4300
+ const provider = getDataLayer();
4301
+ return provider.getUserDB();
4302
+ } catch {
4303
+ logger.info("[UserDB Debug] Data layer not initialized yet.");
4304
+ return null;
4305
+ }
4306
+ }
4307
+ function getRawDB() {
4308
+ const userDB = getUserDB();
4309
+ if (!userDB) return null;
4310
+ const rawDB = userDB.localDB;
4311
+ if (!rawDB) {
4312
+ logger.info("[UserDB Debug] Unable to access raw database instance.");
4313
+ return null;
4314
+ }
4315
+ return rawDB;
4316
+ }
4317
+ function formatTimestamp(isoString) {
4318
+ const date = new Date(isoString);
4319
+ return date.toLocaleString();
4320
+ }
4321
+ function mountUserDBDebugger() {
4322
+ if (typeof window === "undefined") return;
4323
+ const win = window;
4324
+ win.skuilder = win.skuilder || {};
4325
+ win.skuilder.userdb = userDBDebugAPI;
4326
+ }
4327
+ var userDBDebugAPI;
4328
+ var init_UserDBDebugger = __esm({
4329
+ "src/core/UserDBDebugger.ts"() {
4330
+ "use strict";
4331
+ init_logger();
4332
+ init_factory();
4333
+ init_types_legacy();
4334
+ init_userDBHelpers();
4335
+ userDBDebugAPI = {
4336
+ /**
4337
+ * Show current user information
4338
+ */
4339
+ showUser() {
4340
+ const userDB = getUserDB();
4341
+ if (!userDB) return;
4342
+ console.group("\u{1F464} User Information");
4343
+ logger.info(`Username: ${userDB.getUsername()}`);
4344
+ logger.info(`Logged in: ${userDB.isLoggedIn() ? "Yes \u2705" : "No (Guest) \u274C"}`);
4345
+ userDB.getConfig().then((config) => {
4346
+ logger.info("Configuration:");
4347
+ logger.info(JSON.stringify(config, null, 2));
4348
+ }).catch((err) => {
4349
+ logger.info(`Error loading config: ${err.message}`);
4350
+ }).finally(() => {
4351
+ console.groupEnd();
4352
+ });
4353
+ },
4354
+ /**
4355
+ * Show scheduled reviews
4356
+ */
4357
+ async showScheduledReviews(courseId) {
4358
+ const userDB = getUserDB();
4359
+ if (!userDB) return;
4360
+ try {
4361
+ const reviews = await userDB.getPendingReviews(courseId);
4362
+ console.group(`\u{1F4C5} Scheduled Reviews${courseId ? ` (${courseId})` : ""}`);
4363
+ logger.info(`Total: ${reviews.length}`);
4364
+ if (reviews.length > 0) {
4365
+ const byCourse = /* @__PURE__ */ new Map();
4366
+ for (const review of reviews) {
4367
+ if (!byCourse.has(review.courseId)) {
4368
+ byCourse.set(review.courseId, []);
4369
+ }
4370
+ byCourse.get(review.courseId).push(review);
4371
+ }
4372
+ for (const [course, courseReviews] of byCourse) {
4373
+ console.group(`Course: ${course} (${courseReviews.length} reviews)`);
4374
+ const sorted = courseReviews.sort((a, b) => {
4375
+ const timeA = typeof a.reviewTime === "string" ? a.reviewTime : a.reviewTime.toISOString();
4376
+ const timeB = typeof b.reviewTime === "string" ? b.reviewTime : b.reviewTime.toISOString();
4377
+ return new Date(timeA).getTime() - new Date(timeB).getTime();
4378
+ });
4379
+ for (const review of sorted.slice(0, 10)) {
4380
+ const reviewTimeStr = typeof review.reviewTime === "string" ? review.reviewTime : review.reviewTime.toISOString();
4381
+ logger.info(
4382
+ ` ${review.cardId.slice(0, 12)}... @ ${formatTimestamp(reviewTimeStr)} [${review.scheduledFor}/${review.schedulingAgentId}]`
4383
+ );
4384
+ }
4385
+ if (sorted.length > 10) {
4386
+ logger.info(` ... and ${sorted.length - 10} more`);
4387
+ }
4388
+ console.groupEnd();
4389
+ }
4390
+ }
4391
+ console.groupEnd();
4392
+ } catch (err) {
4393
+ logger.info(`Error loading scheduled reviews: ${err.message}`);
4394
+ }
4395
+ },
4396
+ /**
4397
+ * Show course registrations
4398
+ */
4399
+ async showCourseRegistrations() {
4400
+ const userDB = getUserDB();
4401
+ if (!userDB) return;
4402
+ try {
4403
+ const registrations = await userDB.getActiveCourses();
4404
+ console.group("\u{1F4DA} Course Registrations");
4405
+ logger.info(`Total: ${registrations.length}`);
4406
+ if (registrations.length > 0) {
4407
+ console.table(
4408
+ registrations.map((reg) => ({
4409
+ courseId: reg.courseID,
4410
+ status: reg.status || "active",
4411
+ elo: typeof reg.elo === "number" ? reg.elo.toFixed(0) : reg.elo?.global?.score?.toFixed(0) || "N/A"
4412
+ }))
4413
+ );
4414
+ }
4415
+ console.groupEnd();
4416
+ } catch (err) {
4417
+ logger.info(`Error loading course registrations: ${err.message}`);
4418
+ }
4419
+ },
4420
+ /**
4421
+ * Show card history for a specific card
4422
+ */
4423
+ async showCardHistory(cardId) {
4424
+ const rawDB = getRawDB();
4425
+ if (!rawDB) return;
4426
+ try {
4427
+ const result = await filterAllDocsByPrefix(rawDB, DocTypePrefixes["CARDRECORD" /* CARDRECORD */]);
4428
+ const cardHistories = result.rows.filter((row) => row.doc && row.doc.cardID === cardId).map((row) => row.doc);
4429
+ console.group(`\u{1F3B4} Card History: ${cardId}`);
4430
+ logger.info(`Total interactions: ${cardHistories.length}`);
4431
+ if (cardHistories.length > 0) {
4432
+ const sorted = cardHistories.sort(
4433
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
4434
+ );
4435
+ console.table(
4436
+ sorted.slice(0, 20).map((doc) => ({
4437
+ time: formatTimestamp(doc.timestamp),
4438
+ outcome: doc.outcome || "N/A",
4439
+ duration: doc.duration ? `${(doc.duration / 1e3).toFixed(1)}s` : "N/A",
4440
+ courseId: doc.courseId
4441
+ }))
4442
+ );
4443
+ if (sorted.length > 20) {
4444
+ logger.info(`... and ${sorted.length - 20} more interactions`);
4445
+ }
4446
+ }
4447
+ console.groupEnd();
4448
+ } catch (err) {
4449
+ logger.info(`Error loading card history: ${err.message}`);
4450
+ }
4451
+ },
4452
+ /**
4453
+ * Query documents by type
4454
+ */
4455
+ async queryByType(docType, limit = 50) {
4456
+ const rawDB = getRawDB();
4457
+ if (!rawDB) return;
4458
+ try {
4459
+ const prefix = DocTypePrefixes[DocType[docType]];
4460
+ if (!prefix) {
4461
+ logger.info(`Unknown document type: ${docType}`);
4462
+ return;
4463
+ }
4464
+ const result = await filterAllDocsByPrefix(rawDB, prefix);
4465
+ console.group(`\u{1F4C4} Documents: ${docType}`);
4466
+ logger.info(`Total: ${result.rows.length}`);
4467
+ logger.info(`Prefix: ${prefix}`);
4468
+ if (result.rows.length > 0) {
4469
+ logger.info("Sample documents:");
4470
+ const samples = result.rows.slice(0, Math.min(limit, result.rows.length));
4471
+ for (const row of samples) {
4472
+ logger.info(`
4473
+ ${row.id}:`);
4474
+ logger.info(JSON.stringify(row.doc, null, 2));
4475
+ }
4476
+ if (result.rows.length > limit) {
4477
+ logger.info(`
4478
+ ... and ${result.rows.length - limit} more documents`);
4479
+ }
4480
+ }
4481
+ console.groupEnd();
4482
+ } catch (err) {
4483
+ logger.info(`Error querying documents: ${err.message}`);
4484
+ }
4485
+ },
4486
+ /**
4487
+ * Show database info and statistics
4488
+ */
4489
+ async dbInfo() {
4490
+ const rawDB = getRawDB();
4491
+ if (!rawDB) return;
4492
+ try {
4493
+ const info = await rawDB.info();
4494
+ console.group("\u2139\uFE0F Database Information");
4495
+ logger.info(`Database name: ${info.db_name}`);
4496
+ logger.info(`Total documents: ${info.doc_count}`);
4497
+ logger.info(`Update sequence: ${info.update_seq}`);
4498
+ if ("disk_size" in info) {
4499
+ logger.info(`Disk size: ${(info.disk_size || 0) / 1024 / 1024} MB`);
4500
+ }
4501
+ logger.info("\nDocument counts by type:");
4502
+ const allDocs = await rawDB.allDocs({ include_docs: false });
4503
+ const typeCounts = /* @__PURE__ */ new Map();
4504
+ for (const row of allDocs.rows) {
4505
+ let prefix = "other";
4506
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
4507
+ if (row.id.startsWith(typePrefix)) {
4508
+ prefix = type;
4509
+ break;
4510
+ }
4511
+ }
4512
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
4513
+ }
4514
+ console.table(
4515
+ Array.from(typeCounts.entries()).sort((a, b) => b[1] - a[1]).map(([type, count]) => ({ type, count }))
4516
+ );
4517
+ console.groupEnd();
4518
+ } catch (err) {
4519
+ logger.info(`Error getting database info: ${err.message}`);
4520
+ }
4521
+ },
4522
+ /**
4523
+ * List all document types
4524
+ */
4525
+ listDocTypes() {
4526
+ console.group("\u{1F4CB} Available Document Types");
4527
+ logger.info("Use with queryByType(type):");
4528
+ for (const [type, prefix] of Object.entries(DocTypePrefixes)) {
4529
+ logger.info(` ${type.padEnd(30)} \u2192 prefix: "${prefix}"`);
4530
+ }
4531
+ console.groupEnd();
4532
+ },
4533
+ /**
4534
+ * Export database contents (limited, for debugging)
4535
+ */
4536
+ async export(includeContent = false) {
4537
+ const rawDB = getRawDB();
4538
+ const userDB = getUserDB();
4539
+ if (!rawDB || !userDB) return "{}";
4540
+ try {
4541
+ const data = {
4542
+ username: userDB.getUsername(),
4543
+ loggedIn: userDB.isLoggedIn(),
4544
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
4545
+ };
4546
+ if (includeContent) {
4547
+ const allDocs = await rawDB.allDocs({ include_docs: true });
4548
+ data.documents = allDocs.rows.map((row) => ({
4549
+ id: row.id,
4550
+ doc: row.doc
4551
+ }));
4552
+ data.totalDocs = allDocs.rows.length;
4553
+ } else {
4554
+ const allDocs = await rawDB.allDocs({ include_docs: false });
4555
+ data.totalDocs = allDocs.rows.length;
4556
+ const typeCounts = /* @__PURE__ */ new Map();
4557
+ for (const row of allDocs.rows) {
4558
+ let prefix = "other";
4559
+ for (const [type, typePrefix] of Object.entries(DocTypePrefixes)) {
4560
+ if (row.id.startsWith(typePrefix)) {
4561
+ prefix = type;
4562
+ break;
4563
+ }
4564
+ }
4565
+ typeCounts.set(prefix, (typeCounts.get(prefix) || 0) + 1);
4566
+ }
4567
+ data.docCounts = Object.fromEntries(typeCounts);
4568
+ }
4569
+ const json = JSON.stringify(data, null, 2);
4570
+ logger.info("[UserDB Debug] Database info exported. Copy the returned string or use:");
4571
+ logger.info(" copy(window.skuilder.userdb.export())");
4572
+ if (!includeContent) {
4573
+ logger.info(" For full content export: window.skuilder.userdb.export(true)");
4574
+ }
4575
+ return json;
4576
+ } catch (err) {
4577
+ logger.info(`Error exporting database: ${err.message}`);
4578
+ return "{}";
4579
+ }
4580
+ },
4581
+ /**
4582
+ * Execute raw PouchDB query
4583
+ */
4584
+ async raw(queryFn) {
4585
+ const rawDB = getRawDB();
4586
+ if (!rawDB) return;
4587
+ try {
4588
+ const result = await queryFn(rawDB);
4589
+ logger.info("[UserDB Debug] Query result:");
4590
+ logger.info(result);
4591
+ } catch (err) {
4592
+ logger.info(`[UserDB Debug] Query error: ${err.message}`);
4593
+ }
4594
+ },
4595
+ /**
4596
+ * Show help
4597
+ */
4598
+ help() {
4599
+ logger.info(`
4600
+ \u{1F527} UserDB Debug API
4601
+
4602
+ Commands:
4603
+ .showUser() Show current user info and config
4604
+ .showScheduledReviews(courseId?) Show scheduled reviews (optionally filter by course)
4605
+ .showCourseRegistrations() Show all course registrations
4606
+ .showCardHistory(cardId) Show interaction history for a card
4607
+ .queryByType(docType, limit?) Query documents by type (e.g., 'SCHEDULED_CARD')
4608
+ .listDocTypes() List all available document types
4609
+ .dbInfo() Show database info and statistics
4610
+ .export(includeContent?) Export database info (true = include all docs)
4611
+ .raw(queryFn) Execute raw PouchDB query
4612
+ .help() Show this help message
4613
+
4614
+ Examples:
4615
+ window.skuilder.userdb.showUser()
4616
+ window.skuilder.userdb.showScheduledReviews('course123')
4617
+ window.skuilder.userdb.queryByType('SCHEDULED_CARD', 10)
4618
+ window.skuilder.userdb.raw(db => db.allDocs({ limit: 5 }))
4619
+ `);
4620
+ }
4621
+ };
4622
+ mountUserDBDebugger();
4623
+ }
4624
+ });
4625
+
4273
4626
  // src/core/index.ts
4274
4627
  var init_core = __esm({
4275
4628
  "src/core/index.ts"() {
@@ -4284,6 +4637,7 @@ var init_core = __esm({
4284
4637
  init_navigators();
4285
4638
  init_bulkImport();
4286
4639
  init_orchestration();
4640
+ init_UserDBDebugger();
4287
4641
  }
4288
4642
  });
4289
4643