@vue-skuilder/db 0.1.14-2 → 0.1.14

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.
@@ -258,6 +258,33 @@ var init_updateQueue = __esm({
258
258
  // Database for read operations
259
259
  writeDB;
260
260
  // Database for write operations (local-first)
261
+ /**
262
+ * Queues an update for a document and applies it with conflict resolution.
263
+ *
264
+ * @param id - Document ID to update
265
+ * @param update - Partial object or function that transforms the document
266
+ * @returns Promise resolving to the updated document
267
+ *
268
+ * @throws {PouchError} with status 404 if document doesn't exist
269
+ *
270
+ * @remarks
271
+ * **Error Handling Pattern:**
272
+ * - This method does NOT create documents if they don't exist
273
+ * - Callers are responsible for handling 404 errors and creating documents
274
+ * - This design maintains separation of concerns (UpdateQueue handles conflicts, callers handle lifecycle)
275
+ *
276
+ * @example
277
+ * ```typescript
278
+ * try {
279
+ * await updateQueue.update(docId, (doc) => ({ ...doc, field: newValue }));
280
+ * } catch (e) {
281
+ * if ((e as PouchError).status === 404) {
282
+ * // Create the document with initial values
283
+ * await db.put({ _id: docId, field: newValue, ...initialFields });
284
+ * }
285
+ * }
286
+ * ```
287
+ */
261
288
  update(id, update) {
262
289
  logger.debug(`Update requested on doc: ${id}`);
263
290
  if (this.pendingUpdates[id]) {
@@ -290,7 +317,6 @@ var init_updateQueue = __esm({
290
317
  for (let i = 0; i < MAX_RETRIES; i++) {
291
318
  try {
292
319
  const doc = await this.readDB.get(id);
293
- logger.debug(`Retrieved doc: ${id}`);
294
320
  let updatedDoc = { ...doc };
295
321
  const updatesToApply = [...this.pendingUpdates[id]];
296
322
  for (const update of updatesToApply) {
@@ -304,7 +330,6 @@ var init_updateQueue = __esm({
304
330
  }
305
331
  }
306
332
  await this.writeDB.put(updatedDoc);
307
- logger.debug(`Put doc: ${id}`);
308
333
  this.pendingUpdates[id].splice(0, updatesToApply.length);
309
334
  if (this.pendingUpdates[id].length === 0) {
310
335
  this.inprogressUpdates[id] = false;
@@ -319,6 +344,7 @@ var init_updateQueue = __esm({
319
344
  await new Promise((res) => setTimeout(res, 50 * Math.random()));
320
345
  } else if (e.name === "not_found" && i === 0) {
321
346
  logger.warn(`Update failed for ${id} - does not exist. Throwing to caller.`);
347
+ delete this.inprogressUpdates[id];
322
348
  throw e;
323
349
  } else {
324
350
  delete this.inprogressUpdates[id];
@@ -1483,12 +1509,22 @@ Currently logged-in as ${this._username}.`
1483
1509
  }
1484
1510
  /**
1485
1511
  * Logs a record of the user's interaction with the card and returns the card's
1486
- * up-to-date history
1512
+ * up-to-date history.
1513
+ *
1514
+ * **Automatic Initialization:**
1515
+ * If this is the user's first interaction with the card (CardHistory doesn't exist),
1516
+ * this method automatically creates the CardHistory document with initial values
1517
+ * (lapses: 0, streak: 0, bestInterval: 0).
1518
+ *
1519
+ * **Error Handling:**
1520
+ * - Handles 404 errors by creating initial CardHistory document
1521
+ * - Re-throws all other errors from UpdateQueue
1487
1522
  *
1488
1523
  * // [ ] #db-refactor extract to a smaller scope - eg, UserStudySession
1489
1524
  *
1490
- * @param record the recent recorded interaction between user and card
1525
+ * @param record - The recent recorded interaction between user and card
1491
1526
  * @returns The updated state of the card's CardHistory data
1527
+ * @throws Error if document creation fails or non-404 database error occurs
1492
1528
  */
1493
1529
  async putCardRecord(record) {
1494
1530
  const cardHistoryID = getCardHistoryID(record.courseID, record.cardID);
@@ -2676,6 +2712,8 @@ var init_StaticDataLayerProvider = __esm({
2676
2712
  initialized = false;
2677
2713
  courseUnpackers = /* @__PURE__ */ new Map();
2678
2714
  manifests = {};
2715
+ // Mapping from dependency name to actual courseId for backwards compatibility
2716
+ dependencyNameToCourseId = /* @__PURE__ */ new Map();
2679
2717
  constructor(config) {
2680
2718
  this.config = {
2681
2719
  localStoragePrefix: config.localStoragePrefix || "skuilder-static",
@@ -2703,10 +2741,15 @@ var init_StaticDataLayerProvider = __esm({
2703
2741
  throw new Error(`Failed to fetch final content manifest for ${courseName} at ${finalManifestUrl}`);
2704
2742
  }
2705
2743
  const finalManifest = await finalManifestResponse.json();
2706
- this.manifests[courseName] = finalManifest;
2744
+ const courseId = finalManifest.courseId || finalManifest.courseConfig?.courseID;
2745
+ if (!courseId) {
2746
+ throw new Error(`Course manifest for ${courseName} missing courseId`);
2747
+ }
2748
+ this.manifests[courseId] = finalManifest;
2707
2749
  const unpacker = new StaticDataUnpacker(finalManifest, baseUrl);
2708
- this.courseUnpackers.set(courseName, unpacker);
2709
- logger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${courseName}`);
2750
+ this.courseUnpackers.set(courseId, unpacker);
2751
+ this.dependencyNameToCourseId.set(courseName, courseId);
2752
+ logger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${courseName} (courseId: ${courseId})`);
2710
2753
  }
2711
2754
  } catch (e) {
2712
2755
  logger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${courseName}:`, e);
@@ -2729,12 +2772,20 @@ var init_StaticDataLayerProvider = __esm({
2729
2772
  return BaseUser.Dummy(syncStrategy);
2730
2773
  }
2731
2774
  getCourseDB(courseId) {
2732
- const unpacker = this.courseUnpackers.get(courseId);
2775
+ let unpacker = this.courseUnpackers.get(courseId);
2776
+ let actualCourseId = courseId;
2777
+ if (!unpacker) {
2778
+ const mappedCourseId = this.dependencyNameToCourseId.get(courseId);
2779
+ if (mappedCourseId) {
2780
+ unpacker = this.courseUnpackers.get(mappedCourseId);
2781
+ actualCourseId = mappedCourseId;
2782
+ }
2783
+ }
2733
2784
  if (!unpacker) {
2734
2785
  throw new Error(`Course ${courseId} not found or failed to initialize in static data layer.`);
2735
2786
  }
2736
- const manifest = this.manifests[courseId];
2737
- return new StaticCourseDB(courseId, unpacker, this.getUserDB(), manifest);
2787
+ const manifest = this.manifests[actualCourseId];
2788
+ return new StaticCourseDB(actualCourseId, unpacker, this.getUserDB(), manifest);
2738
2789
  }
2739
2790
  getCoursesDB() {
2740
2791
  return new StaticCoursesDB(this.manifests);