@morscherlab/mint-sdk 1.2.0-beta.1 → 1.2.0-beta.3

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 (1006) hide show
  1. package/README.md +7 -13
  2. package/dist/EmptyState-p90quq8Z.js +0 -2
  3. package/dist/{ExperimentPopover-tLwJ7XF4.js → ExperimentPopover-Bn6PIGHE.js} +5 -10
  4. package/dist/ExperimentPopover-C1e0cd94.js +3 -0
  5. package/dist/ExperimentSelectorModal-DCWTFyos.js +4 -0
  6. package/dist/{ExperimentSelectorModal-DyPAUCLw.js → ExperimentSelectorModal-DGhrJSSV.js} +6 -11
  7. package/dist/SettingsModal-Bpybht86.js +5 -0
  8. package/dist/{SettingsModal-BgKY93zh.js → SettingsModal-wF2btHu6.js} +7 -12
  9. package/dist/{analysisArtifactTypes-DQ0MjwHZ.js → analysisArtifactTypes-ejqR8MX3.js} +0 -2
  10. package/dist/components/JobsStatusTray.vue.d.ts +0 -2
  11. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -2
  12. package/dist/components/SmartGroupManual.vue.d.ts +2 -2
  13. package/dist/components/WellPlate.vue.d.ts +1 -1
  14. package/dist/components/index.d.ts +0 -9
  15. package/dist/components/index.js +6 -6
  16. package/dist/{components-DkHddRMl.js → components-DpyzaeIc.js} +1466 -3375
  17. package/dist/composables/index.d.ts +1 -8
  18. package/dist/composables/index.js +9 -9
  19. package/dist/composables/useAnalysisArtifacts.d.ts +0 -2
  20. package/dist/composables/useAuth.d.ts +0 -2
  21. package/dist/composables/useAutoGroup.d.ts +1 -30
  22. package/dist/composables/useGeneratedAnalysis.d.ts +0 -2
  23. package/dist/composables/useJobsStatusTray.d.ts +4 -17
  24. package/dist/composables/usePluginClient.d.ts +0 -2
  25. package/dist/{composables-C_i90sGS.js → composables-yz8bTkEV.js} +59 -629
  26. package/dist/{experiment-Cq145oEW.js → experiment-D08H_TIH.js} +1 -3
  27. package/dist/experiment-utils-CLnzPPq5.js +0 -2
  28. package/dist/index.js +33 -18
  29. package/dist/jobs.d.ts +1 -15
  30. package/dist/permissions.d.ts +0 -5
  31. package/dist/permissions.js +2 -4
  32. package/dist/stores/index.js +2 -2
  33. package/dist/styles.css +265 -2831
  34. package/dist/tailwind.preset.js +0 -2
  35. package/dist/templates/catalog.d.ts +4 -4
  36. package/dist/templates/index.js +2 -2
  37. package/dist/templates/presets.d.ts +2 -2
  38. package/dist/{templates-DsP51i-S.js → templates-Pbxjdqlh.js} +5 -22
  39. package/dist/types/auto-group.d.ts +0 -7
  40. package/dist/types/componentWorkflowTypes.d.ts +0 -22
  41. package/dist/types/components.d.ts +1 -1
  42. package/dist/types/generated-ui.d.ts +2 -11
  43. package/dist/types/index.d.ts +4 -4
  44. package/dist/types/index.js +1 -1
  45. package/dist/types/jobs.d.ts +3 -11
  46. package/dist/{useApi-J6zFkHmn.js → useApi-yE0re8k-.js} +0 -14
  47. package/dist/{useControlSchema-BDx2Olha.js → useControlSchema-Ds4VeFxt.js} +8 -96
  48. package/dist/{useDropdownState-DSb3BC3N.js → useDropdownState-WIGW6Rr-.js} +0 -2
  49. package/dist/{useExperimentSelector-CV4iNfMS.js → useExperimentSelector-DXqsZuSk.js} +1 -3
  50. package/dist/{useFormBuilder-BLxG3BOX.js → useFormBuilder-1so6QSQL.js} +1 -3
  51. package/dist/{useProtocolTemplates-CS_SQl6U.js → useProtocolTemplates-Cv0ca1AM.js} +32 -478
  52. package/package.json +2 -8
  53. package/dist/EmptyState-p90quq8Z.js.map +0 -1
  54. package/dist/ExperimentPopover-tLwJ7XF4.js.map +0 -1
  55. package/dist/ExperimentSelectorModal-DyPAUCLw.js.map +0 -1
  56. package/dist/SettingsModal-BgKY93zh.js.map +0 -1
  57. package/dist/__stories__/experiment-helpers.d.ts +0 -28
  58. package/dist/__tests__/components/ActionItem.test.d.ts +0 -1
  59. package/dist/__tests__/components/ActionMenu.test.d.ts +0 -1
  60. package/dist/__tests__/components/AppAvatarMenu.test.d.ts +0 -1
  61. package/dist/__tests__/components/AppLayout.test.d.ts +0 -1
  62. package/dist/__tests__/components/AppPluginSwitcher.test.d.ts +0 -1
  63. package/dist/__tests__/components/AppSidebar.test.d.ts +0 -1
  64. package/dist/__tests__/components/AppToastContainer.test.d.ts +0 -1
  65. package/dist/__tests__/components/AppTopBar.navigation.test.d.ts +0 -1
  66. package/dist/__tests__/components/AppTopBar.test.d.ts +0 -1
  67. package/dist/__tests__/components/AppTopBarPageSelector.test.d.ts +0 -1
  68. package/dist/__tests__/components/AppTopBarPillNav.test.d.ts +0 -1
  69. package/dist/__tests__/components/AppTopBarPresence.test.d.ts +0 -1
  70. package/dist/__tests__/components/ArtifactSaveDialog.test.d.ts +0 -1
  71. package/dist/__tests__/components/ArtifactSelectorModal.test.d.ts +0 -1
  72. package/dist/__tests__/components/AutoGroupModal.adapter.test.d.ts +0 -1
  73. package/dist/__tests__/components/BaseInput.test.d.ts +0 -1
  74. package/dist/__tests__/components/BaseModal.test.d.ts +0 -1
  75. package/dist/__tests__/components/BasePill.test.d.ts +0 -1
  76. package/dist/__tests__/components/BaseRadioGroup.test.d.ts +0 -1
  77. package/dist/__tests__/components/BaseSelect.test.d.ts +0 -1
  78. package/dist/__tests__/components/BaseTabs.test.d.ts +0 -1
  79. package/dist/__tests__/components/BaseToggle.test.d.ts +0 -1
  80. package/dist/__tests__/components/BatchProgressList.test.d.ts +0 -1
  81. package/dist/__tests__/components/BioTemplateExperimentWorkspaceView.test.d.ts +0 -1
  82. package/dist/__tests__/components/BioTemplatePackWorkspaceView.test.d.ts +0 -1
  83. package/dist/__tests__/components/BioTemplatePresetWorkspaceView.test.d.ts +0 -1
  84. package/dist/__tests__/components/BioTemplateRenderer.test.d.ts +0 -1
  85. package/dist/__tests__/components/Breadcrumb.test.d.ts +0 -1
  86. package/dist/__tests__/components/Calendar.test.d.ts +0 -1
  87. package/dist/__tests__/components/CalendarGridPanel.test.d.ts +0 -1
  88. package/dist/__tests__/components/CollapsibleCard.test.d.ts +0 -1
  89. package/dist/__tests__/components/ComponentBindingRenderer.test.d.ts +0 -1
  90. package/dist/__tests__/components/ConcentrationInput.test.d.ts +0 -1
  91. package/dist/__tests__/components/ControlWorkspaceView.test.d.ts +0 -1
  92. package/dist/__tests__/components/DataFrame.test.d.ts +0 -1
  93. package/dist/__tests__/components/DatePicker.test.d.ts +0 -1
  94. package/dist/__tests__/components/DateTimePicker.test.d.ts +0 -1
  95. package/dist/__tests__/components/DoseCalculatorVolumeField.test.d.ts +0 -1
  96. package/dist/__tests__/components/DoseDesignWorkspaceView.test.d.ts +0 -1
  97. package/dist/__tests__/components/DropdownButton.test.d.ts +0 -1
  98. package/dist/__tests__/components/EmptyState.test.d.ts +0 -1
  99. package/dist/__tests__/components/ExperimentPopover.test.d.ts +0 -1
  100. package/dist/__tests__/components/ExperimentSelectorModal.test.d.ts +0 -1
  101. package/dist/__tests__/components/FormBuilder.test.d.ts +0 -1
  102. package/dist/__tests__/components/GeneratedPathInput.test.d.ts +0 -1
  103. package/dist/__tests__/components/GeneratedPlotlyResult.test.d.ts +0 -1
  104. package/dist/__tests__/components/GeneratedPluginView.test.d.ts +0 -1
  105. package/dist/__tests__/components/GeneratedResultRenderer.test.d.ts +0 -1
  106. package/dist/__tests__/components/GroupAssigner.test.d.ts +0 -1
  107. package/dist/__tests__/components/InstrumentAlertLog.test.d.ts +0 -1
  108. package/dist/__tests__/components/JobsStatusTray.test.d.ts +0 -1
  109. package/dist/__tests__/components/LcmsSequenceTable.test.d.ts +0 -1
  110. package/dist/__tests__/components/MobileSupportGate.test.d.ts +0 -1
  111. package/dist/__tests__/components/MultiSelect.test.d.ts +0 -1
  112. package/dist/__tests__/components/PlateMapEditorToolbarInternal.test.d.ts +0 -1
  113. package/dist/__tests__/components/PluginIcon.test.d.ts +0 -1
  114. package/dist/__tests__/components/PluginWorkspaceView.controls.test.d.ts +0 -1
  115. package/dist/__tests__/components/PluginWorkspaceView.navigation.test.d.ts +0 -1
  116. package/dist/__tests__/components/PluginWorkspaceView.shell.test.d.ts +0 -1
  117. package/dist/__tests__/components/PluginWorkspaceView.test.d.ts +0 -1
  118. package/dist/__tests__/components/ProgressBar.test.d.ts +0 -1
  119. package/dist/__tests__/components/ProtocolStep.presentation.test.d.ts +0 -1
  120. package/dist/__tests__/components/ProtocolStepEditor.state.test.d.ts +0 -1
  121. package/dist/__tests__/components/ProtocolStepEditor.test.d.ts +0 -1
  122. package/dist/__tests__/components/ProtocolStepParameterField.test.d.ts +0 -1
  123. package/dist/__tests__/components/RackEditor.test.d.ts +0 -1
  124. package/dist/__tests__/components/ReagentList.presentation.test.d.ts +0 -1
  125. package/dist/__tests__/components/ReagentList.test.d.ts +0 -1
  126. package/dist/__tests__/components/RetiredStyles.test.d.ts +0 -1
  127. package/dist/__tests__/components/RuntimeUpdateNotice.test.d.ts +0 -1
  128. package/dist/__tests__/components/SampleHierarchyTree.test.d.ts +0 -1
  129. package/dist/__tests__/components/SampleSelector.colors.test.d.ts +0 -1
  130. package/dist/__tests__/components/SampleSelector.drag.test.d.ts +0 -1
  131. package/dist/__tests__/components/SampleSelector.groups.test.d.ts +0 -1
  132. package/dist/__tests__/components/SampleSelector.selection.test.d.ts +0 -1
  133. package/dist/__tests__/components/SampleSelector.test.d.ts +0 -1
  134. package/dist/__tests__/components/SampleSelectorSampleRow.test.d.ts +0 -1
  135. package/dist/__tests__/components/ScheduleCalendar.test.d.ts +0 -1
  136. package/dist/__tests__/components/SectionCard.test.d.ts +0 -1
  137. package/dist/__tests__/components/SegmentedControl.test.d.ts +0 -1
  138. package/dist/__tests__/components/SequenceProgressBar.test.d.ts +0 -1
  139. package/dist/__tests__/components/SettingsModal.schema.test.d.ts +0 -1
  140. package/dist/__tests__/components/SettingsModal.test.d.ts +0 -1
  141. package/dist/__tests__/components/SmartGroupFieldRecipe.groups.test.d.ts +0 -1
  142. package/dist/__tests__/components/SmartGroupManual.cohorts.test.d.ts +0 -1
  143. package/dist/__tests__/components/TagsInput.test.d.ts +0 -1
  144. package/dist/__tests__/components/ThemeToggle.test.d.ts +0 -1
  145. package/dist/__tests__/components/TimePicker.test.d.ts +0 -1
  146. package/dist/__tests__/components/WellPlate.colors.test.d.ts +0 -1
  147. package/dist/__tests__/components/WellPlate.conditions.test.d.ts +0 -1
  148. package/dist/__tests__/components/WellPlate.geometry.test.d.ts +0 -1
  149. package/dist/__tests__/components/WellPlate.interaction.test.d.ts +0 -1
  150. package/dist/__tests__/components/WellPlate.legend.test.d.ts +0 -1
  151. package/dist/__tests__/components/WellPlate.rendering.test.d.ts +0 -1
  152. package/dist/__tests__/components/WellPlate.sampleDrop.test.d.ts +0 -1
  153. package/dist/__tests__/composables/analysisArtifactTarget.test.d.ts +0 -1
  154. package/dist/__tests__/composables/autoGroup/classKey.test.d.ts +0 -1
  155. package/dist/__tests__/composables/autoGroup/classify.test.d.ts +0 -1
  156. package/dist/__tests__/composables/autoGroup/columns.test.d.ts +0 -1
  157. package/dist/__tests__/composables/autoGroup/compose.test.d.ts +0 -1
  158. package/dist/__tests__/composables/autoGroup/cooccurrence.test.d.ts +0 -1
  159. package/dist/__tests__/composables/autoGroup/fingerprint.test.d.ts +0 -1
  160. package/dist/__tests__/composables/autoGroup/groupByOrder.test.d.ts +0 -1
  161. package/dist/__tests__/composables/autoGroup/groupTree.test.d.ts +0 -1
  162. package/dist/__tests__/composables/autoGroup/integration.test.d.ts +0 -1
  163. package/dist/__tests__/composables/autoGroup/template.test.d.ts +0 -1
  164. package/dist/__tests__/composables/autoGroup/tokenLength.test.d.ts +0 -1
  165. package/dist/__tests__/composables/autoGroup/tokenize.test.d.ts +0 -1
  166. package/dist/__tests__/composables/experiment-utils.test.d.ts +0 -1
  167. package/dist/__tests__/composables/formBuilderRegistry.test.d.ts +0 -1
  168. package/dist/__tests__/composables/resolvePluginFrontendBase.test.d.ts +0 -1
  169. package/dist/__tests__/composables/useAnalysisArtifacts.test.d.ts +0 -1
  170. package/dist/__tests__/composables/useApi.test.d.ts +0 -1
  171. package/dist/__tests__/composables/useAppExperiment.test.d.ts +0 -1
  172. package/dist/__tests__/composables/useAuth.test.d.ts +0 -1
  173. package/dist/__tests__/composables/useAutoGroup.test.d.ts +0 -1
  174. package/dist/__tests__/composables/useAutoGroupInputSources.test.d.ts +0 -1
  175. package/dist/__tests__/composables/useBioTemplatePackWorkspace.test.d.ts +0 -1
  176. package/dist/__tests__/composables/useBioTemplatePresetWorkspace.test.d.ts +0 -1
  177. package/dist/__tests__/composables/useBioTemplateWorkspace.test.d.ts +0 -1
  178. package/dist/__tests__/composables/useCalendarGrid.test.d.ts +0 -1
  179. package/dist/__tests__/composables/useCommandHistory.test.d.ts +0 -1
  180. package/dist/__tests__/composables/useControlSchema.test.d.ts +0 -1
  181. package/dist/__tests__/composables/useDebouncedWatch.test.d.ts +0 -1
  182. package/dist/__tests__/composables/useDropdownState.test.d.ts +0 -1
  183. package/dist/__tests__/composables/useEventListener.test.d.ts +0 -1
  184. package/dist/__tests__/composables/useEventStream.test.d.ts +0 -1
  185. package/dist/__tests__/composables/useExpansionSet.test.d.ts +0 -1
  186. package/dist/__tests__/composables/useExperimentData.test.d.ts +0 -14
  187. package/dist/__tests__/composables/useExperimentSamples.test.d.ts +0 -1
  188. package/dist/__tests__/composables/useExperimentSave.test.d.ts +0 -1
  189. package/dist/__tests__/composables/useExperimentSelector.test.d.ts +0 -1
  190. package/dist/__tests__/composables/useFileImport.test.d.ts +0 -1
  191. package/dist/__tests__/composables/useForm.test.d.ts +0 -1
  192. package/dist/__tests__/composables/useFormBuilder.test.d.ts +0 -1
  193. package/dist/__tests__/composables/useGeneratedAnalysis.test.d.ts +0 -1
  194. package/dist/__tests__/composables/useGroupAssignment.test.d.ts +0 -1
  195. package/dist/__tests__/composables/useJobsStatusTray.test.d.ts +0 -1
  196. package/dist/__tests__/composables/useListSelection.test.d.ts +0 -1
  197. package/dist/__tests__/composables/useMobileSupportGate.test.d.ts +0 -1
  198. package/dist/__tests__/composables/useOptimisticMutation.test.d.ts +0 -1
  199. package/dist/__tests__/composables/usePlatformContext.test.d.ts +0 -1
  200. package/dist/__tests__/composables/usePluginClient.test.d.ts +0 -1
  201. package/dist/__tests__/composables/usePresenceHeartbeat.test.d.ts +0 -1
  202. package/dist/__tests__/composables/useProtocolTemplates.test.d.ts +0 -1
  203. package/dist/__tests__/composables/useRequestSyncState.test.d.ts +0 -1
  204. package/dist/__tests__/composables/useResourceCrud.test.d.ts +0 -1
  205. package/dist/__tests__/composables/useRuntimeAlignment.test.d.ts +0 -1
  206. package/dist/__tests__/composables/useSampleGroups.test.d.ts +0 -1
  207. package/dist/__tests__/composables/useSampleGroups.tree.test.d.ts +0 -1
  208. package/dist/__tests__/composables/useScheduleCalendarLayout.test.d.ts +0 -1
  209. package/dist/__tests__/composables/useSelectionLimit.test.d.ts +0 -1
  210. package/dist/__tests__/composables/useSortedItems.test.d.ts +0 -1
  211. package/dist/__tests__/composables/useTemplateCollection.test.d.ts +0 -1
  212. package/dist/__tests__/composables/useTextSearch.test.d.ts +0 -1
  213. package/dist/__tests__/composables/useTheme.test.d.ts +0 -1
  214. package/dist/__tests__/composables/useTimeUtils.test.d.ts +0 -1
  215. package/dist/__tests__/composables/useWellPainting.test.d.ts +0 -1
  216. package/dist/__tests__/composables/useWellPlateAdapter.test.d.ts +0 -1
  217. package/dist/__tests__/composables/useWellPlateValidation.test.d.ts +0 -1
  218. package/dist/__tests__/docs/extractDocsComponents.test.d.ts +0 -1
  219. package/dist/__tests__/docs/extractDocsExports.test.d.ts +0 -1
  220. package/dist/__tests__/docs/extractDocsParsing.test.d.ts +0 -1
  221. package/dist/__tests__/docs/extractDocsTemplates.test.d.ts +0 -1
  222. package/dist/__tests__/docs/extractDocsTheme.test.d.ts +0 -1
  223. package/dist/__tests__/docs/frontendDocsCatalog.test.d.ts +0 -1
  224. package/dist/__tests__/generatedUi.test.d.ts +0 -1
  225. package/dist/__tests__/stores/experiment.test.d.ts +0 -1
  226. package/dist/__tests__/stores/settings.test.d.ts +0 -1
  227. package/dist/__tests__/templates/templates.test.d.ts +0 -1
  228. package/dist/__tests__/types/GeneratedJsonSchema.test.d.ts +0 -1
  229. package/dist/__tests__/utils/color.test.d.ts +0 -1
  230. package/dist/__tests__/utils/instrument.test.d.ts +0 -1
  231. package/dist/__tests__/utils/jobs.test.d.ts +0 -1
  232. package/dist/__tests__/utils/lcms.test.d.ts +0 -1
  233. package/dist/__tests__/utils/permissions.test.d.ts +0 -1
  234. package/dist/__tests__/utils/rack.test.d.ts +0 -1
  235. package/dist/analysisArtifactTypes-DQ0MjwHZ.js.map +0 -1
  236. package/dist/chunk-BoAXSpZd.js +0 -33
  237. package/dist/components/AuditTrail.vue.d.ts +0 -38
  238. package/dist/components/ColorSlider.vue.d.ts +0 -34
  239. package/dist/components/DoseDesignWorkspaceView.vue.d.ts +0 -149
  240. package/dist/components/FitPanel.vue.d.ts +0 -46
  241. package/dist/components/GroupAssigner.vue.d.ts +0 -25
  242. package/dist/components/RackEditor.vue.d.ts +0 -78
  243. package/dist/components/ReagentEditor.vue.d.ts +0 -30
  244. package/dist/components/ResourceCard.vue.d.ts +0 -50
  245. package/dist/components/ScientificNumber.vue.d.ts +0 -14
  246. package/dist/components-DkHddRMl.js.map +0 -1
  247. package/dist/composables/autoGroupConstants.d.ts +0 -1
  248. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  249. package/dist/composables/useAsync.d.ts +0 -128
  250. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  251. package/dist/composables/useCommandHistory.d.ts +0 -29
  252. package/dist/composables/useGroupAssignment.d.ts +0 -31
  253. package/dist/composables/useRackEditor.d.ts +0 -31
  254. package/dist/composables/useResourceCrud.d.ts +0 -40
  255. package/dist/composables/useWellPainting.d.ts +0 -35
  256. package/dist/composables/useWellPlateAdapter.d.ts +0 -36
  257. package/dist/composables-C_i90sGS.js.map +0 -1
  258. package/dist/experiment-Cq145oEW.js.map +0 -1
  259. package/dist/experiment-utils-CLnzPPq5.js.map +0 -1
  260. package/dist/histoire.setup.d.ts +0 -1
  261. package/dist/index.js.map +0 -1
  262. package/dist/install.js +0 -28
  263. package/dist/install.js.map +0 -1
  264. package/dist/permissions.js.map +0 -1
  265. package/dist/plotly.min-c2Sez60c.js +0 -180634
  266. package/dist/plotly.min-c2Sez60c.js.map +0 -1
  267. package/dist/tailwind.preset.js.map +0 -1
  268. package/dist/templates-DsP51i-S.js.map +0 -1
  269. package/dist/useApi-J6zFkHmn.js.map +0 -1
  270. package/dist/useControlSchema-BDx2Olha.js.map +0 -1
  271. package/dist/useDropdownState-DSb3BC3N.js.map +0 -1
  272. package/dist/useExperimentSelector-CV4iNfMS.js.map +0 -1
  273. package/dist/useFormBuilder-BLxG3BOX.js.map +0 -1
  274. package/dist/useProtocolTemplates-CS_SQl6U.js.map +0 -1
  275. package/src/__stories__/experiment-helpers.ts +0 -86
  276. package/src/__tests__/components/ActionItem.test.ts +0 -99
  277. package/src/__tests__/components/ActionMenu.test.ts +0 -120
  278. package/src/__tests__/components/AppAvatarMenu.test.ts +0 -38
  279. package/src/__tests__/components/AppLayout.test.ts +0 -207
  280. package/src/__tests__/components/AppPluginSwitcher.test.ts +0 -44
  281. package/src/__tests__/components/AppSidebar.test.ts +0 -857
  282. package/src/__tests__/components/AppToastContainer.test.ts +0 -37
  283. package/src/__tests__/components/AppTopBar.navigation.test.ts +0 -68
  284. package/src/__tests__/components/AppTopBar.test.ts +0 -1256
  285. package/src/__tests__/components/AppTopBarPageSelector.test.ts +0 -156
  286. package/src/__tests__/components/AppTopBarPillNav.test.ts +0 -125
  287. package/src/__tests__/components/AppTopBarPresence.test.ts +0 -47
  288. package/src/__tests__/components/ArtifactSaveDialog.test.ts +0 -566
  289. package/src/__tests__/components/ArtifactSelectorModal.test.ts +0 -178
  290. package/src/__tests__/components/AutoGroupModal.adapter.test.ts +0 -204
  291. package/src/__tests__/components/BaseInput.test.ts +0 -99
  292. package/src/__tests__/components/BaseModal.test.ts +0 -133
  293. package/src/__tests__/components/BasePill.test.ts +0 -291
  294. package/src/__tests__/components/BaseRadioGroup.test.ts +0 -25
  295. package/src/__tests__/components/BaseSelect.test.ts +0 -73
  296. package/src/__tests__/components/BaseTabs.test.ts +0 -40
  297. package/src/__tests__/components/BaseToggle.test.ts +0 -40
  298. package/src/__tests__/components/BatchProgressList.test.ts +0 -52
  299. package/src/__tests__/components/BioTemplateExperimentWorkspaceView.test.ts +0 -159
  300. package/src/__tests__/components/BioTemplatePackWorkspaceView.test.ts +0 -192
  301. package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +0 -328
  302. package/src/__tests__/components/BioTemplateRenderer.test.ts +0 -96
  303. package/src/__tests__/components/Breadcrumb.test.ts +0 -23
  304. package/src/__tests__/components/Calendar.test.ts +0 -566
  305. package/src/__tests__/components/CalendarGridPanel.test.ts +0 -36
  306. package/src/__tests__/components/CollapsibleCard.test.ts +0 -571
  307. package/src/__tests__/components/ComponentBindingRenderer.test.ts +0 -278
  308. package/src/__tests__/components/ConcentrationInput.test.ts +0 -45
  309. package/src/__tests__/components/ControlWorkspaceView.test.ts +0 -1102
  310. package/src/__tests__/components/DataFrame.test.ts +0 -915
  311. package/src/__tests__/components/DatePicker.test.ts +0 -45
  312. package/src/__tests__/components/DateTimePicker.test.ts +0 -48
  313. package/src/__tests__/components/DoseCalculatorVolumeField.test.ts +0 -53
  314. package/src/__tests__/components/DoseDesignWorkspaceView.test.ts +0 -185
  315. package/src/__tests__/components/DropdownButton.test.ts +0 -494
  316. package/src/__tests__/components/EmptyState.test.ts +0 -23
  317. package/src/__tests__/components/ExperimentPopover.test.ts +0 -143
  318. package/src/__tests__/components/ExperimentSelectorModal.test.ts +0 -143
  319. package/src/__tests__/components/FormBuilder.test.ts +0 -353
  320. package/src/__tests__/components/GeneratedPathInput.test.ts +0 -132
  321. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +0 -117
  322. package/src/__tests__/components/GeneratedPluginView.test.ts +0 -235
  323. package/src/__tests__/components/GeneratedResultRenderer.test.ts +0 -93
  324. package/src/__tests__/components/GroupAssigner.test.ts +0 -48
  325. package/src/__tests__/components/InstrumentAlertLog.test.ts +0 -59
  326. package/src/__tests__/components/JobsStatusTray.test.ts +0 -165
  327. package/src/__tests__/components/LcmsSequenceTable.test.ts +0 -57
  328. package/src/__tests__/components/MobileSupportGate.test.ts +0 -120
  329. package/src/__tests__/components/MultiSelect.test.ts +0 -48
  330. package/src/__tests__/components/PlateMapEditorToolbarInternal.test.ts +0 -54
  331. package/src/__tests__/components/PluginIcon.test.ts +0 -215
  332. package/src/__tests__/components/PluginWorkspaceView.controls.test.ts +0 -156
  333. package/src/__tests__/components/PluginWorkspaceView.navigation.test.ts +0 -102
  334. package/src/__tests__/components/PluginWorkspaceView.shell.test.ts +0 -43
  335. package/src/__tests__/components/PluginWorkspaceView.test.ts +0 -719
  336. package/src/__tests__/components/ProgressBar.test.ts +0 -18
  337. package/src/__tests__/components/ProtocolStep.presentation.test.ts +0 -31
  338. package/src/__tests__/components/ProtocolStepEditor.state.test.ts +0 -165
  339. package/src/__tests__/components/ProtocolStepEditor.test.ts +0 -33
  340. package/src/__tests__/components/ProtocolStepParameterField.test.ts +0 -44
  341. package/src/__tests__/components/RackEditor.test.ts +0 -125
  342. package/src/__tests__/components/ReagentList.presentation.test.ts +0 -68
  343. package/src/__tests__/components/ReagentList.test.ts +0 -82
  344. package/src/__tests__/components/RetiredStyles.test.ts +0 -82
  345. package/src/__tests__/components/RuntimeUpdateNotice.test.ts +0 -14
  346. package/src/__tests__/components/SampleHierarchyTree.test.ts +0 -53
  347. package/src/__tests__/components/SampleSelector.colors.test.ts +0 -49
  348. package/src/__tests__/components/SampleSelector.drag.test.ts +0 -126
  349. package/src/__tests__/components/SampleSelector.groups.test.ts +0 -94
  350. package/src/__tests__/components/SampleSelector.selection.test.ts +0 -56
  351. package/src/__tests__/components/SampleSelector.test.ts +0 -466
  352. package/src/__tests__/components/SampleSelectorSampleRow.test.ts +0 -40
  353. package/src/__tests__/components/ScheduleCalendar.test.ts +0 -44
  354. package/src/__tests__/components/SectionCard.test.ts +0 -181
  355. package/src/__tests__/components/SegmentedControl.test.ts +0 -69
  356. package/src/__tests__/components/SequenceProgressBar.test.ts +0 -39
  357. package/src/__tests__/components/SettingsModal.schema.test.ts +0 -97
  358. package/src/__tests__/components/SettingsModal.test.ts +0 -407
  359. package/src/__tests__/components/SmartGroupFieldRecipe.groups.test.ts +0 -101
  360. package/src/__tests__/components/SmartGroupManual.cohorts.test.ts +0 -97
  361. package/src/__tests__/components/TagsInput.test.ts +0 -75
  362. package/src/__tests__/components/ThemeToggle.test.ts +0 -47
  363. package/src/__tests__/components/TimePicker.test.ts +0 -38
  364. package/src/__tests__/components/WellPlate.colors.test.ts +0 -28
  365. package/src/__tests__/components/WellPlate.conditions.test.ts +0 -68
  366. package/src/__tests__/components/WellPlate.geometry.test.ts +0 -54
  367. package/src/__tests__/components/WellPlate.interaction.test.ts +0 -171
  368. package/src/__tests__/components/WellPlate.legend.test.ts +0 -13
  369. package/src/__tests__/components/WellPlate.rendering.test.ts +0 -122
  370. package/src/__tests__/components/WellPlate.sampleDrop.test.ts +0 -70
  371. package/src/__tests__/composables/analysisArtifactTarget.test.ts +0 -77
  372. package/src/__tests__/composables/autoGroup/classKey.test.ts +0 -25
  373. package/src/__tests__/composables/autoGroup/classify.test.ts +0 -107
  374. package/src/__tests__/composables/autoGroup/columns.test.ts +0 -135
  375. package/src/__tests__/composables/autoGroup/compose.test.ts +0 -226
  376. package/src/__tests__/composables/autoGroup/cooccurrence.test.ts +0 -91
  377. package/src/__tests__/composables/autoGroup/fingerprint.test.ts +0 -122
  378. package/src/__tests__/composables/autoGroup/groupByOrder.test.ts +0 -278
  379. package/src/__tests__/composables/autoGroup/groupTree.test.ts +0 -99
  380. package/src/__tests__/composables/autoGroup/integration.test.ts +0 -75
  381. package/src/__tests__/composables/autoGroup/template.test.ts +0 -70
  382. package/src/__tests__/composables/autoGroup/tokenLength.test.ts +0 -85
  383. package/src/__tests__/composables/autoGroup/tokenize.test.ts +0 -33
  384. package/src/__tests__/composables/experiment-utils.test.ts +0 -63
  385. package/src/__tests__/composables/formBuilderRegistry.test.ts +0 -191
  386. package/src/__tests__/composables/resolvePluginFrontendBase.test.ts +0 -65
  387. package/src/__tests__/composables/useAnalysisArtifacts.test.ts +0 -740
  388. package/src/__tests__/composables/useApi.test.ts +0 -157
  389. package/src/__tests__/composables/useAppExperiment.test.ts +0 -899
  390. package/src/__tests__/composables/useAuth.test.ts +0 -231
  391. package/src/__tests__/composables/useAutoGroup.test.ts +0 -524
  392. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  393. package/src/__tests__/composables/useBioTemplatePackWorkspace.test.ts +0 -125
  394. package/src/__tests__/composables/useBioTemplatePresetWorkspace.test.ts +0 -199
  395. package/src/__tests__/composables/useBioTemplateWorkspace.test.ts +0 -104
  396. package/src/__tests__/composables/useCalendarGrid.test.ts +0 -38
  397. package/src/__tests__/composables/useCommandHistory.test.ts +0 -43
  398. package/src/__tests__/composables/useControlSchema.test.ts +0 -1060
  399. package/src/__tests__/composables/useDebouncedWatch.test.ts +0 -93
  400. package/src/__tests__/composables/useDropdownState.test.ts +0 -95
  401. package/src/__tests__/composables/useEventListener.test.ts +0 -116
  402. package/src/__tests__/composables/useEventStream.test.ts +0 -140
  403. package/src/__tests__/composables/useExpansionSet.test.ts +0 -62
  404. package/src/__tests__/composables/useExperimentData.test.ts +0 -154
  405. package/src/__tests__/composables/useExperimentSamples.test.ts +0 -91
  406. package/src/__tests__/composables/useExperimentSave.test.ts +0 -542
  407. package/src/__tests__/composables/useExperimentSelector.test.ts +0 -338
  408. package/src/__tests__/composables/useFileImport.test.ts +0 -44
  409. package/src/__tests__/composables/useForm.test.ts +0 -263
  410. package/src/__tests__/composables/useFormBuilder.test.ts +0 -994
  411. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +0 -1903
  412. package/src/__tests__/composables/useGroupAssignment.test.ts +0 -73
  413. package/src/__tests__/composables/useJobsStatusTray.test.ts +0 -283
  414. package/src/__tests__/composables/useListSelection.test.ts +0 -66
  415. package/src/__tests__/composables/useMobileSupportGate.test.ts +0 -74
  416. package/src/__tests__/composables/useOptimisticMutation.test.ts +0 -40
  417. package/src/__tests__/composables/usePlatformContext.test.ts +0 -148
  418. package/src/__tests__/composables/usePluginClient.test.ts +0 -1772
  419. package/src/__tests__/composables/usePresenceHeartbeat.test.ts +0 -164
  420. package/src/__tests__/composables/useProtocolTemplates.test.ts +0 -64
  421. package/src/__tests__/composables/useRequestSyncState.test.ts +0 -92
  422. package/src/__tests__/composables/useResourceCrud.test.ts +0 -56
  423. package/src/__tests__/composables/useRuntimeAlignment.test.ts +0 -145
  424. package/src/__tests__/composables/useSampleGroups.test.ts +0 -66
  425. package/src/__tests__/composables/useSampleGroups.tree.test.ts +0 -145
  426. package/src/__tests__/composables/useScheduleCalendarLayout.test.ts +0 -89
  427. package/src/__tests__/composables/useSelectionLimit.test.ts +0 -41
  428. package/src/__tests__/composables/useSortedItems.test.ts +0 -87
  429. package/src/__tests__/composables/useTemplateCollection.test.ts +0 -147
  430. package/src/__tests__/composables/useTextSearch.test.ts +0 -55
  431. package/src/__tests__/composables/useTheme.test.ts +0 -91
  432. package/src/__tests__/composables/useTimeUtils.test.ts +0 -35
  433. package/src/__tests__/composables/useWellPainting.test.ts +0 -52
  434. package/src/__tests__/composables/useWellPlateAdapter.test.ts +0 -50
  435. package/src/__tests__/composables/useWellPlateValidation.test.ts +0 -42
  436. package/src/__tests__/docs/extractDocsComponents.test.ts +0 -156
  437. package/src/__tests__/docs/extractDocsExports.test.ts +0 -92
  438. package/src/__tests__/docs/extractDocsParsing.test.ts +0 -91
  439. package/src/__tests__/docs/extractDocsTemplates.test.ts +0 -53
  440. package/src/__tests__/docs/extractDocsTheme.test.ts +0 -89
  441. package/src/__tests__/docs/frontendDocsCatalog.test.ts +0 -425
  442. package/src/__tests__/fixtures/auto-group/mixed-lc-ms-batch.txt +0 -187
  443. package/src/__tests__/fixtures/templates/dose-response.json +0 -81
  444. package/src/__tests__/fixtures/templates/plate-map.json +0 -54
  445. package/src/__tests__/fixtures/templates/qpcr-plate.json +0 -96
  446. package/src/__tests__/fixtures/templates/sample-sheet.json +0 -71
  447. package/src/__tests__/generatedUi.test.ts +0 -119
  448. package/src/__tests__/stores/experiment.test.ts +0 -300
  449. package/src/__tests__/stores/settings.test.ts +0 -78
  450. package/src/__tests__/templates/templates.test.ts +0 -1185
  451. package/src/__tests__/types/GeneratedJsonSchema.test.ts +0 -62
  452. package/src/__tests__/utils/color.test.ts +0 -96
  453. package/src/__tests__/utils/instrument.test.ts +0 -47
  454. package/src/__tests__/utils/jobs.test.ts +0 -95
  455. package/src/__tests__/utils/lcms.test.ts +0 -73
  456. package/src/__tests__/utils/permissions.test.ts +0 -62
  457. package/src/__tests__/utils/rack.test.ts +0 -120
  458. package/src/components/ActionMenu.story.vue +0 -26
  459. package/src/components/ActionMenu.vue +0 -209
  460. package/src/components/AlertBox.story.vue +0 -204
  461. package/src/components/AlertBox.vue +0 -88
  462. package/src/components/AppAvatarMenu.story.vue +0 -155
  463. package/src/components/AppAvatarMenu.vue +0 -133
  464. package/src/components/AppContainer.story.vue +0 -104
  465. package/src/components/AppContainer.vue +0 -34
  466. package/src/components/AppLayout.story.vue +0 -331
  467. package/src/components/AppLayout.vue +0 -156
  468. package/src/components/AppPluginSwitcher.vue +0 -137
  469. package/src/components/AppSidebar.story.vue +0 -584
  470. package/src/components/AppSidebar.vue +0 -471
  471. package/src/components/AppToastContainer.story.vue +0 -157
  472. package/src/components/AppToastContainer.vue +0 -62
  473. package/src/components/AppTopBar.navigation.ts +0 -60
  474. package/src/components/AppTopBar.story.vue +0 -280
  475. package/src/components/AppTopBar.vue +0 -474
  476. package/src/components/ArtifactSaveDialog.story.vue +0 -319
  477. package/src/components/ArtifactSaveDialog.vue +0 -434
  478. package/src/components/ArtifactSelectorModal.story.vue +0 -295
  479. package/src/components/ArtifactSelectorModal.vue +0 -333
  480. package/src/components/AuditTrail.story.vue +0 -163
  481. package/src/components/AuditTrail.vue +0 -151
  482. package/src/components/AutoGroupModal.adapter.ts +0 -203
  483. package/src/components/AutoGroupModal.story.vue +0 -458
  484. package/src/components/AutoGroupModal.vue +0 -294
  485. package/src/components/Avatar.story.vue +0 -115
  486. package/src/components/Avatar.vue +0 -79
  487. package/src/components/BaseButton.story.vue +0 -96
  488. package/src/components/BaseButton.vue +0 -75
  489. package/src/components/BaseCheckbox.story.vue +0 -100
  490. package/src/components/BaseCheckbox.vue +0 -131
  491. package/src/components/BaseInput.story.vue +0 -98
  492. package/src/components/BaseInput.vue +0 -76
  493. package/src/components/BaseModal.story.vue +0 -335
  494. package/src/components/BaseModal.vue +0 -328
  495. package/src/components/BasePill.story.vue +0 -142
  496. package/src/components/BasePill.vue +0 -89
  497. package/src/components/BaseRadioGroup.story.vue +0 -145
  498. package/src/components/BaseRadioGroup.vue +0 -128
  499. package/src/components/BaseSelect.story.vue +0 -120
  500. package/src/components/BaseSelect.vue +0 -89
  501. package/src/components/BaseSlider.story.vue +0 -122
  502. package/src/components/BaseSlider.vue +0 -126
  503. package/src/components/BaseTabs.story.vue +0 -127
  504. package/src/components/BaseTabs.vue +0 -82
  505. package/src/components/BaseTextarea.story.vue +0 -91
  506. package/src/components/BaseTextarea.vue +0 -62
  507. package/src/components/BaseToggle.story.vue +0 -108
  508. package/src/components/BaseToggle.vue +0 -143
  509. package/src/components/BatchProgressList.story.vue +0 -92
  510. package/src/components/BatchProgressList.vue +0 -181
  511. package/src/components/BioTemplateExperimentWorkspaceView.story.vue +0 -123
  512. package/src/components/BioTemplateExperimentWorkspaceView.vue +0 -350
  513. package/src/components/BioTemplatePackWorkspaceView.story.vue +0 -107
  514. package/src/components/BioTemplatePackWorkspaceView.vue +0 -184
  515. package/src/components/BioTemplatePresetWorkspaceView.story.vue +0 -163
  516. package/src/components/BioTemplatePresetWorkspaceView.vue +0 -408
  517. package/src/components/BioTemplateRenderer.story.vue +0 -57
  518. package/src/components/BioTemplateRenderer.vue +0 -64
  519. package/src/components/Breadcrumb.story.vue +0 -106
  520. package/src/components/Breadcrumb.vue +0 -81
  521. package/src/components/Calendar.story.vue +0 -106
  522. package/src/components/Calendar.vue +0 -367
  523. package/src/components/ChartContainer.story.vue +0 -113
  524. package/src/components/ChartContainer.vue +0 -64
  525. package/src/components/ChemicalFormula.story.vue +0 -102
  526. package/src/components/ChemicalFormula.vue +0 -39
  527. package/src/components/CollapsibleCard.story.vue +0 -135
  528. package/src/components/CollapsibleCard.vue +0 -245
  529. package/src/components/ColorSlider.story.vue +0 -120
  530. package/src/components/ColorSlider.vue +0 -164
  531. package/src/components/ComponentBindingRenderer.story.vue +0 -87
  532. package/src/components/ComponentBindingRenderer.vue +0 -324
  533. package/src/components/ConcentrationInput.story.vue +0 -77
  534. package/src/components/ConcentrationInput.vue +0 -149
  535. package/src/components/ConfirmDialog.story.vue +0 -248
  536. package/src/components/ConfirmDialog.vue +0 -100
  537. package/src/components/ControlWorkspaceView.story.vue +0 -347
  538. package/src/components/ControlWorkspaceView.vue +0 -381
  539. package/src/components/DataFrame.story.vue +0 -148
  540. package/src/components/DataFrame.vue +0 -520
  541. package/src/components/DatePicker.story.vue +0 -119
  542. package/src/components/DatePicker.vue +0 -197
  543. package/src/components/DateTimePicker.story.vue +0 -112
  544. package/src/components/DateTimePicker.vue +0 -271
  545. package/src/components/Divider.story.vue +0 -80
  546. package/src/components/Divider.vue +0 -49
  547. package/src/components/DoseCalculator.story.vue +0 -68
  548. package/src/components/DoseCalculator.vue +0 -416
  549. package/src/components/DoseCalculatorVolumeField.vue +0 -61
  550. package/src/components/DoseDesignWorkspaceView.story.vue +0 -77
  551. package/src/components/DoseDesignWorkspaceView.vue +0 -262
  552. package/src/components/DropdownButton.story.vue +0 -102
  553. package/src/components/DropdownButton.vue +0 -163
  554. package/src/components/EmptyState.story.vue +0 -135
  555. package/src/components/EmptyState.vue +0 -71
  556. package/src/components/ExperimentCodeBadge.story.vue +0 -77
  557. package/src/components/ExperimentCodeBadge.vue +0 -64
  558. package/src/components/ExperimentDataViewer.story.vue +0 -174
  559. package/src/components/ExperimentDataViewer.vue +0 -293
  560. package/src/components/ExperimentPopover.story.vue +0 -442
  561. package/src/components/ExperimentPopover.vue +0 -312
  562. package/src/components/ExperimentSelectorModal.story.vue +0 -381
  563. package/src/components/ExperimentSelectorModal.vue +0 -432
  564. package/src/components/ExperimentTimeline.story.vue +0 -161
  565. package/src/components/ExperimentTimeline.vue +0 -357
  566. package/src/components/FileUploader.story.vue +0 -107
  567. package/src/components/FileUploader.vue +0 -424
  568. package/src/components/FitPanel.story.vue +0 -125
  569. package/src/components/FitPanel.vue +0 -120
  570. package/src/components/FormActions.vue +0 -92
  571. package/src/components/FormBuilder.story.vue +0 -203
  572. package/src/components/FormBuilder.vue +0 -311
  573. package/src/components/FormField.story.vue +0 -132
  574. package/src/components/FormField.vue +0 -59
  575. package/src/components/FormulaInput.story.vue +0 -96
  576. package/src/components/FormulaInput.vue +0 -125
  577. package/src/components/GeneratedPathInput.vue +0 -218
  578. package/src/components/GeneratedPlotlyResult.vue +0 -87
  579. package/src/components/GeneratedPluginView.vue +0 -289
  580. package/src/components/GeneratedResultRenderer.vue +0 -147
  581. package/src/components/GroupAssigner.story.vue +0 -83
  582. package/src/components/GroupAssigner.vue +0 -257
  583. package/src/components/IconButton.story.vue +0 -140
  584. package/src/components/IconButton.vue +0 -73
  585. package/src/components/InstrumentAlertLog.vue +0 -191
  586. package/src/components/InstrumentStateBadge.vue +0 -50
  587. package/src/components/InstrumentStatusCard.vue +0 -188
  588. package/src/components/JobsStatusTray.story.vue +0 -126
  589. package/src/components/JobsStatusTray.vue +0 -392
  590. package/src/components/LcmsSequenceTable.vue +0 -191
  591. package/src/components/LoadingSpinner.story.vue +0 -70
  592. package/src/components/LoadingSpinner.vue +0 -50
  593. package/src/components/MobileSupportGate.story.vue +0 -52
  594. package/src/components/MobileSupportGate.vue +0 -115
  595. package/src/components/MoleculeInput.story.vue +0 -66
  596. package/src/components/MoleculeInput.vue +0 -426
  597. package/src/components/MultiSelect.story.vue +0 -132
  598. package/src/components/MultiSelect.vue +0 -123
  599. package/src/components/NumberInput.story.vue +0 -122
  600. package/src/components/NumberInput.vue +0 -162
  601. package/src/components/PlateMapEditor.story.vue +0 -92
  602. package/src/components/PlateMapEditor.vue +0 -434
  603. package/src/components/PluginIcon.story.vue +0 -103
  604. package/src/components/PluginIcon.vue +0 -158
  605. package/src/components/PluginWorkspaceView.controls.ts +0 -182
  606. package/src/components/PluginWorkspaceView.navigation.ts +0 -106
  607. package/src/components/PluginWorkspaceView.props.ts +0 -169
  608. package/src/components/PluginWorkspaceView.shell.ts +0 -67
  609. package/src/components/PluginWorkspaceView.story.vue +0 -341
  610. package/src/components/PluginWorkspaceView.vue +0 -395
  611. package/src/components/ProgressBar.story.vue +0 -148
  612. package/src/components/ProgressBar.vue +0 -117
  613. package/src/components/ProtocolStep.presentation.ts +0 -31
  614. package/src/components/ProtocolStepEditor.state.ts +0 -104
  615. package/src/components/ProtocolStepEditor.story.vue +0 -69
  616. package/src/components/ProtocolStepEditor.vue +0 -382
  617. package/src/components/ProtocolStepParameterField.vue +0 -134
  618. package/src/components/RackEditor.story.vue +0 -100
  619. package/src/components/RackEditor.vue +0 -442
  620. package/src/components/ReagentEditor.story.vue +0 -153
  621. package/src/components/ReagentEditor.vue +0 -418
  622. package/src/components/ReagentList.presentation.ts +0 -105
  623. package/src/components/ReagentList.story.vue +0 -137
  624. package/src/components/ReagentList.vue +0 -392
  625. package/src/components/ResourceCard.story.vue +0 -150
  626. package/src/components/ResourceCard.vue +0 -161
  627. package/src/components/RuntimeUpdateNotice.vue +0 -51
  628. package/src/components/SampleHierarchyTree.story.vue +0 -161
  629. package/src/components/SampleHierarchyTree.vue +0 -246
  630. package/src/components/SampleLegend.story.vue +0 -91
  631. package/src/components/SampleLegend.vue +0 -119
  632. package/src/components/SampleSelector.colors.ts +0 -48
  633. package/src/components/SampleSelector.drag.ts +0 -164
  634. package/src/components/SampleSelector.groups.ts +0 -109
  635. package/src/components/SampleSelector.selection.ts +0 -64
  636. package/src/components/SampleSelector.story.vue +0 -192
  637. package/src/components/SampleSelector.tree.ts +0 -48
  638. package/src/components/SampleSelector.vue +0 -451
  639. package/src/components/SampleSelectorGroupNode.vue +0 -197
  640. package/src/components/SampleSelectorSampleRow.vue +0 -68
  641. package/src/components/ScheduleCalendar.story.vue +0 -195
  642. package/src/components/ScheduleCalendar.vue +0 -414
  643. package/src/components/ScientificNumber.story.vue +0 -127
  644. package/src/components/ScientificNumber.vue +0 -197
  645. package/src/components/SectionCard.story.vue +0 -163
  646. package/src/components/SectionCard.vue +0 -98
  647. package/src/components/SegmentedControl.story.vue +0 -149
  648. package/src/components/SegmentedControl.vue +0 -94
  649. package/src/components/SequenceInput.story.vue +0 -119
  650. package/src/components/SequenceInput.vue +0 -209
  651. package/src/components/SequenceProgressBar.vue +0 -71
  652. package/src/components/SettingsModal.schema.ts +0 -74
  653. package/src/components/SettingsModal.story.vue +0 -524
  654. package/src/components/SettingsModal.vue +0 -399
  655. package/src/components/Skeleton.story.vue +0 -141
  656. package/src/components/Skeleton.vue +0 -74
  657. package/src/components/SmartGroup.types.ts +0 -98
  658. package/src/components/SmartGroupFieldRecipe.groups.ts +0 -109
  659. package/src/components/SmartGroupFieldRecipe.story.vue +0 -58
  660. package/src/components/SmartGroupFieldRecipe.vue +0 -499
  661. package/src/components/SmartGroupManual.cohorts.ts +0 -112
  662. package/src/components/SmartGroupManual.story.vue +0 -55
  663. package/src/components/SmartGroupManual.vue +0 -398
  664. package/src/components/SmartGroupModal.story.vue +0 -61
  665. package/src/components/SmartGroupModal.vue +0 -61
  666. package/src/components/StatusIndicator.story.vue +0 -99
  667. package/src/components/StatusIndicator.vue +0 -40
  668. package/src/components/StepWizard.story.vue +0 -155
  669. package/src/components/StepWizard.vue +0 -223
  670. package/src/components/TagsInput.story.vue +0 -155
  671. package/src/components/TagsInput.vue +0 -280
  672. package/src/components/ThemeToggle.story.vue +0 -36
  673. package/src/components/ThemeToggle.vue +0 -56
  674. package/src/components/TimePicker.story.vue +0 -96
  675. package/src/components/TimePicker.vue +0 -251
  676. package/src/components/TimeRangeInput.story.vue +0 -104
  677. package/src/components/TimeRangeInput.vue +0 -122
  678. package/src/components/Tooltip.story.vue +0 -138
  679. package/src/components/Tooltip.vue +0 -114
  680. package/src/components/UnitInput.story.vue +0 -194
  681. package/src/components/UnitInput.vue +0 -217
  682. package/src/components/WellPlate.colors.ts +0 -56
  683. package/src/components/WellPlate.conditions.ts +0 -100
  684. package/src/components/WellPlate.geometry.ts +0 -91
  685. package/src/components/WellPlate.interaction.ts +0 -272
  686. package/src/components/WellPlate.legend.ts +0 -8
  687. package/src/components/WellPlate.rendering.ts +0 -105
  688. package/src/components/WellPlate.sampleDrop.ts +0 -73
  689. package/src/components/WellPlate.story.vue +0 -282
  690. package/src/components/WellPlate.vue +0 -497
  691. package/src/components/index.ts +0 -139
  692. package/src/components/internal/ActionItemInternal.vue +0 -82
  693. package/src/components/internal/AppTopBarPageSelectorInternal.vue +0 -127
  694. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -194
  695. package/src/components/internal/CalendarGridPanelInternal.vue +0 -120
  696. package/src/components/internal/FormFieldRendererInternal.vue +0 -68
  697. package/src/components/internal/FormSectionRenderer.vue +0 -78
  698. package/src/components/internal/PlateMapEditorToolbarInternal.vue +0 -128
  699. package/src/components/internal/WellEditPopupInternal.vue +0 -230
  700. package/src/composables/analysisArtifactTarget.ts +0 -53
  701. package/src/composables/autoGroup/classKey.ts +0 -8
  702. package/src/composables/autoGroup/classify.ts +0 -205
  703. package/src/composables/autoGroup/colors.ts +0 -6
  704. package/src/composables/autoGroup/columns.ts +0 -226
  705. package/src/composables/autoGroup/compose.ts +0 -244
  706. package/src/composables/autoGroup/cooccurrence.ts +0 -46
  707. package/src/composables/autoGroup/csv-shim.ts +0 -44
  708. package/src/composables/autoGroup/fingerprint.ts +0 -63
  709. package/src/composables/autoGroup/index.ts +0 -22
  710. package/src/composables/autoGroup/replicatePreGroup.ts +0 -124
  711. package/src/composables/autoGroup/template.ts +0 -126
  712. package/src/composables/autoGroup/tokenLength.ts +0 -53
  713. package/src/composables/autoGroup/tokenize.ts +0 -41
  714. package/src/composables/autoGroup/vocab.json +0 -66
  715. package/src/composables/autoGroupConstants.ts +0 -4
  716. package/src/composables/autoGroupGrouping.ts +0 -148
  717. package/src/composables/controlComponentBindings.ts +0 -80
  718. package/src/composables/controlSchemaAdapters.ts +0 -199
  719. package/src/composables/controlSchemaDoseDesign.ts +0 -222
  720. package/src/composables/controlSchemaFormFields.ts +0 -64
  721. package/src/composables/controlSchemaLayout.ts +0 -59
  722. package/src/composables/controlSchemaModel.ts +0 -172
  723. package/src/composables/controlSchemaNormalize.ts +0 -101
  724. package/src/composables/controlSchemaTypes.ts +0 -372
  725. package/src/composables/controlSchemaUtils.ts +0 -36
  726. package/src/composables/controlWorkspaceOptions.ts +0 -21
  727. package/src/composables/experiment-utils.ts +0 -105
  728. package/src/composables/experimentDesignData.ts +0 -182
  729. package/src/composables/formBuilderRegistry.ts +0 -81
  730. package/src/composables/formBuilderSchema.ts +0 -153
  731. package/src/composables/index.ts +0 -523
  732. package/src/composables/platformContextHelpers.ts +0 -81
  733. package/src/composables/pluginEndpointBuilder.ts +0 -267
  734. package/src/composables/pluginFrontendBase.ts +0 -22
  735. package/src/composables/protocolTemplateCatalog.ts +0 -325
  736. package/src/composables/useAnalysisArtifacts.ts +0 -361
  737. package/src/composables/useApi.ts +0 -319
  738. package/src/composables/useAppExperiment.ts +0 -228
  739. package/src/composables/useAsync.ts +0 -323
  740. package/src/composables/useAuth.ts +0 -455
  741. package/src/composables/useAutoGroup.ts +0 -682
  742. package/src/composables/useAutoGroupInputSources.ts +0 -147
  743. package/src/composables/useBioTemplateComponents.ts +0 -105
  744. package/src/composables/useBioTemplateControls.ts +0 -41
  745. package/src/composables/useBioTemplatePackWorkspace.ts +0 -193
  746. package/src/composables/useBioTemplatePresetWorkspace.ts +0 -326
  747. package/src/composables/useBioTemplateWorkspace.ts +0 -141
  748. package/src/composables/useCalendarGrid.ts +0 -140
  749. package/src/composables/useChemicalFormula.ts +0 -275
  750. package/src/composables/useCommandHistory.ts +0 -113
  751. package/src/composables/useConcentrationUnits.ts +0 -246
  752. package/src/composables/useControlSchema.ts +0 -135
  753. package/src/composables/useControlWorkspace.ts +0 -209
  754. package/src/composables/useDebouncedWatch.ts +0 -119
  755. package/src/composables/useDoseCalculator.ts +0 -370
  756. package/src/composables/useDropdownState.ts +0 -83
  757. package/src/composables/useEventListener.ts +0 -111
  758. package/src/composables/useEventStream.ts +0 -314
  759. package/src/composables/useExpansionSet.ts +0 -117
  760. package/src/composables/useExperimentData.ts +0 -136
  761. package/src/composables/useExperimentSamples.ts +0 -142
  762. package/src/composables/useExperimentSave.ts +0 -344
  763. package/src/composables/useExperimentSelector.ts +0 -408
  764. package/src/composables/useFileImport.ts +0 -231
  765. package/src/composables/useForm.ts +0 -279
  766. package/src/composables/useFormBuilder.ts +0 -292
  767. package/src/composables/useFormValidation.ts +0 -154
  768. package/src/composables/useGeneratedAnalysis.ts +0 -1214
  769. package/src/composables/useGroupAssignment.ts +0 -148
  770. package/src/composables/useJobsStatusTray.ts +0 -326
  771. package/src/composables/useListSelection.ts +0 -158
  772. package/src/composables/useMobileSupportGate.ts +0 -80
  773. package/src/composables/useOptimisticMutation.ts +0 -107
  774. package/src/composables/usePasskey.ts +0 -216
  775. package/src/composables/usePlatformContext.ts +0 -299
  776. package/src/composables/usePluginClient.ts +0 -963
  777. package/src/composables/usePresenceHeartbeat.ts +0 -201
  778. package/src/composables/useProtocolTemplates.ts +0 -212
  779. package/src/composables/useRackEditor.ts +0 -223
  780. package/src/composables/useReagentSeries.ts +0 -91
  781. package/src/composables/useRequestSyncState.ts +0 -126
  782. package/src/composables/useResourceCrud.ts +0 -245
  783. package/src/composables/useRuntimeAlignment.ts +0 -184
  784. package/src/composables/useSampleGroups.ts +0 -211
  785. package/src/composables/useScheduleCalendarLayout.ts +0 -287
  786. package/src/composables/useScheduleDrag.ts +0 -245
  787. package/src/composables/useSelectionLimit.ts +0 -57
  788. package/src/composables/useSequenceUtils.ts +0 -105
  789. package/src/composables/useSortedItems.ts +0 -118
  790. package/src/composables/useTemplateCollection.ts +0 -229
  791. package/src/composables/useTextSearch.ts +0 -60
  792. package/src/composables/useTheme.ts +0 -32
  793. package/src/composables/useTimeUtils.ts +0 -155
  794. package/src/composables/useToast.ts +0 -40
  795. package/src/composables/useWellPainting.ts +0 -187
  796. package/src/composables/useWellPlateAdapter.ts +0 -147
  797. package/src/composables/useWellPlateEditor.ts +0 -425
  798. package/src/composables/useWellPlateValidation.ts +0 -85
  799. package/src/generated/schema.ts +0 -130
  800. package/src/generated-ui/main.ts +0 -21
  801. package/src/histoire.setup.ts +0 -17
  802. package/src/index.ts +0 -67
  803. package/src/install.ts +0 -39
  804. package/src/instrument.ts +0 -90
  805. package/src/jobs.ts +0 -80
  806. package/src/lcms.ts +0 -108
  807. package/src/permissions.ts +0 -144
  808. package/src/plotly-dist.d.ts +0 -3
  809. package/src/stores/auth.ts +0 -205
  810. package/src/stores/experiment.ts +0 -120
  811. package/src/stores/index.ts +0 -3
  812. package/src/stores/settings.ts +0 -232
  813. package/src/styles/components/action-menu.css +0 -59
  814. package/src/styles/components/alert-box.css +0 -150
  815. package/src/styles/components/app-avatar-menu.css +0 -156
  816. package/src/styles/components/app-container.css +0 -33
  817. package/src/styles/components/app-layout.css +0 -180
  818. package/src/styles/components/app-page-selector.css +0 -212
  819. package/src/styles/components/app-pill-nav.css +0 -133
  820. package/src/styles/components/app-plugin-switcher.css +0 -196
  821. package/src/styles/components/app-sidebar.css +0 -392
  822. package/src/styles/components/app-top-bar.css +0 -249
  823. package/src/styles/components/artifact-save-dialog.css +0 -17
  824. package/src/styles/components/artifact-selector-modal.css +0 -216
  825. package/src/styles/components/audit-trail.css +0 -143
  826. package/src/styles/components/avatar.css +0 -73
  827. package/src/styles/components/batch-progress-list.css +0 -196
  828. package/src/styles/components/breadcrumb.css +0 -64
  829. package/src/styles/components/button.css +0 -192
  830. package/src/styles/components/calendar.css +0 -192
  831. package/src/styles/components/chart-container.css +0 -69
  832. package/src/styles/components/checkbox.css +0 -210
  833. package/src/styles/components/chemical-formula.css +0 -46
  834. package/src/styles/components/collapsible-card.css +0 -393
  835. package/src/styles/components/color-slider.css +0 -110
  836. package/src/styles/components/concentration-input.css +0 -17
  837. package/src/styles/components/confirm-dialog.css +0 -59
  838. package/src/styles/components/dataframe.css +0 -554
  839. package/src/styles/components/date-picker.css +0 -243
  840. package/src/styles/components/datetime-picker.css +0 -229
  841. package/src/styles/components/divider.css +0 -63
  842. package/src/styles/components/dose-calculator.css +0 -297
  843. package/src/styles/components/dropdown-button.css +0 -280
  844. package/src/styles/components/empty-state.css +0 -135
  845. package/src/styles/components/experiment-code-badge.css +0 -33
  846. package/src/styles/components/experiment-data-viewer.css +0 -138
  847. package/src/styles/components/experiment-popover.css +0 -563
  848. package/src/styles/components/experiment-selector-modal.css +0 -341
  849. package/src/styles/components/experiment-timeline.css +0 -529
  850. package/src/styles/components/file-uploader.css +0 -310
  851. package/src/styles/components/fit-panel.css +0 -67
  852. package/src/styles/components/form-builder.css +0 -69
  853. package/src/styles/components/form-field.css +0 -48
  854. package/src/styles/components/formula-input.css +0 -103
  855. package/src/styles/components/group-assigner.css +0 -200
  856. package/src/styles/components/icon-button.css +0 -196
  857. package/src/styles/components/input.css +0 -65
  858. package/src/styles/components/instrument-monitor.css +0 -478
  859. package/src/styles/components/jobs-status-tray.css +0 -420
  860. package/src/styles/components/lcms-sequence-table.css +0 -189
  861. package/src/styles/components/loading-spinner.css +0 -67
  862. package/src/styles/components/mobile-support-gate.css +0 -119
  863. package/src/styles/components/modal.css +0 -646
  864. package/src/styles/components/molecule-input.css +0 -186
  865. package/src/styles/components/multi-select.css +0 -131
  866. package/src/styles/components/number-input.css +0 -199
  867. package/src/styles/components/pill.css +0 -188
  868. package/src/styles/components/plate-map-editor.css +0 -464
  869. package/src/styles/components/plugin-icon.css +0 -46
  870. package/src/styles/components/progress-bar.css +0 -133
  871. package/src/styles/components/protocol-step-editor.css +0 -443
  872. package/src/styles/components/rack-editor.css +0 -265
  873. package/src/styles/components/radio-group.css +0 -240
  874. package/src/styles/components/reagent-editor.css +0 -505
  875. package/src/styles/components/reagent-list.css +0 -407
  876. package/src/styles/components/resource-card.css +0 -360
  877. package/src/styles/components/sample-hierarchy-tree.css +0 -310
  878. package/src/styles/components/sample-legend.css +0 -201
  879. package/src/styles/components/sample-selector.css +0 -682
  880. package/src/styles/components/schedule-calendar.css +0 -472
  881. package/src/styles/components/scientific-number.css +0 -63
  882. package/src/styles/components/section-card.css +0 -161
  883. package/src/styles/components/segmented-control.css +0 -194
  884. package/src/styles/components/select.css +0 -77
  885. package/src/styles/components/sequence-input.css +0 -184
  886. package/src/styles/components/sequence-progress-bar.css +0 -63
  887. package/src/styles/components/settings-modal.css +0 -76
  888. package/src/styles/components/skeleton.css +0 -49
  889. package/src/styles/components/slider.css +0 -74
  890. package/src/styles/components/smart-group.css +0 -734
  891. package/src/styles/components/status-indicator.css +0 -66
  892. package/src/styles/components/step-wizard.css +0 -192
  893. package/src/styles/components/tabs.css +0 -103
  894. package/src/styles/components/tags-input.css +0 -195
  895. package/src/styles/components/textarea.css +0 -81
  896. package/src/styles/components/theme-toggle.css +0 -6
  897. package/src/styles/components/time-picker.css +0 -171
  898. package/src/styles/components/time-range-input.css +0 -42
  899. package/src/styles/components/toast.css +0 -91
  900. package/src/styles/components/toggle.css +0 -226
  901. package/src/styles/components/tooltip.css +0 -91
  902. package/src/styles/components/unit-input.css +0 -123
  903. package/src/styles/components/well-edit-popup.css +0 -258
  904. package/src/styles/components/well-plate.css +0 -286
  905. package/src/styles/index.css +0 -93
  906. package/src/styles/variables.css +0 -1150
  907. package/src/tailwind.preset.ts +0 -66
  908. package/src/templates/adapters.ts +0 -137
  909. package/src/templates/assayLookups.ts +0 -33
  910. package/src/templates/assayMatrixAdapters.ts +0 -78
  911. package/src/templates/assayMatrixBuilder.ts +0 -59
  912. package/src/templates/assayNormalizers.ts +0 -34
  913. package/src/templates/builderDefaults.ts +0 -11
  914. package/src/templates/builderIdUtils.ts +0 -20
  915. package/src/templates/builderPresetControls.ts +0 -165
  916. package/src/templates/builderReadUtils.ts +0 -57
  917. package/src/templates/builders.ts +0 -122
  918. package/src/templates/calibrationCurveAdapters.ts +0 -59
  919. package/src/templates/calibrationCurveBuilder.ts +0 -99
  920. package/src/templates/calibrationNormalizers.ts +0 -60
  921. package/src/templates/catalog.ts +0 -245
  922. package/src/templates/componentBindingCatalog.ts +0 -90
  923. package/src/templates/componentBindingHelpers.ts +0 -93
  924. package/src/templates/componentBindings.ts +0 -253
  925. package/src/templates/componentDoseResponseProps.ts +0 -42
  926. package/src/templates/componentGenericProps.ts +0 -77
  927. package/src/templates/componentPlateHelpers.ts +0 -29
  928. package/src/templates/componentPlateMapProps.ts +0 -32
  929. package/src/templates/componentPropsFactory.ts +0 -21
  930. package/src/templates/componentQpcrPlateProps.ts +0 -28
  931. package/src/templates/componentTargetResolvers.ts +0 -69
  932. package/src/templates/componentTemplateProps.ts +0 -78
  933. package/src/templates/controlSchemaClone.ts +0 -32
  934. package/src/templates/controlSchemaConstants.ts +0 -11
  935. package/src/templates/controlSchemaMerge.ts +0 -40
  936. package/src/templates/controlSchemaTargets.ts +0 -87
  937. package/src/templates/controlSchemaTypes.ts +0 -20
  938. package/src/templates/controlSchemas.ts +0 -104
  939. package/src/templates/defaultBioTemplateBuilder.ts +0 -124
  940. package/src/templates/doseResponseAdapters.ts +0 -45
  941. package/src/templates/doseResponseBuilder.ts +0 -44
  942. package/src/templates/elisaAssayCollectionBuilder.ts +0 -62
  943. package/src/templates/flowCytometryAssayCollectionBuilder.ts +0 -41
  944. package/src/templates/flowCytometryPanelBuilder.ts +0 -53
  945. package/src/templates/flowNormalizers.ts +0 -58
  946. package/src/templates/flowPanelAdapters.ts +0 -58
  947. package/src/templates/index.ts +0 -326
  948. package/src/templates/instrumentRunAdapterHelpers.ts +0 -94
  949. package/src/templates/instrumentRunAdapters.ts +0 -163
  950. package/src/templates/instrumentRunBuilder.ts +0 -97
  951. package/src/templates/lcmsBatchCollectionBuilder.ts +0 -38
  952. package/src/templates/lookup.ts +0 -18
  953. package/src/templates/packs.ts +0 -162
  954. package/src/templates/plateGeometry.ts +0 -62
  955. package/src/templates/plateMapAdapters.ts +0 -36
  956. package/src/templates/plateMapBuilder.ts +0 -43
  957. package/src/templates/presetControlSchemas.ts +0 -258
  958. package/src/templates/presets.ts +0 -179
  959. package/src/templates/protocolAdapters.ts +0 -69
  960. package/src/templates/protocolNormalizers.ts +0 -37
  961. package/src/templates/protocolStepsBuilder.ts +0 -36
  962. package/src/templates/qpcrAdapters.ts +0 -104
  963. package/src/templates/qpcrExpressionCollectionBuilder.ts +0 -33
  964. package/src/templates/qpcrPlateBuilder.ts +0 -96
  965. package/src/templates/reagentAdapters.ts +0 -77
  966. package/src/templates/reagentListBuilder.ts +0 -30
  967. package/src/templates/runNormalizers.ts +0 -63
  968. package/src/templates/sampleNormalizers.ts +0 -58
  969. package/src/templates/samplePrepAdapters.ts +0 -63
  970. package/src/templates/samplePrepBuilder.ts +0 -51
  971. package/src/templates/sampleSheetAdapters.ts +0 -75
  972. package/src/templates/sampleSheetBuilder.ts +0 -23
  973. package/src/templates/targetedMetabolomicsCollectionBuilder.ts +0 -79
  974. package/src/templates/targetedMetabolomicsHelpers.ts +0 -102
  975. package/src/templates/templateAdapterTypes.ts +0 -58
  976. package/src/templates/templateControlSchemas.ts +0 -320
  977. package/src/templates/templateCreateOptions.ts +0 -208
  978. package/src/templates/templateEnvelopes.ts +0 -137
  979. package/src/templates/templatePackCollectionBuilder.ts +0 -23
  980. package/src/templates/templatePresetCollectionBuilder.ts +0 -139
  981. package/src/templates/templateQpcrTypes.ts +0 -48
  982. package/src/templates/templateValidators.ts +0 -414
  983. package/src/templates/timeCourseAdapters.ts +0 -73
  984. package/src/templates/timeCourseBuilder.ts +0 -64
  985. package/src/templates/types.ts +0 -493
  986. package/src/templates/wellPlateScreenCollectionBuilder.ts +0 -36
  987. package/src/templates/westernBlotAssayCollectionBuilder.ts +0 -68
  988. package/src/types/analysisArtifactTypes.ts +0 -176
  989. package/src/types/auth.ts +0 -58
  990. package/src/types/auto-group.ts +0 -157
  991. package/src/types/componentLabTypes.ts +0 -235
  992. package/src/types/componentWorkflowTypes.ts +0 -190
  993. package/src/types/components.ts +0 -527
  994. package/src/types/form-builder.ts +0 -207
  995. package/src/types/generated-ui.ts +0 -189
  996. package/src/types/index.ts +0 -299
  997. package/src/types/instrument.ts +0 -62
  998. package/src/types/jobs.ts +0 -70
  999. package/src/types/platform.ts +0 -132
  1000. package/src/utils/color.ts +0 -96
  1001. package/src/utils/formModelSync.ts +0 -52
  1002. package/src/utils/items.ts +0 -28
  1003. package/src/utils/options.ts +0 -23
  1004. package/src/utils/pluginIcon.ts +0 -190
  1005. package/src/utils/rack.ts +0 -209
  1006. package/src/utils/sampleGroupPath.ts +0 -19
