@morscherlab/mint-sdk 1.0.0-alpha.2

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 (491) hide show
  1. package/README.md +326 -0
  2. package/dist/__stories__/experiment-helpers.d.ts +25 -0
  3. package/dist/__tests__/components/AppLayout.test.d.ts +1 -0
  4. package/dist/__tests__/components/AppSidebar.test.d.ts +1 -0
  5. package/dist/__tests__/components/AppTopBar.test.d.ts +1 -0
  6. package/dist/__tests__/components/BaseInput.test.d.ts +1 -0
  7. package/dist/__tests__/components/BasePill.test.d.ts +1 -0
  8. package/dist/__tests__/components/Calendar.test.d.ts +1 -0
  9. package/dist/__tests__/components/CollapsibleCard.test.d.ts +1 -0
  10. package/dist/__tests__/components/DataFrame.test.d.ts +1 -0
  11. package/dist/__tests__/components/DropdownButton.test.d.ts +1 -0
  12. package/dist/__tests__/composables/formBuilderRegistry.test.d.ts +1 -0
  13. package/dist/__tests__/composables/useAppExperiment.test.d.ts +1 -0
  14. package/dist/__tests__/composables/useAuth.test.d.ts +1 -0
  15. package/dist/__tests__/composables/useAutoGroup.test.d.ts +1 -0
  16. package/dist/__tests__/composables/useExperimentData.test.d.ts +13 -0
  17. package/dist/__tests__/composables/useExperimentSave.test.d.ts +1 -0
  18. package/dist/__tests__/composables/useForm.test.d.ts +1 -0
  19. package/dist/__tests__/composables/useFormBuilder.test.d.ts +1 -0
  20. package/dist/__tests__/composables/usePlatformContext.test.d.ts +1 -0
  21. package/dist/__tests__/composables/usePluginApi.test.d.ts +13 -0
  22. package/dist/__tests__/composables/usePluginConfig.test.d.ts +14 -0
  23. package/dist/__tests__/utils/color.test.d.ts +1 -0
  24. package/dist/auth-BYmxZdJl.js +297 -0
  25. package/dist/auth-BYmxZdJl.js.map +1 -0
  26. package/dist/components/AlertBox.vue.d.ts +34 -0
  27. package/dist/components/AppAvatarMenu.vue.d.ts +58 -0
  28. package/dist/components/AppContainer.vue.d.ts +28 -0
  29. package/dist/components/AppLayout.vue.d.ts +31 -0
  30. package/dist/components/AppPageSelector.vue.d.ts +43 -0
  31. package/dist/components/AppPillNav.vue.d.ts +11 -0
  32. package/dist/components/AppPluginSwitcher.vue.d.ts +38 -0
  33. package/dist/components/AppSidebar.vue.d.ts +47 -0
  34. package/dist/components/AppTopBar.vue.d.ts +111 -0
  35. package/dist/components/AuditTrail.vue.d.ts +38 -0
  36. package/dist/components/AutoGroupModal.vue.d.ts +124 -0
  37. package/dist/components/Avatar.vue.d.ts +14 -0
  38. package/dist/components/BaseButton.vue.d.ts +37 -0
  39. package/dist/components/BaseCheckbox.vue.d.ts +17 -0
  40. package/dist/components/BaseInput.vue.d.ts +34 -0
  41. package/dist/components/BaseModal.vue.d.ts +46 -0
  42. package/dist/components/BasePill.vue.d.ts +57 -0
  43. package/dist/components/BaseRadioGroup.vue.d.ts +21 -0
  44. package/dist/components/BaseSelect.vue.d.ts +20 -0
  45. package/dist/components/BaseSlider.vue.d.ts +22 -0
  46. package/dist/components/BaseTabs.vue.d.ts +14 -0
  47. package/dist/components/BaseTextarea.vue.d.ts +30 -0
  48. package/dist/components/BaseToggle.vue.d.ts +19 -0
  49. package/dist/components/BatchProgressList.vue.d.ts +43 -0
  50. package/dist/components/Breadcrumb.vue.d.ts +33 -0
  51. package/dist/components/Calendar.vue.d.ts +107 -0
  52. package/dist/components/ChartContainer.vue.d.ts +31 -0
  53. package/dist/components/ChemicalFormula.vue.d.ts +8 -0
  54. package/dist/components/CollapsibleCard.vue.d.ts +41 -0
  55. package/dist/components/ColorSlider.vue.d.ts +34 -0
  56. package/dist/components/ConcentrationInput.vue.d.ts +25 -0
  57. package/dist/components/ConfirmDialog.vue.d.ts +42 -0
  58. package/dist/components/DataFrame.vue.d.ts +107 -0
  59. package/dist/components/DatePicker.vue.d.ts +25 -0
  60. package/dist/components/DateTimePicker.vue.d.ts +30 -0
  61. package/dist/components/Divider.vue.d.ts +14 -0
  62. package/dist/components/DoseCalculator.vue.d.ts +19 -0
  63. package/dist/components/DropdownButton.vue.d.ts +47 -0
  64. package/dist/components/EmptyState.vue.d.ts +36 -0
  65. package/dist/components/ExperimentCodeBadge.vue.d.ts +14 -0
  66. package/dist/components/ExperimentDataViewer.vue.d.ts +29 -0
  67. package/dist/components/ExperimentPopover.vue.d.ts +32 -0
  68. package/dist/components/ExperimentSelectorModal.vue.d.ts +28 -0
  69. package/dist/components/ExperimentTimeline.vue.d.ts +44 -0
  70. package/dist/components/FileUploader.vue.d.ts +40 -0
  71. package/dist/components/FitPanel.vue.d.ts +46 -0
  72. package/dist/components/FormActions.vue.d.ts +33 -0
  73. package/dist/components/FormBuilder.vue.d.ts +287 -0
  74. package/dist/components/FormField.vue.d.ts +28 -0
  75. package/dist/components/FormFieldRenderer.vue.d.ts +31 -0
  76. package/dist/components/FormSection.vue.d.ts +43 -0
  77. package/dist/components/FormulaInput.vue.d.ts +25 -0
  78. package/dist/components/GroupAssigner.vue.d.ts +25 -0
  79. package/dist/components/GroupingModal.vue.d.ts +12 -0
  80. package/dist/components/IconButton.vue.d.ts +34 -0
  81. package/dist/components/LoadingSpinner.vue.d.ts +12 -0
  82. package/dist/components/MoleculeInput.vue.d.ts +27 -0
  83. package/dist/components/MultiSelect.vue.d.ts +19 -0
  84. package/dist/components/NumberInput.vue.d.ts +22 -0
  85. package/dist/components/PlateMapEditor.vue.d.ts +50 -0
  86. package/dist/components/ProgressBar.vue.d.ts +23 -0
  87. package/dist/components/ProtocolStepEditor.vue.d.ts +24 -0
  88. package/dist/components/RackEditor.vue.d.ts +40 -0
  89. package/dist/components/ReagentEditor.vue.d.ts +30 -0
  90. package/dist/components/ReagentList.vue.d.ts +32 -0
  91. package/dist/components/ResourceCard.vue.d.ts +50 -0
  92. package/dist/components/SampleHierarchyTree.vue.d.ts +26 -0
  93. package/dist/components/SampleLegend.vue.d.ts +32 -0
  94. package/dist/components/SampleSelector.vue.d.ts +29 -0
  95. package/dist/components/ScheduleCalendar.vue.d.ts +110 -0
  96. package/dist/components/ScientificNumber.vue.d.ts +14 -0
  97. package/dist/components/SegmentedControl.vue.d.ts +20 -0
  98. package/dist/components/SequenceInput.vue.d.ts +54 -0
  99. package/dist/components/SettingsButton.vue.d.ts +30 -0
  100. package/dist/components/SettingsModal.vue.d.ts +36 -0
  101. package/dist/components/Skeleton.vue.d.ts +11 -0
  102. package/dist/components/StatusIndicator.vue.d.ts +13 -0
  103. package/dist/components/StepWizard.vue.d.ts +65 -0
  104. package/dist/components/TagsInput.vue.d.ts +39 -0
  105. package/dist/components/ThemeToggle.vue.d.ts +7 -0
  106. package/dist/components/TimePicker.vue.d.ts +29 -0
  107. package/dist/components/TimeRangeInput.vue.d.ts +27 -0
  108. package/dist/components/ToastNotification.vue.d.ts +2 -0
  109. package/dist/components/Tooltip.vue.d.ts +35 -0
  110. package/dist/components/UnitInput.vue.d.ts +39 -0
  111. package/dist/components/WellEditPopup.vue.d.ts +25 -0
  112. package/dist/components/WellPlate.vue.d.ts +73 -0
  113. package/dist/components/index.d.ts +87 -0
  114. package/dist/components/index.js +3 -0
  115. package/dist/components-CKf-UpGi.js +15089 -0
  116. package/dist/components-CKf-UpGi.js.map +1 -0
  117. package/dist/composables/experiment-utils.d.ts +8 -0
  118. package/dist/composables/formBuilderRegistry.d.ts +13 -0
  119. package/dist/composables/index.d.ts +28 -0
  120. package/dist/composables/index.js +3 -0
  121. package/dist/composables/useApi.d.ts +20 -0
  122. package/dist/composables/useAppExperiment.d.ts +37 -0
  123. package/dist/composables/useAsync.d.ts +128 -0
  124. package/dist/composables/useAuth.d.ts +47 -0
  125. package/dist/composables/useAutoGroup.d.ts +106 -0
  126. package/dist/composables/useChemicalFormula.d.ts +21 -0
  127. package/dist/composables/useConcentrationUnits.d.ts +29 -0
  128. package/dist/composables/useDoseCalculator.d.ts +58 -0
  129. package/dist/composables/useExperimentData.d.ts +18 -0
  130. package/dist/composables/useExperimentSave.d.ts +36 -0
  131. package/dist/composables/useExperimentSelector.d.ts +30 -0
  132. package/dist/composables/useForm.d.ts +92 -0
  133. package/dist/composables/useFormBuilder.d.ts +24 -0
  134. package/dist/composables/usePasskey.d.ts +10 -0
  135. package/dist/composables/usePlatformContext.d.ts +131 -0
  136. package/dist/composables/usePluginApi.d.ts +29 -0
  137. package/dist/composables/usePluginConfig.d.ts +13 -0
  138. package/dist/composables/useProtocolTemplates.d.ts +44 -0
  139. package/dist/composables/useRackEditor.d.ts +31 -0
  140. package/dist/composables/useReagentSeries.d.ts +23 -0
  141. package/dist/composables/useScheduleDrag.d.ts +78 -0
  142. package/dist/composables/useSequenceUtils.d.ts +14 -0
  143. package/dist/composables/useTheme.d.ts +8 -0
  144. package/dist/composables/useTimeUtils.d.ts +29 -0
  145. package/dist/composables/useToast.d.ts +22 -0
  146. package/dist/composables/useWellPlateEditor.d.ts +33 -0
  147. package/dist/composables-D0QfFzq1.js +805 -0
  148. package/dist/composables-D0QfFzq1.js.map +1 -0
  149. package/dist/histoire.setup.d.ts +1 -0
  150. package/dist/index.d.ts +6 -0
  151. package/dist/index.js +7 -0
  152. package/dist/install.d.ts +16 -0
  153. package/dist/install.js +23 -0
  154. package/dist/install.js.map +1 -0
  155. package/dist/stores/auth.d.ts +146 -0
  156. package/dist/stores/index.d.ts +2 -0
  157. package/dist/stores/index.js +2 -0
  158. package/dist/stores/settings.d.ts +75 -0
  159. package/dist/styles.css +29728 -0
  160. package/dist/tailwind.preset.d.ts +58 -0
  161. package/dist/tailwind.preset.js +66 -0
  162. package/dist/tailwind.preset.js.map +1 -0
  163. package/dist/types/auth.d.ts +42 -0
  164. package/dist/types/auto-group.d.ts +34 -0
  165. package/dist/types/components.d.ts +528 -0
  166. package/dist/types/form-builder.d.ts +167 -0
  167. package/dist/types/index.d.ts +5 -0
  168. package/dist/types/index.js +0 -0
  169. package/dist/types/platform.d.ts +75 -0
  170. package/dist/useScheduleDrag-DAJueTbK.js +7181 -0
  171. package/dist/useScheduleDrag-DAJueTbK.js.map +1 -0
  172. package/dist/utils/color.d.ts +24 -0
  173. package/package.json +114 -0
  174. package/src/__stories__/experiment-helpers.ts +83 -0
  175. package/src/__tests__/components/AppLayout.test.ts +163 -0
  176. package/src/__tests__/components/AppSidebar.test.ts +292 -0
  177. package/src/__tests__/components/AppTopBar.test.ts +683 -0
  178. package/src/__tests__/components/BaseInput.test.ts +99 -0
  179. package/src/__tests__/components/BasePill.test.ts +291 -0
  180. package/src/__tests__/components/Calendar.test.ts +566 -0
  181. package/src/__tests__/components/CollapsibleCard.test.ts +524 -0
  182. package/src/__tests__/components/DataFrame.test.ts +767 -0
  183. package/src/__tests__/components/DropdownButton.test.ts +471 -0
  184. package/src/__tests__/composables/formBuilderRegistry.test.ts +187 -0
  185. package/src/__tests__/composables/useAppExperiment.test.ts +560 -0
  186. package/src/__tests__/composables/useAuth.test.ts +188 -0
  187. package/src/__tests__/composables/useAutoGroup.test.ts +860 -0
  188. package/src/__tests__/composables/useExperimentData.test.ts +127 -0
  189. package/src/__tests__/composables/useExperimentSave.test.ts +347 -0
  190. package/src/__tests__/composables/useForm.test.ts +205 -0
  191. package/src/__tests__/composables/useFormBuilder.test.ts +917 -0
  192. package/src/__tests__/composables/usePlatformContext.test.ts +116 -0
  193. package/src/__tests__/composables/usePluginApi.test.ts +81 -0
  194. package/src/__tests__/composables/usePluginConfig.test.ts +176 -0
  195. package/src/__tests__/utils/color.test.ts +96 -0
  196. package/src/components/AlertBox.story.vue +204 -0
  197. package/src/components/AlertBox.vue +88 -0
  198. package/src/components/AppAvatarMenu.story.vue +155 -0
  199. package/src/components/AppAvatarMenu.vue +184 -0
  200. package/src/components/AppContainer.story.vue +104 -0
  201. package/src/components/AppContainer.vue +34 -0
  202. package/src/components/AppLayout.story.vue +292 -0
  203. package/src/components/AppLayout.vue +75 -0
  204. package/src/components/AppPageSelector.vue +159 -0
  205. package/src/components/AppPillNav.vue +66 -0
  206. package/src/components/AppPluginSwitcher.vue +241 -0
  207. package/src/components/AppSidebar.story.vue +309 -0
  208. package/src/components/AppSidebar.vue +119 -0
  209. package/src/components/AppTopBar.story.vue +304 -0
  210. package/src/components/AppTopBar.vue +661 -0
  211. package/src/components/AuditTrail.story.vue +163 -0
  212. package/src/components/AuditTrail.vue +151 -0
  213. package/src/components/AutoGroupModal.story.vue +273 -0
  214. package/src/components/AutoGroupModal.vue +566 -0
  215. package/src/components/Avatar.story.vue +115 -0
  216. package/src/components/Avatar.vue +79 -0
  217. package/src/components/BaseButton.story.vue +96 -0
  218. package/src/components/BaseButton.vue +73 -0
  219. package/src/components/BaseCheckbox.story.vue +73 -0
  220. package/src/components/BaseCheckbox.vue +69 -0
  221. package/src/components/BaseInput.story.vue +98 -0
  222. package/src/components/BaseInput.vue +74 -0
  223. package/src/components/BaseModal.story.vue +237 -0
  224. package/src/components/BaseModal.vue +182 -0
  225. package/src/components/BasePill.story.vue +142 -0
  226. package/src/components/BasePill.vue +89 -0
  227. package/src/components/BaseRadioGroup.story.vue +145 -0
  228. package/src/components/BaseRadioGroup.vue +124 -0
  229. package/src/components/BaseSelect.story.vue +120 -0
  230. package/src/components/BaseSelect.vue +71 -0
  231. package/src/components/BaseSlider.story.vue +122 -0
  232. package/src/components/BaseSlider.vue +126 -0
  233. package/src/components/BaseTabs.story.vue +127 -0
  234. package/src/components/BaseTabs.vue +59 -0
  235. package/src/components/BaseTextarea.story.vue +91 -0
  236. package/src/components/BaseTextarea.vue +62 -0
  237. package/src/components/BaseToggle.story.vue +81 -0
  238. package/src/components/BaseToggle.vue +76 -0
  239. package/src/components/BatchProgressList.story.vue +92 -0
  240. package/src/components/BatchProgressList.vue +184 -0
  241. package/src/components/Breadcrumb.story.vue +106 -0
  242. package/src/components/Breadcrumb.vue +75 -0
  243. package/src/components/Calendar.story.vue +106 -0
  244. package/src/components/Calendar.vue +363 -0
  245. package/src/components/ChartContainer.story.vue +113 -0
  246. package/src/components/ChartContainer.vue +64 -0
  247. package/src/components/ChemicalFormula.story.vue +102 -0
  248. package/src/components/ChemicalFormula.vue +39 -0
  249. package/src/components/CollapsibleCard.story.vue +135 -0
  250. package/src/components/CollapsibleCard.vue +167 -0
  251. package/src/components/ColorSlider.story.vue +120 -0
  252. package/src/components/ColorSlider.vue +164 -0
  253. package/src/components/ConcentrationInput.story.vue +77 -0
  254. package/src/components/ConcentrationInput.vue +185 -0
  255. package/src/components/ConfirmDialog.story.vue +248 -0
  256. package/src/components/ConfirmDialog.vue +93 -0
  257. package/src/components/DataFrame.story.vue +148 -0
  258. package/src/components/DataFrame.vue +419 -0
  259. package/src/components/DatePicker.story.vue +119 -0
  260. package/src/components/DatePicker.vue +330 -0
  261. package/src/components/DateTimePicker.story.vue +112 -0
  262. package/src/components/DateTimePicker.vue +392 -0
  263. package/src/components/Divider.story.vue +80 -0
  264. package/src/components/Divider.vue +49 -0
  265. package/src/components/DoseCalculator.story.vue +68 -0
  266. package/src/components/DoseCalculator.vue +476 -0
  267. package/src/components/DropdownButton.story.vue +102 -0
  268. package/src/components/DropdownButton.vue +181 -0
  269. package/src/components/EmptyState.story.vue +135 -0
  270. package/src/components/EmptyState.vue +69 -0
  271. package/src/components/ExperimentCodeBadge.story.vue +77 -0
  272. package/src/components/ExperimentCodeBadge.vue +64 -0
  273. package/src/components/ExperimentDataViewer.story.vue +174 -0
  274. package/src/components/ExperimentDataViewer.vue +288 -0
  275. package/src/components/ExperimentPopover.story.vue +384 -0
  276. package/src/components/ExperimentPopover.vue +241 -0
  277. package/src/components/ExperimentSelectorModal.story.vue +391 -0
  278. package/src/components/ExperimentSelectorModal.vue +387 -0
  279. package/src/components/ExperimentTimeline.story.vue +161 -0
  280. package/src/components/ExperimentTimeline.vue +382 -0
  281. package/src/components/FileUploader.story.vue +107 -0
  282. package/src/components/FileUploader.vue +386 -0
  283. package/src/components/FitPanel.story.vue +125 -0
  284. package/src/components/FitPanel.vue +120 -0
  285. package/src/components/FormActions.vue +92 -0
  286. package/src/components/FormBuilder.vue +214 -0
  287. package/src/components/FormField.story.vue +132 -0
  288. package/src/components/FormField.vue +59 -0
  289. package/src/components/FormFieldRenderer.vue +58 -0
  290. package/src/components/FormSection.vue +90 -0
  291. package/src/components/FormulaInput.story.vue +96 -0
  292. package/src/components/FormulaInput.vue +125 -0
  293. package/src/components/GroupAssigner.story.vue +83 -0
  294. package/src/components/GroupAssigner.vue +284 -0
  295. package/src/components/GroupingModal.story.vue +52 -0
  296. package/src/components/GroupingModal.vue +422 -0
  297. package/src/components/IconButton.story.vue +135 -0
  298. package/src/components/IconButton.vue +73 -0
  299. package/src/components/LoadingSpinner.story.vue +70 -0
  300. package/src/components/LoadingSpinner.vue +50 -0
  301. package/src/components/MoleculeInput.story.vue +66 -0
  302. package/src/components/MoleculeInput.vue +426 -0
  303. package/src/components/MultiSelect.story.vue +132 -0
  304. package/src/components/MultiSelect.vue +118 -0
  305. package/src/components/NumberInput.story.vue +122 -0
  306. package/src/components/NumberInput.vue +160 -0
  307. package/src/components/PlateMapEditor.story.vue +92 -0
  308. package/src/components/PlateMapEditor.vue +513 -0
  309. package/src/components/ProgressBar.story.vue +148 -0
  310. package/src/components/ProgressBar.vue +114 -0
  311. package/src/components/ProtocolStepEditor.story.vue +69 -0
  312. package/src/components/ProtocolStepEditor.vue +522 -0
  313. package/src/components/RackEditor.story.vue +100 -0
  314. package/src/components/RackEditor.vue +371 -0
  315. package/src/components/ReagentEditor.story.vue +153 -0
  316. package/src/components/ReagentEditor.vue +418 -0
  317. package/src/components/ReagentList.story.vue +137 -0
  318. package/src/components/ReagentList.vue +463 -0
  319. package/src/components/ResourceCard.story.vue +150 -0
  320. package/src/components/ResourceCard.vue +161 -0
  321. package/src/components/SampleHierarchyTree.story.vue +161 -0
  322. package/src/components/SampleHierarchyTree.vue +256 -0
  323. package/src/components/SampleLegend.story.vue +91 -0
  324. package/src/components/SampleLegend.vue +119 -0
  325. package/src/components/SampleSelector.story.vue +111 -0
  326. package/src/components/SampleSelector.vue +1033 -0
  327. package/src/components/ScheduleCalendar.story.vue +195 -0
  328. package/src/components/ScheduleCalendar.vue +569 -0
  329. package/src/components/ScientificNumber.story.vue +127 -0
  330. package/src/components/ScientificNumber.vue +197 -0
  331. package/src/components/SegmentedControl.story.vue +132 -0
  332. package/src/components/SegmentedControl.vue +79 -0
  333. package/src/components/SequenceInput.story.vue +119 -0
  334. package/src/components/SequenceInput.vue +209 -0
  335. package/src/components/SettingsButton.story.vue +58 -0
  336. package/src/components/SettingsButton.vue +76 -0
  337. package/src/components/SettingsModal.story.vue +145 -0
  338. package/src/components/SettingsModal.vue +146 -0
  339. package/src/components/Skeleton.story.vue +141 -0
  340. package/src/components/Skeleton.vue +74 -0
  341. package/src/components/StatusIndicator.story.vue +99 -0
  342. package/src/components/StatusIndicator.vue +40 -0
  343. package/src/components/StepWizard.story.vue +155 -0
  344. package/src/components/StepWizard.vue +223 -0
  345. package/src/components/TagsInput.story.vue +155 -0
  346. package/src/components/TagsInput.vue +265 -0
  347. package/src/components/ThemeToggle.story.vue +36 -0
  348. package/src/components/ThemeToggle.vue +54 -0
  349. package/src/components/TimePicker.story.vue +96 -0
  350. package/src/components/TimePicker.vue +273 -0
  351. package/src/components/TimeRangeInput.story.vue +104 -0
  352. package/src/components/TimeRangeInput.vue +122 -0
  353. package/src/components/ToastNotification.story.vue +157 -0
  354. package/src/components/ToastNotification.vue +62 -0
  355. package/src/components/Tooltip.story.vue +138 -0
  356. package/src/components/Tooltip.vue +119 -0
  357. package/src/components/UnitInput.story.vue +194 -0
  358. package/src/components/UnitInput.vue +213 -0
  359. package/src/components/WellEditPopup.vue +234 -0
  360. package/src/components/WellPlate.story.vue +282 -0
  361. package/src/components/WellPlate.vue +830 -0
  362. package/src/components/index.ts +118 -0
  363. package/src/composables/experiment-utils.ts +57 -0
  364. package/src/composables/formBuilderRegistry.ts +79 -0
  365. package/src/composables/index.ts +140 -0
  366. package/src/composables/useApi.ts +167 -0
  367. package/src/composables/useAppExperiment.ts +159 -0
  368. package/src/composables/useAsync.ts +323 -0
  369. package/src/composables/useAuth.ts +445 -0
  370. package/src/composables/useAutoGroup.ts +641 -0
  371. package/src/composables/useChemicalFormula.ts +275 -0
  372. package/src/composables/useConcentrationUnits.ts +246 -0
  373. package/src/composables/useDoseCalculator.ts +370 -0
  374. package/src/composables/useExperimentData.ts +86 -0
  375. package/src/composables/useExperimentSave.ts +192 -0
  376. package/src/composables/useExperimentSelector.ts +292 -0
  377. package/src/composables/useForm.ts +416 -0
  378. package/src/composables/useFormBuilder.ts +383 -0
  379. package/src/composables/usePasskey.ts +216 -0
  380. package/src/composables/usePlatformContext.ts +299 -0
  381. package/src/composables/usePluginApi.ts +39 -0
  382. package/src/composables/usePluginConfig.ts +93 -0
  383. package/src/composables/useProtocolTemplates.ts +518 -0
  384. package/src/composables/useRackEditor.ts +222 -0
  385. package/src/composables/useReagentSeries.ts +91 -0
  386. package/src/composables/useScheduleDrag.ts +245 -0
  387. package/src/composables/useSequenceUtils.ts +105 -0
  388. package/src/composables/useTheme.ts +58 -0
  389. package/src/composables/useTimeUtils.ts +131 -0
  390. package/src/composables/useToast.ts +40 -0
  391. package/src/composables/useWellPlateEditor.ts +421 -0
  392. package/src/histoire.setup.ts +17 -0
  393. package/src/index.ts +367 -0
  394. package/src/install.ts +32 -0
  395. package/src/stores/auth.ts +152 -0
  396. package/src/stores/index.ts +2 -0
  397. package/src/stores/settings.ts +218 -0
  398. package/src/styles/components/alert-box.css +150 -0
  399. package/src/styles/components/app-avatar-menu.css +155 -0
  400. package/src/styles/components/app-container.css +33 -0
  401. package/src/styles/components/app-layout.css +98 -0
  402. package/src/styles/components/app-page-selector.css +191 -0
  403. package/src/styles/components/app-pill-nav.css +57 -0
  404. package/src/styles/components/app-plugin-switcher.css +209 -0
  405. package/src/styles/components/app-sidebar.css +145 -0
  406. package/src/styles/components/app-top-bar.css +492 -0
  407. package/src/styles/components/audit-trail.css +143 -0
  408. package/src/styles/components/auto-group-modal.css +644 -0
  409. package/src/styles/components/avatar.css +73 -0
  410. package/src/styles/components/batch-progress-list.css +196 -0
  411. package/src/styles/components/breadcrumb.css +64 -0
  412. package/src/styles/components/button.css +188 -0
  413. package/src/styles/components/calendar.css +192 -0
  414. package/src/styles/components/chart-container.css +69 -0
  415. package/src/styles/components/checkbox.css +123 -0
  416. package/src/styles/components/chemical-formula.css +46 -0
  417. package/src/styles/components/collapsible-card.css +253 -0
  418. package/src/styles/components/color-slider.css +110 -0
  419. package/src/styles/components/concentration-input.css +156 -0
  420. package/src/styles/components/confirm-dialog.css +183 -0
  421. package/src/styles/components/dataframe.css +382 -0
  422. package/src/styles/components/date-picker.css +243 -0
  423. package/src/styles/components/datetime-picker.css +229 -0
  424. package/src/styles/components/divider.css +63 -0
  425. package/src/styles/components/dose-calculator.css +301 -0
  426. package/src/styles/components/dropdown-button.css +280 -0
  427. package/src/styles/components/empty-state.css +151 -0
  428. package/src/styles/components/experiment-code-badge.css +33 -0
  429. package/src/styles/components/experiment-data-viewer.css +138 -0
  430. package/src/styles/components/experiment-popover.css +562 -0
  431. package/src/styles/components/experiment-selector-modal.css +285 -0
  432. package/src/styles/components/experiment-timeline.css +529 -0
  433. package/src/styles/components/file-uploader.css +310 -0
  434. package/src/styles/components/fit-panel.css +67 -0
  435. package/src/styles/components/form-builder.css +69 -0
  436. package/src/styles/components/form-field.css +48 -0
  437. package/src/styles/components/formula-input.css +103 -0
  438. package/src/styles/components/group-assigner.css +200 -0
  439. package/src/styles/components/grouping-modal.css +323 -0
  440. package/src/styles/components/icon-button.css +192 -0
  441. package/src/styles/components/input.css +66 -0
  442. package/src/styles/components/loading-spinner.css +67 -0
  443. package/src/styles/components/modal.css +350 -0
  444. package/src/styles/components/molecule-input.css +186 -0
  445. package/src/styles/components/multi-select.css +131 -0
  446. package/src/styles/components/number-input.css +199 -0
  447. package/src/styles/components/pill.css +188 -0
  448. package/src/styles/components/plate-map-editor.css +464 -0
  449. package/src/styles/components/progress-bar.css +133 -0
  450. package/src/styles/components/protocol-step-editor.css +449 -0
  451. package/src/styles/components/rack-editor.css +265 -0
  452. package/src/styles/components/radio-group.css +240 -0
  453. package/src/styles/components/reagent-editor.css +510 -0
  454. package/src/styles/components/reagent-list.css +407 -0
  455. package/src/styles/components/resource-card.css +360 -0
  456. package/src/styles/components/sample-hierarchy-tree.css +314 -0
  457. package/src/styles/components/sample-legend.css +201 -0
  458. package/src/styles/components/sample-selector.css +751 -0
  459. package/src/styles/components/schedule-calendar.css +478 -0
  460. package/src/styles/components/scientific-number.css +63 -0
  461. package/src/styles/components/segmented-control.css +197 -0
  462. package/src/styles/components/select.css +77 -0
  463. package/src/styles/components/sequence-input.css +184 -0
  464. package/src/styles/components/settings-button.css +94 -0
  465. package/src/styles/components/settings-modal.css +95 -0
  466. package/src/styles/components/skeleton.css +49 -0
  467. package/src/styles/components/slider.css +74 -0
  468. package/src/styles/components/status-indicator.css +66 -0
  469. package/src/styles/components/step-wizard.css +192 -0
  470. package/src/styles/components/tabs.css +95 -0
  471. package/src/styles/components/tags-input.css +195 -0
  472. package/src/styles/components/textarea.css +82 -0
  473. package/src/styles/components/theme-toggle.css +69 -0
  474. package/src/styles/components/time-picker.css +171 -0
  475. package/src/styles/components/time-range-input.css +42 -0
  476. package/src/styles/components/toast.css +91 -0
  477. package/src/styles/components/toggle.css +146 -0
  478. package/src/styles/components/tooltip.css +91 -0
  479. package/src/styles/components/unit-input.css +123 -0
  480. package/src/styles/components/well-edit-popup.css +252 -0
  481. package/src/styles/components/well-plate.css +307 -0
  482. package/src/styles/index.css +87 -0
  483. package/src/styles/variables.css +1117 -0
  484. package/src/tailwind.preset.ts +61 -0
  485. package/src/types/auth.ts +55 -0
  486. package/src/types/auto-group.ts +40 -0
  487. package/src/types/components.ts +710 -0
  488. package/src/types/form-builder.ts +197 -0
  489. package/src/types/index.ts +207 -0
  490. package/src/types/platform.ts +116 -0
  491. package/src/utils/color.ts +96 -0
