@vue-skuilder/db 0.1.11-7 → 0.1.11

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.
Files changed (68) hide show
  1. package/dist/core/index.d.mts +5 -5
  2. package/dist/core/index.d.ts +5 -5
  3. package/dist/core/index.js +212 -50
  4. package/dist/core/index.js.map +1 -1
  5. package/dist/core/index.mjs +212 -50
  6. package/dist/core/index.mjs.map +1 -1
  7. package/dist/{dataLayerProvider-DqtNroSh.d.ts → dataLayerProvider-VieuAAkV.d.mts} +8 -1
  8. package/dist/{dataLayerProvider-BInqI_RF.d.mts → dataLayerProvider-juuqUHOP.d.ts} +8 -1
  9. package/dist/impl/couch/index.d.mts +19 -7
  10. package/dist/impl/couch/index.d.ts +19 -7
  11. package/dist/impl/couch/index.js +229 -63
  12. package/dist/impl/couch/index.js.map +1 -1
  13. package/dist/impl/couch/index.mjs +228 -62
  14. package/dist/impl/couch/index.mjs.map +1 -1
  15. package/dist/impl/static/index.d.mts +13 -6
  16. package/dist/impl/static/index.d.ts +13 -6
  17. package/dist/impl/static/index.js +142 -46
  18. package/dist/impl/static/index.js.map +1 -1
  19. package/dist/impl/static/index.mjs +142 -46
  20. package/dist/impl/static/index.mjs.map +1 -1
  21. package/dist/{index-CLL31bEy.d.ts → index-CWY6yhkV.d.ts} +1 -1
  22. package/dist/{index-CUNnL38E.d.mts → index-DZyxHCcf.d.mts} +1 -1
  23. package/dist/index.d.mts +28 -20
  24. package/dist/index.d.ts +28 -20
  25. package/dist/index.js +374 -108
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +378 -108
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/pouch/index.d.mts +1 -0
  30. package/dist/pouch/index.d.ts +1 -0
  31. package/dist/pouch/index.js +49 -0
  32. package/dist/pouch/index.js.map +1 -0
  33. package/dist/pouch/index.mjs +16 -0
  34. package/dist/pouch/index.mjs.map +1 -0
  35. package/dist/{types-DC-ckZug.d.mts → types-Che4wTwA.d.mts} +1 -1
  36. package/dist/{types-BefDGkKa.d.ts → types-DtoI27Xh.d.ts} +1 -1
  37. package/dist/{types-legacy-Birv-Jx6.d.mts → types-legacy-B8ahaCbj.d.mts} +5 -1
  38. package/dist/{types-legacy-Birv-Jx6.d.ts → types-legacy-B8ahaCbj.d.ts} +5 -1
  39. package/dist/{userDB-C33Hzjgn.d.mts → userDB-B7zTQ123.d.ts} +88 -55
  40. package/dist/{userDB-DusL7OXe.d.ts → userDB-DJ8HMw83.d.mts} +88 -55
  41. package/dist/util/packer/index.d.mts +3 -3
  42. package/dist/util/packer/index.d.ts +3 -3
  43. package/package.json +3 -3
  44. package/src/core/interfaces/contentSource.ts +3 -2
  45. package/src/core/interfaces/courseDB.ts +26 -3
  46. package/src/core/interfaces/dataLayerProvider.ts +9 -1
  47. package/src/core/interfaces/userDB.ts +80 -64
  48. package/src/core/navigators/elo.ts +10 -7
  49. package/src/core/navigators/index.ts +1 -1
  50. package/src/core/types/types-legacy.ts +5 -0
  51. package/src/impl/common/BaseUserDB.ts +45 -3
  52. package/src/impl/couch/CouchDBSyncStrategy.ts +2 -2
  53. package/src/impl/couch/PouchDataLayerProvider.ts +21 -0
  54. package/src/impl/couch/adminDB.ts +2 -2
  55. package/src/impl/couch/auth.ts +13 -4
  56. package/src/impl/couch/classroomDB.ts +10 -12
  57. package/src/impl/couch/courseAPI.ts +2 -2
  58. package/src/impl/couch/courseDB.ts +130 -11
  59. package/src/impl/couch/courseLookupDB.ts +4 -3
  60. package/src/impl/couch/index.ts +36 -4
  61. package/src/impl/couch/pouchdb-setup.ts +3 -3
  62. package/src/impl/couch/updateQueue.ts +51 -33
  63. package/src/impl/static/StaticDataLayerProvider.ts +11 -0
  64. package/src/impl/static/courseDB.ts +47 -8
  65. package/src/pouch/index.ts +2 -0
  66. package/src/study/SessionController.ts +168 -51
  67. package/src/study/SpacedRepetition.ts +1 -1
  68. package/tsup.config.ts +1 -0
