@morscherlab/mld-sdk 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (714) hide show
  1. package/README.md +326 -0
  2. package/dist/__tests__/components/AppLayout.test.d.ts +1 -0
  3. package/dist/__tests__/components/AppSidebar.test.d.ts +1 -0
  4. package/dist/__tests__/components/AppTopBar.test.d.ts +1 -0
  5. package/dist/__tests__/components/BaseInput.test.d.ts +1 -0
  6. package/dist/__tests__/components/BasePill.test.d.ts +1 -0
  7. package/dist/__tests__/components/Calendar.test.d.ts +1 -0
  8. package/dist/__tests__/components/CollapsibleCard.test.d.ts +1 -0
  9. package/dist/__tests__/components/DataFrame.test.d.ts +1 -0
  10. package/dist/__tests__/components/DropdownButton.test.d.ts +1 -0
  11. package/dist/__tests__/composables/useAuth.test.d.ts +1 -0
  12. package/dist/__tests__/composables/useForm.test.d.ts +1 -0
  13. package/dist/components/AlertBox.vue.d.ts +30 -0
  14. package/dist/components/AlertBox.vue.js +125 -0
  15. package/dist/components/AlertBox.vue.js.map +1 -0
  16. package/dist/components/AlertBox.vue3.js +6 -0
  17. package/dist/components/AlertBox.vue3.js.map +1 -0
  18. package/dist/components/AppContainer.vue.d.ts +28 -0
  19. package/dist/components/AppContainer.vue.js +28 -0
  20. package/dist/components/AppContainer.vue.js.map +1 -0
  21. package/dist/components/AppContainer.vue2.js +5 -0
  22. package/dist/components/AppContainer.vue2.js.map +1 -0
  23. package/dist/components/AppLayout.vue.d.ts +31 -0
  24. package/dist/components/AppLayout.vue.js +51 -0
  25. package/dist/components/AppLayout.vue.js.map +1 -0
  26. package/dist/components/AppLayout.vue3.js +6 -0
  27. package/dist/components/AppLayout.vue3.js.map +1 -0
  28. package/dist/components/AppSidebar.vue.d.ts +44 -0
  29. package/dist/components/AppSidebar.vue.js +79 -0
  30. package/dist/components/AppSidebar.vue.js.map +1 -0
  31. package/dist/components/AppSidebar.vue3.js +6 -0
  32. package/dist/components/AppSidebar.vue3.js.map +1 -0
  33. package/dist/components/AppTopBar.vue.d.ts +77 -0
  34. package/dist/components/AppTopBar.vue.js +564 -0
  35. package/dist/components/AppTopBar.vue.js.map +1 -0
  36. package/dist/components/AppTopBar.vue3.js +6 -0
  37. package/dist/components/AppTopBar.vue3.js.map +1 -0
  38. package/dist/components/AuditTrail.vue.d.ts +47 -0
  39. package/dist/components/AuditTrail.vue.js +189 -0
  40. package/dist/components/AuditTrail.vue.js.map +1 -0
  41. package/dist/components/AuditTrail.vue3.js +6 -0
  42. package/dist/components/AuditTrail.vue3.js.map +1 -0
  43. package/dist/components/Avatar.vue.d.ts +13 -0
  44. package/dist/components/Avatar.vue.js +64 -0
  45. package/dist/components/Avatar.vue.js.map +1 -0
  46. package/dist/components/Avatar.vue3.js +6 -0
  47. package/dist/components/Avatar.vue3.js.map +1 -0
  48. package/dist/components/BaseButton.vue.d.ts +37 -0
  49. package/dist/components/BaseButton.vue.js +64 -0
  50. package/dist/components/BaseButton.vue.js.map +1 -0
  51. package/dist/components/BaseButton.vue3.js +6 -0
  52. package/dist/components/BaseButton.vue3.js.map +1 -0
  53. package/dist/components/BaseCheckbox.vue.d.ts +16 -0
  54. package/dist/components/BaseCheckbox.vue.js +71 -0
  55. package/dist/components/BaseCheckbox.vue.js.map +1 -0
  56. package/dist/components/BaseCheckbox.vue3.js +6 -0
  57. package/dist/components/BaseCheckbox.vue3.js.map +1 -0
  58. package/dist/components/BaseInput.vue.d.ts +33 -0
  59. package/dist/components/BaseInput.vue.js +57 -0
  60. package/dist/components/BaseInput.vue.js.map +1 -0
  61. package/dist/components/BaseInput.vue3.js +6 -0
  62. package/dist/components/BaseInput.vue3.js.map +1 -0
  63. package/dist/components/BaseModal.vue.d.ts +38 -0
  64. package/dist/components/BaseModal.vue.js +118 -0
  65. package/dist/components/BaseModal.vue.js.map +1 -0
  66. package/dist/components/BaseModal.vue3.js +6 -0
  67. package/dist/components/BaseModal.vue3.js.map +1 -0
  68. package/dist/components/BasePill.vue.d.ts +54 -0
  69. package/dist/components/BasePill.vue.js +68 -0
  70. package/dist/components/BasePill.vue.js.map +1 -0
  71. package/dist/components/BasePill.vue3.js +6 -0
  72. package/dist/components/BasePill.vue3.js.map +1 -0
  73. package/dist/components/BaseRadioGroup.vue.d.ts +19 -0
  74. package/dist/components/BaseRadioGroup.vue.js +80 -0
  75. package/dist/components/BaseRadioGroup.vue.js.map +1 -0
  76. package/dist/components/BaseRadioGroup.vue3.js +6 -0
  77. package/dist/components/BaseRadioGroup.vue3.js.map +1 -0
  78. package/dist/components/BaseSelect.vue.d.ts +19 -0
  79. package/dist/components/BaseSelect.vue.js +70 -0
  80. package/dist/components/BaseSelect.vue.js.map +1 -0
  81. package/dist/components/BaseSelect.vue3.js +6 -0
  82. package/dist/components/BaseSelect.vue3.js.map +1 -0
  83. package/dist/components/BaseSlider.vue.d.ts +22 -0
  84. package/dist/components/BaseSlider.vue.js +97 -0
  85. package/dist/components/BaseSlider.vue.js.map +1 -0
  86. package/dist/components/BaseSlider.vue3.js +6 -0
  87. package/dist/components/BaseSlider.vue3.js.map +1 -0
  88. package/dist/components/BaseTabs.vue.d.ts +14 -0
  89. package/dist/components/BaseTabs.vue.js +63 -0
  90. package/dist/components/BaseTabs.vue.js.map +1 -0
  91. package/dist/components/BaseTabs.vue3.js +6 -0
  92. package/dist/components/BaseTabs.vue3.js.map +1 -0
  93. package/dist/components/BaseTextarea.vue.d.ts +28 -0
  94. package/dist/components/BaseTextarea.vue.js +49 -0
  95. package/dist/components/BaseTextarea.vue.js.map +1 -0
  96. package/dist/components/BaseTextarea.vue3.js +6 -0
  97. package/dist/components/BaseTextarea.vue3.js.map +1 -0
  98. package/dist/components/BaseToggle.vue.d.ts +16 -0
  99. package/dist/components/BaseToggle.vue.js +65 -0
  100. package/dist/components/BaseToggle.vue.js.map +1 -0
  101. package/dist/components/BaseToggle.vue3.js +6 -0
  102. package/dist/components/BaseToggle.vue3.js.map +1 -0
  103. package/dist/components/BatchProgressList.vue.d.ts +59 -0
  104. package/dist/components/BatchProgressList.vue.js +250 -0
  105. package/dist/components/BatchProgressList.vue.js.map +1 -0
  106. package/dist/components/BatchProgressList.vue3.js +6 -0
  107. package/dist/components/BatchProgressList.vue3.js.map +1 -0
  108. package/dist/components/Breadcrumb.vue.d.ts +37 -0
  109. package/dist/components/Breadcrumb.vue.js +71 -0
  110. package/dist/components/Breadcrumb.vue.js.map +1 -0
  111. package/dist/components/Breadcrumb.vue3.js +6 -0
  112. package/dist/components/Breadcrumb.vue3.js.map +1 -0
  113. package/dist/components/Calendar.vue.d.ts +107 -0
  114. package/dist/components/Calendar.vue.js +328 -0
  115. package/dist/components/Calendar.vue.js.map +1 -0
  116. package/dist/components/Calendar.vue3.js +6 -0
  117. package/dist/components/Calendar.vue3.js.map +1 -0
  118. package/dist/components/ChartContainer.vue.d.ts +31 -0
  119. package/dist/components/ChartContainer.vue.js +78 -0
  120. package/dist/components/ChartContainer.vue.js.map +1 -0
  121. package/dist/components/ChartContainer.vue3.js +6 -0
  122. package/dist/components/ChartContainer.vue3.js.map +1 -0
  123. package/dist/components/ChemicalFormula.vue.d.ts +8 -0
  124. package/dist/components/ChemicalFormula.vue.js +57 -0
  125. package/dist/components/ChemicalFormula.vue.js.map +1 -0
  126. package/dist/components/ChemicalFormula.vue3.js +6 -0
  127. package/dist/components/ChemicalFormula.vue3.js.map +1 -0
  128. package/dist/components/CollapsibleCard.vue.d.ts +39 -0
  129. package/dist/components/CollapsibleCard.vue.js +175 -0
  130. package/dist/components/CollapsibleCard.vue.js.map +1 -0
  131. package/dist/components/CollapsibleCard.vue3.js +6 -0
  132. package/dist/components/CollapsibleCard.vue3.js.map +1 -0
  133. package/dist/components/ColorSlider.vue.d.ts +34 -0
  134. package/dist/components/ColorSlider.vue.js +131 -0
  135. package/dist/components/ColorSlider.vue.js.map +1 -0
  136. package/dist/components/ColorSlider.vue3.js +6 -0
  137. package/dist/components/ColorSlider.vue3.js.map +1 -0
  138. package/dist/components/ConcentrationInput.vue.d.ts +25 -0
  139. package/dist/components/ConcentrationInput.vue.js +161 -0
  140. package/dist/components/ConcentrationInput.vue.js.map +1 -0
  141. package/dist/components/ConcentrationInput.vue3.js +6 -0
  142. package/dist/components/ConcentrationInput.vue3.js.map +1 -0
  143. package/dist/components/ConfirmDialog.vue.d.ts +41 -0
  144. package/dist/components/ConfirmDialog.vue.js +140 -0
  145. package/dist/components/ConfirmDialog.vue.js.map +1 -0
  146. package/dist/components/ConfirmDialog.vue3.js +6 -0
  147. package/dist/components/ConfirmDialog.vue3.js.map +1 -0
  148. package/dist/components/DataFrame.vue.d.ts +107 -0
  149. package/dist/components/DataFrame.vue.js +430 -0
  150. package/dist/components/DataFrame.vue.js.map +1 -0
  151. package/dist/components/DataFrame.vue3.js +6 -0
  152. package/dist/components/DataFrame.vue3.js.map +1 -0
  153. package/dist/components/DatePicker.vue.d.ts +23 -0
  154. package/dist/components/DatePicker.vue.js +278 -0
  155. package/dist/components/DatePicker.vue.js.map +1 -0
  156. package/dist/components/DatePicker.vue3.js +6 -0
  157. package/dist/components/DatePicker.vue3.js.map +1 -0
  158. package/dist/components/DateTimePicker.vue.d.ts +30 -0
  159. package/dist/components/DateTimePicker.vue.js +413 -0
  160. package/dist/components/DateTimePicker.vue.js.map +1 -0
  161. package/dist/components/DateTimePicker.vue3.js +6 -0
  162. package/dist/components/DateTimePicker.vue3.js.map +1 -0
  163. package/dist/components/Divider.vue.d.ts +11 -0
  164. package/dist/components/Divider.vue.js +42 -0
  165. package/dist/components/Divider.vue.js.map +1 -0
  166. package/dist/components/Divider.vue3.js +6 -0
  167. package/dist/components/Divider.vue3.js.map +1 -0
  168. package/dist/components/DoseCalculator.vue.d.ts +19 -0
  169. package/dist/components/DoseCalculator.vue.js +470 -0
  170. package/dist/components/DoseCalculator.vue.js.map +1 -0
  171. package/dist/components/DoseCalculator.vue3.js +6 -0
  172. package/dist/components/DoseCalculator.vue3.js.map +1 -0
  173. package/dist/components/DropdownButton.vue.d.ts +47 -0
  174. package/dist/components/DropdownButton.vue.js +171 -0
  175. package/dist/components/DropdownButton.vue.js.map +1 -0
  176. package/dist/components/DropdownButton.vue3.js +6 -0
  177. package/dist/components/DropdownButton.vue3.js.map +1 -0
  178. package/dist/components/EmptyState.vue.d.ts +33 -0
  179. package/dist/components/EmptyState.vue.js +80 -0
  180. package/dist/components/EmptyState.vue.js.map +1 -0
  181. package/dist/components/EmptyState.vue3.js +6 -0
  182. package/dist/components/EmptyState.vue3.js.map +1 -0
  183. package/dist/components/ExperimentTimeline.vue.d.ts +44 -0
  184. package/dist/components/ExperimentTimeline.vue.js +395 -0
  185. package/dist/components/ExperimentTimeline.vue.js.map +1 -0
  186. package/dist/components/ExperimentTimeline.vue3.js +6 -0
  187. package/dist/components/ExperimentTimeline.vue3.js.map +1 -0
  188. package/dist/components/FileUploader.vue.d.ts +23 -0
  189. package/dist/components/FileUploader.vue.js +416 -0
  190. package/dist/components/FileUploader.vue.js.map +1 -0
  191. package/dist/components/FileUploader.vue3.js +6 -0
  192. package/dist/components/FileUploader.vue3.js.map +1 -0
  193. package/dist/components/FormField.vue.d.ts +24 -0
  194. package/dist/components/FormField.vue.js +45 -0
  195. package/dist/components/FormField.vue.js.map +1 -0
  196. package/dist/components/FormField.vue3.js +6 -0
  197. package/dist/components/FormField.vue3.js.map +1 -0
  198. package/dist/components/FormulaInput.vue.d.ts +25 -0
  199. package/dist/components/FormulaInput.vue.js +121 -0
  200. package/dist/components/FormulaInput.vue.js.map +1 -0
  201. package/dist/components/FormulaInput.vue3.js +6 -0
  202. package/dist/components/FormulaInput.vue3.js.map +1 -0
  203. package/dist/components/GroupAssigner.vue.d.ts +25 -0
  204. package/dist/components/GroupAssigner.vue.js +311 -0
  205. package/dist/components/GroupAssigner.vue.js.map +1 -0
  206. package/dist/components/GroupAssigner.vue3.js +6 -0
  207. package/dist/components/GroupAssigner.vue3.js.map +1 -0
  208. package/dist/components/GroupingModal.vue.d.ts +12 -0
  209. package/dist/components/GroupingModal.vue.js +446 -0
  210. package/dist/components/GroupingModal.vue.js.map +1 -0
  211. package/dist/components/GroupingModal.vue3.js +6 -0
  212. package/dist/components/GroupingModal.vue3.js.map +1 -0
  213. package/dist/components/IconButton.vue.d.ts +34 -0
  214. package/dist/components/IconButton.vue.js +67 -0
  215. package/dist/components/IconButton.vue.js.map +1 -0
  216. package/dist/components/IconButton.vue3.js +6 -0
  217. package/dist/components/IconButton.vue3.js.map +1 -0
  218. package/dist/components/LoadingSpinner.vue.d.ts +11 -0
  219. package/dist/components/LoadingSpinner.vue.js +47 -0
  220. package/dist/components/LoadingSpinner.vue.js.map +1 -0
  221. package/dist/components/LoadingSpinner.vue3.js +6 -0
  222. package/dist/components/LoadingSpinner.vue3.js.map +1 -0
  223. package/dist/components/MoleculeInput.vue.d.ts +30 -0
  224. package/dist/components/MoleculeInput.vue.js +327 -0
  225. package/dist/components/MoleculeInput.vue.js.map +1 -0
  226. package/dist/components/MoleculeInput.vue3.js +6 -0
  227. package/dist/components/MoleculeInput.vue3.js.map +1 -0
  228. package/dist/components/MultiSelect.vue.d.ts +19 -0
  229. package/dist/components/MultiSelect.vue.js +109 -0
  230. package/dist/components/MultiSelect.vue.js.map +1 -0
  231. package/dist/components/MultiSelect.vue3.js +6 -0
  232. package/dist/components/MultiSelect.vue3.js.map +1 -0
  233. package/dist/components/NumberInput.vue.d.ts +21 -0
  234. package/dist/components/NumberInput.vue.js +133 -0
  235. package/dist/components/NumberInput.vue.js.map +1 -0
  236. package/dist/components/NumberInput.vue3.js +6 -0
  237. package/dist/components/NumberInput.vue3.js.map +1 -0
  238. package/dist/components/PlateMapEditor.vue.d.ts +50 -0
  239. package/dist/components/PlateMapEditor.vue.js +480 -0
  240. package/dist/components/PlateMapEditor.vue.js.map +1 -0
  241. package/dist/components/PlateMapEditor.vue3.js +6 -0
  242. package/dist/components/PlateMapEditor.vue3.js.map +1 -0
  243. package/dist/components/ProgressBar.vue.d.ts +17 -0
  244. package/dist/components/ProgressBar.vue.js +65 -0
  245. package/dist/components/ProgressBar.vue.js.map +1 -0
  246. package/dist/components/ProgressBar.vue3.js +6 -0
  247. package/dist/components/ProgressBar.vue3.js.map +1 -0
  248. package/dist/components/ProtocolStepEditor.vue.d.ts +24 -0
  249. package/dist/components/ProtocolStepEditor.vue.js +491 -0
  250. package/dist/components/ProtocolStepEditor.vue.js.map +1 -0
  251. package/dist/components/ProtocolStepEditor.vue3.js +6 -0
  252. package/dist/components/ProtocolStepEditor.vue3.js.map +1 -0
  253. package/dist/components/RackEditor.vue.d.ts +40 -0
  254. package/dist/components/RackEditor.vue.js +325 -0
  255. package/dist/components/RackEditor.vue.js.map +1 -0
  256. package/dist/components/RackEditor.vue3.js +6 -0
  257. package/dist/components/RackEditor.vue3.js.map +1 -0
  258. package/dist/components/ReagentList.vue.d.ts +46 -0
  259. package/dist/components/ReagentList.vue.js +526 -0
  260. package/dist/components/ReagentList.vue.js.map +1 -0
  261. package/dist/components/ReagentList.vue3.js +6 -0
  262. package/dist/components/ReagentList.vue3.js.map +1 -0
  263. package/dist/components/ResourceCard.vue.d.ts +50 -0
  264. package/dist/components/ResourceCard.vue.js +212 -0
  265. package/dist/components/ResourceCard.vue.js.map +1 -0
  266. package/dist/components/ResourceCard.vue3.js +6 -0
  267. package/dist/components/ResourceCard.vue3.js.map +1 -0
  268. package/dist/components/SampleHierarchyTree.vue.d.ts +37 -0
  269. package/dist/components/SampleHierarchyTree.vue.js +217 -0
  270. package/dist/components/SampleHierarchyTree.vue.js.map +1 -0
  271. package/dist/components/SampleHierarchyTree.vue3.js +6 -0
  272. package/dist/components/SampleHierarchyTree.vue3.js.map +1 -0
  273. package/dist/components/SampleLegend.vue.d.ts +32 -0
  274. package/dist/components/SampleLegend.vue.js +129 -0
  275. package/dist/components/SampleLegend.vue.js.map +1 -0
  276. package/dist/components/SampleLegend.vue3.js +6 -0
  277. package/dist/components/SampleLegend.vue3.js.map +1 -0
  278. package/dist/components/SampleSelector.vue.d.ts +29 -0
  279. package/dist/components/SampleSelector.vue.js +1076 -0
  280. package/dist/components/SampleSelector.vue.js.map +1 -0
  281. package/dist/components/SampleSelector.vue3.js +6 -0
  282. package/dist/components/SampleSelector.vue3.js.map +1 -0
  283. package/dist/components/ScheduleCalendar.vue.d.ts +110 -0
  284. package/dist/components/ScheduleCalendar.vue.js +535 -0
  285. package/dist/components/ScheduleCalendar.vue.js.map +1 -0
  286. package/dist/components/ScheduleCalendar.vue3.js +6 -0
  287. package/dist/components/ScheduleCalendar.vue3.js.map +1 -0
  288. package/dist/components/ScientificNumber.vue.d.ts +14 -0
  289. package/dist/components/ScientificNumber.vue.js +190 -0
  290. package/dist/components/ScientificNumber.vue.js.map +1 -0
  291. package/dist/components/ScientificNumber.vue3.js +6 -0
  292. package/dist/components/ScientificNumber.vue3.js.map +1 -0
  293. package/dist/components/SegmentedControl.vue.d.ts +20 -0
  294. package/dist/components/SegmentedControl.vue.js +71 -0
  295. package/dist/components/SegmentedControl.vue.js.map +1 -0
  296. package/dist/components/SegmentedControl.vue3.js +6 -0
  297. package/dist/components/SegmentedControl.vue3.js.map +1 -0
  298. package/dist/components/SequenceInput.vue.d.ts +54 -0
  299. package/dist/components/SequenceInput.vue.js +204 -0
  300. package/dist/components/SequenceInput.vue.js.map +1 -0
  301. package/dist/components/SequenceInput.vue3.js +6 -0
  302. package/dist/components/SequenceInput.vue3.js.map +1 -0
  303. package/dist/components/SettingsButton.vue.d.ts +30 -0
  304. package/dist/components/SettingsButton.vue.js +72 -0
  305. package/dist/components/SettingsButton.vue.js.map +1 -0
  306. package/dist/components/SettingsButton.vue3.js +6 -0
  307. package/dist/components/SettingsButton.vue3.js.map +1 -0
  308. package/dist/components/SettingsModal.vue.d.ts +40 -0
  309. package/dist/components/SettingsModal.vue.js +141 -0
  310. package/dist/components/SettingsModal.vue.js.map +1 -0
  311. package/dist/components/SettingsModal.vue3.js +6 -0
  312. package/dist/components/SettingsModal.vue3.js.map +1 -0
  313. package/dist/components/Skeleton.vue.d.ts +11 -0
  314. package/dist/components/Skeleton.vue.js +65 -0
  315. package/dist/components/Skeleton.vue.js.map +1 -0
  316. package/dist/components/Skeleton.vue3.js +6 -0
  317. package/dist/components/Skeleton.vue3.js.map +1 -0
  318. package/dist/components/StatusIndicator.vue.d.ts +13 -0
  319. package/dist/components/StatusIndicator.vue.js +38 -0
  320. package/dist/components/StatusIndicator.vue.js.map +1 -0
  321. package/dist/components/StatusIndicator.vue3.js +6 -0
  322. package/dist/components/StatusIndicator.vue3.js.map +1 -0
  323. package/dist/components/StepWizard.vue.d.ts +72 -0
  324. package/dist/components/StepWizard.vue.js +213 -0
  325. package/dist/components/StepWizard.vue.js.map +1 -0
  326. package/dist/components/StepWizard.vue3.js +6 -0
  327. package/dist/components/StepWizard.vue3.js.map +1 -0
  328. package/dist/components/TagsInput.vue.d.ts +23 -0
  329. package/dist/components/TagsInput.vue.js +124 -0
  330. package/dist/components/TagsInput.vue.js.map +1 -0
  331. package/dist/components/TagsInput.vue3.js +6 -0
  332. package/dist/components/TagsInput.vue3.js.map +1 -0
  333. package/dist/components/ThemeToggle.vue.d.ts +7 -0
  334. package/dist/components/ThemeToggle.vue.js +49 -0
  335. package/dist/components/ThemeToggle.vue.js.map +1 -0
  336. package/dist/components/ThemeToggle.vue3.js +6 -0
  337. package/dist/components/ThemeToggle.vue3.js.map +1 -0
  338. package/dist/components/TimePicker.vue.d.ts +29 -0
  339. package/dist/components/TimePicker.vue.js +275 -0
  340. package/dist/components/TimePicker.vue.js.map +1 -0
  341. package/dist/components/TimePicker.vue3.js +6 -0
  342. package/dist/components/TimePicker.vue3.js.map +1 -0
  343. package/dist/components/TimeRangeInput.vue.d.ts +27 -0
  344. package/dist/components/TimeRangeInput.vue.js +115 -0
  345. package/dist/components/TimeRangeInput.vue.js.map +1 -0
  346. package/dist/components/TimeRangeInput.vue3.js +6 -0
  347. package/dist/components/TimeRangeInput.vue3.js.map +1 -0
  348. package/dist/components/ToastNotification.vue.d.ts +2 -0
  349. package/dist/components/ToastNotification.vue.js +113 -0
  350. package/dist/components/ToastNotification.vue.js.map +1 -0
  351. package/dist/components/ToastNotification.vue3.js +6 -0
  352. package/dist/components/ToastNotification.vue3.js.map +1 -0
  353. package/dist/components/Tooltip.vue.d.ts +25 -0
  354. package/dist/components/Tooltip.vue.js +52 -0
  355. package/dist/components/Tooltip.vue.js.map +1 -0
  356. package/dist/components/Tooltip.vue3.js +6 -0
  357. package/dist/components/Tooltip.vue3.js.map +1 -0
  358. package/dist/components/UnitInput.vue.d.ts +44 -0
  359. package/dist/components/UnitInput.vue.js +178 -0
  360. package/dist/components/UnitInput.vue.js.map +1 -0
  361. package/dist/components/UnitInput.vue3.js +6 -0
  362. package/dist/components/UnitInput.vue3.js.map +1 -0
  363. package/dist/components/WellEditPopup.vue.d.ts +25 -0
  364. package/dist/components/WellEditPopup.vue.js +250 -0
  365. package/dist/components/WellEditPopup.vue.js.map +1 -0
  366. package/dist/components/WellEditPopup.vue3.js +6 -0
  367. package/dist/components/WellEditPopup.vue3.js.map +1 -0
  368. package/dist/components/WellPlate.vue.d.ts +69 -0
  369. package/dist/components/WellPlate.vue.js +531 -0
  370. package/dist/components/WellPlate.vue.js.map +1 -0
  371. package/dist/components/WellPlate.vue3.js +6 -0
  372. package/dist/components/WellPlate.vue3.js.map +1 -0
  373. package/dist/components/index.d.ts +71 -0
  374. package/dist/components/index.js +215 -0
  375. package/dist/components/index.js.map +1 -0
  376. package/dist/composables/index.d.ts +17 -0
  377. package/dist/composables/index.js +49 -0
  378. package/dist/composables/index.js.map +1 -0
  379. package/dist/composables/useApi.d.ts +19 -0
  380. package/dist/composables/useApi.js +101 -0
  381. package/dist/composables/useApi.js.map +1 -0
  382. package/dist/composables/useAsync.d.ts +127 -0
  383. package/dist/composables/useAsync.js +141 -0
  384. package/dist/composables/useAsync.js.map +1 -0
  385. package/dist/composables/useAuth.d.ts +44 -0
  386. package/dist/composables/useAuth.js +286 -0
  387. package/dist/composables/useAuth.js.map +1 -0
  388. package/dist/composables/useChemicalFormula.d.ts +20 -0
  389. package/dist/composables/useChemicalFormula.js +228 -0
  390. package/dist/composables/useChemicalFormula.js.map +1 -0
  391. package/dist/composables/useConcentrationUnits.d.ts +28 -0
  392. package/dist/composables/useConcentrationUnits.js +154 -0
  393. package/dist/composables/useConcentrationUnits.js.map +1 -0
  394. package/dist/composables/useDoseCalculator.d.ts +57 -0
  395. package/dist/composables/useDoseCalculator.js +228 -0
  396. package/dist/composables/useDoseCalculator.js.map +1 -0
  397. package/dist/composables/useForm.d.ts +91 -0
  398. package/dist/composables/useForm.js +253 -0
  399. package/dist/composables/useForm.js.map +1 -0
  400. package/dist/composables/usePasskey.d.ts +9 -0
  401. package/dist/composables/usePasskey.js +171 -0
  402. package/dist/composables/usePasskey.js.map +1 -0
  403. package/dist/composables/usePlatformContext.d.ts +125 -0
  404. package/dist/composables/usePlatformContext.js +149 -0
  405. package/dist/composables/usePlatformContext.js.map +1 -0
  406. package/dist/composables/useProtocolTemplates.d.ts +43 -0
  407. package/dist/composables/useProtocolTemplates.js +437 -0
  408. package/dist/composables/useProtocolTemplates.js.map +1 -0
  409. package/dist/composables/useRackEditor.d.ts +30 -0
  410. package/dist/composables/useRackEditor.js +168 -0
  411. package/dist/composables/useRackEditor.js.map +1 -0
  412. package/dist/composables/useScheduleDrag.d.ts +77 -0
  413. package/dist/composables/useScheduleDrag.js +183 -0
  414. package/dist/composables/useScheduleDrag.js.map +1 -0
  415. package/dist/composables/useSequenceUtils.d.ts +13 -0
  416. package/dist/composables/useSequenceUtils.js +93 -0
  417. package/dist/composables/useSequenceUtils.js.map +1 -0
  418. package/dist/composables/useTheme.d.ts +7 -0
  419. package/dist/composables/useTheme.js +40 -0
  420. package/dist/composables/useTheme.js.map +1 -0
  421. package/dist/composables/useTimeUtils.d.ts +15 -0
  422. package/dist/composables/useTimeUtils.js +105 -0
  423. package/dist/composables/useTimeUtils.js.map +1 -0
  424. package/dist/composables/useToast.d.ts +19 -0
  425. package/dist/composables/useToast.js +33 -0
  426. package/dist/composables/useToast.js.map +1 -0
  427. package/dist/composables/useWellPlateEditor.d.ts +31 -0
  428. package/dist/composables/useWellPlateEditor.js +315 -0
  429. package/dist/composables/useWellPlateEditor.js.map +1 -0
  430. package/dist/histoire.setup.d.ts +1 -0
  431. package/dist/index.d.ts +5 -0
  432. package/dist/index.js +265 -0
  433. package/dist/index.js.map +1 -0
  434. package/dist/install.d.ts +16 -0
  435. package/dist/install.js +15 -0
  436. package/dist/install.js.map +1 -0
  437. package/dist/stores/auth.d.ts +146 -0
  438. package/dist/stores/auth.js +122 -0
  439. package/dist/stores/auth.js.map +1 -0
  440. package/dist/stores/index.d.ts +2 -0
  441. package/dist/stores/index.js +8 -0
  442. package/dist/stores/index.js.map +1 -0
  443. package/dist/stores/settings.d.ts +75 -0
  444. package/dist/stores/settings.js +180 -0
  445. package/dist/stores/settings.js.map +1 -0
  446. package/dist/styles.css +23264 -0
  447. package/dist/tailwind.preset.d.ts +56 -0
  448. package/dist/tailwind.preset.js +59 -0
  449. package/dist/tailwind.preset.js.map +1 -0
  450. package/dist/types/auth.d.ts +42 -0
  451. package/dist/types/components.d.ts +405 -0
  452. package/dist/types/index.d.ts +3 -0
  453. package/dist/types/index.js +2 -0
  454. package/dist/types/index.js.map +1 -0
  455. package/dist/types/platform.d.ts +66 -0
  456. package/package.json +111 -0
  457. package/src/__tests__/components/AppLayout.test.ts +163 -0
  458. package/src/__tests__/components/AppSidebar.test.ts +292 -0
  459. package/src/__tests__/components/AppTopBar.test.ts +590 -0
  460. package/src/__tests__/components/BaseInput.test.ts +99 -0
  461. package/src/__tests__/components/BasePill.test.ts +291 -0
  462. package/src/__tests__/components/Calendar.test.ts +566 -0
  463. package/src/__tests__/components/CollapsibleCard.test.ts +524 -0
  464. package/src/__tests__/components/DataFrame.test.ts +767 -0
  465. package/src/__tests__/components/DropdownButton.test.ts +471 -0
  466. package/src/__tests__/composables/useAuth.test.ts +141 -0
  467. package/src/__tests__/composables/useForm.test.ts +205 -0
  468. package/src/components/AlertBox.story.vue +100 -0
  469. package/src/components/AlertBox.vue +68 -0
  470. package/src/components/AppContainer.story.vue +104 -0
  471. package/src/components/AppContainer.vue +33 -0
  472. package/src/components/AppLayout.story.vue +218 -0
  473. package/src/components/AppLayout.vue +75 -0
  474. package/src/components/AppSidebar.story.vue +300 -0
  475. package/src/components/AppSidebar.vue +114 -0
  476. package/src/components/AppTopBar.story.vue +112 -0
  477. package/src/components/AppTopBar.vue +471 -0
  478. package/src/components/AuditTrail.story.vue +163 -0
  479. package/src/components/AuditTrail.vue +161 -0
  480. package/src/components/Avatar.story.vue +92 -0
  481. package/src/components/Avatar.vue +65 -0
  482. package/src/components/BaseButton.story.vue +96 -0
  483. package/src/components/BaseButton.vue +72 -0
  484. package/src/components/BaseCheckbox.story.vue +73 -0
  485. package/src/components/BaseCheckbox.vue +68 -0
  486. package/src/components/BaseInput.story.vue +98 -0
  487. package/src/components/BaseInput.vue +70 -0
  488. package/src/components/BaseModal.story.vue +126 -0
  489. package/src/components/BaseModal.vue +118 -0
  490. package/src/components/BasePill.story.vue +131 -0
  491. package/src/components/BasePill.vue +84 -0
  492. package/src/components/BaseRadioGroup.story.vue +116 -0
  493. package/src/components/BaseRadioGroup.vue +83 -0
  494. package/src/components/BaseSelect.story.vue +110 -0
  495. package/src/components/BaseSelect.vue +67 -0
  496. package/src/components/BaseSlider.story.vue +82 -0
  497. package/src/components/BaseSlider.vue +112 -0
  498. package/src/components/BaseTabs.story.vue +106 -0
  499. package/src/components/BaseTabs.vue +58 -0
  500. package/src/components/BaseTextarea.story.vue +91 -0
  501. package/src/components/BaseTextarea.vue +58 -0
  502. package/src/components/BaseToggle.story.vue +81 -0
  503. package/src/components/BaseToggle.vue +72 -0
  504. package/src/components/BatchProgressList.story.vue +92 -0
  505. package/src/components/BatchProgressList.vue +202 -0
  506. package/src/components/Breadcrumb.story.vue +93 -0
  507. package/src/components/Breadcrumb.vue +73 -0
  508. package/src/components/Calendar.story.vue +106 -0
  509. package/src/components/Calendar.vue +362 -0
  510. package/src/components/ChartContainer.story.vue +113 -0
  511. package/src/components/ChartContainer.vue +63 -0
  512. package/src/components/ChemicalFormula.story.vue +102 -0
  513. package/src/components/ChemicalFormula.vue +38 -0
  514. package/src/components/CollapsibleCard.story.vue +124 -0
  515. package/src/components/CollapsibleCard.vue +164 -0
  516. package/src/components/ColorSlider.story.vue +120 -0
  517. package/src/components/ColorSlider.vue +163 -0
  518. package/src/components/ConcentrationInput.story.vue +77 -0
  519. package/src/components/ConcentrationInput.vue +184 -0
  520. package/src/components/ConfirmDialog.story.vue +145 -0
  521. package/src/components/ConfirmDialog.vue +96 -0
  522. package/src/components/DataFrame.story.vue +148 -0
  523. package/src/components/DataFrame.vue +418 -0
  524. package/src/components/DatePicker.story.vue +104 -0
  525. package/src/components/DatePicker.vue +298 -0
  526. package/src/components/DateTimePicker.story.vue +112 -0
  527. package/src/components/DateTimePicker.vue +391 -0
  528. package/src/components/Divider.story.vue +72 -0
  529. package/src/components/Divider.vue +45 -0
  530. package/src/components/DoseCalculator.story.vue +68 -0
  531. package/src/components/DoseCalculator.vue +475 -0
  532. package/src/components/DropdownButton.story.vue +102 -0
  533. package/src/components/DropdownButton.vue +180 -0
  534. package/src/components/EmptyState.story.vue +124 -0
  535. package/src/components/EmptyState.vue +64 -0
  536. package/src/components/ExperimentTimeline.story.vue +161 -0
  537. package/src/components/ExperimentTimeline.vue +381 -0
  538. package/src/components/FileUploader.story.vue +106 -0
  539. package/src/components/FileUploader.vue +397 -0
  540. package/src/components/FormField.story.vue +119 -0
  541. package/src/components/FormField.vue +37 -0
  542. package/src/components/FormulaInput.story.vue +96 -0
  543. package/src/components/FormulaInput.vue +123 -0
  544. package/src/components/GroupAssigner.story.vue +83 -0
  545. package/src/components/GroupAssigner.vue +283 -0
  546. package/src/components/GroupingModal.story.vue +52 -0
  547. package/src/components/GroupingModal.vue +420 -0
  548. package/src/components/IconButton.story.vue +135 -0
  549. package/src/components/IconButton.vue +72 -0
  550. package/src/components/LoadingSpinner.story.vue +70 -0
  551. package/src/components/LoadingSpinner.vue +49 -0
  552. package/src/components/MoleculeInput.story.vue +66 -0
  553. package/src/components/MoleculeInput.vue +414 -0
  554. package/src/components/MultiSelect.story.vue +121 -0
  555. package/src/components/MultiSelect.vue +117 -0
  556. package/src/components/NumberInput.story.vue +90 -0
  557. package/src/components/NumberInput.vue +128 -0
  558. package/src/components/PlateMapEditor.story.vue +92 -0
  559. package/src/components/PlateMapEditor.vue +512 -0
  560. package/src/components/ProgressBar.story.vue +117 -0
  561. package/src/components/ProgressBar.vue +63 -0
  562. package/src/components/ProtocolStepEditor.story.vue +69 -0
  563. package/src/components/ProtocolStepEditor.vue +521 -0
  564. package/src/components/RackEditor.story.vue +100 -0
  565. package/src/components/RackEditor.vue +370 -0
  566. package/src/components/ReagentList.story.vue +137 -0
  567. package/src/components/ReagentList.vue +487 -0
  568. package/src/components/ResourceCard.story.vue +150 -0
  569. package/src/components/ResourceCard.vue +160 -0
  570. package/src/components/SampleHierarchyTree.story.vue +161 -0
  571. package/src/components/SampleHierarchyTree.vue +279 -0
  572. package/src/components/SampleLegend.story.vue +91 -0
  573. package/src/components/SampleLegend.vue +118 -0
  574. package/src/components/SampleSelector.story.vue +100 -0
  575. package/src/components/SampleSelector.vue +955 -0
  576. package/src/components/ScheduleCalendar.story.vue +195 -0
  577. package/src/components/ScheduleCalendar.vue +568 -0
  578. package/src/components/ScientificNumber.story.vue +128 -0
  579. package/src/components/ScientificNumber.vue +197 -0
  580. package/src/components/SegmentedControl.story.vue +112 -0
  581. package/src/components/SegmentedControl.vue +78 -0
  582. package/src/components/SequenceInput.story.vue +119 -0
  583. package/src/components/SequenceInput.vue +208 -0
  584. package/src/components/SettingsButton.story.vue +58 -0
  585. package/src/components/SettingsButton.vue +75 -0
  586. package/src/components/SettingsModal.story.vue +145 -0
  587. package/src/components/SettingsModal.vue +151 -0
  588. package/src/components/Skeleton.story.vue +120 -0
  589. package/src/components/Skeleton.vue +73 -0
  590. package/src/components/StatusIndicator.story.vue +99 -0
  591. package/src/components/StatusIndicator.vue +39 -0
  592. package/src/components/StepWizard.story.vue +155 -0
  593. package/src/components/StepWizard.vue +231 -0
  594. package/src/components/TagsInput.story.vue +104 -0
  595. package/src/components/TagsInput.vue +127 -0
  596. package/src/components/ThemeToggle.story.vue +36 -0
  597. package/src/components/ThemeToggle.vue +53 -0
  598. package/src/components/TimePicker.story.vue +96 -0
  599. package/src/components/TimePicker.vue +272 -0
  600. package/src/components/TimeRangeInput.story.vue +104 -0
  601. package/src/components/TimeRangeInput.vue +121 -0
  602. package/src/components/ToastNotification.story.vue +130 -0
  603. package/src/components/ToastNotification.vue +54 -0
  604. package/src/components/Tooltip.story.vue +102 -0
  605. package/src/components/Tooltip.vue +61 -0
  606. package/src/components/UnitInput.story.vue +170 -0
  607. package/src/components/UnitInput.vue +218 -0
  608. package/src/components/WellEditPopup.vue +234 -0
  609. package/src/components/WellPlate.story.vue +198 -0
  610. package/src/components/WellPlate.vue +637 -0
  611. package/src/components/index.ts +96 -0
  612. package/src/composables/index.ts +87 -0
  613. package/src/composables/useApi.ts +145 -0
  614. package/src/composables/useAsync.ts +322 -0
  615. package/src/composables/useAuth.ts +427 -0
  616. package/src/composables/useChemicalFormula.ts +274 -0
  617. package/src/composables/useConcentrationUnits.ts +245 -0
  618. package/src/composables/useDoseCalculator.ts +369 -0
  619. package/src/composables/useForm.ts +415 -0
  620. package/src/composables/usePasskey.ts +209 -0
  621. package/src/composables/usePlatformContext.ts +232 -0
  622. package/src/composables/useProtocolTemplates.ts +517 -0
  623. package/src/composables/useRackEditor.ts +221 -0
  624. package/src/composables/useScheduleDrag.ts +244 -0
  625. package/src/composables/useSequenceUtils.ts +104 -0
  626. package/src/composables/useTheme.ts +49 -0
  627. package/src/composables/useTimeUtils.ts +114 -0
  628. package/src/composables/useToast.ts +39 -0
  629. package/src/composables/useWellPlateEditor.ts +408 -0
  630. package/src/histoire.setup.ts +17 -0
  631. package/src/index.ts +283 -0
  632. package/src/install.ts +32 -0
  633. package/src/stores/auth.ts +144 -0
  634. package/src/stores/index.ts +2 -0
  635. package/src/stores/settings.ts +229 -0
  636. package/src/styles/components/alert-box.css +94 -0
  637. package/src/styles/components/app-container.css +32 -0
  638. package/src/styles/components/app-layout.css +99 -0
  639. package/src/styles/components/app-sidebar.css +133 -0
  640. package/src/styles/components/app-top-bar.css +396 -0
  641. package/src/styles/components/audit-trail.css +143 -0
  642. package/src/styles/components/avatar.css +64 -0
  643. package/src/styles/components/batch-progress-list.css +196 -0
  644. package/src/styles/components/breadcrumb.css +45 -0
  645. package/src/styles/components/button.css +119 -0
  646. package/src/styles/components/calendar.css +192 -0
  647. package/src/styles/components/chart-container.css +69 -0
  648. package/src/styles/components/checkbox.css +112 -0
  649. package/src/styles/components/chemical-formula.css +46 -0
  650. package/src/styles/components/collapsible-card.css +184 -0
  651. package/src/styles/components/color-slider.css +110 -0
  652. package/src/styles/components/concentration-input.css +142 -0
  653. package/src/styles/components/confirm-dialog.css +137 -0
  654. package/src/styles/components/dataframe.css +382 -0
  655. package/src/styles/components/date-picker.css +239 -0
  656. package/src/styles/components/datetime-picker.css +225 -0
  657. package/src/styles/components/divider.css +62 -0
  658. package/src/styles/components/dose-calculator.css +301 -0
  659. package/src/styles/components/dropdown-button.css +236 -0
  660. package/src/styles/components/empty-state.css +148 -0
  661. package/src/styles/components/experiment-timeline.css +529 -0
  662. package/src/styles/components/file-uploader.css +517 -0
  663. package/src/styles/components/form-field.css +35 -0
  664. package/src/styles/components/formula-input.css +96 -0
  665. package/src/styles/components/group-assigner.css +200 -0
  666. package/src/styles/components/grouping-modal.css +323 -0
  667. package/src/styles/components/icon-button.css +128 -0
  668. package/src/styles/components/input.css +53 -0
  669. package/src/styles/components/loading-spinner.css +67 -0
  670. package/src/styles/components/modal.css +122 -0
  671. package/src/styles/components/molecule-input.css +186 -0
  672. package/src/styles/components/multi-select.css +131 -0
  673. package/src/styles/components/number-input.css +110 -0
  674. package/src/styles/components/pill.css +172 -0
  675. package/src/styles/components/plate-map-editor.css +464 -0
  676. package/src/styles/components/progress-bar.css +88 -0
  677. package/src/styles/components/protocol-step-editor.css +449 -0
  678. package/src/styles/components/rack-editor.css +259 -0
  679. package/src/styles/components/radio-group.css +158 -0
  680. package/src/styles/components/reagent-list.css +407 -0
  681. package/src/styles/components/resource-card.css +360 -0
  682. package/src/styles/components/sample-hierarchy-tree.css +314 -0
  683. package/src/styles/components/sample-legend.css +201 -0
  684. package/src/styles/components/sample-selector.css +701 -0
  685. package/src/styles/components/schedule-calendar.css +478 -0
  686. package/src/styles/components/scientific-number.css +63 -0
  687. package/src/styles/components/segmented-control.css +190 -0
  688. package/src/styles/components/select.css +72 -0
  689. package/src/styles/components/sequence-input.css +184 -0
  690. package/src/styles/components/settings-button.css +75 -0
  691. package/src/styles/components/settings-modal.css +95 -0
  692. package/src/styles/components/skeleton.css +36 -0
  693. package/src/styles/components/slider.css +78 -0
  694. package/src/styles/components/status-indicator.css +59 -0
  695. package/src/styles/components/step-wizard.css +187 -0
  696. package/src/styles/components/tabs.css +108 -0
  697. package/src/styles/components/tags-input.css +118 -0
  698. package/src/styles/components/textarea.css +65 -0
  699. package/src/styles/components/theme-toggle.css +50 -0
  700. package/src/styles/components/time-picker.css +171 -0
  701. package/src/styles/components/time-range-input.css +42 -0
  702. package/src/styles/components/toast.css +72 -0
  703. package/src/styles/components/toggle.css +115 -0
  704. package/src/styles/components/tooltip.css +98 -0
  705. package/src/styles/components/unit-input.css +138 -0
  706. package/src/styles/components/well-edit-popup.css +252 -0
  707. package/src/styles/components/well-plate.css +310 -0
  708. package/src/styles/index.css +80 -0
  709. package/src/styles/variables.css +1078 -0
  710. package/src/tailwind.preset.ts +59 -0
  711. package/src/types/auth.ts +55 -0
  712. package/src/types/components.ts +560 -0
  713. package/src/types/index.ts +146 -0
  714. package/src/types/platform.ts +101 -0