@@ -0,0 +1,805 @@
1
+ import { M as usePlatformContext, V as useApi } from "./useScheduleDrag-DAJueTbK.js";
2
+ import { r as useSettingsStore, t as useAuthStore } from "./auth-BYmxZdJl.js";
3
+ import { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from "vue";
4
+ import axios from "axios";
5
+ //#region src/composables/useAuth.ts
6
+ var TOKEN_REFRESH_MARGIN_MS = 300 * 1e3;
7
+ var TOKEN_REFRESH_CHECK_INTERVAL_MS = 60 * 1e3;
8
+ var _refreshPromise = null;
9
+ var _refreshTimerId = null;
10
+ var _mountedConsumerCount = 0;
11
+ /** Manages authentication state with login/logout/register and automatic JWT token refresh. */
12
+ function useAuth() {
13
+ const authStore = useAuthStore();
14
+ const settingsStore = useSettingsStore();
15
+ const isRefreshing = ref(false);
16
+ function getApiBaseUrl() {
17
+ return settingsStore.getApiBaseUrl();
18
+ }
19
+ async function fetchAuthConfig() {
20
+ try {
21
+ const response = await axios.get(`${getApiBaseUrl()}/setup/config/public`);
22
+ const config = {
23
+ authRequired: response.data.auth_required,
24
+ passkeyEnabled: response.data.passkey_enabled,
25
+ passkeyRegistered: response.data.passkey_registered ?? false,
26
+ registrationEnabled: response.data.registration_enabled ?? false,
27
+ databaseMode: response.data.database_mode ?? "none"
28
+ };
29
+ authStore.setAuthConfig(config);
30
+ return config;
31
+ } catch (error) {
32
+ console.error("Failed to fetch auth config:", error);
33
+ return {
34
+ authRequired: false,
35
+ passkeyEnabled: false,
36
+ passkeyRegistered: false,
37
+ registrationEnabled: false,
38
+ databaseMode: "none"
39
+ };
40
+ }
41
+ }
42
+ async function login(username, password) {
43
+ authStore.setLoading(true);
44
+ authStore.setError(null);
45
+ try {
46
+ const response = await axios.post(`${getApiBaseUrl()}/auth/login`, {
47
+ username,
48
+ password
49
+ });
50
+ authStore.setToken(response.data.access_token, response.data.expires_in);
51
+ authStore.setUsername(username);
52
+ await getCurrentUser();
53
+ scheduleTokenRefresh();
54
+ return true;
55
+ } catch (error) {
56
+ if (axios.isAxiosError(error) && error.response) authStore.setError(error.response.data.detail || "Login failed");
57
+ else authStore.setError("Network error. Please try again.");
58
+ return false;
59
+ } finally {
60
+ authStore.setLoading(false);
61
+ }
62
+ }
63
+ async function register(username, password, email) {
64
+ authStore.setLoading(true);
65
+ authStore.setError(null);
66
+ try {
67
+ await axios.post(`${getApiBaseUrl()}/users/register`, {
68
+ username,
69
+ password,
70
+ email
71
+ });
72
+ return await login(username, password);
73
+ } catch (error) {
74
+ if (axios.isAxiosError(error) && error.response) authStore.setError(error.response.data.detail || "Registration failed");
75
+ else authStore.setError("Network error. Please try again.");
76
+ return false;
77
+ } finally {
78
+ authStore.setLoading(false);
79
+ }
80
+ }
81
+ async function getCurrentUser() {
82
+ if (!authStore.token) return null;
83
+ try {
84
+ const response = await axios.get(`${getApiBaseUrl()}/users/me`, { headers: getAuthHeader() });
85
+ const userInfo = {
86
+ id: response.data.id,
87
+ username: response.data.username,
88
+ shortname: response.data.shortname,
89
+ email: response.data.email,
90
+ role: response.data.role,
91
+ isActive: response.data.is_active
92
+ };
93
+ authStore.setUserInfo(userInfo);
94
+ return userInfo;
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+ async function verifyToken() {
100
+ if (!authStore.token) return false;
101
+ try {
102
+ const response = await axios.get(`${getApiBaseUrl()}/auth/verify`, { headers: { Authorization: `Bearer ${authStore.token}` } });
103
+ if (response.data.valid && response.data.username) {
104
+ authStore.setUsername(response.data.username);
105
+ return true;
106
+ }
107
+ authStore.clearToken();
108
+ return false;
109
+ } catch {
110
+ authStore.clearToken();
111
+ return false;
112
+ }
113
+ }
114
+ /**
115
+ * Refresh the authentication token.
116
+ * Called automatically before token expiration.
117
+ * Uses promise caching to prevent concurrent refresh requests.
118
+ */
119
+ async function refreshToken() {
120
+ if (!authStore.token) return false;
121
+ if (_refreshPromise) return _refreshPromise;
122
+ _refreshPromise = (async () => {
123
+ isRefreshing.value = true;
124
+ try {
125
+ const response = await axios.post(`${getApiBaseUrl()}/auth/refresh`, {}, { headers: getAuthHeader() });
126
+ authStore.setToken(response.data.access_token, response.data.expires_in);
127
+ scheduleTokenRefresh();
128
+ return true;
129
+ } catch (error) {
130
+ if (axios.isAxiosError(error) && error.response?.status === 401) {
131
+ console.warn("[Auth] Token refresh failed - session expired");
132
+ authStore.clearToken();
133
+ stopTokenRefresh();
134
+ }
135
+ return false;
136
+ } finally {
137
+ isRefreshing.value = false;
138
+ _refreshPromise = null;
139
+ }
140
+ })();
141
+ return _refreshPromise;
142
+ }
143
+ /**
144
+ * Schedule automatic token refresh before expiration.
145
+ */
146
+ function scheduleTokenRefresh() {
147
+ stopTokenRefresh();
148
+ if (!authStore.tokenExpires) return;
149
+ const refreshAt = authStore.tokenExpires.getTime() - TOKEN_REFRESH_MARGIN_MS;
150
+ const now = Date.now();
151
+ if (refreshAt <= now) {
152
+ refreshToken();
153
+ return;
154
+ }
155
+ const delay = refreshAt - now;
156
+ _refreshTimerId = window.setTimeout(() => {
157
+ refreshToken();
158
+ }, delay);
159
+ }
160
+ /**
161
+ * Stop automatic token refresh.
162
+ */
163
+ function stopTokenRefresh() {
164
+ if (_refreshTimerId !== null) {
165
+ window.clearTimeout(_refreshTimerId);
166
+ _refreshTimerId = null;
167
+ }
168
+ }
169
+ /**
170
+ * Check if token needs refresh and refresh if necessary.
171
+ * Called periodically as a safety net.
172
+ */
173
+ function checkAndRefreshIfNeeded() {
174
+ if (!authStore.token || !authStore.tokenExpires) return;
175
+ const refreshAt = authStore.tokenExpires.getTime() - TOKEN_REFRESH_MARGIN_MS;
176
+ if (Date.now() >= refreshAt) refreshToken();
177
+ }
178
+ async function initializeAuth() {
179
+ authStore.initialize();
180
+ await fetchAuthConfig();
181
+ if (authStore.token) {
182
+ if (await verifyToken()) {
183
+ await getCurrentUser();
184
+ scheduleTokenRefresh();
185
+ }
186
+ }
187
+ }
188
+ function logout() {
189
+ stopTokenRefresh();
190
+ authStore.logout();
191
+ }
192
+ function getAuthHeader() {
193
+ if (authStore.token) return { Authorization: `Bearer ${authStore.token}` };
194
+ return {};
195
+ }
196
+ async function updateProfile(data) {
197
+ if (!authStore.token) return {
198
+ success: false,
199
+ error: "Not authenticated"
200
+ };
201
+ try {
202
+ const requestData = {};
203
+ if (data.email !== void 0) requestData.email = data.email;
204
+ if (data.shortname !== void 0) requestData.shortname = data.shortname;
205
+ if (data.currentPassword) requestData.current_password = data.currentPassword;
206
+ if (data.newPassword) requestData.new_password = data.newPassword;
207
+ const response = await axios.put(`${getApiBaseUrl()}/users/me`, requestData, { headers: getAuthHeader() });
208
+ const userInfo = {
209
+ id: response.data.id,
210
+ username: response.data.username,
211
+ shortname: response.data.shortname,
212
+ email: response.data.email,
213
+ role: response.data.role,
214
+ isActive: response.data.is_active
215
+ };
216
+ authStore.setUserInfo(userInfo);
217
+ return { success: true };
218
+ } catch (error) {
219
+ if (axios.isAxiosError(error) && error.response) return {
220
+ success: false,
221
+ error: error.response.data.detail || "Update failed"
222
+ };
223
+ return {
224
+ success: false,
225
+ error: "Network error. Please try again."
226
+ };
227
+ }
228
+ }
229
+ let checkInterval = null;
230
+ if (getCurrentInstance()) {
231
+ onMounted(() => {
232
+ _mountedConsumerCount += 1;
233
+ checkInterval = window.setInterval(checkAndRefreshIfNeeded, TOKEN_REFRESH_CHECK_INTERVAL_MS);
234
+ });
235
+ onUnmounted(() => {
236
+ if (checkInterval !== null) {
237
+ window.clearInterval(checkInterval);
238
+ checkInterval = null;
239
+ }
240
+ _mountedConsumerCount = Math.max(0, _mountedConsumerCount - 1);
241
+ if (_mountedConsumerCount === 0) stopTokenRefresh();
242
+ });
243
+ watch(() => authStore.tokenExpires, (newExpires) => {
244
+ if (newExpires) scheduleTokenRefresh();
245
+ else stopTokenRefresh();
246
+ });
247
+ }
248
+ return {
249
+ login,
250
+ logout,
251
+ register,
252
+ verifyToken,
253
+ fetchAuthConfig,
254
+ initializeAuth,
255
+ getCurrentUser,
256
+ getAuthHeader,
257
+ updateProfile,
258
+ refreshToken,
259
+ isRefreshing
260
+ };
261
+ }
262
+ //#endregion
263
+ //#region src/composables/usePasskey.ts
264
+ async function loadWebAuthn() {
265
+ try {
266
+ return await import("@simplewebauthn/browser");
267
+ } catch {
268
+ throw new Error("@simplewebauthn/browser is required for passkey support. Install it: bun add @simplewebauthn/browser");
269
+ }
270
+ }
271
+ /** Registers and authenticates passkeys using WebAuthn, lazily loading the browser dependency. */
272
+ function usePasskey() {
273
+ const authStore = useAuthStore();
274
+ const settingsStore = useSettingsStore();
275
+ function getApiBaseUrl() {
276
+ return settingsStore.getApiBaseUrl();
277
+ }
278
+ async function isSupported() {
279
+ try {
280
+ const { browserSupportsWebAuthn } = await loadWebAuthn();
281
+ return browserSupportsWebAuthn();
282
+ } catch {
283
+ return false;
284
+ }
285
+ }
286
+ async function registerPasskey(deviceName) {
287
+ const webauthn = await loadWebAuthn();
288
+ if (!webauthn.browserSupportsWebAuthn()) {
289
+ authStore.setError("WebAuthn is not supported in this browser");
290
+ return false;
291
+ }
292
+ authStore.setLoading(true);
293
+ authStore.setError(null);
294
+ try {
295
+ const optionsResponse = await axios.get(`${getApiBaseUrl()}/auth/passkey/register/options`, {
296
+ headers: { Authorization: `Bearer ${authStore.token}` },
297
+ withCredentials: true
298
+ });
299
+ const options = JSON.parse(optionsResponse.data.options);
300
+ const credential = await webauthn.startRegistration(options);
301
+ await axios.post(`${getApiBaseUrl()}/auth/passkey/register/verify`, {
302
+ credential: JSON.stringify(credential),
303
+ device_name: deviceName
304
+ }, {
305
+ headers: { Authorization: `Bearer ${authStore.token}` },
306
+ withCredentials: true
307
+ });
308
+ authStore.setAuthConfig({
309
+ ...authStore.authConfig,
310
+ passkeyRegistered: true
311
+ });
312
+ return true;
313
+ } catch (error) {
314
+ if (axios.isAxiosError(error) && error.response) authStore.setError(error.response.data.detail || "Passkey registration failed");
315
+ else if (error instanceof Error) if (error.name === "NotAllowedError") authStore.setError("Registration was cancelled or timed out");
316
+ else if (error.name === "InvalidStateError") authStore.setError("This authenticator is already registered");
317
+ else authStore.setError(error.message);
318
+ else authStore.setError("Passkey registration failed");
319
+ return false;
320
+ } finally {
321
+ authStore.setLoading(false);
322
+ }
323
+ }
324
+ async function loginWithPasskey() {
325
+ const webauthn = await loadWebAuthn();
326
+ if (!webauthn.browserSupportsWebAuthn()) {
327
+ authStore.setError("WebAuthn is not supported in this browser");
328
+ return false;
329
+ }
330
+ authStore.setLoading(true);
331
+ authStore.setError(null);
332
+ try {
333
+ const optionsResponse = await axios.get(`${getApiBaseUrl()}/auth/passkey/login/options`, { withCredentials: true });
334
+ const options = JSON.parse(optionsResponse.data.options);
335
+ const credential = await webauthn.startAuthentication(options);
336
+ const response = await axios.post(`${getApiBaseUrl()}/auth/passkey/login/verify`, { credential: JSON.stringify(credential) }, { withCredentials: true });
337
+ authStore.setToken(response.data.access_token, response.data.expires_in);
338
+ return true;
339
+ } catch (error) {
340
+ if (axios.isAxiosError(error) && error.response) if (error.response.status === 404) authStore.setError("No passkeys registered. Please login with password first.");
341
+ else authStore.setError(error.response.data.detail || "Passkey login failed");
342
+ else if (error instanceof Error) if (error.name === "NotAllowedError") authStore.setError("Authentication was cancelled or timed out");
343
+ else authStore.setError(error.message);
344
+ else authStore.setError("Passkey login failed");
345
+ return false;
346
+ } finally {
347
+ authStore.setLoading(false);
348
+ }
349
+ }
350
+ async function listCredentials() {
351
+ try {
352
+ return (await axios.get(`${getApiBaseUrl()}/auth/passkey/credentials`, { headers: { Authorization: `Bearer ${authStore.token}` } })).data.credentials;
353
+ } catch {
354
+ return [];
355
+ }
356
+ }
357
+ async function deleteCredential(credentialId) {
358
+ try {
359
+ await axios.delete(`${getApiBaseUrl()}/auth/passkey/credentials/${encodeURIComponent(credentialId)}`, { headers: { Authorization: `Bearer ${authStore.token}` } });
360
+ if ((await listCredentials()).length === 0) authStore.setAuthConfig({
361
+ ...authStore.authConfig,
362
+ passkeyRegistered: false
363
+ });
364
+ return true;
365
+ } catch {
366
+ return false;
367
+ }
368
+ }
369
+ async function deleteAllCredentials() {
370
+ try {
371
+ await axios.delete(`${getApiBaseUrl()}/auth/passkey/credentials`, { headers: { Authorization: `Bearer ${authStore.token}` } });
372
+ authStore.setAuthConfig({
373
+ ...authStore.authConfig,
374
+ passkeyRegistered: false
375
+ });
376
+ return true;
377
+ } catch {
378
+ return false;
379
+ }
380
+ }
381
+ return {
382
+ isSupported,
383
+ registerPasskey,
384
+ loginWithPasskey,
385
+ listCredentials,
386
+ deleteCredential,
387
+ deleteAllCredentials
388
+ };
389
+ }
390
+ //#endregion
391
+ //#region src/composables/useAsync.ts
392
+ /**
393
+ * Default error transformer.
394
+ */
395
+ function defaultTransformError(error) {
396
+ if (error instanceof Error) return {
397
+ message: error.message,
398
+ originalError: error
399
+ };
400
+ if (typeof error === "object" && error !== null) {
401
+ const errorObj = error;
402
+ if ("response" in errorObj && errorObj.response) {
403
+ const response = errorObj.response;
404
+ const data = response.data;
405
+ return {
406
+ message: data?.detail || data?.message || "Request failed",
407
+ code: String(response.status),
408
+ details: data,
409
+ originalError: error
410
+ };
411
+ }
412
+ return {
413
+ message: errorObj.message || "Unknown error",
414
+ code: errorObj.code,
415
+ details: errorObj,
416
+ originalError: error
417
+ };
418
+ }
419
+ return {
420
+ message: String(error),
421
+ originalError: error
422
+ };
423
+ }
424
+ /**
425
+ * Composable for managing async operation state.
426
+ *
427
+ * Provides standardized loading, error, and success state management
428
+ * for any async function.
429
+ *
430
+ * @param asyncFn - The async function to wrap
431
+ * @param options - Configuration options
432
+ *
433
+ * @example
434
+ * ```typescript
435
+ * // Basic usage
436
+ * const { data, isLoading, error, execute } = useAsync(
437
+ * async (id: string) => {
438
+ * const response = await api.get(`/users/${id}`)
439
+ * return response.data
440
+ * }
441
+ * )
442
+ *
443
+ * // Execute the function
444
+ * await execute('user-123')
445
+ *
446
+ * // In template
447
+ * <div v-if="isLoading">Loading...</div>
448
+ * <div v-else-if="error">{{ error.message }}</div>
449
+ * <div v-else-if="data">{{ data.name }}</div>
450
+ * ```
451
+ *
452
+ * @example
453
+ * ```typescript
454
+ * // With options
455
+ * const { data, execute } = useAsync(
456
+ * fetchUser,
457
+ * {
458
+ * immediate: true,
459
+ * immediateArgs: ['default-user'],
460
+ * onSuccess: (user) => console.log('Fetched:', user.name),
461
+ * onError: (error) => toast.error(error.message),
462
+ * }
463
+ * )
464
+ * ```
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * // Form submission
469
+ * const { isLoading, error, execute: submit } = useAsync(
470
+ * async (formData: FormData) => {
471
+ * await api.post('/submit', formData)
472
+ * },
473
+ * {
474
+ * onSuccess: () => {
475
+ * toast.success('Submitted!')
476
+ * router.push('/success')
477
+ * },
478
+ * }
479
+ * )
480
+ *
481
+ * const handleSubmit = () => submit(new FormData(formRef.value))
482
+ * ```
483
+ */
484
+ /** Wraps an async function with reactive loading, error, and success state plus optional auto-execute. */
485
+ function useAsync(asyncFn, options = {}) {
486
+ const { initialData = null, immediate = false, immediateArgs = [], transformError = defaultTransformError, onSuccess, onError, resetOnExecute = false } = options;
487
+ const data = ref(initialData);
488
+ const error = ref(null);
489
+ const state = ref("idle");
490
+ const isIdle = computed(() => state.value === "idle");
491
+ const isLoading = computed(() => state.value === "loading");
492
+ const isSuccess = computed(() => state.value === "success");
493
+ const isError = computed(() => state.value === "error");
494
+ async function execute(...args) {
495
+ state.value = "loading";
496
+ error.value = null;
497
+ if (resetOnExecute) data.value = null;
498
+ try {
499
+ const result = await asyncFn(...args);
500
+ data.value = result;
501
+ state.value = "success";
502
+ onSuccess?.(result);
503
+ return result;
504
+ } catch (e) {
505
+ const asyncError = transformError(e);
506
+ error.value = asyncError;
507
+ state.value = "error";
508
+ onError?.(asyncError);
509
+ return null;
510
+ }
511
+ }
512
+ function reset() {
513
+ data.value = initialData;
514
+ error.value = null;
515
+ state.value = "idle";
516
+ }
517
+ function setData(newData) {
518
+ data.value = newData;
519
+ if (newData !== null) {
520
+ state.value = "success";
521
+ error.value = null;
522
+ }
523
+ }
524
+ function setError(newError) {
525
+ error.value = newError;
526
+ if (newError !== null) state.value = "error";
527
+ }
528
+ if (immediate) execute(...immediateArgs);
529
+ return {
530
+ data,
531
+ error,
532
+ state,
533
+ isIdle,
534
+ isLoading,
535
+ isSuccess,
536
+ isError,
537
+ execute,
538
+ reset,
539
+ setData,
540
+ setError
541
+ };
542
+ }
543
+ /**
544
+ * Create a batch of async operations that can be executed in parallel.
545
+ *
546
+ * @example
547
+ * ```typescript
548
+ * const { results, isLoading, execute } = useAsyncBatch([
549
+ * () => fetchUser(userId),
550
+ * () => fetchPosts(userId),
551
+ * () => fetchComments(userId),
552
+ * ])
553
+ *
554
+ * await execute()
555
+ * // results.value = [user, posts, comments]
556
+ * ```
557
+ */
558
+ function useAsyncBatch(asyncFns) {
559
+ const results = ref(asyncFns.map(() => null));
560
+ const errors = ref(asyncFns.map(() => null));
561
+ const isLoading = ref(false);
562
+ async function execute() {
563
+ isLoading.value = true;
564
+ errors.value = asyncFns.map(() => null);
565
+ const promises = asyncFns.map(async (fn, index) => {
566
+ try {
567
+ const result = await fn();
568
+ results.value[index] = result;
569
+ } catch (e) {
570
+ errors.value[index] = defaultTransformError(e);
571
+ results.value[index] = null;
572
+ }
573
+ });
574
+ await Promise.all(promises);
575
+ isLoading.value = false;
576
+ }
577
+ function reset() {
578
+ results.value = asyncFns.map(() => null);
579
+ errors.value = asyncFns.map(() => null);
580
+ isLoading.value = false;
581
+ }
582
+ return {
583
+ results,
584
+ errors,
585
+ isLoading,
586
+ execute,
587
+ reset
588
+ };
589
+ }
590
+ //#endregion
591
+ //#region src/composables/usePluginConfig.ts
592
+ /** Loads, saves, and tracks dirty state for a plugin's persistent configuration via the platform API. */
593
+ function usePluginConfig(pluginName) {
594
+ const api = useApi();
595
+ const { plugin } = usePlatformContext();
596
+ const resolvedName = computed(() => pluginName ?? plugin.value?.name ?? "");
597
+ const config = ref({});
598
+ const savedConfig = ref({});
599
+ const isLoading = ref(false);
600
+ const isSaving = ref(false);
601
+ const error = ref(null);
602
+ const isDirty = computed(() => {
603
+ return JSON.stringify(config.value) !== JSON.stringify(savedConfig.value);
604
+ });
605
+ async function load() {
606
+ const name = resolvedName.value;
607
+ if (!name) return;
608
+ isLoading.value = true;
609
+ error.value = null;
610
+ try {
611
+ const response = await api.get(`/plugins/${encodeURIComponent(name)}/config`);
612
+ config.value = { ...response.config };
613
+ savedConfig.value = { ...response.config };
614
+ } catch (e) {
615
+ error.value = e instanceof Error ? e.message : "Failed to load plugin config";
616
+ } finally {
617
+ isLoading.value = false;
618
+ }
619
+ }
620
+ async function save() {
621
+ const name = resolvedName.value;
622
+ if (!name) return false;
623
+ isSaving.value = true;
624
+ error.value = null;
625
+ try {
626
+ const response = await api.patch(`/plugins/${encodeURIComponent(name)}/config`, { config: config.value });
627
+ config.value = { ...response.config };
628
+ savedConfig.value = { ...response.config };
629
+ return true;
630
+ } catch (e) {
631
+ error.value = e instanceof Error ? e.message : "Failed to save plugin config";
632
+ return false;
633
+ } finally {
634
+ isSaving.value = false;
635
+ }
636
+ }
637
+ function reset() {
638
+ config.value = { ...savedConfig.value };
639
+ error.value = null;
640
+ }
641
+ onMounted(() => {
642
+ load();
643
+ });
644
+ return {
645
+ config,
646
+ isLoading,
647
+ isSaving,
648
+ error,
649
+ isDirty,
650
+ load,
651
+ save,
652
+ reset
653
+ };
654
+ }
655
+ //#endregion
656
+ //#region src/composables/useExperimentSave.ts
657
+ /** Persists and loads experiment design and analysis data via the plugin's API endpoint. */
658
+ function useExperimentSave(options = {}) {
659
+ const api = useApi({ baseUrl: options.apiBaseUrl });
660
+ const pluginId = options.pluginId;
661
+ const schemaVersion = options.schemaVersion ?? "1.0";
662
+ const isSaving = ref(false);
663
+ const error = ref(null);
664
+ const lastSavedAt = ref(null);
665
+ function setError(e) {
666
+ error.value = e instanceof Error ? e.message : "Unknown error";
667
+ }
668
+ async function saveDesign(experimentId, data) {
669
+ if (!pluginId) {
670
+ error.value = "pluginId is required for saveDesign";
671
+ return false;
672
+ }
673
+ isSaving.value = true;
674
+ error.value = null;
675
+ try {
676
+ await api.put(`/experiments/${experimentId}/data`, {
677
+ plugin_id: pluginId,
678
+ data,
679
+ schema_version: schemaVersion
680
+ });
681
+ lastSavedAt.value = /* @__PURE__ */ new Date();
682
+ return true;
683
+ } catch (e) {
684
+ setError(e);
685
+ return false;
686
+ } finally {
687
+ isSaving.value = false;
688
+ }
689
+ }
690
+ async function saveAnalysis(experimentId, result) {
691
+ if (!pluginId) {
692
+ error.value = "pluginId is required for saveAnalysis";
693
+ return false;
694
+ }
695
+ isSaving.value = true;
696
+ error.value = null;
697
+ try {
698
+ await api.put(`/experiments/${experimentId}/results/${pluginId}`, { result });
699
+ lastSavedAt.value = /* @__PURE__ */ new Date();
700
+ return true;
701
+ } catch (e) {
702
+ setError(e);
703
+ return false;
704
+ } finally {
705
+ isSaving.value = false;
706
+ }
707
+ }
708
+ async function save(experimentId, opts) {
709
+ if ((opts.design || opts.analysis) && !pluginId) {
710
+ error.value = "pluginId is required for save";
711
+ return false;
712
+ }
713
+ isSaving.value = true;
714
+ error.value = null;
715
+ try {
716
+ if (opts.design) await api.put(`/experiments/${experimentId}/data`, {
717
+ plugin_id: pluginId,
718
+ data: opts.design,
719
+ schema_version: schemaVersion
720
+ });
721
+ if (opts.analysis) await api.put(`/experiments/${experimentId}/results/${pluginId}`, { result: opts.analysis });
722
+ lastSavedAt.value = /* @__PURE__ */ new Date();
723
+ return true;
724
+ } catch (e) {
725
+ setError(e);
726
+ return false;
727
+ } finally {
728
+ isSaving.value = false;
729
+ }
730
+ }
731
+ async function loadDesign(experimentId) {
732
+ try {
733
+ return await api.get(`/experiments/${experimentId}/data`);
734
+ } catch {
735
+ return null;
736
+ }
737
+ }
738
+ async function loadAnalysis(experimentId) {
739
+ if (!pluginId) return null;
740
+ try {
741
+ return await api.get(`/experiments/${experimentId}/results/${pluginId}`);
742
+ } catch {
743
+ return null;
744
+ }
745
+ }
746
+ async function deleteDesign(experimentId) {
747
+ try {
748
+ await api.delete(`/experiments/${experimentId}/data`);
749
+ return true;
750
+ } catch {
751
+ return false;
752
+ }
753
+ }
754
+ async function deleteAnalysis(experimentId) {
755
+ if (!pluginId) return false;
756
+ try {
757
+ await api.delete(`/experiments/${experimentId}/results/${pluginId}`);
758
+ return true;
759
+ } catch {
760
+ return false;
761
+ }
762
+ }
763
+ return {
764
+ isSaving,
765
+ error,
766
+ lastSavedAt,
767
+ saveDesign,
768
+ saveAnalysis,
769
+ save,
770
+ loadDesign,
771
+ loadAnalysis,
772
+ deleteDesign,
773
+ deleteAnalysis
774
+ };
775
+ }
776
+ //#endregion
777
+ //#region src/composables/usePluginApi.ts
778
+ /**
779
+ * Pre-configured API client for plugins.
780
+ *
781
+ * Resolves the base URL in priority order:
782
+ * 1. `import.meta.env.VITE_API_PREFIX` (build-time env override)
783
+ * 2. `fallbackPrefix` option (plugin's route prefix)
784
+ * 3. `'/api'` (default)
785
+ *
786
+ * Eliminates the repeated pattern across plugins:
787
+ * ```ts
788
+ * const API_BASE = import.meta.env.VITE_API_PREFIX || '/api/my-plugin'
789
+ * const api = useApi({ baseUrl: API_BASE })
790
+ * ```
791
+ *
792
+ * @example
793
+ * ```ts
794
+ * const api = usePluginApi({ fallbackPrefix: '/api/drp' })
795
+ * const data = await api.get('/sessions')
796
+ * ```
797
+ */
798
+ /** Pre-configured API client resolving the plugin base URL from VITE_API_PREFIX or a fallback prefix. */
799
+ function usePluginApi(options = {}) {
800
+ return useApi({ baseUrl: options.fallbackPrefix || "/api" });
801
+ }
802
+ //#endregion
803
+ export { useAsyncBatch as a, useAsync as i, useExperimentSave as n, usePasskey as o, usePluginConfig as r, useAuth as s, usePluginApi as t };
804
+
805
+ //# sourceMappingURL=composables-D0QfFzq1.js.map