@@ -124,9 +124,9 @@ var init_pouchdb_setup = __esm({
124
124
  PouchDB.plugin(PouchDBFind);
125
125
  PouchDB.plugin(PouchDBAuth);
126
126
  PouchDB.defaults({
127
- ajax: {
128
- timeout: 6e4
129
- }
127
+ // ajax: {
128
+ // timeout: 60000,
129
+ // },
130
130
  });
131
131
  pouchdb_setup_default = PouchDB;
132
132
  }
@@ -284,37 +284,48 @@ var init_updateQueue = __esm({
284
284
  } else {
285
285
  if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
286
286
  this.inprogressUpdates[id] = true;
287
- try {
288
- let doc = await this.readDB.get(id);
289
- logger.debug(`Retrieved doc: ${id}`);
290
- while (this.pendingUpdates[id].length !== 0) {
291
- const update = this.pendingUpdates[id].splice(0, 1)[0];
292
- if (typeof update === "function") {
293
- doc = { ...doc, ...update(doc) };
287
+ const MAX_RETRIES = 5;
288
+ for (let i = 0; i < MAX_RETRIES; i++) {
289
+ try {
290
+ const doc = await this.readDB.get(id);
291
+ logger.debug(`Retrieved doc: ${id}`);
292
+ let updatedDoc = { ...doc };
293
+ const updatesToApply = [...this.pendingUpdates[id]];
294
+ for (const update of updatesToApply) {
295
+ if (typeof update === "function") {
296
+ updatedDoc = { ...updatedDoc, ...update(updatedDoc) };
297
+ } else {
298
+ updatedDoc = {
299
+ ...updatedDoc,
300
+ ...update
301
+ };
302
+ }
303
+ }
304
+ await this.writeDB.put(updatedDoc);
305
+ logger.debug(`Put doc: ${id}`);
306
+ this.pendingUpdates[id].splice(0, updatesToApply.length);
307
+ if (this.pendingUpdates[id].length === 0) {
308
+ this.inprogressUpdates[id] = false;
309
+ delete this.inprogressUpdates[id];
294
310
  } else {
295
- doc = {
296
- ...doc,
297
- ...update
298
- };
311
+ return this.applyUpdates(id);
312
+ }
313
+ return updatedDoc;
314
+ } catch (e) {
315
+ if (e.name === "conflict" && i < MAX_RETRIES - 1) {
316
+ logger.warn(`Conflict on update for doc ${id}, retry #${i + 1}`);
317
+ await new Promise((res) => setTimeout(res, 50 * Math.random()));
318
+ } else {
319
+ delete this.inprogressUpdates[id];
320
+ if (this.pendingUpdates[id]) {
321
+ delete this.pendingUpdates[id];
322
+ }
323
+ logger.error(`Error on attemped update (retry ${i}): ${JSON.stringify(e)}`);
324
+ throw e;
299
325
  }
300
326
  }
301
- await this.writeDB.put(doc);
302
- logger.debug(`Put doc: ${id}`);
303
- if (this.pendingUpdates[id].length === 0) {
304
- this.inprogressUpdates[id] = false;
305
- delete this.inprogressUpdates[id];
306
- } else {
307
- return this.applyUpdates(id);
308
- }
309
- return doc;
310
- } catch (e) {
311
- delete this.inprogressUpdates[id];
312
- if (this.pendingUpdates[id]) {
313
- delete this.pendingUpdates[id];
314
- }
315
- logger.error(`Error on attemped update: ${JSON.stringify(e)}`);
316
- throw e;
317
327
  }
328
+ throw new Error(`UpdateQueue failed for doc ${id} after ${MAX_RETRIES} retries.`);
318
329
  } else {
319
330
  throw new Error(`Empty Updates Queue Triggered`);
320
331
  }
@@ -406,7 +417,7 @@ function getCourseDB(courseID) {
406
417
  const dbName = `coursedb-${courseID}`;
407
418
  return new pouchdb_setup_default(
408
419
  ENV.COUCHDB_SERVER_PROTOCOL + "://" + ENV.COUCHDB_SERVER_URL + dbName,
409
- pouchDBincludeCredentialsConfig
420
+ createPouchDBConfig()
410
421
  );
411
422
  }
412
423
  var init_courseAPI = __esm({
@@ -479,13 +490,16 @@ var init_elo = __esm({
479
490
  }
480
491
  async getNewCards(limit = 99) {
481
492
  const activeCards = await this.user.getActiveCards();
482
- return (await this.course.getCardsCenteredAtELO({ limit, elo: "user" }, (c) => {
483
- if (activeCards.some((ac) => c.includes(ac))) {
484
- return false;
485
- } else {
486
- return true;
493
+ return (await this.course.getCardsCenteredAtELO(
494
+ { limit, elo: "user" },
495
+ (c) => {
496
+ if (activeCards.some((ac) => c.cardID === ac.cardID)) {
497
+ return false;
498
+ } else {
499
+ return true;
500
+ }
487
501
  }
488
- })).map((c) => {
502
+ )).map((c) => {
489
503
  return {
490
504
  ...c,
491
505
  status: "new"
@@ -533,7 +547,7 @@ var init_navigators = __esm({
533
547
  static async create(user, course, strategyData) {
534
548
  const implementingClass = strategyData.implementingClass;
535
549
  let NavigatorImpl;
536
- const variations = ["", ".js", ".ts"];
550
+ const variations = [".ts", ".js", ""];
537
551
  for (const ext of variations) {
538
552
  try {
539
553
  const module = await globImport(`./${implementingClass}${ext}`);
@@ -629,6 +643,25 @@ var init_CouchDBSyncStrategy = __esm({
629
643
  import fetch3 from "cross-fetch";
630
644
  import moment4 from "moment";
631
645
  import process2 from "process";
646
+ function createPouchDBConfig() {
647
+ const hasExplicitCredentials = ENV.COUCHDB_USERNAME && ENV.COUCHDB_PASSWORD;
648
+ const isNodeEnvironment = typeof window === "undefined";
649
+ if (hasExplicitCredentials && isNodeEnvironment) {
650
+ return {
651
+ fetch(url, opts = {}) {
652
+ const basicAuth = btoa(`${ENV.COUCHDB_USERNAME}:${ENV.COUCHDB_PASSWORD}`);
653
+ const headers = new Headers(opts.headers || {});
654
+ headers.set("Authorization", `Basic ${basicAuth}`);
655
+ const newOpts = {
656
+ ...opts,
657
+ headers
658
+ };
659
+ return pouchdb_setup_default.fetch(url, newOpts);
660
+ }
661
+ };
662
+ }
663
+ return pouchDBincludeCredentialsConfig;
664
+ }
632
665
  var isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig;
633
666
  var init_couch = __esm({
634
667
  "src/impl/couch/index.ts"() {
@@ -888,6 +921,9 @@ Currently logged-in as ${this._username}.`
888
921
  await this.init();
889
922
  return ret;
890
923
  }
924
+ async get(id) {
925
+ return this.localDB.get(id);
926
+ }
891
927
  update(id, update) {
892
928
  return this.updateQueue.update(id, update);
893
929
  }
@@ -934,7 +970,12 @@ Currently logged-in as ${this._username}.`
934
970
  endkey: keys.endkey,
935
971
  include_docs: true
936
972
  });
937
- return reviews.rows.map((r) => `${r.doc.courseId}-${r.doc.cardId}`);
973
+ return reviews.rows.map((r) => {
974
+ return {
975
+ courseID: r.doc.courseId,
976
+ cardID: r.doc.cardId
977
+ };
978
+ });
938
979
  }
939
980
  async getActivityRecords() {
940
981
  try {
@@ -1214,8 +1255,18 @@ Currently logged-in as ${this._username}.`
1214
1255
  }
1215
1256
  this.setDBandQ();
1216
1257
  this.syncStrategy.startSync(this.localDB, this.remoteDB);
1217
- void this.applyDesignDocs();
1218
- void this.deduplicateReviews();
1258
+ this.applyDesignDocs().catch((error) => {
1259
+ log3(`Error in applyDesignDocs background task: ${error}`);
1260
+ if (error && typeof error === "object") {
1261
+ log3(`Full error details in applyDesignDocs: ${JSON.stringify(error)}`);
1262
+ }
1263
+ });
1264
+ this.deduplicateReviews().catch((error) => {
1265
+ log3(`Error in deduplicateReviews background task: ${error}`);
1266
+ if (error && typeof error === "object") {
1267
+ log3(`Full error details in background task: ${JSON.stringify(error)}`);
1268
+ }
1269
+ });
1219
1270
  _BaseUser._initialized = true;
1220
1271
  }
1221
1272
  static designDocs = [
@@ -1233,10 +1284,15 @@ Currently logged-in as ${this._username}.`
1233
1284
  }
1234
1285
  ];
1235
1286
  async applyDesignDocs() {
1287
+ log3(`Starting applyDesignDocs for user: ${this._username}`);
1288
+ log3(`Remote DB name: ${this.remoteDB.name || "unknown"}`);
1236
1289
  if (this._username === "admin") {
1290
+ log3("Skipping design docs for admin user");
1237
1291
  return;
1238
1292
  }
1293
+ log3(`Applying ${_BaseUser.designDocs.length} design docs`);
1239
1294
  for (const doc of _BaseUser.designDocs) {
1295
+ log3(`Applying design doc: ${doc._id}`);
1240
1296
  try {
1241
1297
  try {
1242
1298
  const existingDoc = await this.remoteDB.get(doc._id);
@@ -1335,8 +1391,13 @@ Currently logged-in as ${this._username}.`
1335
1391
  async deduplicateReviews() {
1336
1392
  try {
1337
1393
  log3("Starting deduplication of scheduled reviews...");
1394
+ log3(`Remote DB name: ${this.remoteDB.name || "unknown"}`);
1395
+ log3(`Write DB name: ${this.writeDB.name || "unknown"}`);
1338
1396
  const reviewsMap = {};
1339
1397
  const duplicateDocIds = [];
1398
+ log3(
1399
+ `Attempting to query remoteDB for reviewCards/reviewCards. Database: ${this.remoteDB.name || "unknown"}`
1400
+ );
1340
1401
  const scheduledReviews = await this.remoteDB.query("reviewCards/reviewCards");
1341
1402
  log3(`Found ${scheduledReviews.rows.length} scheduled reviews to process`);
1342
1403
  scheduledReviews.rows.forEach((r) => {
@@ -1371,6 +1432,17 @@ Currently logged-in as ${this._username}.`
1371
1432
  }
1372
1433
  } catch (error) {
1373
1434
  log3(`Error during review deduplication: ${error}`);
1435
+ if (error && typeof error === "object" && "status" in error && error.status === 404) {
1436
+ log3(
1437
+ `Database not found (404) during review deduplication. Database: ${this.remoteDB.name || "unknown"}`
1438
+ );
1439
+ log3(
1440
+ `This might indicate the user database doesn't exist or the reviewCards view isn't available`
1441
+ );
1442
+ }
1443
+ if (error && typeof error === "object") {
1444
+ log3(`Full error details: ${JSON.stringify(error)}`);
1445
+ }
1374
1446
  }
1375
1447
  }
1376
1448
  /**
@@ -2074,7 +2146,10 @@ var init_courseDB3 = __esm({
2074
2146
  };
2075
2147
  }
2076
2148
  async getCardsByELO(elo, limit) {
2077
- return this.unpacker.queryByElo(elo, limit || 25);
2149
+ return (await this.unpacker.queryByElo(elo, limit || 25)).map((card) => {
2150
+ const [courseID, cardID, elo2] = card.split("-");
2151
+ return { courseID, cardID, elo: elo2 ? parseInt(elo2) : void 0 };
2152
+ });
2078
2153
  }
2079
2154
  async getCardEloData(cardIds) {
2080
2155
  const results = await Promise.all(
@@ -2118,14 +2193,19 @@ var init_courseDB3 = __esm({
2118
2193
  } else if (options.elo === "random") {
2119
2194
  targetElo = 800 + Math.random() * 400;
2120
2195
  }
2121
- let cardIds = await this.unpacker.queryByElo(targetElo, options.limit * 2);
2196
+ let cardIds = (await this.unpacker.queryByElo(targetElo, options.limit * 2)).map((c) => {
2197
+ return {
2198
+ cardID: c,
2199
+ courseID: this.courseId
2200
+ };
2201
+ });
2122
2202
  if (filter) {
2123
2203
  cardIds = cardIds.filter(filter);
2124
2204
  }
2125
- return cardIds.slice(0, options.limit).map((cardId) => ({
2205
+ return cardIds.slice(0, options.limit).map((card) => ({
2126
2206
  status: "new",
2127
- qualifiedID: `${this.courseId}-${cardId}`,
2128
- cardID: cardId,
2207
+ // qualifiedID: `${this.courseId}-${cardId}`,
2208
+ cardID: card.cardID,
2129
2209
  contentSourceType: "course",
2130
2210
  contentSourceID: this.courseId,
2131
2211
  courseID: this.courseId
@@ -2317,6 +2397,16 @@ var init_courseDB3 = __esm({
2317
2397
  async getAttachmentBlob(docId, attachmentName) {
2318
2398
  return this.unpacker.getAttachmentBlob(docId, attachmentName);
2319
2399
  }
2400
+ // Admin search methods
2401
+ async searchCards(_query) {
2402
+ return [];
2403
+ }
2404
+ async find(_request) {
2405
+ return {
2406
+ docs: [],
2407
+ warning: "Find operations not supported in static mode"
2408
+ };
2409
+ }
2320
2410
  };
2321
2411
  }
2322
2412
  });
@@ -2468,6 +2558,12 @@ var init_StaticDataLayerProvider = __esm({
2468
2558
  getAdminDB() {
2469
2559
  throw new Error("Admin functions not supported in static mode");
2470
2560
  }
2561
+ async createUserReaderForUser(targetUsername) {
2562
+ logger.warn(`StaticDataLayerProvider: Multi-user access not supported in static mode`);
2563
+ logger.warn(`Request: trying to access data for ${targetUsername}`);
2564
+ logger.warn(`Returning current user's data instead`);
2565
+ return this.getUserDB();
2566
+ }
2471
2567
  isReadOnly() {
2472
2568
  return true;
2473
2569
  }