@@ -0,0 +1,127 @@
1
+ import { Ref, ComputedRef } from 'vue';
2
+ /**
3
+ * Error type for async operations.
4
+ */
5
+ export interface AsyncError {
6
+ message: string;
7
+ code?: string;
8
+ details?: Record<string, unknown>;
9
+ originalError?: unknown;
10
+ }
11
+ /**
12
+ * State of an async operation.
13
+ */
14
+ export type AsyncState = 'idle' | 'loading' | 'success' | 'error';
15
+ /**
16
+ * Return type for useAsync composable.
17
+ */
18
+ export interface UseAsyncReturn<T> {
19
+ data: Ref<T | null>;
20
+ error: Ref<AsyncError | null>;
21
+ state: Ref<AsyncState>;
22
+ isIdle: ComputedRef<boolean>;
23
+ isLoading: ComputedRef<boolean>;
24
+ isSuccess: ComputedRef<boolean>;
25
+ isError: ComputedRef<boolean>;
26
+ execute: (...args: unknown[]) => Promise<T | null>;
27
+ reset: () => void;
28
+ setData: (data: T | null) => void;
29
+ setError: (error: AsyncError | null) => void;
30
+ }
31
+ /**
32
+ * Options for useAsync.
33
+ */
34
+ export interface UseAsyncOptions<T> {
35
+ initialData?: T | null;
36
+ immediate?: boolean;
37
+ immediateArgs?: unknown[];
38
+ transformError?: (error: unknown) => AsyncError;
39
+ onSuccess?: (data: T) => void;
40
+ onError?: (error: AsyncError) => void;
41
+ resetOnExecute?: boolean;
42
+ }
43
+ /**
44
+ * Composable for managing async operation state.
45
+ *
46
+ * Provides standardized loading, error, and success state management
47
+ * for any async function.
48
+ *
49
+ * @param asyncFn - The async function to wrap
50
+ * @param options - Configuration options
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // Basic usage
55
+ * const { data, isLoading, error, execute } = useAsync(
56
+ * async (id: string) => {
57
+ * const response = await api.get(`/users/${id}`)
58
+ * return response.data
59
+ * }
60
+ * )
61
+ *
62
+ * // Execute the function
63
+ * await execute('user-123')
64
+ *
65
+ * // In template
66
+ * <div v-if="isLoading">Loading...</div>
67
+ * <div v-else-if="error">{{ error.message }}</div>
68
+ * <div v-else-if="data">{{ data.name }}</div>
69
+ * ```
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // With options
74
+ * const { data, execute } = useAsync(
75
+ * fetchUser,
76
+ * {
77
+ * immediate: true,
78
+ * immediateArgs: ['default-user'],
79
+ * onSuccess: (user) => console.log('Fetched:', user.name),
80
+ * onError: (error) => toast.error(error.message),
81
+ * }
82
+ * )
83
+ * ```
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * // Form submission
88
+ * const { isLoading, error, execute: submit } = useAsync(
89
+ * async (formData: FormData) => {
90
+ * await api.post('/submit', formData)
91
+ * },
92
+ * {
93
+ * onSuccess: () => {
94
+ * toast.success('Submitted!')
95
+ * router.push('/success')
96
+ * },
97
+ * }
98
+ * )
99
+ *
100
+ * const handleSubmit = () => submit(new FormData(formRef.value))
101
+ * ```
102
+ */
103
+ export declare function useAsync<T>(asyncFn: (...args: unknown[]) => Promise<T>, options?: UseAsyncOptions<T>): UseAsyncReturn<T>;
104
+ /**
105
+ * Create a batch of async operations that can be executed in parallel.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const { results, isLoading, execute } = useAsyncBatch([
110
+ * () => fetchUser(userId),
111
+ * () => fetchPosts(userId),
112
+ * () => fetchComments(userId),
113
+ * ])
114
+ *
115
+ * await execute()
116
+ * // results.value = [user, posts, comments]
117
+ * ```
118
+ */
119
+ export declare function useAsyncBatch<T extends readonly (() => Promise<unknown>)[]>(asyncFns: T): {
120
+ results: Ref<{
121
+ [K in keyof T]: Awaited<ReturnType<T[K]>> | null;
122
+ }>;
123
+ errors: Ref<(AsyncError | null)[]>;
124
+ isLoading: Ref<boolean>;
125
+ execute: () => Promise<void>;
126
+ reset: () => void;
127
+ };
@@ -0,0 +1,141 @@
1
+ import { ref, computed } from "vue";
2
+ function defaultTransformError(error) {
3
+ if (error instanceof Error) {
4
+ return {
5
+ message: error.message,
6
+ originalError: error
7
+ };
8
+ }
9
+ if (typeof error === "object" && error !== null) {
10
+ const errorObj = error;
11
+ if ("response" in errorObj && errorObj.response) {
12
+ const response = errorObj.response;
13
+ const data = response.data;
14
+ return {
15
+ message: (data == null ? void 0 : data.detail) || (data == null ? void 0 : data.message) || "Request failed",
16
+ code: String(response.status),
17
+ details: data,
18
+ originalError: error
19
+ };
20
+ }
21
+ return {
22
+ message: errorObj.message || "Unknown error",
23
+ code: errorObj.code,
24
+ details: errorObj,
25
+ originalError: error
26
+ };
27
+ }
28
+ return {
29
+ message: String(error),
30
+ originalError: error
31
+ };
32
+ }
33
+ function useAsync(asyncFn, options = {}) {
34
+ const {
35
+ initialData = null,
36
+ immediate = false,
37
+ immediateArgs = [],
38
+ transformError = defaultTransformError,
39
+ onSuccess,
40
+ onError,
41
+ resetOnExecute = false
42
+ } = options;
43
+ const data = ref(initialData);
44
+ const error = ref(null);
45
+ const state = ref("idle");
46
+ const isIdle = computed(() => state.value === "idle");
47
+ const isLoading = computed(() => state.value === "loading");
48
+ const isSuccess = computed(() => state.value === "success");
49
+ const isError = computed(() => state.value === "error");
50
+ async function execute(...args) {
51
+ state.value = "loading";
52
+ error.value = null;
53
+ if (resetOnExecute) {
54
+ data.value = null;
55
+ }
56
+ try {
57
+ const result = await asyncFn(...args);
58
+ data.value = result;
59
+ state.value = "success";
60
+ onSuccess == null ? void 0 : onSuccess(result);
61
+ return result;
62
+ } catch (e) {
63
+ const asyncError = transformError(e);
64
+ error.value = asyncError;
65
+ state.value = "error";
66
+ onError == null ? void 0 : onError(asyncError);
67
+ return null;
68
+ }
69
+ }
70
+ function reset() {
71
+ data.value = initialData;
72
+ error.value = null;
73
+ state.value = "idle";
74
+ }
75
+ function setData(newData) {
76
+ data.value = newData;
77
+ if (newData !== null) {
78
+ state.value = "success";
79
+ error.value = null;
80
+ }
81
+ }
82
+ function setError(newError) {
83
+ error.value = newError;
84
+ if (newError !== null) {
85
+ state.value = "error";
86
+ }
87
+ }
88
+ if (immediate) {
89
+ execute(...immediateArgs);
90
+ }
91
+ return {
92
+ data,
93
+ error,
94
+ state,
95
+ isIdle,
96
+ isLoading,
97
+ isSuccess,
98
+ isError,
99
+ execute,
100
+ reset,
101
+ setData,
102
+ setError
103
+ };
104
+ }
105
+ function useAsyncBatch(asyncFns) {
106
+ const results = ref(asyncFns.map(() => null));
107
+ const errors = ref(asyncFns.map(() => null));
108
+ const isLoading = ref(false);
109
+ async function execute() {
110
+ isLoading.value = true;
111
+ errors.value = asyncFns.map(() => null);
112
+ const promises = asyncFns.map(async (fn, index) => {
113
+ try {
114
+ const result = await fn();
115
+ results.value[index] = result;
116
+ } catch (e) {
117
+ errors.value[index] = defaultTransformError(e);
118
+ results.value[index] = null;
119
+ }
120
+ });
121
+ await Promise.all(promises);
122
+ isLoading.value = false;
123
+ }
124
+ function reset() {
125
+ results.value = asyncFns.map(() => null);
126
+ errors.value = asyncFns.map(() => null);
127
+ isLoading.value = false;
128
+ }
129
+ return {
130
+ results,
131
+ errors,
132
+ isLoading,
133
+ execute,
134
+ reset
135
+ };
136
+ }
137
+ export {
138
+ useAsync,
139
+ useAsyncBatch
140
+ };
141
+ //# sourceMappingURL=useAsync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAsync.js","sources":["../../src/composables/useAsync.ts"],"sourcesContent":["import { ref, computed, type Ref, type ComputedRef } from 'vue'\n\n/**\n * Error type for async operations.\n */\nexport interface AsyncError {\n message: string\n code?: string\n details?: Record<string, unknown>\n originalError?: unknown\n}\n\n/**\n * State of an async operation.\n */\nexport type AsyncState = 'idle' | 'loading' | 'success' | 'error'\n\n/**\n * Return type for useAsync composable.\n */\nexport interface UseAsyncReturn<T> {\n // Data\n data: Ref<T | null>\n error: Ref<AsyncError | null>\n\n // State\n state: Ref<AsyncState>\n isIdle: ComputedRef<boolean>\n isLoading: ComputedRef<boolean>\n isSuccess: ComputedRef<boolean>\n isError: ComputedRef<boolean>\n\n // Methods\n execute: (...args: unknown[]) => Promise<T | null>\n reset: () => void\n setData: (data: T | null) => void\n setError: (error: AsyncError | null) => void\n}\n\n/**\n * Options for useAsync.\n */\nexport interface UseAsyncOptions<T> {\n // Initial data value\n initialData?: T | null\n\n // Whether to run immediately on creation\n immediate?: boolean\n\n // Arguments for immediate execution\n immediateArgs?: unknown[]\n\n // Transform error into AsyncError\n transformError?: (error: unknown) => AsyncError\n\n // Called on success\n onSuccess?: (data: T) => void\n\n // Called on error\n onError?: (error: AsyncError) => void\n\n // Reset data on new execution\n resetOnExecute?: boolean\n}\n\n/**\n * Default error transformer.\n */\nfunction defaultTransformError(error: unknown): AsyncError {\n if (error instanceof Error) {\n return {\n message: error.message,\n originalError: error,\n }\n }\n\n if (typeof error === 'object' && error !== null) {\n const errorObj = error as Record<string, unknown>\n\n // Handle Axios-like errors\n if ('response' in errorObj && errorObj.response) {\n const response = errorObj.response as Record<string, unknown>\n const data = response.data as Record<string, unknown> | undefined\n\n return {\n message: (data?.detail as string) || (data?.message as string) || 'Request failed',\n code: String(response.status),\n details: data,\n originalError: error,\n }\n }\n\n // Handle generic error objects\n return {\n message: (errorObj.message as string) || 'Unknown error',\n code: errorObj.code as string | undefined,\n details: errorObj,\n originalError: error,\n }\n }\n\n return {\n message: String(error),\n originalError: error,\n }\n}\n\n/**\n * Composable for managing async operation state.\n *\n * Provides standardized loading, error, and success state management\n * for any async function.\n *\n * @param asyncFn - The async function to wrap\n * @param options - Configuration options\n *\n * @example\n * ```typescript\n * // Basic usage\n * const { data, isLoading, error, execute } = useAsync(\n * async (id: string) => {\n * const response = await api.get(`/users/${id}`)\n * return response.data\n * }\n * )\n *\n * // Execute the function\n * await execute('user-123')\n *\n * // In template\n * <div v-if=\"isLoading\">Loading...</div>\n * <div v-else-if=\"error\">{{ error.message }}</div>\n * <div v-else-if=\"data\">{{ data.name }}</div>\n * ```\n *\n * @example\n * ```typescript\n * // With options\n * const { data, execute } = useAsync(\n * fetchUser,\n * {\n * immediate: true,\n * immediateArgs: ['default-user'],\n * onSuccess: (user) => console.log('Fetched:', user.name),\n * onError: (error) => toast.error(error.message),\n * }\n * )\n * ```\n *\n * @example\n * ```typescript\n * // Form submission\n * const { isLoading, error, execute: submit } = useAsync(\n * async (formData: FormData) => {\n * await api.post('/submit', formData)\n * },\n * {\n * onSuccess: () => {\n * toast.success('Submitted!')\n * router.push('/success')\n * },\n * }\n * )\n *\n * const handleSubmit = () => submit(new FormData(formRef.value))\n * ```\n */\nexport function useAsync<T>(\n asyncFn: (...args: unknown[]) => Promise<T>,\n options: UseAsyncOptions<T> = {}\n): UseAsyncReturn<T> {\n const {\n initialData = null,\n immediate = false,\n immediateArgs = [],\n transformError = defaultTransformError,\n onSuccess,\n onError,\n resetOnExecute = false,\n } = options\n\n // State\n const data = ref<T | null>(initialData) as Ref<T | null>\n const error = ref<AsyncError | null>(null)\n const state = ref<AsyncState>('idle')\n\n // Computed state helpers\n const isIdle = computed(() => state.value === 'idle')\n const isLoading = computed(() => state.value === 'loading')\n const isSuccess = computed(() => state.value === 'success')\n const isError = computed(() => state.value === 'error')\n\n // Execute the async function\n async function execute(...args: unknown[]): Promise<T | null> {\n state.value = 'loading'\n error.value = null\n\n if (resetOnExecute) {\n data.value = null\n }\n\n try {\n const result = await asyncFn(...args)\n data.value = result\n state.value = 'success'\n onSuccess?.(result)\n return result\n } catch (e) {\n const asyncError = transformError(e)\n error.value = asyncError\n state.value = 'error'\n onError?.(asyncError)\n return null\n }\n }\n\n // Reset to initial state\n function reset(): void {\n data.value = initialData\n error.value = null\n state.value = 'idle'\n }\n\n // Manual data setter\n function setData(newData: T | null): void {\n data.value = newData\n if (newData !== null) {\n state.value = 'success'\n error.value = null\n }\n }\n\n // Manual error setter\n function setError(newError: AsyncError | null): void {\n error.value = newError\n if (newError !== null) {\n state.value = 'error'\n }\n }\n\n // Execute immediately if requested\n if (immediate) {\n execute(...immediateArgs)\n }\n\n return {\n data,\n error,\n state,\n isIdle,\n isLoading,\n isSuccess,\n isError,\n execute,\n reset,\n setData,\n setError,\n }\n}\n\n/**\n * Create a batch of async operations that can be executed in parallel.\n *\n * @example\n * ```typescript\n * const { results, isLoading, execute } = useAsyncBatch([\n * () => fetchUser(userId),\n * () => fetchPosts(userId),\n * () => fetchComments(userId),\n * ])\n *\n * await execute()\n * // results.value = [user, posts, comments]\n * ```\n */\nexport function useAsyncBatch<T extends readonly (() => Promise<unknown>)[]>(\n asyncFns: T\n): {\n results: Ref<{ [K in keyof T]: Awaited<ReturnType<T[K]>> | null }>\n errors: Ref<(AsyncError | null)[]>\n isLoading: Ref<boolean>\n execute: () => Promise<void>\n reset: () => void\n} {\n type Results = { [K in keyof T]: Awaited<ReturnType<T[K]>> | null }\n\n const results = ref<Results>(asyncFns.map(() => null) as unknown as Results) as Ref<Results>\n const errors = ref<(AsyncError | null)[]>(asyncFns.map(() => null))\n const isLoading = ref(false)\n\n async function execute(): Promise<void> {\n isLoading.value = true\n errors.value = asyncFns.map(() => null)\n\n const promises = asyncFns.map(async (fn, index) => {\n try {\n const result = await fn()\n ;(results.value as unknown[])[index] = result\n } catch (e) {\n errors.value[index] = defaultTransformError(e)\n ;(results.value as unknown[])[index] = null\n }\n })\n\n await Promise.all(promises)\n isLoading.value = false\n }\n\n function reset(): void {\n results.value = asyncFns.map(() => null) as unknown as Results\n errors.value = asyncFns.map(() => null)\n isLoading.value = false\n }\n\n return {\n results,\n errors,\n isLoading,\n execute,\n reset,\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { Ref } from 'vue';
2
+ import { AuthConfig, UserInfo } from '../types';
3
+ /**
4
+ * Authentication composable with automatic token refresh.
5
+ *
6
+ * Features:
7
+ * - Automatic token refresh before expiration
8
+ * - Login/logout/register functionality
9
+ * - Token verification on startup
10
+ * - User profile management
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const { login, logout, isAuthenticated, user } = useAuth()
15
+ *
16
+ * // Login
17
+ * const success = await login('username', 'password')
18
+ *
19
+ * // Automatic refresh is enabled by default
20
+ * // Tokens are refreshed 5 minutes before expiration
21
+ * ```
22
+ */
23
+ export interface UseAuthReturn {
24
+ login: (username: string, password: string) => Promise<boolean>;
25
+ logout: () => void;
26
+ register: (username: string, password: string, email?: string) => Promise<boolean>;
27
+ verifyToken: () => Promise<boolean>;
28
+ fetchAuthConfig: () => Promise<AuthConfig>;
29
+ initializeAuth: () => Promise<void>;
30
+ getCurrentUser: () => Promise<UserInfo | null>;
31
+ getAuthHeader: () => Record<string, string>;
32
+ updateProfile: (data: {
33
+ email?: string;
34
+ shortname?: string;
35
+ currentPassword?: string;
36
+ newPassword?: string;
37
+ }) => Promise<{
38
+ success: boolean;
39
+ error?: string;
40
+ }>;
41
+ refreshToken: () => Promise<boolean>;
42
+ isRefreshing: Ref<boolean>;
43
+ }
44
+ export declare function useAuth(): UseAuthReturn;
@@ -0,0 +1,286 @@
1
+ import axios from "axios";
2
+ import { ref, onMounted, onUnmounted, watch } from "vue";
3
+ import { useAuthStore } from "../stores/auth.js";
4
+ import { useSettingsStore } from "../stores/settings.js";
5
+ const TOKEN_REFRESH_MARGIN_MS = 5 * 60 * 1e3;
6
+ const TOKEN_REFRESH_CHECK_INTERVAL_MS = 60 * 1e3;
7
+ function useAuth() {
8
+ const authStore = useAuthStore();
9
+ const settingsStore = useSettingsStore();
10
+ const refreshTimerId = ref(null);
11
+ const isRefreshing = ref(false);
12
+ function getApiBaseUrl() {
13
+ return settingsStore.getApiBaseUrl();
14
+ }
15
+ async function fetchAuthConfig() {
16
+ try {
17
+ const response = await axios.get(`${getApiBaseUrl()}/setup/config/public`);
18
+ const config = {
19
+ authRequired: response.data.auth_required,
20
+ passkeyEnabled: response.data.passkey_enabled,
21
+ passkeyRegistered: response.data.passkey_registered ?? false,
22
+ registrationEnabled: response.data.registration_enabled ?? false,
23
+ databaseMode: response.data.database_mode ?? "none"
24
+ };
25
+ authStore.setAuthConfig(config);
26
+ return config;
27
+ } catch (error) {
28
+ console.error("Failed to fetch auth config:", error);
29
+ return {
30
+ authRequired: false,
31
+ passkeyEnabled: false,
32
+ passkeyRegistered: false,
33
+ registrationEnabled: false,
34
+ databaseMode: "none"
35
+ };
36
+ }
37
+ }
38
+ async function login(username, password) {
39
+ authStore.setLoading(true);
40
+ authStore.setError(null);
41
+ try {
42
+ const response = await axios.post(
43
+ `${getApiBaseUrl()}/auth/login`,
44
+ { username, password }
45
+ );
46
+ authStore.setToken(response.data.access_token, response.data.expires_in);
47
+ authStore.setUsername(username);
48
+ await getCurrentUser();
49
+ scheduleTokenRefresh();
50
+ return true;
51
+ } catch (error) {
52
+ if (axios.isAxiosError(error) && error.response) {
53
+ authStore.setError(error.response.data.detail || "Login failed");
54
+ } else {
55
+ authStore.setError("Network error. Please try again.");
56
+ }
57
+ return false;
58
+ } finally {
59
+ authStore.setLoading(false);
60
+ }
61
+ }
62
+ async function register(username, password, email) {
63
+ authStore.setLoading(true);
64
+ authStore.setError(null);
65
+ try {
66
+ await axios.post(
67
+ `${getApiBaseUrl()}/users/register`,
68
+ { username, password, email }
69
+ );
70
+ return await login(username, password);
71
+ } catch (error) {
72
+ if (axios.isAxiosError(error) && error.response) {
73
+ authStore.setError(error.response.data.detail || "Registration failed");
74
+ } else {
75
+ authStore.setError("Network error. Please try again.");
76
+ }
77
+ return false;
78
+ } finally {
79
+ authStore.setLoading(false);
80
+ }
81
+ }
82
+ async function getCurrentUser() {
83
+ if (!authStore.token) {
84
+ return null;
85
+ }
86
+ try {
87
+ const response = await axios.get(
88
+ `${getApiBaseUrl()}/users/me`,
89
+ { headers: getAuthHeader() }
90
+ );
91
+ const userInfo = {
92
+ id: response.data.id,
93
+ username: response.data.username,
94
+ shortname: response.data.shortname,
95
+ email: response.data.email,
96
+ role: response.data.role,
97
+ isActive: response.data.is_active
98
+ };
99
+ authStore.setUserInfo(userInfo);
100
+ return userInfo;
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+ async function verifyToken() {
106
+ if (!authStore.token) {
107
+ return false;
108
+ }
109
+ try {
110
+ const response = await axios.get(
111
+ `${getApiBaseUrl()}/auth/verify`,
112
+ {
113
+ headers: {
114
+ Authorization: `Bearer ${authStore.token}`
115
+ }
116
+ }
117
+ );
118
+ if (response.data.valid && response.data.username) {
119
+ authStore.setUsername(response.data.username);
120
+ return true;
121
+ }
122
+ authStore.clearToken();
123
+ return false;
124
+ } catch {
125
+ authStore.clearToken();
126
+ return false;
127
+ }
128
+ }
129
+ let refreshPromise = null;
130
+ async function refreshToken() {
131
+ if (!authStore.token) return false;
132
+ if (refreshPromise) return refreshPromise;
133
+ refreshPromise = (async () => {
134
+ var _a;
135
+ isRefreshing.value = true;
136
+ try {
137
+ const response = await axios.post(
138
+ `${getApiBaseUrl()}/auth/refresh`,
139
+ {},
140
+ { headers: getAuthHeader() }
141
+ );
142
+ authStore.setToken(response.data.access_token, response.data.expires_in);
143
+ scheduleTokenRefresh();
144
+ return true;
145
+ } catch (error) {
146
+ if (axios.isAxiosError(error) && ((_a = error.response) == null ? void 0 : _a.status) === 401) {
147
+ console.warn("[Auth] Token refresh failed - session expired");
148
+ authStore.clearToken();
149
+ stopTokenRefresh();
150
+ }
151
+ return false;
152
+ } finally {
153
+ isRefreshing.value = false;
154
+ refreshPromise = null;
155
+ }
156
+ })();
157
+ return refreshPromise;
158
+ }
159
+ function scheduleTokenRefresh() {
160
+ stopTokenRefresh();
161
+ if (!authStore.tokenExpires) {
162
+ return;
163
+ }
164
+ const expiresAt = authStore.tokenExpires.getTime();
165
+ const refreshAt = expiresAt - TOKEN_REFRESH_MARGIN_MS;
166
+ const now = Date.now();
167
+ if (refreshAt <= now) {
168
+ refreshToken();
169
+ return;
170
+ }
171
+ const delay = refreshAt - now;
172
+ refreshTimerId.value = window.setTimeout(() => {
173
+ refreshToken();
174
+ }, delay);
175
+ }
176
+ function stopTokenRefresh() {
177
+ if (refreshTimerId.value !== null) {
178
+ window.clearTimeout(refreshTimerId.value);
179
+ refreshTimerId.value = null;
180
+ }
181
+ }
182
+ function checkAndRefreshIfNeeded() {
183
+ if (!authStore.token || !authStore.tokenExpires) {
184
+ return;
185
+ }
186
+ const expiresAt = authStore.tokenExpires.getTime();
187
+ const refreshAt = expiresAt - TOKEN_REFRESH_MARGIN_MS;
188
+ const now = Date.now();
189
+ if (now >= refreshAt) {
190
+ refreshToken();
191
+ }
192
+ }
193
+ async function initializeAuth() {
194
+ authStore.initialize();
195
+ await fetchAuthConfig();
196
+ if (authStore.token) {
197
+ const valid = await verifyToken();
198
+ if (valid) {
199
+ await getCurrentUser();
200
+ scheduleTokenRefresh();
201
+ }
202
+ }
203
+ }
204
+ function logout() {
205
+ stopTokenRefresh();
206
+ authStore.logout();
207
+ }
208
+ function getAuthHeader() {
209
+ if (authStore.token) {
210
+ return { Authorization: `Bearer ${authStore.token}` };
211
+ }
212
+ return {};
213
+ }
214
+ async function updateProfile(data) {
215
+ if (!authStore.token) {
216
+ return { success: false, error: "Not authenticated" };
217
+ }
218
+ try {
219
+ const requestData = {};
220
+ if (data.email !== void 0) requestData.email = data.email;
221
+ if (data.shortname !== void 0) requestData.shortname = data.shortname;
222
+ if (data.currentPassword) requestData.current_password = data.currentPassword;
223
+ if (data.newPassword) requestData.new_password = data.newPassword;
224
+ const response = await axios.put(
225
+ `${getApiBaseUrl()}/users/me`,
226
+ requestData,
227
+ { headers: getAuthHeader() }
228
+ );
229
+ const userInfo = {
230
+ id: response.data.id,
231
+ username: response.data.username,
232
+ shortname: response.data.shortname,
233
+ email: response.data.email,
234
+ role: response.data.role,
235
+ isActive: response.data.is_active
236
+ };
237
+ authStore.setUserInfo(userInfo);
238
+ return { success: true };
239
+ } catch (error) {
240
+ if (axios.isAxiosError(error) && error.response) {
241
+ return { success: false, error: error.response.data.detail || "Update failed" };
242
+ }
243
+ return { success: false, error: "Network error. Please try again." };
244
+ }
245
+ }
246
+ let checkInterval = null;
247
+ onMounted(() => {
248
+ checkInterval = window.setInterval(checkAndRefreshIfNeeded, TOKEN_REFRESH_CHECK_INTERVAL_MS);
249
+ });
250
+ onUnmounted(() => {
251
+ stopTokenRefresh();
252
+ if (checkInterval !== null) {
253
+ window.clearInterval(checkInterval);
254
+ checkInterval = null;
255
+ }
256
+ });
257
+ watch(
258
+ () => authStore.tokenExpires,
259
+ (newExpires) => {
260
+ if (newExpires) {
261
+ scheduleTokenRefresh();
262
+ } else {
263
+ stopTokenRefresh();
264
+ }
265
+ }
266
+ );
267
+ return {
268
+ // Core auth methods
269
+ login,
270
+ logout,
271
+ register,
272
+ verifyToken,
273
+ fetchAuthConfig,
274
+ initializeAuth,
275
+ getCurrentUser,
276
+ getAuthHeader,
277
+ updateProfile,
278
+ // Token refresh
279
+ refreshToken,
280
+ isRefreshing
281
+ };
282
+ }
283
+ export {
284
+ useAuth
285
+ };
286
+ //# sourceMappingURL=useAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuth.js","sources":["../../src/composables/useAuth.ts"],"sourcesContent":["import axios from 'axios'\nimport { ref, onMounted, onUnmounted, watch, type Ref } from 'vue'\nimport { useAuthStore } from '../stores/auth'\nimport { useSettingsStore } from '../stores/settings'\nimport type { AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, UpdateProfileRequest } from '../types'\n\ninterface UserResponse {\n id: string\n username: string\n shortname: string | null\n email: string | null\n role: string\n is_active: boolean\n}\n\ninterface RefreshResponse {\n access_token: string\n expires_in: number\n token_type: string\n}\n\n// Token refresh configuration\nconst TOKEN_REFRESH_MARGIN_MS = 5 * 60 * 1000 // Refresh 5 minutes before expiry\nconst TOKEN_REFRESH_CHECK_INTERVAL_MS = 60 * 1000 // Check every minute\n\n/**\n * Authentication composable with automatic token refresh.\n *\n * Features:\n * - Automatic token refresh before expiration\n * - Login/logout/register functionality\n * - Token verification on startup\n * - User profile management\n *\n * @example\n * ```typescript\n * const { login, logout, isAuthenticated, user } = useAuth()\n *\n * // Login\n * const success = await login('username', 'password')\n *\n * // Automatic refresh is enabled by default\n * // Tokens are refreshed 5 minutes before expiration\n * ```\n */\nexport interface UseAuthReturn {\n login: (username: string, password: string) => Promise<boolean>\n logout: () => void\n register: (username: string, password: string, email?: string) => Promise<boolean>\n verifyToken: () => Promise<boolean>\n fetchAuthConfig: () => Promise<AuthConfig>\n initializeAuth: () => Promise<void>\n getCurrentUser: () => Promise<UserInfo | null>\n getAuthHeader: () => Record<string, string>\n updateProfile: (data: { email?: string; shortname?: string; currentPassword?: string; newPassword?: string }) => Promise<{ success: boolean; error?: string }>\n refreshToken: () => Promise<boolean>\n isRefreshing: Ref<boolean>\n}\n\nexport function useAuth(): UseAuthReturn {\n const authStore = useAuthStore()\n const settingsStore = useSettingsStore()\n\n // Track refresh timer\n const refreshTimerId = ref<number | null>(null)\n const isRefreshing = ref(false)\n\n function getApiBaseUrl(): string {\n return settingsStore.getApiBaseUrl()\n }\n\n async function fetchAuthConfig(): Promise<AuthConfig> {\n try {\n const response = await axios.get<{\n auth_required: boolean\n passkey_enabled: boolean\n passkey_registered?: boolean\n registration_enabled?: boolean\n database_mode?: string\n }>(`${getApiBaseUrl()}/setup/config/public`)\n\n const config: AuthConfig = {\n authRequired: response.data.auth_required,\n passkeyEnabled: response.data.passkey_enabled,\n passkeyRegistered: response.data.passkey_registered ?? false,\n registrationEnabled: response.data.registration_enabled ?? false,\n databaseMode: response.data.database_mode ?? 'none',\n }\n\n authStore.setAuthConfig(config)\n return config\n } catch (error) {\n console.error('Failed to fetch auth config:', error)\n return {\n authRequired: false,\n passkeyEnabled: false,\n passkeyRegistered: false,\n registrationEnabled: false,\n databaseMode: 'none',\n }\n }\n }\n\n async function login(username: string, password: string): Promise<boolean> {\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n const response = await axios.post<LoginResponse>(\n `${getApiBaseUrl()}/auth/login`,\n { username, password }\n )\n\n authStore.setToken(response.data.access_token, response.data.expires_in)\n authStore.setUsername(username)\n\n await getCurrentUser()\n\n // Start auto-refresh after successful login\n scheduleTokenRefresh()\n\n return true\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n authStore.setError(error.response.data.detail || 'Login failed')\n } else {\n authStore.setError('Network error. Please try again.')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function register(username: string, password: string, email?: string): Promise<boolean> {\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n await axios.post<UserResponse>(\n `${getApiBaseUrl()}/users/register`,\n { username, password, email }\n )\n\n return await login(username, password)\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n authStore.setError(error.response.data.detail || 'Registration failed')\n } else {\n authStore.setError('Network error. Please try again.')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function getCurrentUser(): Promise<UserInfo | null> {\n if (!authStore.token) {\n return null\n }\n\n try {\n const response = await axios.get<UserResponse>(\n `${getApiBaseUrl()}/users/me`,\n { headers: getAuthHeader() }\n )\n\n const userInfo: UserInfo = {\n id: response.data.id,\n username: response.data.username,\n shortname: response.data.shortname,\n email: response.data.email,\n role: response.data.role,\n isActive: response.data.is_active,\n }\n\n authStore.setUserInfo(userInfo)\n return userInfo\n } catch {\n return null\n }\n }\n\n async function verifyToken(): Promise<boolean> {\n if (!authStore.token) {\n return false\n }\n\n try {\n const response = await axios.get<TokenVerifyResponse>(\n `${getApiBaseUrl()}/auth/verify`,\n {\n headers: {\n Authorization: `Bearer ${authStore.token}`,\n },\n }\n )\n\n if (response.data.valid && response.data.username) {\n authStore.setUsername(response.data.username)\n return true\n }\n\n authStore.clearToken()\n return false\n } catch {\n authStore.clearToken()\n return false\n }\n }\n\n /**\n * Refresh the authentication token.\n * Called automatically before token expiration.\n * Uses promise caching to prevent concurrent refresh requests.\n */\n let refreshPromise: Promise<boolean> | null = null\n\n async function refreshToken(): Promise<boolean> {\n if (!authStore.token) return false\n if (refreshPromise) return refreshPromise\n\n refreshPromise = (async () => {\n isRefreshing.value = true\n\n try {\n const response = await axios.post<RefreshResponse>(\n `${getApiBaseUrl()}/auth/refresh`,\n {},\n { headers: getAuthHeader() }\n )\n\n authStore.setToken(response.data.access_token, response.data.expires_in)\n\n // Reschedule next refresh\n scheduleTokenRefresh()\n\n return true\n } catch (error) {\n // If refresh fails, the token may have been revoked\n // Clear auth state and let user re-login\n if (axios.isAxiosError(error) && error.response?.status === 401) {\n console.warn('[Auth] Token refresh failed - session expired')\n authStore.clearToken()\n stopTokenRefresh()\n }\n return false\n } finally {\n isRefreshing.value = false\n refreshPromise = null\n }\n })()\n\n return refreshPromise\n }\n\n /**\n * Schedule automatic token refresh before expiration.\n */\n function scheduleTokenRefresh(): void {\n // Clear any existing timer\n stopTokenRefresh()\n\n if (!authStore.tokenExpires) {\n return\n }\n\n const expiresAt = authStore.tokenExpires.getTime()\n const refreshAt = expiresAt - TOKEN_REFRESH_MARGIN_MS\n const now = Date.now()\n\n if (refreshAt <= now) {\n // Token is already close to expiring or expired, refresh now\n refreshToken()\n return\n }\n\n // Schedule refresh\n const delay = refreshAt - now\n refreshTimerId.value = window.setTimeout(() => {\n refreshToken()\n }, delay)\n }\n\n /**\n * Stop automatic token refresh.\n */\n function stopTokenRefresh(): void {\n if (refreshTimerId.value !== null) {\n window.clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n }\n\n /**\n * Check if token needs refresh and refresh if necessary.\n * Called periodically as a safety net.\n */\n function checkAndRefreshIfNeeded(): void {\n if (!authStore.token || !authStore.tokenExpires) {\n return\n }\n\n const expiresAt = authStore.tokenExpires.getTime()\n const refreshAt = expiresAt - TOKEN_REFRESH_MARGIN_MS\n const now = Date.now()\n\n if (now >= refreshAt) {\n refreshToken()\n }\n }\n\n async function initializeAuth(): Promise<void> {\n authStore.initialize()\n await fetchAuthConfig()\n\n if (authStore.token) {\n const valid = await verifyToken()\n if (valid) {\n await getCurrentUser()\n // Start auto-refresh for existing session\n scheduleTokenRefresh()\n }\n }\n }\n\n function logout(): void {\n stopTokenRefresh()\n authStore.logout()\n }\n\n function getAuthHeader(): Record<string, string> {\n if (authStore.token) {\n return { Authorization: `Bearer ${authStore.token}` }\n }\n return {}\n }\n\n async function updateProfile(data: {\n email?: string\n shortname?: string\n currentPassword?: string\n newPassword?: string\n }): Promise<{ success: boolean; error?: string }> {\n if (!authStore.token) {\n return { success: false, error: 'Not authenticated' }\n }\n\n try {\n const requestData: UpdateProfileRequest = {}\n if (data.email !== undefined) requestData.email = data.email\n if (data.shortname !== undefined) requestData.shortname = data.shortname\n if (data.currentPassword) requestData.current_password = data.currentPassword\n if (data.newPassword) requestData.new_password = data.newPassword\n\n const response = await axios.put<UserResponse>(\n `${getApiBaseUrl()}/users/me`,\n requestData,\n { headers: getAuthHeader() }\n )\n\n const userInfo: UserInfo = {\n id: response.data.id,\n username: response.data.username,\n shortname: response.data.shortname,\n email: response.data.email,\n role: response.data.role,\n isActive: response.data.is_active,\n }\n authStore.setUserInfo(userInfo)\n\n return { success: true }\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n return { success: false, error: error.response.data.detail || 'Update failed' }\n }\n return { success: false, error: 'Network error. Please try again.' }\n }\n }\n\n // Set up periodic check as safety net\n let checkInterval: number | null = null\n\n onMounted(() => {\n // Start periodic check\n checkInterval = window.setInterval(checkAndRefreshIfNeeded, TOKEN_REFRESH_CHECK_INTERVAL_MS)\n })\n\n onUnmounted(() => {\n // Clean up on unmount\n stopTokenRefresh()\n if (checkInterval !== null) {\n window.clearInterval(checkInterval)\n checkInterval = null\n }\n })\n\n // Watch for token changes to reschedule refresh\n watch(\n () => authStore.tokenExpires,\n (newExpires) => {\n if (newExpires) {\n scheduleTokenRefresh()\n } else {\n stopTokenRefresh()\n }\n }\n )\n\n return {\n // Core auth methods\n login,\n logout,\n register,\n verifyToken,\n fetchAuthConfig,\n initializeAuth,\n getCurrentUser,\n getAuthHeader,\n updateProfile,\n\n // Token refresh\n refreshToken,\n isRefreshing,\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface ParsedElement {
2
+ symbol: string;
3
+ count: number;
4
+ }
5
+ export interface FormulaParseResult {
6
+ elements: Record<string, number>;
7
+ valid: boolean;
8
+ error?: string;
9
+ }
10
+ export type FormulaPartType = 'element' | 'subscript' | 'superscript' | 'paren' | 'dot' | 'charge';
11
+ export interface FormulaPart {
12
+ type: FormulaPartType;
13
+ text: string;
14
+ }
15
+ export declare const ATOMIC_WEIGHTS: Record<string, number>;
16
+ export declare function useChemicalFormula(): {
17
+ parseFormula: (formula: string) => FormulaParseResult;
18
+ calculateMW: (elements: Record<string, number>) => number;
19
+ renderFormulaParts: (formula: string) => FormulaPart[];
20
+ };