@vue-skuilder/platform-ui 0.2.36 → 0.2.37

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 (146) hide show
  1. package/dist/assets/{About-74htcNLT.js → About-BkMENQtD.js} +2 -2
  2. package/dist/assets/{About-74htcNLT.js.map → About-BkMENQtD.js.map} +1 -1
  3. package/dist/assets/{AdminDashboard-B00qno2M.js → AdminDashboard-5R-xgY-M.js} +2 -2
  4. package/dist/assets/{AdminDashboard-B00qno2M.js.map → AdminDashboard-5R-xgY-M.js.map} +1 -1
  5. package/dist/assets/{AdminLearner-SJNtSyJ_.js → AdminLearner-Br10DFSt.js} +2 -2
  6. package/dist/assets/{AdminLearner-SJNtSyJ_.js.map → AdminLearner-Br10DFSt.js.map} +1 -1
  7. package/dist/assets/BaseUserDB-BRgNfdWx.js +1 -0
  8. package/dist/assets/{ClassroomCtrlPanel-BSAG3h8B.js → ClassroomCtrlPanel-DQJQ0B7M.js} +2 -2
  9. package/dist/assets/{ClassroomCtrlPanel-BSAG3h8B.js.map → ClassroomCtrlPanel-DQJQ0B7M.js.map} +1 -1
  10. package/dist/assets/{Classrooms-DXNEbtsM.js → Classrooms-B5tQPFEE.js} +2 -2
  11. package/dist/assets/{Classrooms-DXNEbtsM.js.map → Classrooms-B5tQPFEE.js.map} +1 -1
  12. package/dist/assets/CouchDBSyncStrategy-0EgX8AAz.js +1 -0
  13. package/dist/assets/{CourseRouter-CsVa_92r.js → CourseRouter-W6S7DpZN.js} +2 -2
  14. package/dist/assets/{CourseRouter-CsVa_92r.js.map → CourseRouter-W6S7DpZN.js.map} +1 -1
  15. package/dist/assets/CourseSyncService-CrHp0wsl.js +1 -0
  16. package/dist/assets/{CourseWare-BTFRjgBR-DBp_fIwH.js → CourseWare-BTFRjgBR-lpqcYpAW.js} +3 -3
  17. package/dist/assets/{CourseWare-BTFRjgBR-DBp_fIwH.js.map → CourseWare-BTFRjgBR-lpqcYpAW.js.map} +1 -1
  18. package/dist/assets/{Courses-CB6GGtdm.js → Courses-TzwgFdwn.js} +2 -2
  19. package/dist/assets/{Courses-CB6GGtdm.js.map → Courses-TzwgFdwn.js.map} +1 -1
  20. package/dist/assets/{EloModeration-DUBgs-Vh.js → EloModeration-BCz7VKla.js} +2 -2
  21. package/dist/assets/{EloModeration-DUBgs-Vh.js.map → EloModeration-BCz7VKla.js.map} +1 -1
  22. package/dist/assets/{JoinCode-BBvYapCA.js → JoinCode-CEeZkFOp.js} +2 -2
  23. package/dist/assets/{JoinCode-BBvYapCA.js.map → JoinCode-CEeZkFOp.js.map} +1 -1
  24. package/dist/assets/{NewCourseDialog-DBgFVnt3.js → NewCourseDialog-DNzvvz_H.js} +2 -2
  25. package/dist/assets/{NewCourseDialog-DBgFVnt3.js.map → NewCourseDialog-DNzvvz_H.js.map} +1 -1
  26. package/dist/assets/{PipelineDebugger-BHaqzqZw.js → PipelineDebugger-DhnKlMgD.js} +3 -3
  27. package/dist/assets/{PipelineDebugger-BHaqzqZw.js.map → PipelineDebugger-DhnKlMgD.js.map} +1 -1
  28. package/dist/assets/PouchDataLayerProvider-CAuhZYIc.js +2 -0
  29. package/dist/assets/PouchDataLayerProvider-CAuhZYIc.js.map +1 -0
  30. package/dist/assets/{ReleaseNotes-Dg6mLL1C.js → ReleaseNotes-Bvw24QDI.js} +2 -2
  31. package/dist/assets/{ReleaseNotes-Dg6mLL1C.js.map → ReleaseNotes-Bvw24QDI.js.map} +1 -1
  32. package/dist/assets/{RequestPasswordReset-CcFMTnTc.js → RequestPasswordReset-YOq1JJ_o.js} +2 -2
  33. package/dist/assets/{RequestPasswordReset-CcFMTnTc.js.map → RequestPasswordReset-YOq1JJ_o.js.map} +1 -1
  34. package/dist/assets/{ResetPassword-Dw_cBJU2.js → ResetPassword-CQCb3B_Z.js} +2 -2
  35. package/dist/assets/{ResetPassword-Dw_cBJU2.js.map → ResetPassword-CQCb3B_Z.js.map} +1 -1
  36. package/dist/assets/{StaticDataLayerProvider-CtgU3VBh.js → StaticDataLayerProvider-DbGLKpb1.js} +2 -2
  37. package/dist/assets/{StaticDataLayerProvider-CtgU3VBh.js.map → StaticDataLayerProvider-DbGLKpb1.js.map} +1 -1
  38. package/dist/assets/{Study-DDsGQCTJ.js → Study-D2mXR27s.js} +2 -2
  39. package/dist/assets/{Study-DDsGQCTJ.js.map → Study-D2mXR27s.js.map} +1 -1
  40. package/dist/assets/{TagInformation-DBLoXA2a.js → TagInformation-DHw5jRNt.js} +2 -2
  41. package/dist/assets/{TagInformation-DBLoXA2a.js.map → TagInformation-DHw5jRNt.js.map} +1 -1
  42. package/dist/assets/{User-DfXUXjFb.js → User-C0xEcKaU.js} +2 -2
  43. package/dist/assets/{User-DfXUXjFb.js.map → User-C0xEcKaU.js.map} +1 -1
  44. package/dist/assets/{UserDBDebugger-DPqlc4O_.js → UserDBDebugger-BXLoT28w.js} +2 -2
  45. package/dist/assets/{UserDBDebugger-DPqlc4O_.js.map → UserDBDebugger-BXLoT28w.js.map} +1 -1
  46. package/dist/assets/UserDBDebugger-DHONc_-t.js +1 -0
  47. package/dist/assets/{UserStats-C04YVYv7.js → UserStats-Blm_daoT.js} +2 -2
  48. package/dist/assets/{UserStats-C04YVYv7.js.map → UserStats-Blm_daoT.js.map} +1 -1
  49. package/dist/assets/{VerifyEmail-Y05BSR57.js → VerifyEmail-DTwA6sFY.js} +2 -2
  50. package/dist/assets/{VerifyEmail-Y05BSR57.js.map → VerifyEmail-DTwA6sFY.js.map} +1 -1
  51. package/dist/assets/{admin-DcFjvYJw.js → admin-hzNSXp0o.js} +2 -2
  52. package/dist/assets/{admin-DcFjvYJw.js.map → admin-hzNSXp0o.js.map} +1 -1
  53. package/dist/assets/{chess-E2uOAyQS-BZi0vihz.js → chess-E2uOAyQS-DDTgqZMJ.js} +2 -2
  54. package/dist/assets/{chess-E2uOAyQS-BZi0vihz.js.map → chess-E2uOAyQS-DDTgqZMJ.js.map} +1 -1
  55. package/dist/assets/chess-Lfm7Fsvs-RaFhFnIh.js +1 -0
  56. package/dist/assets/{contentSource-DwznMSMs.js → contentSource-FGhM_ge8.js} +8 -8
  57. package/dist/assets/contentSource-FGhM_ge8.js.map +1 -0
  58. package/dist/assets/dist-5Z6GjIpR.js +1 -0
  59. package/dist/assets/{dist-CAHkbl3M.js → dist-BJLhyG8r.js} +3 -3
  60. package/dist/assets/{dist-CAHkbl3M.js.map → dist-BJLhyG8r.js.map} +1 -1
  61. package/dist/assets/dist-C5-_1l75.js +1 -0
  62. package/dist/assets/{dist-BsRvt0gH.js → dist-C8EQUxWW.js} +3 -3
  63. package/dist/assets/{dist-BsRvt0gH.js.map → dist-C8EQUxWW.js.map} +1 -1
  64. package/dist/assets/{dist-Dp6eBE2S.js → dist-DGbpjpKB.js} +2 -2
  65. package/dist/assets/{dist-Dp6eBE2S.js.map → dist-DGbpjpKB.js.map} +1 -1
  66. package/dist/assets/dist-M4o-5YLq.js +1 -0
  67. package/dist/assets/edit-ui.es-BT7ftsox.js +1 -0
  68. package/dist/assets/{edit-ui.es-UaQFL_My.js → edit-ui.es-DJgikaS7.js} +2 -2
  69. package/dist/assets/{edit-ui.es-UaQFL_My.js.map → edit-ui.es-DJgikaS7.js.map} +1 -1
  70. package/dist/assets/elo-5Z2qkwtw.js +1 -0
  71. package/dist/assets/{elo-COgu6Hu5.js → elo-C4ZdbMIJ.js} +2 -2
  72. package/dist/assets/{elo-COgu6Hu5.js.map → elo-C4ZdbMIJ.js.map} +1 -1
  73. package/dist/assets/{eloDistance-BV7vfiK5.js → eloDistance-CRxxdYPJ.js} +2 -2
  74. package/dist/assets/{eloDistance-BV7vfiK5.js.map → eloDistance-CRxxdYPJ.js.map} +1 -1
  75. package/dist/assets/eloDistance-DF4pmPOI.js +1 -0
  76. package/dist/assets/{french-Dk7YG8Td-CD7Hms2j.js → french-Dk7YG8Td-C2awfrzV.js} +2 -2
  77. package/dist/assets/{french-Dk7YG8Td-CD7Hms2j.js.map → french-Dk7YG8Td-C2awfrzV.js.map} +1 -1
  78. package/dist/assets/french-evUMlbbq-4izQyIk4.js +1 -0
  79. package/dist/assets/{hierarchyDefinition-DLC5DjaA.js → hierarchyDefinition-BbqnGEfR.js} +2 -2
  80. package/dist/assets/{hierarchyDefinition-DLC5DjaA.js.map → hierarchyDefinition-BbqnGEfR.js.map} +1 -1
  81. package/dist/assets/{index-CK-rfSIx.js → index-BRaeVAZb.js} +4 -4
  82. package/dist/assets/{index-CK-rfSIx.js.map → index-BRaeVAZb.js.map} +1 -1
  83. package/dist/assets/{interferenceMitigator-D78KgOxz.js → interferenceMitigator-BtAQm-0d.js} +2 -2
  84. package/dist/assets/{interferenceMitigator-D78KgOxz.js.map → interferenceMitigator-BtAQm-0d.js.map} +1 -1
  85. package/dist/assets/math-DR3fXDcX-Bj6dcLDF.js +1 -0
  86. package/dist/assets/{math-D_8HiEQR-E4QDLrWp.js → math-D_8HiEQR-CQynsoTm.js} +2 -2
  87. package/dist/assets/{math-D_8HiEQR-E4QDLrWp.js.map → math-D_8HiEQR-CQynsoTm.js.map} +1 -1
  88. package/dist/assets/piano-BN5Btq91-onBUnVgA.js +1 -0
  89. package/dist/assets/{piano-DF1g6yaX-Ck3BH5EK.js → piano-DF1g6yaX-vXbP1jX_.js} +2 -2
  90. package/dist/assets/{piano-DF1g6yaX-Ck3BH5EK.js.map → piano-DF1g6yaX-vXbP1jX_.js.map} +1 -1
  91. package/dist/assets/{pitch-CgGJFkZ1-Dd0LzmEe.js → pitch-CgGJFkZ1-DVzOpIVa.js} +2 -2
  92. package/dist/assets/{pitch-CgGJFkZ1-Dd0LzmEe.js.map → pitch-CgGJFkZ1-DVzOpIVa.js.map} +1 -1
  93. package/dist/assets/pitch-Dn0iNqiS-L2k4d66s.js +1 -0
  94. package/dist/assets/prescribed-Cjutx2ct.js +2 -0
  95. package/dist/assets/prescribed-Cjutx2ct.js.map +1 -0
  96. package/dist/assets/{relativePriority-DwPMECAp.js → relativePriority-fx6BMJm9.js} +2 -2
  97. package/dist/assets/{relativePriority-DwPMECAp.js.map → relativePriority-fx6BMJm9.js.map} +1 -1
  98. package/dist/assets/{server-CqR7xtQy.js → server-CUqWbXPL.js} +2 -2
  99. package/dist/assets/{server-CqR7xtQy.js.map → server-CUqWbXPL.js.map} +1 -1
  100. package/dist/assets/{sightsing-BFQ7HRig-DV69ELZf.js → sightsing-BFQ7HRig-CYuNcd8z.js} +2 -2
  101. package/dist/assets/{sightsing-BFQ7HRig-DV69ELZf.js.map → sightsing-BFQ7HRig-CYuNcd8z.js.map} +1 -1
  102. package/dist/assets/sightsing-CJX3k0Fd-C4-zGBSZ.js +1 -0
  103. package/dist/assets/{srs-DOsG9Y-i.js → srs-B3R2C3TU.js} +2 -2
  104. package/dist/assets/{srs-DOsG9Y-i.js.map → srs-B3R2C3TU.js.map} +1 -1
  105. package/dist/assets/srs-BD4FD2rw.js +1 -0
  106. package/dist/assets/{typing-BevtfWlp-CvStu5BY.js → typing-BevtfWlp-C0NbuTKI.js} +2 -2
  107. package/dist/assets/{typing-BevtfWlp-CvStu5BY.js.map → typing-BevtfWlp-C0NbuTKI.js.map} +1 -1
  108. package/dist/assets/typing-k-ojjO7G-gZjZ4YQx.js +1 -0
  109. package/dist/assets/{userDBKeys-DYLGKnVC.js → userDBKeys-3SQjNVdK.js} +4 -4
  110. package/dist/assets/{userDBKeys-DYLGKnVC.js.map → userDBKeys-3SQjNVdK.js.map} +1 -1
  111. package/dist/assets/{userTagPreference-cZCPqadC.js → userTagPreference-B23ZX5J4.js} +2 -2
  112. package/dist/assets/{userTagPreference-cZCPqadC.js.map → userTagPreference-B23ZX5J4.js.map} +1 -1
  113. package/dist/assets/validators-CnxSFY0I.js +2 -0
  114. package/dist/assets/{validators-lpYAHmRR.js.map → validators-CnxSFY0I.js.map} +1 -1
  115. package/dist/assets/{word-work-BOnRlZgd-CCGZdwyf.js → word-work-BOnRlZgd-CsMkeNdI.js} +2 -2
  116. package/dist/assets/{word-work-BOnRlZgd-CCGZdwyf.js.map → word-work-BOnRlZgd-CsMkeNdI.js.map} +1 -1
  117. package/dist/assets/word-work-Dd6tIKrt-WI45cKxO.js +1 -0
  118. package/dist/index.html +9 -9
  119. package/dist/sw.js +1 -1
  120. package/dist/sw.js.map +1 -1
  121. package/package.json +7 -7
  122. package/dist/assets/BaseUserDB-CV2ZPZOR.js +0 -1
  123. package/dist/assets/CouchDBSyncStrategy-BjM7ROXC.js +0 -1
  124. package/dist/assets/CourseSyncService-CPU_Ll1h.js +0 -1
  125. package/dist/assets/PouchDataLayerProvider-DxsnSIKd.js +0 -2
  126. package/dist/assets/PouchDataLayerProvider-DxsnSIKd.js.map +0 -1
  127. package/dist/assets/UserDBDebugger-xmycWjck.js +0 -1
  128. package/dist/assets/chess-Lfm7Fsvs-DgN08Qx9.js +0 -1
  129. package/dist/assets/contentSource-DwznMSMs.js.map +0 -1
  130. package/dist/assets/dist-BcwaOf54.js +0 -1
  131. package/dist/assets/dist-CgW7D_Gh.js +0 -1
  132. package/dist/assets/dist-Dnehy0sn.js +0 -1
  133. package/dist/assets/edit-ui.es-BWqvElsJ.js +0 -1
  134. package/dist/assets/elo-Cwa8a3Yo.js +0 -1
  135. package/dist/assets/eloDistance-MReQeAuj.js +0 -1
  136. package/dist/assets/french-evUMlbbq-nGCjilG6.js +0 -1
  137. package/dist/assets/math-DR3fXDcX-C9KfHLHP.js +0 -1
  138. package/dist/assets/piano-BN5Btq91-CnKhyLGE.js +0 -1
  139. package/dist/assets/pitch-Dn0iNqiS-BxAdpDDb.js +0 -1
  140. package/dist/assets/prescribed-BWO17Gan.js +0 -2
  141. package/dist/assets/prescribed-BWO17Gan.js.map +0 -1
  142. package/dist/assets/sightsing-CJX3k0Fd-CG94OiDr.js +0 -1
  143. package/dist/assets/srs-DGscV6W4.js +0 -1
  144. package/dist/assets/typing-k-ojjO7G-AF8vU_q7.js +0 -1
  145. package/dist/assets/validators-lpYAHmRR.js +0 -2
  146. package/dist/assets/word-work-Dd6tIKrt-BNTSCq5F.js +0 -1