@@ -1 +0,0 @@
1
- {"version":3,"file":"composables-C_i90sGS.js","names":[],"sources":["../src/composables/useAuth.ts","../src/composables/usePasskey.ts","../src/composables/pluginFrontendBase.ts","../src/composables/useAsync.ts","../src/composables/analysisArtifactTarget.ts","../src/composables/useCommandHistory.ts","../src/composables/useOptimisticMutation.ts","../src/composables/useResourceCrud.ts","../src/composables/useWellPainting.ts","../src/composables/useWellPlateAdapter.ts","../src/composables/useWellPlateValidation.ts","../src/composables/pluginEndpointBuilder.ts","../src/composables/usePluginClient.ts"],"sourcesContent":["import axios from 'axios'\nimport { ref, onMounted, onUnmounted, watch, getCurrentInstance, type Ref } from 'vue'\nimport { useAuthStore } from '../stores/auth'\nimport { useSettingsStore } from '../stores/settings'\nimport type { AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, UpdateProfileRequest } from '../types'\nimport type { RoleInfo } from '../permissions'\n\ninterface UserResponse {\n id: number\n username: string\n shortname: string | null\n email: string | null\n role: string\n role_obj?: RoleInfo | null\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\n// Module-level singletons to prevent duplicate refresh requests and timers\n// across multiple useAuth() instances\nlet _refreshPromise: Promise<boolean> | null = null\nlet _refreshTimerId: number | null = null\nlet _mountedConsumerCount = 0\n\n/** @internal Reset module-level state — only for use in tests. */\nexport function _resetAuthStateForTesting(): void {\n _refreshPromise = null\n if (_refreshTimerId !== null) {\n clearTimeout(_refreshTimerId)\n _refreshTimerId = null\n }\n _mountedConsumerCount = 0\n}\n\n/** Manages authentication state with login/logout/register and automatic JWT token refresh. */\nexport function useAuth(): UseAuthReturn {\n const authStore = useAuthStore()\n const settingsStore = useSettingsStore()\n\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 access?: {\n experiment_visibility_mode?: 'open' | 'restricted'\n experimentVisibilityMode?: 'open' | 'restricted'\n }\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 experimentVisibilityMode:\n response.data.access?.experiment_visibility_mode\n ?? response.data.access?.experimentVisibilityMode\n ?? 'open',\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 experimentVisibilityMode: 'open',\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 roleObj: response.data.role_obj ?? null,\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 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 = window.setTimeout(() => {\n refreshToken()\n }, delay)\n }\n\n /**\n * Stop automatic token refresh.\n */\n function stopTokenRefresh(): void {\n if (_refreshTimerId !== null) {\n window.clearTimeout(_refreshTimerId)\n _refreshTimerId = 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 roleObj: response.data.role_obj ?? null,\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 (only inside component setup)\n let checkInterval: number | null = null\n\n if (getCurrentInstance()) {\n onMounted(() => {\n _mountedConsumerCount += 1\n checkInterval = window.setInterval(checkAndRefreshIfNeeded, TOKEN_REFRESH_CHECK_INTERVAL_MS)\n })\n\n onUnmounted(() => {\n if (checkInterval !== null) {\n window.clearInterval(checkInterval)\n checkInterval = null\n }\n\n _mountedConsumerCount = Math.max(0, _mountedConsumerCount - 1)\n if (_mountedConsumerCount === 0) {\n stopTokenRefresh()\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\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","import axios from 'axios'\nimport { useAuthStore } from '../stores/auth'\nimport { useSettingsStore } from '../stores/settings'\nimport type { CredentialInfo } from '../types'\n\n// Lazy-load @simplewebauthn/browser so plugins that never call usePasskey\n// don't need the optional peer dep installed (avoids build failures).\nasync function loadWebAuthn() {\n try {\n return await import('@simplewebauthn/browser')\n } catch {\n throw new Error(\n '@simplewebauthn/browser is required for passkey support. Install it: bun add @simplewebauthn/browser',\n )\n }\n}\n\ninterface PasskeyLoginResponse {\n access_token: string\n token_type: string\n expires_in: number\n}\n\n/** Registers and authenticates passkeys using WebAuthn, lazily loading the browser dependency. */\nexport function usePasskey() {\n const authStore = useAuthStore()\n const settingsStore = useSettingsStore()\n\n function getApiBaseUrl(): string {\n return settingsStore.getApiBaseUrl()\n }\n\n async function isSupported(): Promise<boolean> {\n try {\n const { browserSupportsWebAuthn } = await loadWebAuthn()\n return browserSupportsWebAuthn()\n } catch {\n return false\n }\n }\n\n async function registerPasskey(deviceName?: string): Promise<boolean> {\n const webauthn = await loadWebAuthn()\n if (!webauthn.browserSupportsWebAuthn()) {\n authStore.setError('WebAuthn is not supported in this browser')\n return false\n }\n\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n const optionsResponse = await axios.get<{ options: string }>(\n `${getApiBaseUrl()}/auth/passkey/register/options`,\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n withCredentials: true,\n }\n )\n\n const options = JSON.parse(optionsResponse.data.options)\n\n const credential = await webauthn.startRegistration(options)\n\n await axios.post(\n `${getApiBaseUrl()}/auth/passkey/register/verify`,\n {\n credential: JSON.stringify(credential),\n device_name: deviceName,\n },\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n withCredentials: true,\n }\n )\n\n authStore.setAuthConfig({\n ...authStore.authConfig,\n passkeyRegistered: true,\n })\n\n return true\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n authStore.setError(error.response.data.detail || 'Passkey registration failed')\n } else if (error instanceof Error) {\n if (error.name === 'NotAllowedError') {\n authStore.setError('Registration was cancelled or timed out')\n } else if (error.name === 'InvalidStateError') {\n authStore.setError('This authenticator is already registered')\n } else {\n authStore.setError(error.message)\n }\n } else {\n authStore.setError('Passkey registration failed')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function loginWithPasskey(): Promise<boolean> {\n const webauthn = await loadWebAuthn()\n if (!webauthn.browserSupportsWebAuthn()) {\n authStore.setError('WebAuthn is not supported in this browser')\n return false\n }\n\n authStore.setLoading(true)\n authStore.setError(null)\n\n try {\n const optionsResponse = await axios.get<{ options: string }>(\n `${getApiBaseUrl()}/auth/passkey/login/options`,\n { withCredentials: true }\n )\n\n const options = JSON.parse(optionsResponse.data.options)\n\n const credential = await webauthn.startAuthentication(options)\n\n const response = await axios.post<PasskeyLoginResponse>(\n `${getApiBaseUrl()}/auth/passkey/login/verify`,\n { credential: JSON.stringify(credential) },\n { withCredentials: true }\n )\n\n authStore.setToken(response.data.access_token, response.data.expires_in)\n\n return true\n } catch (error) {\n if (axios.isAxiosError(error) && error.response) {\n if (error.response.status === 404) {\n authStore.setError('No passkeys registered. Please login with password first.')\n } else {\n authStore.setError(error.response.data.detail || 'Passkey login failed')\n }\n } else if (error instanceof Error) {\n if (error.name === 'NotAllowedError') {\n authStore.setError('Authentication was cancelled or timed out')\n } else {\n authStore.setError(error.message)\n }\n } else {\n authStore.setError('Passkey login failed')\n }\n return false\n } finally {\n authStore.setLoading(false)\n }\n }\n\n async function listCredentials(): Promise<CredentialInfo[]> {\n try {\n const response = await axios.get<{ credentials: CredentialInfo[] }>(\n `${getApiBaseUrl()}/auth/passkey/credentials`,\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n }\n )\n return response.data.credentials\n } catch {\n return []\n }\n }\n\n async function deleteCredential(credentialId: string): Promise<boolean> {\n try {\n await axios.delete(\n `${getApiBaseUrl()}/auth/passkey/credentials/${encodeURIComponent(credentialId)}`,\n {\n headers: { Authorization: `Bearer ${authStore.token}` },\n }\n )\n\n const remaining = await listCredentials()\n if (remaining.length === 0) {\n authStore.setAuthConfig({\n ...authStore.authConfig,\n passkeyRegistered: false,\n })\n }\n\n return true\n } catch {\n return false\n }\n }\n\n async function deleteAllCredentials(): Promise<boolean> {\n try {\n await axios.delete(`${getApiBaseUrl()}/auth/passkey/credentials`, {\n headers: { Authorization: `Bearer ${authStore.token}` },\n })\n\n authStore.setAuthConfig({\n ...authStore.authConfig,\n passkeyRegistered: false,\n })\n\n return true\n } catch {\n return false\n }\n }\n\n return {\n isSupported,\n registerPasskey,\n loginWithPasskey,\n listCredentials,\n deleteCredential,\n deleteAllCredentials,\n }\n}\n","import { getInjectedPlatformContext } from './platformContextHelpers'\n\nfunction normalizePluginRoutePrefix(prefix: string | undefined): string | undefined {\n const candidate = prefix?.trim()\n if (!candidate) return undefined\n\n const path = candidate.split('/').filter(Boolean).join('/')\n return path ? `/${path}/` : '/'\n}\n\n/**\n * Resolve the Vue Router base for a plugin frontend.\n *\n * Integrated plugins use the platform-injected mount prefix. Standalone and\n * development builds retain the caller's Vite base unchanged.\n */\nexport function resolvePluginFrontendBase(fallbackBase: string = '/'): string {\n const context = getInjectedPlatformContext()\n if (!context?.isIntegrated) return fallbackBase\n\n return normalizePluginRoutePrefix(context.plugin?.route_prefix) ?? fallbackBase\n}\n","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 */\n/** Wraps an async function with reactive loading, error, and success state plus optional auto-execute. */\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","import type { AnalysisArtifactTarget } from '../types/analysisArtifactTypes'\n\nconst EXPERIMENT_ID = 'experiment_id'\nconst ARTIFACT_PLUGIN_ID = 'artifact_plugin_id'\nconst ARTIFACT_KEY = 'artifact_key'\nconst ARTIFACT_ID = 'artifact_id'\n\nfunction parsePositiveInteger(value: string | null): number | undefined {\n if (value === null || !/^\\d+$/.test(value)) return undefined\n const parsed = Number(value)\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined\n}\n\n/** Build the canonical query used to open one analysis artifact in a plugin. */\nexport function buildAnalysisArtifactTargetQuery(\n target: AnalysisArtifactTarget,\n): URLSearchParams {\n const query = new URLSearchParams()\n query.set(EXPERIMENT_ID, String(target.experimentId))\n query.set(ARTIFACT_PLUGIN_ID, target.artifactPluginId)\n query.set(ARTIFACT_KEY, target.artifactKey)\n if (target.artifactId !== undefined) {\n query.set(ARTIFACT_ID, String(target.artifactId))\n }\n return query\n}\n\n/** Parse a complete canonical target. Incomplete or invalid input is not guessed. */\nexport function parseAnalysisArtifactTarget(\n query: URLSearchParams,\n): AnalysisArtifactTarget | null {\n const experimentId = parsePositiveInteger(query.get(EXPERIMENT_ID))\n const artifactPluginId = query.get(ARTIFACT_PLUGIN_ID)?.trim()\n const artifactKey = query.get(ARTIFACT_KEY)?.trim()\n const rawArtifactId = query.get(ARTIFACT_ID)\n const artifactId = parsePositiveInteger(rawArtifactId)\n\n if (\n experimentId === undefined\n || !artifactPluginId\n || !artifactKey\n || (rawArtifactId !== null && artifactId === undefined)\n ) {\n return null\n }\n\n return {\n experimentId,\n artifactPluginId,\n artifactKey,\n ...(artifactId === undefined ? {} : { artifactId }),\n }\n}\n","import { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nexport type CommandHistoryResult = void | Promise<void>\n\nexport interface CommandHistoryCommand {\n execute: () => CommandHistoryResult\n undo: () => CommandHistoryResult\n redo?: () => CommandHistoryResult\n description?: string\n}\n\nexport interface CommandHistoryExecuteOptions {\n skipExecute?: boolean\n}\n\nexport interface UseCommandHistoryOptions {\n maxDepth?: number\n}\n\nexport interface UseCommandHistoryReturn<TCommand extends CommandHistoryCommand = CommandHistoryCommand> {\n undoStack: Ref<TCommand[]>\n redoStack: Ref<TCommand[]>\n canUndo: ComputedRef<boolean>\n canRedo: ComputedRef<boolean>\n undoDescription: ComputedRef<string>\n redoDescription: ComputedRef<string>\n execute: (command: TCommand, options?: CommandHistoryExecuteOptions) => CommandHistoryResult\n push: (command: TCommand) => void\n undo: () => CommandHistoryResult\n redo: () => CommandHistoryResult\n clear: () => void\n}\n\n/** Generic command-stack state for plugin editors with undo/redo controls. */\nexport function useCommandHistory<TCommand extends CommandHistoryCommand = CommandHistoryCommand>(\n options: UseCommandHistoryOptions = {},\n): UseCommandHistoryReturn<TCommand> {\n const maxDepth = Math.max(1, options.maxDepth ?? 50)\n const undoStack = ref<TCommand[]>([]) as Ref<TCommand[]>\n const redoStack = ref<TCommand[]>([]) as Ref<TCommand[]>\n\n const canUndo = computed(() => undoStack.value.length > 0)\n const canRedo = computed(() => redoStack.value.length > 0)\n const undoDescription = computed(() => undoStack.value[undoStack.value.length - 1]?.description ?? '')\n const redoDescription = computed(() => redoStack.value[redoStack.value.length - 1]?.description ?? '')\n\n function push(command: TCommand): void {\n undoStack.value = [...undoStack.value.slice(-(maxDepth - 1)), command]\n redoStack.value = []\n }\n\n function execute(\n command: TCommand,\n executeOptions: CommandHistoryExecuteOptions = {},\n ): CommandHistoryResult {\n if (executeOptions.skipExecute) {\n push(command)\n return\n }\n\n return afterMaybePromise(command.execute(), () => push(command))\n }\n\n function undo(): CommandHistoryResult {\n const command = undoStack.value[undoStack.value.length - 1]\n if (!command) return\n\n return afterMaybePromise(command.undo(), () => {\n undoStack.value = undoStack.value.slice(0, -1)\n redoStack.value = [...redoStack.value, command]\n })\n }\n\n function redo(): CommandHistoryResult {\n const command = redoStack.value[redoStack.value.length - 1]\n if (!command) return\n\n return afterMaybePromise((command.redo ?? command.execute)(), () => {\n redoStack.value = redoStack.value.slice(0, -1)\n undoStack.value = [...undoStack.value.slice(-(maxDepth - 1)), command]\n })\n }\n\n function clear(): void {\n undoStack.value = []\n redoStack.value = []\n }\n\n return {\n undoStack,\n redoStack,\n canUndo,\n canRedo,\n undoDescription,\n redoDescription,\n execute,\n push,\n undo,\n redo,\n clear,\n }\n}\n\nfunction afterMaybePromise(result: CommandHistoryResult, callback: () => void): CommandHistoryResult {\n if (isPromiseLike(result)) {\n return result.then(callback)\n }\n callback()\n}\n\nfunction isPromiseLike(value: unknown): value is Promise<void> {\n return !!value && typeof (value as { then?: unknown }).then === 'function'\n}\n","import { computed, ref, shallowRef, type ComputedRef, type Ref, type ShallowRef } from 'vue'\n\nexport interface OptimisticMutationContext<TVariables, TSnapshot> {\n variables: TVariables\n snapshot: TSnapshot | undefined\n}\n\nexport interface UseOptimisticMutationOptions<TVariables, TData, TSnapshot = unknown> {\n mutation: (variables: TVariables) => Promise<TData>\n snapshot?: (variables: TVariables) => TSnapshot\n apply?: (variables: TVariables, snapshot: TSnapshot | undefined) => void\n commit?: (data: TData, context: OptimisticMutationContext<TVariables, TSnapshot>) => void\n rollback?: (\n snapshot: TSnapshot | undefined,\n variables: TVariables,\n error: unknown,\n ) => void\n onSuccess?: (data: TData, context: OptimisticMutationContext<TVariables, TSnapshot>) => void\n onError?: (error: unknown, context: OptimisticMutationContext<TVariables, TSnapshot>) => void\n onSettled?: (context: OptimisticMutationContext<TVariables, TSnapshot>) => void\n readErrorMessage?: (error: unknown) => string\n}\n\nexport interface UseOptimisticMutationReturn<TVariables, TData, TSnapshot = unknown> {\n loading: ShallowRef<boolean>\n error: Ref<string | null>\n data: Ref<TData | null>\n lastSnapshot: Ref<TSnapshot | undefined>\n isIdle: ComputedRef<boolean>\n run: (variables: TVariables) => Promise<TData>\n clearError: () => void\n reset: () => void\n}\n\n/** Run async mutations with optional optimistic local updates and rollback. */\nexport function useOptimisticMutation<TVariables, TData, TSnapshot = unknown>(\n options: UseOptimisticMutationOptions<TVariables, TData, TSnapshot>,\n): UseOptimisticMutationReturn<TVariables, TData, TSnapshot> {\n const loading = shallowRef(false)\n const error = ref<string | null>(null)\n const data = ref<TData | null>(null) as Ref<TData | null>\n const lastSnapshot = ref<TSnapshot | undefined>(undefined) as Ref<TSnapshot | undefined>\n const isIdle = computed(() => !loading.value && data.value === null && error.value === null)\n\n function clearError(): void {\n error.value = null\n }\n\n function reset(): void {\n loading.value = false\n error.value = null\n data.value = null\n lastSnapshot.value = undefined\n }\n\n async function run(variables: TVariables): Promise<TData> {\n const snapshot = options.snapshot?.(variables)\n const context: OptimisticMutationContext<TVariables, TSnapshot> = { variables, snapshot }\n\n loading.value = true\n error.value = null\n lastSnapshot.value = snapshot\n options.apply?.(variables, snapshot)\n\n try {\n const result = await options.mutation(variables)\n data.value = result\n options.commit?.(result, context)\n options.onSuccess?.(result, context)\n return result\n } catch (err) {\n options.rollback?.(snapshot, variables, err)\n error.value = options.readErrorMessage?.(err) ?? readErrorMessage(err)\n options.onError?.(err, context)\n throw err\n } finally {\n loading.value = false\n options.onSettled?.(context)\n }\n }\n\n return {\n loading,\n error,\n data,\n lastSnapshot,\n isIdle,\n run,\n clearError,\n reset,\n }\n}\n\nfunction readErrorMessage(value: unknown): string {\n if (value instanceof Error && value.message) return value.message\n if (typeof value === 'string' && value.trim()) return value\n if (\n typeof value === 'object'\n && value !== null\n && 'message' in value\n && typeof (value as { message?: unknown }).message === 'string'\n && (value as { message: string }).message.trim()\n ) {\n return (value as { message: string }).message\n }\n return 'Request failed.'\n}\n","import { computed, ref, shallowRef, type ComputedRef, type Ref, type ShallowRef } from 'vue'\n\nexport type ResourceKey = string | number\n\nexport interface ResourceCrudAdapter<TItem, TCreate = Partial<TItem>, TUpdate = Partial<TItem>, TKey extends ResourceKey = ResourceKey> {\n list: () => Promise<TItem[]>\n create?: (payload: TCreate) => Promise<TItem>\n update?: (key: TKey, payload: TUpdate) => Promise<TItem>\n remove?: (key: TKey) => Promise<void>\n}\n\nexport interface UseResourceCrudOptions<\n TItem,\n TCreate = Partial<TItem>,\n TUpdate = Partial<TItem>,\n TKey extends ResourceKey = ResourceKey,\n> {\n adapter: ResourceCrudAdapter<TItem, TCreate, TUpdate, TKey>\n initialItems?: readonly TItem[]\n getKey?: (item: TItem) => TKey\n readErrorMessage?: (error: unknown) => string\n}\n\nexport interface UseResourceCrudReturn<TItem, TCreate, TUpdate, TKey extends ResourceKey> {\n items: Ref<TItem[]>\n loading: ShallowRef<boolean>\n saving: ShallowRef<boolean>\n deleting: ShallowRef<boolean>\n error: Ref<string | null>\n isBusy: ComputedRef<boolean>\n load: () => Promise<TItem[]>\n createItem: (payload: TCreate) => Promise<TItem>\n updateItem: (key: TKey, payload: TUpdate) => Promise<TItem>\n deleteItem: (keyOrItem: TKey | TItem) => Promise<void>\n setItems: (items: readonly TItem[]) => void\n upsertLocal: (item: TItem) => void\n removeLocal: (keyOrItem: TKey | TItem) => void\n clearError: () => void\n}\n\n/** Common list/create/update/delete state wrapper for generated plugin clients. */\nexport function useResourceCrud<\n TItem,\n TCreate = Partial<TItem>,\n TUpdate = Partial<TItem>,\n TKey extends ResourceKey = ResourceKey,\n>(\n options: UseResourceCrudOptions<TItem, TCreate, TUpdate, TKey>,\n): UseResourceCrudReturn<TItem, TCreate, TUpdate, TKey> {\n const items = ref<TItem[]>([...(options.initialItems ?? [])]) as Ref<TItem[]>\n const loading = shallowRef(false)\n const saving = shallowRef(false)\n const deleting = shallowRef(false)\n const error = ref<string | null>(null)\n const isBusy = computed(() => loading.value || saving.value || deleting.value)\n\n const readMessage = options.readErrorMessage ?? readErrorMessage\n const getKey = options.getKey ?? defaultGetKey<TKey, TItem>\n\n function clearError(): void {\n error.value = null\n }\n\n function setError(err: unknown): void {\n error.value = readMessage(err)\n }\n\n function setItems(nextItems: readonly TItem[]): void {\n items.value = [...nextItems]\n }\n\n function upsertLocal(item: TItem): void {\n const key = getKey(item)\n const index = items.value.findIndex(existing => getKey(existing) === key)\n if (index === -1) {\n items.value = [...items.value, item]\n return\n }\n items.value = [\n ...items.value.slice(0, index),\n item,\n ...items.value.slice(index + 1),\n ]\n }\n\n function removeLocal(keyOrItem: TKey | TItem): void {\n const key = resolveKey(keyOrItem, getKey)\n items.value = items.value.filter(item => getKey(item) !== key)\n }\n\n async function load(): Promise<TItem[]> {\n loading.value = true\n clearError()\n try {\n const result = await options.adapter.list()\n setItems(result)\n return result\n } catch (err) {\n setError(err)\n throw err\n } finally {\n loading.value = false\n }\n }\n\n async function createItem(payload: TCreate): Promise<TItem> {\n if (!options.adapter.create) {\n throw new Error('[MINT SDK] Resource adapter does not implement create().')\n }\n saving.value = true\n clearError()\n try {\n const result = await options.adapter.create(payload)\n upsertLocal(result)\n return result\n } catch (err) {\n setError(err)\n throw err\n } finally {\n saving.value = false\n }\n }\n\n async function updateItem(key: TKey, payload: TUpdate): Promise<TItem> {\n if (!options.adapter.update) {\n throw new Error('[MINT SDK] Resource adapter does not implement update().')\n }\n saving.value = true\n clearError()\n try {\n const result = await options.adapter.update(key, payload)\n upsertLocal(result)\n return result\n } catch (err) {\n setError(err)\n throw err\n } finally {\n saving.value = false\n }\n }\n\n async function deleteItem(keyOrItem: TKey | TItem): Promise<void> {\n if (!options.adapter.remove) {\n throw new Error('[MINT SDK] Resource adapter does not implement remove().')\n }\n const key = resolveKey(keyOrItem, getKey)\n deleting.value = true\n clearError()\n try {\n await options.adapter.remove(key)\n removeLocal(key)\n } catch (err) {\n setError(err)\n throw err\n } finally {\n deleting.value = false\n }\n }\n\n return {\n items,\n loading,\n saving,\n deleting,\n error,\n isBusy,\n load,\n createItem,\n updateItem,\n deleteItem,\n setItems,\n upsertLocal,\n removeLocal,\n clearError,\n }\n}\n\nexport interface PluginResourceClientOptions<\n TClient,\n TItem,\n TCreate = Partial<TItem>,\n TUpdate = Partial<TItem>,\n TKey extends ResourceKey = ResourceKey,\n> {\n client: TClient\n list: (client: TClient) => Promise<TItem[]>\n create?: (client: TClient, payload: TCreate) => Promise<TItem>\n update?: (client: TClient, key: TKey, payload: TUpdate) => Promise<TItem>\n remove?: (client: TClient, key: TKey) => Promise<void>\n}\n\nexport function createPluginResourceClient<\n TClient,\n TItem,\n TCreate = Partial<TItem>,\n TUpdate = Partial<TItem>,\n TKey extends ResourceKey = ResourceKey,\n>(\n options: PluginResourceClientOptions<TClient, TItem, TCreate, TUpdate, TKey>,\n): ResourceCrudAdapter<TItem, TCreate, TUpdate, TKey> {\n return {\n list: () => options.list(options.client),\n create: options.create\n ? payload => options.create!(options.client, payload)\n : undefined,\n update: options.update\n ? (key, payload) => options.update!(options.client, key, payload)\n : undefined,\n remove: options.remove\n ? key => options.remove!(options.client, key)\n : undefined,\n }\n}\n\nfunction defaultGetKey<TKey extends ResourceKey, TItem>(item: TItem): TKey {\n if (item && typeof item === 'object' && 'id' in item) {\n return (item as { id: ResourceKey }).id as TKey\n }\n throw new Error('[MINT SDK] Resource items need an id field or a getKey option.')\n}\n\nfunction resolveKey<TItem, TKey extends ResourceKey>(\n keyOrItem: TKey | TItem,\n getKey: (item: TItem) => TKey,\n): TKey {\n if (typeof keyOrItem === 'string' || typeof keyOrItem === 'number') {\n return keyOrItem as TKey\n }\n return getKey(keyOrItem as TItem)\n}\n\nfunction readErrorMessage(value: unknown): string {\n if (value instanceof Error && value.message) return value.message\n if (typeof value === 'string' && value.trim()) return value\n if (\n typeof value === 'object'\n && value !== null\n && 'message' in value\n && typeof (value as { message?: unknown }).message === 'string'\n && (value as { message: string }).message.trim()\n ) {\n return (value as { message: string }).message\n }\n return 'Request failed.'\n}\n","import { computed, ref, toValue, type ComputedRef, type Ref } from 'vue'\nimport type { WellPlateFormat } from '../types'\n\nexport type WellPlateSource<T> = T | Ref<T> | ComputedRef<T> | (() => T)\n\nexport interface WellCoordinate {\n row: number\n col: number\n}\n\nexport interface WellPaintResult<TMode extends string = string, TPayload = unknown> {\n wellIds: string[]\n mode: TMode\n payload?: TPayload\n}\n\nexport interface UseWellPaintingOptions<TMode extends string = string, TPayload = unknown> {\n format: WellPlateSource<WellPlateFormat>\n initialMode?: TMode\n initialPayload?: TPayload\n onComplete?: (result: WellPaintResult<TMode, TPayload>) => void\n}\n\nexport interface UseWellPaintingReturn<TMode extends string = string, TPayload = unknown> {\n activeMode: Ref<TMode>\n activePayload: Ref<TPayload | undefined>\n isDragging: Ref<boolean>\n previewWellIds: ComputedRef<string[]>\n setMode: (mode: TMode, payload?: TPayload) => void\n setPayload: (payload: TPayload | undefined) => void\n onWellMouseDown: (wellId: string) => void\n onWellMouseMove: (wellId: string) => void\n onWellMouseUp: () => void\n cancel: () => void\n}\n\nconst ROW_LABELS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\nconst PLATE_DIMENSIONS: Record<WellPlateFormat, { rows: number; cols: number }> = {\n 6: { rows: 2, cols: 3 },\n 12: { rows: 3, cols: 4 },\n 24: { rows: 4, cols: 6 },\n 48: { rows: 6, cols: 8 },\n 54: { rows: 6, cols: 9 },\n 96: { rows: 8, cols: 12 },\n 384: { rows: 16, cols: 24 },\n}\n\n/** Pointer painting/rectangle selection state for WellPlate-based editors. */\nexport function useWellPainting<TMode extends string = string, TPayload = unknown>(\n options: UseWellPaintingOptions<TMode, TPayload>,\n): UseWellPaintingReturn<TMode, TPayload> {\n const activeMode = ref<TMode>(options.initialMode ?? 'select' as TMode) as Ref<TMode>\n const activePayload = ref<TPayload | undefined>(options.initialPayload) as Ref<TPayload | undefined>\n const isDragging = ref(false)\n const dragStart = ref<WellCoordinate | null>(null)\n const dragEnd = ref<WellCoordinate | null>(null)\n const paintTrail = ref<Set<string>>(new Set())\n\n const previewWellIds = computed(() => {\n if (!isDragging.value) return []\n if (activeMode.value === 'select') {\n if (!dragStart.value || !dragEnd.value) return []\n return wellIdsInRectangle(dragStart.value, dragEnd.value, toValue(options.format))\n }\n return [...paintTrail.value]\n })\n\n function setMode(mode: TMode, payload?: TPayload): void {\n activeMode.value = mode\n activePayload.value = payload\n }\n\n function setPayload(payload: TPayload | undefined): void {\n activePayload.value = payload\n }\n\n function onWellMouseDown(wellId: string): void {\n const coord = wellIdToCoordinate(wellId)\n if (!coord) return\n isDragging.value = true\n dragStart.value = coord\n dragEnd.value = coord\n paintTrail.value = new Set([wellId])\n }\n\n function onWellMouseMove(wellId: string): void {\n if (!isDragging.value) return\n const coord = wellIdToCoordinate(wellId)\n if (!coord) return\n dragEnd.value = coord\n if (activeMode.value !== 'select') {\n paintTrail.value = new Set([...paintTrail.value, wellId])\n }\n }\n\n function onWellMouseUp(): void {\n if (!isDragging.value) return\n const wellIds = previewWellIds.value\n isDragging.value = false\n if (wellIds.length > 0) {\n options.onComplete?.({\n wellIds,\n mode: activeMode.value,\n payload: activePayload.value,\n })\n }\n clearDragState()\n }\n\n function cancel(): void {\n isDragging.value = false\n clearDragState()\n }\n\n function clearDragState(): void {\n dragStart.value = null\n dragEnd.value = null\n paintTrail.value = new Set()\n }\n\n return {\n activeMode,\n activePayload,\n isDragging,\n previewWellIds,\n setMode,\n setPayload,\n onWellMouseDown,\n onWellMouseMove,\n onWellMouseUp,\n cancel,\n }\n}\n\nexport function wellIdToCoordinate(wellId: string): WellCoordinate | null {\n const match = /^([A-Z]+)(\\d+)$/i.exec(wellId.trim())\n if (!match) return null\n return {\n row: rowLabelToIndex(match[1].toUpperCase()),\n col: Number(match[2]) - 1,\n }\n}\n\nexport function coordinateToWellId(coord: WellCoordinate): string {\n return `${indexToRowLabel(coord.row)}${coord.col + 1}`\n}\n\nexport function wellIdsInRectangle(\n start: WellCoordinate,\n end: WellCoordinate,\n format: WellPlateFormat,\n): string[] {\n const dimensions = PLATE_DIMENSIONS[format]\n const minRow = Math.max(0, Math.min(start.row, end.row))\n const maxRow = Math.min(dimensions.rows - 1, Math.max(start.row, end.row))\n const minCol = Math.max(0, Math.min(start.col, end.col))\n const maxCol = Math.min(dimensions.cols - 1, Math.max(start.col, end.col))\n const ids: string[] = []\n\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n ids.push(coordinateToWellId({ row, col }))\n }\n }\n return ids\n}\n\nfunction rowLabelToIndex(label: string): number {\n let result = 0\n for (const char of label) {\n result = result * 26 + (char.charCodeAt(0) - 64)\n }\n return result - 1\n}\n\nfunction indexToRowLabel(index: number): string {\n if (index < ROW_LABELS.length) return ROW_LABELS[index]\n let value = index + 1\n let label = ''\n while (value > 0) {\n value--\n label = ROW_LABELS[value % 26] + label\n value = Math.floor(value / 26)\n }\n return label\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport type { ColumnCondition, RowCondition, Well } from '../types'\n\nexport type WellPlateAdapterSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface WellPlateEntry {\n wellId: string\n state?: Well['state']\n sampleType?: string\n value?: number\n metadata?: Record<string, unknown>\n}\n\nexport interface WellPlateAdapterOptions<TEntry> {\n entries: WellPlateAdapterSource<readonly TEntry[]>\n getWellId: (entry: TEntry) => string\n getState?: (entry: TEntry) => Well['state'] | undefined\n getSampleType?: (entry: TEntry) => string | undefined\n getValue?: (entry: TEntry) => number | undefined\n getMetadata?: (entry: TEntry) => Record<string, unknown> | undefined\n}\n\nexport interface UseWellPlateAdapterReturn {\n wells: ComputedRef<Record<string, Partial<Well>>>\n}\n\n/** Convert domain rows into WellPlate's wells prop without hand-written adapters. */\nexport function useWellPlateAdapter<TEntry>(\n options: WellPlateAdapterOptions<TEntry>,\n): UseWellPlateAdapterReturn {\n const wells = computed(() => createWellPlateWells(toValue(options.entries), options))\n return { wells }\n}\n\nexport function createWellPlateWells<TEntry>(\n entries: readonly TEntry[],\n options: Omit<WellPlateAdapterOptions<TEntry>, 'entries'>,\n): Record<string, Partial<Well>> {\n return Object.fromEntries(entries.map((entry) => {\n const wellId = options.getWellId(entry)\n const coord = parseWellId(wellId)\n const well: Partial<Well> = {\n id: wellId,\n row: coord.row,\n col: coord.col,\n state: options.getState?.(entry) ?? 'filled',\n sampleType: options.getSampleType?.(entry),\n value: options.getValue?.(entry),\n metadata: options.getMetadata?.(entry),\n }\n return [wellId, well]\n }))\n}\n\nexport interface AxisConditionEntry {\n label: string\n color: string\n start: string | number\n concentrations: readonly { value: number; replicates?: number }[]\n unit?: string\n}\n\nexport function createColumnConditions(entries: readonly AxisConditionEntry[]): ColumnCondition[] {\n return entries.map((entry) => {\n const startCol = typeof entry.start === 'number'\n ? entry.start\n : Number.parseInt(entry.start, 10)\n const cols: number[] = []\n const concentrations: number[] = []\n\n for (const concentration of entry.concentrations) {\n const replicates = concentration.replicates ?? 1\n for (let index = 0; index < replicates; index++) {\n cols.push(startCol + cols.length)\n concentrations.push(concentration.value)\n }\n }\n\n return {\n label: entry.label,\n color: entry.color,\n unit: entry.unit,\n cols,\n concentrations,\n }\n })\n}\n\nexport function createRowConditions(entries: readonly AxisConditionEntry[]): RowCondition[] {\n return entries.map((entry) => {\n const startRow = typeof entry.start === 'number'\n ? entry.start\n : rowLabelToIndex(entry.start)\n const rows: string[] = []\n const concentrations: number[] = []\n\n for (const concentration of entry.concentrations) {\n const replicates = concentration.replicates ?? 1\n for (let index = 0; index < replicates; index++) {\n rows.push(indexToRowLabel(startRow + rows.length))\n concentrations.push(concentration.value)\n }\n }\n\n return {\n label: entry.label,\n color: entry.color,\n unit: entry.unit,\n rows,\n concentrations,\n }\n })\n}\n\nfunction parseWellId(wellId: string): { row: number; col: number } {\n const match = /^([A-Z]+)(\\d+)$/i.exec(wellId.trim())\n if (!match) {\n throw new Error(`[MINT SDK] Invalid well id \"${wellId}\".`)\n }\n return {\n row: rowLabelToIndex(match[1].toUpperCase()),\n col: Number(match[2]) - 1,\n }\n}\n\nfunction rowLabelToIndex(label: string): number {\n let result = 0\n for (const char of label.toUpperCase()) {\n result = result * 26 + (char.charCodeAt(0) - 64)\n }\n return result - 1\n}\n\nfunction indexToRowLabel(index: number): string {\n let value = index + 1\n let label = ''\n while (value > 0) {\n value--\n label = String.fromCharCode(65 + (value % 26)) + label\n value = Math.floor(value / 26)\n }\n return label\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type WellPlateValidationSeverity = 'error' | 'warning' | 'info'\n\nexport interface WellPlateValidationWarning<TType extends string = string> {\n type: TType\n severity: WellPlateValidationSeverity\n message: string\n affectedWells?: string[]\n}\n\nexport interface WellPlateValidationRule<TContext, TType extends string = string> {\n type: TType\n severity: WellPlateValidationSeverity\n validate: (context: TContext) => false | string | Omit<WellPlateValidationWarning<TType>, 'type' | 'severity'>\n}\n\nexport type WellPlateValidationSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface UseWellPlateValidationOptions<TContext, TType extends string = string> {\n context: WellPlateValidationSource<TContext>\n rules: WellPlateValidationSource<readonly WellPlateValidationRule<TContext, TType>[]>\n}\n\nexport interface UseWellPlateValidationReturn<TType extends string = string> {\n warnings: ComputedRef<WellPlateValidationWarning<TType>[]>\n hasBlockingIssues: ComputedRef<boolean>\n warningCount: ComputedRef<number>\n errorCount: ComputedRef<number>\n}\n\n/** Rule-driven validation state for WellPlate layout/design screens. */\nexport function useWellPlateValidation<TContext, TType extends string = string>(\n options: UseWellPlateValidationOptions<TContext, TType>,\n): UseWellPlateValidationReturn<TType> {\n const warnings = computed(() => runWellPlateValidation(\n toValue(options.context),\n toValue(options.rules),\n ))\n const hasBlockingIssues = computed(() => warnings.value.some(warning => warning.severity === 'error'))\n const warningCount = computed(() => warnings.value.length)\n const errorCount = computed(() => warnings.value.filter(warning => warning.severity === 'error').length)\n\n return {\n warnings,\n hasBlockingIssues,\n warningCount,\n errorCount,\n }\n}\n\nexport function runWellPlateValidation<TContext, TType extends string = string>(\n context: TContext,\n rules: readonly WellPlateValidationRule<TContext, TType>[],\n): WellPlateValidationWarning<TType>[] {\n const warnings: WellPlateValidationWarning<TType>[] = []\n for (const rule of rules) {\n const result = rule.validate(context)\n if (!result) continue\n warnings.push(normalizeWarning(rule, result))\n }\n return warnings\n}\n\nfunction normalizeWarning<TContext, TType extends string>(\n rule: WellPlateValidationRule<TContext, TType>,\n result: string | Omit<WellPlateValidationWarning<TType>, 'type' | 'severity'>,\n): WellPlateValidationWarning<TType> {\n if (typeof result === 'string') {\n return {\n type: rule.type,\n severity: rule.severity,\n message: result,\n }\n }\n return {\n type: rule.type,\n severity: rule.severity,\n ...result,\n }\n}\n","import {\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\nimport type {\n BuildPluginEndpointUrlOptions,\n PluginContract,\n PluginEndpointDefinition,\n PluginEndpointParamDefinition,\n} from './usePluginClient'\n\nfunction normalizeApiBaseUrl(baseUrl: string | undefined): string | undefined {\n if (!baseUrl) return undefined\n return baseUrl.length > 1 ? baseUrl.replace(/\\/+$/, '') : baseUrl\n}\n\nfunction normalizeApiPrefix(prefix: string | undefined): string | undefined {\n if (!prefix) return undefined\n if (prefix.startsWith('/api/')) return normalizeApiBaseUrl(prefix)\n if (prefix === '/api') return prefix\n if (prefix.startsWith('/')) return normalizeApiBaseUrl(`/api${prefix}`)\n return normalizeApiBaseUrl(`/api/${prefix}`)\n}\n\nfunction endpointParamName(param: PluginEndpointParamDefinition): string {\n return typeof param === 'string' ? param : param.name\n}\n\nfunction endpointParamFieldName(param: PluginEndpointParamDefinition): string {\n return typeof param === 'string' ? param : param.fieldName ?? param.name\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction replacePathParam(path: string, name: string, encoded: string): string {\n const escapedName = escapeRegExp(name)\n return path\n .replace(new RegExp(`\\\\{${escapedName}(?::[^{}]+)?\\\\}`, 'g'), () => encoded)\n .replace(new RegExp(`:${escapedName}(?=/|$)`, 'g'), () => encoded)\n}\n\n/** Resolve the runtime plugin API base URL from env, explicit options, platform injection, or contract metadata. */\nexport function resolvePluginBaseUrl(contract: PluginContract, explicitBaseUrl?: string): string {\n const envPrefix = (import.meta.env?.VITE_API_PREFIX as string | undefined) || undefined\n if (envPrefix) return normalizeApiBaseUrl(envPrefix) ?? envPrefix\n if (explicitBaseUrl) return normalizeApiBaseUrl(explicitBaseUrl) ?? explicitBaseUrl\n\n const injected = getInjectedPlatformContext()\n const platformPrefix =\n normalizeApiBaseUrl(injected?.plugin?.api_prefix) ||\n normalizeApiPrefix(injected?.plugin?.route_prefix)\n if (platformPrefix) return platformPrefix\n\n return normalizeApiBaseUrl(contract.plugin.apiPrefix) || '/api'\n}\n\nfunction encodePath(\n path: string,\n payload: Record<string, unknown>,\n pathParams: PluginEndpointParamDefinition[],\n): string {\n let nextPath = path\n for (const param of pathParams) {\n const name = endpointParamName(param)\n const fieldName = endpointParamFieldName(param)\n const value = payload[fieldName] ?? payload[name]\n if (value === undefined || value === null) {\n throw new Error(`[MINT SDK] Missing path parameter '${fieldName}' for plugin endpoint ${path}`)\n }\n const encoded = encodeURIComponent(String(value))\n nextPath = replacePathParam(nextPath, name, encoded)\n if (fieldName !== name) {\n nextPath = replacePathParam(nextPath, fieldName, encoded)\n }\n }\n return nextPath\n}\n\nfunction withDefaultPathParams(\n payload: Record<string, unknown>,\n pathParams: PluginEndpointParamDefinition[],\n): Record<string, unknown> {\n if (!pathParams.length) return payload\n const nextPayload = { ...payload }\n for (const param of pathParams) {\n const name = endpointParamName(param)\n const fieldName = endpointParamFieldName(param)\n if (\n (nextPayload[fieldName] !== undefined && nextPayload[fieldName] !== null)\n || (nextPayload[name] !== undefined && nextPayload[name] !== null)\n ) {\n continue\n }\n if (isExperimentPathParam(fieldName) || isExperimentPathParam(name)) {\n const experimentId = resolveCurrentExperimentId()\n if (experimentId !== undefined) {\n nextPayload[fieldName] = experimentId\n }\n }\n }\n return nextPayload\n}\n\nfunction isExperimentPathParam(param: string): boolean {\n return param === 'experimentId' || param === 'experiment_id'\n}\n\nfunction withoutPathParams(payload: Record<string, unknown>, pathParams: PluginEndpointParamDefinition[]) {\n const copy = { ...payload }\n for (const param of pathParams) {\n delete copy[endpointParamFieldName(param)]\n delete copy[endpointParamName(param)]\n }\n return copy\n}\n\nfunction queryParamsFromPayload(\n payload: Record<string, unknown>,\n pathParams: PluginEndpointParamDefinition[],\n queryParams?: PluginEndpointParamDefinition[],\n endpointPath?: string,\n includeUnspecifiedParams = false,\n) {\n if (!queryParams?.length) {\n return includeUnspecifiedParams ? withoutPathParams(payload, pathParams) : {}\n }\n\n const query: Record<string, unknown> = {}\n for (const param of queryParams) {\n const name = typeof param === 'string' ? param : param.name\n const fieldName = typeof param === 'string' ? param : param.fieldName ?? param.name\n const required = typeof param !== 'string' && param.required === true\n const value = payload[fieldName]\n if (value === undefined || value === null) {\n if (required) {\n throw new Error(\n `[MINT SDK] Missing query parameter '${fieldName}' for plugin endpoint ${endpointPath ?? ''}`,\n )\n }\n continue\n }\n query[name] = value\n }\n return query\n}\n\nexport function hasKeys(value: Record<string, unknown>): boolean {\n return Object.keys(value).length > 0\n}\n\nfunction isPlainPayloadObject(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction hasOwn(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key)\n}\n\nfunction normalizeStructuredEndpointPayload(payload: Record<string, unknown>): Record<string, unknown> {\n const pathParamPayload = payload.pathParams\n const queryPayload = payload.query\n const hasStructuredPathParams = hasOwn(payload, 'pathParams') && isPlainPayloadObject(pathParamPayload)\n const hasStructuredQuery = hasOwn(payload, 'query') && isPlainPayloadObject(queryPayload)\n if (!hasStructuredPathParams && !hasStructuredQuery) return payload\n\n const nextPayload = { ...payload }\n delete nextPayload.pathParams\n delete nextPayload.query\n\n if (hasStructuredPathParams) {\n Object.assign(nextPayload, pathParamPayload)\n }\n if (hasStructuredQuery) {\n Object.assign(nextPayload, queryPayload)\n }\n\n return nextPayload\n}\n\nexport function requestBodyFromPayload(\n payload: unknown,\n requestPayload: Record<string, unknown>,\n endpoint: PluginEndpointDefinition,\n): unknown {\n if (!endpoint.hasBody) return undefined\n const body = endpoint.pathParams?.length || endpoint.queryParams?.length\n ? requestPayload.body\n : payload\n if (body === undefined || body === null) {\n throw new Error(`[MINT SDK] Missing request body for plugin endpoint ${endpoint.path}`)\n }\n return body\n}\n\nexport function pluginEndpointRequestParts(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n explicitBaseUrl?: string,\n) {\n const payloadObject = isPlainPayloadObject(payload)\n ? normalizeStructuredEndpointPayload(payload)\n : {}\n const pathParams = endpoint.pathParams ?? []\n const requestPayload = withDefaultPathParams(payloadObject, pathParams)\n const path = encodePath(endpoint.path, requestPayload, pathParams)\n const query = queryParamsFromPayload(\n requestPayload,\n pathParams,\n endpoint.queryParams,\n endpoint.path,\n endpoint.method === 'get',\n )\n\n return {\n baseUrl: resolvePluginBaseUrl(contract, explicitBaseUrl),\n path,\n query,\n requestPayload,\n }\n}\n\nfunction appendQueryValue(params: URLSearchParams, key: string, value: unknown): void {\n if (value === undefined || value === null) return\n if (Array.isArray(value)) {\n for (const item of value) {\n appendQueryValue(params, key, item)\n }\n return\n }\n if (typeof value === 'object') {\n params.append(key, JSON.stringify(value))\n return\n }\n params.append(key, String(value))\n}\n\nfunction queryString(query: Record<string, unknown>): string {\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n appendQueryValue(params, key, value)\n }\n const serialized = params.toString()\n return serialized ? `?${serialized}` : ''\n}\n\nfunction joinBaseUrl(baseUrl: string, path: string): string {\n if (!baseUrl) return path\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n return `${normalizedBase}${normalizedPath}`\n}\n\n/** Build the concrete URL for a generated plugin endpoint without making a request. */\nexport function buildPluginEndpointUrl(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: BuildPluginEndpointUrlOptions = {},\n): string {\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const pathWithQuery = `${parts.path}${queryString(parts.query)}`\n if (options.includeBaseUrl === false) return pathWithQuery\n return joinBaseUrl(parts.baseUrl, pathWithQuery)\n}\n","import {\n computed,\n onMounted,\n ref,\n shallowRef,\n watch,\n type ComputedRef,\n type Ref,\n} from 'vue'\nimport {\n AuthenticationRequiredError,\n authenticationRequiredError,\n useApi,\n} from './useApi'\nimport { usePlatformContext } from './usePlatformContext'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { useAuthStore } from '../stores/auth'\nimport {\n currentExperimentFromContext,\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\nimport {\n buildPluginEndpointUrl,\n hasKeys,\n pluginEndpointRequestParts,\n requestBodyFromPayload,\n} from './pluginEndpointBuilder'\nimport {\n useEventStream,\n type EventStreamMessage,\n type EventStreamTransport,\n type UseEventStreamReturn,\n} from './useEventStream'\nimport type {\n ExperimentSummary,\n GeneratedJobDefinition,\n PageSelectorItem,\n SettingsModalSchema,\n TopBarSettingsConfig,\n} from '../types'\n\nexport {\n buildPluginEndpointUrl,\n resolvePluginBaseUrl,\n} from './pluginEndpointBuilder'\n\nexport type PluginHttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport interface PluginEndpointContract {\n name: string\n operationId?: string\n method: PluginHttpMethod\n path: string\n requiresAuth?: boolean\n pathParams?: PluginEndpointParamContract[]\n queryParams?: PluginEndpointParamContract[]\n requestType?: string | null\n requestContentType?: string | null\n responseType?: string | null\n responseContentType?: string | null\n eventStream?: boolean\n}\n\nexport interface PluginEndpointParamContract {\n name: string\n fieldName: string\n type?: string\n required?: boolean\n}\n\nexport interface PluginNavItemContract {\n path: string\n label: string\n id?: string\n icon?: string\n description?: string\n requiresAuth?: boolean\n requiresAdmin?: boolean\n requiresFeature?: string\n}\n\nexport interface PluginContractSettings {\n modelName: string | null\n /** Pydantic JSON Schema used to generate typed settings values. */\n valueSchema: Record<string, unknown> | null\n /** SDK SettingsModal schema used to render the settings form. */\n formSchema: SettingsModalSchema | null\n}\n\nexport interface PluginContract {\n schemaVersion: 2\n plugin: {\n name?: string\n packageName?: string\n version?: string\n description?: string\n routesPrefix: string\n apiPrefix: string\n type: 'analysis' | 'experiment-design' | string\n analysisType?: string\n icon?: string\n color?: string\n navItems?: PluginNavItemContract[]\n analysisResultReaders?: string[]\n capabilities?: Record<string, unknown>\n }\n settings: PluginContractSettings\n endpoints: PluginEndpointContract[]\n schemas?: Record<string, Record<string, unknown>>\n jobs?: GeneratedJobDefinition[]\n hash: string\n}\n\nexport interface PluginEndpointDefinition {\n method: PluginHttpMethod\n path: string\n requiresAuth?: boolean\n pathParams?: PluginEndpointParamDefinition[]\n queryParams?: PluginEndpointParamDefinition[]\n hasBody?: boolean\n requestContentType?: string | null\n eventStream?: boolean\n responseType?: string | null\n responseContentType?: string | null\n}\n\nexport type PluginEndpointParamDefinition = string | {\n name: string\n fieldName?: string\n type?: string\n required?: boolean\n}\n\nexport interface CreatePluginClientOptions {\n endpoints: Record<string, PluginEndpointDefinition>\n baseUrl?: string\n}\n\nexport interface BuildPluginEndpointUrlOptions {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Return only the endpoint path and query string instead of base URL + path. */\n includeBaseUrl?: boolean\n}\n\nexport interface PluginEndpointRequestOptions {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Cancel the request without changing its endpoint or authentication behavior. */\n signal?: AbortSignal\n}\n\nexport interface PluginClientRequestOptions {\n /** Cancel the generated endpoint request. */\n signal?: AbortSignal\n}\n\nexport interface DownloadPluginEndpointOptions extends PluginEndpointRequestOptions {\n /** Browser download filename. When omitted, the blob is returned without triggering a download. */\n filename?: string\n /** Delay before revoking the object URL after a browser download is triggered. */\n revokeObjectUrlDelayMs?: number\n}\n\nexport interface DownloadBlobOptions {\n /** Delay before revoking the object URL after a browser download is triggered. */\n revokeObjectUrlDelayMs?: number\n}\n\nexport type PluginSettingsValues<TSettings> = Partial<TSettings> & Record<string, unknown>\n\nexport interface UsePluginSettingsOptions {\n /** Plugin name for platform persistence. Defaults to the integrated platform plugin name. */\n pluginName?: string\n /** Plugin API base URL for standalone/local settings routes. Generated clients pass pluginApiPrefix. */\n apiBaseUrl?: string\n /** Platform API base URL for /plugins/{name}/config. Defaults to the injected platform API URL. */\n platformApiBaseUrl?: string\n /** SettingsModal schema generated from the backend plugin config model. */\n schema?: SettingsModalSchema | null\n /** SettingsModal title when using settingsConfig. */\n title?: string\n /** Whether SettingsModal should include SDK appearance controls. */\n showAppearance?: boolean\n /** Load persisted values on component mount. */\n loadOnMount?: boolean\n}\n\nexport interface UsePluginSettingsReturn<TSettings = Record<string, unknown>> {\n /** Current typed settings values. */\n settings: ComputedRef<PluginSettingsValues<TSettings>>\n /** Editable settings values for SettingsModal. */\n values: Ref<PluginSettingsValues<TSettings>>\n /** Alias for values, kept for callers that think in platform config terms. */\n config: Ref<PluginSettingsValues<TSettings>>\n /** Ready-to-pass AppTopBar/PluginWorkspaceView settingsConfig. */\n settingsConfig: ComputedRef<TopBarSettingsConfig>\n isLoading: Ref<boolean>\n isSaving: Ref<boolean>\n error: Ref<string | null>\n lastLoadedAt: Ref<Date | null>\n lastSavedAt: Ref<Date | null>\n isDirty: ComputedRef<boolean>\n setValues: (values: Record<string, unknown>) => void\n load: () => Promise<void>\n save: (values?: Record<string, unknown>) => Promise<boolean>\n reset: () => void\n}\n\nexport type PluginEventStreamMessage<TData = string> = EventStreamMessage<TData>\n\nexport interface PluginEventStreamOptions<TData = string> {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Start the stream immediately. Defaults to true. */\n immediate?: boolean\n /** Reconnect after errors or server closes. Defaults to true. */\n reconnect?: boolean\n /** Delay before reconnecting after a stream failure or close. Defaults to 2000ms. */\n reconnectDelayMs?: number\n /** Parse `data:` as JSON. Defaults to true for typed endpoints and false otherwise. */\n parseJson?: boolean\n /** Fetch credentials mode. Defaults to same-origin. */\n credentials?: RequestCredentials\n /** Extra request headers. Authorization is injected unless already supplied. */\n headers?: Record<string, string>\n onOpen?: () => void\n onMessage?: (message: PluginEventStreamMessage<TData>) => void\n onError?: (error: unknown) => void\n}\n\nexport type UsePluginEventStreamReturn<TData = string> = UseEventStreamReturn<TData>\n\nexport type PluginFormDataValue =\n | string\n | number\n | boolean\n | Blob\n | null\n | undefined\n | Record<string, unknown>\n\nexport type PluginFormDataPayload = Record<string, PluginFormDataValue | PluginFormDataValue[]>\n\nexport interface UseCurrentExperimentOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseCurrentExperimentReturn<TExperiment = ExperimentSummary> {\n /** Current experiment id resolved from platform injection or URL conventions. */\n experimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasExperiment: ComputedRef<boolean>\n /** Current experiment payload, if injected or successfully fetched. */\n experiment: Ref<TExperiment | undefined>\n /** Whether the current experiment is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed current-experiment fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful current-experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Return the current experiment id or throw a clear SDK error when absent. */\n requireExperimentId: () => number\n /** Fetch a specific experiment id, defaulting to the current experiment id. */\n fetch: (experimentId?: number) => Promise<TExperiment | undefined>\n /** Refetch the currently resolved experiment id. */\n refresh: () => Promise<TExperiment | undefined>\n}\n\nexport type PluginEndpointCaller = (\n payloadOrOptions?: unknown,\n options?: PluginClientRequestOptions,\n) => Promise<unknown>\nexport type GeneratedPluginClient = Record<string, (...args: any[]) => Promise<any>>\n\nfunction queryConfig(query: Record<string, unknown>) {\n return hasKeys(query) ? { params: query } : undefined\n}\n\nconst OCTET_STREAM = 'application/octet-stream'\nconst MULTIPART_FORM_DATA = 'multipart/form-data'\n\nfunction endpointRequestConfig(\n endpoint: PluginEndpointDefinition,\n query: Record<string, unknown>,\n options?: PluginClientRequestOptions,\n) {\n const config: Record<string, unknown> = {}\n if (hasKeys(query)) config.params = query\n if (endpoint.requestContentType === OCTET_STREAM) {\n config.headers = { 'Content-Type': OCTET_STREAM }\n }\n if (endpoint.requestContentType === MULTIPART_FORM_DATA) {\n config.headers = { 'Content-Type': undefined }\n }\n if (endpoint.responseContentType === OCTET_STREAM) {\n config.responseType = 'blob'\n }\n if (options?.signal) config.signal = options.signal\n return hasKeys(config) ? config : undefined\n}\n\nfunction isFormData(value: unknown): value is FormData {\n return typeof FormData !== 'undefined' && value instanceof FormData\n}\n\nfunction endpointRequestBody(endpoint: PluginEndpointDefinition, body: unknown): unknown {\n return endpoint.requestContentType === MULTIPART_FORM_DATA\n ? pluginFormDataFromPayload(body)\n : body\n}\n\nfunction endpointHasPayload(endpoint: PluginEndpointDefinition): boolean {\n return Boolean(\n endpoint.hasBody\n || endpoint.pathParams?.length\n || endpoint.queryParams?.length,\n )\n}\n\nfunction isBlob(value: unknown): value is Blob {\n return typeof Blob !== 'undefined' && value instanceof Blob\n}\n\nfunction appendFormDataValue(formData: FormData, key: string, value: PluginFormDataValue | PluginFormDataValue[]): void {\n if (value === undefined || value === null) return\n\n if (Array.isArray(value)) {\n for (const item of value) {\n appendFormDataValue(formData, key, item)\n }\n return\n }\n\n if (isBlob(value)) {\n formData.append(key, value)\n return\n }\n\n if (typeof value === 'object') {\n formData.append(key, JSON.stringify(value))\n return\n }\n\n formData.append(key, String(value))\n}\n\n/** Convert plain upload payloads into FormData using the same encoding across generated plugin clients. */\nexport function pluginFormDataFromPayload(payload: unknown): FormData {\n if (isFormData(payload)) return payload\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n throw new Error('[MINT SDK] Plugin upload endpoints require a FormData or plain object payload.')\n }\n\n const formData = new FormData()\n for (const [key, value] of Object.entries(payload as PluginFormDataPayload)) {\n appendFormDataValue(formData, key, value)\n }\n return formData\n}\n\n/** Trigger a browser download for an already-created Blob. */\nexport function downloadBlob(blob: Blob, filename: string, options: DownloadBlobOptions = {}): void {\n if (typeof document === 'undefined' || typeof URL === 'undefined') {\n throw new Error('[MINT SDK] Cannot trigger a file download outside a browser.')\n }\n\n const blobUrl = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n setTimeout(() => URL.revokeObjectURL(blobUrl), options.revokeObjectUrlDelayMs ?? 100)\n}\n\nfunction normalizePluginNavPath(path: string): string {\n const raw = path.trim() || '/'\n const prefixed = raw.startsWith('/') ? raw : `/${raw}`\n return prefixed.replace(/\\/+$/, '') || '/'\n}\n\nfunction pluginPageIdFromPath(path: string, fallbackIndex: number): string {\n const normalizedPath = normalizePluginNavPath(path)\n if (normalizedPath === '/') return 'dashboard'\n return normalizedPath.replace(/^\\/+/, '').replace(/\\/+/g, '-') || `page-${fallbackIndex + 1}`\n}\n\n/** Convert resolved @mint_plugin nav_items into page selectors for the topbar and homepage PluginCards. */\nexport function getPluginPageSelectorItems(contract: PluginContract): PageSelectorItem[] {\n const pluginIcon = contract.plugin.icon ?? ''\n const navItems = contract.plugin.navItems ?? []\n return navItems.map((item, index) => ({\n id: item.id || pluginPageIdFromPath(item.path, index),\n label: item.label,\n to: normalizePluginNavPath(item.path),\n icon: item.icon || pluginIcon || undefined,\n }))\n}\n\n/** Create a typed plugin API client from a generated MINT plugin contract. */\nexport function createPluginClient<TClient extends object = GeneratedPluginClient>(\n contract: PluginContract,\n options: CreatePluginClientOptions,\n): TClient {\n const client: Record<string, PluginEndpointCaller> = {}\n\n for (const [name, endpoint] of Object.entries(options.endpoints)) {\n client[name] = async (\n payloadOrOptions?: unknown,\n explicitOptions?: PluginClientRequestOptions,\n ) => {\n const hasPayload = endpointHasPayload(endpoint)\n const payload = hasPayload ? payloadOrOptions : undefined\n const callOptions = hasPayload\n ? explicitOptions\n : (payloadOrOptions as PluginClientRequestOptions | undefined) ?? explicitOptions\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({\n baseUrl: parts.baseUrl,\n withAuth: endpoint.requiresAuth !== false,\n })\n const config = endpointRequestConfig(endpoint, parts.query, callOptions)\n\n if (endpoint.method === 'get') {\n return api.get(parts.path, config)\n }\n\n if (endpoint.method === 'delete') {\n const rawBody = requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n const body = rawBody === undefined ? undefined : endpointRequestBody(endpoint, rawBody)\n const config = body === undefined\n ? endpointRequestConfig(endpoint, parts.query, callOptions)\n : { ...endpointRequestConfig(endpoint, parts.query, callOptions), data: body }\n return api.delete(parts.path, config)\n }\n\n const body = endpointRequestBody(\n endpoint,\n requestBodyFromPayload(payload, parts.requestPayload, endpoint),\n )\n\n if (endpoint.method === 'post') return api.post(parts.path, body, config)\n if (endpoint.method === 'put') return api.put(parts.path, body, config)\n if (endpoint.method === 'patch') return api.patch(parts.path, body, config)\n throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`)\n }\n }\n\n return client as TClient\n}\n\n/** Send multipart or raw binary data to a generated endpoint with contract URL, cancellation, and auth handling. */\nexport async function uploadPluginEndpoint<TResponse = unknown>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: PluginEndpointRequestOptions = {},\n): Promise<TResponse> {\n if (!['post', 'put', 'patch'].includes(endpoint.method)) {\n throw new Error(`[MINT SDK] Plugin upload endpoints must use POST, PUT, or PATCH; got ${endpoint.method}`)\n }\n\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({\n baseUrl: parts.baseUrl,\n withAuth: endpoint.requiresAuth !== false,\n })\n const body = endpoint.hasBody\n ? requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n : payload\n if (endpoint.requestContentType === OCTET_STREAM) {\n const config = endpointRequestConfig(endpoint, parts.query, { signal: options.signal })\n if (endpoint.method === 'post') return api.post<TResponse>(parts.path, body, config)\n if (endpoint.method === 'put') return api.put<TResponse>(parts.path, body, config)\n return api.patch<TResponse>(parts.path, body, config)\n }\n const formData = pluginFormDataFromPayload(body)\n const config = {\n ...(queryConfig(parts.query) ?? {}),\n ...(options.signal ? { signal: options.signal } : {}),\n // Let Axios/browser set multipart boundaries.\n headers: { 'Content-Type': undefined },\n }\n\n if (endpoint.method === 'post') return api.post<TResponse>(parts.path, formData, config)\n if (endpoint.method === 'put') return api.put<TResponse>(parts.path, formData, config)\n return api.patch<TResponse>(parts.path, formData, config)\n}\n\n/** Fetch a generated plugin endpoint as a Blob and optionally trigger a browser download. */\nexport async function downloadPluginEndpoint(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: DownloadPluginEndpointOptions = {},\n): Promise<Blob> {\n if (endpoint.requestContentType === MULTIPART_FORM_DATA) {\n throw new Error('[MINT SDK] Plugin download endpoints do not support multipart request bodies')\n }\n\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({\n baseUrl: parts.baseUrl,\n withAuth: endpoint.requiresAuth !== false,\n })\n const config = {\n ...(endpointRequestConfig(endpoint, parts.query, { signal: options.signal }) ?? {}),\n responseType: 'blob' as const,\n }\n const rawBody = requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n const body = rawBody === undefined ? undefined : endpointRequestBody(endpoint, rawBody)\n let blob: Blob\n\n if (endpoint.method === 'get') blob = await api.get<Blob>(parts.path, config)\n else if (endpoint.method === 'post') blob = await api.post<Blob>(parts.path, body, config)\n else if (endpoint.method === 'put') blob = await api.put<Blob>(parts.path, body, config)\n else if (endpoint.method === 'patch') blob = await api.patch<Blob>(parts.path, body, config)\n else if (endpoint.method === 'delete') {\n blob = await api.delete<Blob>(parts.path, body === undefined ? config : { ...config, data: body })\n } else {\n throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`)\n }\n\n if (options.filename) {\n downloadBlob(blob, options.filename, {\n revokeObjectUrlDelayMs: options.revokeObjectUrlDelayMs,\n })\n }\n\n return blob\n}\n\nfunction normalizePluginSettingsOptions(options: UsePluginSettingsOptions | string = {}): UsePluginSettingsOptions {\n return typeof options === 'string' ? { pluginName: options } : options\n}\n\nconst PLATFORM_OWNED_SETTINGS_KEY = 'allowed_experiment_types'\n\nfunction cloneRecord(value: Record<string, unknown>): Record<string, unknown> {\n return JSON.parse(JSON.stringify(value)) as Record<string, unknown>\n}\n\nfunction hasOwnSetting(settings: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(settings, key)\n}\n\nfunction responseSettingsPayload(response: unknown): Record<string, unknown> {\n if (!response || typeof response !== 'object') return {}\n const data = response as {\n config?: unknown\n settings?: unknown\n }\n if (data.config && typeof data.config === 'object') {\n return cloneRecord(data.config as Record<string, unknown>)\n }\n if (data.settings && typeof data.settings === 'object') {\n return cloneRecord(data.settings as Record<string, unknown>)\n }\n return {}\n}\n\nfunction responseSettingsRevision(response: unknown): string | null {\n if (!response || typeof response !== 'object') return null\n const revision = (response as { revision?: unknown }).revision\n return typeof revision === 'string' && revision ? revision : null\n}\n\nfunction topLevelSettingsPatch(\n current: Record<string, unknown>,\n keys: Iterable<string>,\n): Record<string, unknown> {\n return Object.fromEntries(\n [...keys].map(key => [\n key,\n hasOwnSetting(current, key) ? current[key] : null,\n ]),\n )\n}\n\nfunction changedTopLevelSettingKeys(\n current: Record<string, unknown>,\n saved: Record<string, unknown>,\n): Set<string> {\n return new Set(\n [...new Set([...Object.keys(current), ...Object.keys(saved)])].filter(\n key => JSON.stringify(current[key]) !== JSON.stringify(saved[key]),\n ),\n )\n}\n\nfunction platformOwnedSettingsPatch(settings: Record<string, unknown>): Record<string, unknown> {\n return {\n [PLATFORM_OWNED_SETTINGS_KEY]: hasOwnSetting(settings, PLATFORM_OWNED_SETTINGS_KEY)\n ? settings[PLATFORM_OWNED_SETTINGS_KEY]\n : null,\n }\n}\n\n/** Load, edit, and persist plugin settings from platform config or the plugin-local settings router. */\nexport function usePluginSettings<TSettings = Record<string, unknown>>(\n options: UsePluginSettingsOptions | string = {},\n): UsePluginSettingsReturn<TSettings> {\n const resolvedOptions = normalizePluginSettingsOptions(options)\n const injectedContext = getInjectedPlatformContext()\n const { plugin, isIntegrated } = usePlatformContext()\n const platformApi = useApi({ baseUrl: resolvedOptions.platformApiBaseUrl ?? injectedContext?.platformApiUrl })\n const pluginApi = useApi({ baseUrl: resolvedOptions.apiBaseUrl ?? injectedContext?.plugin?.api_prefix })\n\n const values = ref({}) as Ref<PluginSettingsValues<TSettings>>\n const savedValues = shallowRef<Record<string, unknown>>({})\n const revision = ref<string | null>(null)\n const request = useRequestSyncState('Plugin settings request failed.')\n const isLoading = ref(false)\n const isSaving = ref(false)\n\n const resolvedPluginName = computed(() =>\n resolvedOptions.pluginName ?? plugin.value?.name ?? injectedContext?.plugin?.name ?? '',\n )\n const usesPluginSettingsApi = computed(() => {\n const currentPlugin = injectedContext?.plugin ?? plugin.value\n return currentPlugin?.settings_api === 'plugin'\n && resolvedPluginName.value === currentPlugin.name\n })\n const usesPlatformConfig = computed(() =>\n Boolean(\n (isIntegrated.value || injectedContext?.isIntegrated)\n && resolvedPluginName.value\n && !usesPluginSettingsApi.value,\n ),\n )\n const settings = computed(() => values.value)\n const isDirty = computed(() => JSON.stringify(values.value) !== JSON.stringify(savedValues.value))\n const settingsConfig = computed<TopBarSettingsConfig>(() => ({\n title: resolvedOptions.title,\n schema: resolvedOptions.schema ?? undefined,\n showAppearance: resolvedOptions.showAppearance,\n values: values.value,\n }))\n\n function setValues(nextValues: Record<string, unknown>): void {\n values.value = cloneRecord(nextValues) as PluginSettingsValues<TSettings>\n }\n\n function applyLoaded(nextValues: Record<string, unknown>, nextRevision: string | null): void {\n const cloned = cloneRecord(nextValues)\n values.value = cloned as PluginSettingsValues<TSettings>\n savedValues.value = cloneRecord(cloned)\n revision.value = nextRevision\n }\n\n async function load(): Promise<void> {\n isLoading.value = true\n try {\n const response = usesPlatformConfig.value\n ? await request.run(\n () => platformApi.get<{ plugin_name: string; config: Record<string, unknown> }>(\n `/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`,\n ),\n { success: 'load', errorMessage: 'Failed to load plugin settings' },\n )\n : await request.run(\n () => pluginApi.get<{ settings: Record<string, unknown>; mode?: string }>('/settings'),\n { success: 'load', errorMessage: 'Failed to load plugin settings' },\n )\n applyLoaded(\n responseSettingsPayload(response),\n responseSettingsRevision(response),\n )\n } catch {\n // Error state is handled by request.run().\n } finally {\n isLoading.value = false\n }\n }\n\n async function save(nextValues?: Record<string, unknown>): Promise<boolean> {\n if (nextValues) {\n setValues(nextValues)\n }\n\n isSaving.value = true\n try {\n const payload = cloneRecord(values.value)\n let response: unknown\n if (usesPlatformConfig.value) {\n const dirtyKeys = changedTopLevelSettingKeys(payload, savedValues.value)\n const platformOwnedChanged = dirtyKeys.has(PLATFORM_OWNED_SETTINGS_KEY)\n const typedKeys = [...dirtyKeys].filter(\n key => key !== PLATFORM_OWNED_SETTINGS_KEY,\n )\n let nextRevision = revision.value\n\n if (typedKeys.length) {\n response = await request.run(\n () => platformApi.patch<{\n plugin_name: string\n config: Record<string, unknown>\n revision?: string\n }>(\n `/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`,\n { config: topLevelSettingsPatch(payload, typedKeys) },\n ),\n { success: 'save', errorMessage: 'Failed to save plugin settings' },\n )\n nextRevision = responseSettingsRevision(response) ?? nextRevision\n }\n\n if (platformOwnedChanged) {\n response = await request.run(\n () => platformApi.patch<{\n plugin_name: string\n config: Record<string, unknown>\n revision?: string\n }>(\n `/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`,\n { config: platformOwnedSettingsPatch(payload) },\n ),\n { success: 'save', errorMessage: 'Failed to save plugin settings' },\n )\n nextRevision = responseSettingsRevision(response) ?? nextRevision\n }\n\n if (!response) return true\n applyLoaded(responseSettingsPayload(response), nextRevision)\n return true\n } else {\n const ifMatch = revision.value\n ? { headers: { 'If-Match': `\"${revision.value}\"` } }\n : undefined\n response = await request.run(\n () => pluginApi.put<{\n settings: Record<string, unknown>\n mode?: string\n revision?: string\n }>('/settings', payload, ifMatch),\n { success: 'save', errorMessage: 'Failed to save plugin settings' },\n )\n }\n applyLoaded(\n responseSettingsPayload(response),\n responseSettingsRevision(response) ?? revision.value,\n )\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n function reset(): void {\n values.value = cloneRecord(savedValues.value) as PluginSettingsValues<TSettings>\n request.clearError()\n }\n\n onMounted(() => {\n if (resolvedOptions.loadOnMount !== false) {\n void load()\n }\n })\n\n return {\n settings,\n values,\n config: values,\n settingsConfig,\n isLoading,\n isSaving,\n error: request.error,\n lastLoadedAt: request.lastLoadedAt,\n lastSavedAt: request.lastSavedAt,\n isDirty,\n setValues,\n load,\n save,\n reset,\n }\n}\n\nfunction streamRequestAuth(\n requestHeaders: HeadersInit | undefined,\n policy: { requiresAuth: boolean },\n): {\n headers: Headers\n token?: string\n} {\n const headers = new Headers(requestHeaders)\n const authStore = useAuthStore()\n if (!authStore.isInitialized) {\n authStore.initialize()\n }\n if (policy.requiresAuth && authStore.token && !headers.has('Authorization')) {\n headers.set('Authorization', `Bearer ${authStore.token}`)\n }\n const token = policy.requiresAuth ? authStore.token : undefined\n return {\n headers,\n token: token && headers.get('Authorization') === `Bearer ${token}` ? token : undefined,\n }\n}\n\nfunction pluginEventStreamTransport(\n endpoint: PluginEndpointDefinition,\n): EventStreamTransport {\n return async (url, init = {}) => {\n if (typeof fetch !== 'function') {\n throw new Error('[MINT SDK] fetch is required for plugin event streams.')\n }\n const requestAuth = streamRequestAuth(\n init.headers,\n { requiresAuth: endpoint.requiresAuth !== false },\n )\n const response = await fetch(url, { ...init, headers: requestAuth.headers })\n if (response.status === 401) {\n throw authenticationRequiredError(response, requestAuth.token)\n }\n return response\n }\n}\n\nfunction looksLikeEventStreamOptions(value: unknown): value is PluginEventStreamOptions {\n if (!value || typeof value !== 'object') return false\n const candidate = value as Record<string, unknown>\n return [\n 'baseUrl',\n 'immediate',\n 'reconnect',\n 'reconnectDelayMs',\n 'parseJson',\n 'credentials',\n 'headers',\n 'onOpen',\n 'onMessage',\n 'onError',\n ].some(key => key in candidate)\n}\n\n/** Consume a generated plugin SSE endpoint with auth headers, reconnect, and teardown. */\nexport function usePluginEventStream<TData = string>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n options?: PluginEventStreamOptions<TData>,\n): UsePluginEventStreamReturn<TData>\nexport function usePluginEventStream<TData = string>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options?: PluginEventStreamOptions<TData>,\n): UsePluginEventStreamReturn<TData>\nexport function usePluginEventStream<TData = string>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payloadOrOptions?: unknown,\n maybeOptions?: PluginEventStreamOptions<TData>,\n): UsePluginEventStreamReturn<TData> {\n if (endpoint.method !== 'get') {\n throw new Error(`[MINT SDK] Plugin event streams must use GET; got ${endpoint.method}`)\n }\n const payload = maybeOptions === undefined && looksLikeEventStreamOptions(payloadOrOptions)\n ? undefined\n : payloadOrOptions\n const options = (\n maybeOptions === undefined && looksLikeEventStreamOptions(payloadOrOptions)\n ? payloadOrOptions\n : maybeOptions ?? {}\n ) as PluginEventStreamOptions<TData>\n const responseType = endpoint.responseType?.trim()\n const parseJson = options.parseJson ?? Boolean(responseType && responseType !== 'string')\n return useEventStream<TData>(\n () => buildPluginEndpointUrl(contract, endpoint, payload, { baseUrl: options.baseUrl }),\n {\n transport: pluginEventStreamTransport(endpoint),\n immediate: options.immediate,\n reconnect: options.reconnect,\n reconnectDelayMs: options.reconnectDelayMs,\n parseJson,\n credentials: options.credentials,\n headers: options.headers,\n shouldReconnect: cause => !(cause instanceof AuthenticationRequiredError),\n onOpen: options.onOpen,\n onMessage: options.onMessage,\n onError: options.onError,\n errorLabel: 'Plugin event stream',\n },\n )\n}\n\n/** Read and optionally load the current platform experiment for integrated plugin views. */\nexport function useCurrentExperiment<TExperiment = ExperimentSummary>(\n options: UseCurrentExperimentOptions = {},\n): UseCurrentExperimentReturn<TExperiment> {\n const api = useApi({ baseUrl: options.apiBaseUrl ?? getInjectedPlatformContext()?.platformApiUrl })\n const experiment = shallowRef<TExperiment | undefined>(currentExperimentFromContext<TExperiment>())\n const request = useRequestSyncState('Failed to load current experiment')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n\n const experimentId = computed<number | undefined>(() => {\n return resolveCurrentExperimentId()\n })\n const hasExperiment = computed(() => experimentId.value !== undefined)\n\n function requireExperimentId(): number {\n const id = experimentId.value\n if (id === undefined) {\n throw new Error('[MINT SDK] No current experiment is selected.')\n }\n return id\n }\n\n async function fetchExperiment(id = experimentId.value): Promise<TExperiment | undefined> {\n if (id === undefined) {\n experiment.value = currentExperimentFromContext<TExperiment>()\n return experiment.value\n }\n\n try {\n const result = await request.run(\n () => api.get<TExperiment>(`/experiments/${id}`),\n { success: 'load', errorMessage: 'Failed to load current experiment' },\n )\n experiment.value = result\n return result\n } catch (e) {\n experiment.value = undefined\n return undefined\n }\n }\n\n async function refresh(): Promise<TExperiment | undefined> {\n return fetchExperiment()\n }\n\n watch(\n experimentId,\n (id) => {\n if (options.immediate === false) return\n if (id === undefined) {\n experiment.value = currentExperimentFromContext<TExperiment>()\n return\n }\n void fetchExperiment(id)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n hasExperiment,\n experiment,\n isLoading,\n error,\n lastLoadedAt,\n requireExperimentId,\n fetch: fetchExperiment,\n refresh,\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"experiment-Cq145oEW.js","names":[],"sources":["../src/stores/experiment.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { useApi } from '../composables/useApi'\nimport type { ExperimentSummary, PlatformContext } from '../types'\n\nfunction getPlatformApiUrl(): string | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n ?.platformApiUrl\n}\n\nfunction readErrorMessage(value: unknown): string {\n if (value instanceof Error && value.message) return value.message\n if (typeof value === 'string' && value.trim()) return value\n return 'Failed to load experiment'\n}\n\n/**\n * The single source of truth for the experiment a plugin is currently working on.\n *\n * Both entry points land here: `ExperimentSelectorModal` calls `select()` with a\n * record the platform already returned, and deep links call `selectById()` with\n * nothing but an id. Because a name can only ever arrive from the platform,\n * there is no code path in which a caller can invent one.\n */\nexport const useExperimentStore = defineStore('mint-experiment', () => {\n const current = ref<ExperimentSummary | null>(null)\n const currentId = ref<number | null>(null)\n const isResolving = ref(false)\n const error = ref<string | null>(null)\n\n // In-flight requests only. Resolved records are deliberately not memoised, so\n // a rename is picked up on the next resolve instead of persisting for the\n // lifetime of the page.\n const inFlight = new Map<number, Promise<ExperimentSummary>>()\n\n // Monotonic token guarding every write to the shared selection. Responses can\n // land in any order, and a late one must never overwrite a newer choice —\n // that would display a name belonging to a different experiment, which is the\n // failure this store exists to prevent.\n let selectionToken = 0\n\n function fetchExperiment(id: number): Promise<ExperimentSummary> {\n const pending = inFlight.get(id)\n if (pending) return pending\n\n const base = getPlatformApiUrl() ?? ''\n const request = useApi()\n .get<ExperimentSummary>(`${base}/experiments/${id}`)\n .finally(() => {\n inFlight.delete(id)\n })\n\n inFlight.set(id, request)\n return request\n }\n\n /** Adopt a record the platform already returned, without a further request. */\n function select(experiment: ExperimentSummary): void {\n selectionToken += 1\n current.value = experiment\n currentId.value = experiment.id\n error.value = null\n isResolving.value = false\n }\n\n /**\n * Bind to an experiment known only by id, resolving its record from the\n * platform. On failure the binding is remembered but `current` stays null, so\n * callers can distinguish \"not resolved yet\" from \"nothing selected\".\n */\n async function selectById(id: number): Promise<ExperimentSummary | null> {\n const joinsCurrentResolution = isResolving.value && currentId.value === id\n const token = joinsCurrentResolution ? selectionToken : (selectionToken += 1)\n if (!joinsCurrentResolution) {\n current.value = null\n currentId.value = id\n error.value = null\n isResolving.value = true\n }\n try {\n const experiment = await fetchExperiment(id)\n // A newer selection superseded this one while the request was in flight.\n // Returning null tells the caller its result is no longer the selection,\n // so it cannot be applied downstream either.\n if (token !== selectionToken) return null\n current.value = experiment\n return experiment\n } catch (err) {\n if (token !== selectionToken) return null\n current.value = null\n error.value = readErrorMessage(err)\n return null\n } finally {\n // Only the newest request owns the loading flag; otherwise a superseded\n // response would clear it while the current one is still pending.\n if (token === selectionToken) isResolving.value = false\n }\n }\n\n function clear(): void {\n // Supersede any in-flight resolve so a detached experiment cannot be\n // repopulated by a response that was already on its way.\n selectionToken += 1\n current.value = null\n currentId.value = null\n error.value = null\n isResolving.value = false\n }\n\n return {\n current,\n currentId,\n isResolving,\n error,\n select,\n selectById,\n clear,\n }\n})\n"],"mappings":";;;;AAKA,SAAS,oBAAwC;AAC/C,KAAI,OAAO,WAAW,YAAa,QAAO,KAAA;AAC1C,QAAQ,OAA8D,mBAClE;;AAGN,SAAS,iBAAiB,OAAwB;AAChD,KAAI,iBAAiB,SAAS,MAAM,QAAS,QAAO,MAAM;AAC1D,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAE,QAAO;AACtD,QAAO;;;;;;;;;;AAWT,IAAa,qBAAqB,YAAY,yBAAyB;CACrE,MAAM,UAAU,IAA8B,KAAK;CACnD,MAAM,YAAY,IAAmB,KAAK;CAC1C,MAAM,cAAc,IAAI,MAAM;CAC9B,MAAM,QAAQ,IAAmB,KAAK;CAKtC,MAAM,2BAAW,IAAI,KAAyC;CAM9D,IAAI,iBAAiB;CAErB,SAAS,gBAAgB,IAAwC;EAC/D,MAAM,UAAU,SAAS,IAAI,GAAG;AAChC,MAAI,QAAS,QAAO;EAEpB,MAAM,OAAO,mBAAmB,IAAI;EACpC,MAAM,UAAU,QAAQ,CACrB,IAAuB,GAAG,KAAK,eAAe,KAAK,CACnD,cAAc;AACb,YAAS,OAAO,GAAG;IACnB;AAEJ,WAAS,IAAI,IAAI,QAAQ;AACzB,SAAO;;;CAIT,SAAS,OAAO,YAAqC;AACnD,oBAAkB;AAClB,UAAQ,QAAQ;AAChB,YAAU,QAAQ,WAAW;AAC7B,QAAM,QAAQ;AACd,cAAY,QAAQ;;;;;;;CAQtB,eAAe,WAAW,IAA+C;EACvE,MAAM,yBAAyB,YAAY,SAAS,UAAU,UAAU;EACxE,MAAM,QAAQ,yBAAyB,iBAAkB,kBAAkB;AAC3E,MAAI,CAAC,wBAAwB;AAC3B,WAAQ,QAAQ;AAChB,aAAU,QAAQ;AAClB,SAAM,QAAQ;AACd,eAAY,QAAQ;;AAEtB,MAAI;GACF,MAAM,aAAa,MAAM,gBAAgB,GAAG;AAI5C,OAAI,UAAU,eAAgB,QAAO;AACrC,WAAQ,QAAQ;AAChB,UAAO;WACA,KAAK;AACZ,OAAI,UAAU,eAAgB,QAAO;AACrC,WAAQ,QAAQ;AAChB,SAAM,QAAQ,iBAAiB,IAAI;AACnC,UAAO;YACC;AAGR,OAAI,UAAU,eAAgB,aAAY,QAAQ;;;CAItD,SAAS,QAAc;AAGrB,oBAAkB;AAClB,UAAQ,QAAQ;AAChB,YAAU,QAAQ;AAClB,QAAM,QAAQ;AACd,cAAY,QAAQ;;AAGtB,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD;EACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"experiment-utils-CLnzPPq5.js","names":["$slots"],"sources":["../src/components/BaseButton.vue","../src/components/BaseButton.vue","../src/composables/useEventListener.ts","../src/components/BaseModal.vue","../src/components/BaseModal.vue","../src/composables/experiment-utils.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/** Renders a styled `<button>` with variant, size, loading spinner, and full-width options. */\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :class=\"[\n 'mint-button',\n `mint-button--${variant}`,\n `mint-button--${size}`,\n fullWidth ? 'mint-button--full-width' : '',\n (disabled || loading) ? 'mint-button--disabled' : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n class=\"mint-button__spinner\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </button>\n</template>\n\n<style>\n@import '../styles/components/button.css';\n</style>\n","<script setup lang=\"ts\">\n/** Renders a styled `<button>` with variant, size, loading spinner, and full-width options. */\nimport type { ButtonVariant, ButtonSize } from '../types'\n\ninterface Props {\n variant?: ButtonVariant\n size?: ButtonSize\n disabled?: boolean\n loading?: boolean\n type?: 'button' | 'submit' | 'reset'\n fullWidth?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'primary',\n size: 'md',\n disabled: false,\n loading: false,\n type: 'button',\n fullWidth: false,\n})\n\nconst emit = defineEmits<{\n click: [event: MouseEvent]\n}>()\n\nfunction handleClick(event: MouseEvent) {\n if (!props.disabled && !props.loading) {\n emit('click', event)\n }\n}\n</script>\n\n<template>\n <button\n :type=\"type\"\n :disabled=\"disabled || loading\"\n :class=\"[\n 'mint-button',\n `mint-button--${variant}`,\n `mint-button--${size}`,\n fullWidth ? 'mint-button--full-width' : '',\n (disabled || loading) ? 'mint-button--disabled' : '',\n ]\"\n @click=\"handleClick\"\n >\n <svg\n v-if=\"loading\"\n class=\"mint-button__spinner\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n style=\"opacity: 0.25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n />\n <path\n style=\"opacity: 0.75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n <slot name=\"icon-left\" />\n <slot />\n <slot name=\"icon-right\" />\n </button>\n</template>\n\n<style>\n@import '../styles/components/button.css';\n</style>\n","import { isRef, onMounted, onUnmounted, watch, type Ref } from 'vue'\n\nexport type EventTargetGetter<TTarget extends EventTarget = EventTarget> =\n () => TTarget | null | undefined\n\nexport type EventTargetLike<TTarget extends EventTarget = EventTarget> =\n | TTarget\n | Ref<TTarget | null | undefined>\n | EventTargetGetter<TTarget>\n | null\n | undefined\n\nexport type EventListenerEnabled = boolean | Ref<boolean>\n\nexport interface UseEventListenerObjectOptions extends AddEventListenerOptions {\n enabled?: EventListenerEnabled\n}\n\nexport type UseEventListenerOptions = boolean | UseEventListenerObjectOptions\nexport type EventListenerStop = () => void\n\nexport type EventMapFor<TTarget extends EventTarget> =\n TTarget extends Window\n ? WindowEventMap\n : TTarget extends Document\n ? DocumentEventMap\n : TTarget extends HTMLElement\n ? HTMLElementEventMap\n : Record<string, Event>\n\nexport type EventFor<\n TTarget extends EventTarget,\n TType extends string,\n> = TType extends keyof EventMapFor<TTarget>\n ? EventMapFor<TTarget>[TType]\n : Event\n\n/** Bind a DOM event listener on mount, remove it on unmount, and rebind when a ref target changes. */\nexport function useEventListener<\n TTarget extends EventTarget = EventTarget,\n TType extends string = string,\n>(\n target: EventTargetLike<TTarget>,\n type: TType,\n listener: (event: EventFor<TTarget, TType>) => void,\n options?: UseEventListenerOptions,\n): EventListenerStop {\n let stopCurrent: EventListenerStop | undefined\n let mounted = false\n\n function stop(): void {\n stopCurrent?.()\n stopCurrent = undefined\n }\n\n function start(): void {\n stop()\n if (!mounted || !isEnabled(options)) return\n const resolvedTarget = resolveEventTarget(target)\n if (!resolvedTarget) return\n\n const eventListener = listener as EventListener\n const eventOptions = getEventOptions(options)\n resolvedTarget.addEventListener(type, eventListener, eventOptions)\n stopCurrent = () => {\n resolvedTarget.removeEventListener(type, eventListener, eventOptions)\n }\n }\n\n onMounted(() => {\n mounted = true\n start()\n })\n\n if (isRef(target)) {\n watch(target, start, { flush: 'post' })\n }\n const enabled = getEnabledOption(options)\n if (isRef(enabled)) {\n watch(enabled, start, { flush: 'post' })\n }\n\n onUnmounted(() => {\n mounted = false\n stop()\n })\n\n return stop\n}\n\nfunction resolveEventTarget(target: EventTargetLike): EventTarget | null | undefined {\n if (isRef(target)) return target.value\n if (typeof target === 'function') return target()\n return target\n}\n\nfunction getEnabledOption(options: UseEventListenerOptions | undefined): EventListenerEnabled | undefined {\n return typeof options === 'object' ? options.enabled : undefined\n}\n\nfunction isEnabled(options: UseEventListenerOptions | undefined): boolean {\n const enabled = getEnabledOption(options)\n if (isRef(enabled)) return enabled.value\n return enabled ?? true\n}\n\nfunction getEventOptions(options: UseEventListenerOptions | undefined): boolean | AddEventListenerOptions | undefined {\n if (typeof options !== 'object') return options\n const { enabled: _enabled, ...eventOptions } = options\n return eventOptions\n}\n","<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant/layout. */\nimport { computed, ref, watch, nextTick, onUnmounted, type ComponentPublicInstance } from 'vue'\nimport type { ModalLayout, ModalSize, ModalTab, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\n\ninterface Props {\n modelValue: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n /**\n * Shell layout. 'tabs' renders a tab strip between header and body;\n * 'rail' renders a sidebar rail + pane as the shell's middle row.\n * Both are shell regions — never part of the scrolling body content.\n */\n layout?: ModalLayout\n /** Sections for the tab strip / rail. The strip renders only with 2+ tabs. */\n tabs?: ModalTab[]\n /** Id of the selected tab. Two-way bindable via update:activeTab. */\n activeTab?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n layout: 'plain',\n tabs: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n 'update:activeTab': [id: string]\n close: []\n}>()\n\nconst activeTabMeta = computed(() => props.tabs.find((tab) => tab.id === props.activeTab))\n\nconst tabButtonRefs = new Map<string, HTMLElement>()\n\nfunction setTabButtonRef(id: string, el: Element | ComponentPublicInstance | null) {\n if (el instanceof HTMLElement) {\n tabButtonRefs.set(id, el)\n } else {\n tabButtonRefs.delete(id)\n }\n}\n\nfunction selectTab(tab: ModalTab) {\n if (tab.disabled || tab.id === props.activeTab) return\n emit('update:activeTab', tab.id)\n}\n\n/** ARIA tablist keyboard contract: arrows move selection to the next non-disabled tab, wrapping. */\nfunction focusTab(delta: number) {\n const enabled = props.tabs.filter((tab) => !tab.disabled)\n if (enabled.length === 0) return\n const currentIndex = enabled.findIndex((tab) => tab.id === props.activeTab)\n const next = enabled[(currentIndex + delta + enabled.length) % enabled.length]\n if (!next || next.id === props.activeTab) return\n emit('update:activeTab', next.id)\n tabButtonRefs.get(next.id)?.focus()\n}\n\nfunction isPathIcon(icon: ModalTab['icon']): icon is string | string[] {\n if (!icon) return false\n return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')\n}\n\nconst containerRef = ref<HTMLElement | null>(null)\nlet previouslyFocused: HTMLElement | null = null\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\nfunction getFocusableElements(): HTMLElement[] {\n if (!containerRef.value) return []\n return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n // Roving tabindex (inactive tabs/rail items) stays out of the Tab cycle.\n .filter((el) => el.tabIndex !== -1)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.modelValue) {\n close()\n return\n }\n\n if (event.key !== 'Tab' || !containerRef.value) return\n\n const focusable = getFocusableElements()\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:modelValue', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nwatch(() => props.modelValue, async (isOpen) => {\n if (isOpen) {\n previouslyFocused = document.activeElement as HTMLElement | null\n document.body.style.overflow = 'hidden'\n await nextTick()\n const focusable = getFocusableElements()\n if (focusable.length > 0) {\n focusable[0].focus()\n } else {\n containerRef.value?.focus()\n }\n } else {\n document.body.style.overflow = ''\n previouslyFocused?.focus()\n previouslyFocused = null\n }\n})\n\nuseEventListener(() => document, 'keydown', handleKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"modelValue\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n `mint-modal__container--${layout}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Tab strip — a shell region between header and body, flush with the modal edges -->\n <div\n v-if=\"layout === 'tabs' && tabs.length > 1\"\n class=\"mint-modal__tabs\"\n role=\"tablist\"\n >\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"activeTab === tab.id ? 0 : -1\"\n :class=\"['mint-modal__tab', {\n 'mint-modal__tab--active': activeTab === tab.id,\n 'mint-modal__tab--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.left.prevent=\"focusTab(-1)\"\n @keydown.right.prevent=\"focusTab(1)\"\n >\n {{ tab.label }}\n <span v-if=\"tab.meta\" class=\"mint-modal__tab-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n\n <!-- Rail layout: rail column + pane are the shell's middle row -->\n <div v-if=\"layout === 'rail'\" class=\"mint-modal__split\">\n <div class=\"mint-modal__rail\" role=\"tablist\" aria-orientation=\"vertical\">\n <div class=\"mint-modal__rail-items\">\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"activeTab === tab.id ? 0 : -1\"\n :class=\"['mint-modal__rail-item', {\n 'mint-modal__rail-item--active': activeTab === tab.id,\n 'mint-modal__rail-item--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.up.prevent=\"focusTab(-1)\"\n @keydown.down.prevent=\"focusTab(1)\"\n >\n <span v-if=\"tab.icon\" class=\"mint-modal__rail-item-icon\" aria-hidden=\"true\">\n <svg\n v-if=\"isPathIcon(tab.icon)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(tab.icon)\">\n <path v-for=\"(d, index) in tab.icon\" :key=\"index\" :d=\"d\" />\n </template>\n <path v-else :d=\"tab.icon\" />\n </svg>\n <!-- Trusted, author-controlled markup only — same contract as SettingsTab.icon. -->\n <span v-else v-html=\"tab.icon\" />\n </span>\n <span class=\"mint-modal__rail-item-text\">\n <span class=\"mint-modal__rail-item-label\">{{ tab.label }}</span>\n <span v-if=\"tab.description\" class=\"mint-modal__rail-item-description\">{{ tab.description }}</span>\n </span>\n <span v-if=\"tab.meta\" class=\"mint-modal__rail-item-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n <!-- Quiet rail-bottom action (e.g. Log out) -->\n <slot name=\"rail-footer\" />\n </div>\n\n <section\n class=\"mint-modal__pane\"\n role=\"tabpanel\"\n :aria-label=\"activeTabMeta?.label\"\n tabindex=\"0\"\n >\n <header v-if=\"activeTabMeta?.label\" class=\"mint-modal__pane-header\">\n <h4 class=\"mint-modal__pane-title\">{{ activeTabMeta.label }}</h4>\n <p v-if=\"activeTabMeta.description\" class=\"mint-modal__pane-subtitle\">\n {{ activeTabMeta.description }}\n </p>\n </header>\n <div class=\"mint-modal__pane-body\">\n <slot />\n </div>\n </section>\n </div>\n\n <!-- Body -->\n <div\n v-else\n :class=\"['mint-modal__body', layout === 'tabs' ? 'mint-modal__body--tabbed' : null]\"\n >\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n\n<style>\n@import '../styles/components/modal.css';\n</style>\n","<script setup lang=\"ts\">\n/** Modal dialog with backdrop, focus trap, Escape-to-close, and configurable size/variant/layout. */\nimport { computed, ref, watch, nextTick, onUnmounted, type ComponentPublicInstance } from 'vue'\nimport type { ModalLayout, ModalSize, ModalTab, ModalVariant } from '../types'\nimport { useEventListener } from '../composables/useEventListener'\n\ninterface Props {\n modelValue: boolean\n title?: string\n subtitle?: string\n size?: ModalSize\n variant?: ModalVariant\n closable?: boolean\n closeOnOverlay?: boolean\n closeOnEscape?: boolean\n /**\n * Shell layout. 'tabs' renders a tab strip between header and body;\n * 'rail' renders a sidebar rail + pane as the shell's middle row.\n * Both are shell regions — never part of the scrolling body content.\n */\n layout?: ModalLayout\n /** Sections for the tab strip / rail. The strip renders only with 2+ tabs. */\n tabs?: ModalTab[]\n /** Id of the selected tab. Two-way bindable via update:activeTab. */\n activeTab?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'centered',\n closable: true,\n closeOnOverlay: false,\n closeOnEscape: true,\n layout: 'plain',\n tabs: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n 'update:activeTab': [id: string]\n close: []\n}>()\n\nconst activeTabMeta = computed(() => props.tabs.find((tab) => tab.id === props.activeTab))\n\nconst tabButtonRefs = new Map<string, HTMLElement>()\n\nfunction setTabButtonRef(id: string, el: Element | ComponentPublicInstance | null) {\n if (el instanceof HTMLElement) {\n tabButtonRefs.set(id, el)\n } else {\n tabButtonRefs.delete(id)\n }\n}\n\nfunction selectTab(tab: ModalTab) {\n if (tab.disabled || tab.id === props.activeTab) return\n emit('update:activeTab', tab.id)\n}\n\n/** ARIA tablist keyboard contract: arrows move selection to the next non-disabled tab, wrapping. */\nfunction focusTab(delta: number) {\n const enabled = props.tabs.filter((tab) => !tab.disabled)\n if (enabled.length === 0) return\n const currentIndex = enabled.findIndex((tab) => tab.id === props.activeTab)\n const next = enabled[(currentIndex + delta + enabled.length) % enabled.length]\n if (!next || next.id === props.activeTab) return\n emit('update:activeTab', next.id)\n tabButtonRefs.get(next.id)?.focus()\n}\n\nfunction isPathIcon(icon: ModalTab['icon']): icon is string | string[] {\n if (!icon) return false\n return Array.isArray(icon) || icon.trim().startsWith('M') || icon.trim().startsWith('m')\n}\n\nconst containerRef = ref<HTMLElement | null>(null)\nlet previouslyFocused: HTMLElement | null = null\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(', ')\n\nfunction getFocusableElements(): HTMLElement[] {\n if (!containerRef.value) return []\n return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))\n // Roving tabindex (inactive tabs/rail items) stays out of the Tab cycle.\n .filter((el) => el.tabIndex !== -1)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && props.closeOnEscape && props.modelValue) {\n close()\n return\n }\n\n if (event.key !== 'Tab' || !containerRef.value) return\n\n const focusable = getFocusableElements()\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault()\n first.focus()\n }\n}\n\nfunction close() {\n if (props.closable) {\n emit('update:modelValue', false)\n emit('close')\n }\n}\n\nfunction handleOverlayClick(event: MouseEvent) {\n if (props.closeOnOverlay && event.target === event.currentTarget) {\n close()\n }\n}\n\nwatch(() => props.modelValue, async (isOpen) => {\n if (isOpen) {\n previouslyFocused = document.activeElement as HTMLElement | null\n document.body.style.overflow = 'hidden'\n await nextTick()\n const focusable = getFocusableElements()\n if (focusable.length > 0) {\n focusable[0].focus()\n } else {\n containerRef.value?.focus()\n }\n } else {\n document.body.style.overflow = ''\n previouslyFocused?.focus()\n previouslyFocused = null\n }\n})\n\nuseEventListener(() => document, 'keydown', handleKeydown)\n\nonUnmounted(() => {\n document.body.style.overflow = ''\n})\n</script>\n\n<template>\n <Teleport to=\"body\">\n <Transition :name=\"`modal-${variant}`\">\n <div\n v-if=\"modelValue\"\n :class=\"['mint-modal', `mint-modal--${variant}`]\"\n @click=\"handleOverlayClick\"\n >\n <!-- Overlay -->\n <div class=\"mint-modal__overlay\" />\n\n <!-- Modal -->\n <div\n ref=\"containerRef\"\n :class=\"[\n 'mint-modal__container',\n `mint-modal__container--${size}`,\n `mint-modal__container--${variant}`,\n `mint-modal__container--${layout}`,\n ]\"\n role=\"dialog\"\n aria-modal=\"true\"\n tabindex=\"-1\"\n >\n <!-- Sheet grab-hint bar (sheet variant only) -->\n <div v-if=\"variant === 'sheet'\" class=\"mint-modal__grab-hint\" aria-hidden=\"true\" />\n\n <!-- Header -->\n <div v-if=\"title || subtitle || closable || $slots.header\" class=\"mint-modal__header\">\n <div v-if=\"title || subtitle || $slots.header\" class=\"mint-modal__header-text\">\n <slot name=\"header\">\n <h3 v-if=\"title\" class=\"mint-modal__title\">\n {{ title }}\n </h3>\n <p v-if=\"subtitle\" class=\"mint-modal__subtitle\">\n {{ subtitle }}\n </p>\n </slot>\n </div>\n <button\n v-if=\"closable\"\n type=\"button\"\n class=\"mint-modal__close\"\n aria-label=\"Close modal\"\n @click=\"close\"\n >\n <svg class=\"mint-modal__close-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n </div>\n\n <!-- Tab strip — a shell region between header and body, flush with the modal edges -->\n <div\n v-if=\"layout === 'tabs' && tabs.length > 1\"\n class=\"mint-modal__tabs\"\n role=\"tablist\"\n >\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"activeTab === tab.id ? 0 : -1\"\n :class=\"['mint-modal__tab', {\n 'mint-modal__tab--active': activeTab === tab.id,\n 'mint-modal__tab--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.left.prevent=\"focusTab(-1)\"\n @keydown.right.prevent=\"focusTab(1)\"\n >\n {{ tab.label }}\n <span v-if=\"tab.meta\" class=\"mint-modal__tab-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n\n <!-- Rail layout: rail column + pane are the shell's middle row -->\n <div v-if=\"layout === 'rail'\" class=\"mint-modal__split\">\n <div class=\"mint-modal__rail\" role=\"tablist\" aria-orientation=\"vertical\">\n <div class=\"mint-modal__rail-items\">\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.id\"\n :ref=\"(el) => setTabButtonRef(tab.id, el)\"\n type=\"button\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.id\"\n :aria-disabled=\"tab.disabled || undefined\"\n :tabindex=\"activeTab === tab.id ? 0 : -1\"\n :class=\"['mint-modal__rail-item', {\n 'mint-modal__rail-item--active': activeTab === tab.id,\n 'mint-modal__rail-item--disabled': tab.disabled,\n }]\"\n @click=\"selectTab(tab)\"\n @keydown.up.prevent=\"focusTab(-1)\"\n @keydown.down.prevent=\"focusTab(1)\"\n >\n <span v-if=\"tab.icon\" class=\"mint-modal__rail-item-icon\" aria-hidden=\"true\">\n <svg\n v-if=\"isPathIcon(tab.icon)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <template v-if=\"Array.isArray(tab.icon)\">\n <path v-for=\"(d, index) in tab.icon\" :key=\"index\" :d=\"d\" />\n </template>\n <path v-else :d=\"tab.icon\" />\n </svg>\n <!-- Trusted, author-controlled markup only — same contract as SettingsTab.icon. -->\n <span v-else v-html=\"tab.icon\" />\n </span>\n <span class=\"mint-modal__rail-item-text\">\n <span class=\"mint-modal__rail-item-label\">{{ tab.label }}</span>\n <span v-if=\"tab.description\" class=\"mint-modal__rail-item-description\">{{ tab.description }}</span>\n </span>\n <span v-if=\"tab.meta\" class=\"mint-modal__rail-item-meta\">{{ tab.meta }}</span>\n </button>\n </div>\n <!-- Quiet rail-bottom action (e.g. Log out) -->\n <slot name=\"rail-footer\" />\n </div>\n\n <section\n class=\"mint-modal__pane\"\n role=\"tabpanel\"\n :aria-label=\"activeTabMeta?.label\"\n tabindex=\"0\"\n >\n <header v-if=\"activeTabMeta?.label\" class=\"mint-modal__pane-header\">\n <h4 class=\"mint-modal__pane-title\">{{ activeTabMeta.label }}</h4>\n <p v-if=\"activeTabMeta.description\" class=\"mint-modal__pane-subtitle\">\n {{ activeTabMeta.description }}\n </p>\n </header>\n <div class=\"mint-modal__pane-body\">\n <slot />\n </div>\n </section>\n </div>\n\n <!-- Body -->\n <div\n v-else\n :class=\"['mint-modal__body', layout === 'tabs' ? 'mint-modal__body--tabbed' : null]\"\n >\n <slot />\n </div>\n\n <!-- Footer -->\n <div v-if=\"$slots.footer\" class=\"mint-modal__footer\">\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </Transition>\n </Teleport>\n</template>\n\n<style>\n@import '../styles/components/modal.css';\n</style>\n","import type { DatePreset, ExperimentStatus, SelectOption, PillVariant } from '../types'\n\ninterface ExperimentCodeSource {\n id?: number | null\n experiment_code?: string | null\n}\n\nexport function formatExperimentDate(dateStr: string): string {\n try {\n return new Date(dateStr).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n } catch {\n return dateStr\n }\n}\n\nexport function datePresetToISO(preset: DatePreset): string {\n const now = new Date()\n const days = preset === 'last_7_days' ? 7 : preset === 'last_30_days' ? 30 : 90\n const d = new Date(now.getTime() - days * 86_400_000)\n return d.toISOString()\n}\n\nexport const EXPERIMENT_STATUS_OPTIONS: SelectOption<string>[] = [\n { value: '', label: 'All statuses' },\n { value: 'planned', label: 'Planned' },\n { value: 'ongoing', label: 'Ongoing' },\n { value: 'completed', label: 'Completed' },\n { value: 'cancelled', label: 'Cancelled' },\n]\n\nexport const EXPERIMENT_STATUS_VARIANT_MAP: Record<ExperimentStatus, PillVariant> = {\n planned: 'default',\n ongoing: 'primary',\n completed: 'success',\n cancelled: 'error',\n}\n\nexport const EXPERIMENT_STATUS_LABELS: Record<ExperimentStatus, string> = {\n planned: 'Planned',\n ongoing: 'Ongoing',\n completed: 'Completed',\n cancelled: 'Cancelled',\n}\n\nexport function formatExperimentStatus(status?: ExperimentStatus | string | null): string {\n if (!status) return ''\n if (status in EXPERIMENT_STATUS_LABELS) {\n return EXPERIMENT_STATUS_LABELS[status as ExperimentStatus]\n }\n const label = String(status).replace(/[-_]+/g, ' ').trim()\n return label ? label.replace(/^\\w/, c => c.toUpperCase()) : ''\n}\n\nexport function getExperimentStatusVariant(status?: ExperimentStatus | string | null): PillVariant {\n if (status && status in EXPERIMENT_STATUS_VARIANT_MAP) {\n return EXPERIMENT_STATUS_VARIANT_MAP[status as ExperimentStatus]\n }\n return 'default'\n}\n\nexport function resolveExperimentCode(experiment: ExperimentCodeSource): string | undefined {\n if (experiment.experiment_code) return experiment.experiment_code\n return undefined\n}\n\n// Mirrors vue-router's LocationQuery, whose array members are `string | null`.\n// Declaring `string[]` here made the helper reject the very type every caller\n// passes it, so keep this assignable from LocationQuery without importing\n// vue-router (the SDK does not depend on it).\ntype RouteQueryValue = string | null | undefined | readonly (string | null | undefined)[]\ntype RouteQueryLike = Record<string, RouteQueryValue>\n\n/**\n * Reads the experiment id a deep link was opened with.\n *\n * Returns an id and never a label: a display name belongs to the platform, so\n * callers must resolve it (see `useExperimentStore().selectById`) rather than\n * derive one from the query or the id itself.\n */\nexport function experimentIdFromRoute(query: RouteQueryLike): number | null {\n const raw = query.experiment_id ?? query.experimentId\n const value = Array.isArray(raw) ? raw.find(item => typeof item === 'string') : raw\n if (typeof value !== 'string' || !value) return null\n const id = Number(value)\n return Number.isInteger(id) && id > 0 ? id : null\n}\n\nexport const DATE_PRESET_OPTIONS: SelectOption<string>[] = [\n { value: '', label: 'Any time' },\n { value: 'last_7_days', label: 'Last 7 days' },\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_90_days', label: 'Last 90 days' },\n]\n\nexport const SORT_OPTIONS: SelectOption<string>[] = [\n { value: 'created_at:desc', label: 'Newest first' },\n { value: 'created_at:asc', label: 'Oldest first' },\n { value: 'updated_at:desc', label: 'Recently updated' },\n { value: 'name:asc', label: 'Name A\\u2013Z' },\n { value: 'name:desc', label: 'Name Z\\u2013A' },\n]\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- export declare const setupVue3: import('@histoire/plugin-vue').Vue3StorySetupHandler;
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/utils/rack.ts"],"sourcesContent":["import type { Rack, SlotPosition, Well, WellEditData, WellPlateFormat } from '../types'\n\nexport type LcmsPlateType = '96well' | '54vial'\nexport type LcmsControlSampleType = 'blank' | 'qc' | 'iqc'\n\nexport interface LcmsPlateCell {\n row: string\n column: number\n sample_name: string\n sample_type?: string | null\n injection_volume?: number | null\n injection_count?: number | null\n custom_method?: string | null\n slot?: SlotPosition | null\n}\n\nexport interface LcmsPlateCellsToRackOptions {\n rackId?: string\n rackName?: string\n format?: WellPlateFormat\n plateType?: LcmsPlateType\n slot?: SlotPosition\n injectionVolume?: number\n}\n\nexport interface LcmsPlateCellsToRacksOptions extends Omit<LcmsPlateCellsToRackOptions, 'rackId' | 'rackName' | 'slot'> {\n defaultSlot?: SlotPosition\n rackId?: (slot: SlotPosition, index: number) => string\n rackName?: (slot: SlotPosition, index: number) => string\n}\n\nexport const LCMS_DEFAULT_CONTROL_POSITIONS: Record<LcmsPlateType, Record<LcmsControlSampleType, { row: string; column: number }>> = {\n '96well': {\n blank: { row: 'H', column: 12 },\n qc: { row: 'H', column: 11 },\n iqc: { row: 'H', column: 10 },\n },\n '54vial': {\n blank: { row: 'F', column: 9 },\n qc: { row: 'F', column: 8 },\n iqc: { row: 'F', column: 7 },\n },\n}\n\nconst SLOT_ORDER: SlotPosition[] = ['R', 'G', 'B', 'Y']\n\nexport function lcmsPlateTypeToRackFormat(plateType: LcmsPlateType): WellPlateFormat {\n return plateType === '96well' ? 96 : 54\n}\n\nexport function rackFormatToLcmsPlateType(format: WellPlateFormat): LcmsPlateType {\n if (format === 96) return '96well'\n if (format === 54) return '54vial'\n throw new Error(`LCMS plate cells support only 54-vial racks and 96-well plates; received format ${format}.`)\n}\n\nexport function lcmsWellId(row: string, column: number): string {\n return `${row.toUpperCase()}${column}`\n}\n\nexport function parseLcmsWellId(wellId: string): { row: string; column: number } {\n const match = /^([A-Za-z]+)(\\d+)$/.exec(wellId.trim())\n if (!match) {\n throw new Error(`Invalid well id \"${wellId}\". Expected a row letter followed by a column number, e.g. A1.`)\n }\n\n return {\n row: match[1].toUpperCase(),\n column: Number(match[2]),\n }\n}\n\nexport function lcmsPlateCellsToRack(cells: LcmsPlateCell[], options: LcmsPlateCellsToRackOptions = {}): Rack {\n const format = options.format ?? (options.plateType ? lcmsPlateTypeToRackFormat(options.plateType) : inferRackFormat(cells))\n const slot = options.slot ?? cells.find(cell => cell.slot)?.slot ?? 'R'\n const injectionVolume = options.injectionVolume ?? inferInjectionVolume(cells) ?? 5\n\n return {\n id: options.rackId ?? `rack-${slot}`,\n name: options.rackName ?? `Rack ${slot}`,\n format,\n slot,\n injectionVolume,\n wells: Object.fromEntries(\n cells\n .filter(cell => cell.sample_name.trim())\n .map((cell) => {\n const wellId = lcmsWellId(cell.row, cell.column)\n const well: Partial<Well> = {\n id: wellId,\n row: rowIndex(cell.row),\n col: cell.column - 1,\n state: 'filled',\n sampleType: cell.sample_type ?? 'sample',\n metadata: {\n label: cell.sample_name.trim(),\n injectionVolume: cell.injection_volume ?? injectionVolume,\n injectionCount: cell.injection_count ?? 1,\n customMethod: cell.custom_method ?? null,\n },\n }\n return [wellId, well]\n }),\n ),\n }\n}\n\nexport function lcmsPlateCellsToRacks(cells: LcmsPlateCell[], options: LcmsPlateCellsToRacksOptions = {}): Rack[] {\n const bySlot = new Map<SlotPosition, LcmsPlateCell[]>()\n const defaultSlot = options.defaultSlot ?? 'R'\n\n for (const cell of cells) {\n const slot = cell.slot ?? defaultSlot\n const slotCells = bySlot.get(slot) ?? []\n slotCells.push(cell)\n bySlot.set(slot, slotCells)\n }\n\n return Array.from(bySlot.entries())\n .sort(([a], [b]) => SLOT_ORDER.indexOf(a) - SLOT_ORDER.indexOf(b))\n .map(([slot, slotCells], index) => lcmsPlateCellsToRack(slotCells, {\n ...options,\n slot,\n rackId: options.rackId?.(slot, index) ?? `rack-${slot}`,\n rackName: options.rackName?.(slot, index) ?? `Rack ${slot}`,\n }))\n}\n\nexport function rackToLcmsPlateCells(rack: Rack): LcmsPlateCell[] {\n return Object.entries(rack.wells)\n .map(([wellId, well]) => wellToLcmsPlateCell(rack, wellId, well))\n .filter((cell): cell is LcmsPlateCell => cell !== null)\n .sort(comparePlateCells)\n}\n\nexport function racksToLcmsPlateCells(racks: Rack[]): LcmsPlateCell[] {\n return racks.flatMap(rackToLcmsPlateCells)\n}\n\nexport function getLcmsDefaultControlWellId(plateType: LcmsPlateType, sampleType: LcmsControlSampleType): string {\n const position = LCMS_DEFAULT_CONTROL_POSITIONS[plateType][sampleType]\n return lcmsWellId(position.row, position.column)\n}\n\nexport function createLcmsControlWellEditData(\n sampleType: LcmsControlSampleType,\n options: {\n wellId?: string\n plateType?: LcmsPlateType\n injectionVolume?: number\n } = {},\n): WellEditData {\n const plateType = options.plateType ?? '54vial'\n return {\n wellId: options.wellId ?? getLcmsDefaultControlWellId(plateType, sampleType),\n label: sampleType === 'blank' ? 'Blank' : sampleType.toUpperCase(),\n sampleType,\n injectionVolume: options.injectionVolume ?? 5,\n injectionCount: 1,\n customMethod: '',\n }\n}\n\nfunction wellToLcmsPlateCell(rack: Rack, wellId: string, well: Partial<Well>): LcmsPlateCell | null {\n const metadata = well.metadata ?? {}\n const label = getString(metadata.label)\n if (!label) return null\n\n const parsed = parseLcmsWellId(well.id ?? wellId)\n return {\n row: parsed.row,\n column: parsed.column,\n sample_name: label,\n sample_type: well.sampleType ?? null,\n injection_volume: getNumber(metadata.injectionVolume) ?? rack.injectionVolume,\n injection_count: getNumber(metadata.injectionCount) ?? 1,\n custom_method: getNullableString(metadata.customMethod),\n slot: rack.slot,\n }\n}\n\nfunction inferRackFormat(cells: LcmsPlateCell[]): WellPlateFormat {\n return cells.some(cell => rowIndex(cell.row) > 5 || cell.column > 9) ? 96 : 54\n}\n\nfunction inferInjectionVolume(cells: LcmsPlateCell[]): number | undefined {\n return cells.find(cell => typeof cell.injection_volume === 'number')?.injection_volume ?? undefined\n}\n\nfunction rowIndex(row: string): number {\n return row.toUpperCase().charCodeAt(0) - 65\n}\n\nfunction getString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction getNullableString(value: unknown): string | null {\n return typeof value === 'string' && value.trim() ? value.trim() : null\n}\n\nfunction getNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction comparePlateCells(a: LcmsPlateCell, b: LcmsPlateCell): number {\n const rowDiff = rowIndex(a.row) - rowIndex(b.row)\n return rowDiff === 0 ? a.column - b.column : rowDiff\n}\n"],"mappings":"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"}
package/dist/install.js DELETED
@@ -1,28 +0,0 @@
1
- import "./experiment-utils-CLnzPPq5.js";
2
- import "./EmptyState-p90quq8Z.js";
3
- import "./useControlSchema-BDx2Olha.js";
4
- import { t as components_exports } from "./components-DkHddRMl.js";
5
- import "./SettingsModal-BgKY93zh.js";
6
- import "./ExperimentPopover-tLwJ7XF4.js";
7
- import "./ExperimentSelectorModal-DyPAUCLw.js";
8
- //#region src/install.ts
9
- /**
10
- * Vue plugin that registers all MINT SDK components globally.
11
- *
12
- * @example
13
- * ```typescript
14
- * import { createApp } from 'vue'
15
- * import { MINTSdk } from '@morscherlab/mint-sdk'
16
- * import '@morscherlab/mint-sdk/styles'
17
- *
18
- * const app = createApp(App)
19
- * app.use(MINTSdk)
20
- * ```
21
- */
22
- var MINTSdk = { install(app) {
23
- for (const [name, component] of Object.entries(components_exports)) if (component && typeof component === "object" && ("setup" in component || "render" in component || "__name" in component)) app.component(name, component);
24
- } };
25
- //#endregion
26
- export { MINTSdk, MINTSdk as default };
27
-
28
- //# sourceMappingURL=install.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"install.js","names":[],"sources":["../src/install.ts"],"sourcesContent":["import * as components from './components'\n\ntype ComponentRegistryApp = {\n component: (name: string, component: any) => unknown\n}\n\nexport interface MINTSdkPlugin {\n install(app: ComponentRegistryApp): void\n}\n\n/**\n * Vue plugin that registers all MINT SDK components globally.\n *\n * @example\n * ```typescript\n * import { createApp } from 'vue'\n * import { MINTSdk } from '@morscherlab/mint-sdk'\n * import '@morscherlab/mint-sdk/styles'\n *\n * const app = createApp(App)\n * app.use(MINTSdk)\n * ```\n */\nexport const MINTSdk: MINTSdkPlugin = {\n install(app) {\n for (const [name, component] of Object.entries(components)) {\n // Check if it's a valid Vue component (has setup, render, or template)\n if (\n component &&\n typeof component === 'object' &&\n ('setup' in component || 'render' in component || '__name' in component)\n ) {\n app.component(name, component)\n }\n }\n },\n}\n\nexport default MINTSdk\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,UAAyB,EACpC,QAAQ,KAAK;AACX,MAAK,MAAM,CAAC,MAAM,cAAc,OAAO,QAAQ,mBAAW,CAExD,KACE,aACA,OAAO,cAAc,aACpB,WAAW,aAAa,YAAY,aAAa,YAAY,WAE9D,KAAI,UAAU,MAAM,UAAU;GAIrC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"permissions.js","names":[],"sources":["../src/permissions.ts"],"sourcesContent":["export const ADMIN_ROLE = 'admin'\n\nexport const ADMIN_PANEL_PERMISSIONS = [\n 'users.view',\n 'users.invite',\n 'users.manage',\n 'platform.configure',\n 'platform.view_logs',\n 'plugins.configure',\n 'plugins.install',\n 'notices.publish',\n] as const\n\nexport type AccessAudience = 'all' | 'admin' | 'user'\nexport type AccessAudienceInput = AccessAudience | readonly AccessAudience[]\n\nexport interface RoleInfo {\n id?: number\n slug: string\n name?: string\n color?: string\n permissions?: readonly string[] | null\n project_scope?: 'all' | 'assigned' | string\n plugin_access?: readonly string[] | 'all' | null\n}\n\nexport interface PermissionUser {\n role?: string | null\n role_obj?: RoleInfo | null\n roleObj?: RoleInfo | null\n permissions?: readonly string[] | null\n}\n\nexport interface AccessPolicy {\n audience?: AccessAudienceInput\n visibleFor?: AccessAudienceInput\n requiresAuth?: boolean\n requiresAdmin?: boolean\n permissions?: readonly string[]\n anyPermissions?: readonly string[]\n plugin?: string\n}\n\nexport interface AccessControlled {\n access?: AccessPolicy\n visibleFor?: AccessAudienceInput\n requiresAdmin?: boolean\n permissions?: readonly string[]\n anyPermissions?: readonly string[]\n}\n\nexport function getRoleInfo(user: PermissionUser | null | undefined): RoleInfo | null {\n return user?.roleObj ?? user?.role_obj ?? null\n}\n\nexport function isAdminRole(role: string | null | undefined): boolean {\n return role === ADMIN_ROLE\n}\n\nexport function isAdminUser(user: PermissionUser | null | undefined): boolean {\n return isAdminRole(user?.role) || getRoleInfo(user)?.slug === ADMIN_ROLE\n}\n\nexport function getAccessAudience(user: PermissionUser | null | undefined): Exclude<AccessAudience, 'all'> {\n return isAdminUser(user) ? 'admin' : 'user'\n}\n\nexport function getUserPermissions(user: PermissionUser | null | undefined): string[] {\n const rolePermissions = getRoleInfo(user)?.permissions\n if (rolePermissions?.length) return [...rolePermissions]\n return [...(user?.permissions ?? [])]\n}\n\nexport function hasAllPermissions(\n user: PermissionUser | null | undefined,\n permissions: readonly string[] = [],\n): boolean {\n if (permissions.length === 0) return true\n if (isAdminUser(user)) return true\n const granted = new Set(getUserPermissions(user))\n return permissions.every(permission => granted.has(permission))\n}\n\nexport function hasAnyPermission(\n user: PermissionUser | null | undefined,\n permissions: readonly string[] = [],\n): boolean {\n if (permissions.length === 0) return true\n if (isAdminUser(user)) return true\n const granted = new Set(getUserPermissions(user))\n return permissions.some(permission => granted.has(permission))\n}\n\nexport function canAccessAdmin(user: PermissionUser | null | undefined): boolean {\n return isAdminUser(user) || hasAnyPermission(user, ADMIN_PANEL_PERMISSIONS)\n}\n\nexport function canAccessPlugin(\n user: PermissionUser | null | undefined,\n pluginName: string | null | undefined,\n): boolean {\n if (!pluginName) return true\n const access = getRoleInfo(user)?.plugin_access\n if (!access || access === 'all') return true\n return Array.isArray(access) && access.includes(pluginName)\n}\n\nexport function normalizeAccessPolicy(rule: AccessControlled | AccessPolicy | undefined): AccessPolicy {\n if (!rule) return {}\n const { access: nested, ...direct } = rule as AccessPolicy & { access?: AccessPolicy }\n return {\n ...(nested ?? {}),\n ...direct,\n ...('visibleFor' in rule && rule.visibleFor !== undefined ? { visibleFor: rule.visibleFor } : {}),\n ...('requiresAdmin' in rule && rule.requiresAdmin !== undefined ? { requiresAdmin: rule.requiresAdmin } : {}),\n ...('permissions' in rule && rule.permissions !== undefined ? { permissions: rule.permissions } : {}),\n ...('anyPermissions' in rule && rule.anyPermissions !== undefined ? { anyPermissions: rule.anyPermissions } : {}),\n }\n}\n\nexport function canAccessByPolicy(\n user: PermissionUser | null | undefined,\n rule: AccessControlled | AccessPolicy | undefined,\n isAuthenticated = user !== null && user !== undefined,\n): boolean {\n const policy = normalizeAccessPolicy(rule)\n if (policy.requiresAuth && !isAuthenticated) return false\n if (policy.requiresAdmin && !isAdminUser(user)) return false\n if (!audienceAllowsUser(policy.visibleFor ?? policy.audience, user)) return false\n if (!hasAllPermissions(user, policy.permissions)) return false\n if (!hasAnyPermission(user, policy.anyPermissions)) return false\n if (policy.plugin && !canAccessPlugin(user, policy.plugin)) return false\n return true\n}\n\nfunction audienceAllowsUser(\n audience: AccessAudienceInput | undefined,\n user: PermissionUser | null | undefined,\n): boolean {\n if (audience === undefined) return true\n const allowed = Array.isArray(audience) ? audience : [audience]\n if (allowed.includes('all')) return true\n return allowed.includes(getAccessAudience(user))\n}\n"],"mappings":"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"}