@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.
- package/dist/core/index.d.mts +5 -5
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +212 -50
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +212 -50
- package/dist/core/index.mjs.map +1 -1
- package/dist/{dataLayerProvider-DqtNroSh.d.ts → dataLayerProvider-VieuAAkV.d.mts} +8 -1
- package/dist/{dataLayerProvider-BInqI_RF.d.mts → dataLayerProvider-juuqUHOP.d.ts} +8 -1
- package/dist/impl/couch/index.d.mts +19 -7
- package/dist/impl/couch/index.d.ts +19 -7
- package/dist/impl/couch/index.js +229 -63
- package/dist/impl/couch/index.js.map +1 -1
- package/dist/impl/couch/index.mjs +228 -62
- package/dist/impl/couch/index.mjs.map +1 -1
- package/dist/impl/static/index.d.mts +13 -6
- package/dist/impl/static/index.d.ts +13 -6
- package/dist/impl/static/index.js +142 -46
- package/dist/impl/static/index.js.map +1 -1
- package/dist/impl/static/index.mjs +142 -46
- package/dist/impl/static/index.mjs.map +1 -1
- package/dist/{index-CLL31bEy.d.ts → index-CWY6yhkV.d.ts} +1 -1
- package/dist/{index-CUNnL38E.d.mts → index-DZyxHCcf.d.mts} +1 -1
- package/dist/index.d.mts +28 -20
- package/dist/index.d.ts +28 -20
- package/dist/index.js +374 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +378 -108
- package/dist/index.mjs.map +1 -1
- package/dist/pouch/index.d.mts +1 -0
- package/dist/pouch/index.d.ts +1 -0
- package/dist/pouch/index.js +49 -0
- package/dist/pouch/index.js.map +1 -0
- package/dist/pouch/index.mjs +16 -0
- package/dist/pouch/index.mjs.map +1 -0
- package/dist/{types-DC-ckZug.d.mts → types-Che4wTwA.d.mts} +1 -1
- package/dist/{types-BefDGkKa.d.ts → types-DtoI27Xh.d.ts} +1 -1
- package/dist/{types-legacy-Birv-Jx6.d.mts → types-legacy-B8ahaCbj.d.mts} +5 -1
- package/dist/{types-legacy-Birv-Jx6.d.ts → types-legacy-B8ahaCbj.d.ts} +5 -1
- package/dist/{userDB-C33Hzjgn.d.mts → userDB-B7zTQ123.d.ts} +88 -55
- package/dist/{userDB-DusL7OXe.d.ts → userDB-DJ8HMw83.d.mts} +88 -55
- package/dist/util/packer/index.d.mts +3 -3
- package/dist/util/packer/index.d.ts +3 -3
- package/package.json +3 -3
- package/src/core/interfaces/contentSource.ts +3 -2
- package/src/core/interfaces/courseDB.ts +26 -3
- package/src/core/interfaces/dataLayerProvider.ts +9 -1
- package/src/core/interfaces/userDB.ts +80 -64
- package/src/core/navigators/elo.ts +10 -7
- package/src/core/navigators/index.ts +1 -1
- package/src/core/types/types-legacy.ts +5 -0
- package/src/impl/common/BaseUserDB.ts +45 -3
- package/src/impl/couch/CouchDBSyncStrategy.ts +2 -2
- package/src/impl/couch/PouchDataLayerProvider.ts +21 -0
- package/src/impl/couch/adminDB.ts +2 -2
- package/src/impl/couch/auth.ts +13 -4
- package/src/impl/couch/classroomDB.ts +10 -12
- package/src/impl/couch/courseAPI.ts +2 -2
- package/src/impl/couch/courseDB.ts +130 -11
- package/src/impl/couch/courseLookupDB.ts +4 -3
- package/src/impl/couch/index.ts +36 -4
- package/src/impl/couch/pouchdb-setup.ts +3 -3
- package/src/impl/couch/updateQueue.ts +51 -33
- package/src/impl/static/StaticDataLayerProvider.ts +11 -0
- package/src/impl/static/courseDB.ts +47 -8
- package/src/pouch/index.ts +2 -0
- package/src/study/SessionController.ts +168 -51
- package/src/study/SpacedRepetition.ts +1 -1
- 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
|
-
|
|
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
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
-
|
|
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(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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
|
-
|
|
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", "
|
|
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) =>
|
|
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
|
-
|
|
1218
|
-
|
|
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((
|
|
2205
|
+
return cardIds.slice(0, options.limit).map((card) => ({
|
|
2126
2206
|
status: "new",
|
|
2127
|
-
qualifiedID: `${this.courseId}-${cardId}`,
|
|
2128
|
-
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
|
}
|