@@ -0,0 +1,2 @@
1
+ import"./chunk-D6hFPZc3.js";import"./moment-DbT30ZpG.js";import{a as e,b as t,c as n,d as r,i,l as a,o,s,u as c}from"./contentSource-FGhM_ge8.js";import{t as l}from"./defineProperty-y9rbOPYz.js";import{k as u}from"./PipelineDebugger-DhnKlMgD.js";import"./eloDistance-CRxxdYPJ.js";var CouchDataLayerProvider=class{constructor(e){l(this,`initialized`,!1),l(this,`userDB`,void 0),l(this,`currentUsername`,``),l(this,`_courseIDs`,[]),l(this,`_courseDBs`,new Map),e&&(this._courseIDs=e)}async initialize(){if(!this.initialized){if(typeof process<`u`&&process.versions!=null&&process.versions.node!=null){u.info(`CouchDataLayerProvider: Running in Node.js environment, creating guest UserDB for testing.`),await t();let e=new o;this.userDB=await r.instance(e)}else{let e=new o;this.userDB=await r.instance(e),this.currentUsername=this.userDB.getUsername(),u.debug(`Current username: ${this.currentUsername}`)}this.initialized=!0}}async teardown(){this.initialized=!1}getUserDB(){return this.userDB}getCourseDB(e){let t=s.getInstance().getLocalDB(e),n=this._courseDBs.get(e);if(n&&n.localDB===t)return n.db;let r=new i(e,async()=>this.getUserDB(),t??void 0);return this._courseDBs.set(e,{db:r,localDB:t}),r}async ensureCourseSynced(e,t){return s.getInstance().ensureSynced(e,t)}getCoursesDB(){return new e(this._courseIDs)}async getClassroomDB(e,t){return t===`student`?await a.factory(e,this.getUserDB()):await c.factory(e)}getAdminDB(){return new n}isReadOnly(){return!1}};export{CouchDataLayerProvider};
2
+ //# sourceMappingURL=PouchDataLayerProvider-CAuhZYIc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PouchDataLayerProvider-CAuhZYIc.js","names":[],"sources":["../../../db/dist/impl/couch/PouchDataLayerProvider.mjs"],"sourcesContent":["import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { AdminDB } from \"./adminDB.mjs\";\nimport { CourseDB, CoursesDB } from \"./courseDB.mjs\";\nimport { initializeDataDirectory } from \"../../util/dataDirectory.mjs\";\nimport { BaseUser } from \"../common/BaseUserDB.mjs\";\nimport { CourseSyncService } from \"./CourseSyncService.mjs\";\nimport { CouchDBSyncStrategy } from \"./CouchDBSyncStrategy.mjs\";\nimport { StudentClassroomDB, TeacherClassroomDB } from \"./classroomDB.mjs\";\n//#region src/impl/couch/PouchDataLayerProvider.ts\nvar CouchDataLayerProvider = class {\n\tinitialized = false;\n\tuserDB;\n\tcurrentUsername = \"\";\n\t_courseIDs = [];\n\t/**\n\t* One CourseDB per course, so its caches (navigator, ELO pool, tags) last\n\t* across sessions and card hydration. Rebuilt when the local replica it reads\n\t* from changes (becomes ready, or is replaced); a session keeps the instance\n\t* it started with.\n\t*/\n\t_courseDBs = /* @__PURE__ */ new Map();\n\tconstructor(coursIDs) {\n\t\tif (coursIDs) this._courseIDs = coursIDs;\n\t}\n\tasync initialize() {\n\t\tif (this.initialized) return;\n\t\tif (typeof process !== \"undefined\" && process.versions != null && process.versions.node != null) {\n\t\t\tlogger.info(\"CouchDataLayerProvider: Running in Node.js environment, creating guest UserDB for testing.\");\n\t\t\tawait initializeDataDirectory();\n\t\t\tconst syncStrategy = new CouchDBSyncStrategy();\n\t\t\tthis.userDB = await BaseUser.instance(syncStrategy);\n\t\t} else {\n\t\t\tconst syncStrategy = new CouchDBSyncStrategy();\n\t\t\tthis.userDB = await BaseUser.instance(syncStrategy);\n\t\t\tthis.currentUsername = this.userDB.getUsername();\n\t\t\tlogger.debug(`Current username: ${this.currentUsername}`);\n\t\t}\n\t\tthis.initialized = true;\n\t}\n\tasync teardown() {\n\t\tthis.initialized = false;\n\t}\n\tgetUserDB() {\n\t\treturn this.userDB;\n\t}\n\tgetCourseDB(courseId) {\n\t\tconst localDB = CourseSyncService.getInstance().getLocalDB(courseId);\n\t\tconst cached = this._courseDBs.get(courseId);\n\t\tif (cached && cached.localDB === localDB) return cached.db;\n\t\tconst db = new CourseDB(courseId, async () => this.getUserDB(), localDB ?? void 0);\n\t\tthis._courseDBs.set(courseId, {\n\t\t\tdb,\n\t\t\tlocalDB\n\t\t});\n\t\treturn db;\n\t}\n\t/**\n\t* Trigger local sync for a course. Call during app initialization or\n\t* pre-session loading for courses that opt in via CourseConfig.localSync.\n\t*\n\t* Safe to call multiple times — concurrent calls coalesce. Returns when\n\t* sync is complete (or immediately if already synced / disabled).\n\t*\n\t* @param courseId - The course to sync locally\n\t* @param forceEnabled - Skip CourseConfig check and sync regardless.\n\t* Use when the caller already knows local sync is desired.\n\t*/\n\tasync ensureCourseSynced(courseId, forceEnabled) {\n\t\treturn CourseSyncService.getInstance().ensureSynced(courseId, forceEnabled);\n\t}\n\tgetCoursesDB() {\n\t\treturn new CoursesDB(this._courseIDs);\n\t}\n\tasync getClassroomDB(classId, type) {\n\t\tif (type === \"student\") return await StudentClassroomDB.factory(classId, this.getUserDB());\n\t\telse return await TeacherClassroomDB.factory(classId);\n\t}\n\tgetAdminDB() {\n\t\treturn new AdminDB();\n\t}\n\tisReadOnly() {\n\t\treturn false;\n\t}\n};\n//#endregion\nexport { CouchDataLayerProvider };\n\n//# sourceMappingURL=PouchDataLayerProvider.mjs.map"],"mappings":"wRAUA,IAAI,uBAAyB,KAAM,CAYlC,YAAY,EAAU,QAXtB,cAAc,GAAM,QACpB,SAAA,IAAA,GAAO,QACP,kBAAkB,GAAG,QACrB,aAAa,EAAE,CAAC,QAOhB,aAA6B,IAAI,IAAM,CAElC,IAAU,KAAK,WAAa,GAEjC,MAAM,YAAa,CACd,SAAK,YACT,IAAI,OAAO,QAAY,KAAe,QAAQ,UAAY,MAAQ,QAAQ,SAAS,MAAQ,KAAM,CAChG,EAAO,KAAK,6FAA6F,CACzG,MAAM,GAAyB,CAC/B,IAAM,EAAe,IAAI,EACzB,KAAK,OAAS,MAAM,EAAS,SAAS,EAAa,KAC7C,CACN,IAAM,EAAe,IAAI,EACzB,KAAK,OAAS,MAAM,EAAS,SAAS,EAAa,CACnD,KAAK,gBAAkB,KAAK,OAAO,aAAa,CAChD,EAAO,MAAM,qBAAqB,KAAK,kBAAkB,CAE1D,KAAK,YAAc,IAEpB,MAAM,UAAW,CAChB,KAAK,YAAc,GAEpB,WAAY,CACX,OAAO,KAAK,OAEb,YAAY,EAAU,CACrB,IAAM,EAAU,EAAkB,aAAa,CAAC,WAAW,EAAS,CAC9D,EAAS,KAAK,WAAW,IAAI,EAAS,CAC5C,GAAI,GAAU,EAAO,UAAY,EAAS,OAAO,EAAO,GACxD,IAAM,EAAK,IAAI,EAAS,EAAU,SAAY,KAAK,WAAW,CAAE,GAAW,IAAK,GAAE,CAKlF,OAJA,KAAK,WAAW,IAAI,EAAU,CAC7B,KACA,UACA,CAAC,CACK,EAaR,MAAM,mBAAmB,EAAU,EAAc,CAChD,OAAO,EAAkB,aAAa,CAAC,aAAa,EAAU,EAAa,CAE5E,cAAe,CACd,OAAO,IAAI,EAAU,KAAK,WAAW,CAEtC,MAAM,eAAe,EAAS,EAAM,CAE9B,OADD,IAAS,UAAkB,MAAM,EAAmB,QAAQ,EAAS,KAAK,WAAW,CAAC,CAC9E,MAAM,EAAmB,QAAQ,EAAQ,CAEtD,YAAa,CACZ,OAAO,IAAI,EAEZ,YAAa,CACZ,MAAO"}
@@ -1,2 +1,2 @@
1
- import"./chunk-D6hFPZc3.js";import{H as e,T as t,_ as n,b as r}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import{t as i}from"./index-CK-rfSIx.js";var a=t({name:`ReleaseNotes`});function _sfc_render(t,i,a,o,s,c){return e(),r(`div`,null,i[0]||(i[0]=[n(`h1`,{class:`text-h2 mb-6`},`Release Notes`,-1),n(`h3`,{class:`text-h4 mb-4`},`0.0.1 - April 21`,-1),n(`ul`,null,[n(`li`,null,`Hello world, these are release notes.`)],-1)]))}var o=i(a,[[`render`,_sfc_render]]);export{o as default};
2
- //# sourceMappingURL=ReleaseNotes-Dg6mLL1C.js.map
1
+ import"./chunk-D6hFPZc3.js";import{H as e,T as t,_ as n,b as r}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import{t as i}from"./index-BRaeVAZb.js";var a=t({name:`ReleaseNotes`});function _sfc_render(t,i,a,o,s,c){return e(),r(`div`,null,i[0]||(i[0]=[n(`h1`,{class:`text-h2 mb-6`},`Release Notes`,-1),n(`h3`,{class:`text-h4 mb-4`},`0.0.1 - April 21`,-1),n(`ul`,null,[n(`li`,null,`Hello world, these are release notes.`)],-1)]))}var o=i(a,[[`render`,_sfc_render]]);export{o as default};
2
+ //# sourceMappingURL=ReleaseNotes-Bvw24QDI.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReleaseNotes-Dg6mLL1C.js","names":[],"sources":["../../src/views/ReleaseNotes.vue","../../src/views/ReleaseNotes.vue"],"sourcesContent":["<template>\n <div>\n <h1 class=\"text-h2 mb-6\">Release Notes</h1>\n\n <h3 class=\"text-h4 mb-4\">0.0.1 - April 21</h3>\n <ul>\n <li>Hello world, these are release notes.</li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'ReleaseNotes',\n});\n</script>\n\n<style scoped></style>\n","<template>\n <div>\n <h1 class=\"text-h2 mb-6\">Release Notes</h1>\n\n <h3 class=\"text-h4 mb-4\">0.0.1 - April 21</h3>\n <ul>\n <li>Hello world, these are release notes.</li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'ReleaseNotes',\n});\n</script>\n\n<style scoped></style>\n"],"mappings":"mJCcA,IAAA,EAAe,EAAgB,CAC7B,KAAM,eACP,CAAC,8CAfA,EAOM,MAAA,KAAA,EAAA,KAAA,EAAA,GAAA,CANJ,EAA2C,KAAA,CAAvC,MAAM,eAAc,CAAC,gBAAa,GAAA,CAEtC,EAA8C,KAAA,CAA1C,MAAM,eAAc,CAAC,mBAAgB,GAAA,CACzC,EAEK,KAAA,KAAA,CADH,EAA8C,KAAA,KAA1C,wCAAqC,CAAA,CAAA,GAAA"}
1
+ {"version":3,"file":"ReleaseNotes-Bvw24QDI.js","names":[],"sources":["../../src/views/ReleaseNotes.vue","../../src/views/ReleaseNotes.vue"],"sourcesContent":["<template>\n <div>\n <h1 class=\"text-h2 mb-6\">Release Notes</h1>\n\n <h3 class=\"text-h4 mb-4\">0.0.1 - April 21</h3>\n <ul>\n <li>Hello world, these are release notes.</li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'ReleaseNotes',\n});\n</script>\n\n<style scoped></style>\n","<template>\n <div>\n <h1 class=\"text-h2 mb-6\">Release Notes</h1>\n\n <h3 class=\"text-h4 mb-4\">0.0.1 - April 21</h3>\n <ul>\n <li>Hello world, these are release notes.</li>\n </ul>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n name: 'ReleaseNotes',\n});\n</script>\n\n<style scoped></style>\n"],"mappings":"mJCcA,IAAA,EAAe,EAAgB,CAC7B,KAAM,eACP,CAAC,8CAfA,EAOM,MAAA,KAAA,EAAA,KAAA,EAAA,GAAA,CANJ,EAA2C,KAAA,CAAvC,MAAM,eAAc,CAAC,gBAAa,GAAA,CAEtC,EAA8C,KAAA,CAA1C,MAAM,eAAc,CAAC,mBAAgB,GAAA,CACzC,EAEK,KAAA,KAAA,CADH,EAA8C,KAAA,KAA1C,wCAAqC,CAAA,CAAA,GAAA"}
@@ -1,2 +1,2 @@
1
- import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,T as i,v as a}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import{u as o}from"./dist-BsRvt0gH.js";import"./contentSource-DwznMSMs.js";import"./dist-Dp6eBE2S.js";import"./PipelineDebugger-BHaqzqZw.js";import"./eloDistance-BV7vfiK5.js";import{t as s}from"./index-CK-rfSIx.js";var c=i({name:`RequestPasswordResetView`,components:{RequestPasswordReset:o},methods:{handleSuccess(e){console.log(`Password reset email sent to ${e}`)},goToLogin(){this.$router.push({name:`login`})}}});function _sfc_render(i,o,s,c,l,u){let d=r(`request-password-reset`,!0),f=r(`v-container`);return n(),a(f,{class:`d-flex align-center request-reset`},{default:e(()=>[t(d,{onCancel:i.goToLogin,onSuccess:i.handleSuccess},null,8,[`onCancel`,`onSuccess`])]),_:1})}var l=s(c,[[`render`,_sfc_render],[`__scopeId`,`data-v-111f280a`]]);export{l as default};
2
- //# sourceMappingURL=RequestPasswordReset-CcFMTnTc.js.map
1
+ import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,T as i,v as a}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import{u as o}from"./dist-C8EQUxWW.js";import"./contentSource-FGhM_ge8.js";import"./dist-DGbpjpKB.js";import"./PipelineDebugger-DhnKlMgD.js";import"./eloDistance-CRxxdYPJ.js";import{t as s}from"./index-BRaeVAZb.js";var c=i({name:`RequestPasswordResetView`,components:{RequestPasswordReset:o},methods:{handleSuccess(e){console.log(`Password reset email sent to ${e}`)},goToLogin(){this.$router.push({name:`login`})}}});function _sfc_render(i,o,s,c,l,u){let d=r(`request-password-reset`,!0),f=r(`v-container`);return n(),a(f,{class:`d-flex align-center request-reset`},{default:e(()=>[t(d,{onCancel:i.goToLogin,onSuccess:i.handleSuccess},null,8,[`onCancel`,`onSuccess`])]),_:1})}var l=s(c,[[`render`,_sfc_render],[`__scopeId`,`data-v-111f280a`]]);export{l as default};
2
+ //# sourceMappingURL=RequestPasswordReset-YOq1JJ_o.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RequestPasswordReset-CcFMTnTc.js","names":[],"sources":["../../src/views/RequestPasswordReset.vue","../../src/views/RequestPasswordReset.vue"],"sourcesContent":["<template>\n <v-container class=\"d-flex align-center request-reset\">\n <request-password-reset @cancel=\"goToLogin\" @success=\"handleSuccess\" />\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { RequestPasswordReset } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'RequestPasswordResetView',\n\n components: {\n RequestPasswordReset,\n },\n\n methods: {\n handleSuccess(email: string) {\n console.log(`Password reset email sent to ${email}`);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n\n<style lang=\"css\" scoped>\n.request-reset {\n max-width: 650px;\n}\n</style>\n","<template>\n <v-container class=\"d-flex align-center request-reset\">\n <request-password-reset @cancel=\"goToLogin\" @success=\"handleSuccess\" />\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { RequestPasswordReset } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'RequestPasswordResetView',\n\n components: {\n RequestPasswordReset,\n },\n\n methods: {\n handleSuccess(email: string) {\n console.log(`Password reset email sent to ${email}`);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n\n<style lang=\"css\" scoped>\n.request-reset {\n max-width: 650px;\n}\n</style>\n"],"mappings":"oZCUA,IAAA,EAAe,EAAgB,CAC7B,KAAM,2BAEN,WAAY,CACV,qBAAA,EACD,CAED,QAAS,CACP,cAAc,EAAe,CAC3B,QAAQ,IAAI,gCAAgC,IAAQ,EAGtD,WAAY,CACV,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,CAAC,EAEvC,CACF,CAAC,sGAzBA,EAEc,EAAA,CAFD,MAAM,oCAAmC,CAAA,CADxD,QAAA,MAE2E,CAAvE,EAAuE,EAAA,CAA9C,SAAQ,EAAA,UAAY,UAAS,EAAA,kDAF1D,EAAA"}
1
+ {"version":3,"file":"RequestPasswordReset-YOq1JJ_o.js","names":[],"sources":["../../src/views/RequestPasswordReset.vue","../../src/views/RequestPasswordReset.vue"],"sourcesContent":["<template>\n <v-container class=\"d-flex align-center request-reset\">\n <request-password-reset @cancel=\"goToLogin\" @success=\"handleSuccess\" />\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { RequestPasswordReset } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'RequestPasswordResetView',\n\n components: {\n RequestPasswordReset,\n },\n\n methods: {\n handleSuccess(email: string) {\n console.log(`Password reset email sent to ${email}`);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n\n<style lang=\"css\" scoped>\n.request-reset {\n max-width: 650px;\n}\n</style>\n","<template>\n <v-container class=\"d-flex align-center request-reset\">\n <request-password-reset @cancel=\"goToLogin\" @success=\"handleSuccess\" />\n </v-container>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { RequestPasswordReset } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'RequestPasswordResetView',\n\n components: {\n RequestPasswordReset,\n },\n\n methods: {\n handleSuccess(email: string) {\n console.log(`Password reset email sent to ${email}`);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n\n<style lang=\"css\" scoped>\n.request-reset {\n max-width: 650px;\n}\n</style>\n"],"mappings":"oZCUA,IAAA,EAAe,EAAgB,CAC7B,KAAM,2BAEN,WAAY,CACV,qBAAA,EACD,CAED,QAAS,CACP,cAAc,EAAe,CAC3B,QAAQ,IAAI,gCAAgC,IAAQ,EAGtD,WAAY,CACV,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,CAAC,EAEvC,CACF,CAAC,sGAzBA,EAEc,EAAA,CAFD,MAAM,oCAAmC,CAAA,CADxD,QAAA,MAE2E,CAAvE,EAAuE,EAAA,CAA9C,SAAQ,EAAA,UAAY,UAAS,EAAA,kDAF1D,EAAA"}
@@ -1,2 +1,2 @@
1
- import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,v as o}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import{s}from"./dist-BsRvt0gH.js";import"./contentSource-DwznMSMs.js";import"./dist-Dp6eBE2S.js";import"./PipelineDebugger-BHaqzqZw.js";import"./eloDistance-BV7vfiK5.js";import{t as c}from"./index-CK-rfSIx.js";var l=a({name:`ResetPasswordView`,components:{ResetPassword:s},methods:{handleComplete(){console.log(`Password reset successfully`)},handleError(e){console.error(`Password reset error:`,e)},goToLogin(){this.$router.push({name:`login`})}}});function _sfc_render(a,s,c,l,u,d){let f=r(`v-btn`),p=r(`reset-password`,!0);return n(),o(p,{onComplete:a.handleComplete,onError:a.handleError},{"success-action":e(()=>[t(f,{color:`primary`,onClick:a.goToLogin},{default:e(()=>s[0]||(s[0]=[i(` Continue to Login `)])),_:1},8,[`onClick`])]),_:1},8,[`onComplete`,`onError`])}var u=c(l,[[`render`,_sfc_render]]);export{u as default};
2
- //# sourceMappingURL=ResetPassword-Dw_cBJU2.js.map
1
+ import"./chunk-D6hFPZc3.js";import{$ as e,C as t,H as n,K as r,S as i,T as a,v as o}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import{s}from"./dist-C8EQUxWW.js";import"./contentSource-FGhM_ge8.js";import"./dist-DGbpjpKB.js";import"./PipelineDebugger-DhnKlMgD.js";import"./eloDistance-CRxxdYPJ.js";import{t as c}from"./index-BRaeVAZb.js";var l=a({name:`ResetPasswordView`,components:{ResetPassword:s},methods:{handleComplete(){console.log(`Password reset successfully`)},handleError(e){console.error(`Password reset error:`,e)},goToLogin(){this.$router.push({name:`login`})}}});function _sfc_render(a,s,c,l,u,d){let f=r(`v-btn`),p=r(`reset-password`,!0);return n(),o(p,{onComplete:a.handleComplete,onError:a.handleError},{"success-action":e(()=>[t(f,{color:`primary`,onClick:a.goToLogin},{default:e(()=>s[0]||(s[0]=[i(` Continue to Login `)])),_:1},8,[`onClick`])]),_:1},8,[`onComplete`,`onError`])}var u=c(l,[[`render`,_sfc_render]]);export{u as default};
2
+ //# sourceMappingURL=ResetPassword-CQCb3B_Z.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResetPassword-Dw_cBJU2.js","names":[],"sources":["../../src/views/ResetPassword.vue","../../src/views/ResetPassword.vue"],"sourcesContent":["<template>\n <reset-password @complete=\"handleComplete\" @error=\"handleError\">\n <template #success-action>\n <v-btn color=\"primary\" @click=\"goToLogin\">\n Continue to Login\n </v-btn>\n </template>\n </reset-password>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { ResetPassword } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ResetPasswordView',\n\n components: {\n ResetPassword,\n },\n\n methods: {\n handleComplete() {\n console.log('Password reset successfully');\n },\n\n handleError(error: string) {\n console.error('Password reset error:', error);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n","<template>\n <reset-password @complete=\"handleComplete\" @error=\"handleError\">\n <template #success-action>\n <v-btn color=\"primary\" @click=\"goToLogin\">\n Continue to Login\n </v-btn>\n </template>\n </reset-password>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { ResetPassword } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ResetPasswordView',\n\n components: {\n ResetPassword,\n },\n\n methods: {\n handleComplete() {\n console.log('Password reset successfully');\n },\n\n handleError(error: string) {\n console.error('Password reset error:', error);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n"],"mappings":"sZCcA,IAAA,EAAe,EAAgB,CAC7B,KAAM,oBAEN,WAAY,CACV,cAAA,EACD,CAED,QAAS,CACP,gBAAiB,CACf,QAAQ,IAAI,8BAA8B,EAG5C,YAAY,EAAe,CACzB,QAAQ,MAAM,wBAAyB,EAAM,EAG/C,WAAY,CACV,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,CAAC,EAEvC,CACF,CAAC,wFAjCA,EAMiB,EAAA,CANA,WAAU,EAAA,eAAiB,QAAO,EAAA,cACtC,iBAAc,MAGf,CAFR,EAEQ,EAAA,CAFD,MAAM,UAAW,QAAO,EAAA,YAHrC,QAAA,MAKM,EAAA,KAAA,EAAA,GAAA,CALN,EAGgD,sBAE1C,CAAA,EAAA,CALN,EAAA,oBAAA,EAAA"}
1
+ {"version":3,"file":"ResetPassword-CQCb3B_Z.js","names":[],"sources":["../../src/views/ResetPassword.vue","../../src/views/ResetPassword.vue"],"sourcesContent":["<template>\n <reset-password @complete=\"handleComplete\" @error=\"handleError\">\n <template #success-action>\n <v-btn color=\"primary\" @click=\"goToLogin\">\n Continue to Login\n </v-btn>\n </template>\n </reset-password>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { ResetPassword } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ResetPasswordView',\n\n components: {\n ResetPassword,\n },\n\n methods: {\n handleComplete() {\n console.log('Password reset successfully');\n },\n\n handleError(error: string) {\n console.error('Password reset error:', error);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n","<template>\n <reset-password @complete=\"handleComplete\" @error=\"handleError\">\n <template #success-action>\n <v-btn color=\"primary\" @click=\"goToLogin\">\n Continue to Login\n </v-btn>\n </template>\n </reset-password>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { ResetPassword } from '@vue-skuilder/common-ui';\n\nexport default defineComponent({\n name: 'ResetPasswordView',\n\n components: {\n ResetPassword,\n },\n\n methods: {\n handleComplete() {\n console.log('Password reset successfully');\n },\n\n handleError(error: string) {\n console.error('Password reset error:', error);\n },\n\n goToLogin() {\n this.$router.push({ name: 'login' });\n },\n },\n});\n</script>\n"],"mappings":"sZCcA,IAAA,EAAe,EAAgB,CAC7B,KAAM,oBAEN,WAAY,CACV,cAAA,EACD,CAED,QAAS,CACP,gBAAiB,CACf,QAAQ,IAAI,8BAA8B,EAG5C,YAAY,EAAe,CACzB,QAAQ,MAAM,wBAAyB,EAAM,EAG/C,WAAY,CACV,KAAK,QAAQ,KAAK,CAAE,KAAM,QAAS,CAAC,EAEvC,CACF,CAAC,wFAjCA,EAMiB,EAAA,CANA,WAAU,EAAA,eAAiB,QAAO,EAAA,cACtC,iBAAc,MAGf,CAFR,EAEQ,EAAA,CAFD,MAAM,UAAW,QAAO,EAAA,YAHrC,QAAA,MAKM,EAAA,KAAA,EAAA,GAAA,CALN,EAGgD,sBAE1C,CAAA,EAAA,CALN,EAAA,oBAAA,EAAA"}
@@ -1,2 +1,2 @@
1
- import{i as __name}from"./chunk-D6hFPZc3.js";import"./moment-DbT30ZpG.js";import{K as Status,d as BaseUser,f as accomodateGuest,g as PipelineAssembler,h as getLocalUserDB,k as createDefaultPipeline}from"./contentSource-DwznMSMs.js";import{t as _defineProperty}from"./defineProperty-y9rbOPYz.js";import{k as logger}from"./PipelineDebugger-BHaqzqZw.js";import{o as DocType,s as DocTypePrefixes}from"./userDBKeys-DYLGKnVC.js";import"./eloDistance-BV7vfiK5.js";var pathUtils={isAbsolute:e=>!!(/^[a-zA-Z]:[\\/]/.test(e)||/^\\\\/.test(e)||e.startsWith(`/`))},nodeFS=null;try{typeof window>`u`&&typeof process<`u`&&process.versions?.node&&(nodeFS=eval(`require`)(`fs`))}catch{}var StaticDataUnpacker=class{constructor(e,t){_defineProperty(this,`manifest`,void 0),_defineProperty(this,`basePath`,void 0),_defineProperty(this,`documentCache`,new Map),_defineProperty(this,`chunkCache`,new Map),_defineProperty(this,`indexCache`,new Map),this.manifest=e,this.basePath=t}async getDocument(e){if(this.documentCache.has(e)){let t=this.documentCache.get(e);return await this.hydrateAttachments(t)}let t=await this.findChunkForDocument(e);if(!t)throw logger.error(`Document ${e} not found in any chunk. Available chunks:`,this.manifest.chunks.map(e=>`${e.id} (${e.docType}): ${e.startKey} - ${e.endKey}`)),Error(`Document ${e} not found in any chunk`);if(await this.loadChunk(t.id),this.documentCache.has(e)){let t=this.documentCache.get(e);return await this.hydrateAttachments(t)}throw logger.error(`Document ${e} not found in chunk ${t.id}`),Error(`Document ${e} not found in chunk ${t.id}`)}async getAllDocumentsByPrefix(e){let t=this.manifest.chunks.filter(t=>{let n=e+`￰`;return t.startKey<=n&&t.endKey>=e});if(t.length===0)return logger.debug(`[StaticDataUnpacker] No chunks found for prefix: ${e}`),[];await Promise.all(t.map(e=>this.loadChunk(e.id)));let n=[];for(let[t,r]of this.documentCache.entries())t.startsWith(e)&&n.push(await this.hydrateAttachments(r));return logger.debug(`[StaticDataUnpacker] Found ${n.length} documents with prefix: ${e}`),n}async queryByElo(e,t=25){let n=await this.loadIndex(`elo`);if(!n||!n.sorted)return logger.warn(`ELO index not found or malformed, returning empty results`),[];let r=n.sorted,i=0,a=0,o=r.length-1;for(;a<=o;){let t=Math.floor((a+o)/2);r[t].elo<e?a=t+1:o=t-1}i=a;let s=[],c=Math.floor(t/2);for(let e=Math.max(0,i-c);e<i&&s.length<t;e++)s.push(r[e].cardId);for(let e=i;e<r.length&&s.length<t;e++)s.push(r[e].cardId);return s}async getTagsIndex(){try{return await this.loadIndex(`tags`)}catch{return{byCard:{},byTag:{}}}}getDocTypeFromId(e){for(let t in DocTypePrefixes){let n=DocTypePrefixes[t];if(e.startsWith(`${n}-`))return t}}async findChunkForDocument(e){let t=this.getDocTypeFromId(e);if(t){let n=this.manifest.chunks.filter(e=>e.docType===t);for(let t of n)if(e>=t.startKey&&e<=t.endKey&&await this.verifyDocumentInChunk(e,t))return t}else{for(let t of this.manifest.chunks)if(e>=t.startKey&&e<=t.endKey&&await this.verifyDocumentInChunk(e,t))return t;let t=this.manifest.chunks.filter(e=>e.docType!==`CARD`&&e.docType!==`DISPLAYABLE_DATA`&&e.docType!==`TAG`);for(let n of t)if(e>=n.startKey&&e<=n.endKey&&await this.verifyDocumentInChunk(e,n))return n;return}}async verifyDocumentInChunk(e,t){try{return await this.loadChunk(t.id),this.documentCache.has(e)}catch{return!1}}async loadChunk(e){if(this.chunkCache.has(e))return;let t=this.manifest.chunks.find(t=>t.id===e);if(!t)throw Error(`Chunk ${e} not found in manifest`);try{let n=`${this.basePath}/${t.path}`;logger.debug(`Loading chunk from ${n}`);let r;if(this.isLocalPath(n)&&nodeFS){let e=await nodeFS.promises.readFile(n,`utf8`);r=JSON.parse(e)}else{let t=await fetch(n);if(!t.ok)throw Error(`Failed to fetch chunk ${e}: ${t.status} ${t.statusText}`);r=await t.json()}this.chunkCache.set(e,r);for(let e of r)e._id&&this.documentCache.set(e._id,e);logger.debug(`Loaded ${r.length} documents from chunk ${e}`)}catch(t){throw logger.error(`Failed to load chunk ${e}:`,t),t}}async loadIndex(e){if(this.indexCache.has(e))return this.indexCache.get(e);let t=this.manifest.indices.find(t=>t.name===e);if(!t)throw Error(`Index ${e} not found in manifest`);try{let n=`${this.basePath}/${t.path}`;logger.debug(`Loading index from ${n}`);let r;if(this.isLocalPath(n)&&nodeFS){let e=await nodeFS.promises.readFile(n,`utf8`);r=JSON.parse(e)}else{let t=await fetch(n);if(!t.ok)throw Error(`Failed to fetch index ${e}: ${t.status} ${t.statusText}`);r=await t.json()}return this.indexCache.set(e,r),logger.debug(`Loaded index ${e}`),r}catch(t){throw logger.error(`Failed to load index ${e}:`,t),t}}async getRawDocument(e){if(this.documentCache.has(e))return this.documentCache.get(e);let t=await this.findChunkForDocument(e);if(!t)throw logger.error(`Document ${e} not found in any chunk. Available chunks:`,this.manifest.chunks.map(e=>`${e.id} (${e.docType}): ${e.startKey} - ${e.endKey}`)),Error(`Document ${e} not found in any chunk`);if(await this.loadChunk(t.id),this.documentCache.has(e))return this.documentCache.get(e);throw logger.error(`Document ${e} not found in chunk ${t.id}`),Error(`Document ${e} not found in chunk ${t.id}`)}getAttachmentUrl(e,t){return`${this.basePath}/attachments/${e}/${t}`}async getAttachmentPath(e,t){try{let n=await this.getRawDocument(e);if(n._attachments&&n._attachments[t]){let e=n._attachments[t];if(e.path)return`${this.basePath}/${e.path}`}return null}catch{return null}}async getAttachmentBlob(e,t){let n=await this.getAttachmentPath(e,t);if(!n)return null;try{if(this.isLocalPath(n)&&nodeFS)return await nodeFS.promises.readFile(n);{let r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch attachment ${e}/${t}: ${r.status} ${r.statusText}`);return await r.blob()}}catch(n){return logger.error(`Failed to load attachment ${e}/${t}:`,n),null}}async hydrateAttachments(e){let t=e;if(!t._attachments)return e;let n=JSON.parse(JSON.stringify(e));for(let[e,r]of Object.entries(t._attachments)){let i=r;if(i.path)try{let r=await this.getAttachmentBlob(t._id,e);r?typeof window<`u`&&window.URL?n._attachments[e]={...i,data:r,stub:!1}:n._attachments[e]={...i,buffer:r}:logger.warn(`[hydrateAttachments] getAttachmentBlob returned null for ${t._id}/${e}. Skipping hydration for this attachment.`)}catch(n){logger.warn(`[hydrateAttachments] Failed to hydrate attachment ${t._id}/${e}:`,n)}else logger.debug(`[hydrateAttachments] Attachment ${e} for doc ${t._id} has no path. Skipping blob conversion.`)}return n}clearCaches(){this.documentCache.clear(),this.chunkCache.clear(),this.indexCache.clear()}getCacheStats(){return{documents:this.documentCache.size,chunks:this.chunkCache.size,indices:this.indexCache.size}}isLocalPath(e){return!e.startsWith(`http://`)&&!e.startsWith(`https://`)&&(pathUtils.isAbsolute(e)||e.startsWith(`./`)||e.startsWith(`../`))}},StaticCourseDB=class{constructor(e,t,n,r){_defineProperty(this,`_pendingHints`,null),this.courseId=e,this.unpacker=t,this.userDB=n,this.manifest=r}getCourseID(){return this.courseId}async getCourseConfig(){if(this.manifest.courseConfig!=null)return this.manifest.courseConfig;throw Error(`Course config not found for course ${this.courseId}`)}async updateCourseConfig(e){throw Error(`Cannot update course config in static mode`)}async getCourseInfo(){return{cardCount:this.manifest.chunks.filter(e=>e.docType===DocType.CARD).reduce((e,t)=>e+t.documentCount,0),registeredUsers:0}}async getCourseDoc(e,t){return this.unpacker.getDocument(e)}async getCourseDocs(e,t){let n=await Promise.all(e.map(async e=>{try{return{id:e,key:e,value:{rev:`1-static`},doc:await this.unpacker.getDocument(e)}}catch{return{key:e,error:`not_found`}}}));return{total_rows:e.length,offset:0,rows:n}}async getCardsByELO(e,t){return(await this.unpacker.queryByElo(e,t||25)).map(e=>{let[t,n,r]=e.split(`-`);return{courseID:t,cardID:n,elo:r?parseInt(r):void 0}})}async getCardEloData(e){return await Promise.all(e.map(async e=>{try{return(await this.unpacker.getDocument(e)).elo||{global:{score:1e3,count:0},tags:{},misc:{}}}catch{return{global:{score:1e3,count:0},tags:{},misc:{}}}}))}async updateCardElo(e,t){return{ok:!0,id:e,rev:`1-static`}}async getCardsCenteredAtELO(e,t){let n=typeof e.elo==`number`?e.elo:1e3;if(e.elo===`user`)try{let e=(await this.userDB.getCourseRegistrationsDoc()).courses.find(e=>e.courseID===this.courseId);e&&typeof e.elo==`object`&&(n=e.elo.global.score)}catch{n=1e3}else e.elo===`random`&&(n=800+Math.random()*400);let r=(await this.unpacker.queryByElo(n,e.limit*2)).map(e=>({cardID:e,courseID:this.courseId}));return t&&(r=r.filter(t)),r.slice(0,e.limit).map(e=>({status:`new`,cardID:e.cardID,contentSourceType:`course`,contentSourceID:this.courseId,courseID:this.courseId}))}async getAppliedTags(e){try{let t=await this.unpacker.getTagsIndex(),n=t.byCard[e]||[],r=await Promise.all(n.map(async n=>{let r=`${DocType.TAG}-${n}`;try{let t=await this.unpacker.getDocument(r);return{id:r,key:e,value:{name:t.name,snippet:t.snippet,count:t.taggedCards?.length||0}}}catch(i){if(i&&i.status===404)logger.warn(`Tag document not found for ${n}, creating stub`);else throw logger.error(`Error getting tag document for ${n}:`,i),i;return{id:r,key:e,value:{name:n,snippet:`Tag: ${n}`,count:t.byTag[n]?.length||0}}}}));return{total_rows:r.length,offset:0,rows:r}}catch(t){return logger.error(`Error getting applied tags for card ${e}:`,t),{total_rows:0,offset:0,rows:[]}}}async getAppliedTagsBatch(e){let t=await this.unpacker.getTagsIndex(),n=new Map;for(let r of e)n.set(r,t.byCard[r]||[]);return n}async getAllCardIds(){let e=await this.unpacker.getTagsIndex();return Object.keys(e.byCard)}async addTagToCard(e,t){throw Error(`Cannot modify tags in static mode`)}async removeTagFromCard(e,t){throw Error(`Cannot modify tags in static mode`)}async createTag(e){throw Error(`Cannot create tags in static mode`)}async getTag(e){return this.unpacker.getDocument(`${DocType.TAG}-${e}`)}async updateTag(e){throw Error(`Cannot update tags in static mode`)}async getCourseTagStubs(){try{let e=await this.unpacker.getTagsIndex();if(!e||!e.byTag)return logger.warn(`Tags index not found or empty`),{total_rows:0,offset:0,rows:[]};let t=Object.keys(e.byTag),n=await Promise.all(t.map(async t=>{let n=e.byTag[t]||[],r=`${DocType.TAG}-${t}`;try{return{id:r,key:r,value:{rev:`1-static`},doc:await this.unpacker.getDocument(r)}}catch(e){if(e&&e.status===404)return logger.warn(`Tag document not found for ${t}, creating stub`),{id:r,key:r,value:{rev:`1-static`},doc:{_id:r,_rev:`1-static`,course:this.courseId,docType:DocType.TAG,name:t,snippet:`Tag: ${t}`,wiki:``,taggedCards:n,author:`system`}};throw logger.error(`Error getting tag document for ${t}:`,e),e}}));return{total_rows:n.length,offset:0,rows:n}}catch(e){return logger.error(`Failed to get course tag stubs:`,e),{total_rows:0,offset:0,rows:[]}}}async addNote(e,t,n,r,i,a,o){return{status:Status.error,message:`Cannot add notes in static mode`}}async removeCard(e){throw Error(`Cannot remove cards in static mode`)}async getInexperiencedCards(){return[]}async getNavigationStrategy(e){try{return await this.unpacker.getDocument(e)}catch(t){throw logger.error(`[static/courseDB] Strategy ${e} not found: ${t}`),t}}async getAllNavigationStrategies(){let e=DocTypePrefixes[DocType.NAVIGATION_STRATEGY];try{return await this.unpacker.getAllDocumentsByPrefix(e)}catch(e){return logger.warn(`[static/courseDB] Error loading navigation strategies: ${e}`),[]}}async addNavigationStrategy(e){throw Error(`Cannot add navigation strategies in static mode`)}async updateNavigationStrategy(e,t){throw Error(`Cannot update navigation strategies in static mode`)}async createNavigator(e){try{let t=await this.getAllNavigationStrategies();if(t.length===0)return logger.debug(`[static/courseDB] No strategy documents found, using default Pipeline(Composite(ELO, SRS), [eloDistanceFilter])`),createDefaultPipeline(e,this);let{pipeline:n,generatorStrategies:r,filterStrategies:i,warnings:a}=await new PipelineAssembler().assemble({strategies:t,user:e,course:this});for(let e of a)logger.warn(`[PipelineAssembler] ${e}`);return n?(logger.debug(`[static/courseDB] Using assembled pipeline with ${r.length} generator(s) and ${i.length} filter(s)`),n):(logger.debug(`[static/courseDB] Pipeline assembly failed, using default pipeline`),createDefaultPipeline(e,this))}catch(e){throw logger.error(`[static/courseDB] Error creating navigator: ${e}`),e}}setEphemeralHints(e){this._pendingHints=e}notePresented(e){e.status===`new`&&this.createNavigator(this.userDB).then(t=>t.notePresented?.(e)).catch(e=>logger.warn(`[static/courseDB] Could not note a presentation: ${e}`))}async getWeightedCards(e){try{let t=await this.createNavigator(this.userDB);return this._pendingHints&&(t.setEphemeralHints(this._pendingHints),this._pendingHints=null),t.getWeightedCards(e)}catch(e){throw logger.error(`[static/courseDB] Error getting weighted cards: ${e}`),e}}getAttachmentUrl(e,t){return this.unpacker.getAttachmentUrl(e,t)}async getAttachmentBlob(e,t){return this.unpacker.getAttachmentBlob(e,t)}async searchCards(e){return[]}async find(e){return{docs:[],warning:`Find operations not supported in static mode`}}},StaticCoursesDB=class{constructor(e,t){this.manifests=e,this.dependencyNameToCourseId=t}async getCourseConfig(e){let t=this.manifests[e];if(!t&&this.dependencyNameToCourseId){let n=this.dependencyNameToCourseId.get(e);n&&(t=this.manifests[n])}if(!t)throw logger.warn(`Course manifest for ${e} not found`),Error(`Course ${e} not found`);if(t.courseConfig)return t.courseConfig;throw logger.warn(`Course config not found in manifest for course ${e}`),Error(`Course config not found for course ${e}`)}async getCourseList(){return Object.keys(this.manifests).map(e=>({courseID:e,name:this.manifests[e].courseName}))}async disambiguateCourse(e,t){logger.warn(`Cannot disambiguate courses in static mode`)}},NoOpSyncStrategy=class{constructor(){_defineProperty(this,`currentUsername`,accomodateGuest().username)}setupRemoteDB(e){return getLocalUserDB(e)}getWriteDB(e){return getLocalUserDB(e)}startSync(e,t){}stopSync(){}canCreateAccount(){return!1}canAuthenticate(){return!1}async createAccount(e,t){throw Error(`Account creation not supported in static mode. Use local account switching instead.`)}async authenticate(e,t){throw Error(`Remote authentication not supported in static mode. Use local account switching instead.`)}async logout(){return this.currentUsername=accomodateGuest().username,{ok:!0}}async getCurrentUsername(){return this.currentUsername}setCurrentUsername(e){this.currentUsername=e}},StaticDataLayerProvider=class{constructor(e){_defineProperty(this,`config`,void 0),_defineProperty(this,`initialized`,!1),_defineProperty(this,`courseUnpackers`,new Map),_defineProperty(this,`manifests`,{}),_defineProperty(this,`dependencyNameToCourseId`,new Map),this.config={localStoragePrefix:e.localStoragePrefix||`skuilder-static`,rootManifest:e.rootManifest||{dependencies:{}},rootManifestUrl:e.rootManifestUrl||`/`}}async resolveCourseDependencies(){logger.info(`[StaticDataLayerProvider] Starting course dependency resolution...`);let e=this.config.rootManifest;for(let[t,n]of Object.entries(e.dependencies||{}))try{logger.debug(`[StaticDataLayerProvider] Resolving dependency: ${t} from ${n}`);let e=new URL(n,this.config.rootManifestUrl).href,r=await fetch(e);if(!r.ok)throw Error(`Failed to fetch course manifest for ${t}`);let i=await r.json();if(i.content&&i.content.manifest){let n=new URL(`.`,e).href,r=new URL(i.content.manifest,e).href,a=await fetch(r);if(!a.ok)throw Error(`Failed to fetch final content manifest for ${t} at ${r}`);let o=await a.json(),s=o.courseId||o.courseConfig?.courseID;if(!s)throw Error(`Course manifest for ${t} missing courseId`);this.manifests[s]=o;let c=new StaticDataUnpacker(o,n);this.courseUnpackers.set(s,c),this.dependencyNameToCourseId.set(t,s),logger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${t} (courseId: ${s})`)}}catch(e){logger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${t}:`,e)}logger.info(`[StaticDataLayerProvider] Course dependency resolution complete.`)}async initialize(){this.initialized||(logger.info(`Initializing static data layer provider`),await this.resolveCourseDependencies(),this.initialized=!0)}async teardown(){this.courseUnpackers.clear(),this.initialized=!1}getUserDB(){let e=new NoOpSyncStrategy;return BaseUser.Dummy(e)}getCourseDB(e){let t=this.courseUnpackers.get(e),n=e;if(!t){let r=this.dependencyNameToCourseId.get(e);r&&(t=this.courseUnpackers.get(r),n=r)}if(!t)throw Error(`Course ${e} not found or failed to initialize in static data layer.`);let r=this.manifests[n];return new StaticCourseDB(n,t,this.getUserDB(),r)}getCoursesDB(){return new StaticCoursesDB(this.manifests,this.dependencyNameToCourseId)}async getClassroomDB(e,t){throw Error(`Classrooms not supported in static mode`)}getAdminDB(){throw Error(`Admin functions not supported in static mode`)}isReadOnly(){return!0}};export{StaticDataLayerProvider};
2
- //# sourceMappingURL=StaticDataLayerProvider-CtgU3VBh.js.map
1
+ import{i as __name}from"./chunk-D6hFPZc3.js";import"./moment-DbT30ZpG.js";import{K as Status,d as BaseUser,f as accomodateGuest,g as PipelineAssembler,h as getLocalUserDB,k as createDefaultPipeline}from"./contentSource-FGhM_ge8.js";import{t as _defineProperty}from"./defineProperty-y9rbOPYz.js";import{k as logger}from"./PipelineDebugger-DhnKlMgD.js";import{o as DocType,s as DocTypePrefixes}from"./userDBKeys-3SQjNVdK.js";import"./eloDistance-CRxxdYPJ.js";var pathUtils={isAbsolute:e=>!!(/^[a-zA-Z]:[\\/]/.test(e)||/^\\\\/.test(e)||e.startsWith(`/`))},nodeFS=null;try{typeof window>`u`&&typeof process<`u`&&process.versions?.node&&(nodeFS=eval(`require`)(`fs`))}catch{}var StaticDataUnpacker=class{constructor(e,t){_defineProperty(this,`manifest`,void 0),_defineProperty(this,`basePath`,void 0),_defineProperty(this,`documentCache`,new Map),_defineProperty(this,`chunkCache`,new Map),_defineProperty(this,`indexCache`,new Map),this.manifest=e,this.basePath=t}async getDocument(e){if(this.documentCache.has(e)){let t=this.documentCache.get(e);return await this.hydrateAttachments(t)}let t=await this.findChunkForDocument(e);if(!t)throw logger.error(`Document ${e} not found in any chunk. Available chunks:`,this.manifest.chunks.map(e=>`${e.id} (${e.docType}): ${e.startKey} - ${e.endKey}`)),Error(`Document ${e} not found in any chunk`);if(await this.loadChunk(t.id),this.documentCache.has(e)){let t=this.documentCache.get(e);return await this.hydrateAttachments(t)}throw logger.error(`Document ${e} not found in chunk ${t.id}`),Error(`Document ${e} not found in chunk ${t.id}`)}async getAllDocumentsByPrefix(e){let t=this.manifest.chunks.filter(t=>{let n=e+`￰`;return t.startKey<=n&&t.endKey>=e});if(t.length===0)return logger.debug(`[StaticDataUnpacker] No chunks found for prefix: ${e}`),[];await Promise.all(t.map(e=>this.loadChunk(e.id)));let n=[];for(let[t,r]of this.documentCache.entries())t.startsWith(e)&&n.push(await this.hydrateAttachments(r));return logger.debug(`[StaticDataUnpacker] Found ${n.length} documents with prefix: ${e}`),n}async queryByElo(e,t=25){let n=await this.loadIndex(`elo`);if(!n||!n.sorted)return logger.warn(`ELO index not found or malformed, returning empty results`),[];let r=n.sorted,i=0,a=0,o=r.length-1;for(;a<=o;){let t=Math.floor((a+o)/2);r[t].elo<e?a=t+1:o=t-1}i=a;let s=[],c=Math.floor(t/2);for(let e=Math.max(0,i-c);e<i&&s.length<t;e++)s.push(r[e].cardId);for(let e=i;e<r.length&&s.length<t;e++)s.push(r[e].cardId);return s}async getTagsIndex(){try{return await this.loadIndex(`tags`)}catch{return{byCard:{},byTag:{}}}}getDocTypeFromId(e){for(let t in DocTypePrefixes){let n=DocTypePrefixes[t];if(e.startsWith(`${n}-`))return t}}async findChunkForDocument(e){let t=this.getDocTypeFromId(e);if(t){let n=this.manifest.chunks.filter(e=>e.docType===t);for(let t of n)if(e>=t.startKey&&e<=t.endKey&&await this.verifyDocumentInChunk(e,t))return t}else{for(let t of this.manifest.chunks)if(e>=t.startKey&&e<=t.endKey&&await this.verifyDocumentInChunk(e,t))return t;let t=this.manifest.chunks.filter(e=>e.docType!==`CARD`&&e.docType!==`DISPLAYABLE_DATA`&&e.docType!==`TAG`);for(let n of t)if(e>=n.startKey&&e<=n.endKey&&await this.verifyDocumentInChunk(e,n))return n;return}}async verifyDocumentInChunk(e,t){try{return await this.loadChunk(t.id),this.documentCache.has(e)}catch{return!1}}async loadChunk(e){if(this.chunkCache.has(e))return;let t=this.manifest.chunks.find(t=>t.id===e);if(!t)throw Error(`Chunk ${e} not found in manifest`);try{let n=`${this.basePath}/${t.path}`;logger.debug(`Loading chunk from ${n}`);let r;if(this.isLocalPath(n)&&nodeFS){let e=await nodeFS.promises.readFile(n,`utf8`);r=JSON.parse(e)}else{let t=await fetch(n);if(!t.ok)throw Error(`Failed to fetch chunk ${e}: ${t.status} ${t.statusText}`);r=await t.json()}this.chunkCache.set(e,r);for(let e of r)e._id&&this.documentCache.set(e._id,e);logger.debug(`Loaded ${r.length} documents from chunk ${e}`)}catch(t){throw logger.error(`Failed to load chunk ${e}:`,t),t}}async loadIndex(e){if(this.indexCache.has(e))return this.indexCache.get(e);let t=this.manifest.indices.find(t=>t.name===e);if(!t)throw Error(`Index ${e} not found in manifest`);try{let n=`${this.basePath}/${t.path}`;logger.debug(`Loading index from ${n}`);let r;if(this.isLocalPath(n)&&nodeFS){let e=await nodeFS.promises.readFile(n,`utf8`);r=JSON.parse(e)}else{let t=await fetch(n);if(!t.ok)throw Error(`Failed to fetch index ${e}: ${t.status} ${t.statusText}`);r=await t.json()}return this.indexCache.set(e,r),logger.debug(`Loaded index ${e}`),r}catch(t){throw logger.error(`Failed to load index ${e}:`,t),t}}async getRawDocument(e){if(this.documentCache.has(e))return this.documentCache.get(e);let t=await this.findChunkForDocument(e);if(!t)throw logger.error(`Document ${e} not found in any chunk. Available chunks:`,this.manifest.chunks.map(e=>`${e.id} (${e.docType}): ${e.startKey} - ${e.endKey}`)),Error(`Document ${e} not found in any chunk`);if(await this.loadChunk(t.id),this.documentCache.has(e))return this.documentCache.get(e);throw logger.error(`Document ${e} not found in chunk ${t.id}`),Error(`Document ${e} not found in chunk ${t.id}`)}getAttachmentUrl(e,t){return`${this.basePath}/attachments/${e}/${t}`}async getAttachmentPath(e,t){try{let n=await this.getRawDocument(e);if(n._attachments&&n._attachments[t]){let e=n._attachments[t];if(e.path)return`${this.basePath}/${e.path}`}return null}catch{return null}}async getAttachmentBlob(e,t){let n=await this.getAttachmentPath(e,t);if(!n)return null;try{if(this.isLocalPath(n)&&nodeFS)return await nodeFS.promises.readFile(n);{let r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch attachment ${e}/${t}: ${r.status} ${r.statusText}`);return await r.blob()}}catch(n){return logger.error(`Failed to load attachment ${e}/${t}:`,n),null}}async hydrateAttachments(e){let t=e;if(!t._attachments)return e;let n=JSON.parse(JSON.stringify(e));for(let[e,r]of Object.entries(t._attachments)){let i=r;if(i.path)try{let r=await this.getAttachmentBlob(t._id,e);r?typeof window<`u`&&window.URL?n._attachments[e]={...i,data:r,stub:!1}:n._attachments[e]={...i,buffer:r}:logger.warn(`[hydrateAttachments] getAttachmentBlob returned null for ${t._id}/${e}. Skipping hydration for this attachment.`)}catch(n){logger.warn(`[hydrateAttachments] Failed to hydrate attachment ${t._id}/${e}:`,n)}else logger.debug(`[hydrateAttachments] Attachment ${e} for doc ${t._id} has no path. Skipping blob conversion.`)}return n}clearCaches(){this.documentCache.clear(),this.chunkCache.clear(),this.indexCache.clear()}getCacheStats(){return{documents:this.documentCache.size,chunks:this.chunkCache.size,indices:this.indexCache.size}}isLocalPath(e){return!e.startsWith(`http://`)&&!e.startsWith(`https://`)&&(pathUtils.isAbsolute(e)||e.startsWith(`./`)||e.startsWith(`../`))}},StaticCourseDB=class{constructor(e,t,n,r){_defineProperty(this,`_pendingHints`,null),this.courseId=e,this.unpacker=t,this.userDB=n,this.manifest=r}getCourseID(){return this.courseId}async getCourseConfig(){if(this.manifest.courseConfig!=null)return this.manifest.courseConfig;throw Error(`Course config not found for course ${this.courseId}`)}async updateCourseConfig(e){throw Error(`Cannot update course config in static mode`)}async getCourseInfo(){return{cardCount:this.manifest.chunks.filter(e=>e.docType===DocType.CARD).reduce((e,t)=>e+t.documentCount,0),registeredUsers:0}}async getCourseDoc(e,t){return this.unpacker.getDocument(e)}async getCourseDocs(e,t){let n=await Promise.all(e.map(async e=>{try{return{id:e,key:e,value:{rev:`1-static`},doc:await this.unpacker.getDocument(e)}}catch{return{key:e,error:`not_found`}}}));return{total_rows:e.length,offset:0,rows:n}}async getCardsByELO(e,t){return(await this.unpacker.queryByElo(e,t||25)).map(e=>{let[t,n,r]=e.split(`-`);return{courseID:t,cardID:n,elo:r?parseInt(r):void 0}})}async getCardEloData(e){return await Promise.all(e.map(async e=>{try{return(await this.unpacker.getDocument(e)).elo||{global:{score:1e3,count:0},tags:{},misc:{}}}catch{return{global:{score:1e3,count:0},tags:{},misc:{}}}}))}async updateCardElo(e,t){return{ok:!0,id:e,rev:`1-static`}}async getCardsCenteredAtELO(e,t){let n=typeof e.elo==`number`?e.elo:1e3;if(e.elo===`user`)try{let e=(await this.userDB.getCourseRegistrationsDoc()).courses.find(e=>e.courseID===this.courseId);e&&typeof e.elo==`object`&&(n=e.elo.global.score)}catch{n=1e3}else e.elo===`random`&&(n=800+Math.random()*400);let r=(await this.unpacker.queryByElo(n,e.limit*2)).map(e=>({cardID:e,courseID:this.courseId}));return t&&(r=r.filter(t)),r.slice(0,e.limit).map(e=>({status:`new`,cardID:e.cardID,contentSourceType:`course`,contentSourceID:this.courseId,courseID:this.courseId}))}async getAppliedTags(e){try{let t=await this.unpacker.getTagsIndex(),n=t.byCard[e]||[],r=await Promise.all(n.map(async n=>{let r=`${DocType.TAG}-${n}`;try{let t=await this.unpacker.getDocument(r);return{id:r,key:e,value:{name:t.name,snippet:t.snippet,count:t.taggedCards?.length||0}}}catch(i){if(i&&i.status===404)logger.warn(`Tag document not found for ${n}, creating stub`);else throw logger.error(`Error getting tag document for ${n}:`,i),i;return{id:r,key:e,value:{name:n,snippet:`Tag: ${n}`,count:t.byTag[n]?.length||0}}}}));return{total_rows:r.length,offset:0,rows:r}}catch(t){return logger.error(`Error getting applied tags for card ${e}:`,t),{total_rows:0,offset:0,rows:[]}}}async getAppliedTagsBatch(e){let t=await this.unpacker.getTagsIndex(),n=new Map;for(let r of e)n.set(r,t.byCard[r]||[]);return n}async getAllCardIds(){let e=await this.unpacker.getTagsIndex();return Object.keys(e.byCard)}async addTagToCard(e,t){throw Error(`Cannot modify tags in static mode`)}async removeTagFromCard(e,t){throw Error(`Cannot modify tags in static mode`)}async createTag(e){throw Error(`Cannot create tags in static mode`)}async getTag(e){return this.unpacker.getDocument(`${DocType.TAG}-${e}`)}async updateTag(e){throw Error(`Cannot update tags in static mode`)}async getCourseTagStubs(){try{let e=await this.unpacker.getTagsIndex();if(!e||!e.byTag)return logger.warn(`Tags index not found or empty`),{total_rows:0,offset:0,rows:[]};let t=Object.keys(e.byTag),n=await Promise.all(t.map(async t=>{let n=e.byTag[t]||[],r=`${DocType.TAG}-${t}`;try{return{id:r,key:r,value:{rev:`1-static`},doc:await this.unpacker.getDocument(r)}}catch(e){if(e&&e.status===404)return logger.warn(`Tag document not found for ${t}, creating stub`),{id:r,key:r,value:{rev:`1-static`},doc:{_id:r,_rev:`1-static`,course:this.courseId,docType:DocType.TAG,name:t,snippet:`Tag: ${t}`,wiki:``,taggedCards:n,author:`system`}};throw logger.error(`Error getting tag document for ${t}:`,e),e}}));return{total_rows:n.length,offset:0,rows:n}}catch(e){return logger.error(`Failed to get course tag stubs:`,e),{total_rows:0,offset:0,rows:[]}}}async addNote(e,t,n,r,i,a,o){return{status:Status.error,message:`Cannot add notes in static mode`}}async removeCard(e){throw Error(`Cannot remove cards in static mode`)}async getInexperiencedCards(){return[]}async getNavigationStrategy(e){try{return await this.unpacker.getDocument(e)}catch(t){throw logger.error(`[static/courseDB] Strategy ${e} not found: ${t}`),t}}async getAllNavigationStrategies(){let e=DocTypePrefixes[DocType.NAVIGATION_STRATEGY];try{return await this.unpacker.getAllDocumentsByPrefix(e)}catch(e){return logger.warn(`[static/courseDB] Error loading navigation strategies: ${e}`),[]}}async addNavigationStrategy(e){throw Error(`Cannot add navigation strategies in static mode`)}async updateNavigationStrategy(e,t){throw Error(`Cannot update navigation strategies in static mode`)}async createNavigator(e){try{let t=await this.getAllNavigationStrategies();if(t.length===0)return logger.debug(`[static/courseDB] No strategy documents found, using default Pipeline(Composite(ELO, SRS), [eloDistanceFilter])`),createDefaultPipeline(e,this);let{pipeline:n,generatorStrategies:r,filterStrategies:i,warnings:a}=await new PipelineAssembler().assemble({strategies:t,user:e,course:this});for(let e of a)logger.warn(`[PipelineAssembler] ${e}`);return n?(logger.debug(`[static/courseDB] Using assembled pipeline with ${r.length} generator(s) and ${i.length} filter(s)`),n):(logger.debug(`[static/courseDB] Pipeline assembly failed, using default pipeline`),createDefaultPipeline(e,this))}catch(e){throw logger.error(`[static/courseDB] Error creating navigator: ${e}`),e}}setEphemeralHints(e){this._pendingHints=e}notePresented(e){e.status===`new`&&this.createNavigator(this.userDB).then(t=>t.notePresented?.(e)).catch(e=>logger.warn(`[static/courseDB] Could not note a presentation: ${e}`))}async getWeightedCards(e){try{let t=await this.createNavigator(this.userDB);return this._pendingHints&&(t.setEphemeralHints(this._pendingHints),this._pendingHints=null),t.getWeightedCards(e)}catch(e){throw logger.error(`[static/courseDB] Error getting weighted cards: ${e}`),e}}getAttachmentUrl(e,t){return this.unpacker.getAttachmentUrl(e,t)}async getAttachmentBlob(e,t){return this.unpacker.getAttachmentBlob(e,t)}async searchCards(e){return[]}async find(e){return{docs:[],warning:`Find operations not supported in static mode`}}},StaticCoursesDB=class{constructor(e,t){this.manifests=e,this.dependencyNameToCourseId=t}async getCourseConfig(e){let t=this.manifests[e];if(!t&&this.dependencyNameToCourseId){let n=this.dependencyNameToCourseId.get(e);n&&(t=this.manifests[n])}if(!t)throw logger.warn(`Course manifest for ${e} not found`),Error(`Course ${e} not found`);if(t.courseConfig)return t.courseConfig;throw logger.warn(`Course config not found in manifest for course ${e}`),Error(`Course config not found for course ${e}`)}async getCourseList(){return Object.keys(this.manifests).map(e=>({courseID:e,name:this.manifests[e].courseName}))}async disambiguateCourse(e,t){logger.warn(`Cannot disambiguate courses in static mode`)}},NoOpSyncStrategy=class{constructor(){_defineProperty(this,`currentUsername`,accomodateGuest().username)}setupRemoteDB(e){return getLocalUserDB(e)}getWriteDB(e){return getLocalUserDB(e)}startSync(e,t){}stopSync(){}canCreateAccount(){return!1}canAuthenticate(){return!1}async createAccount(e,t){throw Error(`Account creation not supported in static mode. Use local account switching instead.`)}async authenticate(e,t){throw Error(`Remote authentication not supported in static mode. Use local account switching instead.`)}async logout(){return this.currentUsername=accomodateGuest().username,{ok:!0}}async getCurrentUsername(){return this.currentUsername}setCurrentUsername(e){this.currentUsername=e}},StaticDataLayerProvider=class{constructor(e){_defineProperty(this,`config`,void 0),_defineProperty(this,`initialized`,!1),_defineProperty(this,`courseUnpackers`,new Map),_defineProperty(this,`manifests`,{}),_defineProperty(this,`dependencyNameToCourseId`,new Map),this.config={localStoragePrefix:e.localStoragePrefix||`skuilder-static`,rootManifest:e.rootManifest||{dependencies:{}},rootManifestUrl:e.rootManifestUrl||`/`}}async resolveCourseDependencies(){logger.info(`[StaticDataLayerProvider] Starting course dependency resolution...`);let e=this.config.rootManifest;for(let[t,n]of Object.entries(e.dependencies||{}))try{logger.debug(`[StaticDataLayerProvider] Resolving dependency: ${t} from ${n}`);let e=new URL(n,this.config.rootManifestUrl).href,r=await fetch(e);if(!r.ok)throw Error(`Failed to fetch course manifest for ${t}`);let i=await r.json();if(i.content&&i.content.manifest){let n=new URL(`.`,e).href,r=new URL(i.content.manifest,e).href,a=await fetch(r);if(!a.ok)throw Error(`Failed to fetch final content manifest for ${t} at ${r}`);let o=await a.json(),s=o.courseId||o.courseConfig?.courseID;if(!s)throw Error(`Course manifest for ${t} missing courseId`);this.manifests[s]=o;let c=new StaticDataUnpacker(o,n);this.courseUnpackers.set(s,c),this.dependencyNameToCourseId.set(t,s),logger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${t} (courseId: ${s})`)}}catch(e){logger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${t}:`,e)}logger.info(`[StaticDataLayerProvider] Course dependency resolution complete.`)}async initialize(){this.initialized||(logger.info(`Initializing static data layer provider`),await this.resolveCourseDependencies(),this.initialized=!0)}async teardown(){this.courseUnpackers.clear(),this.initialized=!1}getUserDB(){let e=new NoOpSyncStrategy;return BaseUser.Dummy(e)}getCourseDB(e){let t=this.courseUnpackers.get(e),n=e;if(!t){let r=this.dependencyNameToCourseId.get(e);r&&(t=this.courseUnpackers.get(r),n=r)}if(!t)throw Error(`Course ${e} not found or failed to initialize in static data layer.`);let r=this.manifests[n];return new StaticCourseDB(n,t,this.getUserDB(),r)}getCoursesDB(){return new StaticCoursesDB(this.manifests,this.dependencyNameToCourseId)}async getClassroomDB(e,t){throw Error(`Classrooms not supported in static mode`)}getAdminDB(){throw Error(`Admin functions not supported in static mode`)}isReadOnly(){return!0}};export{StaticDataLayerProvider};
2
+ //# sourceMappingURL=StaticDataLayerProvider-DbGLKpb1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StaticDataLayerProvider-CtgU3VBh.js","names":[],"sources":["../../../db/dist/impl/static/StaticDataUnpacker.mjs","../../../db/dist/impl/static/courseDB.mjs","../../../db/dist/impl/static/coursesDB.mjs","../../../db/dist/impl/static/NoOpSyncStrategy.mjs","../../../db/dist/impl/static/StaticDataLayerProvider.mjs"],"sourcesContent":["import { __name } from \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { DocTypePrefixes } from \"../../core/types/types-legacy.mjs\";\n//#region src/impl/static/StaticDataUnpacker.ts\nconst pathUtils = { isAbsolute: (path) => {\n\tif (/^[a-zA-Z]:[\\\\/]/.test(path) || /^\\\\\\\\/.test(path)) return true;\n\tif (path.startsWith(\"/\")) return true;\n\treturn false;\n} };\nlet nodeFS = null;\ntry {\n\tif (typeof window === \"undefined\" && typeof process !== \"undefined\" && process.versions?.node) nodeFS = eval(\"require\")(\"fs\");\n} catch {}\nvar StaticDataUnpacker = class {\n\tmanifest;\n\tbasePath;\n\tdocumentCache = /* @__PURE__ */ new Map();\n\tchunkCache = /* @__PURE__ */ new Map();\n\tindexCache = /* @__PURE__ */ new Map();\n\tconstructor(manifest, basePath) {\n\t\tthis.manifest = manifest;\n\t\tthis.basePath = basePath;\n\t}\n\t/**\n\t* Get a document by ID, loading from appropriate chunk if needed\n\t*/\n\tasync getDocument(id) {\n\t\tif (this.documentCache.has(id)) {\n\t\t\tconst doc = this.documentCache.get(id);\n\t\t\treturn await this.hydrateAttachments(doc);\n\t\t}\n\t\tconst chunk = await this.findChunkForDocument(id);\n\t\tif (!chunk) {\n\t\t\tlogger.error(`Document ${id} not found in any chunk. Available chunks:`, this.manifest.chunks.map((c) => `${c.id} (${c.docType}): ${c.startKey} - ${c.endKey}`));\n\t\t\tthrow new Error(`Document ${id} not found in any chunk`);\n\t\t}\n\t\tawait this.loadChunk(chunk.id);\n\t\tif (this.documentCache.has(id)) {\n\t\t\tconst doc = this.documentCache.get(id);\n\t\t\treturn await this.hydrateAttachments(doc);\n\t\t}\n\t\tlogger.error(`Document ${id} not found in chunk ${chunk.id}`);\n\t\tthrow new Error(`Document ${id} not found in chunk ${chunk.id}`);\n\t}\n\t/**\n\t* Get all documents with IDs starting with a specific prefix.\n\t*\n\t* This method loads the relevant chunk(s) and returns all matching documents.\n\t* Useful for querying documents by type (e.g., all NAVIGATION_STRATEGY documents).\n\t*\n\t* @param prefix - Document ID prefix to match (e.g., \"NAVIGATION_STRATEGY\")\n\t* @returns Array of all documents with IDs starting with the prefix\n\t*/\n\tasync getAllDocumentsByPrefix(prefix) {\n\t\tconst relevantChunks = this.manifest.chunks.filter((chunk) => {\n\t\t\tconst prefixEnd = prefix + \"￰\";\n\t\t\treturn chunk.startKey <= prefixEnd && chunk.endKey >= prefix;\n\t\t});\n\t\tif (relevantChunks.length === 0) {\n\t\t\tlogger.debug(`[StaticDataUnpacker] No chunks found for prefix: ${prefix}`);\n\t\t\treturn [];\n\t\t}\n\t\tawait Promise.all(relevantChunks.map((chunk) => this.loadChunk(chunk.id)));\n\t\tconst matchingDocs = [];\n\t\tfor (const [docId, doc] of this.documentCache.entries()) if (docId.startsWith(prefix)) matchingDocs.push(await this.hydrateAttachments(doc));\n\t\tlogger.debug(`[StaticDataUnpacker] Found ${matchingDocs.length} documents with prefix: ${prefix}`);\n\t\treturn matchingDocs;\n\t}\n\t/**\n\t* Query cards by ELO score, returning card IDs sorted by ELO\n\t*/\n\tasync queryByElo(targetElo, limit = 25) {\n\t\tconst eloIndex = await this.loadIndex(\"elo\");\n\t\tif (!eloIndex || !eloIndex.sorted) {\n\t\t\tlogger.warn(\"ELO index not found or malformed, returning empty results\");\n\t\t\treturn [];\n\t\t}\n\t\tconst sorted = eloIndex.sorted;\n\t\tlet startIndex = 0;\n\t\tlet left = 0;\n\t\tlet right = sorted.length - 1;\n\t\twhile (left <= right) {\n\t\t\tconst mid = Math.floor((left + right) / 2);\n\t\t\tif (sorted[mid].elo < targetElo) left = mid + 1;\n\t\t\telse right = mid - 1;\n\t\t}\n\t\tstartIndex = left;\n\t\tconst result = [];\n\t\tconst halfLimit = Math.floor(limit / 2);\n\t\tfor (let i = Math.max(0, startIndex - halfLimit); i < startIndex && result.length < limit; i++) result.push(sorted[i].cardId);\n\t\tfor (let i = startIndex; i < sorted.length && result.length < limit; i++) result.push(sorted[i].cardId);\n\t\treturn result;\n\t}\n\t/**\n\t* Get all tag names mapped to their card arrays\n\t*/\n\tasync getTagsIndex() {\n\t\ttry {\n\t\t\treturn await this.loadIndex(\"tags\");\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tbyCard: {},\n\t\t\t\tbyTag: {}\n\t\t\t};\n\t\t}\n\t}\n\tgetDocTypeFromId(id) {\n\t\tfor (const docTypeKey in DocTypePrefixes) {\n\t\t\tconst prefix = DocTypePrefixes[docTypeKey];\n\t\t\tif (id.startsWith(`${prefix}-`)) return docTypeKey;\n\t\t}\n\t}\n\t/**\n\t* Find which chunk contains a specific document ID\n\t*/\n\tasync findChunkForDocument(docId) {\n\t\tconst expectedDocType = this.getDocTypeFromId(docId);\n\t\tif (expectedDocType) {\n\t\t\tconst typeChunks = this.manifest.chunks.filter((c) => c.docType === expectedDocType);\n\t\t\tfor (const chunk of typeChunks) if (docId >= chunk.startKey && docId <= chunk.endKey) {\n\t\t\t\tif (await this.verifyDocumentInChunk(docId, chunk)) return chunk;\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const chunk of this.manifest.chunks) if (docId >= chunk.startKey && docId <= chunk.endKey) {\n\t\t\t\tif (await this.verifyDocumentInChunk(docId, chunk)) return chunk;\n\t\t\t}\n\t\t\tconst otherChunks = this.manifest.chunks.filter((c) => c.docType !== \"CARD\" && c.docType !== \"DISPLAYABLE_DATA\" && c.docType !== \"TAG\");\n\t\t\tfor (const chunk of otherChunks) if (docId >= chunk.startKey && docId <= chunk.endKey) {\n\t\t\t\tif (await this.verifyDocumentInChunk(docId, chunk)) return chunk;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\t/**\n\t* Verify that a document actually exists in a specific chunk by loading and checking it\n\t*/\n\tasync verifyDocumentInChunk(docId, chunk) {\n\t\ttry {\n\t\t\tawait this.loadChunk(chunk.id);\n\t\t\treturn this.documentCache.has(docId);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\t/**\n\t* Load a chunk file and cache its documents\n\t*/\n\tasync loadChunk(chunkId) {\n\t\tif (this.chunkCache.has(chunkId)) return;\n\t\tconst chunk = this.manifest.chunks.find((c) => c.id === chunkId);\n\t\tif (!chunk) throw new Error(`Chunk ${chunkId} not found in manifest`);\n\t\ttry {\n\t\t\tconst chunkPath = `${this.basePath}/${chunk.path}`;\n\t\t\tlogger.debug(`Loading chunk from ${chunkPath}`);\n\t\t\tlet documents;\n\t\t\tif (this.isLocalPath(chunkPath) && nodeFS) {\n\t\t\t\tconst fileContent = await nodeFS.promises.readFile(chunkPath, \"utf8\");\n\t\t\t\tdocuments = JSON.parse(fileContent);\n\t\t\t} else {\n\t\t\t\tconst response = await fetch(chunkPath);\n\t\t\t\tif (!response.ok) throw new Error(`Failed to fetch chunk ${chunkId}: ${response.status} ${response.statusText}`);\n\t\t\t\tdocuments = await response.json();\n\t\t\t}\n\t\t\tthis.chunkCache.set(chunkId, documents);\n\t\t\tfor (const doc of documents) if (doc._id) this.documentCache.set(doc._id, doc);\n\t\t\tlogger.debug(`Loaded ${documents.length} documents from chunk ${chunkId}`);\n\t\t} catch (error) {\n\t\t\tlogger.error(`Failed to load chunk ${chunkId}:`, error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\t/**\n\t* Load an index file and cache it\n\t*/\n\tasync loadIndex(indexName) {\n\t\tif (this.indexCache.has(indexName)) return this.indexCache.get(indexName);\n\t\tconst indexMeta = this.manifest.indices.find((idx) => idx.name === indexName);\n\t\tif (!indexMeta) throw new Error(`Index ${indexName} not found in manifest`);\n\t\ttry {\n\t\t\tconst indexPath = `${this.basePath}/${indexMeta.path}`;\n\t\t\tlogger.debug(`Loading index from ${indexPath}`);\n\t\t\tlet indexData;\n\t\t\tif (this.isLocalPath(indexPath) && nodeFS) {\n\t\t\t\tconst fileContent = await nodeFS.promises.readFile(indexPath, \"utf8\");\n\t\t\t\tindexData = JSON.parse(fileContent);\n\t\t\t} else {\n\t\t\t\tconst response = await fetch(indexPath);\n\t\t\t\tif (!response.ok) throw new Error(`Failed to fetch index ${indexName}: ${response.status} ${response.statusText}`);\n\t\t\t\tindexData = await response.json();\n\t\t\t}\n\t\t\tthis.indexCache.set(indexName, indexData);\n\t\t\tlogger.debug(`Loaded index ${indexName}`);\n\t\t\treturn indexData;\n\t\t} catch (error) {\n\t\t\tlogger.error(`Failed to load index ${indexName}:`, error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\t/**\n\t* Get a document by ID without hydration (raw document access)\n\t* Used internally to avoid recursion during attachment hydration\n\t*/\n\tasync getRawDocument(id) {\n\t\tif (this.documentCache.has(id)) return this.documentCache.get(id);\n\t\tconst chunk = await this.findChunkForDocument(id);\n\t\tif (!chunk) {\n\t\t\tlogger.error(`Document ${id} not found in any chunk. Available chunks:`, this.manifest.chunks.map((c) => `${c.id} (${c.docType}): ${c.startKey} - ${c.endKey}`));\n\t\t\tthrow new Error(`Document ${id} not found in any chunk`);\n\t\t}\n\t\tawait this.loadChunk(chunk.id);\n\t\tif (this.documentCache.has(id)) return this.documentCache.get(id);\n\t\tlogger.error(`Document ${id} not found in chunk ${chunk.id}`);\n\t\tthrow new Error(`Document ${id} not found in chunk ${chunk.id}`);\n\t}\n\t/**\n\t* Get attachment URL for a given document and attachment name\n\t*/\n\tgetAttachmentUrl(docId, attachmentName) {\n\t\treturn `${this.basePath}/attachments/${docId}/${attachmentName}`;\n\t}\n\t/**\n\t* Load attachment data from the document and get the correct file path\n\t* Uses raw document access to avoid recursion with hydration\n\t*/\n\tasync getAttachmentPath(docId, attachmentName) {\n\t\ttry {\n\t\t\tconst doc = await this.getRawDocument(docId);\n\t\t\tif (doc._attachments && doc._attachments[attachmentName]) {\n\t\t\t\tconst attachment = doc._attachments[attachmentName];\n\t\t\t\tif (attachment.path) return `${this.basePath}/${attachment.path}`;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\t/**\n\t* Load attachment as a blob (for browser) or buffer (for Node.js)\n\t*/\n\tasync getAttachmentBlob(docId, attachmentName) {\n\t\tconst attachmentPath = await this.getAttachmentPath(docId, attachmentName);\n\t\tif (!attachmentPath) return null;\n\t\ttry {\n\t\t\tif (this.isLocalPath(attachmentPath) && nodeFS) return await nodeFS.promises.readFile(attachmentPath);\n\t\t\telse {\n\t\t\t\tconst response = await fetch(attachmentPath);\n\t\t\t\tif (!response.ok) throw new Error(`Failed to fetch attachment ${docId}/${attachmentName}: ${response.status} ${response.statusText}`);\n\t\t\t\treturn await response.blob();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error(`Failed to load attachment ${docId}/${attachmentName}:`, error);\n\t\t\treturn null;\n\t\t}\n\t}\n\t/**\n\t* Hydrate document attachments by converting file paths to blob URLs\n\t*/\n\tasync hydrateAttachments(doc) {\n\t\tconst typedDoc = doc;\n\t\tif (!typedDoc._attachments) return doc;\n\t\tconst hydratedDoc = JSON.parse(JSON.stringify(doc));\n\t\tfor (const [attachmentName, attachment] of Object.entries(typedDoc._attachments)) {\n\t\t\tconst attachmentData = attachment;\n\t\t\tif (attachmentData.path) try {\n\t\t\t\tconst blob = await this.getAttachmentBlob(typedDoc._id, attachmentName);\n\t\t\t\tif (blob) if (typeof window !== \"undefined\" && window.URL) hydratedDoc._attachments[attachmentName] = {\n\t\t\t\t\t...attachmentData,\n\t\t\t\t\tdata: blob,\n\t\t\t\t\tstub: false\n\t\t\t\t};\n\t\t\t\telse hydratedDoc._attachments[attachmentName] = {\n\t\t\t\t\t...attachmentData,\n\t\t\t\t\tbuffer: blob\n\t\t\t\t};\n\t\t\t\telse logger.warn(`[hydrateAttachments] getAttachmentBlob returned null for ${typedDoc._id}/${attachmentName}. Skipping hydration for this attachment.`);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(`[hydrateAttachments] Failed to hydrate attachment ${typedDoc._id}/${attachmentName}:`, error);\n\t\t\t}\n\t\t\telse logger.debug(`[hydrateAttachments] Attachment ${attachmentName} for doc ${typedDoc._id} has no path. Skipping blob conversion.`);\n\t\t}\n\t\treturn hydratedDoc;\n\t}\n\t/**\n\t* Clear all caches (useful for testing or memory management)\n\t*/\n\tclearCaches() {\n\t\tthis.documentCache.clear();\n\t\tthis.chunkCache.clear();\n\t\tthis.indexCache.clear();\n\t}\n\t/**\n\t* Get cache statistics for debugging\n\t*/\n\tgetCacheStats() {\n\t\treturn {\n\t\t\tdocuments: this.documentCache.size,\n\t\t\tchunks: this.chunkCache.size,\n\t\t\tindices: this.indexCache.size\n\t\t};\n\t}\n\t/**\n\t* Check if a path is a local file path (vs URL)\n\t*/\n\tisLocalPath(filePath) {\n\t\treturn !filePath.startsWith(\"http://\") && !filePath.startsWith(\"https://\") && (pathUtils.isAbsolute(filePath) || filePath.startsWith(\"./\") || filePath.startsWith(\"../\"));\n\t}\n};\n//#endregion\nexport { StaticDataUnpacker };\n\n//# sourceMappingURL=StaticDataUnpacker.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { DocType, DocTypePrefixes } from \"../../core/types/types-legacy.mjs\";\nimport { createDefaultPipeline } from \"../../core/navigators/defaults.mjs\";\nimport { PipelineAssembler } from \"../../core/navigators/PipelineAssembler.mjs\";\nimport { Status } from \"@vue-skuilder/common\";\n//#region src/impl/static/courseDB.ts\nvar StaticCourseDB = class {\n\tconstructor(courseId, unpacker, userDB, manifest) {\n\t\tthis.courseId = courseId;\n\t\tthis.unpacker = unpacker;\n\t\tthis.userDB = userDB;\n\t\tthis.manifest = manifest;\n\t}\n\tgetCourseID() {\n\t\treturn this.courseId;\n\t}\n\tasync getCourseConfig() {\n\t\tif (this.manifest.courseConfig != null) return this.manifest.courseConfig;\n\t\telse throw new Error(`Course config not found for course ${this.courseId}`);\n\t}\n\tasync updateCourseConfig(_cfg) {\n\t\tthrow new Error(\"Cannot update course config in static mode\");\n\t}\n\tasync getCourseInfo() {\n\t\treturn {\n\t\t\tcardCount: this.manifest.chunks.filter((chunk) => chunk.docType === DocType.CARD).reduce((total, chunk) => total + chunk.documentCount, 0),\n\t\t\tregisteredUsers: 0\n\t\t};\n\t}\n\tasync getCourseDoc(id, _options) {\n\t\treturn this.unpacker.getDocument(id);\n\t}\n\tasync getCourseDocs(ids, _options) {\n\t\tconst rows = await Promise.all(ids.map(async (id) => {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tid,\n\t\t\t\t\tkey: id,\n\t\t\t\t\tvalue: { rev: \"1-static\" },\n\t\t\t\t\tdoc: await this.unpacker.getDocument(id)\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tkey: id,\n\t\t\t\t\terror: \"not_found\"\n\t\t\t\t};\n\t\t\t}\n\t\t}));\n\t\treturn {\n\t\t\ttotal_rows: ids.length,\n\t\t\toffset: 0,\n\t\t\trows\n\t\t};\n\t}\n\tasync getCardsByELO(elo, limit) {\n\t\treturn (await this.unpacker.queryByElo(elo, limit || 25)).map((card) => {\n\t\t\tconst [courseID, cardID, elo] = card.split(\"-\");\n\t\t\treturn {\n\t\t\t\tcourseID,\n\t\t\t\tcardID,\n\t\t\t\telo: elo ? parseInt(elo) : void 0\n\t\t\t};\n\t\t});\n\t}\n\tasync getCardEloData(cardIds) {\n\t\treturn await Promise.all(cardIds.map(async (id) => {\n\t\t\ttry {\n\t\t\t\treturn (await this.unpacker.getDocument(id)).elo || {\n\t\t\t\t\tglobal: {\n\t\t\t\t\t\tscore: 1e3,\n\t\t\t\t\t\tcount: 0\n\t\t\t\t\t},\n\t\t\t\t\ttags: {},\n\t\t\t\t\tmisc: {}\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tglobal: {\n\t\t\t\t\t\tscore: 1e3,\n\t\t\t\t\t\tcount: 0\n\t\t\t\t\t},\n\t\t\t\t\ttags: {},\n\t\t\t\t\tmisc: {}\n\t\t\t\t};\n\t\t\t}\n\t\t}));\n\t}\n\tasync updateCardElo(cardId, _elo) {\n\t\treturn {\n\t\t\tok: true,\n\t\t\tid: cardId,\n\t\t\trev: \"1-static\"\n\t\t};\n\t}\n\tasync getCardsCenteredAtELO(options, filter) {\n\t\tlet targetElo = typeof options.elo === \"number\" ? options.elo : 1e3;\n\t\tif (options.elo === \"user\") try {\n\t\t\tconst courseReg = (await this.userDB.getCourseRegistrationsDoc()).courses.find((c) => c.courseID === this.courseId);\n\t\t\tif (courseReg && typeof courseReg.elo === \"object\") targetElo = courseReg.elo.global.score;\n\t\t} catch {\n\t\t\ttargetElo = 1e3;\n\t\t}\n\t\telse if (options.elo === \"random\") targetElo = 800 + Math.random() * 400;\n\t\tlet cardIds = (await this.unpacker.queryByElo(targetElo, options.limit * 2)).map((c) => {\n\t\t\treturn {\n\t\t\t\tcardID: c,\n\t\t\t\tcourseID: this.courseId\n\t\t\t};\n\t\t});\n\t\tif (filter) cardIds = cardIds.filter(filter);\n\t\treturn cardIds.slice(0, options.limit).map((card) => ({\n\t\t\tstatus: \"new\",\n\t\t\tcardID: card.cardID,\n\t\t\tcontentSourceType: \"course\",\n\t\t\tcontentSourceID: this.courseId,\n\t\t\tcourseID: this.courseId\n\t\t}));\n\t}\n\tasync getAppliedTags(cardId) {\n\t\ttry {\n\t\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\t\tconst cardTags = tagsIndex.byCard[cardId] || [];\n\t\t\tconst rows = await Promise.all(cardTags.map(async (tagName) => {\n\t\t\t\tconst tagId = `${DocType.TAG}-${tagName}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst tagDoc = await this.unpacker.getDocument(tagId);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\tkey: cardId,\n\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\tname: tagDoc.name,\n\t\t\t\t\t\t\tsnippet: tagDoc.snippet,\n\t\t\t\t\t\t\tcount: tagDoc.taggedCards?.length || 0\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error && error.status === 404) logger.warn(`Tag document not found for ${tagName}, creating stub`);\n\t\t\t\t\telse {\n\t\t\t\t\t\tlogger.error(`Error getting tag document for ${tagName}:`, error);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\tkey: cardId,\n\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\tname: tagName,\n\t\t\t\t\t\t\tsnippet: `Tag: ${tagName}`,\n\t\t\t\t\t\t\tcount: tagsIndex.byTag[tagName]?.length || 0\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}));\n\t\t\treturn {\n\t\t\t\ttotal_rows: rows.length,\n\t\t\t\toffset: 0,\n\t\t\t\trows\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tlogger.error(`Error getting applied tags for card ${cardId}:`, error);\n\t\t\treturn {\n\t\t\t\ttotal_rows: 0,\n\t\t\t\toffset: 0,\n\t\t\t\trows: []\n\t\t\t};\n\t\t}\n\t}\n\tasync getAppliedTagsBatch(cardIds) {\n\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\tconst tagsByCard = /* @__PURE__ */ new Map();\n\t\tfor (const cardId of cardIds) tagsByCard.set(cardId, tagsIndex.byCard[cardId] || []);\n\t\treturn tagsByCard;\n\t}\n\tasync getAllCardIds() {\n\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\treturn Object.keys(tagsIndex.byCard);\n\t}\n\tasync addTagToCard(_cardId, _tagId) {\n\t\tthrow new Error(\"Cannot modify tags in static mode\");\n\t}\n\tasync removeTagFromCard(_cardId, _tagId) {\n\t\tthrow new Error(\"Cannot modify tags in static mode\");\n\t}\n\tasync createTag(_tagName) {\n\t\tthrow new Error(\"Cannot create tags in static mode\");\n\t}\n\tasync getTag(tagName) {\n\t\treturn this.unpacker.getDocument(`${DocType.TAG}-${tagName}`);\n\t}\n\tasync updateTag(_tag) {\n\t\tthrow new Error(\"Cannot update tags in static mode\");\n\t}\n\tasync getCourseTagStubs() {\n\t\ttry {\n\t\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\t\tif (!tagsIndex || !tagsIndex.byTag) {\n\t\t\t\tlogger.warn(\"Tags index not found or empty\");\n\t\t\t\treturn {\n\t\t\t\t\ttotal_rows: 0,\n\t\t\t\t\toffset: 0,\n\t\t\t\t\trows: []\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst tagNames = Object.keys(tagsIndex.byTag);\n\t\t\tconst rows = await Promise.all(tagNames.map(async (tagName) => {\n\t\t\t\tconst cardIds = tagsIndex.byTag[tagName] || [];\n\t\t\t\tconst tagId = `${DocType.TAG}-${tagName}`;\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\tkey: tagId,\n\t\t\t\t\t\tvalue: { rev: \"1-static\" },\n\t\t\t\t\t\tdoc: await this.unpacker.getDocument(tagId)\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error && error.status === 404) {\n\t\t\t\t\t\tlogger.warn(`Tag document not found for ${tagName}, creating stub`);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\t\tkey: tagId,\n\t\t\t\t\t\t\tvalue: { rev: \"1-static\" },\n\t\t\t\t\t\t\tdoc: {\n\t\t\t\t\t\t\t\t_id: tagId,\n\t\t\t\t\t\t\t\t_rev: \"1-static\",\n\t\t\t\t\t\t\t\tcourse: this.courseId,\n\t\t\t\t\t\t\t\tdocType: DocType.TAG,\n\t\t\t\t\t\t\t\tname: tagName,\n\t\t\t\t\t\t\t\tsnippet: `Tag: ${tagName}`,\n\t\t\t\t\t\t\t\twiki: \"\",\n\t\t\t\t\t\t\t\ttaggedCards: cardIds,\n\t\t\t\t\t\t\t\tauthor: \"system\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.error(`Error getting tag document for ${tagName}:`, error);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}));\n\t\t\treturn {\n\t\t\t\ttotal_rows: rows.length,\n\t\t\t\toffset: 0,\n\t\t\t\trows\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tlogger.error(\"Failed to get course tag stubs:\", error);\n\t\t\treturn {\n\t\t\t\ttotal_rows: 0,\n\t\t\t\toffset: 0,\n\t\t\t\trows: []\n\t\t\t};\n\t\t}\n\t}\n\tasync addNote(_codeCourse, _shape, _data, _author, _tags, _uploads, _elo) {\n\t\treturn {\n\t\t\tstatus: Status.error,\n\t\t\tmessage: \"Cannot add notes in static mode\"\n\t\t};\n\t}\n\tasync removeCard(_cardId) {\n\t\tthrow new Error(\"Cannot remove cards in static mode\");\n\t}\n\tasync getInexperiencedCards() {\n\t\treturn [];\n\t}\n\tasync getNavigationStrategy(id) {\n\t\ttry {\n\t\t\treturn await this.unpacker.getDocument(id);\n\t\t} catch (error) {\n\t\t\tlogger.error(`[static/courseDB] Strategy ${id} not found: ${error}`);\n\t\t\tthrow error;\n\t\t}\n\t}\n\tasync getAllNavigationStrategies() {\n\t\tconst prefix = DocTypePrefixes[DocType.NAVIGATION_STRATEGY];\n\t\ttry {\n\t\t\treturn await this.unpacker.getAllDocumentsByPrefix(prefix);\n\t\t} catch (error) {\n\t\t\tlogger.warn(`[static/courseDB] Error loading navigation strategies: ${error}`);\n\t\t\treturn [];\n\t\t}\n\t}\n\tasync addNavigationStrategy(_data) {\n\t\tthrow new Error(\"Cannot add navigation strategies in static mode\");\n\t}\n\tasync updateNavigationStrategy(_id, _data) {\n\t\tthrow new Error(\"Cannot update navigation strategies in static mode\");\n\t}\n\t/**\n\t* Create a ContentNavigator for this course.\n\t*\n\t* Loads navigation strategy documents from static data and uses PipelineAssembler\n\t* to build a Pipeline. Falls back to default pipeline if no strategies found.\n\t*/\n\tasync createNavigator(user) {\n\t\ttry {\n\t\t\tconst allStrategies = await this.getAllNavigationStrategies();\n\t\t\tif (allStrategies.length === 0) {\n\t\t\t\tlogger.debug(\"[static/courseDB] No strategy documents found, using default Pipeline(Composite(ELO, SRS), [eloDistanceFilter])\");\n\t\t\t\treturn createDefaultPipeline(user, this);\n\t\t\t}\n\t\t\tconst { pipeline, generatorStrategies, filterStrategies, warnings } = await new PipelineAssembler().assemble({\n\t\t\t\tstrategies: allStrategies,\n\t\t\t\tuser,\n\t\t\t\tcourse: this\n\t\t\t});\n\t\t\tfor (const warning of warnings) logger.warn(`[PipelineAssembler] ${warning}`);\n\t\t\tif (!pipeline) {\n\t\t\t\tlogger.debug(\"[static/courseDB] Pipeline assembly failed, using default pipeline\");\n\t\t\t\treturn createDefaultPipeline(user, this);\n\t\t\t}\n\t\t\tlogger.debug(`[static/courseDB] Using assembled pipeline with ${generatorStrategies.length} generator(s) and ${filterStrategies.length} filter(s)`);\n\t\t\treturn pipeline;\n\t\t} catch (e) {\n\t\t\tlogger.error(`[static/courseDB] Error creating navigator: ${e}`);\n\t\t\tthrow e;\n\t\t}\n\t}\n\t_pendingHints = null;\n\tsetEphemeralHints(hints) {\n\t\tthis._pendingHints = hints;\n\t}\n\t/** Forward a presentation to the navigator (a new card restarts its intake clock). */\n\tnotePresented(card) {\n\t\tif (card.status !== \"new\") return;\n\t\tthis.createNavigator(this.userDB).then((navigator) => navigator.notePresented?.(card)).catch((e) => logger.warn(`[static/courseDB] Could not note a presentation: ${e}`));\n\t}\n\tasync getWeightedCards(limit) {\n\t\ttry {\n\t\t\tconst navigator = await this.createNavigator(this.userDB);\n\t\t\tif (this._pendingHints) {\n\t\t\t\tnavigator.setEphemeralHints(this._pendingHints);\n\t\t\t\tthis._pendingHints = null;\n\t\t\t}\n\t\t\treturn navigator.getWeightedCards(limit);\n\t\t} catch (e) {\n\t\t\tlogger.error(`[static/courseDB] Error getting weighted cards: ${e}`);\n\t\t\tthrow e;\n\t\t}\n\t}\n\t/**\n\t* Get attachment URL for a document and attachment name\n\t* Internal helper method for static attachment serving\n\t*/\n\tgetAttachmentUrl(docId, attachmentName) {\n\t\treturn this.unpacker.getAttachmentUrl(docId, attachmentName);\n\t}\n\t/**\n\t* Load attachment as blob/buffer\n\t* Internal helper method for static attachment serving\n\t*/\n\tasync getAttachmentBlob(docId, attachmentName) {\n\t\treturn this.unpacker.getAttachmentBlob(docId, attachmentName);\n\t}\n\tasync searchCards(_query) {\n\t\treturn [];\n\t}\n\tasync find(_request) {\n\t\treturn {\n\t\t\tdocs: [],\n\t\t\twarning: \"Find operations not supported in static mode\"\n\t\t};\n\t}\n};\n//#endregion\nexport { StaticCourseDB };\n\n//# sourceMappingURL=courseDB.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\n//#region src/impl/static/coursesDB.ts\nvar StaticCoursesDB = class {\n\tconstructor(manifests, dependencyNameToCourseId) {\n\t\tthis.manifests = manifests;\n\t\tthis.dependencyNameToCourseId = dependencyNameToCourseId;\n\t}\n\tasync getCourseConfig(courseId) {\n\t\tlet manifest = this.manifests[courseId];\n\t\tif (!manifest && this.dependencyNameToCourseId) {\n\t\t\tconst mappedCourseId = this.dependencyNameToCourseId.get(courseId);\n\t\t\tif (mappedCourseId) manifest = this.manifests[mappedCourseId];\n\t\t}\n\t\tif (!manifest) {\n\t\t\tlogger.warn(`Course manifest for ${courseId} not found`);\n\t\t\tthrow new Error(`Course ${courseId} not found`);\n\t\t}\n\t\tif (manifest.courseConfig) return manifest.courseConfig;\n\t\telse {\n\t\t\tlogger.warn(`Course config not found in manifest for course ${courseId}`);\n\t\t\tthrow new Error(`Course config not found for course ${courseId}`);\n\t\t}\n\t}\n\tasync getCourseList() {\n\t\treturn Object.keys(this.manifests).map((courseId) => ({\n\t\t\tcourseID: courseId,\n\t\t\tname: this.manifests[courseId].courseName\n\t\t}));\n\t}\n\tasync disambiguateCourse(_courseId, _disambiguator) {\n\t\tlogger.warn(\"Cannot disambiguate courses in static mode\");\n\t}\n};\n//#endregion\nexport { StaticCoursesDB };\n\n//# sourceMappingURL=coursesDB.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { getLocalUserDB } from \"../common/userDBHelpers.mjs\";\nimport { accomodateGuest } from \"../common/BaseUserDB.mjs\";\n//#region src/impl/static/NoOpSyncStrategy.ts\n/**\n* Sync strategy for static deployments that provides no-op implementations\n* for remote operations. Uses only local storage with no remote synchronization.\n*/\nvar NoOpSyncStrategy = class {\n\tcurrentUsername = accomodateGuest().username;\n\tsetupRemoteDB(username) {\n\t\treturn getLocalUserDB(username);\n\t}\n\tgetWriteDB(username) {\n\t\treturn getLocalUserDB(username);\n\t}\n\tstartSync(_localDB, _remoteDB) {}\n\tstopSync() {}\n\tcanCreateAccount() {\n\t\treturn false;\n\t}\n\tcanAuthenticate() {\n\t\treturn false;\n\t}\n\tasync createAccount(_username, _password) {\n\t\tthrow new Error(\"Account creation not supported in static mode. Use local account switching instead.\");\n\t}\n\tasync authenticate(_username, _password) {\n\t\tthrow new Error(\"Remote authentication not supported in static mode. Use local account switching instead.\");\n\t}\n\tasync logout() {\n\t\tthis.currentUsername = accomodateGuest().username;\n\t\treturn { ok: true };\n\t}\n\tasync getCurrentUsername() {\n\t\treturn this.currentUsername;\n\t}\n\t/**\n\t* Set the current username (for local account switching)\n\t* This method is specific to NoOpSyncStrategy and not part of the base interface\n\t*/\n\tsetCurrentUsername(username) {\n\t\tthis.currentUsername = username;\n\t}\n};\n//#endregion\nexport { NoOpSyncStrategy };\n\n//# sourceMappingURL=NoOpSyncStrategy.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { BaseUser } from \"../common/BaseUserDB.mjs\";\nimport { StaticDataUnpacker } from \"./StaticDataUnpacker.mjs\";\nimport { StaticCourseDB } from \"./courseDB.mjs\";\nimport { StaticCoursesDB } from \"./coursesDB.mjs\";\nimport { NoOpSyncStrategy } from \"./NoOpSyncStrategy.mjs\";\n//#region src/impl/static/StaticDataLayerProvider.ts\nvar StaticDataLayerProvider = class {\n\tconfig;\n\tinitialized = false;\n\tcourseUnpackers = /* @__PURE__ */ new Map();\n\tmanifests = {};\n\tdependencyNameToCourseId = /* @__PURE__ */ new Map();\n\tconstructor(config) {\n\t\tthis.config = {\n\t\t\tlocalStoragePrefix: config.localStoragePrefix || \"skuilder-static\",\n\t\t\trootManifest: config.rootManifest || { dependencies: {} },\n\t\t\trootManifestUrl: config.rootManifestUrl || \"/\"\n\t\t};\n\t}\n\tasync resolveCourseDependencies() {\n\t\tlogger.info(\"[StaticDataLayerProvider] Starting course dependency resolution...\");\n\t\tconst rootManifest = this.config.rootManifest;\n\t\tfor (const [courseName, courseUrl] of Object.entries(rootManifest.dependencies || {})) try {\n\t\t\tlogger.debug(`[StaticDataLayerProvider] Resolving dependency: ${courseName} from ${courseUrl}`);\n\t\t\tconst courseManifestUrl = new URL(courseUrl, this.config.rootManifestUrl).href;\n\t\t\tconst courseJsonResponse = await fetch(courseManifestUrl);\n\t\t\tif (!courseJsonResponse.ok) throw new Error(`Failed to fetch course manifest for ${courseName}`);\n\t\t\tconst courseJson = await courseJsonResponse.json();\n\t\t\tif (courseJson.content && courseJson.content.manifest) {\n\t\t\t\tconst baseUrl = new URL(\".\", courseManifestUrl).href;\n\t\t\t\tconst finalManifestUrl = new URL(courseJson.content.manifest, courseManifestUrl).href;\n\t\t\t\tconst finalManifestResponse = await fetch(finalManifestUrl);\n\t\t\t\tif (!finalManifestResponse.ok) throw new Error(`Failed to fetch final content manifest for ${courseName} at ${finalManifestUrl}`);\n\t\t\t\tconst finalManifest = await finalManifestResponse.json();\n\t\t\t\tconst courseId = finalManifest.courseId || finalManifest.courseConfig?.courseID;\n\t\t\t\tif (!courseId) throw new Error(`Course manifest for ${courseName} missing courseId`);\n\t\t\t\tthis.manifests[courseId] = finalManifest;\n\t\t\t\tconst unpacker = new StaticDataUnpacker(finalManifest, baseUrl);\n\t\t\t\tthis.courseUnpackers.set(courseId, unpacker);\n\t\t\t\tthis.dependencyNameToCourseId.set(courseName, courseId);\n\t\t\t\tlogger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${courseName} (courseId: ${courseId})`);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tlogger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${courseName}:`, e);\n\t\t}\n\t\tlogger.info(\"[StaticDataLayerProvider] Course dependency resolution complete.\");\n\t}\n\tasync initialize() {\n\t\tif (this.initialized) return;\n\t\tlogger.info(\"Initializing static data layer provider\");\n\t\tawait this.resolveCourseDependencies();\n\t\tthis.initialized = true;\n\t}\n\tasync teardown() {\n\t\tthis.courseUnpackers.clear();\n\t\tthis.initialized = false;\n\t}\n\tgetUserDB() {\n\t\tconst syncStrategy = new NoOpSyncStrategy();\n\t\treturn BaseUser.Dummy(syncStrategy);\n\t}\n\tgetCourseDB(courseId) {\n\t\tlet unpacker = this.courseUnpackers.get(courseId);\n\t\tlet actualCourseId = courseId;\n\t\tif (!unpacker) {\n\t\t\tconst mappedCourseId = this.dependencyNameToCourseId.get(courseId);\n\t\t\tif (mappedCourseId) {\n\t\t\t\tunpacker = this.courseUnpackers.get(mappedCourseId);\n\t\t\t\tactualCourseId = mappedCourseId;\n\t\t\t}\n\t\t}\n\t\tif (!unpacker) throw new Error(`Course ${courseId} not found or failed to initialize in static data layer.`);\n\t\tconst manifest = this.manifests[actualCourseId];\n\t\treturn new StaticCourseDB(actualCourseId, unpacker, this.getUserDB(), manifest);\n\t}\n\tgetCoursesDB() {\n\t\treturn new StaticCoursesDB(this.manifests, this.dependencyNameToCourseId);\n\t}\n\tasync getClassroomDB(_classId, _type) {\n\t\tthrow new Error(\"Classrooms not supported in static mode\");\n\t}\n\tgetAdminDB() {\n\t\tthrow new Error(\"Admin functions not supported in static mode\");\n\t}\n\tisReadOnly() {\n\t\treturn true;\n\t}\n};\n//#endregion\nexport { StaticDataLayerProvider };\n\n//# sourceMappingURL=StaticDataLayerProvider.mjs.map"],"mappings":"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"}
1
+ {"version":3,"file":"StaticDataLayerProvider-DbGLKpb1.js","names":[],"sources":["../../../db/dist/impl/static/StaticDataUnpacker.mjs","../../../db/dist/impl/static/courseDB.mjs","../../../db/dist/impl/static/coursesDB.mjs","../../../db/dist/impl/static/NoOpSyncStrategy.mjs","../../../db/dist/impl/static/StaticDataLayerProvider.mjs"],"sourcesContent":["import { __name } from \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { DocTypePrefixes } from \"../../core/types/types-legacy.mjs\";\n//#region src/impl/static/StaticDataUnpacker.ts\nconst pathUtils = { isAbsolute: (path) => {\n\tif (/^[a-zA-Z]:[\\\\/]/.test(path) || /^\\\\\\\\/.test(path)) return true;\n\tif (path.startsWith(\"/\")) return true;\n\treturn false;\n} };\nlet nodeFS = null;\ntry {\n\tif (typeof window === \"undefined\" && typeof process !== \"undefined\" && process.versions?.node) nodeFS = eval(\"require\")(\"fs\");\n} catch {}\nvar StaticDataUnpacker = class {\n\tmanifest;\n\tbasePath;\n\tdocumentCache = /* @__PURE__ */ new Map();\n\tchunkCache = /* @__PURE__ */ new Map();\n\tindexCache = /* @__PURE__ */ new Map();\n\tconstructor(manifest, basePath) {\n\t\tthis.manifest = manifest;\n\t\tthis.basePath = basePath;\n\t}\n\t/**\n\t* Get a document by ID, loading from appropriate chunk if needed\n\t*/\n\tasync getDocument(id) {\n\t\tif (this.documentCache.has(id)) {\n\t\t\tconst doc = this.documentCache.get(id);\n\t\t\treturn await this.hydrateAttachments(doc);\n\t\t}\n\t\tconst chunk = await this.findChunkForDocument(id);\n\t\tif (!chunk) {\n\t\t\tlogger.error(`Document ${id} not found in any chunk. Available chunks:`, this.manifest.chunks.map((c) => `${c.id} (${c.docType}): ${c.startKey} - ${c.endKey}`));\n\t\t\tthrow new Error(`Document ${id} not found in any chunk`);\n\t\t}\n\t\tawait this.loadChunk(chunk.id);\n\t\tif (this.documentCache.has(id)) {\n\t\t\tconst doc = this.documentCache.get(id);\n\t\t\treturn await this.hydrateAttachments(doc);\n\t\t}\n\t\tlogger.error(`Document ${id} not found in chunk ${chunk.id}`);\n\t\tthrow new Error(`Document ${id} not found in chunk ${chunk.id}`);\n\t}\n\t/**\n\t* Get all documents with IDs starting with a specific prefix.\n\t*\n\t* This method loads the relevant chunk(s) and returns all matching documents.\n\t* Useful for querying documents by type (e.g., all NAVIGATION_STRATEGY documents).\n\t*\n\t* @param prefix - Document ID prefix to match (e.g., \"NAVIGATION_STRATEGY\")\n\t* @returns Array of all documents with IDs starting with the prefix\n\t*/\n\tasync getAllDocumentsByPrefix(prefix) {\n\t\tconst relevantChunks = this.manifest.chunks.filter((chunk) => {\n\t\t\tconst prefixEnd = prefix + \"￰\";\n\t\t\treturn chunk.startKey <= prefixEnd && chunk.endKey >= prefix;\n\t\t});\n\t\tif (relevantChunks.length === 0) {\n\t\t\tlogger.debug(`[StaticDataUnpacker] No chunks found for prefix: ${prefix}`);\n\t\t\treturn [];\n\t\t}\n\t\tawait Promise.all(relevantChunks.map((chunk) => this.loadChunk(chunk.id)));\n\t\tconst matchingDocs = [];\n\t\tfor (const [docId, doc] of this.documentCache.entries()) if (docId.startsWith(prefix)) matchingDocs.push(await this.hydrateAttachments(doc));\n\t\tlogger.debug(`[StaticDataUnpacker] Found ${matchingDocs.length} documents with prefix: ${prefix}`);\n\t\treturn matchingDocs;\n\t}\n\t/**\n\t* Query cards by ELO score, returning card IDs sorted by ELO\n\t*/\n\tasync queryByElo(targetElo, limit = 25) {\n\t\tconst eloIndex = await this.loadIndex(\"elo\");\n\t\tif (!eloIndex || !eloIndex.sorted) {\n\t\t\tlogger.warn(\"ELO index not found or malformed, returning empty results\");\n\t\t\treturn [];\n\t\t}\n\t\tconst sorted = eloIndex.sorted;\n\t\tlet startIndex = 0;\n\t\tlet left = 0;\n\t\tlet right = sorted.length - 1;\n\t\twhile (left <= right) {\n\t\t\tconst mid = Math.floor((left + right) / 2);\n\t\t\tif (sorted[mid].elo < targetElo) left = mid + 1;\n\t\t\telse right = mid - 1;\n\t\t}\n\t\tstartIndex = left;\n\t\tconst result = [];\n\t\tconst halfLimit = Math.floor(limit / 2);\n\t\tfor (let i = Math.max(0, startIndex - halfLimit); i < startIndex && result.length < limit; i++) result.push(sorted[i].cardId);\n\t\tfor (let i = startIndex; i < sorted.length && result.length < limit; i++) result.push(sorted[i].cardId);\n\t\treturn result;\n\t}\n\t/**\n\t* Get all tag names mapped to their card arrays\n\t*/\n\tasync getTagsIndex() {\n\t\ttry {\n\t\t\treturn await this.loadIndex(\"tags\");\n\t\t} catch {\n\t\t\treturn {\n\t\t\t\tbyCard: {},\n\t\t\t\tbyTag: {}\n\t\t\t};\n\t\t}\n\t}\n\tgetDocTypeFromId(id) {\n\t\tfor (const docTypeKey in DocTypePrefixes) {\n\t\t\tconst prefix = DocTypePrefixes[docTypeKey];\n\t\t\tif (id.startsWith(`${prefix}-`)) return docTypeKey;\n\t\t}\n\t}\n\t/**\n\t* Find which chunk contains a specific document ID\n\t*/\n\tasync findChunkForDocument(docId) {\n\t\tconst expectedDocType = this.getDocTypeFromId(docId);\n\t\tif (expectedDocType) {\n\t\t\tconst typeChunks = this.manifest.chunks.filter((c) => c.docType === expectedDocType);\n\t\t\tfor (const chunk of typeChunks) if (docId >= chunk.startKey && docId <= chunk.endKey) {\n\t\t\t\tif (await this.verifyDocumentInChunk(docId, chunk)) return chunk;\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const chunk of this.manifest.chunks) if (docId >= chunk.startKey && docId <= chunk.endKey) {\n\t\t\t\tif (await this.verifyDocumentInChunk(docId, chunk)) return chunk;\n\t\t\t}\n\t\t\tconst otherChunks = this.manifest.chunks.filter((c) => c.docType !== \"CARD\" && c.docType !== \"DISPLAYABLE_DATA\" && c.docType !== \"TAG\");\n\t\t\tfor (const chunk of otherChunks) if (docId >= chunk.startKey && docId <= chunk.endKey) {\n\t\t\t\tif (await this.verifyDocumentInChunk(docId, chunk)) return chunk;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\t/**\n\t* Verify that a document actually exists in a specific chunk by loading and checking it\n\t*/\n\tasync verifyDocumentInChunk(docId, chunk) {\n\t\ttry {\n\t\t\tawait this.loadChunk(chunk.id);\n\t\t\treturn this.documentCache.has(docId);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\t/**\n\t* Load a chunk file and cache its documents\n\t*/\n\tasync loadChunk(chunkId) {\n\t\tif (this.chunkCache.has(chunkId)) return;\n\t\tconst chunk = this.manifest.chunks.find((c) => c.id === chunkId);\n\t\tif (!chunk) throw new Error(`Chunk ${chunkId} not found in manifest`);\n\t\ttry {\n\t\t\tconst chunkPath = `${this.basePath}/${chunk.path}`;\n\t\t\tlogger.debug(`Loading chunk from ${chunkPath}`);\n\t\t\tlet documents;\n\t\t\tif (this.isLocalPath(chunkPath) && nodeFS) {\n\t\t\t\tconst fileContent = await nodeFS.promises.readFile(chunkPath, \"utf8\");\n\t\t\t\tdocuments = JSON.parse(fileContent);\n\t\t\t} else {\n\t\t\t\tconst response = await fetch(chunkPath);\n\t\t\t\tif (!response.ok) throw new Error(`Failed to fetch chunk ${chunkId}: ${response.status} ${response.statusText}`);\n\t\t\t\tdocuments = await response.json();\n\t\t\t}\n\t\t\tthis.chunkCache.set(chunkId, documents);\n\t\t\tfor (const doc of documents) if (doc._id) this.documentCache.set(doc._id, doc);\n\t\t\tlogger.debug(`Loaded ${documents.length} documents from chunk ${chunkId}`);\n\t\t} catch (error) {\n\t\t\tlogger.error(`Failed to load chunk ${chunkId}:`, error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\t/**\n\t* Load an index file and cache it\n\t*/\n\tasync loadIndex(indexName) {\n\t\tif (this.indexCache.has(indexName)) return this.indexCache.get(indexName);\n\t\tconst indexMeta = this.manifest.indices.find((idx) => idx.name === indexName);\n\t\tif (!indexMeta) throw new Error(`Index ${indexName} not found in manifest`);\n\t\ttry {\n\t\t\tconst indexPath = `${this.basePath}/${indexMeta.path}`;\n\t\t\tlogger.debug(`Loading index from ${indexPath}`);\n\t\t\tlet indexData;\n\t\t\tif (this.isLocalPath(indexPath) && nodeFS) {\n\t\t\t\tconst fileContent = await nodeFS.promises.readFile(indexPath, \"utf8\");\n\t\t\t\tindexData = JSON.parse(fileContent);\n\t\t\t} else {\n\t\t\t\tconst response = await fetch(indexPath);\n\t\t\t\tif (!response.ok) throw new Error(`Failed to fetch index ${indexName}: ${response.status} ${response.statusText}`);\n\t\t\t\tindexData = await response.json();\n\t\t\t}\n\t\t\tthis.indexCache.set(indexName, indexData);\n\t\t\tlogger.debug(`Loaded index ${indexName}`);\n\t\t\treturn indexData;\n\t\t} catch (error) {\n\t\t\tlogger.error(`Failed to load index ${indexName}:`, error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\t/**\n\t* Get a document by ID without hydration (raw document access)\n\t* Used internally to avoid recursion during attachment hydration\n\t*/\n\tasync getRawDocument(id) {\n\t\tif (this.documentCache.has(id)) return this.documentCache.get(id);\n\t\tconst chunk = await this.findChunkForDocument(id);\n\t\tif (!chunk) {\n\t\t\tlogger.error(`Document ${id} not found in any chunk. Available chunks:`, this.manifest.chunks.map((c) => `${c.id} (${c.docType}): ${c.startKey} - ${c.endKey}`));\n\t\t\tthrow new Error(`Document ${id} not found in any chunk`);\n\t\t}\n\t\tawait this.loadChunk(chunk.id);\n\t\tif (this.documentCache.has(id)) return this.documentCache.get(id);\n\t\tlogger.error(`Document ${id} not found in chunk ${chunk.id}`);\n\t\tthrow new Error(`Document ${id} not found in chunk ${chunk.id}`);\n\t}\n\t/**\n\t* Get attachment URL for a given document and attachment name\n\t*/\n\tgetAttachmentUrl(docId, attachmentName) {\n\t\treturn `${this.basePath}/attachments/${docId}/${attachmentName}`;\n\t}\n\t/**\n\t* Load attachment data from the document and get the correct file path\n\t* Uses raw document access to avoid recursion with hydration\n\t*/\n\tasync getAttachmentPath(docId, attachmentName) {\n\t\ttry {\n\t\t\tconst doc = await this.getRawDocument(docId);\n\t\t\tif (doc._attachments && doc._attachments[attachmentName]) {\n\t\t\t\tconst attachment = doc._attachments[attachmentName];\n\t\t\t\tif (attachment.path) return `${this.basePath}/${attachment.path}`;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\t/**\n\t* Load attachment as a blob (for browser) or buffer (for Node.js)\n\t*/\n\tasync getAttachmentBlob(docId, attachmentName) {\n\t\tconst attachmentPath = await this.getAttachmentPath(docId, attachmentName);\n\t\tif (!attachmentPath) return null;\n\t\ttry {\n\t\t\tif (this.isLocalPath(attachmentPath) && nodeFS) return await nodeFS.promises.readFile(attachmentPath);\n\t\t\telse {\n\t\t\t\tconst response = await fetch(attachmentPath);\n\t\t\t\tif (!response.ok) throw new Error(`Failed to fetch attachment ${docId}/${attachmentName}: ${response.status} ${response.statusText}`);\n\t\t\t\treturn await response.blob();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error(`Failed to load attachment ${docId}/${attachmentName}:`, error);\n\t\t\treturn null;\n\t\t}\n\t}\n\t/**\n\t* Hydrate document attachments by converting file paths to blob URLs\n\t*/\n\tasync hydrateAttachments(doc) {\n\t\tconst typedDoc = doc;\n\t\tif (!typedDoc._attachments) return doc;\n\t\tconst hydratedDoc = JSON.parse(JSON.stringify(doc));\n\t\tfor (const [attachmentName, attachment] of Object.entries(typedDoc._attachments)) {\n\t\t\tconst attachmentData = attachment;\n\t\t\tif (attachmentData.path) try {\n\t\t\t\tconst blob = await this.getAttachmentBlob(typedDoc._id, attachmentName);\n\t\t\t\tif (blob) if (typeof window !== \"undefined\" && window.URL) hydratedDoc._attachments[attachmentName] = {\n\t\t\t\t\t...attachmentData,\n\t\t\t\t\tdata: blob,\n\t\t\t\t\tstub: false\n\t\t\t\t};\n\t\t\t\telse hydratedDoc._attachments[attachmentName] = {\n\t\t\t\t\t...attachmentData,\n\t\t\t\t\tbuffer: blob\n\t\t\t\t};\n\t\t\t\telse logger.warn(`[hydrateAttachments] getAttachmentBlob returned null for ${typedDoc._id}/${attachmentName}. Skipping hydration for this attachment.`);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(`[hydrateAttachments] Failed to hydrate attachment ${typedDoc._id}/${attachmentName}:`, error);\n\t\t\t}\n\t\t\telse logger.debug(`[hydrateAttachments] Attachment ${attachmentName} for doc ${typedDoc._id} has no path. Skipping blob conversion.`);\n\t\t}\n\t\treturn hydratedDoc;\n\t}\n\t/**\n\t* Clear all caches (useful for testing or memory management)\n\t*/\n\tclearCaches() {\n\t\tthis.documentCache.clear();\n\t\tthis.chunkCache.clear();\n\t\tthis.indexCache.clear();\n\t}\n\t/**\n\t* Get cache statistics for debugging\n\t*/\n\tgetCacheStats() {\n\t\treturn {\n\t\t\tdocuments: this.documentCache.size,\n\t\t\tchunks: this.chunkCache.size,\n\t\t\tindices: this.indexCache.size\n\t\t};\n\t}\n\t/**\n\t* Check if a path is a local file path (vs URL)\n\t*/\n\tisLocalPath(filePath) {\n\t\treturn !filePath.startsWith(\"http://\") && !filePath.startsWith(\"https://\") && (pathUtils.isAbsolute(filePath) || filePath.startsWith(\"./\") || filePath.startsWith(\"../\"));\n\t}\n};\n//#endregion\nexport { StaticDataUnpacker };\n\n//# sourceMappingURL=StaticDataUnpacker.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { DocType, DocTypePrefixes } from \"../../core/types/types-legacy.mjs\";\nimport { createDefaultPipeline } from \"../../core/navigators/defaults.mjs\";\nimport { PipelineAssembler } from \"../../core/navigators/PipelineAssembler.mjs\";\nimport { Status } from \"@vue-skuilder/common\";\n//#region src/impl/static/courseDB.ts\nvar StaticCourseDB = class {\n\tconstructor(courseId, unpacker, userDB, manifest) {\n\t\tthis.courseId = courseId;\n\t\tthis.unpacker = unpacker;\n\t\tthis.userDB = userDB;\n\t\tthis.manifest = manifest;\n\t}\n\tgetCourseID() {\n\t\treturn this.courseId;\n\t}\n\tasync getCourseConfig() {\n\t\tif (this.manifest.courseConfig != null) return this.manifest.courseConfig;\n\t\telse throw new Error(`Course config not found for course ${this.courseId}`);\n\t}\n\tasync updateCourseConfig(_cfg) {\n\t\tthrow new Error(\"Cannot update course config in static mode\");\n\t}\n\tasync getCourseInfo() {\n\t\treturn {\n\t\t\tcardCount: this.manifest.chunks.filter((chunk) => chunk.docType === DocType.CARD).reduce((total, chunk) => total + chunk.documentCount, 0),\n\t\t\tregisteredUsers: 0\n\t\t};\n\t}\n\tasync getCourseDoc(id, _options) {\n\t\treturn this.unpacker.getDocument(id);\n\t}\n\tasync getCourseDocs(ids, _options) {\n\t\tconst rows = await Promise.all(ids.map(async (id) => {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tid,\n\t\t\t\t\tkey: id,\n\t\t\t\t\tvalue: { rev: \"1-static\" },\n\t\t\t\t\tdoc: await this.unpacker.getDocument(id)\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tkey: id,\n\t\t\t\t\terror: \"not_found\"\n\t\t\t\t};\n\t\t\t}\n\t\t}));\n\t\treturn {\n\t\t\ttotal_rows: ids.length,\n\t\t\toffset: 0,\n\t\t\trows\n\t\t};\n\t}\n\tasync getCardsByELO(elo, limit) {\n\t\treturn (await this.unpacker.queryByElo(elo, limit || 25)).map((card) => {\n\t\t\tconst [courseID, cardID, elo] = card.split(\"-\");\n\t\t\treturn {\n\t\t\t\tcourseID,\n\t\t\t\tcardID,\n\t\t\t\telo: elo ? parseInt(elo) : void 0\n\t\t\t};\n\t\t});\n\t}\n\tasync getCardEloData(cardIds) {\n\t\treturn await Promise.all(cardIds.map(async (id) => {\n\t\t\ttry {\n\t\t\t\treturn (await this.unpacker.getDocument(id)).elo || {\n\t\t\t\t\tglobal: {\n\t\t\t\t\t\tscore: 1e3,\n\t\t\t\t\t\tcount: 0\n\t\t\t\t\t},\n\t\t\t\t\ttags: {},\n\t\t\t\t\tmisc: {}\n\t\t\t\t};\n\t\t\t} catch {\n\t\t\t\treturn {\n\t\t\t\t\tglobal: {\n\t\t\t\t\t\tscore: 1e3,\n\t\t\t\t\t\tcount: 0\n\t\t\t\t\t},\n\t\t\t\t\ttags: {},\n\t\t\t\t\tmisc: {}\n\t\t\t\t};\n\t\t\t}\n\t\t}));\n\t}\n\tasync updateCardElo(cardId, _elo) {\n\t\treturn {\n\t\t\tok: true,\n\t\t\tid: cardId,\n\t\t\trev: \"1-static\"\n\t\t};\n\t}\n\tasync getCardsCenteredAtELO(options, filter) {\n\t\tlet targetElo = typeof options.elo === \"number\" ? options.elo : 1e3;\n\t\tif (options.elo === \"user\") try {\n\t\t\tconst courseReg = (await this.userDB.getCourseRegistrationsDoc()).courses.find((c) => c.courseID === this.courseId);\n\t\t\tif (courseReg && typeof courseReg.elo === \"object\") targetElo = courseReg.elo.global.score;\n\t\t} catch {\n\t\t\ttargetElo = 1e3;\n\t\t}\n\t\telse if (options.elo === \"random\") targetElo = 800 + Math.random() * 400;\n\t\tlet cardIds = (await this.unpacker.queryByElo(targetElo, options.limit * 2)).map((c) => {\n\t\t\treturn {\n\t\t\t\tcardID: c,\n\t\t\t\tcourseID: this.courseId\n\t\t\t};\n\t\t});\n\t\tif (filter) cardIds = cardIds.filter(filter);\n\t\treturn cardIds.slice(0, options.limit).map((card) => ({\n\t\t\tstatus: \"new\",\n\t\t\tcardID: card.cardID,\n\t\t\tcontentSourceType: \"course\",\n\t\t\tcontentSourceID: this.courseId,\n\t\t\tcourseID: this.courseId\n\t\t}));\n\t}\n\tasync getAppliedTags(cardId) {\n\t\ttry {\n\t\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\t\tconst cardTags = tagsIndex.byCard[cardId] || [];\n\t\t\tconst rows = await Promise.all(cardTags.map(async (tagName) => {\n\t\t\t\tconst tagId = `${DocType.TAG}-${tagName}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst tagDoc = await this.unpacker.getDocument(tagId);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\tkey: cardId,\n\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\tname: tagDoc.name,\n\t\t\t\t\t\t\tsnippet: tagDoc.snippet,\n\t\t\t\t\t\t\tcount: tagDoc.taggedCards?.length || 0\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error && error.status === 404) logger.warn(`Tag document not found for ${tagName}, creating stub`);\n\t\t\t\t\telse {\n\t\t\t\t\t\tlogger.error(`Error getting tag document for ${tagName}:`, error);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\tkey: cardId,\n\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\tname: tagName,\n\t\t\t\t\t\t\tsnippet: `Tag: ${tagName}`,\n\t\t\t\t\t\t\tcount: tagsIndex.byTag[tagName]?.length || 0\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}));\n\t\t\treturn {\n\t\t\t\ttotal_rows: rows.length,\n\t\t\t\toffset: 0,\n\t\t\t\trows\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tlogger.error(`Error getting applied tags for card ${cardId}:`, error);\n\t\t\treturn {\n\t\t\t\ttotal_rows: 0,\n\t\t\t\toffset: 0,\n\t\t\t\trows: []\n\t\t\t};\n\t\t}\n\t}\n\tasync getAppliedTagsBatch(cardIds) {\n\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\tconst tagsByCard = /* @__PURE__ */ new Map();\n\t\tfor (const cardId of cardIds) tagsByCard.set(cardId, tagsIndex.byCard[cardId] || []);\n\t\treturn tagsByCard;\n\t}\n\tasync getAllCardIds() {\n\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\treturn Object.keys(tagsIndex.byCard);\n\t}\n\tasync addTagToCard(_cardId, _tagId) {\n\t\tthrow new Error(\"Cannot modify tags in static mode\");\n\t}\n\tasync removeTagFromCard(_cardId, _tagId) {\n\t\tthrow new Error(\"Cannot modify tags in static mode\");\n\t}\n\tasync createTag(_tagName) {\n\t\tthrow new Error(\"Cannot create tags in static mode\");\n\t}\n\tasync getTag(tagName) {\n\t\treturn this.unpacker.getDocument(`${DocType.TAG}-${tagName}`);\n\t}\n\tasync updateTag(_tag) {\n\t\tthrow new Error(\"Cannot update tags in static mode\");\n\t}\n\tasync getCourseTagStubs() {\n\t\ttry {\n\t\t\tconst tagsIndex = await this.unpacker.getTagsIndex();\n\t\t\tif (!tagsIndex || !tagsIndex.byTag) {\n\t\t\t\tlogger.warn(\"Tags index not found or empty\");\n\t\t\t\treturn {\n\t\t\t\t\ttotal_rows: 0,\n\t\t\t\t\toffset: 0,\n\t\t\t\t\trows: []\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst tagNames = Object.keys(tagsIndex.byTag);\n\t\t\tconst rows = await Promise.all(tagNames.map(async (tagName) => {\n\t\t\t\tconst cardIds = tagsIndex.byTag[tagName] || [];\n\t\t\t\tconst tagId = `${DocType.TAG}-${tagName}`;\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\tkey: tagId,\n\t\t\t\t\t\tvalue: { rev: \"1-static\" },\n\t\t\t\t\t\tdoc: await this.unpacker.getDocument(tagId)\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error && error.status === 404) {\n\t\t\t\t\t\tlogger.warn(`Tag document not found for ${tagName}, creating stub`);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tid: tagId,\n\t\t\t\t\t\t\tkey: tagId,\n\t\t\t\t\t\t\tvalue: { rev: \"1-static\" },\n\t\t\t\t\t\t\tdoc: {\n\t\t\t\t\t\t\t\t_id: tagId,\n\t\t\t\t\t\t\t\t_rev: \"1-static\",\n\t\t\t\t\t\t\t\tcourse: this.courseId,\n\t\t\t\t\t\t\t\tdocType: DocType.TAG,\n\t\t\t\t\t\t\t\tname: tagName,\n\t\t\t\t\t\t\t\tsnippet: `Tag: ${tagName}`,\n\t\t\t\t\t\t\t\twiki: \"\",\n\t\t\t\t\t\t\t\ttaggedCards: cardIds,\n\t\t\t\t\t\t\t\tauthor: \"system\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.error(`Error getting tag document for ${tagName}:`, error);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}));\n\t\t\treturn {\n\t\t\t\ttotal_rows: rows.length,\n\t\t\t\toffset: 0,\n\t\t\t\trows\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tlogger.error(\"Failed to get course tag stubs:\", error);\n\t\t\treturn {\n\t\t\t\ttotal_rows: 0,\n\t\t\t\toffset: 0,\n\t\t\t\trows: []\n\t\t\t};\n\t\t}\n\t}\n\tasync addNote(_codeCourse, _shape, _data, _author, _tags, _uploads, _elo) {\n\t\treturn {\n\t\t\tstatus: Status.error,\n\t\t\tmessage: \"Cannot add notes in static mode\"\n\t\t};\n\t}\n\tasync removeCard(_cardId) {\n\t\tthrow new Error(\"Cannot remove cards in static mode\");\n\t}\n\tasync getInexperiencedCards() {\n\t\treturn [];\n\t}\n\tasync getNavigationStrategy(id) {\n\t\ttry {\n\t\t\treturn await this.unpacker.getDocument(id);\n\t\t} catch (error) {\n\t\t\tlogger.error(`[static/courseDB] Strategy ${id} not found: ${error}`);\n\t\t\tthrow error;\n\t\t}\n\t}\n\tasync getAllNavigationStrategies() {\n\t\tconst prefix = DocTypePrefixes[DocType.NAVIGATION_STRATEGY];\n\t\ttry {\n\t\t\treturn await this.unpacker.getAllDocumentsByPrefix(prefix);\n\t\t} catch (error) {\n\t\t\tlogger.warn(`[static/courseDB] Error loading navigation strategies: ${error}`);\n\t\t\treturn [];\n\t\t}\n\t}\n\tasync addNavigationStrategy(_data) {\n\t\tthrow new Error(\"Cannot add navigation strategies in static mode\");\n\t}\n\tasync updateNavigationStrategy(_id, _data) {\n\t\tthrow new Error(\"Cannot update navigation strategies in static mode\");\n\t}\n\t/**\n\t* Create a ContentNavigator for this course.\n\t*\n\t* Loads navigation strategy documents from static data and uses PipelineAssembler\n\t* to build a Pipeline. Falls back to default pipeline if no strategies found.\n\t*/\n\tasync createNavigator(user) {\n\t\ttry {\n\t\t\tconst allStrategies = await this.getAllNavigationStrategies();\n\t\t\tif (allStrategies.length === 0) {\n\t\t\t\tlogger.debug(\"[static/courseDB] No strategy documents found, using default Pipeline(Composite(ELO, SRS), [eloDistanceFilter])\");\n\t\t\t\treturn createDefaultPipeline(user, this);\n\t\t\t}\n\t\t\tconst { pipeline, generatorStrategies, filterStrategies, warnings } = await new PipelineAssembler().assemble({\n\t\t\t\tstrategies: allStrategies,\n\t\t\t\tuser,\n\t\t\t\tcourse: this\n\t\t\t});\n\t\t\tfor (const warning of warnings) logger.warn(`[PipelineAssembler] ${warning}`);\n\t\t\tif (!pipeline) {\n\t\t\t\tlogger.debug(\"[static/courseDB] Pipeline assembly failed, using default pipeline\");\n\t\t\t\treturn createDefaultPipeline(user, this);\n\t\t\t}\n\t\t\tlogger.debug(`[static/courseDB] Using assembled pipeline with ${generatorStrategies.length} generator(s) and ${filterStrategies.length} filter(s)`);\n\t\t\treturn pipeline;\n\t\t} catch (e) {\n\t\t\tlogger.error(`[static/courseDB] Error creating navigator: ${e}`);\n\t\t\tthrow e;\n\t\t}\n\t}\n\t_pendingHints = null;\n\tsetEphemeralHints(hints) {\n\t\tthis._pendingHints = hints;\n\t}\n\t/** Forward a presentation to the navigator (a new card restarts its intake clock). */\n\tnotePresented(card) {\n\t\tif (card.status !== \"new\") return;\n\t\tthis.createNavigator(this.userDB).then((navigator) => navigator.notePresented?.(card)).catch((e) => logger.warn(`[static/courseDB] Could not note a presentation: ${e}`));\n\t}\n\tasync getWeightedCards(limit) {\n\t\ttry {\n\t\t\tconst navigator = await this.createNavigator(this.userDB);\n\t\t\tif (this._pendingHints) {\n\t\t\t\tnavigator.setEphemeralHints(this._pendingHints);\n\t\t\t\tthis._pendingHints = null;\n\t\t\t}\n\t\t\treturn navigator.getWeightedCards(limit);\n\t\t} catch (e) {\n\t\t\tlogger.error(`[static/courseDB] Error getting weighted cards: ${e}`);\n\t\t\tthrow e;\n\t\t}\n\t}\n\t/**\n\t* Get attachment URL for a document and attachment name\n\t* Internal helper method for static attachment serving\n\t*/\n\tgetAttachmentUrl(docId, attachmentName) {\n\t\treturn this.unpacker.getAttachmentUrl(docId, attachmentName);\n\t}\n\t/**\n\t* Load attachment as blob/buffer\n\t* Internal helper method for static attachment serving\n\t*/\n\tasync getAttachmentBlob(docId, attachmentName) {\n\t\treturn this.unpacker.getAttachmentBlob(docId, attachmentName);\n\t}\n\tasync searchCards(_query) {\n\t\treturn [];\n\t}\n\tasync find(_request) {\n\t\treturn {\n\t\t\tdocs: [],\n\t\t\twarning: \"Find operations not supported in static mode\"\n\t\t};\n\t}\n};\n//#endregion\nexport { StaticCourseDB };\n\n//# sourceMappingURL=courseDB.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\n//#region src/impl/static/coursesDB.ts\nvar StaticCoursesDB = class {\n\tconstructor(manifests, dependencyNameToCourseId) {\n\t\tthis.manifests = manifests;\n\t\tthis.dependencyNameToCourseId = dependencyNameToCourseId;\n\t}\n\tasync getCourseConfig(courseId) {\n\t\tlet manifest = this.manifests[courseId];\n\t\tif (!manifest && this.dependencyNameToCourseId) {\n\t\t\tconst mappedCourseId = this.dependencyNameToCourseId.get(courseId);\n\t\t\tif (mappedCourseId) manifest = this.manifests[mappedCourseId];\n\t\t}\n\t\tif (!manifest) {\n\t\t\tlogger.warn(`Course manifest for ${courseId} not found`);\n\t\t\tthrow new Error(`Course ${courseId} not found`);\n\t\t}\n\t\tif (manifest.courseConfig) return manifest.courseConfig;\n\t\telse {\n\t\t\tlogger.warn(`Course config not found in manifest for course ${courseId}`);\n\t\t\tthrow new Error(`Course config not found for course ${courseId}`);\n\t\t}\n\t}\n\tasync getCourseList() {\n\t\treturn Object.keys(this.manifests).map((courseId) => ({\n\t\t\tcourseID: courseId,\n\t\t\tname: this.manifests[courseId].courseName\n\t\t}));\n\t}\n\tasync disambiguateCourse(_courseId, _disambiguator) {\n\t\tlogger.warn(\"Cannot disambiguate courses in static mode\");\n\t}\n};\n//#endregion\nexport { StaticCoursesDB };\n\n//# sourceMappingURL=coursesDB.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { getLocalUserDB } from \"../common/userDBHelpers.mjs\";\nimport { accomodateGuest } from \"../common/BaseUserDB.mjs\";\n//#region src/impl/static/NoOpSyncStrategy.ts\n/**\n* Sync strategy for static deployments that provides no-op implementations\n* for remote operations. Uses only local storage with no remote synchronization.\n*/\nvar NoOpSyncStrategy = class {\n\tcurrentUsername = accomodateGuest().username;\n\tsetupRemoteDB(username) {\n\t\treturn getLocalUserDB(username);\n\t}\n\tgetWriteDB(username) {\n\t\treturn getLocalUserDB(username);\n\t}\n\tstartSync(_localDB, _remoteDB) {}\n\tstopSync() {}\n\tcanCreateAccount() {\n\t\treturn false;\n\t}\n\tcanAuthenticate() {\n\t\treturn false;\n\t}\n\tasync createAccount(_username, _password) {\n\t\tthrow new Error(\"Account creation not supported in static mode. Use local account switching instead.\");\n\t}\n\tasync authenticate(_username, _password) {\n\t\tthrow new Error(\"Remote authentication not supported in static mode. Use local account switching instead.\");\n\t}\n\tasync logout() {\n\t\tthis.currentUsername = accomodateGuest().username;\n\t\treturn { ok: true };\n\t}\n\tasync getCurrentUsername() {\n\t\treturn this.currentUsername;\n\t}\n\t/**\n\t* Set the current username (for local account switching)\n\t* This method is specific to NoOpSyncStrategy and not part of the base interface\n\t*/\n\tsetCurrentUsername(username) {\n\t\tthis.currentUsername = username;\n\t}\n};\n//#endregion\nexport { NoOpSyncStrategy };\n\n//# sourceMappingURL=NoOpSyncStrategy.mjs.map","import \"../../_virtual/_rolldown/runtime.mjs\";\nimport { logger } from \"../../util/logger.mjs\";\nimport { BaseUser } from \"../common/BaseUserDB.mjs\";\nimport { StaticDataUnpacker } from \"./StaticDataUnpacker.mjs\";\nimport { StaticCourseDB } from \"./courseDB.mjs\";\nimport { StaticCoursesDB } from \"./coursesDB.mjs\";\nimport { NoOpSyncStrategy } from \"./NoOpSyncStrategy.mjs\";\n//#region src/impl/static/StaticDataLayerProvider.ts\nvar StaticDataLayerProvider = class {\n\tconfig;\n\tinitialized = false;\n\tcourseUnpackers = /* @__PURE__ */ new Map();\n\tmanifests = {};\n\tdependencyNameToCourseId = /* @__PURE__ */ new Map();\n\tconstructor(config) {\n\t\tthis.config = {\n\t\t\tlocalStoragePrefix: config.localStoragePrefix || \"skuilder-static\",\n\t\t\trootManifest: config.rootManifest || { dependencies: {} },\n\t\t\trootManifestUrl: config.rootManifestUrl || \"/\"\n\t\t};\n\t}\n\tasync resolveCourseDependencies() {\n\t\tlogger.info(\"[StaticDataLayerProvider] Starting course dependency resolution...\");\n\t\tconst rootManifest = this.config.rootManifest;\n\t\tfor (const [courseName, courseUrl] of Object.entries(rootManifest.dependencies || {})) try {\n\t\t\tlogger.debug(`[StaticDataLayerProvider] Resolving dependency: ${courseName} from ${courseUrl}`);\n\t\t\tconst courseManifestUrl = new URL(courseUrl, this.config.rootManifestUrl).href;\n\t\t\tconst courseJsonResponse = await fetch(courseManifestUrl);\n\t\t\tif (!courseJsonResponse.ok) throw new Error(`Failed to fetch course manifest for ${courseName}`);\n\t\t\tconst courseJson = await courseJsonResponse.json();\n\t\t\tif (courseJson.content && courseJson.content.manifest) {\n\t\t\t\tconst baseUrl = new URL(\".\", courseManifestUrl).href;\n\t\t\t\tconst finalManifestUrl = new URL(courseJson.content.manifest, courseManifestUrl).href;\n\t\t\t\tconst finalManifestResponse = await fetch(finalManifestUrl);\n\t\t\t\tif (!finalManifestResponse.ok) throw new Error(`Failed to fetch final content manifest for ${courseName} at ${finalManifestUrl}`);\n\t\t\t\tconst finalManifest = await finalManifestResponse.json();\n\t\t\t\tconst courseId = finalManifest.courseId || finalManifest.courseConfig?.courseID;\n\t\t\t\tif (!courseId) throw new Error(`Course manifest for ${courseName} missing courseId`);\n\t\t\t\tthis.manifests[courseId] = finalManifest;\n\t\t\t\tconst unpacker = new StaticDataUnpacker(finalManifest, baseUrl);\n\t\t\t\tthis.courseUnpackers.set(courseId, unpacker);\n\t\t\t\tthis.dependencyNameToCourseId.set(courseName, courseId);\n\t\t\t\tlogger.info(`[StaticDataLayerProvider] Successfully resolved and prepared course: ${courseName} (courseId: ${courseId})`);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tlogger.error(`[StaticDataLayerProvider] Failed to resolve dependency ${courseName}:`, e);\n\t\t}\n\t\tlogger.info(\"[StaticDataLayerProvider] Course dependency resolution complete.\");\n\t}\n\tasync initialize() {\n\t\tif (this.initialized) return;\n\t\tlogger.info(\"Initializing static data layer provider\");\n\t\tawait this.resolveCourseDependencies();\n\t\tthis.initialized = true;\n\t}\n\tasync teardown() {\n\t\tthis.courseUnpackers.clear();\n\t\tthis.initialized = false;\n\t}\n\tgetUserDB() {\n\t\tconst syncStrategy = new NoOpSyncStrategy();\n\t\treturn BaseUser.Dummy(syncStrategy);\n\t}\n\tgetCourseDB(courseId) {\n\t\tlet unpacker = this.courseUnpackers.get(courseId);\n\t\tlet actualCourseId = courseId;\n\t\tif (!unpacker) {\n\t\t\tconst mappedCourseId = this.dependencyNameToCourseId.get(courseId);\n\t\t\tif (mappedCourseId) {\n\t\t\t\tunpacker = this.courseUnpackers.get(mappedCourseId);\n\t\t\t\tactualCourseId = mappedCourseId;\n\t\t\t}\n\t\t}\n\t\tif (!unpacker) throw new Error(`Course ${courseId} not found or failed to initialize in static data layer.`);\n\t\tconst manifest = this.manifests[actualCourseId];\n\t\treturn new StaticCourseDB(actualCourseId, unpacker, this.getUserDB(), manifest);\n\t}\n\tgetCoursesDB() {\n\t\treturn new StaticCoursesDB(this.manifests, this.dependencyNameToCourseId);\n\t}\n\tasync getClassroomDB(_classId, _type) {\n\t\tthrow new Error(\"Classrooms not supported in static mode\");\n\t}\n\tgetAdminDB() {\n\t\tthrow new Error(\"Admin functions not supported in static mode\");\n\t}\n\tisReadOnly() {\n\t\treturn true;\n\t}\n};\n//#endregion\nexport { StaticDataLayerProvider };\n\n//# sourceMappingURL=StaticDataLayerProvider.mjs.map"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{i as e}from"./chunk-D6hFPZc3.js";import{$ as t,C as n,H as r,Ht as i,K as a,Lt as o,S as s,T as c,W as l,_ as u,b as d,f,v as p,y as m}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import{w as h}from"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import{B as g,C as _,g as v,h as y,n as b}from"./dist-BsRvt0gH.js";import{V as x}from"./contentSource-DwznMSMs.js";import{h as S}from"./edit-ui.es-UaQFL_My.js";import"./dist-Dp6eBE2S.js";import"./CourseWare-BTFRjgBR-DBp_fIwH.js";import"./PipelineDebugger-BHaqzqZw.js";import{d as C}from"./userDBKeys-DYLGKnVC.js";import"./eloDistance-BV7vfiK5.js";import{t as w}from"./index-CK-rfSIx.js";import"./chess-E2uOAyQS-BZi0vihz.js";import"./math-D_8HiEQR-E4QDLrWp.js";import"./piano-DF1g6yaX-Ck3BH5EK.js";import"./sightsing-BFQ7HRig-DV69ELZf.js";import"./typing-BevtfWlp-CvStu5BY.js";import{t as T}from"./dist-CAHkbl3M.js";var E=c({name:`SessionConfiguration`,components:{SkMouseTrapToolTip:g,CourseTagFilterWidget:b},props:{initialTimeLimit:{type:Number,required:!0,default:5}},emits:[`initStudySession`],data(){return{registeredHotkeys:[],allSelected:!0,activeCourses:[],activeClasses:[],hasRegistrations:!0,user:null,timeLimit:this.initialTimeLimit,courseLoadError:!1,classroomLoadError:!1,expandedFilters:{}}},computed:{hasSelectedSources(){return this.activeCourses.some(e=>e.selected)||this.activeClasses.some(e=>e.selected)},hasAnyActiveFilter(){return this.activeCourses.some(e=>e.selected&&this.hasActiveTagFilter(e))},activeFilterCount(){return this.activeCourses.filter(e=>e.selected&&this.hasActiveTagFilter(e)).length}},watch:{timeLimit:{handler(){this.timeLimit<=0&&(this.timeLimit=1)}}},beforeUnmount(){this.registeredHotkeys&&this.registeredHotkeys.forEach(e=>{h.removeBinding(e)})},async created(){this.user=await v(),this.timeLimit=this.initialTimeLimit,this.setHotkeys();let[e,t]=await Promise.allSettled([this.getActiveCourses(),this.getActiveClassrooms()]);e.status===`rejected`&&(console.error(`Failed to load courses:`,e.reason),this.courseLoadError=!0),t.status===`rejected`&&(console.error(`Failed to load classrooms:`,t.reason),this.classroomLoadError=!0),this.activeCourses.length===0&&this.activeClasses.length===0&&!this.courseLoadError&&!this.classroomLoadError&&(this.hasRegistrations=!1)},mounted(){document.getElementById(`SelectAll`)?.focus()},unmounted(){this.registeredHotkeys&&this.registeredHotkeys.forEach(e=>{h.removeBinding(e)})},methods:{inc(){this.timeLimit+=1,console.log(`inc to ${this.timeLimit}`)},dec(){this.timeLimit--,console.log(`dec to ${this.timeLimit}`)},update(){console.log(JSON.stringify(this.activeCourses)),console.log(JSON.stringify(this.activeClasses))},toggleAll(){console.log(`Toggling all courses`),this.activeCourses.forEach(e=>{e.selected=this.allSelected}),this.activeClasses.forEach(e=>{e.selected=this.allSelected}),console.log(JSON.stringify(this.activeCourses))},toggleTagFilter(e){this.expandedFilters[e]=!this.expandedFilters[e]},hasActiveTagFilter(e){return x(e.tagFilter)},startSession(){this.registeredHotkeys&&this.registeredHotkeys.forEach(e=>{h.removeBinding(e)});let e=this.activeCourses.filter(e=>e.selected).map(e=>{let t={type:`course`,id:e.courseID};return x(e.tagFilter)&&(t.tagFilter=e.tagFilter),t}),t=this.activeClasses.filter(e=>e.selected).map(e=>({type:`classroom`,id:e.classID})),n=[...e,...t];this.$emit(`initStudySession`,n,this.timeLimit)},async getActiveClassrooms(){let e=await(await v()).getActiveClasses(),t=[];console.log(`Active classes: ${JSON.stringify(e)}`),await Promise.all(e.map(e=>(async e=>{let n=await C().getClassroomDB(e,`student`);t.push({classID:e,name:n.getConfig().name,selected:!0,reviews:0})})(e))),this.activeClasses=t},async getActiveCourses(){this.activeCourses=(await this.user.getActiveCourses()).map(e=>({...e,selected:!0,name:``,reviews:0,tagFilter:void 0})),Promise.all(this.activeCourses.map(async(e,t)=>{let n=await C().getCoursesDB().getCourseConfig(e.courseID),r=await this.user?.getCourseInterface(e.courseID);return(async()=>Promise.all([this.activeCourses[t].name=n.name,this.activeCourses[t].reviews=await r.getScheduledReviewCount()]))()}))},setHotkeys(){let e=[{hotkey:`right`,callback:()=>{this.timeLimit++},command:`Increase time limit`},{hotkey:`left`,callback:()=>{this.timeLimit--},command:`Decrease time limit`}];h.addBinding(e),this.registeredHotkeys=e.map(e=>e.hotkey)}}}),D={key:0},O={class:`session-layout`},k={class:`course-selection-container`},A={class:`course-row-header`},j={class:`course-row-header`},M={class:`course-row-actions`},N={class:`reviews-count`},P={key:0,class:`tag-filter-container`},F={class:`select-all-row mt-3`},I={class:`fixed-controls-container`},L={class:`fixed-controls`},R={class:`mb-5`},z={key:0,class:`filter-summary mb-4`},B={class:`text-caption`},V={key:1,class:`text-h4`},H={key:2,class:`text-h4`};function _sfc_render$1(e,o,c,h,g,_){let v=a(`v-alert`),y=a(`v-checkbox`),b=a(`v-icon`),x=a(`v-btn`),S=a(`CourseTagFilterWidget`),C=a(`v-expand-transition`),w=a(`v-text-field`),T=a(`SkMouseTrapToolTip`),E=a(`router-link`);return e.hasRegistrations||e.courseLoadError||e.classroomLoadError?(r(),d(`div`,D,[o[11]||(o[11]=u(`div`,{"data-cy":`select-quilts-header`,class:`text-h4 mb-4`},`Study Session Setup`,-1)),e.courseLoadError?(r(),p(v,{key:0,type:`warning`,class:`mb-4`},{default:t(()=>o[2]||(o[2]=[s(` Unable to load course data. Some features may be unavailable. `)])),_:1})):m(``,!0),e.classroomLoadError?(r(),p(v,{key:1,type:`warning`,class:`mb-4`},{default:t(()=>o[3]||(o[3]=[s(` Unable to load classroom data. You can still study individual courses. `)])),_:1})):m(``,!0),u(`div`,O,[u(`div`,k,[o[6]||(o[6]=u(`div`,{class:`text-h6 mb-3`},`Select Quilts to Study`,-1)),(r(!0),d(f,null,l(e.activeClasses,t=>(r(),d(`div`,{key:t.classID,class:`course-row`},[u(`div`,A,[n(y,{modelValue:t.selected,"onUpdate:modelValue":e=>t.selected=e,label:`Class: ${t.name}`,"hide-details":``,onClickCapture:e.update},null,8,[`modelValue`,`onUpdate:modelValue`,`label`,`onClickCapture`]),o[4]||(o[4]=u(`span`,{class:`reviews-count`},`-`,-1))])]))),128)),(r(!0),d(f,null,l(e.activeCourses,a=>(r(),d(`div`,{key:a.courseID,class:`course-row`},[u(`div`,j,[n(y,{modelValue:a.selected,"onUpdate:modelValue":e=>a.selected=e,"data-cy":`course-checkbox`,label:`q/${a.name}`,"hide-details":``,onClickCapture:e.update},null,8,[`modelValue`,`onUpdate:modelValue`,`label`,`onClickCapture`]),u(`div`,M,[u(`span`,N,i(a.reviews),1),a.selected?(r(),p(x,{key:0,variant:`text`,size:`small`,color:e.hasActiveTagFilter(a)?`primary`:`default`,onClick:t=>e.toggleTagFilter(a.courseID)},{default:t(()=>[n(b,{start:``,size:`small`},{default:t(()=>o[5]||(o[5]=[s(`mdi-filter-variant`)])),_:1}),s(` `+i(e.hasActiveTagFilter(a)?`Filtered`:`Filter`)+` `,1),n(b,{end:``,size:`small`},{default:t(()=>[s(i(e.expandedFilters[a.courseID]?`mdi-chevron-up`:`mdi-chevron-down`),1)]),_:2},1024)]),_:2},1032,[`color`,`onClick`])):m(``,!0)])]),n(C,null,{default:t(()=>[a.selected&&e.expandedFilters[a.courseID]?(r(),d(`div`,P,[n(S,{modelValue:a.tagFilter,"onUpdate:modelValue":e=>a.tagFilter=e,"course-id":a.courseID},null,8,[`modelValue`,`onUpdate:modelValue`,`course-id`])])):m(``,!0)]),_:2},1024)]))),128)),u(`div`,F,[n(y,{id:`SelectAll`,ref:`selectAll`,modelValue:e.allSelected,"onUpdate:modelValue":[o[0]||(o[0]=t=>e.allSelected=t),e.toggleAll],autofocus:``,label:`Select All`,"hide-details":``},null,8,[`modelValue`,`onUpdate:modelValue`])])]),u(`div`,I,[u(`div`,L,[o[10]||(o[10]=u(`div`,{class:`text-h6 mb-3`},`Session Settings`,-1)),u(`div`,R,[n(w,{ref:`numberField`,modelValue:e.timeLimit,"onUpdate:modelValue":o[1]||(o[1]=t=>e.timeLimit=t),class:`time-limit-field`,variant:`outlined`,label:`Study Session Timelimit`,"prepend-inner-icon":`mdi-clock-outline`,"prepend-icon":`mdi-minus`,"append-icon":`mdi-plus`,suffix:e.timeLimit>1?`minutes`:`minute`,mask:`##`,type:`number`,"onClick:prepend":e.dec,"onClick:append":e.inc},null,8,[`modelValue`,`suffix`,`onClick:prepend`,`onClick:append`])]),e.hasAnyActiveFilter?(r(),d(`div`,z,[n(b,{size:`small`,color:`primary`,class:`mr-1`},{default:t(()=>o[7]||(o[7]=[s(`mdi-filter`)])),_:1}),u(`span`,B,i(e.activeFilterCount)+` course`+i(e.activeFilterCount>1?`s`:``)+` with tag filters `,1)])):m(``,!0),n(T,{hotkey:`enter`,command:`Start Session`,disabled:!e.hasSelectedSources,"highlight-effect":`scale`},{default:t(()=>[n(x,{"data-cy":`start-studying-button`,color:`success`,size:`large`,block:``,class:`start-btn`,disabled:!e.hasSelectedSources,onClick:e.startSession},{default:t(()=>[n(b,{start:``},{default:t(()=>o[8]||(o[8]=[s(`mdi-play`)])),_:1}),o[9]||(o[9]=s(` Start! `))]),_:1},8,[`disabled`,`onClick`])]),_:1},8,[`disabled`])])])])])):!e.courseLoadError&&!e.classroomLoadError?(r(),d(`div`,V,[o[15]||(o[15]=u(`p`,null,`You don't have anything to study!`,-1)),u(`p`,null,[o[13]||(o[13]=s(`Head over to the `)),n(E,{to:`/quilts`},{default:t(()=>o[12]||(o[12]=[s(`Quilts`)])),_:1}),o[14]||(o[14]=s(` page to find something for you.`))])])):(r(),d(`div`,H,o[16]||(o[16]=[u(`p`,null,`Unable to load study data due to technical issues.`,-1),u(`p`,null,`Please try refreshing the page or contact support if the problem persists.`,-1)])))}e(_sfc_render$1,`_sfc_render`);var U=w(E,[[`render`,_sfc_render$1],[`__scopeId`,`data-v-c5ff4b5f`]]);function randomInt(e,t){return Math.floor(Math.random()*(t-e+1))+e}var W=c({name:`StudyView`,components:{SessionConfiguration:U,StudySession:_},inject:{router:{from:`router`}},props:{previewCourseID:{type:String,required:!1,default:``},randomPreview:{type:Boolean,required:!1},focusCourseID:{type:String,required:!1,default:``}},data(){return{user:null,studySessionConfig:void 0,previewCourseConfig:void 0,previewMode:!1,sessionTimeLimit:5,inSession:!1,sessionPrepared:!1,sessionError:!1,errorMessage:``,sessionContentSources:[],dataInputFormStore:S(),getViewComponent:e=>T.getView(e),dataLayer:C()}},async created(){this.user=await v(),this.studySessionConfig={likesConfetti:y().config.likesConfetti};let e=``;if(this.randomPreview){let t=await this.user.getCourseRegistrationsDoc(),n=(await C().getCoursesDB().getCourseList()).map(e=>e.courseID),r=n.filter(e=>!t.courses.some(t=>t.courseID===e));e=r.length>0?r[randomInt(0,r.length)]:n[randomInt(0,n.length)]}if(this.previewCourseID&&(this.previewMode=!0,C().getCoursesDB().getCourseList().then(e=>{e.forEach(e=>{e.courseID===this.previewCourseID&&(this.previewCourseConfig=e,this.previewCourseConfig.courseID=e.courseID)})}),console.log(`[Study] COURSE PREVIEW MODE FOR ${this.previewCourseID}`),await this.user.registerForCourse(this.previewCourseID,!0),e=this.previewCourseID),this.focusCourseID&&(console.log(`[Study] FOCUS study session: ${this.focusCourseID}`),e=this.focusCourseID),e){let t=this.parseTagFilterFromQuery(),n={type:`course`,id:e};x(t)&&(n.tagFilter=t,console.log(`[Study] Tag filter from query params:`,t)),this.initStudySession([n],this.sessionTimeLimit)}},methods:{refreshRoute(){this.router.go(0)},async initStudySession(e,t){console.log(`[Study] starting study session w/ sources: ${JSON.stringify(e)}`),this.sessionContentSources=e,this.sessionTimeLimit=t,this.inSession=!0,this.sessionPrepared=!1,console.log(`[Study] Waiting for session-prepared event from StudySession component`)},registerUserForPreviewCourse(){this.user.registerForCourse(this.previewCourseConfig.courseID).then(()=>this.router.push(`/quilts/${this.previewCourseConfig.courseID}`))},handleSessionFinished(){this.refreshRoute()},handleSessionPrepared(){console.log(`[Study] Session preparation complete - received session-prepared event`),this.sessionPrepared=!0,this.sessionError=!1,this.errorMessage=``},handleSessionError({message:e,error:t}){console.error(`[Study] Session error:`,e,t),this.sessionError=!0,this.errorMessage=e||`An error occurred while preparing your study session.`,this.sessionPrepared=!1},parseTagFilterFromQuery(){let e=this.$route.query.include,t=this.$route.query.exclude,parseParam=e=>e?Array.isArray(e)?e.flatMap(e=>e?e.split(`,`).map(e=>e.trim()):[]).filter(Boolean):e.split(`,`).map(e=>e.trim()).filter(Boolean):[];return{include:parseParam(e),exclude:parseParam(t)}}}}),G={key:0},K={key:1},q={key:0,align:`center`},J={class:`text-h5`},Y={key:1},X={key:2},Z={key:0,class:`session-loading`},Q={key:1,class:`session-error`},$={class:`text-subtitle-1 mt-2`};function _sfc_render(e,c,l,f,p,h){let g=a(`SessionConfiguration`),_=a(`v-btn`),v=a(`router-link`),y=a(`v-spacer`),b=a(`v-col`),x=a(`v-row`),S=a(`v-progress-circular`),C=a(`v-container`),w=a(`v-icon`),T=a(`StudySession`);return e.inSession?(r(),d(`div`,K,[e.previewMode&&e.previewCourseConfig?(r(),d(`div`,q,[n(x,null,{default:t(()=>[n(b,null,{default:t(()=>[u(`span`,J,[c[1]||(c[1]=s(` Quilt preview for `)),u(`em`,null,i(e.previewCourseConfig.name),1)]),n(_,{size:`small`,color:`primary`,onClick:e.registerUserForPreviewCourse},{default:t(()=>c[2]||(c[2]=[s(`Join`)])),_:1},8,[`onClick`]),n(v,{to:`/quilts/${e.previewCourseConfig.courseID}`},{default:t(()=>[n(_,{size:`small`,color:`secondary`},{default:t(()=>c[3]||(c[3]=[s(`More info`)])),_:1})]),_:1},8,[`to`]),n(y)]),_:1})]),_:1})])):e.previewMode?(r(),d(`div`,Y,[n(x,null,{default:t(()=>[n(b,null,{default:t(()=>c[4]||(c[4]=[u(`span`,{class:`text-h5`},`... No course was specified for the preview.`,-1),u(`div`,null,`(this shouldn't happen)...`,-1)])),_:1})]),_:1})])):m(``,!0),e.inSession?(r(),d(`div`,X,[!e.sessionPrepared&&!e.sessionError?(r(),d(`div`,Z,[n(C,{class:`text-center`},{default:t(()=>[n(x,{justify:`center`,align:`center`,style:{"min-height":`50vh`}},{default:t(()=>[n(b,{cols:`12`},{default:t(()=>[n(S,{size:`70`,width:`7`,color:`primary`,indeterminate:``}),c[5]||(c[5]=u(`div`,{class:`text-h5 mt-4`},`Preparing your study session...`,-1)),c[6]||(c[6]=u(`div`,{class:`text-subtitle-1 mt-2`},`Getting your learning materials ready`,-1))]),_:1})]),_:1})]),_:1})])):m(``,!0),e.sessionError?(r(),d(`div`,Q,[n(C,{class:`text-center`},{default:t(()=>[n(x,{justify:`center`,align:`center`,style:{"min-height":`50vh`}},{default:t(()=>[n(b,{cols:`12`},{default:t(()=>[n(w,{size:`64`,color:`error`},{default:t(()=>c[7]||(c[7]=[s(`mdi-alert-circle`)])),_:1}),c[9]||(c[9]=u(`div`,{class:`text-h5 mt-4 text-error`},`Session Preparation Failed`,-1)),u(`div`,$,i(e.errorMessage||`There was a problem preparing your study session.`),1),n(_,{color:`primary`,class:`mt-6`,onClick:e.refreshRoute},{default:t(()=>c[8]||(c[8]=[s(`Try Again`)])),_:1},8,[`onClick`])]),_:1})]),_:1})]),_:1})])):m(``,!0),n(T,{"content-sources":e.sessionContentSources,"session-time-limit":e.sessionTimeLimit,user:e.user,"session-config":e.studySessionConfig,"data-layer":e.dataLayer,"get-view-component":e.getViewComponent,class:o({"hidden-session":!e.sessionPrepared}),onSessionFinished:e.handleSessionFinished,onSessionPrepared:e.handleSessionPrepared,onSessionError:e.handleSessionError},null,8,[`content-sources`,`session-time-limit`,`user`,`session-config`,`data-layer`,`get-view-component`,`class`,`onSessionFinished`,`onSessionPrepared`,`onSessionError`])])):m(``,!0)])):(r(),d(`div`,G,[n(g,{"initial-time-limit":e.sessionTimeLimit,onInitStudySession:c[0]||(c[0]=(t,n)=>e.initStudySession(t,n))},null,8,[`initial-time-limit`])]))}var ee=w(W,[[`render`,_sfc_render],[`__scopeId`,`data-v-dcbc1fde`]]);export{ee as default};
2
- //# sourceMappingURL=Study-DDsGQCTJ.js.map
1
+ import{i as e}from"./chunk-D6hFPZc3.js";import{$ as t,C as n,H as r,Ht as i,K as a,Lt as o,S as s,T as c,W as l,_ as u,b as d,f,v as p,y as m}from"./vue.runtime.esm-bundler--Fxmd6l9.js";import{w as h}from"./MarkdownRenderer-borh39Lq.js";import"./moment-DbT30ZpG.js";import{B as g,C as _,g as v,h as y,n as b}from"./dist-C8EQUxWW.js";import{V as x}from"./contentSource-FGhM_ge8.js";import{h as S}from"./edit-ui.es-DJgikaS7.js";import"./dist-DGbpjpKB.js";import"./CourseWare-BTFRjgBR-lpqcYpAW.js";import"./PipelineDebugger-DhnKlMgD.js";import{d as C}from"./userDBKeys-3SQjNVdK.js";import"./eloDistance-CRxxdYPJ.js";import{t as w}from"./index-BRaeVAZb.js";import"./chess-E2uOAyQS-DDTgqZMJ.js";import"./math-D_8HiEQR-CQynsoTm.js";import"./piano-DF1g6yaX-vXbP1jX_.js";import"./sightsing-BFQ7HRig-CYuNcd8z.js";import"./typing-BevtfWlp-C0NbuTKI.js";import{t as T}from"./dist-BJLhyG8r.js";var E=c({name:`SessionConfiguration`,components:{SkMouseTrapToolTip:g,CourseTagFilterWidget:b},props:{initialTimeLimit:{type:Number,required:!0,default:5}},emits:[`initStudySession`],data(){return{registeredHotkeys:[],allSelected:!0,activeCourses:[],activeClasses:[],hasRegistrations:!0,user:null,timeLimit:this.initialTimeLimit,courseLoadError:!1,classroomLoadError:!1,expandedFilters:{}}},computed:{hasSelectedSources(){return this.activeCourses.some(e=>e.selected)||this.activeClasses.some(e=>e.selected)},hasAnyActiveFilter(){return this.activeCourses.some(e=>e.selected&&this.hasActiveTagFilter(e))},activeFilterCount(){return this.activeCourses.filter(e=>e.selected&&this.hasActiveTagFilter(e)).length}},watch:{timeLimit:{handler(){this.timeLimit<=0&&(this.timeLimit=1)}}},beforeUnmount(){this.registeredHotkeys&&this.registeredHotkeys.forEach(e=>{h.removeBinding(e)})},async created(){this.user=await v(),this.timeLimit=this.initialTimeLimit,this.setHotkeys();let[e,t]=await Promise.allSettled([this.getActiveCourses(),this.getActiveClassrooms()]);e.status===`rejected`&&(console.error(`Failed to load courses:`,e.reason),this.courseLoadError=!0),t.status===`rejected`&&(console.error(`Failed to load classrooms:`,t.reason),this.classroomLoadError=!0),this.activeCourses.length===0&&this.activeClasses.length===0&&!this.courseLoadError&&!this.classroomLoadError&&(this.hasRegistrations=!1)},mounted(){document.getElementById(`SelectAll`)?.focus()},unmounted(){this.registeredHotkeys&&this.registeredHotkeys.forEach(e=>{h.removeBinding(e)})},methods:{inc(){this.timeLimit+=1,console.log(`inc to ${this.timeLimit}`)},dec(){this.timeLimit--,console.log(`dec to ${this.timeLimit}`)},update(){console.log(JSON.stringify(this.activeCourses)),console.log(JSON.stringify(this.activeClasses))},toggleAll(){console.log(`Toggling all courses`),this.activeCourses.forEach(e=>{e.selected=this.allSelected}),this.activeClasses.forEach(e=>{e.selected=this.allSelected}),console.log(JSON.stringify(this.activeCourses))},toggleTagFilter(e){this.expandedFilters[e]=!this.expandedFilters[e]},hasActiveTagFilter(e){return x(e.tagFilter)},startSession(){this.registeredHotkeys&&this.registeredHotkeys.forEach(e=>{h.removeBinding(e)});let e=this.activeCourses.filter(e=>e.selected).map(e=>{let t={type:`course`,id:e.courseID};return x(e.tagFilter)&&(t.tagFilter=e.tagFilter),t}),t=this.activeClasses.filter(e=>e.selected).map(e=>({type:`classroom`,id:e.classID})),n=[...e,...t];this.$emit(`initStudySession`,n,this.timeLimit)},async getActiveClassrooms(){let e=await(await v()).getActiveClasses(),t=[];console.log(`Active classes: ${JSON.stringify(e)}`),await Promise.all(e.map(e=>(async e=>{let n=await C().getClassroomDB(e,`student`);t.push({classID:e,name:n.getConfig().name,selected:!0,reviews:0})})(e))),this.activeClasses=t},async getActiveCourses(){this.activeCourses=(await this.user.getActiveCourses()).map(e=>({...e,selected:!0,name:``,reviews:0,tagFilter:void 0})),Promise.all(this.activeCourses.map(async(e,t)=>{let n=await C().getCoursesDB().getCourseConfig(e.courseID),r=await this.user?.getCourseInterface(e.courseID);return(async()=>Promise.all([this.activeCourses[t].name=n.name,this.activeCourses[t].reviews=await r.getScheduledReviewCount()]))()}))},setHotkeys(){let e=[{hotkey:`right`,callback:()=>{this.timeLimit++},command:`Increase time limit`},{hotkey:`left`,callback:()=>{this.timeLimit--},command:`Decrease time limit`}];h.addBinding(e),this.registeredHotkeys=e.map(e=>e.hotkey)}}}),D={key:0},O={class:`session-layout`},k={class:`course-selection-container`},A={class:`course-row-header`},j={class:`course-row-header`},M={class:`course-row-actions`},N={class:`reviews-count`},P={key:0,class:`tag-filter-container`},F={class:`select-all-row mt-3`},I={class:`fixed-controls-container`},L={class:`fixed-controls`},R={class:`mb-5`},z={key:0,class:`filter-summary mb-4`},B={class:`text-caption`},V={key:1,class:`text-h4`},H={key:2,class:`text-h4`};function _sfc_render$1(e,o,c,h,g,_){let v=a(`v-alert`),y=a(`v-checkbox`),b=a(`v-icon`),x=a(`v-btn`),S=a(`CourseTagFilterWidget`),C=a(`v-expand-transition`),w=a(`v-text-field`),T=a(`SkMouseTrapToolTip`),E=a(`router-link`);return e.hasRegistrations||e.courseLoadError||e.classroomLoadError?(r(),d(`div`,D,[o[11]||(o[11]=u(`div`,{"data-cy":`select-quilts-header`,class:`text-h4 mb-4`},`Study Session Setup`,-1)),e.courseLoadError?(r(),p(v,{key:0,type:`warning`,class:`mb-4`},{default:t(()=>o[2]||(o[2]=[s(` Unable to load course data. Some features may be unavailable. `)])),_:1})):m(``,!0),e.classroomLoadError?(r(),p(v,{key:1,type:`warning`,class:`mb-4`},{default:t(()=>o[3]||(o[3]=[s(` Unable to load classroom data. You can still study individual courses. `)])),_:1})):m(``,!0),u(`div`,O,[u(`div`,k,[o[6]||(o[6]=u(`div`,{class:`text-h6 mb-3`},`Select Quilts to Study`,-1)),(r(!0),d(f,null,l(e.activeClasses,t=>(r(),d(`div`,{key:t.classID,class:`course-row`},[u(`div`,A,[n(y,{modelValue:t.selected,"onUpdate:modelValue":e=>t.selected=e,label:`Class: ${t.name}`,"hide-details":``,onClickCapture:e.update},null,8,[`modelValue`,`onUpdate:modelValue`,`label`,`onClickCapture`]),o[4]||(o[4]=u(`span`,{class:`reviews-count`},`-`,-1))])]))),128)),(r(!0),d(f,null,l(e.activeCourses,a=>(r(),d(`div`,{key:a.courseID,class:`course-row`},[u(`div`,j,[n(y,{modelValue:a.selected,"onUpdate:modelValue":e=>a.selected=e,"data-cy":`course-checkbox`,label:`q/${a.name}`,"hide-details":``,onClickCapture:e.update},null,8,[`modelValue`,`onUpdate:modelValue`,`label`,`onClickCapture`]),u(`div`,M,[u(`span`,N,i(a.reviews),1),a.selected?(r(),p(x,{key:0,variant:`text`,size:`small`,color:e.hasActiveTagFilter(a)?`primary`:`default`,onClick:t=>e.toggleTagFilter(a.courseID)},{default:t(()=>[n(b,{start:``,size:`small`},{default:t(()=>o[5]||(o[5]=[s(`mdi-filter-variant`)])),_:1}),s(` `+i(e.hasActiveTagFilter(a)?`Filtered`:`Filter`)+` `,1),n(b,{end:``,size:`small`},{default:t(()=>[s(i(e.expandedFilters[a.courseID]?`mdi-chevron-up`:`mdi-chevron-down`),1)]),_:2},1024)]),_:2},1032,[`color`,`onClick`])):m(``,!0)])]),n(C,null,{default:t(()=>[a.selected&&e.expandedFilters[a.courseID]?(r(),d(`div`,P,[n(S,{modelValue:a.tagFilter,"onUpdate:modelValue":e=>a.tagFilter=e,"course-id":a.courseID},null,8,[`modelValue`,`onUpdate:modelValue`,`course-id`])])):m(``,!0)]),_:2},1024)]))),128)),u(`div`,F,[n(y,{id:`SelectAll`,ref:`selectAll`,modelValue:e.allSelected,"onUpdate:modelValue":[o[0]||(o[0]=t=>e.allSelected=t),e.toggleAll],autofocus:``,label:`Select All`,"hide-details":``},null,8,[`modelValue`,`onUpdate:modelValue`])])]),u(`div`,I,[u(`div`,L,[o[10]||(o[10]=u(`div`,{class:`text-h6 mb-3`},`Session Settings`,-1)),u(`div`,R,[n(w,{ref:`numberField`,modelValue:e.timeLimit,"onUpdate:modelValue":o[1]||(o[1]=t=>e.timeLimit=t),class:`time-limit-field`,variant:`outlined`,label:`Study Session Timelimit`,"prepend-inner-icon":`mdi-clock-outline`,"prepend-icon":`mdi-minus`,"append-icon":`mdi-plus`,suffix:e.timeLimit>1?`minutes`:`minute`,mask:`##`,type:`number`,"onClick:prepend":e.dec,"onClick:append":e.inc},null,8,[`modelValue`,`suffix`,`onClick:prepend`,`onClick:append`])]),e.hasAnyActiveFilter?(r(),d(`div`,z,[n(b,{size:`small`,color:`primary`,class:`mr-1`},{default:t(()=>o[7]||(o[7]=[s(`mdi-filter`)])),_:1}),u(`span`,B,i(e.activeFilterCount)+` course`+i(e.activeFilterCount>1?`s`:``)+` with tag filters `,1)])):m(``,!0),n(T,{hotkey:`enter`,command:`Start Session`,disabled:!e.hasSelectedSources,"highlight-effect":`scale`},{default:t(()=>[n(x,{"data-cy":`start-studying-button`,color:`success`,size:`large`,block:``,class:`start-btn`,disabled:!e.hasSelectedSources,onClick:e.startSession},{default:t(()=>[n(b,{start:``},{default:t(()=>o[8]||(o[8]=[s(`mdi-play`)])),_:1}),o[9]||(o[9]=s(` Start! `))]),_:1},8,[`disabled`,`onClick`])]),_:1},8,[`disabled`])])])])])):!e.courseLoadError&&!e.classroomLoadError?(r(),d(`div`,V,[o[15]||(o[15]=u(`p`,null,`You don't have anything to study!`,-1)),u(`p`,null,[o[13]||(o[13]=s(`Head over to the `)),n(E,{to:`/quilts`},{default:t(()=>o[12]||(o[12]=[s(`Quilts`)])),_:1}),o[14]||(o[14]=s(` page to find something for you.`))])])):(r(),d(`div`,H,o[16]||(o[16]=[u(`p`,null,`Unable to load study data due to technical issues.`,-1),u(`p`,null,`Please try refreshing the page or contact support if the problem persists.`,-1)])))}e(_sfc_render$1,`_sfc_render`);var U=w(E,[[`render`,_sfc_render$1],[`__scopeId`,`data-v-c5ff4b5f`]]);function randomInt(e,t){return Math.floor(Math.random()*(t-e+1))+e}var W=c({name:`StudyView`,components:{SessionConfiguration:U,StudySession:_},inject:{router:{from:`router`}},props:{previewCourseID:{type:String,required:!1,default:``},randomPreview:{type:Boolean,required:!1},focusCourseID:{type:String,required:!1,default:``}},data(){return{user:null,studySessionConfig:void 0,previewCourseConfig:void 0,previewMode:!1,sessionTimeLimit:5,inSession:!1,sessionPrepared:!1,sessionError:!1,errorMessage:``,sessionContentSources:[],dataInputFormStore:S(),getViewComponent:e=>T.getView(e),dataLayer:C()}},async created(){this.user=await v(),this.studySessionConfig={likesConfetti:y().config.likesConfetti};let e=``;if(this.randomPreview){let t=await this.user.getCourseRegistrationsDoc(),n=(await C().getCoursesDB().getCourseList()).map(e=>e.courseID),r=n.filter(e=>!t.courses.some(t=>t.courseID===e));e=r.length>0?r[randomInt(0,r.length)]:n[randomInt(0,n.length)]}if(this.previewCourseID&&(this.previewMode=!0,C().getCoursesDB().getCourseList().then(e=>{e.forEach(e=>{e.courseID===this.previewCourseID&&(this.previewCourseConfig=e,this.previewCourseConfig.courseID=e.courseID)})}),console.log(`[Study] COURSE PREVIEW MODE FOR ${this.previewCourseID}`),await this.user.registerForCourse(this.previewCourseID,!0),e=this.previewCourseID),this.focusCourseID&&(console.log(`[Study] FOCUS study session: ${this.focusCourseID}`),e=this.focusCourseID),e){let t=this.parseTagFilterFromQuery(),n={type:`course`,id:e};x(t)&&(n.tagFilter=t,console.log(`[Study] Tag filter from query params:`,t)),this.initStudySession([n],this.sessionTimeLimit)}},methods:{refreshRoute(){this.router.go(0)},async initStudySession(e,t){console.log(`[Study] starting study session w/ sources: ${JSON.stringify(e)}`),this.sessionContentSources=e,this.sessionTimeLimit=t,this.inSession=!0,this.sessionPrepared=!1,console.log(`[Study] Waiting for session-prepared event from StudySession component`)},registerUserForPreviewCourse(){this.user.registerForCourse(this.previewCourseConfig.courseID).then(()=>this.router.push(`/quilts/${this.previewCourseConfig.courseID}`))},handleSessionFinished(){this.refreshRoute()},handleSessionPrepared(){console.log(`[Study] Session preparation complete - received session-prepared event`),this.sessionPrepared=!0,this.sessionError=!1,this.errorMessage=``},handleSessionError({message:e,error:t}){console.error(`[Study] Session error:`,e,t),this.sessionError=!0,this.errorMessage=e||`An error occurred while preparing your study session.`,this.sessionPrepared=!1},parseTagFilterFromQuery(){let e=this.$route.query.include,t=this.$route.query.exclude,parseParam=e=>e?Array.isArray(e)?e.flatMap(e=>e?e.split(`,`).map(e=>e.trim()):[]).filter(Boolean):e.split(`,`).map(e=>e.trim()).filter(Boolean):[];return{include:parseParam(e),exclude:parseParam(t)}}}}),G={key:0},K={key:1},q={key:0,align:`center`},J={class:`text-h5`},Y={key:1},X={key:2},Z={key:0,class:`session-loading`},Q={key:1,class:`session-error`},$={class:`text-subtitle-1 mt-2`};function _sfc_render(e,c,l,f,p,h){let g=a(`SessionConfiguration`),_=a(`v-btn`),v=a(`router-link`),y=a(`v-spacer`),b=a(`v-col`),x=a(`v-row`),S=a(`v-progress-circular`),C=a(`v-container`),w=a(`v-icon`),T=a(`StudySession`);return e.inSession?(r(),d(`div`,K,[e.previewMode&&e.previewCourseConfig?(r(),d(`div`,q,[n(x,null,{default:t(()=>[n(b,null,{default:t(()=>[u(`span`,J,[c[1]||(c[1]=s(` Quilt preview for `)),u(`em`,null,i(e.previewCourseConfig.name),1)]),n(_,{size:`small`,color:`primary`,onClick:e.registerUserForPreviewCourse},{default:t(()=>c[2]||(c[2]=[s(`Join`)])),_:1},8,[`onClick`]),n(v,{to:`/quilts/${e.previewCourseConfig.courseID}`},{default:t(()=>[n(_,{size:`small`,color:`secondary`},{default:t(()=>c[3]||(c[3]=[s(`More info`)])),_:1})]),_:1},8,[`to`]),n(y)]),_:1})]),_:1})])):e.previewMode?(r(),d(`div`,Y,[n(x,null,{default:t(()=>[n(b,null,{default:t(()=>c[4]||(c[4]=[u(`span`,{class:`text-h5`},`... No course was specified for the preview.`,-1),u(`div`,null,`(this shouldn't happen)...`,-1)])),_:1})]),_:1})])):m(``,!0),e.inSession?(r(),d(`div`,X,[!e.sessionPrepared&&!e.sessionError?(r(),d(`div`,Z,[n(C,{class:`text-center`},{default:t(()=>[n(x,{justify:`center`,align:`center`,style:{"min-height":`50vh`}},{default:t(()=>[n(b,{cols:`12`},{default:t(()=>[n(S,{size:`70`,width:`7`,color:`primary`,indeterminate:``}),c[5]||(c[5]=u(`div`,{class:`text-h5 mt-4`},`Preparing your study session...`,-1)),c[6]||(c[6]=u(`div`,{class:`text-subtitle-1 mt-2`},`Getting your learning materials ready`,-1))]),_:1})]),_:1})]),_:1})])):m(``,!0),e.sessionError?(r(),d(`div`,Q,[n(C,{class:`text-center`},{default:t(()=>[n(x,{justify:`center`,align:`center`,style:{"min-height":`50vh`}},{default:t(()=>[n(b,{cols:`12`},{default:t(()=>[n(w,{size:`64`,color:`error`},{default:t(()=>c[7]||(c[7]=[s(`mdi-alert-circle`)])),_:1}),c[9]||(c[9]=u(`div`,{class:`text-h5 mt-4 text-error`},`Session Preparation Failed`,-1)),u(`div`,$,i(e.errorMessage||`There was a problem preparing your study session.`),1),n(_,{color:`primary`,class:`mt-6`,onClick:e.refreshRoute},{default:t(()=>c[8]||(c[8]=[s(`Try Again`)])),_:1},8,[`onClick`])]),_:1})]),_:1})]),_:1})])):m(``,!0),n(T,{"content-sources":e.sessionContentSources,"session-time-limit":e.sessionTimeLimit,user:e.user,"session-config":e.studySessionConfig,"data-layer":e.dataLayer,"get-view-component":e.getViewComponent,class:o({"hidden-session":!e.sessionPrepared}),onSessionFinished:e.handleSessionFinished,onSessionPrepared:e.handleSessionPrepared,onSessionError:e.handleSessionError},null,8,[`content-sources`,`session-time-limit`,`user`,`session-config`,`data-layer`,`get-view-component`,`class`,`onSessionFinished`,`onSessionPrepared`,`onSessionError`])])):m(``,!0)])):(r(),d(`div`,G,[n(g,{"initial-time-limit":e.sessionTimeLimit,onInitStudySession:c[0]||(c[0]=(t,n)=>e.initStudySession(t,n))},null,8,[`initial-time-limit`])]))}var ee=w(W,[[`render`,_sfc_render],[`__scopeId`,`data-v-dcbc1fde`]]);export{ee as default};
2
+ //# sourceMappingURL=Study-D2mXR27s.js.map