@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
@@ -1,8 +1,8 @@
1
- import { U as UserDBInterface, C as CourseDBInterface, a as CoursesDBInterface, b as ClassroomDBInterface, A as AdminDBInterface, c as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, d as ContentNavigationStrategyData, e as StudySessionReviewItem, f as ScheduledCard } from '../../userDB-C33Hzjgn.mjs';
2
- import { D as DataLayerProvider } from '../../dataLayerProvider-BInqI_RF.mjs';
3
- import { S as StaticCourseManifest } from '../../types-DC-ckZug.mjs';
1
+ import { U as UserDBInterface, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface, a as UserDBReader, d as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, e as ContentNavigationStrategyData, f as StudySessionReviewItem, g as ScheduledCard } from '../../userDB-DJ8HMw83.mjs';
2
+ import { D as DataLayerProvider } from '../../dataLayerProvider-VieuAAkV.mjs';
3
+ import { S as StaticCourseManifest } from '../../types-Che4wTwA.mjs';
4
4
  import { CourseConfig, CourseElo, DataShape } from '@vue-skuilder/common';
5
- import { S as SkuilderCourseData, T as TagStub, a as Tag } from '../../types-legacy-Birv-Jx6.mjs';
5
+ import { S as SkuilderCourseData, Q as QualifiedCardID, T as TagStub, a as Tag } from '../../types-legacy-B8ahaCbj.mjs';
6
6
  import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-CyATpyLQ.mjs';
7
7
  import 'moment';
8
8
 
@@ -23,6 +23,7 @@ declare class StaticDataLayerProvider implements DataLayerProvider {
23
23
  getCoursesDB(): CoursesDBInterface;
24
24
  getClassroomDB(_classId: string, _type: 'student' | 'teacher'): Promise<ClassroomDBInterface>;
25
25
  getAdminDB(): AdminDBInterface;
26
+ createUserReaderForUser(targetUsername: string): Promise<UserDBReader>;
26
27
  isReadOnly(): boolean;
27
28
  }
28
29
 
@@ -118,14 +119,18 @@ declare class StaticCourseDB implements CourseDBInterface {
118
119
  getCourseInfo(): Promise<CourseInfo>;
119
120
  getCourseDoc<T extends SkuilderCourseData>(id: string, _options?: PouchDB.Core.GetOptions): Promise<T>;
120
121
  getCourseDocs<T extends SkuilderCourseData>(ids: string[], _options?: PouchDB.Core.AllDocsOptions): Promise<PouchDB.Core.AllDocsWithKeysResponse<{} & T>>;
121
- getCardsByELO(elo: number, limit?: number): Promise<string[]>;
122
+ getCardsByELO(elo: number, limit?: number): Promise<{
123
+ courseID: string;
124
+ cardID: string;
125
+ elo?: number;
126
+ }[]>;
122
127
  getCardEloData(cardIds: string[]): Promise<CourseElo[]>;
123
128
  updateCardElo(cardId: string, _elo: CourseElo): Promise<PouchDB.Core.Response>;
124
129
  getNewCards(limit?: number): Promise<StudySessionNewItem[]>;
125
130
  getCardsCenteredAtELO(options: {
126
131
  limit: number;
127
132
  elo: 'user' | 'random' | number;
128
- }, filter?: (id: string) => boolean): Promise<StudySessionNewItem[]>;
133
+ }, filter?: (id: QualifiedCardID) => boolean): Promise<StudySessionNewItem[]>;
129
134
  getAppliedTags(cardId: string): Promise<PouchDB.Query.Response<TagStub>>;
130
135
  addTagToCard(_cardId: string, _tagId: string): Promise<PouchDB.Core.Response>;
131
136
  removeTagFromCard(_cardId: string, _tagId: string): Promise<PouchDB.Core.Response>;
