@vue-skuilder/db 0.1.7 → 0.1.8-1

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 (65) hide show
  1. package/dist/{SyncStrategy-DnJRj-Xp.d.mts → SyncStrategy-CyATpyLQ.d.mts} +6 -0
  2. package/dist/{SyncStrategy-DnJRj-Xp.d.ts → SyncStrategy-CyATpyLQ.d.ts} +6 -0
  3. package/dist/core/index.d.mts +5 -5
  4. package/dist/core/index.d.ts +5 -5
  5. package/dist/core/index.js +131 -118
  6. package/dist/core/index.js.map +1 -1
  7. package/dist/core/index.mjs +128 -115
  8. package/dist/core/index.mjs.map +1 -1
  9. package/dist/{dataLayerProvider-BbW9EnZK.d.mts → dataLayerProvider-BInqI_RF.d.mts} +1 -1
  10. package/dist/{dataLayerProvider-6stCgDME.d.ts → dataLayerProvider-DqtNroSh.d.ts} +1 -1
  11. package/dist/impl/couch/index.d.mts +6 -6
  12. package/dist/impl/couch/index.d.ts +6 -6
  13. package/dist/impl/couch/index.js +1368 -1255
  14. package/dist/impl/couch/index.js.map +1 -1
  15. package/dist/impl/couch/index.mjs +1362 -1249
  16. package/dist/impl/couch/index.mjs.map +1 -1
  17. package/dist/impl/static/index.d.mts +8 -6
  18. package/dist/impl/static/index.d.ts +8 -6
  19. package/dist/impl/static/index.js +253 -843
  20. package/dist/impl/static/index.js.map +1 -1
  21. package/dist/impl/static/index.mjs +250 -842
  22. package/dist/impl/static/index.mjs.map +1 -1
  23. package/dist/index-CLL31bEy.d.ts +137 -0
  24. package/dist/index-CUNnL38E.d.mts +137 -0
  25. package/dist/index.d.mts +11 -56
  26. package/dist/index.d.ts +11 -56
  27. package/dist/index.js +346 -173
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +343 -170
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/{types-BvzcRAys.d.ts → types-BefDGkKa.d.ts} +1 -1
  32. package/dist/{types-CQQ80R5N.d.mts → types-DC-ckZug.d.mts} +1 -1
  33. package/dist/{types-legacy-CtrmkOLu.d.mts → types-legacy-Birv-Jx6.d.mts} +2 -2
  34. package/dist/{types-legacy-CtrmkOLu.d.ts → types-legacy-Birv-Jx6.d.ts} +2 -2
  35. package/dist/{userDB-DUY63VMN.d.ts → userDB-C33Hzjgn.d.mts} +10 -3
  36. package/dist/{userDB-7fM4tpgr.d.mts → userDB-DusL7OXe.d.ts} +10 -3
  37. package/dist/util/packer/index.d.mts +3 -63
  38. package/dist/util/packer/index.d.ts +3 -63
  39. package/dist/util/packer/index.js +53 -1
  40. package/dist/util/packer/index.js.map +1 -1
  41. package/dist/util/packer/index.mjs +53 -1
  42. package/dist/util/packer/index.mjs.map +1 -1
  43. package/package.json +7 -4
  44. package/src/core/types/types-legacy.ts +13 -1
  45. package/src/core/types/user.ts +9 -2
  46. package/src/core/util/index.ts +5 -4
  47. package/src/impl/common/BaseUserDB.ts +33 -22
  48. package/src/impl/common/SyncStrategy.ts +7 -0
  49. package/src/impl/common/index.ts +0 -1
  50. package/src/impl/common/userDBHelpers.ts +4 -4
  51. package/src/impl/couch/CouchDBSyncStrategy.ts +10 -0
  52. package/src/impl/couch/adminDB.ts +1 -1
  53. package/src/impl/couch/courseAPI.ts +7 -6
  54. package/src/impl/couch/courseDB.ts +1 -1
  55. package/src/impl/couch/courseLookupDB.ts +1 -1
  56. package/src/impl/couch/index.ts +10 -5
  57. package/src/impl/couch/updateQueue.ts +12 -8
  58. package/src/impl/couch/user-course-relDB.ts +17 -27
  59. package/src/impl/static/NoOpSyncStrategy.ts +5 -0
  60. package/src/impl/static/StaticDataUnpacker.ts +18 -36
  61. package/src/impl/static/courseDB.ts +135 -17
  62. package/src/study/getCardDataShape.ts +2 -2
  63. package/src/util/migrator/FileSystemAdapter.ts +20 -0
  64. package/src/util/migrator/StaticToCouchDBMigrator.ts +6 -0
  65. package/src/util/packer/CouchDBToStaticPacker.ts +92 -2
