@vue-skuilder/db 0.1.7 → 0.1.8-0
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/{SyncStrategy-DnJRj-Xp.d.mts → SyncStrategy-CyATpyLQ.d.mts} +6 -0
- package/dist/{SyncStrategy-DnJRj-Xp.d.ts → SyncStrategy-CyATpyLQ.d.ts} +6 -0
- package/dist/core/index.d.mts +5 -5
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +131 -118
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +128 -115
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-BbW9EnZK.d.mts → dataLayerProvider-BInqI_RF.d.mts} +1 -1
- package/dist/{dataLayerProvider-6stCgDME.d.ts → dataLayerProvider-DqtNroSh.d.ts} +1 -1
- package/dist/impl/couch/index.d.mts +6 -6
- package/dist/impl/couch/index.d.ts +6 -6
- package/dist/impl/couch/index.js +1365 -1252
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +1359 -1246
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.mts +8 -6
- package/dist/impl/static/index.d.ts +8 -6
- package/dist/impl/static/index.js +253 -843
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +250 -842
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/index-CLL31bEy.d.ts +137 -0
- package/dist/index-CUNnL38E.d.mts +137 -0
- package/dist/index.d.mts +10 -55
- package/dist/index.d.ts +10 -55
- package/dist/index.js +343 -170
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +340 -167
- package/dist/index.mjs.map +1 -1
- package/dist/{types-BvzcRAys.d.ts → types-BefDGkKa.d.ts} +1 -1
- package/dist/{types-CQQ80R5N.d.mts → types-DC-ckZug.d.mts} +1 -1
- package/dist/{types-legacy-CtrmkOLu.d.mts → types-legacy-Birv-Jx6.d.mts} +2 -2
- package/dist/{types-legacy-CtrmkOLu.d.ts → types-legacy-Birv-Jx6.d.ts} +2 -2
- package/dist/{userDB-DUY63VMN.d.ts → userDB-C33Hzjgn.d.mts} +10 -3
- package/dist/{userDB-7fM4tpgr.d.mts → userDB-DusL7OXe.d.ts} +10 -3
- package/dist/util/packer/index.d.mts +3 -63
- package/dist/util/packer/index.d.ts +3 -63
- package/dist/util/packer/index.js +53 -1
- package/dist/util/packer/index.js.map +1 -1
- package/dist/util/packer/index.mjs +53 -1
- package/dist/util/packer/index.mjs.map +1 -1
- package/package.json +7 -4
- package/src/core/types/types-legacy.ts +13 -1
- package/src/core/types/user.ts +9 -2
- package/src/core/util/index.ts +5 -4
- package/src/impl/common/BaseUserDB.ts +33 -22
- package/src/impl/common/SyncStrategy.ts +7 -0
- package/src/impl/common/index.ts +0 -1
- package/src/impl/common/userDBHelpers.ts +4 -4
- package/src/impl/couch/CouchDBSyncStrategy.ts +10 -0
- package/src/impl/couch/courseAPI.ts +7 -6
- package/src/impl/couch/index.ts +10 -5
- package/src/impl/couch/updateQueue.ts +12 -8
- package/src/impl/couch/user-course-relDB.ts +17 -27
- package/src/impl/static/NoOpSyncStrategy.ts +5 -0
- package/src/impl/static/StaticDataUnpacker.ts +18 -36
- package/src/impl/static/courseDB.ts +135 -17
- package/src/util/migrator/FileSystemAdapter.ts +20 -0
- package/src/util/migrator/StaticToCouchDBMigrator.ts +6 -0
- package/src/util/packer/CouchDBToStaticPacker.ts +92 -2
package/dist/index.js
CHANGED
|
@@ -102,7 +102,7 @@ var init_logger = __esm({
|
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
// src/core/types/types-legacy.ts
|
|
105
|
-
var GuestUsername, log, DocType,
|
|
105
|
+
var GuestUsername, log, DocType, DocTypePrefixes;
|
|
106
106
|
var init_types_legacy = __esm({
|
|
107
107
|
"src/core/types/types-legacy.ts"() {
|
|
108
108
|
"use strict";
|
|
@@ -111,20 +111,32 @@ var init_types_legacy = __esm({
|
|
|
111
111
|
log = (message) => {
|
|
112
112
|
logger.log(message);
|
|
113
113
|
};
|
|
114
|
-
DocType = /* @__PURE__ */ ((
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return
|
|
114
|
+
DocType = /* @__PURE__ */ ((DocType3) => {
|
|
115
|
+
DocType3["DISPLAYABLE_DATA"] = "DISPLAYABLE_DATA";
|
|
116
|
+
DocType3["CARD"] = "CARD";
|
|
117
|
+
DocType3["DATASHAPE"] = "DATASHAPE";
|
|
118
|
+
DocType3["QUESTIONTYPE"] = "QUESTION";
|
|
119
|
+
DocType3["VIEW"] = "VIEW";
|
|
120
|
+
DocType3["PEDAGOGY"] = "PEDAGOGY";
|
|
121
|
+
DocType3["CARDRECORD"] = "CARDRECORD";
|
|
122
|
+
DocType3["SCHEDULED_CARD"] = "SCHEDULED_CARD";
|
|
123
|
+
DocType3["TAG"] = "TAG";
|
|
124
|
+
DocType3["NAVIGATION_STRATEGY"] = "NAVIGATION_STRATEGY";
|
|
125
|
+
return DocType3;
|
|
126
126
|
})(DocType || {});
|
|
127
|
-
|
|
127
|
+
DocTypePrefixes = {
|
|
128
|
+
["CARD" /* CARD */]: "c",
|
|
129
|
+
["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]: "dd",
|
|
130
|
+
["TAG" /* TAG */]: "TAG",
|
|
131
|
+
["CARDRECORD" /* CARDRECORD */]: "cardH",
|
|
132
|
+
["SCHEDULED_CARD" /* SCHEDULED_CARD */]: "card_review_",
|
|
133
|
+
// Add other doctypes here as they get prefixed IDs
|
|
134
|
+
["DATASHAPE" /* DATASHAPE */]: "DATASHAPE",
|
|
135
|
+
["QUESTION" /* QUESTIONTYPE */]: "QUESTION",
|
|
136
|
+
["VIEW" /* VIEW */]: "VIEW",
|
|
137
|
+
["PEDAGOGY" /* PEDAGOGY */]: "PEDAGOGY",
|
|
138
|
+
["NAVIGATION_STRATEGY" /* NAVIGATION_STRATEGY */]: "NAVIGATION_STRATEGY"
|
|
139
|
+
};
|
|
128
140
|
}
|
|
129
141
|
});
|
|
130
142
|
|
|
@@ -136,16 +148,16 @@ function isQuestionRecord(c) {
|
|
|
136
148
|
return c.userAnswer !== void 0;
|
|
137
149
|
}
|
|
138
150
|
function getCardHistoryID(courseID, cardID) {
|
|
139
|
-
return `${
|
|
151
|
+
return `${DocTypePrefixes["CARDRECORD" /* CARDRECORD */]}-${courseID}-${cardID}`;
|
|
140
152
|
}
|
|
141
153
|
function parseCardHistoryID(id) {
|
|
142
154
|
const split = id.split("-");
|
|
143
155
|
let error = "";
|
|
144
156
|
error += split.length === 3 ? "" : `
|
|
145
157
|
given ID has incorrect number of '-' characters`;
|
|
146
|
-
error += split[0] ===
|
|
147
|
-
given ID does not start with ${
|
|
148
|
-
if (split.length === 3 && split[0] ===
|
|
158
|
+
error += split[0] === DocTypePrefixes["CARDRECORD" /* CARDRECORD */] ? "" : `
|
|
159
|
+
given ID does not start with ${DocTypePrefixes["CARDRECORD" /* CARDRECORD */]}`;
|
|
160
|
+
if (split.length === 3 && split[0] === DocTypePrefixes["CARDRECORD" /* CARDRECORD */]) {
|
|
149
161
|
return {
|
|
150
162
|
courseID: split[1],
|
|
151
163
|
cardID: split[2]
|
|
@@ -363,11 +375,11 @@ function scheduleCardReviewLocal(userDB, review) {
|
|
|
363
375
|
const now = import_moment.default.utc();
|
|
364
376
|
logger.info(`Scheduling for review in: ${review.time.diff(now, "h") / 24} days`);
|
|
365
377
|
void userDB.put({
|
|
366
|
-
_id:
|
|
378
|
+
_id: DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */] + review.time.format(REVIEW_TIME_FORMAT),
|
|
367
379
|
cardId: review.card_id,
|
|
368
|
-
reviewTime: review.time,
|
|
380
|
+
reviewTime: review.time.toISOString(),
|
|
369
381
|
courseId: review.course_id,
|
|
370
|
-
scheduledAt: now,
|
|
382
|
+
scheduledAt: now.toISOString(),
|
|
371
383
|
scheduledFor: review.scheduledFor,
|
|
372
384
|
schedulingAgentId: review.schedulingAgentId
|
|
373
385
|
});
|
|
@@ -383,15 +395,15 @@ async function removeScheduledCardReviewLocal(userDB, reviewDocID) {
|
|
|
383
395
|
${JSON.stringify(err)}`);
|
|
384
396
|
});
|
|
385
397
|
}
|
|
386
|
-
var import_moment,
|
|
398
|
+
var import_moment, REVIEW_TIME_FORMAT, log2;
|
|
387
399
|
var init_userDBHelpers = __esm({
|
|
388
400
|
"src/impl/common/userDBHelpers.ts"() {
|
|
389
401
|
"use strict";
|
|
390
402
|
import_moment = __toESM(require("moment"));
|
|
403
|
+
init_core();
|
|
391
404
|
init_logger();
|
|
392
405
|
init_pouchdb_setup();
|
|
393
406
|
init_dataDirectory();
|
|
394
|
-
REVIEW_PREFIX = "card_review_";
|
|
395
407
|
REVIEW_TIME_FORMAT = "YYYY-MM-DD--kk:mm:ss-SSS";
|
|
396
408
|
log2 = (s) => {
|
|
397
409
|
logger.info(s);
|
|
@@ -426,7 +438,10 @@ var init_updateQueue = __esm({
|
|
|
426
438
|
_className = "UpdateQueue";
|
|
427
439
|
pendingUpdates = {};
|
|
428
440
|
inprogressUpdates = {};
|
|
429
|
-
|
|
441
|
+
readDB;
|
|
442
|
+
// Database for read operations
|
|
443
|
+
writeDB;
|
|
444
|
+
// Database for write operations (local-first)
|
|
430
445
|
update(id, update) {
|
|
431
446
|
logger.debug(`Update requested on doc: ${id}`);
|
|
432
447
|
if (this.pendingUpdates[id]) {
|
|
@@ -436,24 +451,25 @@ var init_updateQueue = __esm({
|
|
|
436
451
|
}
|
|
437
452
|
return this.applyUpdates(id);
|
|
438
453
|
}
|
|
439
|
-
constructor(
|
|
454
|
+
constructor(readDB, writeDB) {
|
|
440
455
|
super();
|
|
441
|
-
this.
|
|
456
|
+
this.readDB = readDB;
|
|
457
|
+
this.writeDB = writeDB || readDB;
|
|
442
458
|
logger.debug(`UpdateQ initialized...`);
|
|
443
|
-
void this.
|
|
459
|
+
void this.readDB.info().then((i) => {
|
|
444
460
|
logger.debug(`db info: ${JSON.stringify(i)}`);
|
|
445
461
|
});
|
|
446
462
|
}
|
|
447
463
|
async applyUpdates(id) {
|
|
448
464
|
logger.debug(`Applying updates on doc: ${id}`);
|
|
449
465
|
if (this.inprogressUpdates[id]) {
|
|
450
|
-
await this.
|
|
466
|
+
await this.readDB.info();
|
|
451
467
|
return this.applyUpdates(id);
|
|
452
468
|
} else {
|
|
453
469
|
if (this.pendingUpdates[id] && this.pendingUpdates[id].length > 0) {
|
|
454
470
|
this.inprogressUpdates[id] = true;
|
|
455
471
|
try {
|
|
456
|
-
let doc = await this.
|
|
472
|
+
let doc = await this.readDB.get(id);
|
|
457
473
|
logger.debug(`Retrieved doc: ${id}`);
|
|
458
474
|
while (this.pendingUpdates[id].length !== 0) {
|
|
459
475
|
const update = this.pendingUpdates[id].splice(0, 1)[0];
|
|
@@ -466,7 +482,7 @@ var init_updateQueue = __esm({
|
|
|
466
482
|
};
|
|
467
483
|
}
|
|
468
484
|
}
|
|
469
|
-
await this.
|
|
485
|
+
await this.writeDB.put(doc);
|
|
470
486
|
logger.debug(`Put doc: ${id}`);
|
|
471
487
|
if (this.pendingUpdates[id].length === 0) {
|
|
472
488
|
this.inprogressUpdates[id] = false;
|
|
@@ -492,6 +508,60 @@ var init_updateQueue = __esm({
|
|
|
492
508
|
}
|
|
493
509
|
});
|
|
494
510
|
|
|
511
|
+
// src/impl/couch/user-course-relDB.ts
|
|
512
|
+
var import_moment2, UsrCrsData;
|
|
513
|
+
var init_user_course_relDB = __esm({
|
|
514
|
+
"src/impl/couch/user-course-relDB.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
import_moment2 = __toESM(require("moment"));
|
|
517
|
+
init_logger();
|
|
518
|
+
UsrCrsData = class {
|
|
519
|
+
user;
|
|
520
|
+
_courseId;
|
|
521
|
+
constructor(user, courseId) {
|
|
522
|
+
this.user = user;
|
|
523
|
+
this._courseId = courseId;
|
|
524
|
+
}
|
|
525
|
+
async getReviewsForcast(daysCount) {
|
|
526
|
+
const time = import_moment2.default.utc().add(daysCount, "days");
|
|
527
|
+
return this.getReviewstoDate(time);
|
|
528
|
+
}
|
|
529
|
+
async getPendingReviews() {
|
|
530
|
+
const now = import_moment2.default.utc();
|
|
531
|
+
return this.getReviewstoDate(now);
|
|
532
|
+
}
|
|
533
|
+
async getScheduledReviewCount() {
|
|
534
|
+
return (await this.getPendingReviews()).length;
|
|
535
|
+
}
|
|
536
|
+
async getCourseSettings() {
|
|
537
|
+
const regDoc = await this.user.getCourseRegistrationsDoc();
|
|
538
|
+
const crsDoc = regDoc.courses.find((c) => c.courseID === this._courseId);
|
|
539
|
+
if (crsDoc && crsDoc.settings) {
|
|
540
|
+
return crsDoc.settings;
|
|
541
|
+
} else {
|
|
542
|
+
logger.warn(`no settings found during lookup on course ${this._courseId}`);
|
|
543
|
+
return {};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
updateCourseSettings(updates) {
|
|
547
|
+
if ("updateCourseSettings" in this.user) {
|
|
548
|
+
void this.user.updateCourseSettings(this._courseId, updates);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
async getReviewstoDate(targetDate) {
|
|
552
|
+
const allReviews = await this.user.getPendingReviews(this._courseId);
|
|
553
|
+
logger.debug(
|
|
554
|
+
`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`
|
|
555
|
+
);
|
|
556
|
+
return allReviews.filter((review) => {
|
|
557
|
+
const reviewTime = import_moment2.default.utc(review.reviewTime);
|
|
558
|
+
return targetDate.isAfter(reviewTime);
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
495
565
|
// src/impl/couch/clientCache.ts
|
|
496
566
|
async function GET_CACHED(k, f) {
|
|
497
567
|
if (CLIENT_CACHE[k]) {
|
|
@@ -515,7 +585,8 @@ var init_clientCache = __esm({
|
|
|
515
585
|
async function addNote55(courseID, codeCourse, shape, data, author, tags, uploads, elo = (0, import_common2.blankCourseElo)()) {
|
|
516
586
|
const db = getCourseDB(courseID);
|
|
517
587
|
const payload = (0, import_common3.prepareNote55)(courseID, codeCourse, shape, data, author, tags, uploads);
|
|
518
|
-
const
|
|
588
|
+
const _id = `${DocTypePrefixes["DISPLAYABLE_DATA" /* DISPLAYABLE_DATA */]}-${(0, import_uuid.v4)()}`;
|
|
589
|
+
const result = await db.put({ ...payload, _id });
|
|
519
590
|
const dataShapeId = import_common.NameSpacer.getDataShapeString({
|
|
520
591
|
course: codeCourse,
|
|
521
592
|
dataShape: shape.name
|
|
@@ -586,7 +657,9 @@ async function createCard(questionViewName, courseID, dsDescriptor, noteID, tags
|
|
|
586
657
|
}
|
|
587
658
|
async function addCard(courseID, course, id_displayable_data, id_view, elo, tags, author) {
|
|
588
659
|
const db = getCourseDB(courseID);
|
|
589
|
-
const
|
|
660
|
+
const _id = `${DocTypePrefixes["CARD" /* CARD */]}-${(0, import_uuid.v4)()}`;
|
|
661
|
+
const card = await db.put({
|
|
662
|
+
_id,
|
|
590
663
|
course,
|
|
591
664
|
id_displayable_data,
|
|
592
665
|
id_view,
|
|
@@ -679,7 +752,7 @@ function getCourseDB(courseID) {
|
|
|
679
752
|
pouchDBincludeCredentialsConfig
|
|
680
753
|
);
|
|
681
754
|
}
|
|
682
|
-
var import_common, import_common2, import_common3, AlreadyTaggedErr;
|
|
755
|
+
var import_common, import_common2, import_common3, import_uuid, AlreadyTaggedErr;
|
|
683
756
|
var init_courseAPI = __esm({
|
|
684
757
|
"src/impl/couch/courseAPI.ts"() {
|
|
685
758
|
"use strict";
|
|
@@ -693,6 +766,7 @@ var init_courseAPI = __esm({
|
|
|
693
766
|
import_common3 = require("@vue-skuilder/common");
|
|
694
767
|
init_common();
|
|
695
768
|
init_logger();
|
|
769
|
+
import_uuid = require("uuid");
|
|
696
770
|
AlreadyTaggedErr = class extends Error {
|
|
697
771
|
constructor(message) {
|
|
698
772
|
super(message);
|
|
@@ -1493,13 +1567,13 @@ ${above.rows.map((r) => ` ${r.id}-${r.key}
|
|
|
1493
1567
|
});
|
|
1494
1568
|
|
|
1495
1569
|
// src/impl/couch/classroomDB.ts
|
|
1496
|
-
var
|
|
1570
|
+
var import_moment3, classroomLookupDBTitle, CLASSROOM_CONFIG, ClassroomDBBase, StudentClassroomDB, TeacherClassroomDB, ClassroomLookupDB;
|
|
1497
1571
|
var init_classroomDB2 = __esm({
|
|
1498
1572
|
"src/impl/couch/classroomDB.ts"() {
|
|
1499
1573
|
"use strict";
|
|
1500
1574
|
init_factory();
|
|
1501
1575
|
init_logger();
|
|
1502
|
-
|
|
1576
|
+
import_moment3 = __toESM(require("moment"));
|
|
1503
1577
|
init_pouchdb_setup();
|
|
1504
1578
|
init_couch();
|
|
1505
1579
|
init_courseDB();
|
|
@@ -1594,9 +1668,9 @@ var init_classroomDB2 = __esm({
|
|
|
1594
1668
|
}
|
|
1595
1669
|
async getNewCards() {
|
|
1596
1670
|
const activeCards = await this._user.getActiveCards();
|
|
1597
|
-
const now =
|
|
1671
|
+
const now = import_moment3.default.utc();
|
|
1598
1672
|
const assigned = await this.getAssignedContent();
|
|
1599
|
-
const due = assigned.filter((c) => now.isAfter(
|
|
1673
|
+
const due = assigned.filter((c) => now.isAfter(import_moment3.default.utc(c.activeOn, REVIEW_TIME_FORMAT2)));
|
|
1600
1674
|
logger.info(`Due content: ${JSON.stringify(due)}`);
|
|
1601
1675
|
let ret = [];
|
|
1602
1676
|
for (let i = 0; i < due.length; i++) {
|
|
@@ -1687,8 +1761,8 @@ var init_classroomDB2 = __esm({
|
|
|
1687
1761
|
type: "tag",
|
|
1688
1762
|
_id: id,
|
|
1689
1763
|
assignedBy: content.assignedBy,
|
|
1690
|
-
assignedOn:
|
|
1691
|
-
activeOn: content.activeOn ||
|
|
1764
|
+
assignedOn: import_moment3.default.utc(),
|
|
1765
|
+
activeOn: content.activeOn || import_moment3.default.utc()
|
|
1692
1766
|
});
|
|
1693
1767
|
} else {
|
|
1694
1768
|
put = await this._db.put({
|
|
@@ -1696,8 +1770,8 @@ var init_classroomDB2 = __esm({
|
|
|
1696
1770
|
type: "course",
|
|
1697
1771
|
_id: id,
|
|
1698
1772
|
assignedBy: content.assignedBy,
|
|
1699
|
-
assignedOn:
|
|
1700
|
-
activeOn: content.activeOn ||
|
|
1773
|
+
assignedOn: import_moment3.default.utc(),
|
|
1774
|
+
activeOn: content.activeOn || import_moment3.default.utc()
|
|
1701
1775
|
});
|
|
1702
1776
|
}
|
|
1703
1777
|
if (put.ok) {
|
|
@@ -1860,6 +1934,13 @@ var init_CouchDBSyncStrategy = __esm({
|
|
|
1860
1934
|
return this.getUserDB(username);
|
|
1861
1935
|
}
|
|
1862
1936
|
}
|
|
1937
|
+
getWriteDB(username) {
|
|
1938
|
+
if (username === GuestUsername || username.startsWith(GuestUsername)) {
|
|
1939
|
+
return getLocalUserDB(username);
|
|
1940
|
+
} else {
|
|
1941
|
+
return this.getUserDB(username);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1863
1944
|
startSync(localDB, remoteDB) {
|
|
1864
1945
|
if (localDB !== remoteDB) {
|
|
1865
1946
|
this.syncHandle = pouchdb_setup_default.sync(localDB, remoteDB, {
|
|
@@ -2037,13 +2118,13 @@ function getStartAndEndKeys2(key) {
|
|
|
2037
2118
|
endkey: key + "\uFFF0"
|
|
2038
2119
|
};
|
|
2039
2120
|
}
|
|
2040
|
-
var
|
|
2121
|
+
var import_moment4, import_process, isBrowser, GUEST_LOCAL_DB, localUserDB, pouchDBincludeCredentialsConfig, REVIEW_TIME_FORMAT2;
|
|
2041
2122
|
var init_couch = __esm({
|
|
2042
2123
|
"src/impl/couch/index.ts"() {
|
|
2043
2124
|
"use strict";
|
|
2044
2125
|
init_factory();
|
|
2045
2126
|
init_types_legacy();
|
|
2046
|
-
|
|
2127
|
+
import_moment4 = __toESM(require("moment"));
|
|
2047
2128
|
init_logger();
|
|
2048
2129
|
init_pouchdb_setup();
|
|
2049
2130
|
import_process = __toESM(require("process"));
|
|
@@ -2065,78 +2146,10 @@ var init_couch = __esm({
|
|
|
2065
2146
|
return pouchdb_setup_default.fetch(url, opts);
|
|
2066
2147
|
}
|
|
2067
2148
|
};
|
|
2068
|
-
REVIEW_PREFIX2 = "card_review_";
|
|
2069
2149
|
REVIEW_TIME_FORMAT2 = "YYYY-MM-DD--kk:mm:ss-SSS";
|
|
2070
2150
|
}
|
|
2071
2151
|
});
|
|
2072
2152
|
|
|
2073
|
-
// src/impl/couch/user-course-relDB.ts
|
|
2074
|
-
var import_moment4, UsrCrsData;
|
|
2075
|
-
var init_user_course_relDB = __esm({
|
|
2076
|
-
"src/impl/couch/user-course-relDB.ts"() {
|
|
2077
|
-
"use strict";
|
|
2078
|
-
import_moment4 = __toESM(require("moment"));
|
|
2079
|
-
init_couch();
|
|
2080
|
-
init_courseDB();
|
|
2081
|
-
init_logger();
|
|
2082
|
-
UsrCrsData = class {
|
|
2083
|
-
user;
|
|
2084
|
-
course;
|
|
2085
|
-
_courseId;
|
|
2086
|
-
constructor(user, courseId) {
|
|
2087
|
-
this.user = user;
|
|
2088
|
-
this.course = new CourseDB(courseId, async () => this.user);
|
|
2089
|
-
this._courseId = courseId;
|
|
2090
|
-
}
|
|
2091
|
-
async getReviewsForcast(daysCount) {
|
|
2092
|
-
const time = import_moment4.default.utc().add(daysCount, "days");
|
|
2093
|
-
return this.getReviewstoDate(time);
|
|
2094
|
-
}
|
|
2095
|
-
async getPendingReviews() {
|
|
2096
|
-
const now = import_moment4.default.utc();
|
|
2097
|
-
return this.getReviewstoDate(now);
|
|
2098
|
-
}
|
|
2099
|
-
async getScheduledReviewCount() {
|
|
2100
|
-
return (await this.getPendingReviews()).length;
|
|
2101
|
-
}
|
|
2102
|
-
async getCourseSettings() {
|
|
2103
|
-
const regDoc = await this.user.getCourseRegistrationsDoc();
|
|
2104
|
-
const crsDoc = regDoc.courses.find((c) => c.courseID === this._courseId);
|
|
2105
|
-
if (crsDoc && crsDoc.settings) {
|
|
2106
|
-
return crsDoc.settings;
|
|
2107
|
-
} else {
|
|
2108
|
-
logger.warn(`no settings found during lookup on course ${this._courseId}`);
|
|
2109
|
-
return {};
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
updateCourseSettings(updates) {
|
|
2113
|
-
void this.user.updateCourseSettings(this._courseId, updates);
|
|
2114
|
-
}
|
|
2115
|
-
async getReviewstoDate(targetDate) {
|
|
2116
|
-
const keys = getStartAndEndKeys2(REVIEW_PREFIX2);
|
|
2117
|
-
const reviews = await this.user.remote().allDocs({
|
|
2118
|
-
startkey: keys.startkey,
|
|
2119
|
-
endkey: keys.endkey,
|
|
2120
|
-
include_docs: true
|
|
2121
|
-
});
|
|
2122
|
-
logger.debug(
|
|
2123
|
-
`Fetching ${this.user.getUsername()}'s scheduled reviews for course ${this._courseId}.`
|
|
2124
|
-
);
|
|
2125
|
-
return reviews.rows.filter((r) => {
|
|
2126
|
-
if (r.id.startsWith(REVIEW_PREFIX2)) {
|
|
2127
|
-
const date = import_moment4.default.utc(r.id.substr(REVIEW_PREFIX2.length), REVIEW_TIME_FORMAT2);
|
|
2128
|
-
if (targetDate.isAfter(date)) {
|
|
2129
|
-
if (this._courseId === void 0 || r.doc.courseId === this._courseId) {
|
|
2130
|
-
return true;
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
|
-
}).map((r) => r.doc);
|
|
2135
|
-
}
|
|
2136
|
-
};
|
|
2137
|
-
}
|
|
2138
|
-
});
|
|
2139
|
-
|
|
2140
2153
|
// src/impl/common/BaseUserDB.ts
|
|
2141
2154
|
async function getOrCreateClassroomRegistrationsDoc(user) {
|
|
2142
2155
|
let ret;
|
|
@@ -2230,10 +2243,11 @@ async function dropUserFromClassroom(user, classID) {
|
|
|
2230
2243
|
async function getUserClassrooms(user) {
|
|
2231
2244
|
return getOrCreateClassroomRegistrationsDoc(user);
|
|
2232
2245
|
}
|
|
2233
|
-
var import_common8, import_moment5, log4,
|
|
2246
|
+
var import_common8, import_moment5, log4, BaseUser, userCoursesDoc, userClassroomsDoc;
|
|
2234
2247
|
var init_BaseUserDB = __esm({
|
|
2235
2248
|
"src/impl/common/BaseUserDB.ts"() {
|
|
2236
2249
|
"use strict";
|
|
2250
|
+
init_core();
|
|
2237
2251
|
init_util();
|
|
2238
2252
|
import_common8 = require("@vue-skuilder/common");
|
|
2239
2253
|
import_moment5 = __toESM(require("moment"));
|
|
@@ -2246,7 +2260,6 @@ var init_BaseUserDB = __esm({
|
|
|
2246
2260
|
log4 = (s) => {
|
|
2247
2261
|
logger.info(s);
|
|
2248
2262
|
};
|
|
2249
|
-
cardHistoryPrefix2 = "cardH-";
|
|
2250
2263
|
BaseUser = class _BaseUser {
|
|
2251
2264
|
static _instance;
|
|
2252
2265
|
static _initialized = false;
|
|
@@ -2267,11 +2280,13 @@ var init_BaseUserDB = __esm({
|
|
|
2267
2280
|
isLoggedIn() {
|
|
2268
2281
|
return !this._username.startsWith(GuestUsername);
|
|
2269
2282
|
}
|
|
2270
|
-
remoteDB;
|
|
2271
2283
|
remote() {
|
|
2272
2284
|
return this.remoteDB;
|
|
2273
2285
|
}
|
|
2274
2286
|
localDB;
|
|
2287
|
+
remoteDB;
|
|
2288
|
+
writeDB;
|
|
2289
|
+
// Database to use for write operations (local-first approach)
|
|
2275
2290
|
updateQueue;
|
|
2276
2291
|
async createAccount(username, password) {
|
|
2277
2292
|
if (!this.syncStrategy.canCreateAccount()) {
|
|
@@ -2335,8 +2350,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2335
2350
|
const allDocs = await localDB.allDocs({ include_docs: false });
|
|
2336
2351
|
const docsToDelete = allDocs.rows.filter((row) => {
|
|
2337
2352
|
const id = row.id;
|
|
2338
|
-
return id.startsWith(
|
|
2339
|
-
id.startsWith(
|
|
2353
|
+
return id.startsWith(DocTypePrefixes["CARDRECORD" /* CARDRECORD */]) || // Card interaction history
|
|
2354
|
+
id.startsWith(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]) || // Scheduled reviews
|
|
2340
2355
|
id === _BaseUser.DOC_IDS.COURSE_REGISTRATIONS || // Course registrations
|
|
2341
2356
|
id === _BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS || // Classroom registrations
|
|
2342
2357
|
id === _BaseUser.DOC_IDS.CONFIG;
|
|
@@ -2405,7 +2420,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2405
2420
|
*
|
|
2406
2421
|
*/
|
|
2407
2422
|
async getActiveCards() {
|
|
2408
|
-
const keys = getStartAndEndKeys(
|
|
2423
|
+
const keys = getStartAndEndKeys(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]);
|
|
2409
2424
|
const reviews = await this.remoteDB.allDocs({
|
|
2410
2425
|
startkey: keys.startkey,
|
|
2411
2426
|
endkey: keys.endkey,
|
|
@@ -2477,7 +2492,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2477
2492
|
}
|
|
2478
2493
|
}
|
|
2479
2494
|
async getReviewstoDate(targetDate, course_id) {
|
|
2480
|
-
const keys = getStartAndEndKeys(
|
|
2495
|
+
const keys = getStartAndEndKeys(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */]);
|
|
2481
2496
|
const reviews = await this.remoteDB.allDocs({
|
|
2482
2497
|
startkey: keys.startkey,
|
|
2483
2498
|
endkey: keys.endkey,
|
|
@@ -2487,8 +2502,11 @@ Currently logged-in as ${this._username}.`
|
|
|
2487
2502
|
`Fetching ${this._username}'s scheduled reviews${course_id ? ` for course ${course_id}` : ""}.`
|
|
2488
2503
|
);
|
|
2489
2504
|
return reviews.rows.filter((r) => {
|
|
2490
|
-
if (r.id.startsWith(
|
|
2491
|
-
const date = import_moment5.default.utc(
|
|
2505
|
+
if (r.id.startsWith(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */])) {
|
|
2506
|
+
const date = import_moment5.default.utc(
|
|
2507
|
+
r.id.substr(DocTypePrefixes["SCHEDULED_CARD" /* SCHEDULED_CARD */].length),
|
|
2508
|
+
REVIEW_TIME_FORMAT
|
|
2509
|
+
);
|
|
2492
2510
|
if (targetDate.isAfter(date)) {
|
|
2493
2511
|
if (course_id === void 0 || r.doc.courseId === course_id) {
|
|
2494
2512
|
return true;
|
|
@@ -2603,7 +2621,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2603
2621
|
const defaultConfig = {
|
|
2604
2622
|
_id: _BaseUser.DOC_IDS.CONFIG,
|
|
2605
2623
|
darkMode: false,
|
|
2606
|
-
likesConfetti: false
|
|
2624
|
+
likesConfetti: false,
|
|
2625
|
+
sessionTimeLimit: 5
|
|
2607
2626
|
};
|
|
2608
2627
|
try {
|
|
2609
2628
|
const cfg = await this.localDB.get(_BaseUser.DOC_IDS.CONFIG);
|
|
@@ -2676,7 +2695,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2676
2695
|
setDBandQ() {
|
|
2677
2696
|
this.localDB = getLocalUserDB(this._username);
|
|
2678
2697
|
this.remoteDB = this.syncStrategy.setupRemoteDB(this._username);
|
|
2679
|
-
this.
|
|
2698
|
+
this.writeDB = this.syncStrategy.getWriteDB ? this.syncStrategy.getWriteDB(this._username) : this.localDB;
|
|
2699
|
+
this.updateQueue = new UpdateQueue(this.localDB, this.writeDB);
|
|
2680
2700
|
}
|
|
2681
2701
|
async init() {
|
|
2682
2702
|
_BaseUser._initialized = false;
|
|
@@ -2794,8 +2814,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2794
2814
|
streak: 0,
|
|
2795
2815
|
bestInterval: 0
|
|
2796
2816
|
};
|
|
2797
|
-
|
|
2798
|
-
return initCardHistory;
|
|
2817
|
+
const putResult = await this.writeDB.put(initCardHistory);
|
|
2818
|
+
return { ...initCardHistory, _rev: putResult.rev };
|
|
2799
2819
|
} else {
|
|
2800
2820
|
throw new Error(`putCardRecord failed because of:
|
|
2801
2821
|
name:${reason.name}
|
|
@@ -2830,7 +2850,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2830
2850
|
const deletePromises = duplicateDocIds.map(async (docId) => {
|
|
2831
2851
|
try {
|
|
2832
2852
|
const doc = await this.remoteDB.get(docId);
|
|
2833
|
-
await this.
|
|
2853
|
+
await this.writeDB.remove(doc);
|
|
2834
2854
|
log4(`Successfully removed duplicate review: ${docId}`);
|
|
2835
2855
|
} catch (error) {
|
|
2836
2856
|
log4(`Failed to remove duplicate review ${docId}: ${error}`);
|
|
@@ -2852,7 +2872,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2852
2872
|
* @param course_id optional specification of individual course
|
|
2853
2873
|
*/
|
|
2854
2874
|
async getSeenCards(course_id) {
|
|
2855
|
-
let prefix =
|
|
2875
|
+
let prefix = DocTypePrefixes["CARDRECORD" /* CARDRECORD */];
|
|
2856
2876
|
if (course_id) {
|
|
2857
2877
|
prefix += course_id;
|
|
2858
2878
|
}
|
|
@@ -2861,8 +2881,8 @@ Currently logged-in as ${this._username}.`
|
|
|
2861
2881
|
});
|
|
2862
2882
|
const ret = [];
|
|
2863
2883
|
docs.rows.forEach((row) => {
|
|
2864
|
-
if (row.id.startsWith(
|
|
2865
|
-
ret.push(row.id.substr(
|
|
2884
|
+
if (row.id.startsWith(DocTypePrefixes["CARDRECORD" /* CARDRECORD */])) {
|
|
2885
|
+
ret.push(row.id.substr(DocTypePrefixes["CARDRECORD" /* CARDRECORD */].length));
|
|
2866
2886
|
}
|
|
2867
2887
|
});
|
|
2868
2888
|
return ret;
|
|
@@ -2874,7 +2894,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2874
2894
|
async getHistory() {
|
|
2875
2895
|
const cards = await filterAllDocsByPrefix(
|
|
2876
2896
|
this.remoteDB,
|
|
2877
|
-
|
|
2897
|
+
DocTypePrefixes["CARDRECORD" /* CARDRECORD */],
|
|
2878
2898
|
{
|
|
2879
2899
|
include_docs: true,
|
|
2880
2900
|
attachments: false
|
|
@@ -2915,7 +2935,7 @@ Currently logged-in as ${this._username}.`
|
|
|
2915
2935
|
} catch (e) {
|
|
2916
2936
|
const err = e;
|
|
2917
2937
|
if (err.status === 404) {
|
|
2918
|
-
await this.
|
|
2938
|
+
await this.writeDB.put({
|
|
2919
2939
|
_id: _BaseUser.DOC_IDS.CLASSROOM_REGISTRATIONS,
|
|
2920
2940
|
registrations: []
|
|
2921
2941
|
});
|
|
@@ -2963,10 +2983,10 @@ Currently logged-in as ${this._username}.`
|
|
|
2963
2983
|
}
|
|
2964
2984
|
}
|
|
2965
2985
|
async scheduleCardReview(review) {
|
|
2966
|
-
return scheduleCardReviewLocal(this.
|
|
2986
|
+
return scheduleCardReviewLocal(this.writeDB, review);
|
|
2967
2987
|
}
|
|
2968
2988
|
async removeScheduledCardReview(reviewId) {
|
|
2969
|
-
return removeScheduledCardReviewLocal(this.
|
|
2989
|
+
return removeScheduledCardReviewLocal(this.writeDB, reviewId);
|
|
2970
2990
|
}
|
|
2971
2991
|
async registerForClassroom(_classId, _registerAs) {
|
|
2972
2992
|
return registerUserForClassroom(this._username, _classId, _registerAs);
|
|
@@ -3178,18 +3198,21 @@ var init_StaticDataUnpacker = __esm({
|
|
|
3178
3198
|
async getTagsIndex() {
|
|
3179
3199
|
return await this.loadIndex("tags");
|
|
3180
3200
|
}
|
|
3201
|
+
getDocTypeFromId(id) {
|
|
3202
|
+
for (const docTypeKey in DocTypePrefixes) {
|
|
3203
|
+
const prefix = DocTypePrefixes[docTypeKey];
|
|
3204
|
+
if (id.startsWith(`${prefix}-`)) {
|
|
3205
|
+
return docTypeKey;
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
return void 0;
|
|
3209
|
+
}
|
|
3181
3210
|
/**
|
|
3182
3211
|
* Find which chunk contains a specific document ID
|
|
3183
3212
|
*/
|
|
3184
3213
|
async findChunkForDocument(docId) {
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
if (docId.startsWith(`${docType}-`)) {
|
|
3188
|
-
expectedDocType = docType;
|
|
3189
|
-
break;
|
|
3190
|
-
}
|
|
3191
|
-
}
|
|
3192
|
-
if (expectedDocType !== void 0) {
|
|
3214
|
+
const expectedDocType = this.getDocTypeFromId(docId);
|
|
3215
|
+
if (expectedDocType) {
|
|
3193
3216
|
const typeChunks = this.manifest.chunks.filter((c) => c.docType === expectedDocType);
|
|
3194
3217
|
for (const chunk of typeChunks) {
|
|
3195
3218
|
if (docId >= chunk.startKey && docId <= chunk.endKey) {
|
|
@@ -3199,21 +3222,8 @@ var init_StaticDataUnpacker = __esm({
|
|
|
3199
3222
|
}
|
|
3200
3223
|
}
|
|
3201
3224
|
}
|
|
3202
|
-
return void 0;
|
|
3203
3225
|
} else {
|
|
3204
|
-
const
|
|
3205
|
-
(c) => c.docType === "DISPLAYABLE_DATA"
|
|
3206
|
-
);
|
|
3207
|
-
for (const chunk of displayableChunks) {
|
|
3208
|
-
if (docId >= chunk.startKey && docId <= chunk.endKey) {
|
|
3209
|
-
const exists = await this.verifyDocumentInChunk(docId, chunk);
|
|
3210
|
-
if (exists) {
|
|
3211
|
-
return chunk;
|
|
3212
|
-
}
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3215
|
-
const cardChunks = this.manifest.chunks.filter((c) => c.docType === "CARD");
|
|
3216
|
-
for (const chunk of cardChunks) {
|
|
3226
|
+
for (const chunk of this.manifest.chunks) {
|
|
3217
3227
|
if (docId >= chunk.startKey && docId <= chunk.endKey) {
|
|
3218
3228
|
const exists = await this.verifyDocumentInChunk(docId, chunk);
|
|
3219
3229
|
if (exists) {
|
|
@@ -3234,6 +3244,7 @@ var init_StaticDataUnpacker = __esm({
|
|
|
3234
3244
|
}
|
|
3235
3245
|
return void 0;
|
|
3236
3246
|
}
|
|
3247
|
+
return void 0;
|
|
3237
3248
|
}
|
|
3238
3249
|
/**
|
|
3239
3250
|
* Verify that a document actually exists in a specific chunk by loading and checking it
|
|
@@ -3477,6 +3488,7 @@ var init_courseDB2 = __esm({
|
|
|
3477
3488
|
import_common10 = require("@vue-skuilder/common");
|
|
3478
3489
|
init_types_legacy();
|
|
3479
3490
|
init_navigators();
|
|
3491
|
+
init_logger();
|
|
3480
3492
|
StaticCourseDB = class {
|
|
3481
3493
|
constructor(courseId, unpacker, userDB, manifest) {
|
|
3482
3494
|
this.courseId = courseId;
|
|
@@ -3498,10 +3510,11 @@ var init_courseDB2 = __esm({
|
|
|
3498
3510
|
throw new Error("Cannot update course config in static mode");
|
|
3499
3511
|
}
|
|
3500
3512
|
async getCourseInfo() {
|
|
3513
|
+
const cardCount = this.manifest.chunks.filter((chunk) => chunk.docType === "CARD" /* CARD */).reduce((total, chunk) => total + chunk.documentCount, 0);
|
|
3501
3514
|
return {
|
|
3502
|
-
cardCount
|
|
3503
|
-
// Would come from manifest
|
|
3515
|
+
cardCount,
|
|
3504
3516
|
registeredUsers: 0
|
|
3517
|
+
// Always 0 in static mode
|
|
3505
3518
|
};
|
|
3506
3519
|
}
|
|
3507
3520
|
async getCourseDoc(id, _options) {
|
|
@@ -3590,12 +3603,56 @@ var init_courseDB2 = __esm({
|
|
|
3590
3603
|
courseID: this.courseId
|
|
3591
3604
|
}));
|
|
3592
3605
|
}
|
|
3593
|
-
async getAppliedTags(
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
rows
|
|
3598
|
-
|
|
3606
|
+
async getAppliedTags(cardId) {
|
|
3607
|
+
try {
|
|
3608
|
+
const tagsIndex = await this.unpacker.getTagsIndex();
|
|
3609
|
+
const cardTags = tagsIndex.byCard[cardId] || [];
|
|
3610
|
+
const rows = await Promise.all(
|
|
3611
|
+
cardTags.map(async (tagName) => {
|
|
3612
|
+
const tagId = `${"TAG" /* TAG */}-${tagName}`;
|
|
3613
|
+
try {
|
|
3614
|
+
const tagDoc = await this.unpacker.getDocument(tagId);
|
|
3615
|
+
return {
|
|
3616
|
+
id: tagId,
|
|
3617
|
+
key: cardId,
|
|
3618
|
+
value: {
|
|
3619
|
+
name: tagDoc.name,
|
|
3620
|
+
snippet: tagDoc.snippet,
|
|
3621
|
+
count: tagDoc.taggedCards?.length || 0
|
|
3622
|
+
}
|
|
3623
|
+
};
|
|
3624
|
+
} catch (error) {
|
|
3625
|
+
if (error && error.status === 404) {
|
|
3626
|
+
logger.warn(`Tag document not found for ${tagName}, creating stub`);
|
|
3627
|
+
} else {
|
|
3628
|
+
logger.error(`Error getting tag document for ${tagName}:`, error);
|
|
3629
|
+
throw error;
|
|
3630
|
+
}
|
|
3631
|
+
return {
|
|
3632
|
+
id: tagId,
|
|
3633
|
+
key: cardId,
|
|
3634
|
+
value: {
|
|
3635
|
+
name: tagName,
|
|
3636
|
+
snippet: `Tag: ${tagName}`,
|
|
3637
|
+
count: tagsIndex.byTag[tagName]?.length || 0
|
|
3638
|
+
}
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
})
|
|
3642
|
+
);
|
|
3643
|
+
return {
|
|
3644
|
+
total_rows: rows.length,
|
|
3645
|
+
offset: 0,
|
|
3646
|
+
rows
|
|
3647
|
+
};
|
|
3648
|
+
} catch (error) {
|
|
3649
|
+
logger.error(`Error getting applied tags for card ${cardId}:`, error);
|
|
3650
|
+
return {
|
|
3651
|
+
total_rows: 0,
|
|
3652
|
+
offset: 0,
|
|
3653
|
+
rows: []
|
|
3654
|
+
};
|
|
3655
|
+
}
|
|
3599
3656
|
}
|
|
3600
3657
|
async addTagToCard(_cardId, _tagId) {
|
|
3601
3658
|
throw new Error("Cannot modify tags in static mode");
|
|
@@ -3613,11 +3670,69 @@ var init_courseDB2 = __esm({
|
|
|
3613
3670
|
throw new Error("Cannot update tags in static mode");
|
|
3614
3671
|
}
|
|
3615
3672
|
async getCourseTagStubs() {
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3673
|
+
try {
|
|
3674
|
+
const tagsIndex = await this.unpacker.getTagsIndex();
|
|
3675
|
+
if (!tagsIndex || !tagsIndex.byTag) {
|
|
3676
|
+
logger.warn("Tags index not found or empty");
|
|
3677
|
+
return {
|
|
3678
|
+
total_rows: 0,
|
|
3679
|
+
offset: 0,
|
|
3680
|
+
rows: []
|
|
3681
|
+
};
|
|
3682
|
+
}
|
|
3683
|
+
const tagNames = Object.keys(tagsIndex.byTag);
|
|
3684
|
+
const rows = await Promise.all(
|
|
3685
|
+
tagNames.map(async (tagName) => {
|
|
3686
|
+
const cardIds = tagsIndex.byTag[tagName] || [];
|
|
3687
|
+
const tagId = `${"TAG" /* TAG */}-${tagName}`;
|
|
3688
|
+
try {
|
|
3689
|
+
const tagDoc = await this.unpacker.getDocument(tagId);
|
|
3690
|
+
return {
|
|
3691
|
+
id: tagId,
|
|
3692
|
+
key: tagId,
|
|
3693
|
+
value: { rev: "1-static" },
|
|
3694
|
+
doc: tagDoc
|
|
3695
|
+
};
|
|
3696
|
+
} catch (error) {
|
|
3697
|
+
if (error && error.status === 404) {
|
|
3698
|
+
logger.warn(`Tag document not found for ${tagName}, creating stub`);
|
|
3699
|
+
const stubDoc = {
|
|
3700
|
+
_id: tagId,
|
|
3701
|
+
_rev: "1-static",
|
|
3702
|
+
course: this.courseId,
|
|
3703
|
+
docType: "TAG" /* TAG */,
|
|
3704
|
+
name: tagName,
|
|
3705
|
+
snippet: `Tag: ${tagName}`,
|
|
3706
|
+
wiki: "",
|
|
3707
|
+
taggedCards: cardIds,
|
|
3708
|
+
author: "system"
|
|
3709
|
+
};
|
|
3710
|
+
return {
|
|
3711
|
+
id: tagId,
|
|
3712
|
+
key: tagId,
|
|
3713
|
+
value: { rev: "1-static" },
|
|
3714
|
+
doc: stubDoc
|
|
3715
|
+
};
|
|
3716
|
+
} else {
|
|
3717
|
+
logger.error(`Error getting tag document for ${tagName}:`, error);
|
|
3718
|
+
throw error;
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
})
|
|
3722
|
+
);
|
|
3723
|
+
return {
|
|
3724
|
+
total_rows: rows.length,
|
|
3725
|
+
offset: 0,
|
|
3726
|
+
rows
|
|
3727
|
+
};
|
|
3728
|
+
} catch (error) {
|
|
3729
|
+
logger.error("Failed to get course tag stubs:", error);
|
|
3730
|
+
return {
|
|
3731
|
+
total_rows: 0,
|
|
3732
|
+
offset: 0,
|
|
3733
|
+
rows: []
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3621
3736
|
}
|
|
3622
3737
|
async addNote(_codeCourse, _shape, _data, _author, _tags, _uploads, _elo) {
|
|
3623
3738
|
return {
|
|
@@ -3723,6 +3838,9 @@ var init_NoOpSyncStrategy = __esm({
|
|
|
3723
3838
|
setupRemoteDB(username) {
|
|
3724
3839
|
return getLocalUserDB(username);
|
|
3725
3840
|
}
|
|
3841
|
+
getWriteDB(username) {
|
|
3842
|
+
return getLocalUserDB(username);
|
|
3843
|
+
}
|
|
3726
3844
|
startSync(_localDB, _remoteDB) {
|
|
3727
3845
|
}
|
|
3728
3846
|
stopSync() {
|
|
@@ -4117,6 +4235,7 @@ __export(index_exports, {
|
|
|
4117
4235
|
CouchDBToStaticPacker: () => CouchDBToStaticPacker,
|
|
4118
4236
|
CourseLookup: () => CourseLookup,
|
|
4119
4237
|
DocType: () => DocType,
|
|
4238
|
+
DocTypePrefixes: () => DocTypePrefixes,
|
|
4120
4239
|
ENV: () => ENV,
|
|
4121
4240
|
FileSystemError: () => FileSystemError,
|
|
4122
4241
|
GuestUsername: () => GuestUsername,
|
|
@@ -4126,7 +4245,6 @@ __export(index_exports, {
|
|
|
4126
4245
|
StaticToCouchDBMigrator: () => StaticToCouchDBMigrator,
|
|
4127
4246
|
_resetDataLayer: () => _resetDataLayer,
|
|
4128
4247
|
areQuestionRecords: () => areQuestionRecords,
|
|
4129
|
-
cardHistoryPrefix: () => cardHistoryPrefix,
|
|
4130
4248
|
docIsDeleted: () => docIsDeleted,
|
|
4131
4249
|
ensureAppDataDirectory: () => ensureAppDataDirectory,
|
|
4132
4250
|
getAppDataDirectory: () => getAppDataDirectory,
|
|
@@ -4216,6 +4334,57 @@ var CouchDBToStaticPacker = class {
|
|
|
4216
4334
|
attachments
|
|
4217
4335
|
};
|
|
4218
4336
|
}
|
|
4337
|
+
/**
|
|
4338
|
+
* Pack a CouchDB course database and write the static files to disk
|
|
4339
|
+
*/
|
|
4340
|
+
async packCourseToFiles(sourceDB, courseId, outputDir, fsAdapter) {
|
|
4341
|
+
logger.info(`Packing course ${courseId} to files in ${outputDir}`);
|
|
4342
|
+
const packedData = await this.packCourse(sourceDB, courseId);
|
|
4343
|
+
const filesWritten = await this.writePackedDataToFiles(packedData, outputDir, fsAdapter);
|
|
4344
|
+
return {
|
|
4345
|
+
manifest: packedData.manifest,
|
|
4346
|
+
filesWritten,
|
|
4347
|
+
attachmentsFound: packedData.attachments ? packedData.attachments.size : 0
|
|
4348
|
+
};
|
|
4349
|
+
}
|
|
4350
|
+
/**
|
|
4351
|
+
* Write packed course data to files using FileSystemAdapter
|
|
4352
|
+
*/
|
|
4353
|
+
async writePackedDataToFiles(packedData, outputDir, fsAdapter) {
|
|
4354
|
+
let totalFiles = 0;
|
|
4355
|
+
await fsAdapter.ensureDir(outputDir);
|
|
4356
|
+
const manifestPath = fsAdapter.joinPath(outputDir, "manifest.json");
|
|
4357
|
+
await fsAdapter.writeJson(manifestPath, packedData.manifest, { spaces: 2 });
|
|
4358
|
+
totalFiles++;
|
|
4359
|
+
logger.info(`Wrote manifest: ${manifestPath}`);
|
|
4360
|
+
const chunksDir = fsAdapter.joinPath(outputDir, "chunks");
|
|
4361
|
+
const indicesDir = fsAdapter.joinPath(outputDir, "indices");
|
|
4362
|
+
await fsAdapter.ensureDir(chunksDir);
|
|
4363
|
+
await fsAdapter.ensureDir(indicesDir);
|
|
4364
|
+
for (const [chunkId, chunkData] of packedData.chunks) {
|
|
4365
|
+
const chunkPath = fsAdapter.joinPath(chunksDir, `${chunkId}.json`);
|
|
4366
|
+
await fsAdapter.writeJson(chunkPath, chunkData);
|
|
4367
|
+
totalFiles++;
|
|
4368
|
+
}
|
|
4369
|
+
logger.info(`Wrote ${packedData.chunks.size} chunk files`);
|
|
4370
|
+
for (const [indexName, indexData] of packedData.indices) {
|
|
4371
|
+
const indexPath = fsAdapter.joinPath(indicesDir, `${indexName}.json`);
|
|
4372
|
+
await fsAdapter.writeJson(indexPath, indexData, { spaces: 2 });
|
|
4373
|
+
totalFiles++;
|
|
4374
|
+
}
|
|
4375
|
+
logger.info(`Wrote ${packedData.indices.size} index files`);
|
|
4376
|
+
if (packedData.attachments && packedData.attachments.size > 0) {
|
|
4377
|
+
for (const [attachmentPath, attachmentData] of packedData.attachments) {
|
|
4378
|
+
const fullAttachmentPath = fsAdapter.joinPath(outputDir, attachmentPath);
|
|
4379
|
+
const attachmentDir = fsAdapter.dirname(fullAttachmentPath);
|
|
4380
|
+
await fsAdapter.ensureDir(attachmentDir);
|
|
4381
|
+
await fsAdapter.writeFile(fullAttachmentPath, attachmentData.buffer);
|
|
4382
|
+
totalFiles++;
|
|
4383
|
+
}
|
|
4384
|
+
logger.info(`Wrote ${packedData.attachments.size} attachment files`);
|
|
4385
|
+
}
|
|
4386
|
+
return totalFiles;
|
|
4387
|
+
}
|
|
4219
4388
|
async extractCourseConfig(db) {
|
|
4220
4389
|
try {
|
|
4221
4390
|
return await db.get("CourseConfig");
|
|
@@ -4384,7 +4553,8 @@ var CouchDBToStaticPacker = class {
|
|
|
4384
4553
|
}
|
|
4385
4554
|
try {
|
|
4386
4555
|
const designDocId = designDoc._id;
|
|
4387
|
-
const
|
|
4556
|
+
const designDocName = designDocId.replace("_design/", "");
|
|
4557
|
+
const viewPath = `${designDocName}/${viewName}`;
|
|
4388
4558
|
logger.info(`Querying CouchDB view: ${viewPath}`);
|
|
4389
4559
|
const viewResults = await this.sourceDB.query(viewPath, {
|
|
4390
4560
|
include_docs: false
|
|
@@ -5309,6 +5479,7 @@ var StaticToCouchDBMigrator = class {
|
|
|
5309
5479
|
const docsToInsert = batch.map((doc) => {
|
|
5310
5480
|
const cleanDoc = { ...doc };
|
|
5311
5481
|
delete cleanDoc._rev;
|
|
5482
|
+
delete cleanDoc._attachments;
|
|
5312
5483
|
return cleanDoc;
|
|
5313
5484
|
});
|
|
5314
5485
|
const bulkResult = await db.bulkDocs(docsToInsert);
|
|
@@ -5422,9 +5593,11 @@ var StaticToCouchDBMigrator = class {
|
|
|
5422
5593
|
attachmentData = await response.arrayBuffer();
|
|
5423
5594
|
}
|
|
5424
5595
|
}
|
|
5596
|
+
const doc = await db.get(docId);
|
|
5425
5597
|
await db.putAttachment(
|
|
5426
5598
|
docId,
|
|
5427
5599
|
attachmentName,
|
|
5600
|
+
doc._rev,
|
|
5428
5601
|
attachmentData,
|
|
5429
5602
|
// PouchDB accepts both ArrayBuffer and Buffer
|
|
5430
5603
|
attachmentMeta.content_type
|
|
@@ -5893,6 +6066,7 @@ init_factory();
|
|
|
5893
6066
|
CouchDBToStaticPacker,
|
|
5894
6067
|
CourseLookup,
|
|
5895
6068
|
DocType,
|
|
6069
|
+
DocTypePrefixes,
|
|
5896
6070
|
ENV,
|
|
5897
6071
|
FileSystemError,
|
|
5898
6072
|
GuestUsername,
|
|
@@ -5902,7 +6076,6 @@ init_factory();
|
|
|
5902
6076
|
StaticToCouchDBMigrator,
|
|
5903
6077
|
_resetDataLayer,
|
|
5904
6078
|
areQuestionRecords,
|
|
5905
|
-
cardHistoryPrefix,
|
|
5906
6079
|
docIsDeleted,
|
|
5907
6080
|
ensureAppDataDirectory,
|
|
5908
6081
|
getAppDataDirectory,
|