@@ -154,6 +159,8 @@ declare class StaticCourseDB implements CourseDBInterface {
154
159
  * Internal helper method for static attachment serving
155
160
  */
156
161
  getAttachmentBlob(docId: string, attachmentName: string): Promise<Blob | Buffer | null>;
162
+ searchCards(_query: string): Promise<any[]>;
163
+ find(_request: PouchDB.Find.FindRequest<any>): Promise<PouchDB.Find.FindResponse<any>>;
157
164
  }
158
165
 
159
166
  declare class StaticCoursesDB implements CoursesDBInterface {
@@ -1,8 +1,8 @@
1
- import { U as UserDBInterface, C as CourseDBInterface, a as CoursesDBInterface, b as ClassroomDBInterface, A as AdminDBInterface, c as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, d as ContentNavigationStrategyData, e as StudySessionReviewItem, f as ScheduledCard } from '../../userDB-DusL7OXe.js';
2
- import { D as DataLayerProvider } from '../../dataLayerProvider-DqtNroSh.js';
3
- import { S as StaticCourseManifest } from '../../types-BefDGkKa.js';
1
+ import { U as UserDBInterface, C as CourseDBInterface, b as CoursesDBInterface, c as ClassroomDBInterface, A as AdminDBInterface, a as UserDBReader, d as CourseInfo, S as StudySessionNewItem, D as DataLayerResult, e as ContentNavigationStrategyData, f as StudySessionReviewItem, g as ScheduledCard } from '../../userDB-B7zTQ123.js';
2
+ import { D as DataLayerProvider } from '../../dataLayerProvider-juuqUHOP.js';
3
+ import { S as StaticCourseManifest } from '../../types-DtoI27Xh.js';
4
4
  import { CourseConfig, CourseElo, DataShape } from '@vue-skuilder/common';
5
- import { S as SkuilderCourseData, T as TagStub, a as Tag } from '../../types-legacy-Birv-Jx6.js';
5
+ import { S as SkuilderCourseData, Q as QualifiedCardID, T as TagStub, a as Tag } from '../../types-legacy-B8ahaCbj.js';
6
6
  import { S as SyncStrategy, A as AccountCreationResult, a as AuthenticationResult } from '../../SyncStrategy-CyATpyLQ.js';
7
7
  import 'moment';
8
8
 
@@ -23,6 +23,7 @@ declare class StaticDataLayerProvider implements DataLayerProvider {
23
23
  getCoursesDB(): CoursesDBInterface;
24
24
  getClassroomDB(_classId: string, _type: 'student' | 'teacher'): Promise<ClassroomDBInterface>;
25
25
  getAdminDB(): AdminDBInterface;
26
+ createUserReaderForUser(targetUsername: string): Promise<UserDBReader>;
26
27
  isReadOnly(): boolean;
27
28
  }
28
29
 
@@ -118,14 +119,18 @@ declare class StaticCourseDB implements CourseDBInterface {
118
119
  getCourseInfo(): Promise<CourseInfo>;
119
120
  getCourseDoc<T extends SkuilderCourseData>(id: string, _options?: PouchDB.Core.GetOptions): Promise<T>;
120
121
  getCourseDocs<T extends SkuilderCourseData>(ids: string[], _options?: PouchDB.Core.AllDocsOptions): Promise<PouchDB.Core.AllDocsWithKeysResponse<{} & T>>;
121
- getCardsByELO(elo: number, limit?: number): Promise<string[]>;
122
+ getCardsByELO(elo: number, limit?: number): Promise<{
123
+ courseID: string;
124
+ cardID: string;
125
+ elo?: number;
126
+ }[]>;
122
127
  getCardEloData(cardIds: string[]): Promise<CourseElo[]>;
123
128
  updateCardElo(cardId: string, _elo: CourseElo): Promise<PouchDB.Core.Response>;
124
129
  getNewCards(limit?: number): Promise<StudySessionNewItem[]>;
125
130
  getCardsCenteredAtELO(options: {
126
131
  limit: number;
127
132
  elo: 'user' | 'random' | number;
128
- }, filter?: (id: string) => boolean): Promise<StudySessionNewItem[]>;
133
+ }, filter?: (id: QualifiedCardID) => boolean): Promise<StudySessionNewItem[]>;
129
134
  getAppliedTags(cardId: string): Promise<PouchDB.Query.Response<TagStub>>;
