@vue-skuilder/common-ui 0.2.34 → 0.2.36

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 (207) hide show
  1. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs +13 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPrimitive.mjs +15 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/toPropertyKey.mjs +10 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.115.0/helpers/typeof.mjs +12 -0
  5. package/dist/_virtual/_plugin-vue_export-helper.mjs +9 -0
  6. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  7. package/dist/admin/admin.css +1 -1
  8. package/dist/admin/common-ui-admin.es.js +1074 -473
  9. package/dist/admin/common-ui-admin.es.js.map +1 -1
  10. package/dist/admin/components/EChart.vue.d.ts +14 -0
  11. package/dist/admin/components/EChart.vue.d.ts.map +1 -0
  12. package/dist/admin/components/LearnerDiagnostics.vue.d.ts +3 -3
  13. package/dist/admin/components/LearnerDiagnostics.vue.d.ts.map +1 -1
  14. package/dist/admin/components/LearnerTagElo.vue.d.ts +14 -0
  15. package/dist/admin/components/LearnerTagElo.vue.d.ts.map +1 -0
  16. package/dist/admin/index.d.ts +1 -0
  17. package/dist/admin/index.d.ts.map +1 -1
  18. package/dist/assets/index.css +2 -1
  19. package/dist/components/CardBrowser.mjs +63 -0
  20. package/dist/components/CardBrowser.mjs.map +1 -0
  21. package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs +50 -0
  22. package/dist/components/CardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
  23. package/dist/components/CardHistoryViewer.mjs +70 -0
  24. package/dist/components/CardHistoryViewer.mjs.map +1 -0
  25. package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs +108 -0
  26. package/dist/components/CardHistoryViewer.vue_vue_type_script_lang.mjs.map +1 -0
  27. package/dist/components/CardSearch.mjs +26 -0
  28. package/dist/components/CardSearch.mjs.map +1 -0
  29. package/dist/components/CardSearch.vue_vue_type_script_lang.mjs +17 -0
  30. package/dist/components/CardSearch.vue_vue_type_script_lang.mjs.map +1 -0
  31. package/dist/components/CardSearchResults.mjs +32 -0
  32. package/dist/components/CardSearchResults.mjs.map +1 -0
  33. package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs +71 -0
  34. package/dist/components/CardSearchResults.vue_vue_type_script_lang.mjs.map +1 -0
  35. package/dist/components/CourseCardBrowser.mjs +175 -0
  36. package/dist/components/CourseCardBrowser.mjs.map +1 -0
  37. package/dist/components/CourseCardBrowser.vue.d.ts +3 -3
  38. package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs +173 -0
  39. package/dist/components/CourseCardBrowser.vue_vue_type_script_lang.mjs.map +1 -0
  40. package/dist/components/CourseInformation.mjs +132 -0
  41. package/dist/components/CourseInformation.mjs.map +1 -0
  42. package/dist/components/CourseInformation.vue.d.ts +3 -3
  43. package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs +56 -0
  44. package/dist/components/CourseInformation.vue_vue_type_script_lang.mjs.map +1 -0
  45. package/dist/components/CourseTagFilterWidget.mjs +114 -0
  46. package/dist/components/CourseTagFilterWidget.mjs.map +1 -0
  47. package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs +65 -0
  48. package/dist/components/CourseTagFilterWidget.vue_vue_type_script_lang.mjs.map +1 -0
  49. package/dist/components/HeatMap.mjs +40 -0
  50. package/dist/components/HeatMap.mjs.map +1 -0
  51. package/dist/components/HeatMap.vue_vue_type_script_lang.mjs +211 -0
  52. package/dist/components/HeatMap.vue_vue_type_script_lang.mjs.map +1 -0
  53. package/dist/components/PaginatingToolbar.mjs +94 -0
  54. package/dist/components/PaginatingToolbar.mjs.map +1 -0
  55. package/dist/components/PaginatingToolbar.vue.d.ts +3 -3
  56. package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs +36 -0
  57. package/dist/components/PaginatingToolbar.vue_vue_type_script_lang.mjs.map +1 -0
  58. package/dist/components/SessionControllerDebug.mjs +130 -0
  59. package/dist/components/SessionControllerDebug.mjs.map +1 -0
  60. package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs +45 -0
  61. package/dist/components/SessionControllerDebug.vue_vue_type_script_lang.mjs.map +1 -0
  62. package/dist/components/SkMouseTrap.mjs +66 -0
  63. package/dist/components/SkMouseTrap.mjs.map +1 -0
  64. package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs +31 -0
  65. package/dist/components/SkMouseTrap.vue_vue_type_script_lang.mjs.map +1 -0
  66. package/dist/components/SkMouseTrapToolTip.mjs +28 -0
  67. package/dist/components/SkMouseTrapToolTip.mjs.map +1 -0
  68. package/dist/components/SkMouseTrapToolTip.vue.d.ts +1 -1
  69. package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs +91 -0
  70. package/dist/components/SkMouseTrapToolTip.vue_vue_type_script_lang.mjs.map +1 -0
  71. package/dist/components/SnackbarService.mjs +24 -0
  72. package/dist/components/SnackbarService.mjs.map +1 -0
  73. package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs +34 -0
  74. package/dist/components/SnackbarService.vue_vue_type_script_lang.mjs.map +1 -0
  75. package/dist/components/SnackbarService2.mjs +40 -0
  76. package/dist/components/SnackbarService2.mjs.map +1 -0
  77. package/dist/components/StudySession.mjs +123 -0
  78. package/dist/components/StudySession.mjs.map +1 -0
  79. package/dist/components/StudySession.vue_vue_type_script_lang.mjs +280 -0
  80. package/dist/components/StudySession.vue_vue_type_script_lang.mjs.map +1 -0
  81. package/dist/components/StudySessionTimer.mjs +50 -0
  82. package/dist/components/StudySessionTimer.mjs.map +1 -0
  83. package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs +43 -0
  84. package/dist/components/StudySessionTimer.vue_vue_type_script_lang.mjs.map +1 -0
  85. package/dist/components/TagsInput.mjs +45 -0
  86. package/dist/components/TagsInput.mjs.map +1 -0
  87. package/dist/components/TagsInput.vue_vue_type_script_lang.mjs +117 -0
  88. package/dist/components/TagsInput.vue_vue_type_script_lang.mjs.map +1 -0
  89. package/dist/components/UserTagPreferences.mjs +205 -0
  90. package/dist/components/UserTagPreferences.mjs.map +1 -0
  91. package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs +139 -0
  92. package/dist/components/UserTagPreferences.vue_vue_type_script_lang.mjs.map +1 -0
  93. package/dist/components/auth/RequestPasswordReset.mjs +96 -0
  94. package/dist/components/auth/RequestPasswordReset.mjs.map +1 -0
  95. package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs +47 -0
  96. package/dist/components/auth/RequestPasswordReset.vue_vue_type_script_lang.mjs.map +1 -0
  97. package/dist/components/auth/ResetPassword.mjs +129 -0
  98. package/dist/components/auth/ResetPassword.mjs.map +1 -0
  99. package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs +69 -0
  100. package/dist/components/auth/ResetPassword.vue_vue_type_script_lang.mjs.map +1 -0
  101. package/dist/components/auth/UserChip.mjs +9 -0
  102. package/dist/components/auth/UserChip.mjs.map +1 -0
  103. package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs +213 -0
  104. package/dist/components/auth/UserChip.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  105. package/dist/components/auth/UserLogin.mjs +9 -0
  106. package/dist/components/auth/UserLogin.mjs.map +1 -0
  107. package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs +155 -0
  108. package/dist/components/auth/UserLogin.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  109. package/dist/components/auth/UserLoginAndRegistrationContainer.mjs +9 -0
  110. package/dist/components/auth/UserLoginAndRegistrationContainer.mjs.map +1 -0
  111. package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs +126 -0
  112. package/dist/components/auth/UserLoginAndRegistrationContainer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  113. package/dist/components/auth/UserRegistration.mjs +147 -0
  114. package/dist/components/auth/UserRegistration.mjs.map +1 -0
  115. package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs +130 -0
  116. package/dist/components/auth/UserRegistration.vue_vue_type_script_lang.mjs.map +1 -0
  117. package/dist/components/auth/VerifyEmail.mjs +118 -0
  118. package/dist/components/auth/VerifyEmail.mjs.map +1 -0
  119. package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs +59 -0
  120. package/dist/components/auth/VerifyEmail.vue_vue_type_script_lang.mjs.map +1 -0
  121. package/dist/components/cardRendering/AudioAutoPlayer.mjs +9 -0
  122. package/dist/components/cardRendering/AudioAutoPlayer.mjs.map +1 -0
  123. package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs +69 -0
  124. package/dist/components/cardRendering/AudioAutoPlayer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  125. package/dist/components/cardRendering/CardLoader.mjs +31 -0
  126. package/dist/components/cardRendering/CardLoader.mjs.map +1 -0
  127. package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs +75 -0
  128. package/dist/components/cardRendering/CardLoader.vue_vue_type_script_lang.mjs.map +1 -0
  129. package/dist/components/cardRendering/CardViewer.mjs +39 -0
  130. package/dist/components/cardRendering/CardViewer.mjs.map +1 -0
  131. package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs +66 -0
  132. package/dist/components/cardRendering/CardViewer.vue_vue_type_script_lang.mjs.map +1 -0
  133. package/dist/components/cardRendering/CodeBlockRenderer.mjs +8 -0
  134. package/dist/components/cardRendering/CodeBlockRenderer.mjs.map +1 -0
  135. package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs +44 -0
  136. package/dist/components/cardRendering/CodeBlockRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  137. package/dist/components/cardRendering/MarkdownRenderer.mjs +21 -0
  138. package/dist/components/cardRendering/MarkdownRenderer.mjs.map +1 -0
  139. package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs +24 -0
  140. package/dist/components/cardRendering/MarkdownRenderer.vue_vue_type_script_lang.mjs.map +1 -0
  141. package/dist/components/cardRendering/MarkdownRendererHelpers.mjs +79 -0
  142. package/dist/components/cardRendering/MarkdownRendererHelpers.mjs.map +1 -0
  143. package/dist/components/cardRendering/MdTokenRenderer.mjs +9 -0
  144. package/dist/components/cardRendering/MdTokenRenderer.mjs.map +1 -0
  145. package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs +176 -0
  146. package/dist/components/cardRendering/MdTokenRenderer.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
  147. package/dist/components/studentInputs/BaseUserInput.mjs +54 -0
  148. package/dist/components/studentInputs/BaseUserInput.mjs.map +1 -0
  149. package/dist/components/studentInputs/MultipleChoiceOption.mjs +26 -0
  150. package/dist/components/studentInputs/MultipleChoiceOption.mjs.map +1 -0
  151. package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs +76 -0
  152. package/dist/components/studentInputs/MultipleChoiceOption.vue_vue_type_script_lang.mjs.map +1 -0
  153. package/dist/components/studentInputs/RadioMultipleChoice.mjs +33 -0
  154. package/dist/components/studentInputs/RadioMultipleChoice.mjs.map +1 -0
  155. package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs +105 -0
  156. package/dist/components/studentInputs/RadioMultipleChoice.vue_vue_type_script_lang.mjs.map +1 -0
  157. package/dist/components/studentInputs/TrueFalse.mjs +19 -0
  158. package/dist/components/studentInputs/TrueFalse.mjs.map +1 -0
  159. package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs +21 -0
  160. package/dist/components/studentInputs/TrueFalse.vue_vue_type_script_lang.mjs.map +1 -0
  161. package/dist/components/studentInputs/UserInputNumber.mjs +33 -0
  162. package/dist/components/studentInputs/UserInputNumber.mjs.map +1 -0
  163. package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs +25 -0
  164. package/dist/components/studentInputs/UserInputNumber.vue_vue_type_script_lang.mjs.map +1 -0
  165. package/dist/components/studentInputs/UserInputString.mjs +22 -0
  166. package/dist/components/studentInputs/UserInputString.mjs.map +1 -0
  167. package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs +23 -0
  168. package/dist/components/studentInputs/UserInputString.vue_vue_type_script_lang.mjs.map +1 -0
  169. package/dist/components/studentInputs/fillInInput.mjs +25 -0
  170. package/dist/components/studentInputs/fillInInput.mjs.map +1 -0
  171. package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs +26 -0
  172. package/dist/components/studentInputs/fillInInput.vue_vue_type_script_lang.mjs.map +1 -0
  173. package/dist/composables/CompositionViewable.mjs +65 -0
  174. package/dist/composables/CompositionViewable.mjs.map +1 -0
  175. package/dist/composables/Displayable.mjs +36 -0
  176. package/dist/composables/Displayable.mjs.map +1 -0
  177. package/dist/composables/useAuthUI.mjs +38 -0
  178. package/dist/composables/useAuthUI.mjs.map +1 -0
  179. package/dist/composables/useEntitlements.mjs +58 -0
  180. package/dist/composables/useEntitlements.mjs.map +1 -0
  181. package/dist/index.mjs +49 -0
  182. package/dist/plugins/pinia.mjs +12 -0
  183. package/dist/plugins/pinia.mjs.map +1 -0
  184. package/dist/services/authAPI.mjs +159 -0
  185. package/dist/services/authAPI.mjs.map +1 -0
  186. package/dist/stores/useAuthStore.mjs +68 -0
  187. package/dist/stores/useAuthStore.mjs.map +1 -0
  188. package/dist/stores/useCardPreviewModeStore.mjs +20 -0
  189. package/dist/stores/useCardPreviewModeStore.mjs.map +1 -0
  190. package/dist/stores/useConfigStore.mjs +60 -0
  191. package/dist/stores/useConfigStore.mjs.map +1 -0
  192. package/dist/utils/SkldrMouseTrap.mjs +48 -0
  193. package/dist/utils/SkldrMouseTrap.mjs.map +1 -0
  194. package/dist/utils/passwordValidation.mjs +12 -0
  195. package/dist/utils/passwordValidation.mjs.map +1 -0
  196. package/package.json +8 -8
  197. package/src/admin/components/EChart.vue +59 -0
  198. package/src/admin/components/LearnerDiagnostics.vue +8 -4
  199. package/src/admin/components/LearnerTagElo.vue +563 -0
  200. package/src/admin/index.ts +1 -0
  201. package/dist/MarkdownRenderer-U_iPiA2x.mjs +0 -4966
  202. package/dist/MarkdownRenderer-U_iPiA2x.mjs.map +0 -1
  203. package/dist/assets/MarkdownRenderer.css +0 -1
  204. package/dist/common-ui.es.js +0 -5090
  205. package/dist/common-ui.es.js.map +0 -1
  206. package/dist/common-ui.umd.js +0 -77
  207. package/dist/common-ui.umd.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompositionViewable.mjs","names":[],"sources":["../../src/composables/CompositionViewable.ts"],"sourcesContent":["// src/base-course/CompositionViewable.ts\n\nimport moment from 'moment';\nimport { customRef, ref, Ref } from 'vue';\nimport { CardRecord, QuestionRecord } from '@vue-skuilder/db';\nimport { HotKey } from '../utils/SkldrMouseTrap';\nimport { Question } from './Displayable';\nimport { ViewData, Answer } from '@vue-skuilder/common';\n\n// Core interfaces to ensure type safety\nexport interface ViewableUtils {\n startTime: Ref<moment.Moment>;\n hotKeys: Ref<HotKey[]>;\n timeSpent: Readonly<Ref<number>>;\n logger: ViewableLogger;\n getURL: (item: string, dataShapeIndex?: number) => string;\n emitResponse: (record: CardRecord) => void;\n}\n\nexport interface ViewableLogger {\n log: (message?: unknown, ...params: unknown[]) => void;\n error: (message?: unknown, ...params: unknown[]) => void;\n warn: (message?: unknown, ...params: unknown[]) => void;\n}\n\n/**\n * Options that can be passed to `submitAnswer` to control framework behaviour.\n */\nexport interface SubmitAnswerOpts {\n /**\n * When true, the framework logs the card record and updates ELO/SRS but\n * does **not** advance to the next card. The view is expected to emit\n * `ready-to-advance` later to trigger navigation.\n */\n deferAdvance?: boolean;\n}\n\nexport interface QuestionViewUtils<Q extends Question> {\n priorSessionViews: Ref<number>;\n priorAttempts: Ref<number>;\n priorAnswers: Ref<[Answer, string][]>;\n maxAttemptsPerView: Ref<number>;\n maxSessionViews: Ref<number>;\n question: Ref<Q | undefined>;\n submitAnswer: (answer: Answer, submittingClass?: string, opts?: SubmitAnswerOpts) => QuestionRecord;\n}\n\n// Base composable for viewable functionality\nexport function useViewable(\n props: { data: ViewData[] },\n emit: (event: string, ...args: unknown[]) => void,\n componentName: string\n): ViewableUtils {\n const startTime = ref(moment.utc());\n const hotKeys = ref<HotKey[]>([]);\n\n const logger: ViewableLogger = {\n log: (message?: unknown, ...params: unknown[]) =>\n console.log(`[${componentName}]: `, message, ...params),\n error: (message?: unknown, ...params: unknown[]) =>\n console.error(`[${componentName}]: `, message, ...params),\n warn: (message?: unknown, ...params: unknown[]) =>\n console.warn(`[${componentName}]: `, message, ...params),\n };\n\n // Recomputed on every read. A computed caches its first read (moment.utc() isn't reactive),\n // so retries were recorded with the first attempt's time.\n const timeSpent = customRef<number>(() => ({\n get: () => Math.abs(moment.utc().diff(startTime.value, 'milliseconds')),\n set: () => {},\n }));\n\n const getURL = (item: string, dataShapeIndex = 0): string => {\n try {\n if (props.data[dataShapeIndex]?.[item]) {\n return URL.createObjectURL(props.data[dataShapeIndex][item] as Blob);\n }\n } catch (error) {\n logger.error('Error creating URL for item:', item, error);\n }\n return '';\n };\n\n const emitResponse = (record: CardRecord) => {\n emit('emitResponse', record);\n };\n\n return {\n startTime,\n hotKeys,\n timeSpent,\n logger,\n getURL,\n emitResponse,\n };\n}\n\n// Question view composable\nexport function useQuestionView<Q extends Question>(\n viewableUtils: ViewableUtils\n // modifyDifficulty?: number\n): QuestionViewUtils<Q> {\n const priorSessionViews = ref(0);\n const priorAttempts = ref(0);\n const priorAnswers = ref<[Answer, string][]>([]);\n const maxAttemptsPerView = ref(3);\n const maxSessionViews = ref(2);\n const question = ref<Q>();\n\n const submitAnswer = (answer: Answer, submittingClass?: string, opts?: SubmitAnswerOpts): QuestionRecord => {\n viewableUtils.logger.log('submitAnswer called...');\n\n if (!question.value) {\n throw new Error('Question not initialized');\n }\n\n priorAnswers.value.push([answer, submittingClass ?? '']);\n\n const timeSpent = viewableUtils.timeSpent.value;\n const evaluation = question.value.evaluate(answer, timeSpent);\n\n viewableUtils.logger.log(`evaluation of answer ${answer}:`, evaluation);\n\n const record: QuestionRecord = {\n ...evaluation,\n priorAttemps: priorAttempts.value,\n courseID: '',\n cardID: '',\n timeSpent,\n timeStamp: viewableUtils.startTime.value,\n userAnswer: answer,\n };\n\n // Merge deferAdvance from opts if provided (takes precedence over evaluate())\n if (opts?.deferAdvance !== undefined) {\n record.deferAdvance = opts.deferAdvance;\n }\n\n if (!evaluation.isCorrect) {\n priorAttempts.value++;\n }\n\n viewableUtils.emitResponse(record);\n return record;\n };\n\n return {\n priorSessionViews,\n priorAttempts,\n priorAnswers,\n maxAttemptsPerView,\n maxSessionViews,\n question,\n submitAnswer,\n };\n}\n\n// Helper functions\nexport function isQuestionView(component: unknown): component is QuestionViewUtils<Question> {\n return (\n typeof component === 'object' &&\n component !== null &&\n 'submitAnswer' in component &&\n 'priorAttempts' in component\n );\n}\n\n// Example usage in a child component:\n/*\nimport { defineComponent, PropType } from 'vue';\nimport { useViewable, useQuestionView } from './CompositionViewable';\nimport { MyCustomQuestion } from './types';\n\nexport default defineComponent({\n name: 'MyCustomQuestionView',\n props: {\n data: {\n type: Array as PropType<ViewData[]>,\n required: true,\n },\n modifyDifficulty: Number,\n },\n setup(props, { emit }) {\n const viewableUtils = useViewable(props, emit, 'MyCustomQuestionView');\n const questionUtils = useQuestionView<MyCustomQuestion>(viewableUtils, props.modifyDifficulty);\n\n // Initialize question\n questionUtils.question.value = new MyCustomQuestion(props.data);\n\n // Add custom logic here\n const customMethod = () => {\n viewableUtils.logger.log('Custom method called');\n // ...\n };\n\n return {\n ...viewableUtils,\n ...questionUtils,\n customMethod,\n };\n },\n template: `\n <div data-viewable=\"MyCustomQuestionView\">\n <!-- Your template here -->\n </div>\n `\n});\n*/\n"],"mappings":";;;;AAgDA,SAAgB,YACd,GACA,GACA,GACe;CACf,IAAM,IAAY,EAAI,EAAO,KAAK,CAAC,EAC7B,IAAU,EAAc,EAAE,CAAC,EAE3B,IAAyB;EAC7B,MAAM,GAAmB,GAAG,MAC1B,QAAQ,IAAI,IAAI,EAAc,MAAM,GAAS,GAAG,EAAO;EACzD,QAAQ,GAAmB,GAAG,MAC5B,QAAQ,MAAM,IAAI,EAAc,MAAM,GAAS,GAAG,EAAO;EAC3D,OAAO,GAAmB,GAAG,MAC3B,QAAQ,KAAK,IAAI,EAAc,MAAM,GAAS,GAAG,EAAO;EAC3D,EAIK,IAAY,SAAyB;EACzC,WAAW,KAAK,IAAI,EAAO,KAAK,CAAC,KAAK,EAAU,OAAO,eAAe,CAAC;EACvE,WAAW;EACZ,EAAE,EAEG,UAAU,GAAc,IAAiB,MAAc;AAC3D,MAAI;AACF,OAAI,EAAM,KAAK,KAAkB,GAC/B,QAAO,IAAI,gBAAgB,EAAM,KAAK,GAAgB,GAAc;WAE/D,GAAO;AACd,KAAO,MAAM,gCAAgC,GAAM,EAAM;;AAE3D,SAAO;IAGH,gBAAgB,MAAuB;AAC3C,IAAK,gBAAgB,EAAO;;AAG9B,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD;;AAIH,SAAgB,gBACd,GAEsB;CACtB,IAAM,IAAoB,EAAI,EAAE,EAC1B,IAAgB,EAAI,EAAE,EACtB,IAAe,EAAwB,EAAE,CAAC,EAC1C,IAAqB,EAAI,EAAE,EAC3B,IAAkB,EAAI,EAAE,EACxB,IAAW,GAAQ,EAEnB,gBAAgB,GAAgB,GAA0B,MAA4C;AAG1G,MAFA,EAAc,OAAO,IAAI,yBAAyB,EAE9C,CAAC,EAAS,MACZ,OAAU,MAAM,2BAA2B;AAG7C,IAAa,MAAM,KAAK,CAAC,GAAQ,KAAmB,GAAG,CAAC;EAExD,IAAM,IAAY,EAAc,UAAU,OACpC,IAAa,EAAS,MAAM,SAAS,GAAQ,EAAU;AAE7D,IAAc,OAAO,IAAI,wBAAwB,EAAO,IAAI,EAAW;EAEvE,IAAM,IAAyB;GAC7B,GAAG;GACH,cAAc,EAAc;GAC5B,UAAU;GACV,QAAQ;GACR;GACA,WAAW,EAAc,UAAU;GACnC,YAAY;GACb;AAYD,SATI,GAAM,iBAAiB,KAAA,MACzB,EAAO,eAAe,EAAK,eAGxB,EAAW,aACd,EAAc,SAGhB,EAAc,aAAa,EAAO,EAC3B;;AAGT,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;AAIH,SAAgB,eAAe,GAA8D;AAC3F,QACE,OAAO,KAAc,cACrB,KACA,kBAAkB,KAClB,mBAAmB"}