@@ -80,7 +80,7 @@ var init_logger = __esm({
80
80
  });
81
81
 
82
82
  // src/core/types/types-legacy.ts
83
- var GuestUsername, log, DocType, cardHistoryPrefix;
83
+ var GuestUsername, log, DocType, DocTypePrefixes;
84
84
  var init_types_legacy = __esm({
85
85
  "src/core/types/types-legacy.ts"() {
86
86
  "use strict";
@@ -102,7 +102,19 @@ var init_types_legacy = __esm({
102
102
  DocType2["NAVIGATION_STRATEGY"] = "NAVIGATION_STRATEGY";
103
103
  return DocType2;
104
104
  })(DocType || {});
105
- cardHistoryPrefix = "cardH";
105
+ DocTypePrefixes = {
106
+ ["CARD" /* CARD */]: "c",
107
+ ["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]: "dd",
108
+ ["TAG" /* TAG */]: "TAG",
109
+ ["CARDRECORD" /* CARDRECORD */]: "cardH",
110
+ ["SCHEDULED_CARD" /* SCHEDULED_CARD */]: "card_review_",
111
+ // Add other doctypes here as they get prefixed IDs
112
+ ["DATASHAPE" /* DATASHAPE */]: "DATASHAPE",
113
+ ["QUESTION" /* QUESTIONTYPE */]: "QUESTION",
114
+ ["VIEW" /* VIEW */]: "VIEW",
115
+ ["PEDAGOGY" /* PEDAGOGY */]: "PEDAGOGY",
116
+ ["NAVIGATION_STRATEGY" /* NAVIGATION_STRATEGY */]: "NAVIGATION_STRATEGY"
117
+ };
106
118
  }
107
119
  });
108
120
 
@@ -114,16 +126,16 @@ function isQuestionRecord(c) {
114
126
  return c.userAnswer !== void 0;
115
127
  }
116
128
  function getCardHistoryID(courseID, cardID) {
117
- return `${cardHistoryPrefix}-${courseID}-${cardID}`;
129
+ return `${DocTypePrefixes["CARDRECORD" /* CARDRECORD */]}-${courseID}-${cardID}`;
118
130
  }
119
131
  function parseCardHistoryID(id) {
120
132
  const split = id.split("-");
121
133
  let error = "";
122
134
  error += split.length === 3 ? "" : `
123
135
  given ID has incorrect number of '-' characters`;
124
- error += split[0] === cardHistoryPrefix ? "" : `
125
- given ID does not start with ${cardHistoryPrefix}`;
126
- if (split.length === 3 && split[0] === cardHistoryPrefix) {
136
+ error += split[0] === DocTypePrefixes["CARDRECORD" /* CARDRECORD */] ? "" : `
137
+ given ID does not start with ${DocTypePrefixes["CARDRECORD" /* CARDRECORD */]}`;
138
+ if (split.length === 3 && split[0] === DocTypePrefixes["CARDRECORD" /* CARDRECORD */]) {
127
139
  return {
128
140
  courseID: split[1],
129
141
  cardID: split[2]
@@ -216,11 +228,11 @@ function scheduleCardReviewLocal(userDB, review) {
216
228
  const now = moment.utc();
217
229
  logger.info(`Scheduling for review in: ${review.time.diff(now, "h") / 24} days`);
218
230
  void userDB.put({
219
- _id: REVIEW_PREFIX + review.time.format(REVIEW_TIME_FORMAT),
231
+ _id: DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */] + review.time.format(REVIEW_TIME_FORMAT),
220
232
  cardId: review.card_id,
221
- reviewTime: review.time,
233
+ reviewTime: review.time.toISOString(),
222
234
  courseId: review.course_id,
223
- scheduledAt: now,
235
+ scheduledAt: now.toISOString(),
224
236
  scheduledFor: review.scheduledFor,
225
237
  schedulingAgentId: review.schedulingAgentId
226
238
  });
@@ -236,14 +248,14 @@ async function removeScheduledCardReviewLocal(userDB, reviewDocID) {
236
248
  ${JSON.stringify(err)}`);
237
249
  });
238
250
  }
239
- var REVIEW_PREFIX, REVIEW_TIME_FORMAT, log2;
251
+ var REVIEW_TIME_FORMAT, log2;
240
252
  var init_userDBHelpers = __esm({
241
253
  "src/impl/common/userDBHelpers.ts"() {
242
254
  "use strict";
255
+ init_core();
243
256
  init_logger();
244
257
  init_pouchdb_setup();
245
258
  init_dataDirectory();
246
- REVIEW_PREFIX = "card_review_";
247
259
  REVIEW_TIME_FORMAT = "YYYY-MM-DD--kk:mm:ss-SSS";
248
260
  log2 = (s) => {
249
261
  logger.info(s);
@@ -278,7 +290,10 @@ var init_updateQueue = __esm({
278
290
  _className = "UpdateQueue";
279
291
  pendingUpdates = {};
280
292
  inprogressUpdates = {};
281
- db;
293
+ readDB;
294
+ // Database for read operations
295
+ writeDB;
296
+ // Database for write operations (local-first)
282
297
  update(id, update) {
283
298
  logger.debug(`Update requested on doc: ${id}`);
284
299
  if (this.pendingUpdates[id]) {
@@ -288,24 +303,25 @@ var init_updateQueue = __esm({
288
303
  }
289
304
  return this.applyUpdates(id);
290
305
  }
291
- constructor(db) {
306
+ constructor(readDB, writeDB) {
292
307
  super();
293
- this.db = db;
308
+ this.readDB = readDB;
309
+ this.writeDB = writeDB || readDB;
294
310
  logger.debug(`UpdateQ initialized...`);
295
- void this.db.info().then((i) => {
311
+ void this.readDB.info().then((i) => {
296
312
  logger.debug(`db info: ${JSON.stringify(i)}`);
297
313
  });
298
314
  }
299
315
  async applyUpdates(id) {
300
316
  logger.debug(`Applying updates on doc: ${id}`);
301
317
  if (this.inprogressUpdates[id]) {
302
- await this.db.info();
318
+ await this.readDB.info();
303
319
  return this.applyUpdates(id);
304
320
  } else {
305
321
  if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
306
322
  this.inprogressUpdates[id] = true;
307
323
  try {
308
- let doc = await this.db.get(id);
324
+ let doc = await this.readDB.get(id);
309
325
  logger.debug(`Retrieved doc: ${id}`);
310
326
  while (this.pendingUpdates[id].length !== 0) {
311
327
  const update = this.pendingUpdates[id].splice(0, 1)[0];
@@ -318,7 +334,7 @@ var init_updateQueue = __esm({
318
334
  };
319
335
  }
320
336
  }
321
- await this.db.put(doc);
337
+ await this.writeDB.put(doc);
322
338
  logger.debug(`Put doc: ${id}`);
323
339
  if (this.pendingUpdates[id].length === 0) {
324
340
  this.inprogressUpdates[id] = false;
@@ -344,6 +360,60 @@ var init_updateQueue = __esm({
344
360
  }
345
361
  });
346
362
 
363
+ // src/impl/couch/user-course-relDB.ts
364
+ import moment2 from "moment";
365
+ var UsrCrsData;
366
+ var init_user_course_relDB = __esm({
367
+ "src/impl/couch/user-course-relDB.ts"() {
368
+ "use strict";
369
+ init_logger();
370
+ UsrCrsData = class {
371
+ user;
372
+ _courseId;
373
+ constructor(user, courseId) {
374
+ this.user = user;
375
+ this._courseId = courseId;
376
+ }
377
+ async getReviewsForcast(daysCount) {
378
+ const time = moment2.utc().add(daysCount, "days");
379
+ return this.getReviewstoDate(time);
380
+ }
381
+ async getPendingReviews() {
382
+ const now = moment2.utc();
383
+ return this.getReviewstoDate(now);
384
+ }
385
+ async getScheduledReviewCount() {
386
+ return (await this.getPendingReviews()).length;
387
+ }
388
+ async getCourseSettings() {
389
+ const regDoc = await this.user.getCourseRegistrationsDoc();
390
+ const crsDoc = regDoc.courses.find((c) => c.courseID === this._courseId);
391
+ if (crsDoc && crsDoc.settings) {
392
+ return crsDoc.settings;
393
+ } else {
394
+ logger.warn(`no settings found during lookup on course ${this._courseId}`);
395
+ return {};
396
+ }
397
+ }
398
+ updateCourseSettings(updates) {
399
+ if ("updateCourseSettings" in this.user) {
400
+ void this.user.updateCourseSettings(this._courseId, updates);
401
+ }
402
+ }
403
+ async getReviewstoDate(targetDate) {
404
+ const allReviews = await this.user.getPendingReviews(this._courseId);
405
+ logger.debug(
406
+ `Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`
407
+ );
408
+ return allReviews.filter((review) => {
409
+ const reviewTime = moment2.utc(review.reviewTime);
410
+ return targetDate.isAfter(reviewTime);
411
+ });
412
+ }
413
+ };
414
+ }
415
+ });
416
+
347
417
  // src/impl/couch/clientCache.ts
348
418
  async function GET_CACHED(k, f) {
349
419
  if (CLIENT_CACHE[k]) {
@@ -367,10 +437,12 @@ var init_clientCache = __esm({
367
437
  import { NameSpacer } from "@vue-skuilder/common";
368
438
  import { blankCourseElo, toCourseElo } from "@vue-skuilder/common";
369
439
  import { prepareNote55 } from "@vue-skuilder/common";
440
+ import { v4 as uuidv4 } from "uuid";
370
441
  async function addNote55(courseID, codeCourse, shape, data, author, tags, uploads, elo = blankCourseElo()) {
371
442
  const db = getCourseDB(courseID);
372
443
  const payload = prepareNote55(courseID, codeCourse, shape, data, author, tags, uploads);
373
- const result = await db.post(payload);
444
+ const _id = `${DocTypePrefixes["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]}-${uuidv4()}`;
445
+ const result = await db.put({ ...payload, _id });
374
446
  const dataShapeId = NameSpacer.getDataShapeString({
375
447
  course: codeCourse,
376
448
  dataShape: shape.name
@@ -441,7 +513,9 @@ async function createCard(questionViewName, courseID, dsDescriptor, noteID, tags
441
513
  }
442
514
  async function addCard(courseID, course, id_displayable_data, id_view, elo, tags, author) {
443
515
  const db = getCourseDB(courseID);
444
- const card = await db.post({
516
+ const _id = `${DocTypePrefixes["CARD" /* CARD */]}-${uuidv4()}`;
517
+ const card = await db.put({
518
+ _id,
445
519
  course,
446
520
  id_displayable_data,
447
521
  id_view,
@@ -1193,7 +1267,7 @@ ${above.rows.map((r) => ` ${r.id}-${r.key}
1193
1267
  });
1194
1268
 
1195
1269
  // src/impl/couch/classroomDB.ts
1196
- import moment2 from "moment";
1270
+ import moment3 from "moment";
1197
1271
  var CLASSROOM_CONFIG, ClassroomDBBase, StudentClassroomDB;
1198
1272
  var init_classroomDB2 = __esm({
1199
1273
  "src/impl/couch/classroomDB.ts"() {
@@ -1293,9 +1367,9 @@ var init_classroomDB2 = __esm({
1293
1367
  }
1294
1368
  async getNewCards() {
1295
1369
  const activeCards = await this._user.getActiveCards();
1296
- const now = moment2.utc();
1370
+ const now = moment3.utc();
1297
1371
  const assigned = await this.getAssignedContent();
1298
- const due = assigned.filter((c) => now.isAfter(moment2.utc(c.activeOn, REVIEW_TIME_FORMAT2)));
1372
+ const due = assigned.filter((c) => now.isAfter(moment3.utc(c.activeOn, REVIEW_TIME_FORMAT2)));
1299
1373
  logger.info(`Due content: ${JSON.stringify(due)}`);
1300
1374
  let ret = [];
1301
1375
  for (let i = 0; i < due.length; i++) {
@@ -1373,7 +1447,7 @@ var init_CouchDBSyncStrategy = __esm({
1373
1447
  });
1374
1448
 
1375
1449
  // src/impl/couch/index.ts
1376
- import moment3 from "moment";
1450
+ import moment4 from "moment";
1377
1451
  import process2 from "process";
1378
1452
  function getCourseDB2(courseID) {
1379
1453
  return new pouchdb_setup_default(
@@ -1407,7 +1481,7 @@ function getStartAndEndKeys2(key) {
1407
1481
  endkey: key + "\uFFF0"
1408
1482
  };
1409
1483
  }
1410
- var isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig, REVIEW_PREFIX2, REVIEW_TIME_FORMAT2;
1484
+ var isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig, REVIEW_TIME_FORMAT2;
1411
1485
  var init_couch = __esm({
1412
1486
  "src/impl/couch/index.ts"() {
1413
1487
  "use strict";
@@ -1433,78 +1507,10 @@ var init_couch = __esm({
1433
1507
  return pouchdb_setup_default.fetch(url, opts);
1434
1508
  }
1435
1509
  };
1436
- REVIEW_PREFIX2 = "card_review_";
1437
1510
  REVIEW_TIME_FORMAT2 = "YYYY-MM-DD--kk:mm:ss-SSS";
1438
1511
  }
1439
1512
  });
1440
1513
 
1441
- // src/impl/couch/user-course-relDB.ts
1442
- import moment4 from "moment";
1443
- var UsrCrsData;
1444
- var init_user_course_relDB = __esm({
1445
- "src/impl/couch/user-course-relDB.ts"() {
1446
- "use strict";
1447
- init_couch();
1448
- init_courseDB();
1449
- init_logger();
1450
- UsrCrsData = class {
1451
- user;
1452
- course;
1453
- _courseId;
1454
- constructor(user, courseId) {
1455
- this.user = user;
1456
- this.course = new CourseDB(courseId, async () => this.user);
1457
- this._courseId = courseId;
1458
- }
1459
- async getReviewsForcast(daysCount) {
1460
- const time = moment4.utc().add(daysCount, "days");
1461
- return this.getReviewstoDate(time);
1462
- }
1463
- async getPendingReviews() {
1464
- const now = moment4.utc();
1465
- return this.getReviewstoDate(now);
1466
- }
1467
- async getScheduledReviewCount() {
1468
- return (await this.getPendingReviews()).length;
1469
- }
1470
- async getCourseSettings() {
1471
- const regDoc = await this.user.getCourseRegistrationsDoc();
1472
- const crsDoc = regDoc.courses.find((c) => c.courseID === this._courseId);
1473
- if (crsDoc && crsDoc.settings) {
1474
- return crsDoc.settings;
1475
- } else {
1476
- logger.warn(`no settings found during lookup on course ${this._courseId}`);
1477
- return {};
1478
- }
1479
- }
1480
- updateCourseSettings(updates) {
1481
- void this.user.updateCourseSettings(this._courseId, updates);
1482
- }
1483
- async getReviewstoDate(targetDate) {
1484
- const keys = getStartAndEndKeys2(REVIEW_PREFIX2);
1485
- const reviews = await this.user.remote().allDocs({
1486
- startkey: keys.startkey,
1487
- endkey: keys.endkey,
1488
- include_docs: true
1489
- });
1490
- logger.debug(
1491
- `Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`
1492
- );
1493
- return reviews.rows.filter((r) => {
1494
- if (r.id.startsWith(REVIEW_PREFIX2)) {
1495
- const date = moment4.utc(r.id.substr(REVIEW_PREFIX2.length), REVIEW_TIME_FORMAT2);
1496
- if (targetDate.isAfter(date)) {
1497
- if (this._courseId === void 0 || r.doc.courseId === this._courseId) {
1498
- return true;
1499
- }
1500
- }
1501
- }
1502
- }).map((r) => r.doc);
1503
- }
1504
- };
1505
- }
1506
- });
1507
-
1508
1514
  // src/impl/common/BaseUserDB.ts
1509
1515
  import { Status as Status3 } from "@vue-skuilder/common";
1510
1516
  import moment5 from "moment";
@@ -1600,10 +1606,11 @@ async function dropUserFromClassroom(user, classID) {
1600
1606
  async function getUserClassrooms(user) {
1601
1607
  return getOrCreateClassroomRegistrationsDoc(user);
1602
1608
  }
1603
- var log3, cardHistoryPrefix2, BaseUser, userCoursesDoc, userClassroomsDoc;
1609
+ var log3, BaseUser, userCoursesDoc, userClassroomsDoc;
1604
1610
  var init_BaseUserDB = __esm({
1605
1611
  "src/impl/common/BaseUserDB.ts"() {
1606
1612
  "use strict";
1613
+ init_core();
1607
1614
  init_util();
1608
1615
  init_types_legacy();
1609
1616
  init_logger();
@@ -1614,7 +1621,6 @@ var init_BaseUserDB = __esm({
1614
1621
  log3 = (s) => {
1615
1622
  logger.info(s);
1616
1623
  };
1617
- cardHistoryPrefix2 = "cardH-";
1618
1624
  BaseUser = class _BaseUser {
1619
1625
  static _instance;
1620
1626
  static _initialized = false;
@@ -1635,11 +1641,13 @@ var init_BaseUserDB = __esm({
1635
1641
  isLoggedIn() {
1636
1642
  return !this._username.startsWith(GuestUsername);
1637
1643
  }
1638
- remoteDB;
1639
1644
  remote() {
1640
1645
  return this.remoteDB;
1641
1646
  }
1642
1647
  localDB;
1648
+ remoteDB;
1649
+ writeDB;
1650
+ // Database to use for write operations (local-first approach)
1643
1651
  updateQueue;
1644
1652
  async createAccount(username, password) {
1645
1653
  if (!this.syncStrategy.canCreateAccount()) {
@@ -1703,8 +1711,8 @@ Currently logged-in as ${this._username}.`
1703
1711
  const allDocs = await localDB.allDocs({ include_docs: false });
1704
1712
  const docsToDelete = allDocs.rows.filter((row) => {
1705
1713
  const id = row.id;
1706
- return id.startsWith(cardHistoryPrefix2) || // Card interaction history
1707
- id.startsWith(REVIEW_PREFIX) || // Scheduled reviews
1714
+ return id.startsWith(DocTypePrefixes["CARDRECORD" /* CARDRECORD */]) || // Card interaction history
1715
+ id.startsWith(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]) || // Scheduled reviews
1708
1716
  id === _BaseUser.DOC_IDS.COURSE_REGISTRATIONS || // Course registrations
1709
1717
  id === _BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS || // Classroom registrations
1710
1718
  id === _BaseUser.DOC_IDS.CONFIG;
@@ -1773,7 +1781,7 @@ Currently logged-in as ${this._username}.`
1773
1781
  *
1774
1782
  */
1775
1783
  async getActiveCards() {
1776
- const keys = getStartAndEndKeys(REVIEW_PREFIX);
1784
+ const keys = getStartAndEndKeys(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]);
1777
1785
  const reviews = await this.remoteDB.allDocs({
1778
1786
  startkey: keys.startkey,
1779
1787
  endkey: keys.endkey,
@@ -1845,7 +1853,7 @@ Currently logged-in as ${this._username}.`
1845
1853
  }
1846
1854
  }
1847
1855
  async getReviewstoDate(targetDate, course_id) {
1848
- const keys = getStartAndEndKeys(REVIEW_PREFIX);
1856
+ const keys = getStartAndEndKeys(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]);
1849
1857
  const reviews = await this.remoteDB.allDocs({
1850
1858
  startkey: keys.startkey,
1851
1859
  endkey: keys.endkey,
@@ -1855,8 +1863,11 @@ Currently logged-in as ${this._username}.`
1855
1863
  `Fetching ${this._username}'s scheduled reviews${course_id ? ` for course ${course_id}` : ""}.`
1856
1864
  );
1857
1865
  return reviews.rows.filter((r) => {
1858
- if (r.id.startsWith(REVIEW_PREFIX)) {
1859
- const date = moment5.utc(r.id.substr(REVIEW_PREFIX.length), REVIEW_TIME_FORMAT);
1866
+ if (r.id.startsWith(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */])) {
1867
+ const date = moment5.utc(
1868
+ r.id.substr(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */].length),
1869
+ REVIEW_TIME_FORMAT
1870
+ );
1860
1871
  if (targetDate.isAfter(date)) {
1861
1872
  if (course_id === void 0 || r.doc.courseId === course_id) {
1862
1873
  return true;
@@ -1971,7 +1982,8 @@ Currently logged-in as ${this._username}.`
1971
1982
  const defaultConfig = {
1972
1983
  _id: _BaseUser.DOC_IDS.CONFIG,
1973
1984
  darkMode: false,
1974
- likesConfetti: false
1985
+ likesConfetti: false,
1986
+ sessionTimeLimit: 5
1975
1987
  };
1976
1988
  try {
1977
1989
  const cfg = await this.localDB.get(_BaseUser.DOC_IDS.CONFIG);
@@ -2044,7 +2056,8 @@ Currently logged-in as ${this._username}.`
2044
2056
  setDBandQ() {
2045
2057
  this.localDB = getLocalUserDB(this._username);
2046
2058
  this.remoteDB = this.syncStrategy.setupRemoteDB(this._username);
2047
- this.updateQueue = new UpdateQueue(this.localDB);
2059
+ this.writeDB = this.syncStrategy.getWriteDB ? this.syncStrategy.getWriteDB(this._username) : this.localDB;
2060
+ this.updateQueue = new UpdateQueue(this.localDB, this.writeDB);
2048
2061
  }
2049
2062
  async init() {
2050
2063
  _BaseUser._initialized = false;
@@ -2162,8 +2175,8 @@ Currently logged-in as ${this._username}.`
2162
2175
  streak: 0,
2163
2176
  bestInterval: 0
2164
2177
  };
2165
- void this.remoteDB.put(initCardHistory);
2166
- return initCardHistory;
2178
+ const putResult = await this.writeDB.put(initCardHistory);
2179
+ return { ...initCardHistory, _rev: putResult.rev };
2167
2180
  } else {
2168
2181
  throw new Error(`putCardRecord failed because of:
2169
2182
  name:${reason.name}
@@ -2198,7 +2211,7 @@ Currently logged-in as ${this._username}.`
2198
2211
  const deletePromises = duplicateDocIds.map(async (docId) => {
2199
2212
  try {
2200
2213
  const doc = await this.remoteDB.get(docId);
2201
- await this.remoteDB.remove(doc);
2214
+ await this.writeDB.remove(doc);
2202
2215
  log3(`Successfully removed duplicate review: ${docId}`);
2203
2216
  } catch (error) {
2204
2217
  log3(`Failed to remove duplicate review ${docId}: ${error}`);
@@ -2220,7 +2233,7 @@ Currently logged-in as ${this._username}.`
2220
2233
  * @param course_id optional specification of individual course
2221
2234
  */
2222
2235
  async getSeenCards(course_id) {
2223
- let prefix = cardHistoryPrefix2;
2236
+ let prefix = DocTypePrefixes["CARDRECORD" /* CARDRECORD */];
2224
2237
  if (course_id) {
2225
2238
  prefix += course_id;
2226
2239
  }
@@ -2229,8 +2242,8 @@ Currently logged-in as ${this._username}.`
2229
2242
  });
2230
2243
  const ret = [];
2231
2244
  docs.rows.forEach((row) => {
2232
- if (row.id.startsWith(cardHistoryPrefix2)) {
2233
- ret.push(row.id.substr(cardHistoryPrefix2.length));
2245
+ if (row.id.startsWith(DocTypePrefixes["CARDRECORD" /* CARDRECORD */])) {
2246
+ ret.push(row.id.substr(DocTypePrefixes["CARDRECORD" /* CARDRECORD */].length));
2234
2247
  }
2235
2248
  });
2236
2249
  return ret;
@@ -2242,7 +2255,7 @@ Currently logged-in as ${this._username}.`
2242
2255
  async getHistory() {
2243
2256
  const cards = await filterAllDocsByPrefix(
2244
2257
  this.remoteDB,
2245
- cardHistoryPrefix2,
2258
+ DocTypePrefixes["CARDRECORD" /* CARDRECORD */],
2246
2259
  {
2247
2260
  include_docs: true,
2248
2261
  attachments: false
@@ -2283,7 +2296,7 @@ Currently logged-in as ${this._username}.`
2283
2296
  } catch (e) {
2284
2297
  const err = e;
2285
2298
  if (err.status === 404) {
2286
- await this.remoteDB.put({
2299
+ await this.writeDB.put({
2287
2300
  _id: _BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS,
2288
2301
  registrations: []
2289
2302
  });
@@ -2331,10 +2344,10 @@ Currently logged-in as ${this._username}.`
2331
2344
  }
2332
2345
  }
2333
2346
  async scheduleCardReview(review) {
2334
- return scheduleCardReviewLocal(this.remoteDB, review);
2347
+ return scheduleCardReviewLocal(this.writeDB, review);
2335
2348
  }
2336
2349
  async removeScheduledCardReview(reviewId) {
2337
- return removeScheduledCardReviewLocal(this.remoteDB, reviewId);
2350
+ return removeScheduledCardReviewLocal(this.writeDB, reviewId);
2338
2351
  }
2339
2352
  async registerForClassroom(_classId, _registerAs) {
2340
2353
  return registerUserForClassroom(this._username, _classId, _registerAs);
@@ -2598,11 +2611,11 @@ init_core();
2598
2611
  export {
2599
2612
  ContentNavigator,
2600
2613
  DocType,
2614
+ DocTypePrefixes,
2601
2615
  GuestUsername,
2602
2616
  Loggable,
2603
2617
  Navigators,
2604
2618
  areQuestionRecords,
2605
- cardHistoryPrefix,
2606
2619
  docIsDeleted,
2607
2620
  getCardHistoryID,
2608
2621
  getStudySource,