@morscherlab/mint-sdk 1.2.0-beta.2 → 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,1903 +0,0 @@
1
- import { effectScope } from 'vue'
2
- import { describe, expect, it, vi } from 'vitest'
3
-
4
- import { useGeneratedAnalysis } from '../../composables/useGeneratedAnalysis'
5
- import {
6
- createGeneratedAnalysisTransport,
7
- type GeneratedAnalysisTransport,
8
- } from '../../composables/useGeneratedAnalysis'
9
- import type { PluginJobCenterSource } from '../../composables/useJobsStatusTray'
10
- import type {
11
- GeneratedAnalysisJob,
12
- GeneratedAnalysisManifest,
13
- } from '../../types/generated-ui'
14
-
15
- const manifest: GeneratedAnalysisManifest = {
16
- schema_version: '1',
17
- plugin: {
18
- name: 'Demo',
19
- version: '1.0.0',
20
- description: 'Demo plugin',
21
- routes_prefix: '/demo',
22
- },
23
- ui: { title: 'Demo analysis', description: 'Run it' },
24
- jobs: [],
25
- }
26
-
27
- function response(body: unknown, status = 200): Response {
28
- return new Response(JSON.stringify(body), {
29
- status,
30
- headers: { 'Content-Type': 'application/json' },
31
- })
32
- }
33
-
34
- function eventStream(...frames: string[]): Response {
35
- const encoder = new TextEncoder()
36
- return new Response(new ReadableStream<Uint8Array>({
37
- start(controller) {
38
- for (const frame of frames) controller.enqueue(encoder.encode(frame))
39
- controller.close()
40
- },
41
- }), {
42
- headers: { 'Content-Type': 'text/event-stream' },
43
- })
44
- }
45
-
46
- function deferred<T>(): {
47
- promise: Promise<T>
48
- resolve: (value: T) => void
49
- } {
50
- let resolve!: (value: T) => void
51
- const promise = new Promise<T>((next) => { resolve = next })
52
- return { promise, resolve }
53
- }
54
-
55
- function memoryStorage(): Storage {
56
- const values = new Map<string, string>()
57
- return {
58
- get length() { return values.size },
59
- clear: () => values.clear(),
60
- getItem: key => values.get(key) ?? null,
61
- key: index => [...values.keys()][index] ?? null,
62
- removeItem: key => values.delete(key),
63
- setItem: (key, value) => values.set(key, value),
64
- }
65
- }
66
-
67
- function completedJob(jobId: string): GeneratedAnalysisJob {
68
- return {
69
- id: jobId,
70
- job_id: jobId,
71
- kind: 'analysis',
72
- name: 'Run analysis',
73
- status: 'completed',
74
- progress: {
75
- current_file: 0,
76
- total_files: 0,
77
- current_filename: null,
78
- percent: 100,
79
- message: '',
80
- stage: 'completed',
81
- },
82
- queue_position: 0,
83
- warnings: [],
84
- error: null,
85
- output_path: null,
86
- save_path: null,
87
- session_id: 'session-1',
88
- folders: [],
89
- folder_path: null,
90
- user_id: 'user-1',
91
- owner_user_id: 'user-1',
92
- experiment_id: null,
93
- extraction_result_id: null,
94
- metadata: { definition_id: 'run', has_result: true },
95
- created_at: '',
96
- started_at: '',
97
- completed_at: '',
98
- definition_id: 'run',
99
- can_cancel: false,
100
- can_delete: true,
101
- result_status: 'available',
102
- result_expires_at: null,
103
- }
104
- }
105
-
106
- function activeJob(
107
- jobId: string,
108
- status: 'queued' | 'running' = 'queued',
109
- ): GeneratedAnalysisJob {
110
- return {
111
- ...completedJob(jobId),
112
- status,
113
- progress: {
114
- current_file: 0,
115
- total_files: 0,
116
- current_filename: null,
117
- percent: 0,
118
- message: status === 'queued' ? 'Queued' : 'Running',
119
- stage: status,
120
- },
121
- completed_at: null,
122
- can_cancel: true,
123
- can_delete: false,
124
- result_status: 'none',
125
- metadata: { definition_id: 'run', has_result: false },
126
- }
127
- }
128
-
129
- function streamingJobTransport(): ReturnType<typeof vi.fn<GeneratedAnalysisTransport>> {
130
- return vi.fn<GeneratedAnalysisTransport>(async (input, init) => {
131
- const url = String(input)
132
- if (url.endsWith('/generated/manifest')) return response(manifest)
133
- if (url.endsWith('/jobs/sessions') && init?.method === 'GET') {
134
- return response({ sessions: [] })
135
- }
136
- if (url.endsWith('/jobs/sessions') && init?.method === 'POST') {
137
- return response({
138
- id: 'session-1',
139
- tab_id: 'tab-1',
140
- created_at: '',
141
- last_seen_at: '',
142
- active_job_ids: [],
143
- })
144
- }
145
- if (url.endsWith('/jobs/events')) return eventStream()
146
- if (url.endsWith('/jobs')) return response({ jobs: [activeJob('job-1')] })
147
- throw new Error(`Unexpected request: ${url}`)
148
- })
149
- }
150
-
151
- describe('useGeneratedAnalysis', () => {
152
- it('is directly usable as a job center source', () => {
153
- const scope = effectScope()
154
- const generated = scope.run(() => useGeneratedAnalysis({
155
- baseUrl: '/api/demo',
156
- transport: vi.fn<GeneratedAnalysisTransport>(),
157
- storage: memoryStorage(),
158
- stream: false,
159
- }))!
160
-
161
- const source: PluginJobCenterSource = generated
162
- expect(source.jobs).toBe(generated.jobs)
163
- scope.stop()
164
- })
165
-
166
- it('should report an immediate initialization failure without an unhandled rejection', async () => {
167
- const scope = effectScope()
168
- const generated = scope.run(() => useGeneratedAnalysis({
169
- baseUrl: '/api/demo',
170
- transport: vi.fn<GeneratedAnalysisTransport>()
171
- .mockRejectedValue(new TypeError('offline')),
172
- storage: memoryStorage(),
173
- immediate: true,
174
- stream: false,
175
- }))!
176
-
177
- try {
178
- await vi.waitFor(() => expect(generated.status.value).toBe('error'))
179
- expect(generated.error.value).toBe('offline')
180
- } finally {
181
- scope.stop()
182
- }
183
- })
184
-
185
- it('should initialize with page-local session state when browser storage is unavailable', async () => {
186
- const unavailableStorage = {
187
- get length(): number { throw new DOMException('Blocked', 'SecurityError') },
188
- clear: () => { throw new DOMException('Blocked', 'SecurityError') },
189
- getItem: () => { throw new DOMException('Blocked', 'SecurityError') },
190
- key: () => { throw new DOMException('Blocked', 'SecurityError') },
191
- removeItem: () => { throw new DOMException('Blocked', 'SecurityError') },
192
- setItem: () => { throw new DOMException('Blocked', 'SecurityError') },
193
- } satisfies Storage
194
- const transport = vi.fn<GeneratedAnalysisTransport>()
195
- .mockResolvedValueOnce(response(manifest))
196
- .mockResolvedValueOnce(response({ sessions: [] }))
197
- .mockResolvedValueOnce(response({
198
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
199
- }))
200
- .mockResolvedValueOnce(response({ jobs: [] }))
201
- const scope = effectScope()
202
- const generated = scope.run(() => useGeneratedAnalysis({
203
- baseUrl: '/api/demo',
204
- transport,
205
- storage: unavailableStorage,
206
- createId: () => 'tab-1',
207
- stream: false,
208
- }))!
209
-
210
- try {
211
- await generated.initialize()
212
-
213
- expect(generated.session.value?.id).toBe('session-1')
214
- } finally {
215
- scope.stop()
216
- }
217
- })
218
-
219
- it('should add the current bearer token to JSON and event-stream requests', async () => {
220
- const fetcher = vi.fn().mockResolvedValue(response({ ok: true }))
221
- const transport = createGeneratedAnalysisTransport({
222
- fetcher,
223
- getAccessToken: () => 'viewer-token',
224
- })
225
-
226
- await transport('/api/demo/generated/manifest', {
227
- headers: { Accept: 'application/json' },
228
- })
229
- await transport('/api/demo/jobs/events', {
230
- headers: { Accept: 'text/event-stream' },
231
- })
232
-
233
- expect(fetcher.mock.calls.map(call => {
234
- const headers = new Headers(call[1]?.headers)
235
- return [headers.get('Accept'), headers.get('Authorization')]
236
- })).toEqual([
237
- ['application/json', 'Bearer viewer-token'],
238
- ['text/event-stream', 'Bearer viewer-token'],
239
- ])
240
- })
241
-
242
- it('should consume job updates from an authenticated fetch stream without EventSource', async () => {
243
- const storage = memoryStorage()
244
- const runningJob = activeJob('job-1', 'running')
245
- const completedJob = {
246
- ...runningJob,
247
- status: 'completed',
248
- completed_at: '',
249
- can_cancel: false,
250
- can_delete: true,
251
- result_status: 'available',
252
- metadata: { definition_id: 'run', has_result: true },
253
- }
254
- const transport = vi.fn<GeneratedAnalysisTransport>()
255
- .mockResolvedValueOnce(response(manifest))
256
- .mockResolvedValueOnce(response({ sessions: [] }))
257
- .mockResolvedValueOnce(response({
258
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
259
- }))
260
- .mockResolvedValueOnce(response({ jobs: [runningJob] }))
261
- .mockResolvedValueOnce(eventStream(
262
- `event: snapshot\ndata: ${JSON.stringify({ jobs: [runningJob] })}\n\n`,
263
- `event: terminal\ndata: ${JSON.stringify(completedJob)}\n\n`,
264
- ))
265
- .mockResolvedValueOnce(response({ kind: 'text', text: 'done' }))
266
- const eventSource = vi.fn(() => {
267
- throw new Error('Generated job streams must not use EventSource')
268
- })
269
- vi.stubGlobal('EventSource', eventSource)
270
- const scope = effectScope()
271
- const generated = scope.run(() => useGeneratedAnalysis({
272
- baseUrl: '/api/demo',
273
- transport,
274
- storage,
275
- createId: () => 'tab-1',
276
- streamReconnectDelay: 60_000,
277
- }))!
278
-
279
- try {
280
- await generated.initialize()
281
- await vi.waitFor(() => expect(generated.jobs.value[0]?.status).toBe('completed'))
282
-
283
- expect(transport.mock.calls.some(call => String(call[0]).endsWith('/result'))).toBe(false)
284
-
285
- await generated.loadResult(generated.jobs.value[0]!)
286
-
287
- const streamCall = transport.mock.calls.find(call => String(call[0]).endsWith('/jobs/events'))
288
- const resultCall = transport.mock.calls.find(call => String(call[0]).endsWith('/jobs/job-1/result'))
289
- expect({
290
- eventSourceCalls: eventSource.mock.calls.length,
291
- accept: new Headers(streamCall?.[1]?.headers).get('Accept'),
292
- signal: streamCall?.[1]?.signal instanceof AbortSignal,
293
- resultMethod: resultCall?.[1]?.method,
294
- result: generated.latestResult.value,
295
- }).toEqual({
296
- eventSourceCalls: 0,
297
- accept: 'text/event-stream',
298
- signal: true,
299
- resultMethod: 'GET',
300
- result: { kind: 'text', text: 'done' },
301
- })
302
- } finally {
303
- scope.stop()
304
- vi.unstubAllGlobals()
305
- }
306
- })
307
-
308
- it('should poll active jobs while a closed stream waits to reconnect', async () => {
309
- vi.useFakeTimers()
310
- const transport = streamingJobTransport()
311
- const scope = effectScope()
312
- const generated = scope.run(() => useGeneratedAnalysis({
313
- baseUrl: '/api/demo',
314
- transport,
315
- storage: memoryStorage(),
316
- createId: () => 'tab-1',
317
- pollInterval: 5,
318
- streamReconnectDelay: 1_000,
319
- }))!
320
-
321
- try {
322
- await generated.initialize()
323
- await vi.advanceTimersByTimeAsync(5)
324
-
325
- expect(transport.mock.calls.filter(([input]) => String(input).endsWith('/jobs'))).toHaveLength(2)
326
- } finally {
327
- generated.dispose()
328
- scope.stop()
329
- vi.useRealTimers()
330
- }
331
- })
332
-
333
- it('should not poll or reconnect a paused job stream', async () => {
334
- vi.useFakeTimers()
335
- const transport = streamingJobTransport()
336
- const scope = effectScope()
337
- const generated = scope.run(() => useGeneratedAnalysis({
338
- baseUrl: '/api/demo',
339
- transport,
340
- storage: memoryStorage(),
341
- createId: () => 'tab-1',
342
- pollInterval: 5,
343
- streamReconnectDelay: 10,
344
- }))!
345
-
346
- try {
347
- await generated.initialize()
348
- await vi.advanceTimersByTimeAsync(0)
349
- generated.pause()
350
- await vi.advanceTimersByTimeAsync(20)
351
-
352
- expect({
353
- jobLists: transport.mock.calls.filter(([input]) => String(input).endsWith('/jobs')).length,
354
- streams: transport.mock.calls.filter(([input]) => String(input).endsWith('/jobs/events')).length,
355
- }).toEqual({ jobLists: 1, streams: 1 })
356
- } finally {
357
- generated.dispose()
358
- scope.stop()
359
- vi.useRealTimers()
360
- }
361
- })
362
-
363
- it('should not poll or reconnect a disposed job stream', async () => {
364
- vi.useFakeTimers()
365
- const transport = streamingJobTransport()
366
- const scope = effectScope()
367
- const generated = scope.run(() => useGeneratedAnalysis({
368
- baseUrl: '/api/demo',
369
- transport,
370
- storage: memoryStorage(),
371
- createId: () => 'tab-1',
372
- pollInterval: 5,
373
- streamReconnectDelay: 10,
374
- }))!
375
-
376
- await generated.initialize()
377
- await vi.advanceTimersByTimeAsync(0)
378
- generated.dispose()
379
- await vi.advanceTimersByTimeAsync(20)
380
-
381
- expect({
382
- jobLists: transport.mock.calls.filter(([input]) => String(input).endsWith('/jobs')).length,
383
- streams: transport.mock.calls.filter(([input]) => String(input).endsWith('/jobs/events')).length,
384
- }).toEqual({ jobLists: 1, streams: 1 })
385
- scope.stop()
386
- vi.useRealTimers()
387
- })
388
-
389
- it('does not let a late submit response regress a terminal stream update', async () => {
390
- const terminal = completedJob('fast-service-job')
391
- const lateQueued = activeJob('fast-service-job')
392
- const transport = vi.fn<GeneratedAnalysisTransport>()
393
- .mockResolvedValueOnce(response(manifest))
394
- .mockResolvedValueOnce(response({ sessions: [] }))
395
- .mockResolvedValueOnce(response({
396
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
397
- }))
398
- .mockResolvedValueOnce(response({ jobs: [] }))
399
- .mockResolvedValueOnce(eventStream(
400
- `event: terminal\ndata: ${JSON.stringify(terminal)}\n\n`,
401
- ))
402
- .mockResolvedValueOnce(response(lateQueued))
403
- const scope = effectScope()
404
- const generated = scope.run(() => useGeneratedAnalysis({
405
- baseUrl: '/api/demo',
406
- transport,
407
- storage: memoryStorage(),
408
- createId: () => 'tab-1',
409
- streamReconnectDelay: 60_000,
410
- }))!
411
-
412
- try {
413
- await generated.initialize()
414
- await vi.waitFor(() => expect(generated.jobs.value[0]?.status).toBe('completed'))
415
-
416
- const submitted = await generated.submit('run', {})
417
-
418
- expect({
419
- submitted: submitted.status,
420
- stored: generated.jobs.value[0]?.status,
421
- }).toEqual({ submitted: 'completed', stored: 'completed' })
422
- } finally {
423
- scope.stop()
424
- }
425
- })
426
-
427
- it('creates one server session for the current sessionStorage tab and exposes results', async () => {
428
- const storage = memoryStorage()
429
- const fetcher = vi.fn()
430
- .mockResolvedValueOnce(response(manifest))
431
- .mockResolvedValueOnce(response({ sessions: [] }))
432
- .mockResolvedValueOnce(response({
433
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
434
- }))
435
- .mockResolvedValueOnce(response({ jobs: [] }))
436
- .mockResolvedValueOnce(response(activeJob('job-1')))
437
- .mockResolvedValueOnce(response({
438
- jobs: [completedJob('job-1')],
439
- }))
440
- .mockResolvedValueOnce(response({ kind: 'text', text: 'done' }))
441
- const scope = effectScope()
442
- const generated = scope.run(() => useGeneratedAnalysis({
443
- baseUrl: '/api/demo',
444
- transport: fetcher,
445
- storage,
446
- createId: () => 'tab-1',
447
- pollInterval: 60_000,
448
- stream: false,
449
- }))!
450
-
451
- await generated.initialize()
452
- await generated.submit('run', { threshold: 2.5 })
453
- await generated.refreshJobs()
454
- await generated.loadResult(generated.jobs.value[0]!)
455
- scope.stop()
456
-
457
- expect({
458
- session: generated.session.value?.id,
459
- result: generated.latestResult.value,
460
- resultRequest: fetcher.mock.calls[6]?.[0],
461
- storedTab: storage.getItem('mint:generated:/api/demo:tab'),
462
- submitted: JSON.parse(String(fetcher.mock.calls[4]?.[1]?.body)),
463
- }).toEqual({
464
- session: 'session-1',
465
- result: { kind: 'text', text: 'done' },
466
- resultRequest: '/api/demo/jobs/job-1/result',
467
- storedTab: 'tab-1',
468
- submitted: {
469
- definition_id: 'run',
470
- inputs: { threshold: 2.5 },
471
- session_id: 'session-1',
472
- client_request_id: expect.any(String),
473
- },
474
- })
475
- })
476
-
477
- it('should stage a selected path before submitting its opaque token', async () => {
478
- const transport = vi.fn<GeneratedAnalysisTransport>()
479
- .mockResolvedValueOnce(response(manifest))
480
- .mockResolvedValueOnce(response({ sessions: [] }))
481
- .mockResolvedValueOnce(response({
482
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
483
- }))
484
- .mockResolvedValueOnce(response({ jobs: [] }))
485
- .mockResolvedValueOnce(response({ token: 'upload-token', kind: 'file', name: 'data.csv', size: 4 }))
486
- .mockResolvedValueOnce(response(activeJob('job-1')))
487
- const scope = effectScope()
488
- const generated = scope.run(() => useGeneratedAnalysis({
489
- baseUrl: '/api/demo',
490
- transport,
491
- storage: memoryStorage(),
492
- createId: () => 'tab-1',
493
- stream: false,
494
- }))!
495
-
496
- try {
497
- await generated.initialize()
498
- await generated.submit('run', {
499
- source: {
500
- kind: 'path',
501
- files: [new File(['data'], 'data.csv')],
502
- relativePaths: ['data.csv'],
503
- },
504
- })
505
-
506
- const upload = transport.mock.calls[4]
507
- const form = upload?.[1]?.body as FormData
508
- const submit = JSON.parse(String(transport.mock.calls[5]?.[1]?.body))
509
- expect({
510
- uploadUrl: upload?.[0],
511
- uploadMethod: upload?.[1]?.method,
512
- uploadSessionHeader: new Headers(upload?.[1]?.headers).get('X-Mint-Job-Session'),
513
- uploadDefinitionHeader: new Headers(upload?.[1]?.headers).get('X-Mint-Job-Definition'),
514
- sessionId: form.get('session_id'),
515
- relativePaths: form.getAll('relative_paths'),
516
- submittedSource: submit.inputs.source,
517
- }).toEqual({
518
- uploadUrl: '/api/demo/jobs/uploads',
519
- uploadMethod: 'POST',
520
- uploadSessionHeader: 'session-1',
521
- uploadDefinitionHeader: 'run',
522
- sessionId: 'session-1',
523
- relativePaths: ['data.csv'],
524
- submittedSource: { token: 'upload-token' },
525
- })
526
- } finally {
527
- scope.stop()
528
- }
529
- })
530
-
531
- it('uploads, inspects, and seals staged job parts through the canonical runtime', async () => {
532
- const stagingSummary = {
533
- job_id: 'staged/job',
534
- sealed: false,
535
- part_count: 1,
536
- total_bytes: 3,
537
- }
538
- const part = {
539
- key: 'sample one/chunk#1',
540
- size: 3,
541
- sha256: 'a'.repeat(64),
542
- metadata: { sampleIndex: 1 },
543
- }
544
- const staging = {
545
- ...stagingSummary,
546
- parts: [part],
547
- offset: 0,
548
- limit: 10,
549
- next_offset: null,
550
- has_more: false,
551
- }
552
- const sealedJob = {
553
- ...activeJob('staged/job'),
554
- definition_id: 'client-xic',
555
- metadata: { definition_id: 'client-xic', has_result: false },
556
- }
557
- const transport = vi.fn<GeneratedAnalysisTransport>()
558
- .mockResolvedValueOnce(response(manifest))
559
- .mockResolvedValueOnce(response({ sessions: [] }))
560
- .mockResolvedValueOnce(response({
561
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
562
- }))
563
- .mockResolvedValueOnce(response({ jobs: [] }))
564
- .mockResolvedValueOnce(response({ part, staging: stagingSummary }))
565
- .mockResolvedValueOnce(response(staging))
566
- .mockResolvedValueOnce(response(sealedJob))
567
- const scope = effectScope()
568
- const generated = scope.run(() => useGeneratedAnalysis({
569
- baseUrl: '/api/demo',
570
- transport,
571
- storage: memoryStorage(),
572
- createId: () => 'tab-1',
573
- stream: false,
574
- }))!
575
-
576
- try {
577
- await generated.initialize()
578
- const uploaded = await generated.uploadStagedPart({
579
- job: 'staged/job',
580
- key: 'sample one/chunk#1',
581
- file: new Blob(['xic']),
582
- metadata: { sampleIndex: 1 },
583
- expectedSize: 3,
584
- expectedSha256: 'a'.repeat(64),
585
- })
586
- const inspected = await generated.getJobStaging<{ sampleIndex: number }>(
587
- 'staged/job',
588
- { offset: 0, limit: 10 },
589
- )
590
- const sealed = await generated.sealJob('staged/job')
591
-
592
- const upload = transport.mock.calls[4]
593
- const body = upload?.[1]?.body as FormData
594
- expect({
595
- uploadUrl: upload?.[0],
596
- uploadMethod: upload?.[1]?.method,
597
- file: body.get('file'),
598
- metadata: body.get('metadata'),
599
- expectedSize: body.get('expected_size'),
600
- expectedSha256: body.get('expected_sha256'),
601
- uploadedMetadata: uploaded.part.metadata,
602
- inspectedMetadata: inspected.parts[0]?.metadata,
603
- stagingUrl: transport.mock.calls[5]?.[0],
604
- sealRequest: transport.mock.calls[6],
605
- sealedDefinition: sealed.definition_id,
606
- jobs: generated.jobs.value.map(job => job.job_id),
607
- }).toEqual({
608
- uploadUrl: '/api/demo/jobs/staged%2Fjob/parts/sample%20one/chunk%231',
609
- uploadMethod: 'PUT',
610
- file: expect.any(Blob),
611
- metadata: '{"sampleIndex":1}',
612
- expectedSize: '3',
613
- expectedSha256: 'a'.repeat(64),
614
- uploadedMetadata: { sampleIndex: 1 },
615
- inspectedMetadata: { sampleIndex: 1 },
616
- stagingUrl: '/api/demo/jobs/staged%2Fjob/staging?offset=0&limit=10',
617
- sealRequest: [
618
- '/api/demo/jobs/staged%2Fjob/seal',
619
- { method: 'POST', headers: { Accept: 'application/json' } },
620
- ],
621
- sealedDefinition: 'client-xic',
622
- jobs: ['staged/job'],
623
- })
624
- } finally {
625
- scope.stop()
626
- }
627
- })
628
-
629
- it('keeps a forward seal response after an awaiting-input snapshot bumps its revision', async () => {
630
- const awaiting = {
631
- ...activeJob('seal-race'),
632
- status: 'awaiting_input' as const,
633
- progress: {
634
- ...activeJob('seal-race').progress,
635
- message: 'Awaiting input',
636
- stage: 'awaiting_input',
637
- },
638
- }
639
- const queued = activeJob('seal-race')
640
- const sealRequest = deferred<Response>()
641
- const transport = vi.fn<GeneratedAnalysisTransport>()
642
- .mockResolvedValueOnce(response(manifest))
643
- .mockResolvedValueOnce(response({ sessions: [] }))
644
- .mockResolvedValueOnce(response({
645
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
646
- }))
647
- .mockResolvedValueOnce(response({ jobs: [awaiting] }))
648
- .mockReturnValueOnce(sealRequest.promise)
649
- .mockResolvedValueOnce(response({ jobs: [awaiting] }))
650
- const scope = effectScope()
651
- const generated = scope.run(() => useGeneratedAnalysis({
652
- baseUrl: '/api/demo',
653
- transport,
654
- storage: memoryStorage(),
655
- createId: () => 'tab-1',
656
- stream: false,
657
- }))!
658
-
659
- try {
660
- await generated.initialize()
661
- const sealing = generated.sealJob('seal-race')
662
- await vi.waitFor(() => expect(transport).toHaveBeenCalledTimes(5))
663
- await generated.refreshJobs()
664
- sealRequest.resolve(response(queued))
665
-
666
- await expect(sealing).resolves.toMatchObject({ status: 'queued' })
667
- expect(generated.jobs.value[0]?.status).toBe('queued')
668
- } finally {
669
- scope.stop()
670
- }
671
- })
672
-
673
- it('reuses a live server session after a tab reload', async () => {
674
- const storage = memoryStorage()
675
- storage.setItem('mint:generated:/api/demo:tab', 'tab-1')
676
- storage.setItem('mint:generated:/api/demo:session', 'session-1')
677
- const fetcher = vi.fn()
678
- .mockResolvedValueOnce(response(manifest))
679
- .mockResolvedValueOnce(response({
680
- sessions: [{
681
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
682
- }],
683
- }))
684
- .mockResolvedValueOnce(response({ jobs: [] }))
685
- const scope = effectScope()
686
- const generated = scope.run(() => useGeneratedAnalysis({
687
- baseUrl: '/api/demo',
688
- transport: fetcher,
689
- storage,
690
- createId: () => 'new-tab',
691
- stream: false,
692
- }))!
693
-
694
- await generated.initialize()
695
- scope.stop()
696
-
697
- expect(fetcher.mock.calls.map(call => [call[0], call[1]?.method])).toEqual([
698
- ['/api/demo/generated/manifest', 'GET'],
699
- ['/api/demo/jobs/sessions', 'GET'],
700
- ['/api/demo/jobs', 'GET'],
701
- ])
702
- })
703
-
704
- it('should recreate an expired session and retry one job with the same request id', async () => {
705
- const storage = memoryStorage()
706
- const createId = vi.fn()
707
- .mockReturnValueOnce('tab-1')
708
- .mockReturnValueOnce('request-1')
709
- const transport = vi.fn<GeneratedAnalysisTransport>()
710
- .mockResolvedValueOnce(response(manifest))
711
- .mockResolvedValueOnce(response({ sessions: [] }))
712
- .mockResolvedValueOnce(response({
713
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
714
- }))
715
- .mockResolvedValueOnce(response({ jobs: [] }))
716
- .mockResolvedValueOnce(response({ detail: 'Session not found' }, 404))
717
- .mockResolvedValueOnce(response({ sessions: [] }))
718
- .mockResolvedValueOnce(response({
719
- id: 'session-2', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
720
- }))
721
- .mockResolvedValueOnce(response({ ...activeJob('job-1'), session_id: 'session-2' }))
722
- const scope = effectScope()
723
- const generated = scope.run(() => useGeneratedAnalysis({
724
- baseUrl: '/api/demo',
725
- transport,
726
- storage,
727
- createId,
728
- stream: false,
729
- }))!
730
-
731
- try {
732
- await generated.initialize()
733
- const job = await generated.submit('run', { threshold: 2.5 })
734
- const jobBodies = transport.mock.calls
735
- .filter(call => String(call[0]).endsWith('/jobs') && call[1]?.method === 'POST')
736
- .map(call => JSON.parse(String(call[1]?.body)))
737
-
738
- expect({
739
- jobId: job.job_id,
740
- sessionId: generated.session.value?.id,
741
- storedSessionId: storage.getItem('mint:generated:/api/demo:session'),
742
- jobBodies,
743
- }).toEqual({
744
- jobId: 'job-1',
745
- sessionId: 'session-2',
746
- storedSessionId: 'session-2',
747
- jobBodies: [
748
- {
749
- definition_id: 'run',
750
- inputs: { threshold: 2.5 },
751
- session_id: 'session-1',
752
- client_request_id: 'request-1',
753
- },
754
- {
755
- definition_id: 'run',
756
- inputs: { threshold: 2.5 },
757
- session_id: 'session-2',
758
- client_request_id: 'request-1',
759
- },
760
- ],
761
- })
762
- } finally {
763
- scope.stop()
764
- }
765
- })
766
-
767
- it.each([
768
- { label: 'another 404', status: 404, detail: 'Unknown job definition' },
769
- { label: 'a server error', status: 500, detail: 'Internal server error' },
770
- ])('should not retry submission for $label', async ({ status, detail }) => {
771
- const storage = memoryStorage()
772
- const transport = vi.fn<GeneratedAnalysisTransport>()
773
- .mockResolvedValueOnce(response(manifest))
774
- .mockResolvedValueOnce(response({ sessions: [] }))
775
- .mockResolvedValueOnce(response({
776
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
777
- }))
778
- .mockResolvedValueOnce(response({ jobs: [] }))
779
- .mockResolvedValueOnce(response({ detail }, status))
780
- const scope = effectScope()
781
- const generated = scope.run(() => useGeneratedAnalysis({
782
- baseUrl: '/api/demo',
783
- transport,
784
- storage,
785
- createId: () => 'request-1',
786
- stream: false,
787
- }))!
788
- let caught: unknown
789
-
790
- try {
791
- await generated.initialize()
792
- await generated.submit('run', {})
793
- } catch (error) {
794
- caught = error
795
- } finally {
796
- scope.stop()
797
- }
798
-
799
- expect({
800
- status: (caught as { status?: number } | undefined)?.status,
801
- message: caught instanceof Error ? caught.message : null,
802
- jobPosts: transport.mock.calls.filter(call => (
803
- String(call[0]).endsWith('/jobs') && call[1]?.method === 'POST'
804
- )).length,
805
- sessionRequests: transport.mock.calls.filter(call => String(call[0]).endsWith('/sessions')).length,
806
- }).toEqual({
807
- status,
808
- message: detail,
809
- jobPosts: 1,
810
- sessionRequests: 2,
811
- })
812
- })
813
-
814
- it('should keep polling active jobs when one refresh request fails', async () => {
815
- vi.useFakeTimers()
816
- const storage = memoryStorage()
817
- const runningJob = activeJob('job-1', 'running')
818
- const fetcher = vi.fn()
819
- .mockResolvedValueOnce(response(manifest))
820
- .mockResolvedValueOnce(response({ sessions: [] }))
821
- .mockResolvedValueOnce(response({
822
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: ['job-1'],
823
- }))
824
- .mockResolvedValueOnce(response({ jobs: [runningJob] }))
825
- .mockRejectedValueOnce(new TypeError('temporary network failure'))
826
- .mockResolvedValueOnce(response({ jobs: [completedJob('job-1')] }))
827
- .mockResolvedValueOnce(response({ kind: 'text', text: 'done' }))
828
- const scope = effectScope()
829
- const generated = scope.run(() => useGeneratedAnalysis({
830
- baseUrl: '/api/demo',
831
- transport: fetcher,
832
- storage,
833
- createId: () => 'tab-1',
834
- pollInterval: 10,
835
- stream: false,
836
- }))!
837
-
838
- try {
839
- await generated.initialize()
840
- await vi.advanceTimersByTimeAsync(20)
841
-
842
- expect({
843
- status: generated.jobs.value[0]?.status,
844
- error: generated.error.value,
845
- }).toEqual({ status: 'completed', error: null })
846
- } finally {
847
- scope.stop()
848
- vi.useRealTimers()
849
- }
850
- })
851
-
852
- it('should deduplicate result loads and keep the newest result when older requests finish later', async () => {
853
- const storage = memoryStorage()
854
- const oldResult = deferred<Response>()
855
- const newResult = deferred<Response>()
856
- const oldJob = completedJob('job-old')
857
- const newJob = {
858
- ...oldJob,
859
- id: 'job-new',
860
- job_id: 'job-new',
861
- }
862
- const transport = vi.fn<GeneratedAnalysisTransport>()
863
- .mockResolvedValueOnce(response(manifest))
864
- .mockResolvedValueOnce(response({ sessions: [] }))
865
- .mockResolvedValueOnce(response({
866
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
867
- }))
868
- .mockResolvedValueOnce(response({ jobs: [] }))
869
- .mockResolvedValueOnce(response({ jobs: [oldJob] }))
870
- .mockReturnValueOnce(oldResult.promise)
871
- .mockResolvedValueOnce(response({ jobs: [newJob, oldJob] }))
872
- .mockReturnValueOnce(newResult.promise)
873
- const scope = effectScope()
874
- const generated = scope.run(() => useGeneratedAnalysis({
875
- baseUrl: '/api/demo',
876
- transport,
877
- storage,
878
- createId: () => 'tab-1',
879
- stream: false,
880
- }))!
881
-
882
- try {
883
- await generated.initialize()
884
- await generated.refreshJobs()
885
- const oldLoad = generated.loadResult(oldJob)
886
- const duplicateOldLoad = generated.loadResult(oldJob)
887
- await vi.waitFor(() => expect(transport).toHaveBeenCalledTimes(6))
888
- await generated.refreshJobs()
889
- const newLoad = generated.loadResult(newJob)
890
- await vi.waitFor(() => expect(transport).toHaveBeenCalledTimes(8))
891
-
892
- newResult.resolve(response({ kind: 'text', text: 'new' }))
893
- await newLoad
894
- oldResult.resolve(response({ kind: 'text', text: 'old' }))
895
- await oldLoad
896
- await duplicateOldLoad
897
-
898
- expect({
899
- latest: generated.latestResult.value,
900
- resultRequests: transport.mock.calls
901
- .map(call => String(call[0]))
902
- .filter(url => url.endsWith('/result')),
903
- }).toEqual({
904
- latest: { kind: 'text', text: 'new' },
905
- resultRequests: [
906
- '/api/demo/jobs/job-old/result',
907
- '/api/demo/jobs/job-new/result',
908
- ],
909
- })
910
- } finally {
911
- scope.stop()
912
- }
913
- })
914
-
915
- it('should refresh a cached managed download before its capability expires', async () => {
916
- vi.useFakeTimers()
917
- vi.setSystemTime(new Date('2026-07-21T10:00:00Z'))
918
- const completed = completedJob('managed-job')
919
- const transport = vi.fn<GeneratedAnalysisTransport>()
920
- .mockResolvedValueOnce(response(manifest))
921
- .mockResolvedValueOnce(response({ sessions: [] }))
922
- .mockResolvedValueOnce(response({
923
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
924
- }))
925
- .mockResolvedValueOnce(response({ jobs: [completed] }))
926
- .mockResolvedValueOnce(response({
927
- kind: 'artifact',
928
- id: 'artifact-1',
929
- name: 'result.bin',
930
- media_type: 'application/octet-stream',
931
- size: 6,
932
- managed: true,
933
- download_url: '/api/demo/jobs/managed-job/result/file/token-1',
934
- download_expires_at: '2026-07-21T10:05:00Z',
935
- }))
936
- .mockResolvedValueOnce(response({
937
- kind: 'artifact',
938
- id: 'artifact-1',
939
- name: 'result.bin',
940
- media_type: 'application/octet-stream',
941
- size: 6,
942
- managed: true,
943
- download_url: '/api/demo/jobs/managed-job/result/file/token-2',
944
- download_expires_at: '2026-07-21T10:09:30Z',
945
- }))
946
- const scope = effectScope()
947
- const generated = scope.run(() => useGeneratedAnalysis({
948
- baseUrl: '/api/demo',
949
- transport,
950
- storage: memoryStorage(),
951
- createId: () => 'tab-1',
952
- stream: false,
953
- }))!
954
-
955
- try {
956
- await generated.initialize()
957
- await generated.loadResult(completed)
958
- await vi.advanceTimersByTimeAsync(270_000)
959
-
960
- expect({
961
- result: generated.resultForJob('managed-job'),
962
- resultRequests: transport.mock.calls
963
- .filter(call => String(call[0]).endsWith('/result')).length,
964
- }).toMatchObject({
965
- result: {
966
- download_url: '/api/demo/jobs/managed-job/result/file/token-2',
967
- },
968
- resultRequests: 2,
969
- })
970
- } finally {
971
- scope.stop()
972
- vi.useRealTimers()
973
- }
974
- })
975
-
976
- it('should stop renewing a managed download after the result expires', async () => {
977
- vi.useFakeTimers()
978
- vi.setSystemTime(new Date('2026-07-21T10:00:00Z'))
979
- const completed = completedJob('managed-job')
980
- const transport = vi.fn<GeneratedAnalysisTransport>()
981
- .mockResolvedValueOnce(response(manifest))
982
- .mockResolvedValueOnce(response({ sessions: [] }))
983
- .mockResolvedValueOnce(response({
984
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
985
- }))
986
- .mockResolvedValueOnce(response({ jobs: [completed] }))
987
- .mockResolvedValueOnce(response({
988
- kind: 'artifact',
989
- id: 'artifact-1',
990
- name: 'result.bin',
991
- media_type: 'application/octet-stream',
992
- size: 6,
993
- managed: true,
994
- download_url: '/api/demo/jobs/managed-job/result/file/token-1',
995
- download_expires_at: '2026-07-21T10:05:00Z',
996
- }))
997
- .mockResolvedValueOnce(response({ detail: 'Job result expired' }, 410))
998
- const scope = effectScope()
999
- const generated = scope.run(() => useGeneratedAnalysis({
1000
- baseUrl: '/api/demo',
1001
- transport,
1002
- storage: memoryStorage(),
1003
- createId: () => 'tab-1',
1004
- stream: false,
1005
- }))!
1006
-
1007
- try {
1008
- await generated.initialize()
1009
- await generated.loadResult(completed)
1010
- await vi.advanceTimersByTimeAsync(270_000)
1011
- await vi.advanceTimersByTimeAsync(60_000)
1012
-
1013
- expect({
1014
- result: generated.resultForJob('managed-job'),
1015
- resultStatus: generated.jobs.value[0]?.result_status,
1016
- resultRequests: transport.mock.calls
1017
- .filter(call => String(call[0]).endsWith('/result')).length,
1018
- }).toEqual({
1019
- result: null,
1020
- resultStatus: 'expired',
1021
- resultRequests: 2,
1022
- })
1023
- } finally {
1024
- scope.stop()
1025
- vi.useRealTimers()
1026
- }
1027
- })
1028
-
1029
- it('should wait for a near-result-TTL capability to expire instead of tight-looping', async () => {
1030
- vi.useFakeTimers()
1031
- vi.setSystemTime(new Date('2026-07-21T10:00:00Z'))
1032
- const completed = completedJob('managed-job')
1033
- const transport = vi.fn<GeneratedAnalysisTransport>()
1034
- .mockResolvedValueOnce(response(manifest))
1035
- .mockResolvedValueOnce(response({ sessions: [] }))
1036
- .mockResolvedValueOnce(response({
1037
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1038
- }))
1039
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1040
- .mockResolvedValueOnce(response({
1041
- kind: 'artifact',
1042
- id: 'artifact-1',
1043
- name: 'result.bin',
1044
- media_type: 'application/octet-stream',
1045
- size: 6,
1046
- managed: true,
1047
- download_url: '/api/demo/jobs/managed-job/result/file/token-1',
1048
- download_expires_at: '2026-07-21T10:00:20Z',
1049
- }))
1050
- .mockResolvedValueOnce(response({ detail: 'Job result expired' }, 410))
1051
- const scope = effectScope()
1052
- const generated = scope.run(() => useGeneratedAnalysis({
1053
- baseUrl: '/api/demo',
1054
- transport,
1055
- storage: memoryStorage(),
1056
- createId: () => 'tab-1',
1057
- stream: false,
1058
- }))!
1059
-
1060
- try {
1061
- await generated.initialize()
1062
- await generated.loadResult(completed)
1063
- await vi.advanceTimersByTimeAsync(19_999)
1064
- expect(transport.mock.calls.filter(call => String(call[0]).endsWith('/result'))).toHaveLength(1)
1065
-
1066
- await vi.advanceTimersByTimeAsync(1)
1067
- expect(transport.mock.calls.filter(call => String(call[0]).endsWith('/result'))).toHaveLength(2)
1068
- } finally {
1069
- scope.stop()
1070
- vi.useRealTimers()
1071
- }
1072
- })
1073
-
1074
- it('should pause managed download renewal and refresh it after resume', async () => {
1075
- vi.useFakeTimers()
1076
- vi.setSystemTime(new Date('2026-07-21T10:00:00Z'))
1077
- const completed = completedJob('managed-job')
1078
- const managedResult = (token: string, expires: string) => ({
1079
- kind: 'artifact' as const,
1080
- id: 'artifact-1',
1081
- name: 'result.bin',
1082
- media_type: 'application/octet-stream',
1083
- size: 6,
1084
- managed: true,
1085
- download_url: `/api/demo/jobs/managed-job/result/file/${token}`,
1086
- download_expires_at: expires,
1087
- })
1088
- const transport = vi.fn<GeneratedAnalysisTransport>()
1089
- .mockResolvedValueOnce(response(manifest))
1090
- .mockResolvedValueOnce(response({ sessions: [] }))
1091
- .mockResolvedValueOnce(response({
1092
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1093
- }))
1094
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1095
- .mockResolvedValueOnce(response(managedResult('token-1', '2026-07-21T10:05:00Z')))
1096
- .mockResolvedValueOnce(response(managedResult('token-2', '2026-07-21T10:10:01Z')))
1097
- const scope = effectScope()
1098
- const generated = scope.run(() => useGeneratedAnalysis({
1099
- baseUrl: '/api/demo',
1100
- transport,
1101
- storage: memoryStorage(),
1102
- createId: () => 'tab-1',
1103
- stream: false,
1104
- }))!
1105
-
1106
- try {
1107
- await generated.initialize()
1108
- await generated.loadResult(completed)
1109
- generated.pause()
1110
- await vi.advanceTimersByTimeAsync(301_000)
1111
- expect(transport.mock.calls.filter(call => String(call[0]).endsWith('/result'))).toHaveLength(1)
1112
-
1113
- generated.resume()
1114
- await vi.advanceTimersByTimeAsync(0)
1115
-
1116
- expect(generated.resultForJob('managed-job')).toMatchObject({
1117
- download_url: '/api/demo/jobs/managed-job/result/file/token-2',
1118
- })
1119
- } finally {
1120
- scope.stop()
1121
- vi.useRealTimers()
1122
- }
1123
- })
1124
-
1125
- it('should retry a transient result failure and surface the loading error', async () => {
1126
- vi.useFakeTimers()
1127
- const storage = memoryStorage()
1128
- const completed = completedJob('job-1')
1129
- const transport = vi.fn<GeneratedAnalysisTransport>()
1130
- .mockResolvedValueOnce(response(manifest))
1131
- .mockResolvedValueOnce(response({ sessions: [] }))
1132
- .mockResolvedValueOnce(response({
1133
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1134
- }))
1135
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1136
- .mockRejectedValueOnce(new TypeError('temporary result failure'))
1137
- .mockResolvedValueOnce(response({ kind: 'text', text: 'recovered' }))
1138
- const scope = effectScope()
1139
- const generated = scope.run(() => useGeneratedAnalysis({
1140
- baseUrl: '/api/demo',
1141
- transport,
1142
- storage,
1143
- createId: () => 'tab-1',
1144
- pollInterval: 10,
1145
- stream: false,
1146
- }))!
1147
-
1148
- try {
1149
- await generated.initialize()
1150
- await generated.loadResult(completed)
1151
-
1152
- expect(generated.error.value).toBe('temporary result failure')
1153
-
1154
- await vi.advanceTimersByTimeAsync(10)
1155
-
1156
- expect({
1157
- result: generated.resultForJob('job-1'),
1158
- error: generated.error.value,
1159
- resultRequests: transport.mock.calls.filter(call => String(call[0]).endsWith('/result')).length,
1160
- }).toEqual({
1161
- result: { kind: 'text', text: 'recovered' },
1162
- error: null,
1163
- resultRequests: 2,
1164
- })
1165
- } finally {
1166
- scope.stop()
1167
- vi.useRealTimers()
1168
- }
1169
- })
1170
-
1171
- it('should load a visible completed result from another session', async () => {
1172
- const storage = memoryStorage()
1173
- const sharedJob = {
1174
- ...completedJob('shared-job'),
1175
- session_id: 'another-session',
1176
- }
1177
- const transport = vi.fn<GeneratedAnalysisTransport>()
1178
- .mockResolvedValueOnce(response(manifest))
1179
- .mockResolvedValueOnce(response({ sessions: [] }))
1180
- .mockResolvedValueOnce(response({
1181
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1182
- }))
1183
- .mockResolvedValueOnce(response({ jobs: [sharedJob] }))
1184
- .mockResolvedValueOnce(response({ kind: 'text', text: 'shared' }))
1185
- const scope = effectScope()
1186
- const generated = scope.run(() => useGeneratedAnalysis({
1187
- baseUrl: '/api/demo',
1188
- transport,
1189
- storage,
1190
- createId: () => 'tab-1',
1191
- stream: false,
1192
- }))!
1193
-
1194
- try {
1195
- await generated.initialize()
1196
- const result = await generated.loadResult(sharedJob)
1197
-
1198
- expect(result).toEqual({ kind: 'text', text: 'shared' })
1199
- } finally {
1200
- scope.stop()
1201
- }
1202
- })
1203
-
1204
- it('should clear exhausted retry state after a job leaves the visible list', async () => {
1205
- vi.useFakeTimers()
1206
- const storage = memoryStorage()
1207
- const completed = completedJob('retry-job')
1208
- const transport = vi.fn<GeneratedAnalysisTransport>()
1209
- .mockResolvedValueOnce(response(manifest))
1210
- .mockResolvedValueOnce(response({ sessions: [] }))
1211
- .mockResolvedValueOnce(response({
1212
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1213
- }))
1214
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1215
- .mockRejectedValueOnce(new TypeError('failure-1'))
1216
- .mockRejectedValueOnce(new TypeError('failure-2'))
1217
- .mockRejectedValueOnce(new TypeError('failure-3'))
1218
- .mockRejectedValueOnce(new TypeError('failure-4'))
1219
- .mockResolvedValueOnce(response({ jobs: [] }))
1220
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1221
- .mockRejectedValueOnce(new TypeError('failure-after-return'))
1222
- .mockResolvedValueOnce(response({ kind: 'text', text: 'recovered' }))
1223
- const scope = effectScope()
1224
- const generated = scope.run(() => useGeneratedAnalysis({
1225
- baseUrl: '/api/demo',
1226
- transport,
1227
- storage,
1228
- createId: () => 'tab-1',
1229
- pollInterval: 10,
1230
- stream: false,
1231
- }))!
1232
-
1233
- try {
1234
- await generated.initialize()
1235
- await generated.loadResult(completed)
1236
- await vi.advanceTimersByTimeAsync(70)
1237
- await generated.refreshJobs()
1238
- await generated.refreshJobs()
1239
- await generated.loadResult(completed)
1240
- await vi.advanceTimersByTimeAsync(10)
1241
-
1242
- expect(generated.resultForJob('retry-job')).toEqual({
1243
- kind: 'text',
1244
- text: 'recovered',
1245
- })
1246
- } finally {
1247
- scope.stop()
1248
- vi.useRealTimers()
1249
- }
1250
- })
1251
-
1252
- it('should retain at most thirty-two lazily loaded results', async () => {
1253
- const storage = memoryStorage()
1254
- const completedJobs = Array.from(
1255
- { length: 33 },
1256
- (_, index) => completedJob(`job-${index}`),
1257
- )
1258
- const transport = vi.fn<GeneratedAnalysisTransport>()
1259
- .mockResolvedValueOnce(response(manifest))
1260
- .mockResolvedValueOnce(response({ sessions: [] }))
1261
- .mockResolvedValueOnce(response({
1262
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1263
- }))
1264
- .mockResolvedValueOnce(response({ jobs: completedJobs }))
1265
- .mockImplementation(async input => response({ kind: 'text', text: String(input) }))
1266
- const scope = effectScope()
1267
- const generated = scope.run(() => useGeneratedAnalysis({
1268
- baseUrl: '/api/demo',
1269
- transport,
1270
- storage,
1271
- createId: () => 'tab-1',
1272
- stream: false,
1273
- }))!
1274
-
1275
- try {
1276
- await generated.initialize()
1277
- for (const job of completedJobs) await generated.loadResult(job)
1278
-
1279
- expect({
1280
- evicted: generated.resultForJob('job-0'),
1281
- retained: generated.resultForJob('job-32'),
1282
- }).toEqual({
1283
- evicted: null,
1284
- retained: {
1285
- kind: 'text',
1286
- text: '/api/demo/jobs/job-32/result',
1287
- },
1288
- })
1289
- } finally {
1290
- scope.stop()
1291
- }
1292
- })
1293
-
1294
- it('waits for a terminal refresh and supports immediate terminal results', async () => {
1295
- const queued = activeJob('wait-job')
1296
- const running = activeJob('wait-job', 'running')
1297
- const completed = completedJob('wait-job')
1298
- const transport = vi.fn<GeneratedAnalysisTransport>()
1299
- .mockResolvedValueOnce(response(manifest))
1300
- .mockResolvedValueOnce(response({ sessions: [] }))
1301
- .mockResolvedValueOnce(response({
1302
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1303
- }))
1304
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1305
- .mockResolvedValueOnce(response(running))
1306
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1307
- const scope = effectScope()
1308
- const generated = scope.run(() => useGeneratedAnalysis({
1309
- baseUrl: '/api/demo',
1310
- transport,
1311
- storage: memoryStorage(),
1312
- createId: () => 'tab-1',
1313
- pollInterval: 60_000,
1314
- stream: false,
1315
- }))!
1316
-
1317
- try {
1318
- await generated.initialize()
1319
- const waiting = generated.waitForJob('wait-job')
1320
- await vi.waitFor(() => expect(generated.jobs.value[0]?.status).toBe('running'))
1321
- await generated.refreshJobs()
1322
-
1323
- await expect(waiting).resolves.toMatchObject({
1324
- job_id: 'wait-job',
1325
- status: 'completed',
1326
- })
1327
- await expect(generated.waitForJob(completed)).resolves.toEqual(completed)
1328
- expect(transport).toHaveBeenCalledTimes(6)
1329
- } finally {
1330
- scope.stop()
1331
- }
1332
- })
1333
-
1334
- it('can reject failed jobs and pre-aborted waits without requesting the job', async () => {
1335
- const failed = {
1336
- ...activeJob('failed-job'),
1337
- status: 'failed' as const,
1338
- error: 'analysis exploded',
1339
- completed_at: '2026-07-21T00:00:00Z',
1340
- can_cancel: false,
1341
- can_delete: true,
1342
- }
1343
- const transport = vi.fn<GeneratedAnalysisTransport>()
1344
- .mockResolvedValueOnce(response(manifest))
1345
- .mockResolvedValueOnce(response({ sessions: [] }))
1346
- .mockResolvedValueOnce(response({
1347
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1348
- }))
1349
- .mockResolvedValueOnce(response({ jobs: [failed] }))
1350
- const scope = effectScope()
1351
- const generated = scope.run(() => useGeneratedAnalysis({
1352
- baseUrl: '/api/demo',
1353
- transport,
1354
- storage: memoryStorage(),
1355
- createId: () => 'tab-1',
1356
- stream: false,
1357
- }))!
1358
-
1359
- try {
1360
- await generated.initialize()
1361
- await expect(generated.waitForJob(failed)).resolves.toMatchObject({ status: 'failed' })
1362
- await expect(generated.waitForJob(failed, { rejectOnFailure: true }))
1363
- .rejects.toThrow('analysis exploded')
1364
-
1365
- const controller = new AbortController()
1366
- controller.abort()
1367
- await expect(generated.waitForJob(failed, { signal: controller.signal }))
1368
- .rejects.toMatchObject({ name: 'AbortError' })
1369
- expect(transport).toHaveBeenCalledTimes(4)
1370
- } finally {
1371
- scope.stop()
1372
- }
1373
- })
1374
-
1375
- it('removes an aborted waiter before a late job response arrives', async () => {
1376
- const queued = activeJob('abort-job')
1377
- const jobRequest = deferred<Response>()
1378
- const transport = vi.fn<GeneratedAnalysisTransport>()
1379
- .mockResolvedValueOnce(response(manifest))
1380
- .mockResolvedValueOnce(response({ sessions: [] }))
1381
- .mockResolvedValueOnce(response({
1382
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1383
- }))
1384
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1385
- .mockReturnValueOnce(jobRequest.promise)
1386
- const scope = effectScope()
1387
- const generated = scope.run(() => useGeneratedAnalysis({
1388
- baseUrl: '/api/demo',
1389
- transport,
1390
- storage: memoryStorage(),
1391
- createId: () => 'tab-1',
1392
- pollInterval: 60_000,
1393
- stream: false,
1394
- }))!
1395
-
1396
- try {
1397
- await generated.initialize()
1398
- const controller = new AbortController()
1399
- const waiting = generated.waitForJob('abort-job', { signal: controller.signal })
1400
- expect(transport.mock.calls[4]?.[1]?.signal).toBe(controller.signal)
1401
- controller.abort()
1402
-
1403
- await expect(waiting).rejects.toMatchObject({ name: 'AbortError' })
1404
- jobRequest.resolve(response(completedJob('abort-job')))
1405
- await vi.waitFor(() => expect(generated.jobs.value[0]?.status).toBe('completed'))
1406
- } finally {
1407
- scope.stop()
1408
- }
1409
- })
1410
-
1411
- it('keeps a known active waiter through a transient lookup failure', async () => {
1412
- const queued = activeJob('retry-wait-job')
1413
- const completed = completedJob('retry-wait-job')
1414
- const transport = vi.fn<GeneratedAnalysisTransport>()
1415
- .mockResolvedValueOnce(response(manifest))
1416
- .mockResolvedValueOnce(response({ sessions: [] }))
1417
- .mockResolvedValueOnce(response({
1418
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1419
- }))
1420
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1421
- .mockResolvedValueOnce(response({ detail: 'temporarily unavailable' }, 503))
1422
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1423
- const scope = effectScope()
1424
- const generated = scope.run(() => useGeneratedAnalysis({
1425
- baseUrl: '/api/demo',
1426
- transport,
1427
- storage: memoryStorage(),
1428
- createId: () => 'tab-1',
1429
- pollInterval: 60_000,
1430
- stream: false,
1431
- }))!
1432
-
1433
- try {
1434
- await generated.initialize()
1435
- const waiting = generated.waitForJob('retry-wait-job')
1436
- await vi.waitFor(() => expect(transport).toHaveBeenCalledTimes(5))
1437
- await generated.refreshJobs()
1438
- await expect(waiting).resolves.toMatchObject({
1439
- job_id: 'retry-wait-job',
1440
- status: 'completed',
1441
- })
1442
- } finally {
1443
- scope.stop()
1444
- }
1445
- })
1446
-
1447
- it('rejects an active wait immediately while background updates are paused', async () => {
1448
- const queued = activeJob('paused-wait-job')
1449
- const transport = vi.fn<GeneratedAnalysisTransport>()
1450
- .mockResolvedValueOnce(response(manifest))
1451
- .mockResolvedValueOnce(response({ sessions: [] }))
1452
- .mockResolvedValueOnce(response({
1453
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1454
- }))
1455
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1456
- const scope = effectScope()
1457
- const generated = scope.run(() => useGeneratedAnalysis({
1458
- baseUrl: '/api/demo',
1459
- transport,
1460
- storage: memoryStorage(),
1461
- createId: () => 'tab-1',
1462
- stream: false,
1463
- }))!
1464
-
1465
- try {
1466
- await generated.initialize()
1467
- generated.pause()
1468
- await expect(generated.waitForJob('paused-wait-job')).rejects.toThrow(
1469
- 'Plugin jobs runtime is paused',
1470
- )
1471
- expect(transport).toHaveBeenCalledTimes(4)
1472
- } finally {
1473
- scope.stop()
1474
- }
1475
- })
1476
-
1477
- it('rejects pending waiters when their job is deleted or the runtime is disposed', async () => {
1478
- const queued = activeJob('delete-wait-job')
1479
- const disposeJobRequest = deferred<Response>()
1480
- const transport = vi.fn<GeneratedAnalysisTransport>()
1481
- .mockResolvedValueOnce(response(manifest))
1482
- .mockResolvedValueOnce(response({ sessions: [] }))
1483
- .mockResolvedValueOnce(response({
1484
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1485
- }))
1486
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1487
- .mockResolvedValueOnce(response(queued))
1488
- .mockResolvedValueOnce(response({ status: 'deleted' }))
1489
- .mockReturnValueOnce(disposeJobRequest.promise)
1490
- const scope = effectScope()
1491
- const generated = scope.run(() => useGeneratedAnalysis({
1492
- baseUrl: '/api/demo',
1493
- transport,
1494
- storage: memoryStorage(),
1495
- createId: () => 'tab-1',
1496
- pollInterval: 60_000,
1497
- stream: false,
1498
- }))!
1499
-
1500
- await generated.initialize()
1501
- const deletedWait = generated.waitForJob('delete-wait-job')
1502
- await vi.waitFor(() => expect(transport).toHaveBeenCalledTimes(5))
1503
- await generated.deleteJob('delete-wait-job')
1504
- await expect(deletedWait).rejects.toThrow('was deleted')
1505
-
1506
- const disposeWait = generated.waitForJob(activeJob('dispose-wait-job'))
1507
- scope.stop()
1508
- await expect(disposeWait).rejects.toThrow('runtime is disposed')
1509
- disposeJobRequest.resolve(response(activeJob('dispose-wait-job')))
1510
- })
1511
-
1512
- it('coalesces initialization and refreshes, then disposes idempotently', async () => {
1513
- const manifestRequest = deferred<Response>()
1514
- const refreshRequest = deferred<Response>()
1515
- const transport = vi.fn<GeneratedAnalysisTransport>()
1516
- .mockReturnValueOnce(manifestRequest.promise)
1517
- .mockResolvedValueOnce(response({ sessions: [] }))
1518
- .mockResolvedValueOnce(response({
1519
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1520
- }))
1521
- .mockResolvedValueOnce(response({ jobs: [] }))
1522
- .mockReturnValueOnce(refreshRequest.promise)
1523
- const scope = effectScope()
1524
- const generated = scope.run(() => useGeneratedAnalysis({
1525
- baseUrl: '/api/demo',
1526
- transport,
1527
- storage: memoryStorage(),
1528
- createId: () => 'tab-1',
1529
- stream: false,
1530
- }))!
1531
-
1532
- const firstInitialize = generated.initialize()
1533
- const secondInitialize = generated.ready()
1534
- expect(firstInitialize).toBe(secondInitialize)
1535
- manifestRequest.resolve(response(manifest))
1536
- await firstInitialize
1537
-
1538
- const firstRefresh = generated.refreshJobs()
1539
- const secondRefresh = generated.refresh()
1540
- expect(firstRefresh).toBe(secondRefresh)
1541
- refreshRequest.resolve(response({ jobs: [completedJob('coalesced')] }))
1542
- await firstRefresh
1543
-
1544
- generated.dispose()
1545
- generated.dispose()
1546
- scope.stop()
1547
-
1548
- expect({
1549
- status: generated.status.value,
1550
- requests: transport.mock.calls.length,
1551
- filtered: generated.jobsFor('run').map(job => job.job_id),
1552
- }).toEqual({
1553
- status: 'disposed',
1554
- requests: 5,
1555
- filtered: ['coalesced'],
1556
- })
1557
- await expect(generated.initialize()).rejects.toThrow('disposed')
1558
- })
1559
-
1560
- it('does not let a late list response overwrite a newer canonical job update', async () => {
1561
- const staleRefresh = deferred<Response>()
1562
- const queued = activeJob('live-job')
1563
- const completed = completedJob('live-job')
1564
- const transport = vi.fn<GeneratedAnalysisTransport>()
1565
- .mockResolvedValueOnce(response(manifest))
1566
- .mockResolvedValueOnce(response({ sessions: [] }))
1567
- .mockResolvedValueOnce(response({
1568
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1569
- }))
1570
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1571
- .mockReturnValueOnce(staleRefresh.promise)
1572
- .mockResolvedValueOnce(response(completed))
1573
- const scope = effectScope()
1574
- const generated = scope.run(() => useGeneratedAnalysis({
1575
- baseUrl: '/api/demo',
1576
- transport,
1577
- storage: memoryStorage(),
1578
- createId: () => 'tab-1',
1579
- stream: false,
1580
- }))!
1581
-
1582
- try {
1583
- await generated.initialize()
1584
- const refresh = generated.refreshJobs()
1585
- await generated.getJob('live-job')
1586
- staleRefresh.resolve(response({ jobs: [queued] }))
1587
- await refresh
1588
-
1589
- expect(generated.jobs.value[0]?.status).toBe('completed')
1590
- } finally {
1591
- scope.stop()
1592
- }
1593
- })
1594
-
1595
- it('should keep polling when a stale list response overlaps an active job lookup', async () => {
1596
- vi.useFakeTimers()
1597
- const queued = activeJob('live-job')
1598
- const running = activeJob('live-job', 'running')
1599
- const completed = completedJob('live-job')
1600
- const jobRequest = deferred<Response>()
1601
- const staleRefresh = deferred<Response>()
1602
- const transport = vi.fn<GeneratedAnalysisTransport>()
1603
- .mockResolvedValueOnce(response(manifest))
1604
- .mockResolvedValueOnce(response({ sessions: [] }))
1605
- .mockResolvedValueOnce(response({
1606
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1607
- }))
1608
- .mockResolvedValueOnce(response({ jobs: [queued] }))
1609
- .mockReturnValueOnce(jobRequest.promise)
1610
- .mockReturnValueOnce(staleRefresh.promise)
1611
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1612
- const scope = effectScope()
1613
- const generated = scope.run(() => useGeneratedAnalysis({
1614
- baseUrl: '/api/demo',
1615
- transport,
1616
- storage: memoryStorage(),
1617
- createId: () => 'tab-1',
1618
- pollInterval: 10,
1619
- stream: false,
1620
- }))!
1621
- let waiting: Promise<GeneratedAnalysisJob> | undefined
1622
-
1623
- try {
1624
- await generated.initialize()
1625
- waiting = generated.waitForJob('live-job')
1626
- void waiting.catch(() => undefined)
1627
-
1628
- vi.advanceTimersByTime(10)
1629
- await vi.waitFor(() => {
1630
- if (transport.mock.calls.length !== 6) throw new Error('Concurrent job requests did not start')
1631
- })
1632
- jobRequest.resolve(response(running))
1633
- await vi.waitFor(() => {
1634
- if (generated.jobs.value[0]?.status !== 'running') throw new Error('Job lookup did not resolve')
1635
- })
1636
- staleRefresh.resolve(response({ jobs: [running] }))
1637
- await vi.advanceTimersByTimeAsync(10)
1638
- await vi.waitFor(() => {
1639
- if (transport.mock.calls.length !== 7) throw new Error('Next list poll was not scheduled')
1640
- })
1641
-
1642
- await expect(waiting).resolves.toMatchObject({
1643
- job_id: 'live-job',
1644
- status: 'completed',
1645
- })
1646
- } finally {
1647
- scope.stop()
1648
- await waiting?.catch(() => undefined)
1649
- vi.useRealTimers()
1650
- }
1651
- })
1652
-
1653
- it('does not regress a terminal job when a stale snapshot arrives without a concurrent update', async () => {
1654
- const completed = completedJob('terminal-job')
1655
- const staleQueued = activeJob('terminal-job')
1656
- const transport = vi.fn<GeneratedAnalysisTransport>()
1657
- .mockResolvedValueOnce(response(manifest))
1658
- .mockResolvedValueOnce(response({ sessions: [] }))
1659
- .mockResolvedValueOnce(response({
1660
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1661
- }))
1662
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1663
- .mockResolvedValueOnce(response({ jobs: [staleQueued] }))
1664
- const scope = effectScope()
1665
- const generated = scope.run(() => useGeneratedAnalysis({
1666
- baseUrl: '/api/demo',
1667
- transport,
1668
- storage: memoryStorage(),
1669
- createId: () => 'tab-1',
1670
- stream: false,
1671
- }))!
1672
-
1673
- try {
1674
- await generated.initialize()
1675
- await generated.refreshJobs()
1676
-
1677
- expect(generated.jobs.value[0]?.status).toBe('completed')
1678
- } finally {
1679
- scope.stop()
1680
- }
1681
- })
1682
-
1683
- it('initializes and lists jobs only once when refresh is the first operation', async () => {
1684
- const transport = vi.fn<GeneratedAnalysisTransport>()
1685
- .mockResolvedValueOnce(response(manifest))
1686
- .mockResolvedValueOnce(response({ sessions: [] }))
1687
- .mockResolvedValueOnce(response({
1688
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1689
- }))
1690
- .mockResolvedValueOnce(response({ jobs: [completedJob('initial-refresh')] }))
1691
- const scope = effectScope()
1692
- const generated = scope.run(() => useGeneratedAnalysis({
1693
- baseUrl: '/api/demo',
1694
- transport,
1695
- storage: memoryStorage(),
1696
- createId: () => 'tab-1',
1697
- stream: false,
1698
- }))!
1699
-
1700
- try {
1701
- const firstRefresh = generated.refresh()
1702
- const secondRefresh = generated.refresh()
1703
- expect(firstRefresh).toBe(secondRefresh)
1704
- const jobs = await firstRefresh
1705
-
1706
- expect(jobs.map(job => job.job_id)).toEqual(['initial-refresh'])
1707
- expect(transport).toHaveBeenCalledTimes(4)
1708
- expect(transport.mock.calls.filter(([url]) => url === '/api/demo/jobs')).toHaveLength(1)
1709
- } finally {
1710
- scope.stop()
1711
- }
1712
- })
1713
-
1714
- it('cancels one active job through the generated runtime', async () => {
1715
- const running = {
1716
- ...activeJob('cancel-me', 'running'),
1717
- }
1718
- const cancelled = {
1719
- ...running,
1720
- status: 'cancelled' as const,
1721
- completed_at: '2026-07-21T00:00:00Z',
1722
- can_cancel: false,
1723
- can_delete: true,
1724
- }
1725
- const transport = vi.fn<GeneratedAnalysisTransport>()
1726
- .mockResolvedValueOnce(response(manifest))
1727
- .mockResolvedValueOnce(response({ sessions: [] }))
1728
- .mockResolvedValueOnce(response({
1729
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1730
- }))
1731
- .mockResolvedValueOnce(response({ jobs: [running] }))
1732
- .mockResolvedValueOnce(response(cancelled))
1733
- const scope = effectScope()
1734
- const generated = scope.run(() => useGeneratedAnalysis({
1735
- baseUrl: '/api/demo',
1736
- transport,
1737
- storage: memoryStorage(),
1738
- createId: () => 'tab-1',
1739
- stream: false,
1740
- }))!
1741
-
1742
- try {
1743
- await generated.initialize()
1744
- const updated = await generated.cancelJob('cancel-me')
1745
-
1746
- expect({
1747
- updated,
1748
- jobs: generated.jobs.value,
1749
- request: transport.mock.calls[4]?.slice(0, 2),
1750
- }).toEqual({
1751
- updated: cancelled,
1752
- jobs: [cancelled],
1753
- request: [
1754
- '/api/demo/jobs/cancel-me/cancel',
1755
- { method: 'POST', headers: { Accept: 'application/json' } },
1756
- ],
1757
- })
1758
- } finally {
1759
- scope.stop()
1760
- }
1761
- })
1762
-
1763
- it('canonicalizes legacy job payloads and fetches one job without refreshing the list', async () => {
1764
- const {
1765
- definition_id: _activeDefinitionId,
1766
- can_cancel: _activeCanCancel,
1767
- can_delete: _activeCanDelete,
1768
- result_status: _activeResultStatus,
1769
- result_expires_at: _activeResultExpiresAt,
1770
- ...legacyActive
1771
- } = activeJob('legacy-active', 'running')
1772
- legacyActive.progress = { ...legacyActive.progress, percent: 140 }
1773
- const {
1774
- definition_id: _completedDefinitionId,
1775
- can_cancel: _completedCanCancel,
1776
- can_delete: _completedCanDelete,
1777
- result_status: _completedResultStatus,
1778
- result_expires_at: _completedResultExpiresAt,
1779
- ...legacyCompleted
1780
- } = completedJob('legacy-completed')
1781
- const transport = vi.fn<GeneratedAnalysisTransport>()
1782
- .mockResolvedValueOnce(response(manifest))
1783
- .mockResolvedValueOnce(response({ sessions: [] }))
1784
- .mockResolvedValueOnce(response({
1785
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1786
- }))
1787
- .mockResolvedValueOnce(response({ jobs: [legacyActive] }))
1788
- .mockResolvedValueOnce(response(legacyCompleted))
1789
- const scope = effectScope()
1790
- const generated = scope.run(() => useGeneratedAnalysis({
1791
- baseUrl: '/api/demo',
1792
- transport,
1793
- storage: memoryStorage(),
1794
- createId: () => 'tab-1',
1795
- stream: false,
1796
- }))!
1797
-
1798
- try {
1799
- await generated.initialize()
1800
- const fetched = await generated.getJob('legacy-completed')
1801
-
1802
- expect(generated.jobs.value[1]).toMatchObject({
1803
- job_id: 'legacy-active',
1804
- definition_id: 'run',
1805
- can_cancel: true,
1806
- can_delete: false,
1807
- result_status: 'none',
1808
- progress: { percent: 100 },
1809
- })
1810
- expect(fetched).toMatchObject({
1811
- job_id: 'legacy-completed',
1812
- definition_id: 'run',
1813
- can_cancel: false,
1814
- can_delete: true,
1815
- result_status: 'available',
1816
- })
1817
- expect(generated.jobs.value[0]).toBe(fetched)
1818
- expect(transport.mock.calls[4]?.slice(0, 2)).toEqual([
1819
- '/api/demo/jobs/legacy-completed',
1820
- { method: 'GET', headers: { Accept: 'application/json' } },
1821
- ])
1822
- } finally {
1823
- scope.stop()
1824
- }
1825
- })
1826
-
1827
- it('deletes one finished job through the generated runtime', async () => {
1828
- const completed = completedJob('delete-me')
1829
- const transport = vi.fn<GeneratedAnalysisTransport>()
1830
- .mockResolvedValueOnce(response(manifest))
1831
- .mockResolvedValueOnce(response({ sessions: [] }))
1832
- .mockResolvedValueOnce(response({
1833
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1834
- }))
1835
- .mockResolvedValueOnce(response({ jobs: [completed] }))
1836
- .mockResolvedValueOnce(response({ status: 'deleted' }))
1837
- const scope = effectScope()
1838
- const generated = scope.run(() => useGeneratedAnalysis({
1839
- baseUrl: '/api/demo',
1840
- transport,
1841
- storage: memoryStorage(),
1842
- createId: () => 'tab-1',
1843
- stream: false,
1844
- }))!
1845
-
1846
- try {
1847
- await generated.initialize()
1848
- const deleted = await generated.deleteJob(completed)
1849
-
1850
- expect({
1851
- deleted,
1852
- jobs: generated.jobs.value,
1853
- request: transport.mock.calls[4]?.slice(0, 2),
1854
- }).toEqual({
1855
- deleted: true,
1856
- jobs: [],
1857
- request: ['/api/demo/jobs/delete-me', { method: 'DELETE', headers: { Accept: 'application/json' } }],
1858
- })
1859
- } finally {
1860
- scope.stop()
1861
- }
1862
- })
1863
-
1864
- it('clears finished jobs for one definition without clearing other definitions', async () => {
1865
- const runJob = completedJob('clear-run')
1866
- const otherJob = {
1867
- ...completedJob('keep-other'),
1868
- definition_id: 'other',
1869
- metadata: { definition_id: 'other', has_result: true },
1870
- }
1871
- const transport = vi.fn<GeneratedAnalysisTransport>()
1872
- .mockResolvedValueOnce(response(manifest))
1873
- .mockResolvedValueOnce(response({ sessions: [] }))
1874
- .mockResolvedValueOnce(response({
1875
- id: 'session-1', tab_id: 'tab-1', created_at: '', last_seen_at: '', active_job_ids: [],
1876
- }))
1877
- .mockResolvedValueOnce(response({ jobs: [runJob, otherJob] }))
1878
- .mockResolvedValueOnce(response({ deleted: 1 }))
1879
- .mockResolvedValueOnce(response({ jobs: [otherJob] }))
1880
- const scope = effectScope()
1881
- const generated = scope.run(() => useGeneratedAnalysis({
1882
- baseUrl: '/api/demo',
1883
- transport,
1884
- storage: memoryStorage(),
1885
- createId: () => 'tab-1',
1886
- stream: false,
1887
- }))!
1888
-
1889
- try {
1890
- await generated.initialize()
1891
- const deleted = await generated.clearFinishedJobs('run')
1892
-
1893
- expect(deleted).toBe(1)
1894
- expect(generated.jobs.value.map(job => job.job_id)).toEqual(['keep-other'])
1895
- expect(transport.mock.calls[4]?.slice(0, 2)).toEqual([
1896
- '/api/demo/jobs?definition_id=run',
1897
- { method: 'DELETE', headers: { Accept: 'application/json' } },
1898
- ])
1899
- } finally {
1900
- scope.stop()
1901
- }
1902
- })
1903
- })