130
135
  addTagToCard(_cardId: string, _tagId: string): Promise<PouchDB.Core.Response>;
131
136
  removeTagFromCard(_cardId: string, _tagId: string): Promise<PouchDB.Core.Response>;
@@ -154,6 +159,8 @@ declare class StaticCourseDB implements CourseDBInterface {
154
159
  * Internal helper method for static attachment serving
155
160
  */
156
161
  getAttachmentBlob(docId: string, attachmentName: string): Promise<Blob | Buffer | null>;
162
+ searchCards(_query: string): Promise<any[]>;
163
+ find(_request: PouchDB.Find.FindRequest<any>): Promise<PouchDB.Find.FindResponse<any>>;
157
164
  }
158
165
 
159
166
  declare class StaticCoursesDB implements CoursesDBInterface {
@@ -146,9 +146,9 @@ var init_pouchdb_setup = __esm({
146
146
  import_pouchdb.default.plugin(import_pouchdb_find.default);
147
147
  import_pouchdb.default.plugin(import_pouchdb_authentication.default);
148
148
  import_pouchdb.default.defaults({
149
- ajax: {
150
- timeout: 6e4
151
- }
149
+ // ajax: {
150
+ // timeout: 60000,
151
+ // },
152
152
  });
153
153
  pouchdb_setup_default = import_pouchdb.default;
154
154
  }
@@ -307,37 +307,48 @@ var init_updateQueue = __esm({
307
307
  } else {
308
308
  if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
309
309
  this.inprogressUpdates[id] = true;
310
- try {
311
- let doc = await this.readDB.get(id);
312
- logger.debug(`Retrieved doc: ${id}`);
313
- while (this.pendingUpdates[id].length !== 0) {
314
- const update = this.pendingUpdates[id].splice(0, 1)[0];
315
- if (typeof update === "function") {
316
- doc = { ...doc, ...update(doc) };
310
+ const MAX_RETRIES = 5;
311
+ for (let i = 0; i < MAX_RETRIES; i++) {
312
+ try {
313
+ const doc = await this.readDB.get(id);
314
+ logger.debug(`Retrieved doc: ${id}`);
315
+ let updatedDoc = { ...doc };
316
+ const updatesToApply = [...this.pendingUpdates[id]];
317
+ for (const update of updatesToApply) {
318
+ if (typeof update === "function") {
319
+ updatedDoc = { ...updatedDoc, ...update(updatedDoc) };
320
+ } else {
321
+ updatedDoc = {
322
+ ...updatedDoc,
323
+ ...update
324
+ };
325
+ }
326
+ }
327
+ await this.writeDB.put(updatedDoc);
328
+ logger.debug(`Put doc: ${id}`);
329
+ this.pendingUpdates[id].splice(0, updatesToApply.length);
330
+ if (this.pendingUpdates[id].length === 0) {
331
+ this.inprogressUpdates[id] = false;
332
+ delete this.inprogressUpdates[id];
317
333
  } else {
318
- doc = {
319
- ...doc,
320
- ...update
321
- };
334
+ return this.applyUpdates(id);
335
+ }
336
+ return updatedDoc;
337
+ } catch (e) {
338
+ if (e.name === "conflict" && i < MAX_RETRIES - 1) {
339
+ logger.warn(`Conflict on update for doc ${id}, retry #${i + 1}`);
340
+ await new Promise((res) => setTimeout(res, 50 * Math.random()));
341
+ } else {
342
+ delete this.inprogressUpdates[id];
343
+ if (this.pendingUpdates[id]) {
344
+ delete this.pendingUpdates[id];
345
+ }
346
+ logger.error(`Error on attemped update (retry ${i}): ${JSON.stringify(e)}`);
347
+ throw e;
322
348
  }
323
349
  }
324
- await this.writeDB.put(doc);
325
- logger.debug(`Put doc: ${id}`);
326
- if (this.pendingUpdates[id].length === 0) {
327
- this.inprogressUpdates[id] = false;
328
- delete this.inprogressUpdates[id];
329
- } else {
330
- return this.applyUpdates(id);
331
- }
332
- return doc;
333
- } catch (e) {
334
- delete this.inprogressUpdates[id];
335
- if (this.pendingUpdates[id]) {
336
- delete this.pendingUpdates[id];
337
- }
338
- logger.error(`Error on attemped update: ${JSON.stringify(e)}`);
339
- throw e;
340
350
  }
351
+ throw new Error(`UpdateQueue failed for doc ${id} after ${MAX_RETRIES} retries.`);
341
352
  } else {
342
353
  throw new Error(`Empty Updates Queue Triggered`);
343
354
  }
@@ -425,7 +436,7 @@ function getCourseDB(courseID) {
425
436
  const dbName = `coursedb-${courseID}`;
426
437
  return new pouchdb_setup_default(
427
438
  ENV.COUCHDB_SERVER_PROTOCOL + "://" + ENV.COUCHDB_SERVER_URL + dbName,
428
- pouchDBincludeCredentialsConfig
439
+ createPouchDBConfig()
429
440
  );
430
441
  }
431
442
  var import_common, import_common2, import_common3, import_uuid;
@@ -503,13 +514,16 @@ var init_elo = __esm({
503
514
  }
504
515
  async getNewCards(limit = 99) {
505
516
  const activeCards = await this.user.getActiveCards();
506
- return (await this.course.getCardsCenteredAtELO({ limit, elo: "user" }, (c) => {
507
- if (activeCards.some((ac) => c.includes(ac))) {
508
- return false;
509
- } else {
510
- return true;
517
+ return (await this.course.getCardsCenteredAtELO(
518
+ { limit, elo: "user" },
519
+ (c) => {
520
+ if (activeCards.some((ac) => c.cardID === ac.cardID)) {
521
+ return false;
522
+ } else {
523
+ return true;
524
+ }
511
525
  }
512
- })).map((c) => {
526
+ )).map((c) => {
513
527
  return {
514
528
  ...c,
515
529
  status: "new"
@@ -557,7 +571,7 @@ var init_navigators = __esm({
557
571
  static async create(user, course, strategyData) {
558
572
  const implementingClass = strategyData.implementingClass;
559
573
  let NavigatorImpl;
560
- const variations = ["", ".js", ".ts"];
574
+ const variations = [".ts", ".js", ""];
561
575
  for (const ext of variations) {
562
576
  try {
563
577
  const module2 = await globImport(`./${implementingClass}${ext}`);
@@ -649,6 +663,25 @@ var init_CouchDBSyncStrategy = __esm({
649
663
  });
650
664
 
651
665
  // src/impl/couch/index.ts
666
+ function createPouchDBConfig() {
667
+ const hasExplicitCredentials = ENV.COUCHDB_USERNAME && ENV.COUCHDB_PASSWORD;
668
+ const isNodeEnvironment = typeof window === "undefined";
669
+ if (hasExplicitCredentials && isNodeEnvironment) {
670
+ return {
671
+ fetch(url, opts = {}) {
672
+ const basicAuth = btoa(`${ENV.COUCHDB_USERNAME}:${ENV.COUCHDB_PASSWORD}`);
673
+ const headers = new Headers(opts.headers || {});
674
+ headers.set("Authorization", `Basic ${basicAuth}`);
675
+ const newOpts = {
676
+ ...opts,
677
+ headers
678
+ };
679
+ return pouchdb_setup_default.fetch(url, newOpts);
680
+ }
681
+ };
682
+ }
683
+ return pouchDBincludeCredentialsConfig;
684
+ }
652
685
  var import_cross_fetch2, import_moment4, import_process, isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig;
653
686
  var init_couch = __esm({
654
687
  "src/impl/couch/index.ts"() {
@@ -911,6 +944,9 @@ Currently logged-in as ${this._username}.`
911
944
  await this.init();
912
945
  return ret;
913
946
  }
947
+ async get(id) {
948
+ return this.localDB.get(id);
949
+ }
914
950
  update(id, update) {
915
951
  return this.updateQueue.update(id, update);
916
952
  }
@@ -957,7 +993,12 @@ Currently logged-in as ${this._username}.`
957
993
  endkey: keys.endkey,
958
994
  include_docs: true
959
995
  });
960
- return reviews.rows.map((r) => `${r.doc.courseId}-${r.doc.cardId}`);
996
+ return reviews.rows.map((r) => {
997
+ return {
998
+ courseID: r.doc.courseId,
999
+ cardID: r.doc.cardId
1000
+ };
1001
+ });
961
1002
  }
962
1003
  async getActivityRecords() {
963
1004
  try {
@@ -1237,8 +1278,18 @@ Currently logged-in as ${this._username}.`
1237
1278
  }
1238
1279
  this.setDBandQ();
1239
1280
  this.syncStrategy.startSync(this.localDB, this.remoteDB);
1240
- void this.applyDesignDocs();
1241
- void this.deduplicateReviews();
1281
+ this.applyDesignDocs().catch((error) => {
1282
+ log3(`Error in applyDesignDocs background task: ${error}`);
1283
+ if (error && typeof error === "object") {
1284
+ log3(`Full error details in applyDesignDocs: ${JSON.stringify(error)}`);
1285
+ }
1286
+ });
1287
+ this.deduplicateReviews().catch((error) => {
1288
+ log3(`Error in deduplicateReviews background task: ${error}`);
1289
+ if (error && typeof error === "object") {
1290
+ log3(`Full error details in background task: ${JSON.stringify(error)}`);
1291
+ }
1292
+ });
1242
1293
  _BaseUser._initialized = true;
1243
1294
  }
1244
1295
  static designDocs = [
@@ -1256,10 +1307,15 @@ Currently logged-in as ${this._username}.`
1256
1307
  }
1257
1308
  ];
1258
1309
  async applyDesignDocs() {
1310
+ log3(`Starting applyDesignDocs for user: ${this._username}`);
1311
+ log3(`Remote DB name: ${this.remoteDB.name || "unknown"}`);
1259
1312
  if (this._username === "admin") {
1313
+ log3("Skipping design docs for admin user");
1260
1314
  return;
1261
1315
  }
1316
+ log3(`Applying ${_BaseUser.designDocs.length} design docs`);
1262
1317
  for (const doc of _BaseUser.designDocs) {
1318
+ log3(`Applying design doc: ${doc._id}`);
1263
1319
  try {
1264
1320
  try {
1265
1321
  const existingDoc = await this.remoteDB.get(doc._id);
@@ -1358,8 +1414,13 @@ Currently logged-in as ${this._username}.`
1358
1414
  async deduplicateReviews() {
1359
1415
  try {
1360
1416
  log3("Starting deduplication of scheduled reviews...");
1417
+ log3(`Remote DB name: ${this.remoteDB.name || "unknown"}`);
1418
+ log3(`Write DB name: ${this.writeDB.name || "unknown"}`);
1361
1419
  const reviewsMap = {};
1362
1420
  const duplicateDocIds = [];
1421
+ log3(
1422
+ `Attempting to query remoteDB for reviewCards/reviewCards. Database: ${this.remoteDB.name || "unknown"}`
1423
+ );
1363
1424
  const scheduledReviews = await this.remoteDB.query("reviewCards/reviewCards");
1364
1425
  log3(`Found ${scheduledReviews.rows.length} scheduled reviews to process`);
1365
1426
  scheduledReviews.rows.forEach((r) => {
@@ -1394,6 +1455,17 @@ Currently logged-in as ${this._username}.`
1394
1455
  }
1395
1456
  } catch (error) {
1396
1457
  log3(`Error during review deduplication: ${error}`);
1458
+ if (error && typeof error === "object" && "status" in error && error.status === 404) {
1459
+ log3(
1460
+ `Database not found (404) during review deduplication. Database: ${this.remoteDB.name || "unknown"}`
1461
+ );
1462
+ log3(
1463
+ `This might indicate the user database doesn't exist or the reviewCards view isn't available`
1464
+ );
1465
+ }
1466
+ if (error && typeof error === "object") {
1467
+ log3(`Full error details: ${JSON.stringify(error)}`);
1468
+ }
1397
1469
  }
1398
1470
  }
1399
1471
  /**
@@ -2098,7 +2170,10 @@ var init_courseDB3 = __esm({
2098
2170
  };
2099
2171
  }
2100
2172
  async getCardsByELO(elo, limit) {
2101
- return this.unpacker.queryByElo(elo, limit || 25);
2173
+ return (await this.unpacker.queryByElo(elo, limit || 25)).map((card) => {
2174
+ const [courseID, cardID, elo2] = card.split("-");
2175
+ return { courseID, cardID, elo: elo2 ? parseInt(elo2) : void 0 };
2176
+ });
2102
2177
  }
2103
2178
  async getCardEloData(cardIds) {
2104
2179
  const results = await Promise.all(
@@ -2142,14 +2217,19 @@ var init_courseDB3 = __esm({
2142
2217
  } else if (options.elo === "random") {
2143
2218
  targetElo = 800 + Math.random() * 400;
2144
2219
  }
2145
- let cardIds = await this.unpacker.queryByElo(targetElo, options.limit * 2);
2220
+ let cardIds = (await this.unpacker.queryByElo(targetElo, options.limit * 2)).map((c) => {
2221
+ return {
2222
+ cardID: c,
2223
+ courseID: this.courseId
2224
+ };
2225
+ });
2146
2226
  if (filter) {
2147
2227
  cardIds = cardIds.filter(filter);
2148
2228
  }
2149
- return cardIds.slice(0, options.limit).map((cardId) => ({
2229
+ return cardIds.slice(0, options.limit).map((card) => ({
2150
2230
  status: "new",
2151
- qualifiedID: `${this.courseId}-${cardId}`,
2152
- cardID: cardId,
2231
+ // qualifiedID: `${this.courseId}-${cardId}`,
2232
+ cardID: card.cardID,
2153
2233
  contentSourceType: "course",
2154
2234
  contentSourceID: this.courseId,
2155
2235
  courseID: this.courseId
@@ -2341,6 +2421,16 @@ var init_courseDB3 = __esm({
2341
2421
  async getAttachmentBlob(docId, attachmentName) {
2342
2422
  return this.unpacker.getAttachmentBlob(docId, attachmentName);
2343
2423
  }
2424
+ // Admin search methods
2425
+ async searchCards(_query) {
2426
+ return [];
2427
+ }
2428
+ async find(_request) {
2429
+ return {
2430
+ docs: [],
2431
+ warning: "Find operations not supported in static mode"
2432
+ };
2433
+ }
2344
2434
  };
2345
2435
  }
2346
2436
  });
@@ -2492,6 +2582,12 @@ var init_StaticDataLayerProvider = __esm({
2492
2582
  getAdminDB() {
2493
2583
  throw new Error("Admin functions not supported in static mode");
2494
2584
  }
2585
+ async createUserReaderForUser(targetUsername) {
2586
+ logger.warn(`StaticDataLayerProvider: Multi-user access not supported in static mode`);
2587
+ logger.warn(`Request: trying to access data for ${targetUsername}`);
2588
+ logger.warn(`Returning current user's data instead`);
2589
+ return this.getUserDB();
2590
+ }
2495
2591
  isReadOnly() {
2496
2592
  return true;
2497
2593
  }