@@ -0,0 +1,36 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ import { _defineProperty as e } from "../_virtual/_@oxc-project_runtime@0.115.0/helpers/defineProperty.mjs";
3
+ import { FieldType as t } from "@vue-skuilder/common";
4
+ //#region src/composables/Displayable.ts
5
+ function isDefineComponent(e) {
6
+ return e.__isFragment !== void 0;
7
+ }
8
+ var Displayable = class {
9
+ constructor(e) {
10
+ if (e.length === 0) throw Error("\nDisplayable Constructor was called with no view Data.\n ");
11
+ validateData(this.dataShapes(), e);
12
+ }
13
+ };
14
+ e(Displayable, "dataShapes", void 0), e(Displayable, "views", void 0), e(Displayable, "seedData", void 0), e(Displayable, "acceptsUserData", !0), e(Displayable, "seedMeta", void 0);
15
+ function validateData(e, n) {
16
+ for (let r = 0; r < e.length; r++) e[r].fields.forEach((e, i) => {
17
+ console.log(`[Displayable] shape[${r}].field[${i}]:\n ${JSON.stringify(e)}`), n[r][e.name] === void 0 && e.type !== t.MEDIA_UPLOADS && console.warn("[Displayable] missing data");
18
+ });
19
+ }
20
+ var Question = class extends Displayable {
21
+ displayedSkill(e, t) {
22
+ console.warn("Question is running the reference implementation of displayedSkill.\n Consider overriding!");
23
+ let n = 5e3, r = Math.min(t, 10 * n), i = r / n, a = r > n ? .8 ** i : 1, o = this.isCorrect(e) ? 1 : 0;
24
+ return o *= a, Math.min(o, 1);
25
+ }
26
+ evaluate(e, t) {
27
+ return {
28
+ isCorrect: this.isCorrect(e),
29
+ performance: this.displayedSkill(e, t)
30
+ };
31
+ }
32
+ };
33
+ //#endregion
34
+ export { Displayable, Question, isDefineComponent };
35
+
36
+ //# sourceMappingURL=Displayable.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Displayable.mjs","names":[],"sources":["../../src/composables/Displayable.ts"],"sourcesContent":["import { type DefineComponent, defineComponent } from 'vue';\nimport { FieldType, DataShape, ViewData, Answer, Evaluation, SeedMeta } from '@vue-skuilder/common';\n\n// [ ] #vue3 - post migration, specify this more precisely (no longer a hodge-podge)\nexport type ViewComponent =\n | DefineComponent<unknown, unknown, unknown>\n | ReturnType<typeof defineComponent>;\n\nexport function isDefineComponent(\n v: ViewComponent\n): v is DefineComponent<unknown, unknown, unknown> {\n return (v as DefineComponent<unknown, unknown, unknown>).__isFragment !== undefined;\n}\n\n// export function isComponentOptions(v: ViewComponent): v is ComponentOptions<any> {\n// return (v as ComponentOptions<Vue>).name !== undefined;\n// }\n\n// tslint:disable-next-line:max-classes-per-file\nexport abstract class Displayable {\n public static dataShapes: DataShape[];\n\n public static views: Array<ViewComponent>;\n public static seedData?: Array<unknown>;\n /**\n * True if this displayable content type is meant to have\n * user-submitted questions. False if supplied seedData array\n * is comprehensive for the content type. EG, a SingleDigitAddition\n * type may comprehensively supply 0+0,0+1,...,9+9 as its seed\n * data, and not want any user input.\n */\n public static acceptsUserData: boolean = true;\n\n /**\n * Optional tags and starting ELO for the cards seeded from one seedData\n * item. Without it, seeded cards start untagged at ~1000.\n */\n public static seedMeta?: (item: unknown) => SeedMeta;\n\n /**\n *\n */\n constructor(viewData: ViewData[]) {\n if (viewData.length === 0) {\n throw new Error(`\nDisplayable Constructor was called with no view Data.\n `);\n }\n validateData(this.dataShapes(), viewData);\n }\n\n public abstract dataShapes(): DataShape[];\n public abstract views(): Array<ViewComponent>;\n}\n\nfunction validateData(shape: DataShape[], data: ViewData[]) {\n for (let i = 0; i < shape.length; i++) {\n shape[i].fields.forEach((field, j) => {\n console.log(`[Displayable] shape[${i}].field[${j}]:\\n ${JSON.stringify(field)}`);\n if (data[i][field.name] === undefined && field.type !== FieldType.MEDIA_UPLOADS) {\n // throw new Error(`field validation failed:\\n\\t${field.name}, (${field.type})`);\n console.warn(`[Displayable] missing data`);\n }\n });\n }\n}\n\n// tslint:disable-next-line:max-classes-per-file\nexport abstract class Question extends Displayable {\n /**\n * returns a yes/no evaluation of a user's answer. Informs the SRS\n * algorithm's decision to expand or reset a card's spacing\n * @param answer\n */\n protected abstract isCorrect(answer: Answer): boolean;\n /**\n * returns a number from [0,1] representing the user's performance on the question,\n * which informs elo adjustments and SRS multipliers\n *\n * @param answer the user's answer\n * @param timeSpent the time the user spent on the card in milliseconds\n * @returns a rating of the user's displayed skill, from 0-1\n */\n protected displayedSkill(answer: Answer, timeSpent: number): number {\n console.warn(`Question is running the reference implementation of displayedSkill.\n Consider overriding!`);\n // experts should answer this question in <= 5 secnods (5000 ms)\n const expertSpeed = 5000;\n const userSpeed = Math.min(timeSpent, 10 * expertSpeed);\n\n // if userResponse is > 10 x expertSpeed, discount as probably afk / distracted ?\n\n const speedPenalty = userSpeed / expertSpeed;\n const speedPenaltyMultiplier = userSpeed > expertSpeed ? Math.pow(0.8, speedPenalty) : 1;\n\n let ret = this.isCorrect(answer) ? 1 : 0;\n\n ret = ret * speedPenaltyMultiplier;\n\n return Math.min(ret, 1);\n }\n\n /**\n *\n * @param answer the student's answer\n * @param timeSpent the amount of time spent in ms\n * @returns\n */\n public evaluate(answer: Answer, timeSpent: number): Evaluation {\n return {\n isCorrect: this.isCorrect(answer),\n performance: this.displayedSkill(answer, timeSpent),\n };\n }\n\n /*\n TODO:\n\n This class and its interface are critical in this app - it defines the app's\n methodology, or its architecture of methodologies, for making inferences based on\n student performance.\n\n Some future directions:\n\n displayedSkill() should receive contextual data as well as the direct report of\n a user's interaction with this card. Context includes, eg, the status of the current\n study session (is the user on tilt? have there been leading Qs? have there been distractors?),\n the status of the user's interaction with the card (new? mature? history of resets?)\n\n displayedSkill() should reach out to a course (or just the card, or card-type?) in order to receive\n custom skill-dimension evaluators. EG: a card in the ear training course tagged 'articulation'\n could trigger a fetch of a particular evaluator fcn for articulation. In general, we\n want high-dimension evaluations.\n\n answers should be processed for the likelihood of non-substantive-incorrectness. eg,\n 7 * 4 = 8 is much more likely to be a typo than a substantive error when compared\n with 7 * 4 = 21\n */\n}\n"],"mappings":";;;;AAQA,SAAgB,kBACd,GACiD;AACjD,QAAQ,EAAiD,iBAAiB,KAAA;;AAQ5E,IAAsB,cAAtB,MAAkC;CAuBhC,YAAY,GAAsB;AAChC,MAAI,EAAS,WAAW,EACtB,OAAU,MAAM,wEAER;AAEV,eAAa,KAAK,YAAY,EAAE,EAAS;;;eA5B7B,cAAA,KAAA,EAAA,iBAEA,SAAA,KAAA,EAAA,iBACA,YAAA,KAAA,EAAA,iBAQA,mBAA2B,GAAA,iBAM3B,YAAA,KAAA,EAAA;AAkBhB,SAAS,aAAa,GAAoB,GAAkB;AAC1D,MAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,IAChC,GAAM,GAAG,OAAO,SAAS,GAAO,MAAM;AAEpC,EADA,QAAQ,IAAI,uBAAuB,EAAE,UAAU,EAAE,OAAO,KAAK,UAAU,EAAM,GAAG,EAC5E,EAAK,GAAG,EAAM,UAAU,KAAA,KAAa,EAAM,SAAS,EAAU,iBAEhE,QAAQ,KAAK,6BAA6B;GAE5C;;AAKN,IAAsB,WAAtB,cAAuC,YAAY;CAejD,eAAyB,GAAgB,GAA2B;AAClE,UAAQ,KAAK,gGACS;EAEtB,IAAM,IAAc,KACd,IAAY,KAAK,IAAI,GAAW,KAAK,EAAY,EAIjD,IAAe,IAAY,GAC3B,IAAyB,IAAY,IAAuB,MAAK,IAAgB,GAEnF,IAAM,KAAK,UAAU,EAAO,GAAG,IAAI;AAIvC,SAFA,KAAY,GAEL,KAAK,IAAI,GAAK,EAAE;;CASzB,SAAgB,GAAgB,GAA+B;AAC7D,SAAO;GACL,WAAW,KAAK,UAAU,EAAO;GACjC,aAAa,KAAK,eAAe,GAAQ,EAAU;GACpD"}
@@ -0,0 +1,38 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ import { getCurrentUser as e } from "../stores/useAuthStore.mjs";
3
+ import { computed as t, ref as n } from "vue";
4
+ //#region src/composables/useAuthUI.ts
5
+ function useAuthUI() {
6
+ let r = n(!0), i = n(!1), a = n(!1), o = t(() => a.value ? {
7
+ showLoginRegistration: !1,
8
+ showLogout: !1,
9
+ showResetData: !0,
10
+ logoutLabel: "",
11
+ resetLabel: "Reset User Data"
12
+ } : {
13
+ showLoginRegistration: !0,
14
+ showLogout: !0,
15
+ showResetData: !1,
16
+ logoutLabel: "Log out",
17
+ resetLabel: ""
18
+ }), detectSyncStrategy = async () => {
19
+ try {
20
+ r.value = !0, a.value = !(await e()).syncStrategy?.canCreateAccount?.(), i.value = !0;
21
+ } catch (e) {
22
+ console.error("Failed to detect sync strategy:", e), a.value = !1, i.value = !0;
23
+ } finally {
24
+ r.value = !1;
25
+ }
26
+ };
27
+ return {
28
+ config: o,
29
+ isLoading: r,
30
+ syncStrategyDetected: i,
31
+ isLocalOnlyMode: a,
32
+ detectSyncStrategy
33
+ };
34
+ }
35
+ //#endregion
36
+ export { useAuthUI };
37
+
38
+ //# sourceMappingURL=useAuthUI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthUI.mjs","names":[],"sources":["../../src/composables/useAuthUI.ts"],"sourcesContent":["import { ref, computed } from 'vue';\nimport { getCurrentUser } from '../stores/useAuthStore';\n\nexport interface AuthUIConfig {\n showLoginRegistration: boolean;\n showLogout: boolean;\n showResetData: boolean;\n logoutLabel: string;\n resetLabel: string;\n}\n\nexport function useAuthUI() {\n const isLoading = ref(true);\n const syncStrategyDetected = ref(false);\n const isLocalOnlyMode = ref(false);\n\n const config = computed<AuthUIConfig>(() => {\n if (isLocalOnlyMode.value) {\n return {\n showLoginRegistration: false,\n showLogout: false,\n showResetData: true,\n logoutLabel: '',\n resetLabel: 'Reset User Data',\n };\n } else {\n return {\n showLoginRegistration: true,\n showLogout: true,\n showResetData: false,\n logoutLabel: 'Log out',\n resetLabel: '',\n };\n }\n });\n\n const detectSyncStrategy = async () => {\n try {\n isLoading.value = true;\n const user = await getCurrentUser();\n \n // Access the sync strategy through the user's private syncStrategy property\n // NoOpSyncStrategy (local-only) returns false for canCreateAccount\n // CouchDBSyncStrategy (remote sync) returns true for canCreateAccount\n const userInternal = user as { syncStrategy?: { canCreateAccount?: () => boolean } };\n const canCreateAccount = userInternal.syncStrategy?.canCreateAccount?.();\n \n isLocalOnlyMode.value = !canCreateAccount;\n syncStrategyDetected.value = true;\n } catch (error) {\n console.error('Failed to detect sync strategy:', error);\n // Default to remote sync mode on error\n isLocalOnlyMode.value = false;\n syncStrategyDetected.value = true;\n } finally {\n isLoading.value = false;\n }\n };\n\n return {\n config,\n isLoading,\n syncStrategyDetected,\n isLocalOnlyMode,\n detectSyncStrategy,\n };\n}"],"mappings":";;;;AAWA,SAAgB,YAAY;CAC1B,IAAM,IAAY,EAAI,GAAK,EACrB,IAAuB,EAAI,GAAM,EACjC,IAAkB,EAAI,GAAM,EAE5B,IAAS,QACT,EAAgB,QACX;EACL,uBAAuB;EACvB,YAAY;EACZ,eAAe;EACf,aAAa;EACb,YAAY;EACb,GAEM;EACL,uBAAuB;EACvB,YAAY;EACZ,eAAe;EACf,aAAa;EACb,YAAY;EACb,CAEH,EAEI,qBAAqB,YAAY;AACrC,MAAI;AAWF,GAVA,EAAU,QAAQ,IASlB,EAAgB,QAAQ,EARX,MAAM,GAAgB,EAMG,cAAc,oBAAoB,EAGxE,EAAqB,QAAQ;WACtB,GAAO;AAId,GAHA,QAAQ,MAAM,mCAAmC,EAAM,EAEvD,EAAgB,QAAQ,IACxB,EAAqB,QAAQ;YACrB;AACR,KAAU,QAAQ;;;AAItB,QAAO;EACL;EACA;EACA;EACA;EACA;EACD"}
@@ -0,0 +1,58 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ import { getUserStatus as e } from "../services/authAPI.mjs";
3
+ import { computed as t, ref as n } from "vue";
4
+ //#region src/composables/useEntitlements.ts
5
+ function useEntitlements(r) {
6
+ let i = n({}), a = n(!1), o = n(null), s = t(() => {
7
+ let e = i.value[r];
8
+ if (!e) return {
9
+ isActive: !1,
10
+ isPaid: !1,
11
+ daysRemaining: null,
12
+ expiresDate: null
13
+ };
14
+ if (e.status === "paid") return {
15
+ isActive: !0,
16
+ isPaid: !0,
17
+ daysRemaining: null,
18
+ expiresDate: null
19
+ };
20
+ let t = e.expires;
21
+ if (!t) return {
22
+ isActive: !0,
23
+ isPaid: !1,
24
+ daysRemaining: null,
25
+ expiresDate: null
26
+ };
27
+ let n = new Date(t), a = /* @__PURE__ */ new Date(), o = Math.ceil((n.getTime() - a.getTime()) / (1e3 * 60 * 60 * 24));
28
+ return {
29
+ isActive: o > 0,
30
+ isPaid: !1,
31
+ daysRemaining: Math.max(0, o),
32
+ expiresDate: t
33
+ };
34
+ }), c = t(() => s.value.isPaid);
35
+ async function fetchEntitlements() {
36
+ a.value = !0, o.value = null;
37
+ try {
38
+ let t = await e();
39
+ t.ok ? i.value = t.entitlements || {} : (o.value = t.error || "Failed to fetch entitlements", console.error("[useEntitlements] Error:", o.value));
40
+ } catch (e) {
41
+ o.value = e instanceof Error ? e.message : "Unknown error", console.error("[useEntitlements] Exception:", e);
42
+ } finally {
43
+ a.value = !1;
44
+ }
45
+ }
46
+ return {
47
+ entitlements: i,
48
+ trialStatus: s,
49
+ hasPremiumAccess: c,
50
+ loading: a,
51
+ error: o,
52
+ fetchEntitlements
53
+ };
54
+ }
55
+ //#endregion
56
+ export { useEntitlements };
57
+
58
+ //# sourceMappingURL=useEntitlements.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEntitlements.mjs","names":[],"sources":["../../src/composables/useEntitlements.ts"],"sourcesContent":["import { ref, computed } from 'vue';\nimport { getUserStatus } from '../services/authAPI';\nimport type { Entitlement, UserEntitlements } from '../services/authAPI';\n\nexport interface TrialStatus {\n isActive: boolean;\n isPaid: boolean;\n daysRemaining: number | null;\n expiresDate: string | null;\n}\n\n/**\n * Composable for managing user entitlements and trial status\n *\n * @param courseId - The course identifier to check entitlements for\n * @returns Object with entitlements data and helper methods\n *\n * @example\n * ```typescript\n * const { trialStatus, hasPremiumAccess, fetchEntitlements, loading } = useEntitlements('letterspractice-basic');\n *\n * onMounted(async () => {\n * await fetchEntitlements();\n * console.log('Days remaining:', trialStatus.value.daysRemaining);\n * });\n * ```\n */\nexport function useEntitlements(courseId: string) {\n const entitlements = ref<UserEntitlements>({});\n const loading = ref(false);\n const error = ref<string | null>(null);\n\n /**\n * Get trial status for the specified course\n */\n const trialStatus = computed<TrialStatus>(() => {\n const entitlement: Entitlement | undefined = entitlements.value[courseId];\n\n if (!entitlement) {\n return {\n isActive: false,\n isPaid: false,\n daysRemaining: null,\n expiresDate: null,\n };\n }\n\n if (entitlement.status === 'paid') {\n return {\n isActive: true,\n isPaid: true,\n daysRemaining: null,\n expiresDate: null,\n };\n }\n\n // Trial status\n const expiresDate = entitlement.expires;\n if (!expiresDate) {\n return {\n isActive: true,\n isPaid: false,\n daysRemaining: null,\n expiresDate: null,\n };\n }\n\n const expires = new Date(expiresDate);\n const now = new Date();\n const daysLeft = Math.ceil((expires.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));\n\n return {\n isActive: daysLeft > 0,\n isPaid: false,\n daysRemaining: Math.max(0, daysLeft),\n expiresDate,\n };\n });\n\n /**\n * Whether the user has premium (paid) access to the course\n */\n const hasPremiumAccess = computed<boolean>(() => {\n return trialStatus.value.isPaid;\n });\n\n /**\n * Fetch entitlements from the backend\n */\n async function fetchEntitlements(): Promise<void> {\n loading.value = true;\n error.value = null;\n\n try {\n const result = await getUserStatus();\n if (result.ok) {\n entitlements.value = result.entitlements || {};\n } else {\n error.value = result.error || 'Failed to fetch entitlements';\n console.error('[useEntitlements] Error:', error.value);\n }\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Unknown error';\n console.error('[useEntitlements] Exception:', e);\n } finally {\n loading.value = false;\n }\n }\n\n return {\n entitlements,\n trialStatus,\n hasPremiumAccess,\n loading,\n error,\n fetchEntitlements,\n };\n}\n"],"mappings":";;;;AA2BA,SAAgB,gBAAgB,GAAkB;CAChD,IAAM,IAAe,EAAsB,EAAE,CAAC,EACxC,IAAU,EAAI,GAAM,EACpB,IAAQ,EAAmB,KAAK,EAKhC,IAAc,QAA4B;EAC9C,IAAM,IAAuC,EAAa,MAAM;AAEhE,MAAI,CAAC,EACH,QAAO;GACL,UAAU;GACV,QAAQ;GACR,eAAe;GACf,aAAa;GACd;AAGH,MAAI,EAAY,WAAW,OACzB,QAAO;GACL,UAAU;GACV,QAAQ;GACR,eAAe;GACf,aAAa;GACd;EAIH,IAAM,IAAc,EAAY;AAChC,MAAI,CAAC,EACH,QAAO;GACL,UAAU;GACV,QAAQ;GACR,eAAe;GACf,aAAa;GACd;EAGH,IAAM,IAAU,IAAI,KAAK,EAAY,EAC/B,oBAAM,IAAI,MAAM,EAChB,IAAW,KAAK,MAAM,EAAQ,SAAS,GAAG,EAAI,SAAS,KAAK,MAAO,KAAK,KAAK,IAAI;AAEvF,SAAO;GACL,UAAU,IAAW;GACrB,QAAQ;GACR,eAAe,KAAK,IAAI,GAAG,EAAS;GACpC;GACD;GACD,EAKI,IAAmB,QAChB,EAAY,MAAM,OACzB;CAKF,eAAe,oBAAmC;AAEhD,EADA,EAAQ,QAAQ,IAChB,EAAM,QAAQ;AAEd,MAAI;GACF,IAAM,IAAS,MAAM,GAAe;AACpC,GAAI,EAAO,KACT,EAAa,QAAQ,EAAO,gBAAgB,EAAE,IAE9C,EAAM,QAAQ,EAAO,SAAS,gCAC9B,QAAQ,MAAM,4BAA4B,EAAM,MAAM;WAEjD,GAAG;AAEV,GADA,EAAM,QAAQ,aAAa,QAAQ,EAAE,UAAU,iBAC/C,QAAQ,MAAM,gCAAgC,EAAE;YACxC;AACR,KAAQ,QAAQ;;;AAIpB,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD"}
package/dist/index.mjs ADDED
@@ -0,0 +1,49 @@
1
+ import e from "./components/HeatMap.mjs";
2
+ import { SkldrMouseTrap as t } from "./utils/SkldrMouseTrap.mjs";
3
+ import n from "./components/SkMouseTrap.mjs";
4
+ import r from "./components/SkMouseTrapToolTip.mjs";
5
+ import { alertUser as i } from "./components/SnackbarService.mjs";
6
+ import a from "./components/SnackbarService2.mjs";
7
+ import o from "./components/PaginatingToolbar.mjs";
8
+ import s from "./components/CardSearch.mjs";
9
+ import c from "./components/CardSearchResults.mjs";
10
+ import l from "./components/CardHistoryViewer.mjs";
11
+ import { isQuestionView as u, useQuestionView as d, useViewable as f } from "./composables/CompositionViewable.mjs";
12
+ import { Displayable as p, Question as m, isDefineComponent as h } from "./composables/Displayable.mjs";
13
+ import { getUserStatus as g, requestPasswordReset as _, resetPassword as v, resolveLoginIdentifier as y, sendVerificationEmail as b, verifyEmail as x } from "./services/authAPI.mjs";
14
+ import { useEntitlements as S } from "./composables/useEntitlements.mjs";
15
+ import C from "./components/StudySessionTimer.mjs";
16
+ import w from "./components/cardRendering/CardViewer.mjs";
17
+ import T from "./components/SessionControllerDebug.mjs";
18
+ import E from "./components/StudySession.mjs";
19
+ import { piniaPlugin as D } from "./plugins/pinia.mjs";
20
+ import { useCardPreviewModeStore as O } from "./stores/useCardPreviewModeStore.mjs";
21
+ import k from "./components/studentInputs/MultipleChoiceOption.mjs";
22
+ import A from "./components/studentInputs/RadioMultipleChoice.mjs";
23
+ import j from "./components/studentInputs/TrueFalse.mjs";
24
+ import M from "./components/studentInputs/UserInputNumber.mjs";
25
+ import N from "./components/studentInputs/UserInputString.mjs";
26
+ import P from "./components/studentInputs/fillInInput.mjs";
27
+ import F from "./components/cardRendering/CardLoader.mjs";
28
+ import { containsComponent as I, isComponent as L, isInlineComponent as R, parseComponentSyntax as z, parseComponentToken as B, splitByDelimiters as V, splitParagraphToken as H, splitTextToken as U } from "./components/cardRendering/MarkdownRendererHelpers.mjs";
29
+ import W from "./components/cardRendering/AudioAutoPlayer.mjs";
30
+ import G from "./components/cardRendering/CodeBlockRenderer.mjs";
31
+ import K from "./components/cardRendering/MdTokenRenderer.mjs";
32
+ import q from "./components/cardRendering/MarkdownRenderer.mjs";
33
+ import { getCurrentUser as J, useAuthStore as Y } from "./stores/useAuthStore.mjs";
34
+ import { useConfigStore as X } from "./stores/useConfigStore.mjs";
35
+ import Z from "./components/auth/UserChip.mjs";
36
+ import Q from "./components/auth/UserLogin.mjs";
37
+ import { isPasswordValid as $, validatePassword as ee } from "./utils/passwordValidation.mjs";
38
+ import te from "./components/auth/UserRegistration.mjs";
39
+ import ne from "./components/auth/RequestPasswordReset.mjs";
40
+ import re from "./components/auth/UserLoginAndRegistrationContainer.mjs";
41
+ import ie from "./components/auth/VerifyEmail.mjs";
42
+ import ae from "./components/auth/ResetPassword.mjs";
43
+ import oe from "./components/TagsInput.mjs";
44
+ import se from "./components/CourseCardBrowser.mjs";
45
+ import ce from "./components/CourseInformation.mjs";
46
+ import le from "./components/CardBrowser.mjs";
47
+ import ue from "./components/CourseTagFilterWidget.mjs";
48
+ import de from "./components/UserTagPreferences.mjs";
49
+ export { W as AudioAutoPlayer, le as CardBrowser, l as CardHistoryViewer, F as CardLoader, s as CardSearch, c as CardSearchResults, w as CardViewer, G as CodeBlockRenderer, se as CourseCardBrowser, ce as CourseInformation, ue as CourseTagFilterWidget, p as Displayable, P as FillInInput, e as HeatMap, q as MarkdownRenderer, K as MdTokenRenderer, k as MultipleChoiceOption, o as PaginatingToolbar, m as Question, A as RadioMultipleChoice, ne as RequestPasswordReset, ae as ResetPassword, T as SessionControllerDebug, n as SkMouseTrap, r as SkMouseTrapToolTip, t as SkldrMouseTrap, a as SnackbarService, E as StudySession, C as StudySessionTimer, j as TFSelect, oe as TagsInput, Z as UserChip, M as UserInputNumber, N as UserInputString, Q as UserLogin, re as UserLoginAndRegistrationContainer, te as UserRegistration, de as UserTagPreferences, ie as VerifyEmail, i as alertUser, I as containsComponent, J as getCurrentUser, g as getUserStatus, L as isComponent, h as isDefineComponent, R as isInlineComponent, $ as isPasswordValid, u as isQuestionView, z as parseComponentSyntax, B as parseComponentToken, D as piniaPlugin, _ as requestPasswordReset, v as resetPassword, y as resolveLoginIdentifier, b as sendVerificationEmail, V as splitByDelimiters, H as splitParagraphToken, U as splitTextToken, Y as useAuthStore, O as useCardPreviewModeStore, X as useConfigStore, S as useEntitlements, d as useQuestionView, f as useViewable, ee as validatePassword, x as verifyEmail };
@@ -0,0 +1,12 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ //#region src/plugins/pinia.ts
3
+ var e = null, setPinia = (t) => {
4
+ e = t;
5
+ }, getPinia = () => e, t = { install(e, t) {
6
+ let n = t?.pinia;
7
+ n && setPinia(n);
8
+ } };
9
+ //#endregion
10
+ export { getPinia, t as piniaPlugin };
11
+
12
+ //# sourceMappingURL=pinia.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinia.mjs","names":[],"sources":["../../src/plugins/pinia.ts"],"sourcesContent":["// common-ui/src/plugins/pinia.ts\nimport { Plugin } from 'vue';\nimport { Pinia } from 'pinia';\n\n// This will hold the Pinia instance provided by the main app\nlet _pinia: Pinia | null = null;\n\nexport const setPinia = (pinia: Pinia) => {\n _pinia = pinia;\n};\n\nexport const getPinia = (): Pinia | null => {\n return _pinia;\n};\n\n// Create a plugin that the main app can use\nexport const piniaPlugin: Plugin = {\n install(_app, options) {\n const pinia = options?.pinia;\n if (pinia) {\n setPinia(pinia);\n }\n },\n};\n"],"mappings":";;AAKA,IAAI,IAAuB,MAEd,YAAY,MAAiB;AACxC,KAAS;GAGE,iBACJ,GAII,IAAsB,EACjC,QAAQ,GAAM,GAAS;CACrB,IAAM,IAAQ,GAAS;AACvB,CAAI,KACF,SAAS,EAAM;GAGpB"}
@@ -0,0 +1,159 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ //#region src/services/authAPI.ts
3
+ var getApiBase = () => {
4
+ let e = "fallback (empty string)", t = "";
5
+ if (!t && typeof window < "u" && window.__SKUILDER_CONFIG__?.apiBase) {
6
+ let n = window.__SKUILDER_CONFIG__.apiBase.replace(/\/$/, "");
7
+ t = n.startsWith("/") ? n : `/${n}`, e = "window.__SKUILDER_CONFIG__.apiBase";
8
+ }
9
+ return console.log("[authAPI] getApiBase() called"), console.log("[authAPI] source:", e), console.log("[authAPI] result:", t), t;
10
+ };
11
+ async function sendVerificationEmail(e, t, n) {
12
+ try {
13
+ let r = {
14
+ username: e,
15
+ email: t
16
+ };
17
+ n && (r.origin = n);
18
+ let i = await fetch(`${getApiBase()}/auth/send-verification`, {
19
+ method: "POST",
20
+ headers: { "Content-Type": "application/json" },
21
+ credentials: "include",
22
+ body: JSON.stringify(r)
23
+ });
24
+ if (!i.ok) {
25
+ let e = await i.text();
26
+ return console.error("Send verification email error:", e), {
27
+ ok: !1,
28
+ error: `HTTP ${i.status}: ${i.statusText}`
29
+ };
30
+ }
31
+ return await i.json();
32
+ } catch (e) {
33
+ return console.error("Send verification email fetch error:", e), {
34
+ ok: !1,
35
+ error: e instanceof Error ? e.message : "Network error"
36
+ };
37
+ }
38
+ }
39
+ async function verifyEmail(e) {
40
+ try {
41
+ let t = await fetch(`${getApiBase()}/auth/verify`, {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ credentials: "include",
45
+ body: JSON.stringify({ token: e })
46
+ });
47
+ if (!t.ok) {
48
+ let e;
49
+ try {
50
+ e = (await t.json())?.error;
51
+ } catch {}
52
+ return {
53
+ ok: !1,
54
+ error: e || `HTTP ${t.status}: ${t.statusText}`
55
+ };
56
+ }
57
+ return await t.json();
58
+ } catch (e) {
59
+ return {
60
+ ok: !1,
61
+ error: e instanceof Error ? e.message : "Network error"
62
+ };
63
+ }
64
+ }
65
+ async function resolveLoginIdentifier(e, t) {
66
+ try {
67
+ let n = await fetch(`${getApiBase()}/auth/resolve-login`, {
68
+ method: "POST",
69
+ headers: { "Content-Type": "application/json" },
70
+ credentials: "include",
71
+ body: JSON.stringify({
72
+ identifier: e,
73
+ password: t
74
+ })
75
+ });
76
+ if (!n.ok) {
77
+ let e;
78
+ try {
79
+ e = (await n.json())?.error;
80
+ } catch {}
81
+ return {
82
+ ok: !1,
83
+ status: n.status,
84
+ error: e || `HTTP ${n.status}: ${n.statusText}`
85
+ };
86
+ }
87
+ return await n.json();
88
+ } catch (e) {
89
+ return {
90
+ ok: !1,
91
+ error: e instanceof Error ? e.message : "Network error"
92
+ };
93
+ }
94
+ }
95
+ async function getUserStatus() {
96
+ try {
97
+ let e = await fetch(`${getApiBase()}/auth/status`, {
98
+ method: "GET",
99
+ headers: { "Content-Type": "application/json" },
100
+ credentials: "include"
101
+ });
102
+ return e.ok ? await e.json() : {
103
+ ok: !1,
104
+ error: `HTTP ${e.status}: ${e.statusText}`
105
+ };
106
+ } catch (e) {
107
+ return {
108
+ ok: !1,
109
+ error: e instanceof Error ? e.message : "Network error"
110
+ };
111
+ }
112
+ }
113
+ async function requestPasswordReset(e, t) {
114
+ try {
115
+ let n = { email: e };
116
+ t && (n.origin = t);
117
+ let r = await fetch(`${getApiBase()}/auth/request-reset`, {
118
+ method: "POST",
119
+ headers: { "Content-Type": "application/json" },
120
+ credentials: "include",
121
+ body: JSON.stringify(n)
122
+ });
123
+ return r.ok ? await r.json() : {
124
+ ok: !1,
125
+ error: `HTTP ${r.status}: ${r.statusText}`
126
+ };
127
+ } catch (e) {
128
+ return {
129
+ ok: !1,
130
+ error: e instanceof Error ? e.message : "Network error"
131
+ };
132
+ }
133
+ }
134
+ async function resetPassword(e, t) {
135
+ try {
136
+ let n = await fetch(`${getApiBase()}/auth/reset-password`, {
137
+ method: "POST",
138
+ headers: { "Content-Type": "application/json" },
139
+ credentials: "include",
140
+ body: JSON.stringify({
141
+ token: e,
142
+ newPassword: t
143
+ })
144
+ });
145
+ return n.ok ? await n.json() : {
146
+ ok: !1,
147
+ error: `HTTP ${n.status}: ${n.statusText}`
148
+ };
149
+ } catch (e) {
150
+ return {
151
+ ok: !1,
152
+ error: e instanceof Error ? e.message : "Network error"
153
+ };
154
+ }
155
+ }
156
+ //#endregion
157
+ export { getUserStatus, requestPasswordReset, resetPassword, resolveLoginIdentifier, sendVerificationEmail, verifyEmail };
158
+
159
+ //# sourceMappingURL=authAPI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authAPI.mjs","names":[],"sources":["../../src/services/authAPI.ts"],"sourcesContent":["/**\n * Authentication API service for interacting with Express backend auth endpoints.\n * Uses configurable API base path from environment or runtime config.\n */\n\n// Global runtime configuration (set by consuming app)\ndeclare global {\n interface Window {\n __SKUILDER_CONFIG__?: {\n apiBase?: string;\n [key: string]: unknown;\n };\n }\n}\n\n// Get API base path: check env first, then runtime config, then fallback to empty\nconst getApiBase = (): string => {\n let source = 'fallback (empty string)';\n let result = '';\n\n // Try import.meta.env first (build-time, only works in consuming app builds)\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n const base = import.meta.env.VITE_API_BASE_URL;\n if (base) {\n const cleaned = base.replace(/\\/$/, '');\n result = cleaned.startsWith('/') ? cleaned : `/${cleaned}`;\n source = 'import.meta.env.VITE_API_BASE_URL';\n }\n }\n\n // Fallback to runtime config (works in library builds)\n if (!result && typeof window !== 'undefined' && window.__SKUILDER_CONFIG__?.apiBase) {\n const base = window.__SKUILDER_CONFIG__.apiBase;\n const cleaned = base.replace(/\\/$/, '');\n result = cleaned.startsWith('/') ? cleaned : `/${cleaned}`;\n source = 'window.__SKUILDER_CONFIG__.apiBase';\n }\n\n console.log('[authAPI] getApiBase() called');\n console.log('[authAPI] source:', source);\n console.log('[authAPI] result:', result);\n\n return result;\n};\n\nexport interface AuthResponse {\n ok: boolean;\n error?: string;\n}\n\nexport interface VerifyEmailResponse extends AuthResponse {\n username?: string;\n}\n\nexport interface Entitlement {\n status: 'trial' | 'paid';\n registrationDate: string;\n purchaseDate?: string;\n expires?: string;\n}\n\nexport type UserEntitlements = Record<string, Entitlement>;\n\nexport interface UserStatusResponse extends AuthResponse {\n username?: string;\n status?: 'pending_verification' | 'verified' | 'suspended';\n email?: string | null;\n entitlements?: UserEntitlements;\n}\n\nexport interface ResolveLoginResponse extends AuthResponse {\n username?: string;\n /**\n * HTTP status of the resolve call on failure, so callers can distinguish a\n * genuine credential rejection from a system/service failure. The server\n * returns a uniform 401 for every real auth failure (unknown identifier,\n * unverified email, wrong password — no enumeration leak); anything else\n * (404 = route not deployed, 5xx, or `undefined` for a network error) means\n * the resolver itself is unavailable, not that the credentials were wrong.\n * Undefined on success.\n */\n status?: number;\n}\n\n/**\n * Triggers verification email send for a newly created account.\n *\n * @param username - Username of the newly created account\n * @param email - User's email address (passed directly to avoid race conditions with DB sync)\n * @param origin - Optional frontend origin URL (e.g., window.location.origin)\n * Used to construct the correct verification link in the email.\n * If not provided, backend falls back to APP_URL env var.\n */\nexport async function sendVerificationEmail(\n username: string,\n email: string,\n origin?: string\n): Promise<AuthResponse> {\n try {\n const body: { username: string; email: string; origin?: string } = { username, email };\n if (origin) {\n body.origin = origin;\n }\n\n const response = await fetch(`${getApiBase()}/auth/send-verification`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error('Send verification email error:', errorText);\n return {\n ok: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return await response.json();\n } catch (error) {\n console.error('Send verification email fetch error:', error);\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Network error',\n };\n }\n}\n\n/**\n * Verify user email using token from magic link.\n */\nexport async function verifyEmail(token: string): Promise<VerifyEmailResponse> {\n try {\n const response = await fetch(`${getApiBase()}/auth/verify`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n // Prefer the server's explanatory message (expired token, email already\n // verified on another account, …) over a bare HTTP status.\n let serverError: string | undefined;\n try {\n serverError = (await response.json())?.error;\n } catch {\n // non-JSON body — fall through to the generic message\n }\n return {\n ok: false,\n error: serverError || `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return await response.json();\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Network error',\n };\n }\n}\n\n/**\n * Resolve a login identifier (username OR email) to a couch username, gated on\n * the correct password. Returns the username only on success; every failure is\n * a uniform \"invalid credentials\" (no account-enumeration leak). Used by the\n * login form before calling user.login() when the identifier is an email.\n */\nexport async function resolveLoginIdentifier(\n identifier: string,\n password: string\n): Promise<ResolveLoginResponse> {\n try {\n const response = await fetch(`${getApiBase()}/auth/resolve-login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ identifier, password }),\n });\n\n if (!response.ok) {\n let serverError: string | undefined;\n try {\n serverError = (await response.json())?.error;\n } catch {\n // non-JSON body — fall through to the generic message\n }\n return {\n ok: false,\n status: response.status,\n error: serverError || `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return await response.json();\n } catch (error) {\n // Network / fetch failure — no HTTP status. Left undefined so callers treat\n // it as a system failure, not a credential rejection.\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Network error',\n };\n }\n}\n\n/**\n * Get current user's account status (verification status, email).\n * Requires valid AuthSession cookie.\n */\nexport async function getUserStatus(): Promise<UserStatusResponse> {\n try {\n const response = await fetch(`${getApiBase()}/auth/status`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return await response.json();\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Network error',\n };\n }\n}\n\n/**\n * Request password reset email for user identified by email.\n *\n * @param email - User's email address\n * @param origin - Optional frontend origin URL (e.g., window.location.origin)\n * Used to construct the correct password reset link in the email.\n * If not provided, backend falls back to APP_URL env var.\n */\nexport async function requestPasswordReset(\n email: string,\n origin?: string\n): Promise<AuthResponse> {\n try {\n const body: { email: string; origin?: string } = { email };\n if (origin) {\n body.origin = origin;\n }\n\n const response = await fetch(`${getApiBase()}/auth/request-reset`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return await response.json();\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Network error',\n };\n }\n}\n\n/**\n * Reset password using token from magic link.\n */\nexport async function resetPassword(\n token: string,\n newPassword: string\n): Promise<AuthResponse> {\n try {\n const response = await fetch(`${getApiBase()}/auth/reset-password`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ token, newPassword }),\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return await response.json();\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : 'Network error',\n };\n }\n}\n"],"mappings":";;AAgBA,IAAM,mBAA2B;CAC/B,IAAI,IAAS,2BACT,IAAS;AAab,KAAI,CAAC,KAAU,OAAO,SAAW,OAAe,OAAO,qBAAqB,SAAS;EAEnF,IAAM,IADO,OAAO,oBAAoB,QACnB,QAAQ,OAAO,GAAG;AAEvC,EADA,IAAS,EAAQ,WAAW,IAAI,GAAG,IAAU,IAAI,KACjD,IAAS;;AAOX,QAJA,QAAQ,IAAI,gCAAgC,EAC5C,QAAQ,IAAI,uBAAuB,EAAO,EAC1C,QAAQ,IAAI,uBAAuB,EAAO,EAEnC;;AAmDT,eAAsB,sBACpB,GACA,GACA,GACuB;AACvB,KAAI;EACF,IAAM,IAA6D;GAAE;GAAU;GAAO;AACtF,EAAI,MACF,EAAK,SAAS;EAGhB,IAAM,IAAW,MAAM,MAAM,GAAG,YAAY,CAAC,0BAA0B;GACrE,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,aAAa;GACb,MAAM,KAAK,UAAU,EAAK;GAC3B,CAAC;AAEF,MAAI,CAAC,EAAS,IAAI;GAChB,IAAM,IAAY,MAAM,EAAS,MAAM;AAEvC,UADA,QAAQ,MAAM,kCAAkC,EAAU,EACnD;IACL,IAAI;IACJ,OAAO,QAAQ,EAAS,OAAO,IAAI,EAAS;IAC7C;;AAGH,SAAO,MAAM,EAAS,MAAM;UACrB,GAAO;AAEd,SADA,QAAQ,MAAM,wCAAwC,EAAM,EACrD;GACL,IAAI;GACJ,OAAO,aAAiB,QAAQ,EAAM,UAAU;GACjD;;;AAOL,eAAsB,YAAY,GAA6C;AAC7E,KAAI;EACF,IAAM,IAAW,MAAM,MAAM,GAAG,YAAY,CAAC,eAAe;GAC1D,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,aAAa;GACb,MAAM,KAAK,UAAU,EAAE,UAAO,CAAC;GAChC,CAAC;AAEF,MAAI,CAAC,EAAS,IAAI;GAGhB,IAAI;AACJ,OAAI;AACF,SAAe,MAAM,EAAS,MAAM,GAAG;WACjC;AAGR,UAAO;IACL,IAAI;IACJ,OAAO,KAAe,QAAQ,EAAS,OAAO,IAAI,EAAS;IAC5D;;AAGH,SAAO,MAAM,EAAS,MAAM;UACrB,GAAO;AACd,SAAO;GACL,IAAI;GACJ,OAAO,aAAiB,QAAQ,EAAM,UAAU;GACjD;;;AAUL,eAAsB,uBACpB,GACA,GAC+B;AAC/B,KAAI;EACF,IAAM,IAAW,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB;GACjE,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,aAAa;GACb,MAAM,KAAK,UAAU;IAAE;IAAY;IAAU,CAAC;GAC/C,CAAC;AAEF,MAAI,CAAC,EAAS,IAAI;GAChB,IAAI;AACJ,OAAI;AACF,SAAe,MAAM,EAAS,MAAM,GAAG;WACjC;AAGR,UAAO;IACL,IAAI;IACJ,QAAQ,EAAS;IACjB,OAAO,KAAe,QAAQ,EAAS,OAAO,IAAI,EAAS;IAC5D;;AAGH,SAAO,MAAM,EAAS,MAAM;UACrB,GAAO;AAGd,SAAO;GACL,IAAI;GACJ,OAAO,aAAiB,QAAQ,EAAM,UAAU;GACjD;;;AAQL,eAAsB,gBAA6C;AACjE,KAAI;EACF,IAAM,IAAW,MAAM,MAAM,GAAG,YAAY,CAAC,eAAe;GAC1D,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,aAAa;GACd,CAAC;AASF,SAPK,EAAS,KAOP,MAAM,EAAS,MAAM,GANnB;GACL,IAAI;GACJ,OAAO,QAAQ,EAAS,OAAO,IAAI,EAAS;GAC7C;UAII,GAAO;AACd,SAAO;GACL,IAAI;GACJ,OAAO,aAAiB,QAAQ,EAAM,UAAU;GACjD;;;AAYL,eAAsB,qBACpB,GACA,GACuB;AACvB,KAAI;EACF,IAAM,IAA2C,EAAE,UAAO;AAC1D,EAAI,MACF,EAAK,SAAS;EAGhB,IAAM,IAAW,MAAM,MAAM,GAAG,YAAY,CAAC,sBAAsB;GACjE,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,aAAa;GACb,MAAM,KAAK,UAAU,EAAK;GAC3B,CAAC;AASF,SAPK,EAAS,KAOP,MAAM,EAAS,MAAM,GANnB;GACL,IAAI;GACJ,OAAO,QAAQ,EAAS,OAAO,IAAI,EAAS;GAC7C;UAII,GAAO;AACd,SAAO;GACL,IAAI;GACJ,OAAO,aAAiB,QAAQ,EAAM,UAAU;GACjD;;;AAOL,eAAsB,cACpB,GACA,GACuB;AACvB,KAAI;EACF,IAAM,IAAW,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB;GAClE,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,aAAa;GACb,MAAM,KAAK,UAAU;IAAE;IAAO;IAAa,CAAC;GAC7C,CAAC;AASF,SAPK,EAAS,KAOP,MAAM,EAAS,MAAM,GANnB;GACL,IAAI;GACJ,OAAO,QAAQ,EAAS,OAAO,IAAI,EAAS;GAC7C;UAII,GAAO;AACd,SAAO;GACL,IAAI;GACJ,OAAO,aAAiB,QAAQ,EAAM,UAAU;GACjD"}
@@ -0,0 +1,68 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ import { getPinia as e } from "../plugins/pinia.mjs";
3
+ import { getDataLayer as t } from "@vue-skuilder/db";
4
+ import { defineStore as n, setActivePinia as r } from "pinia";
5
+ //#region src/stores/useAuthStore.ts
6
+ async function getCurrentUser() {
7
+ let e = useAuthStore();
8
+ if (!e.onLoadComplete) {
9
+ let t = 200;
10
+ for (; !e.onLoadComplete && t > 0;) await new Promise((e) => setTimeout(e, 50)), t--;
11
+ if (!e.onLoadComplete) throw Error("User initialization timed out");
12
+ }
13
+ return t().getUserDB();
14
+ }
15
+ var useAuthStore = () => {
16
+ let i = e();
17
+ return i && r(i), n("auth", {
18
+ state: () => ({
19
+ _user: void 0,
20
+ loginAndRegistration: {
21
+ init: !1,
22
+ loggedIn: !1,
23
+ regDialogOpen: !1,
24
+ loginDialogOpen: !1
25
+ },
26
+ onLoadComplete: !1
27
+ }),
28
+ actions: {
29
+ async init() {
30
+ try {
31
+ this._user = t().getUserDB(), this.loginAndRegistration.loggedIn = this._user ? this._user.isLoggedIn() : !1, this.onLoadComplete = !0, this.loginAndRegistration.init = !0;
32
+ } catch (e) {
33
+ console.error("Failed to initialize auth store:", e), this.loginAndRegistration.loggedIn = !1, this.onLoadComplete = !0, this.loginAndRegistration.init = !0;
34
+ }
35
+ },
36
+ setLoginDialog(e) {
37
+ this.loginAndRegistration.loginDialogOpen = e;
38
+ },
39
+ setRegDialog(e) {
40
+ this.loginAndRegistration.regDialogOpen = e;
41
+ },
42
+ async resetUserData() {
43
+ try {
44
+ if (!this._user) throw Error("No user available for data reset");
45
+ let e = await this._user.resetUserData();
46
+ if (e.status !== "ok") throw Error(e.error || "Reset failed");
47
+ return console.log("User data reset successfully"), e;
48
+ } catch (e) {
49
+ throw console.error("Failed to reset user data:", e), e;
50
+ }
51
+ }
52
+ },
53
+ getters: {
54
+ currentUser: async () => getCurrentUser(),
55
+ isLoggedIn: (e) => e.loginAndRegistration.loggedIn,
56
+ isInitialized: (e) => e.loginAndRegistration.init,
57
+ status: (e) => ({
58
+ loggedIn: e.loginAndRegistration.loggedIn,
59
+ init: e.loginAndRegistration.init,
60
+ user: e._user
61
+ })
62
+ }
63
+ })();
64
+ };
65
+ //#endregion
66
+ export { getCurrentUser, useAuthStore };
67
+
68
+ //# sourceMappingURL=useAuthStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthStore.mjs","names":[],"sources":["../../src/stores/useAuthStore.ts"],"sourcesContent":["// stores/useAuthStore.ts\nimport { defineStore, setActivePinia } from 'pinia';\nimport { getDataLayer, UserDBInterface } from '@vue-skuilder/db';\nimport { getPinia } from '../plugins/pinia';\n\nexport interface AuthState {\n _user: UserDBInterface | undefined;\n loginAndRegistration: {\n init: boolean;\n loggedIn: boolean;\n regDialogOpen: boolean;\n loginDialogOpen: boolean;\n };\n onLoadComplete: boolean;\n}\n\nexport async function getCurrentUser(): Promise<UserDBInterface | undefined> {\n const store = useAuthStore();\n\n if (!store.onLoadComplete) {\n // Wait for initialization\n let retries = 200;\n const timeout = 50;\n while (!store.onLoadComplete && retries > 0) {\n await new Promise((resolve) => setTimeout(resolve, timeout));\n retries--;\n }\n if (!store.onLoadComplete) {\n throw new Error('User initialization timed out');\n }\n }\n\n return getDataLayer().getUserDB();\n}\n\nexport const useAuthStore = () => {\n // Get the Pinia instance from the plugin\n const pinia = getPinia();\n if (pinia) {\n setActivePinia(pinia);\n }\n\n // Return the store\n return defineStore('auth', {\n state: (): AuthState => ({\n _user: undefined as UserDBInterface | undefined,\n loginAndRegistration: {\n init: false,\n loggedIn: false,\n regDialogOpen: false,\n loginDialogOpen: false,\n },\n onLoadComplete: false,\n }),\n\n actions: {\n async init() {\n try {\n this._user = getDataLayer().getUserDB();\n\n this.loginAndRegistration.loggedIn = this._user ? this._user.isLoggedIn() : false;\n\n this.onLoadComplete = true;\n this.loginAndRegistration.init = true;\n } catch (e) {\n console.error('Failed to initialize auth store:', e);\n // Set onLoadComplete even on error to prevent timeout\n this.loginAndRegistration.loggedIn = false;\n this.onLoadComplete = true;\n this.loginAndRegistration.init = true;\n }\n },\n\n setLoginDialog(open: boolean) {\n this.loginAndRegistration.loginDialogOpen = open;\n },\n\n setRegDialog(open: boolean) {\n this.loginAndRegistration.regDialogOpen = open;\n },\n\n async resetUserData() {\n try {\n if (!this._user) {\n throw new Error('No user available for data reset');\n }\n \n const result = await this._user.resetUserData();\n if (result.status !== 'ok') {\n throw new Error(result.error || 'Reset failed');\n }\n \n console.log('User data reset successfully');\n return result;\n } catch (error) {\n console.error('Failed to reset user data:', error);\n throw error;\n }\n },\n },\n\n getters: {\n currentUser: async () => getCurrentUser(),\n isLoggedIn: (state) => state.loginAndRegistration.loggedIn,\n isInitialized: (state) => state.loginAndRegistration.init,\n status: (state) => {\n return {\n loggedIn: state.loginAndRegistration.loggedIn,\n init: state.loginAndRegistration.init,\n user: state._user,\n };\n },\n },\n })();\n};\n"],"mappings":";;;;;AAgBA,eAAsB,iBAAuD;CAC3E,IAAM,IAAQ,cAAc;AAE5B,KAAI,CAAC,EAAM,gBAAgB;EAEzB,IAAI,IAAU;AAEd,SAAO,CAAC,EAAM,kBAAkB,IAAU,GAExC,CADA,MAAM,IAAI,SAAS,MAAY,WAAW,GAAS,GAAQ,CAAC,EAC5D;AAEF,MAAI,CAAC,EAAM,eACT,OAAU,MAAM,gCAAgC;;AAIpD,QAAO,GAAc,CAAC,WAAW;;AAGnC,IAAa,qBAAqB;CAEhC,IAAM,IAAQ,GAAU;AAMxB,QALI,KACF,EAAe,EAAM,EAIhB,EAAY,QAAQ;EACzB,cAAyB;GACvB,OAAO,KAAA;GACP,sBAAsB;IACpB,MAAM;IACN,UAAU;IACV,eAAe;IACf,iBAAiB;IAClB;GACD,gBAAgB;GACjB;EAED,SAAS;GACP,MAAM,OAAO;AACX,QAAI;AAMF,KALA,KAAK,QAAQ,GAAc,CAAC,WAAW,EAEvC,KAAK,qBAAqB,WAAW,KAAK,QAAQ,KAAK,MAAM,YAAY,GAAG,IAE5E,KAAK,iBAAiB,IACtB,KAAK,qBAAqB,OAAO;aAC1B,GAAG;AAKV,KAJA,QAAQ,MAAM,oCAAoC,EAAE,EAEpD,KAAK,qBAAqB,WAAW,IACrC,KAAK,iBAAiB,IACtB,KAAK,qBAAqB,OAAO;;;GAIrC,eAAe,GAAe;AAC5B,SAAK,qBAAqB,kBAAkB;;GAG9C,aAAa,GAAe;AAC1B,SAAK,qBAAqB,gBAAgB;;GAG5C,MAAM,gBAAgB;AACpB,QAAI;AACF,SAAI,CAAC,KAAK,MACR,OAAU,MAAM,mCAAmC;KAGrD,IAAM,IAAS,MAAM,KAAK,MAAM,eAAe;AAC/C,SAAI,EAAO,WAAW,KACpB,OAAU,MAAM,EAAO,SAAS,eAAe;AAIjD,YADA,QAAQ,IAAI,+BAA+B,EACpC;aACA,GAAO;AAEd,WADA,QAAQ,MAAM,8BAA8B,EAAM,EAC5C;;;GAGX;EAED,SAAS;GACP,aAAa,YAAY,gBAAgB;GACzC,aAAa,MAAU,EAAM,qBAAqB;GAClD,gBAAgB,MAAU,EAAM,qBAAqB;GACrD,SAAS,OACA;IACL,UAAU,EAAM,qBAAqB;IACrC,MAAM,EAAM,qBAAqB;IACjC,MAAM,EAAM;IACb;GAEJ;EACF,CAAC,EAAE"}
@@ -0,0 +1,20 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ import { getPinia as e } from "../plugins/pinia.mjs";
3
+ import { defineStore as t, setActivePinia as n } from "pinia";
4
+ //#region src/stores/useCardPreviewModeStore.ts
5
+ var useCardPreviewModeStore = () => {
6
+ let r = e();
7
+ return r && n(r), t("previewMode", {
8
+ state: () => ({ previewMode: !1 }),
9
+ actions: { setPreviewMode(e) {
10
+ this.previewMode = e;
11
+ } },
12
+ getters: { isPreviewMode() {
13
+ return this.previewMode;
14
+ } }
15
+ })();
16
+ };
17
+ //#endregion
18
+ export { useCardPreviewModeStore };
19
+
20
+ //# sourceMappingURL=useCardPreviewModeStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCardPreviewModeStore.mjs","names":[],"sources":["../../src/stores/useCardPreviewModeStore.ts"],"sourcesContent":["// common-ui/src/stores/useCardPreviewModeStore.ts\nimport { defineStore, setActivePinia } from 'pinia';\nimport { getPinia } from '../plugins/pinia';\n\nexport interface PreviewModeState {\n previewMode: boolean;\n}\n\nexport const useCardPreviewModeStore = () => {\n // Get the Pinia instance from the plugin\n const pinia = getPinia();\n if (pinia) {\n setActivePinia(pinia);\n }\n\n // Return the store\n return defineStore('previewMode', {\n state: (): PreviewModeState => ({\n previewMode: false,\n }),\n actions: {\n setPreviewMode(mode: boolean) {\n this.previewMode = mode;\n },\n },\n getters: {\n isPreviewMode(): boolean {\n return this.previewMode;\n },\n },\n })();\n};\n"],"mappings":";;;;AAQA,IAAa,gCAAgC;CAE3C,IAAM,IAAQ,GAAU;AAMxB,QALI,KACF,EAAe,EAAM,EAIhB,EAAY,eAAe;EAChC,cAAgC,EAC9B,aAAa,IACd;EACD,SAAS,EACP,eAAe,GAAe;AAC5B,QAAK,cAAc;KAEtB;EACD,SAAS,EACP,gBAAyB;AACvB,UAAO,KAAK;KAEf;EACF,CAAC,EAAE"}
@@ -0,0 +1,60 @@
1
+ import "../_virtual/_rolldown/runtime.mjs";
2
+ import { getPinia as e } from "../plugins/pinia.mjs";
3
+ import { getCurrentUser as t } from "./useAuthStore.mjs";
4
+ import { defineStore as n, setActivePinia as r } from "pinia";
5
+ //#region src/stores/useConfigStore.ts
6
+ var useConfigStore = () => {
7
+ let i = e();
8
+ return i && r(i), n("config", {
9
+ state: () => ({ config: {
10
+ darkMode: !1,
11
+ likesConfetti: !1,
12
+ sessionTimeLimit: 5
13
+ } }),
14
+ actions: {
15
+ updateConfig(e) {
16
+ this.config = e;
17
+ },
18
+ async updateDarkMode(e) {
19
+ this.config.darkMode = e;
20
+ let n = await t();
21
+ n && await n.setConfig({ darkMode: e });
22
+ },
23
+ async updateLikesConfetti(e) {
24
+ this.config.likesConfetti = e;
25
+ let n = await t();
26
+ n && await n.setConfig({ likesConfetti: e });
27
+ },
28
+ async updateSessionTimeLimit(e) {
29
+ this.config.sessionTimeLimit = e;
30
+ let n = await t();
31
+ n && await n.setConfig({ sessionTimeLimit: e });
32
+ },
33
+ async hydrate() {
34
+ try {
35
+ let e = await t();
36
+ if (e) {
37
+ let t = await e.getConfig();
38
+ console.log(`user config: ${JSON.stringify(t)}`), this.updateConfig(t);
39
+ } else console.log("No user logged in, using default config");
40
+ } catch (e) {
41
+ console.warn("Failed to hydrate config store, using defaults:", e);
42
+ }
43
+ },
44
+ async init() {
45
+ await this.hydrate();
46
+ },
47
+ resetDefaults() {
48
+ this.config = {
49
+ darkMode: !1,
50
+ likesConfetti: !1,
51
+ sessionTimeLimit: 5
52
+ };
53
+ }
54
+ }
55
+ })();
56
+ };
57
+ //#endregion
58
+ export { useConfigStore };
59
+
60
+ //# sourceMappingURL=useConfigStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConfigStore.mjs","names":[],"sources":["../../src/stores/useConfigStore.ts"],"sourcesContent":["// stores/useConfigStore.ts\nimport { defineStore, setActivePinia } from 'pinia';\nimport { getCurrentUser } from './useAuthStore';\nimport { UserConfig } from '@vue-skuilder/db';\nimport { getPinia } from '../plugins/pinia';\n\nexport const useConfigStore = () => {\n // Get the Pinia instance from the plugin\n const pinia = getPinia();\n if (pinia) {\n setActivePinia(pinia);\n }\n\n // Return the store\n return defineStore('config', {\n state: () => ({\n config: {\n darkMode: false,\n likesConfetti: false,\n sessionTimeLimit: 5, // Default 5 minutes\n } as UserConfig,\n }),\n\n actions: {\n updateConfig(newConfig: UserConfig) {\n this.config = newConfig;\n },\n async updateDarkMode(darkMode: boolean) {\n this.config.darkMode = darkMode;\n const user = await getCurrentUser();\n if (user) {\n await user.setConfig({\n darkMode,\n });\n }\n },\n\n async updateLikesConfetti(likesConfetti: boolean) {\n this.config.likesConfetti = likesConfetti;\n const user = await getCurrentUser();\n if (user) {\n await user.setConfig({\n likesConfetti,\n });\n }\n },\n\n async updateSessionTimeLimit(sessionTimeLimit: number) {\n this.config.sessionTimeLimit = sessionTimeLimit;\n const user = await getCurrentUser();\n if (user) {\n await user.setConfig({\n sessionTimeLimit,\n });\n }\n },\n\n async hydrate() {\n try {\n const user = await getCurrentUser();\n if (user) {\n const cfg = await user.getConfig();\n console.log(`user config: ${JSON.stringify(cfg)}`);\n this.updateConfig(cfg);\n } else {\n console.log('No user logged in, using default config');\n }\n } catch (e) {\n console.warn('Failed to hydrate config store, using defaults:', e);\n }\n },\n async init() {\n await this.hydrate();\n },\n resetDefaults() {\n this.config = {\n darkMode: false,\n likesConfetti: false,\n sessionTimeLimit: 5,\n };\n },\n },\n })();\n};\n"],"mappings":";;;;;AAMA,IAAa,uBAAuB;CAElC,IAAM,IAAQ,GAAU;AAMxB,QALI,KACF,EAAe,EAAM,EAIhB,EAAY,UAAU;EAC3B,cAAc,EACZ,QAAQ;GACN,UAAU;GACV,eAAe;GACf,kBAAkB;GACnB,EACF;EAED,SAAS;GACP,aAAa,GAAuB;AAClC,SAAK,SAAS;;GAEhB,MAAM,eAAe,GAAmB;AACtC,SAAK,OAAO,WAAW;IACvB,IAAM,IAAO,MAAM,GAAgB;AACnC,IAAI,KACF,MAAM,EAAK,UAAU,EACnB,aACD,CAAC;;GAIN,MAAM,oBAAoB,GAAwB;AAChD,SAAK,OAAO,gBAAgB;IAC5B,IAAM,IAAO,MAAM,GAAgB;AACnC,IAAI,KACF,MAAM,EAAK,UAAU,EACnB,kBACD,CAAC;;GAIN,MAAM,uBAAuB,GAA0B;AACrD,SAAK,OAAO,mBAAmB;IAC/B,IAAM,IAAO,MAAM,GAAgB;AACnC,IAAI,KACF,MAAM,EAAK,UAAU,EACnB,qBACD,CAAC;;GAIN,MAAM,UAAU;AACd,QAAI;KACF,IAAM,IAAO,MAAM,GAAgB;AACnC,SAAI,GAAM;MACR,IAAM,IAAM,MAAM,EAAK,WAAW;AAElC,MADA,QAAQ,IAAI,gBAAgB,KAAK,UAAU,EAAI,GAAG,EAClD,KAAK,aAAa,EAAI;WAEtB,SAAQ,IAAI,0CAA0C;aAEjD,GAAG;AACV,aAAQ,KAAK,mDAAmD,EAAE;;;GAGtE,MAAM,OAAO;AACX,UAAM,KAAK,SAAS;;GAEtB,gBAAgB;AACd,SAAK,SAAS;KACZ,UAAU;KACV,eAAe;KACf,kBAAkB;KACnB;;GAEJ;EACF,CAAC,EAAE"}