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

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 (408) hide show
  1. package/README.md +35 -5
  2. package/dist/{ExperimentPopover-tLwJ7XF4.js → ExperimentPopover-oL0fg_A0.js} +6 -4
  3. package/dist/ExperimentPopover-oL0fg_A0.js.map +1 -0
  4. package/dist/{ExperimentSelectorModal-DyPAUCLw.js → ExperimentSelectorModal-BeEOomw_.js} +5 -5
  5. package/dist/ExperimentSelectorModal-BeEOomw_.js.map +1 -0
  6. package/dist/{SettingsModal-BgKY93zh.js → SettingsModal-Dphh3RrI.js} +5 -8
  7. package/dist/SettingsModal-Dphh3RrI.js.map +1 -0
  8. package/dist/{EmptyState-p90quq8Z.js → Skeleton-DxtwJ5gt.js} +111 -93
  9. package/dist/Skeleton-DxtwJ5gt.js.map +1 -0
  10. package/dist/__tests__/components/ExperimentTimeline.test.d.ts +1 -0
  11. package/dist/__tests__/components/PluginWorkspaceView.internal.test.d.ts +1 -0
  12. package/dist/__tests__/components/SecretInput.test.d.ts +1 -0
  13. package/dist/__tests__/components/WellEditPopupInternal.test.d.ts +1 -0
  14. package/dist/__tests__/composables/useListReorder.test.d.ts +1 -0
  15. package/dist/__tests__/composables/usePluginConfig.test.d.ts +15 -0
  16. package/dist/__tests__/styles/cssTokens.test.d.ts +1 -0
  17. package/dist/components/ActionMenu.vue.d.ts +1 -1
  18. package/dist/components/AppAvatarMenu.vue.d.ts +4 -0
  19. package/dist/components/AppPluginSwitcher.vue.d.ts +2 -0
  20. package/dist/components/AppSidebar.vue.d.ts +1 -1
  21. package/dist/components/AuditTrail.vue.d.ts +13 -0
  22. package/dist/components/AutoGroupModal.vue.d.ts +1 -1
  23. package/dist/components/BatchProgressList.vue.d.ts +17 -0
  24. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  25. package/dist/components/DataFrame.vue.d.ts +14 -2
  26. package/dist/components/DatePicker.vue.d.ts +1 -1
  27. package/dist/components/DateTimePicker.vue.d.ts +2 -0
  28. package/dist/components/DropdownButton.vue.d.ts +2 -0
  29. package/dist/components/ExperimentDataViewer.vue.d.ts +26 -1
  30. package/dist/components/ExperimentPopover.vue.d.ts +1 -0
  31. package/dist/components/ExperimentTimeline.vue.d.ts +29 -1
  32. package/dist/components/FitPanel.vue.d.ts +1 -1
  33. package/dist/components/JobsStatusTray.vue.d.ts +9 -2
  34. package/dist/components/LcmsSequenceTable.vue.d.ts +29 -1
  35. package/dist/components/PluginWorkspaceView.props.d.ts +29 -1
  36. package/dist/components/PluginWorkspaceView.vue.d.ts +5 -5
  37. package/dist/components/ProgressBar.vue.d.ts +1 -1
  38. package/dist/components/ProtocolStepEditor.vue.d.ts +1 -0
  39. package/dist/components/ReagentList.vue.d.ts +29 -1
  40. package/dist/components/SampleHierarchyTree.vue.d.ts +29 -1
  41. package/dist/components/SampleLegend.vue.d.ts +1 -1
  42. package/dist/components/SampleSelector.drag.d.ts +13 -0
  43. package/dist/components/SampleSelector.tree.d.ts +2 -0
  44. package/dist/components/SampleSelector.vue.d.ts +35 -2
  45. package/dist/components/ScheduleCalendar.vue.d.ts +20 -0
  46. package/dist/components/SecretInput.vue.d.ts +28 -0
  47. package/dist/components/SettingsModal.vue.d.ts +1 -1
  48. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -1
  49. package/dist/components/TimePicker.vue.d.ts +1 -0
  50. package/dist/components/WellPlate.geometry.d.ts +15 -0
  51. package/dist/components/WellPlate.interaction.d.ts +13 -0
  52. package/dist/components/WellPlate.vue.d.ts +29 -0
  53. package/dist/components/index.d.ts +9 -0
  54. package/dist/components/index.js +8 -8
  55. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -0
  56. package/dist/components/internal/DataStateInternal.vue.d.ts +43 -0
  57. package/dist/components/internal/WellEditPopupInternal.vue.d.ts +3 -1
  58. package/dist/components/internal/WorkspaceControlsInternal.vue.d.ts +23 -0
  59. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +70 -0
  60. package/dist/components/internal/WorkspaceSidebarInternal.vue.d.ts +43 -0
  61. package/dist/{components-DkHddRMl.js → components-CgAUzF8F.js} +2497 -2235
  62. package/dist/components-CgAUzF8F.js.map +1 -0
  63. package/dist/composables/controlSchemaTypes.d.ts +34 -0
  64. package/dist/composables/flattenWorkspaceBindings.d.ts +61 -0
  65. package/dist/composables/index.d.ts +9 -2
  66. package/dist/composables/index.js +10 -10
  67. package/dist/composables/pluginWorkspaceModel.d.ts +164 -0
  68. package/dist/composables/useAsync.d.ts +5 -1
  69. package/dist/composables/useBioTemplateWorkspace.d.ts +4 -20
  70. package/dist/composables/useCommandHistory.d.ts +5 -1
  71. package/dist/composables/useDropdownState.d.ts +18 -2
  72. package/dist/composables/useEventStream.d.ts +9 -0
  73. package/dist/composables/useFocusTrap.d.ts +21 -0
  74. package/dist/composables/useGeneratedAnalysis.d.ts +3 -1
  75. package/dist/composables/useJobsStatusTray.d.ts +25 -1
  76. package/dist/composables/useListReorder.d.ts +90 -0
  77. package/dist/composables/useMenuKeyboard.d.ts +29 -0
  78. package/dist/composables/useOptimisticMutation.d.ts +5 -1
  79. package/dist/composables/usePluginClient.d.ts +2 -0
  80. package/dist/composables/usePluginConfig.d.ts +27 -0
  81. package/dist/composables/usePluginWorkspace.d.ts +51 -0
  82. package/dist/composables/useRequestSyncState.d.ts +42 -2
  83. package/dist/composables/useResourceCrud.d.ts +5 -1
  84. package/dist/composables/useRovingFocus.d.ts +24 -0
  85. package/dist/composables/useScheduleDrag.d.ts +1 -0
  86. package/dist/composables/useWellPainting.d.ts +5 -1
  87. package/dist/composables/useWellPlateAdapter.d.ts +5 -1
  88. package/dist/composables/useWellPlateValidation.d.ts +5 -1
  89. package/dist/composables/workspaceRecipes.d.ts +188 -0
  90. package/dist/{composables-C_i90sGS.js → composables-B_pia3hO.js} +209 -82
  91. package/dist/composables-B_pia3hO.js.map +1 -0
  92. package/dist/{useApi-J6zFkHmn.js → errors-_W0-LbA6.js} +103 -3
  93. package/dist/errors-_W0-LbA6.js.map +1 -0
  94. package/dist/{experiment-Cq145oEW.js → experiment-Cwl9AYxw.js} +3 -8
  95. package/dist/experiment-Cwl9AYxw.js.map +1 -0
  96. package/dist/{experiment-utils-CLnzPPq5.js → experiment-utils-DV3DrvE_.js} +70 -51
  97. package/dist/experiment-utils-DV3DrvE_.js.map +1 -0
  98. package/dist/index.d.ts +1 -0
  99. package/dist/index.js +15 -15
  100. package/dist/install.js +2 -7
  101. package/dist/install.js.map +1 -1
  102. package/dist/permissions.d.ts +42 -1
  103. package/dist/permissions.js +20 -10
  104. package/dist/permissions.js.map +1 -1
  105. package/dist/stores/auth.d.ts +6 -0
  106. package/dist/stores/index.d.ts +1 -1
  107. package/dist/stores/index.js +3 -3
  108. package/dist/stores/settings.d.ts +31 -1
  109. package/dist/styles.css +11247 -29501
  110. package/dist/templates/builderReadUtils.d.ts +1 -1
  111. package/dist/templates/index.js +2 -4
  112. package/dist/{templates-DsP51i-S.js → templates-Qq113pyZ.js} +303 -106
  113. package/dist/templates-Qq113pyZ.js.map +1 -0
  114. package/dist/types/auth.d.ts +1 -0
  115. package/dist/types/form-builder.d.ts +1 -1
  116. package/dist/{useControlSchema-BDx2Olha.js → useControlSchema-aMZlb4Sc.js} +462 -1130
  117. package/dist/useControlSchema-aMZlb4Sc.js.map +1 -0
  118. package/dist/{useDropdownState-DSb3BC3N.js → useDropdownState-DitCtrTT.js} +22 -6
  119. package/dist/useDropdownState-DitCtrTT.js.map +1 -0
  120. package/dist/{useExperimentSelector-CV4iNfMS.js → useExperimentSelector-I8HC8hUu.js} +4 -4
  121. package/dist/{useExperimentSelector-CV4iNfMS.js.map → useExperimentSelector-I8HC8hUu.js.map} +1 -1
  122. package/dist/{useFormBuilder-BLxG3BOX.js → useFormBuilder-TCxNnqeb.js} +2 -2
  123. package/dist/{useFormBuilder-BLxG3BOX.js.map → useFormBuilder-TCxNnqeb.js.map} +1 -1
  124. package/dist/{useProtocolTemplates-CS_SQl6U.js → useProtocolTemplates-BmX_iVBR.js} +766 -212
  125. package/dist/useProtocolTemplates-BmX_iVBR.js.map +1 -0
  126. package/dist/utils/color.d.ts +13 -0
  127. package/dist/utils/errors.d.ts +9 -0
  128. package/dist/utils/pluginSecrets.d.ts +53 -0
  129. package/dist/utils/records.d.ts +4 -0
  130. package/package.json +1 -1
  131. package/src/__tests__/components/ActionMenu.test.ts +94 -0
  132. package/src/__tests__/components/AppAvatarMenu.test.ts +123 -0
  133. package/src/__tests__/components/BaseTabs.test.ts +67 -0
  134. package/src/__tests__/components/DataFrame.test.ts +183 -11
  135. package/src/__tests__/components/DataStates.test.ts +176 -0
  136. package/src/__tests__/components/DatePicker.test.ts +76 -0
  137. package/src/__tests__/components/DateTimePicker.test.ts +36 -0
  138. package/src/__tests__/components/DropdownButton.test.ts +134 -0
  139. package/src/__tests__/components/ExperimentTimeline.test.ts +63 -0
  140. package/src/__tests__/components/GroupAssigner.test.ts +53 -0
  141. package/src/__tests__/components/LcmsSequenceTable.test.ts +22 -0
  142. package/src/__tests__/components/PluginWorkspaceView.internal.test.ts +230 -0
  143. package/src/__tests__/components/RackEditor.test.ts +35 -0
  144. package/src/__tests__/components/ReagentList.test.ts +64 -2
  145. package/src/__tests__/components/RetiredStyles.test.ts +31 -0
  146. package/src/__tests__/components/SampleSelector.drag.test.ts +51 -1
  147. package/src/__tests__/components/ScheduleCalendar.test.ts +63 -0
  148. package/src/__tests__/components/SecretInput.test.ts +87 -0
  149. package/src/__tests__/components/SegmentedControl.test.ts +88 -0
  150. package/src/__tests__/components/TimePicker.test.ts +61 -0
  151. package/src/__tests__/components/WellEditPopupInternal.test.ts +108 -0
  152. package/src/__tests__/components/WellPlate.interaction.test.ts +59 -0
  153. package/src/__tests__/composables/useAuth.test.ts +2 -0
  154. package/src/__tests__/composables/useDropdownState.test.ts +58 -1
  155. package/src/__tests__/composables/useListReorder.test.ts +145 -0
  156. package/src/__tests__/composables/usePluginClient.test.ts +140 -0
  157. package/src/__tests__/composables/usePluginConfig.test.ts +497 -0
  158. package/src/__tests__/composables/useRequestSyncState.test.ts +140 -0
  159. package/src/__tests__/docs/frontendDocsCatalog.test.ts +39 -7
  160. package/src/__tests__/stores/settings.test.ts +71 -1
  161. package/src/__tests__/styles/cssTokens.test.ts +131 -0
  162. package/src/__tests__/utils/permissions.test.ts +68 -0
  163. package/src/components/ActionMenu.vue +45 -88
  164. package/src/components/AlertBox.vue +0 -4
  165. package/src/components/AppAvatarMenu.vue +26 -7
  166. package/src/components/AppLayout.vue +0 -4
  167. package/src/components/AppPluginSwitcher.story.vue +87 -0
  168. package/src/components/AppPluginSwitcher.vue +2 -5
  169. package/src/components/AppSidebar.vue +0 -4
  170. package/src/components/AppToastContainer.vue +6 -8
  171. package/src/components/AppTopBar.vue +0 -4
  172. package/src/components/ArtifactSaveDialog.vue +0 -4
  173. package/src/components/ArtifactSelectorModal.vue +0 -4
  174. package/src/components/AuditTrail.story.vue +18 -0
  175. package/src/components/AuditTrail.vue +27 -7
  176. package/src/components/AutoGroupModal.vue +0 -4
  177. package/src/components/Avatar.vue +0 -4
  178. package/src/components/BaseButton.vue +0 -4
  179. package/src/components/BaseCheckbox.vue +0 -4
  180. package/src/components/BaseInput.vue +0 -4
  181. package/src/components/BaseModal.vue +8 -60
  182. package/src/components/BasePill.vue +0 -4
  183. package/src/components/BaseRadioGroup.vue +0 -4
  184. package/src/components/BaseSelect.vue +0 -4
  185. package/src/components/BaseSlider.vue +0 -4
  186. package/src/components/BaseTabs.vue +26 -5
  187. package/src/components/BaseTextarea.vue +0 -4
  188. package/src/components/BaseToggle.vue +0 -4
  189. package/src/components/BatchProgressList.story.vue +18 -0
  190. package/src/components/BatchProgressList.vue +32 -4
  191. package/src/components/BioTemplateExperimentWorkspaceView.vue +10 -21
  192. package/src/components/BioTemplatePackWorkspaceView.vue +11 -15
  193. package/src/components/BioTemplatePresetWorkspaceView.vue +8 -13
  194. package/src/components/Breadcrumb.vue +0 -4
  195. package/src/components/Calendar.vue +0 -4
  196. package/src/components/ChartContainer.story.vue +1 -1
  197. package/src/components/ChartContainer.vue +0 -4
  198. package/src/components/ChemicalFormula.vue +0 -4
  199. package/src/components/CollapsibleCard.vue +0 -4
  200. package/src/components/ColorSlider.vue +0 -4
  201. package/src/components/ComponentBindingRenderer.vue +1 -3
  202. package/src/components/ConcentrationInput.vue +0 -4
  203. package/src/components/ConfirmDialog.vue +0 -4
  204. package/src/components/ControlWorkspaceView.vue +11 -22
  205. package/src/components/DataFrame.story.vue +14 -0
  206. package/src/components/DataFrame.vue +97 -23
  207. package/src/components/DatePicker.vue +73 -27
  208. package/src/components/DateTimePicker.vue +45 -17
  209. package/src/components/Divider.vue +0 -4
  210. package/src/components/DoseCalculator.vue +0 -4
  211. package/src/components/DoseDesignWorkspaceView.vue +6 -25
  212. package/src/components/DropdownButton.vue +24 -6
  213. package/src/components/EmptyState.vue +0 -4
  214. package/src/components/ExperimentCodeBadge.vue +0 -4
  215. package/src/components/ExperimentDataViewer.story.vue +3 -0
  216. package/src/components/ExperimentDataViewer.vue +33 -13
  217. package/src/components/ExperimentPopover.vue +2 -5
  218. package/src/components/ExperimentSelectorModal.vue +0 -4
  219. package/src/components/ExperimentTimeline.story.vue +18 -0
  220. package/src/components/ExperimentTimeline.vue +81 -75
  221. package/src/components/FileUploader.vue +0 -4
  222. package/src/components/FitPanel.vue +0 -4
  223. package/src/components/FormActions.story.vue +96 -0
  224. package/src/components/FormActions.vue +0 -4
  225. package/src/components/FormBuilder.vue +0 -4
  226. package/src/components/FormField.vue +0 -4
  227. package/src/components/FormulaInput.vue +0 -4
  228. package/src/components/GeneratedPathInput.story.vue +68 -0
  229. package/src/components/GeneratedPlotlyResult.story.vue +96 -0
  230. package/src/components/GeneratedPlotlyResult.vue +3 -3
  231. package/src/components/GeneratedPluginView.story.vue +145 -0
  232. package/src/components/GeneratedPluginView.vue +10 -10
  233. package/src/components/GeneratedResultRenderer.story.vue +117 -0
  234. package/src/components/GeneratedResultRenderer.vue +4 -4
  235. package/src/components/GroupAssigner.vue +67 -5
  236. package/src/components/IconButton.vue +0 -4
  237. package/src/components/InstrumentAlertLog.vue +0 -4
  238. package/src/components/InstrumentStateBadge.vue +0 -4
  239. package/src/components/InstrumentStatusCard.vue +0 -4
  240. package/src/components/JobsStatusTray.vue +16 -5
  241. package/src/components/LcmsSequenceTable.vue +81 -50
  242. package/src/components/LoadingSpinner.vue +0 -4
  243. package/src/components/MobileSupportGate.vue +0 -4
  244. package/src/components/MoleculeInput.vue +0 -4
  245. package/src/components/MultiSelect.vue +0 -4
  246. package/src/components/NumberInput.vue +0 -4
  247. package/src/components/PlateMapEditor.vue +3 -14
  248. package/src/components/PluginIcon.vue +0 -4
  249. package/src/components/PluginWorkspaceView.props.ts +38 -0
  250. package/src/components/PluginWorkspaceView.vue +53 -224
  251. package/src/components/ProgressBar.vue +0 -4
  252. package/src/components/ProtocolStepEditor.vue +2 -4
  253. package/src/components/RackEditor.vue +51 -70
  254. package/src/components/ReagentEditor.vue +0 -4
  255. package/src/components/ReagentList.story.vue +18 -0
  256. package/src/components/ReagentList.vue +127 -82
  257. package/src/components/ResourceCard.vue +0 -4
  258. package/src/components/RuntimeUpdateNotice.story.vue +49 -0
  259. package/src/components/RuntimeUpdateNotice.vue +4 -4
  260. package/src/components/SampleHierarchyTree.story.vue +18 -0
  261. package/src/components/SampleHierarchyTree.vue +32 -9
  262. package/src/components/SampleLegend.vue +2 -8
  263. package/src/components/SampleSelector.drag.ts +51 -0
  264. package/src/components/SampleSelector.story.vue +6 -0
  265. package/src/components/SampleSelector.tree.ts +2 -0
  266. package/src/components/SampleSelector.vue +49 -10
  267. package/src/components/SampleSelectorGroupNode.vue +19 -0
  268. package/src/components/ScheduleCalendar.story.vue +6 -0
  269. package/src/components/ScheduleCalendar.vue +82 -7
  270. package/src/components/ScientificNumber.vue +0 -4
  271. package/src/components/SecretInput.story.vue +79 -0
  272. package/src/components/SecretInput.vue +150 -0
  273. package/src/components/SectionCard.vue +0 -4
  274. package/src/components/SegmentedControl.vue +48 -5
  275. package/src/components/SequenceInput.vue +0 -4
  276. package/src/components/SequenceProgressBar.story.vue +110 -0
  277. package/src/components/SequenceProgressBar.vue +0 -4
  278. package/src/components/SettingsModal.vue +0 -4
  279. package/src/components/Skeleton.vue +0 -4
  280. package/src/components/SmartGroupFieldRecipe.vue +8 -6
  281. package/src/components/SmartGroupManual.vue +0 -4
  282. package/src/components/StatusIndicator.vue +0 -4
  283. package/src/components/StepWizard.vue +0 -4
  284. package/src/components/TagsInput.vue +4 -6
  285. package/src/components/ThemeToggle.vue +0 -4
  286. package/src/components/TimePicker.vue +36 -7
  287. package/src/components/TimeRangeInput.vue +0 -4
  288. package/src/components/Tooltip.story.vue +3 -3
  289. package/src/components/Tooltip.vue +0 -4
  290. package/src/components/UnitInput.vue +0 -4
  291. package/src/components/WellPlate.geometry.ts +60 -1
  292. package/src/components/WellPlate.interaction.ts +44 -0
  293. package/src/components/WellPlate.story.vue +8 -0
  294. package/src/components/WellPlate.vue +53 -7
  295. package/src/components/index.ts +9 -0
  296. package/src/components/internal/AppTopBarPageSelectorInternal.vue +2 -5
  297. package/src/components/internal/AppTopBarPillNavInternal.vue +0 -4
  298. package/src/components/internal/DataStateInternal.vue +74 -0
  299. package/src/components/internal/FormSectionRenderer.vue +0 -4
  300. package/src/components/internal/WellEditPopupInternal.vue +20 -5
  301. package/src/components/internal/WorkspaceControlsInternal.vue +20 -0
  302. package/src/components/internal/WorkspaceShellInternal.vue +125 -0
  303. package/src/components/internal/WorkspaceSidebarInternal.vue +82 -0
  304. package/src/composables/controlSchemaTypes.ts +34 -0
  305. package/src/composables/experimentDesignData.ts +1 -3
  306. package/src/composables/flattenWorkspaceBindings.ts +104 -0
  307. package/src/composables/formBuilderRegistry.ts +5 -0
  308. package/src/composables/index.ts +43 -0
  309. package/src/composables/pluginWorkspaceModel.ts +182 -0
  310. package/src/composables/useAsync.ts +5 -1
  311. package/src/composables/useAuth.ts +3 -0
  312. package/src/composables/useBioTemplatePackWorkspace.ts +15 -9
  313. package/src/composables/useBioTemplatePresetWorkspace.ts +14 -15
  314. package/src/composables/useBioTemplateWorkspace.ts +18 -43
  315. package/src/composables/useCommandHistory.ts +5 -1
  316. package/src/composables/useDropdownState.ts +35 -5
  317. package/src/composables/useEventStream.ts +14 -2
  318. package/src/composables/useFileImport.ts +2 -7
  319. package/src/composables/useFocusTrap.ts +91 -0
  320. package/src/composables/useGeneratedAnalysis.ts +22 -10
  321. package/src/composables/useJobsStatusTray.ts +184 -17
  322. package/src/composables/useListReorder.story.vue +143 -0
  323. package/src/composables/useListReorder.ts +242 -0
  324. package/src/composables/useMenuKeyboard.ts +90 -0
  325. package/src/composables/useOptimisticMutation.ts +6 -16
  326. package/src/composables/usePluginClient.ts +47 -4
  327. package/src/composables/usePluginConfig.ts +252 -0
  328. package/src/composables/usePluginWorkspace.ts +208 -0
  329. package/src/composables/useRackEditor.ts +2 -11
  330. package/src/composables/useRequestSyncState.ts +98 -28
  331. package/src/composables/useResourceCrud.ts +6 -16
  332. package/src/composables/useRovingFocus.ts +66 -0
  333. package/src/composables/useScheduleDrag.ts +37 -0
  334. package/src/composables/useWellPainting.ts +10 -30
  335. package/src/composables/useWellPlateAdapter.ts +5 -1
  336. package/src/composables/useWellPlateEditor.ts +1 -11
  337. package/src/composables/useWellPlateValidation.ts +5 -1
  338. package/src/composables/workspaceRecipes.ts +267 -0
  339. package/src/index.ts +16 -0
  340. package/src/permissions.ts +48 -9
  341. package/src/stores/auth.ts +1 -0
  342. package/src/stores/experiment.ts +2 -7
  343. package/src/stores/index.ts +9 -1
  344. package/src/stores/settings.ts +93 -1
  345. package/src/styles/components/audit-trail.css +5 -5
  346. package/src/styles/components/batch-progress-list.css +7 -0
  347. package/src/styles/components/color-slider.css +2 -2
  348. package/src/styles/components/data-state.css +30 -0
  349. package/src/styles/components/dataframe.css +29 -35
  350. package/src/styles/components/experiment-data-viewer.css +4 -4
  351. package/src/styles/components/experiment-timeline.css +3 -30
  352. package/src/styles/components/form-builder.css +5 -5
  353. package/src/styles/components/lcms-sequence-table.css +16 -1
  354. package/src/styles/components/multi-select.css +1 -1
  355. package/src/styles/components/reagent-list.css +38 -31
  356. package/src/styles/components/sample-hierarchy-tree.css +5 -19
  357. package/src/styles/components/sample-selector.css +9 -2
  358. package/src/styles/components/schedule-calendar.css +8 -0
  359. package/src/styles/components/scientific-number.css +1 -1
  360. package/src/styles/components/secret-input.css +60 -0
  361. package/src/styles/components/well-plate.css +8 -0
  362. package/src/styles/index.css +9 -0
  363. package/src/styles/variables.css +29 -0
  364. package/src/templates/builderPresetControls.ts +1 -1
  365. package/src/templates/builderReadUtils.ts +1 -3
  366. package/src/templates/componentPlateHelpers.ts +3 -1
  367. package/src/templates/componentTargetResolvers.ts +1 -3
  368. package/src/templates/controlSchemaTargets.ts +1 -3
  369. package/src/templates/doseResponseAdapters.ts +2 -13
  370. package/src/templates/elisaAssayCollectionBuilder.ts +2 -2
  371. package/src/templates/plateMapBuilder.ts +2 -2
  372. package/src/templates/qpcrPlateBuilder.ts +1 -1
  373. package/src/templates/templateValidators.ts +1 -1
  374. package/src/templates/timeCourseBuilder.ts +2 -2
  375. package/src/templates/wellPlateScreenCollectionBuilder.ts +2 -2
  376. package/src/types/auth.ts +1 -0
  377. package/src/types/form-builder.ts +1 -0
  378. package/src/utils/color.ts +51 -0
  379. package/src/utils/errors.ts +29 -0
  380. package/src/utils/formModelSync.ts +1 -3
  381. package/src/utils/pluginIcon.ts +1 -3
  382. package/src/utils/pluginSecrets.ts +102 -0
  383. package/src/utils/records.ts +9 -0
  384. package/dist/EmptyState-p90quq8Z.js.map +0 -1
  385. package/dist/ExperimentPopover-tLwJ7XF4.js.map +0 -1
  386. package/dist/ExperimentSelectorModal-DyPAUCLw.js.map +0 -1
  387. package/dist/SettingsModal-BgKY93zh.js.map +0 -1
  388. package/dist/components-DkHddRMl.js.map +0 -1
  389. package/dist/composables/autoGroupConstants.d.ts +0 -1
  390. package/dist/composables/autoGroupGrouping.d.ts +0 -3
  391. package/dist/composables/useAutoGroupInputSources.d.ts +0 -32
  392. package/dist/composables-C_i90sGS.js.map +0 -1
  393. package/dist/experiment-Cq145oEW.js.map +0 -1
  394. package/dist/experiment-utils-CLnzPPq5.js.map +0 -1
  395. package/dist/templates/builderDefaults.d.ts +0 -1
  396. package/dist/templates/plateGeometry.d.ts +0 -4
  397. package/dist/templates-DsP51i-S.js.map +0 -1
  398. package/dist/useApi-J6zFkHmn.js.map +0 -1
  399. package/dist/useControlSchema-BDx2Olha.js.map +0 -1
  400. package/dist/useDropdownState-DSb3BC3N.js.map +0 -1
  401. package/dist/useProtocolTemplates-CS_SQl6U.js.map +0 -1
  402. package/src/__tests__/composables/useAutoGroupInputSources.test.ts +0 -127
  403. package/src/composables/autoGroupConstants.ts +0 -4
  404. package/src/composables/autoGroupGrouping.ts +0 -148
  405. package/src/composables/useAutoGroupInputSources.ts +0 -147
  406. package/src/templates/builderDefaults.ts +0 -11
  407. package/src/templates/plateGeometry.ts +0 -62
  408. /package/dist/__tests__/{composables/useAutoGroupInputSources.test.d.ts → components/DataStates.test.d.ts} +0 -0
@@ -0,0 +1,60 @@
1
+ /* SecretInput — plugin secret settings field with a set / not set / environment badge. */
2
+
3
+ .mint-secret-input {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 0.5rem;
7
+ }
8
+
9
+ .mint-secret-input__status {
10
+ display: flex;
11
+ align-items: center;
12
+ gap: 0.5rem;
13
+ flex-wrap: wrap;
14
+ }
15
+
16
+ .mint-secret-input__badge {
17
+ display: inline-flex;
18
+ align-items: center;
19
+ border-radius: 999px;
20
+ padding: 0.125rem 0.5rem;
21
+ font-size: 0.75rem;
22
+ font-weight: 500;
23
+ line-height: 1.4;
24
+ border: 1px solid transparent;
25
+ background-color: var(--bg-tertiary);
26
+ color: var(--text-secondary);
27
+ }
28
+
29
+ .mint-secret-input__badge--set {
30
+ background-color: color-mix(in srgb, var(--mint-success) 12%, transparent);
31
+ border-color: color-mix(in srgb, var(--mint-success) 35%, transparent);
32
+ color: var(--mint-success);
33
+ }
34
+
35
+ .mint-secret-input__badge--environment {
36
+ background-color: color-mix(in srgb, var(--mint-info) 12%, transparent);
37
+ border-color: color-mix(in srgb, var(--mint-info) 35%, transparent);
38
+ color: var(--mint-info);
39
+ }
40
+
41
+ .mint-secret-input__badge--pending {
42
+ background-color: color-mix(in srgb, var(--mint-warning) 12%, transparent);
43
+ border-color: color-mix(in srgb, var(--mint-warning) 35%, transparent);
44
+ color: var(--mint-warning);
45
+ }
46
+
47
+ .mint-secret-input__hint {
48
+ font-size: 0.75rem;
49
+ color: var(--text-muted);
50
+ }
51
+
52
+ .mint-secret-input__actions {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 0.5rem;
56
+ }
57
+
58
+ .mint-secret-input--error .mint-secret-input__badge {
59
+ border-color: color-mix(in srgb, var(--mint-error) 45%, transparent);
60
+ }
@@ -284,3 +284,11 @@
284
284
  font-size: 0.75rem;
285
285
  color: var(--text-muted);
286
286
  }
287
+
288
+ /* Empty / loading / error placeholder host (content comes from EmptyState) */
289
+ .mint-well-plate__state {
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: center;
293
+ min-height: 12rem;
294
+ }
@@ -30,6 +30,7 @@
30
30
  @import './components/radio-group.css';
31
31
  @import './components/sample-legend.css';
32
32
  @import './components/section-card.css';
33
+ @import './components/secret-input.css';
33
34
  @import './components/select.css';
34
35
  @import './components/skeleton.css';
35
36
  @import './components/slider.css';
@@ -56,6 +57,7 @@
56
57
  @import './components/dropdown-button.css';
57
58
  @import './components/calendar.css';
58
59
  @import './components/dataframe.css';
60
+ @import './components/data-state.css';
59
61
  @import './components/well-edit-popup.css';
60
62
  @import './components/rack-editor.css';
61
63
  @import './components/loading-spinner.css';
@@ -91,3 +93,10 @@
91
93
  @import './components/artifact-save-dialog.css';
92
94
  @import './components/experiment-popover.css';
93
95
  @import './components/fit-panel.css';
96
+ @import './components/app-avatar-menu.css';
97
+ @import './components/app-page-selector.css';
98
+ @import './components/app-pill-nav.css';
99
+ @import './components/app-plugin-switcher.css';
100
+ @import './components/mobile-support-gate.css';
101
+ @import './components/plugin-icon.css';
102
+ @import './components/reagent-editor.css';
@@ -66,6 +66,32 @@
66
66
  /* The MINT 1.1 card system uses exactly one shadow for every card. */
67
67
  --card-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 1px 3px 0 rgb(0 0 0 / 0.06);
68
68
 
69
+ /* Categorical sample scale — mirrored by SAMPLE_COLOR_SCALE in
70
+ src/utils/color.ts. The JS constant carries the same hexes as a
71
+ canvas/SVG/persistence-safe fallback; change both together. */
72
+ --mint-sample-1: #3B82F6;
73
+ --mint-sample-2: #10B981;
74
+ --mint-sample-3: #EF4444;
75
+ --mint-sample-4: #F59E0B;
76
+ --mint-sample-5: #8B5CF6;
77
+ --mint-sample-6: #F97316;
78
+ --mint-sample-7: #06B6D4;
79
+ --mint-sample-8: #14B8A6;
80
+ --mint-sample-9: #6B7280;
81
+
82
+ /* Rack / plate slot positions — mirrored by SLOT_COLORS in
83
+ src/utils/color.ts. */
84
+ --mint-slot-r: #ef4444;
85
+ --mint-slot-g: #22c55e;
86
+ --mint-slot-b: #3b82f6;
87
+ --mint-slot-y: #eab308;
88
+
89
+ /* Motion — the SDK's standard easing curve. */
90
+ --mint-ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
91
+
92
+ /* Typography — Fira Code for data, code and routes. */
93
+ --font-mono: 'Fira Code', ui-monospace, SFMono-Regular, Menlo, monospace;
94
+
69
95
  /* Border radius */
70
96
  --radius-sm: 0.25rem;
71
97
  --radius: 0.375rem;
@@ -90,6 +116,8 @@
90
116
  --mint-warning-hover: #D97706;
91
117
  --mint-warning-bg: rgba(245, 158, 11, 0.1);
92
118
  --mint-warning-border: rgba(245, 158, 11, 0.3);
119
+ /* Readable warning label on --mint-warning-bg (amber-700, 5.9:1). */
120
+ --mint-warning-text: #B45309;
93
121
  --mint-info: #3B82F6;
94
122
  --mint-info-bg: rgba(59, 130, 246, 0.1);
95
123
  --mint-info-border: rgba(59, 130, 246, 0.3);
@@ -178,6 +206,7 @@ html.dark {
178
206
  --mint-success-bg: rgba(16, 185, 129, 0.15);
179
207
  --mint-error-bg: rgba(239, 68, 68, 0.15);
180
208
  --mint-warning-bg: rgba(245, 158, 11, 0.15);
209
+ --mint-warning-text: #FCD34D;
181
210
  --mint-info-bg: rgba(59, 130, 246, 0.15);
182
211
 
183
212
  /* Focus ring - dark mode offset uses bg-primary instead of white */
@@ -7,7 +7,7 @@ import {
7
7
  readString,
8
8
  readStringList,
9
9
  } from './builderReadUtils'
10
- import { readPlateFormat } from './plateGeometry'
10
+ import { readPlateFormat } from '../components/WellPlate.geometry'
11
11
  import { getBioTemplatePresetInfo } from './presets'
12
12
  import type {
13
13
  CreateElisaAssayCollectionOptions,
@@ -1,6 +1,4 @@
1
- export function isRecord(value: unknown): value is Record<string, unknown> {
2
- return typeof value === 'object' && value !== null && !Array.isArray(value)
3
- }
1
+ export { isRecord } from '../utils/records'
4
2
 
5
3
  export function readStringList(value: unknown, fallback: string[]): string[] {
6
4
  if (Array.isArray(value)) {
@@ -2,6 +2,7 @@ import type {
2
2
  PlateMapEditorState,
3
3
  WellLegendItem,
4
4
  } from '../types'
5
+ import { SAMPLE_COLOR_SCALE } from '../utils/color'
5
6
 
6
7
  export function activePlateFromState(state: PlateMapEditorState) {
7
8
  return state.plates.find(plate => plate.id === state.activePlateId) ?? state.plates[0]
@@ -24,6 +25,7 @@ export function legendItemsFromPlateState(state: PlateMapEditorState): WellLegen
24
25
  }
25
26
 
26
27
  export function colorForIndex(index: number): string {
27
- const colors = ['#3B82F6', '#10B981', '#EF4444', '#F59E0B', '#8B5CF6', '#F97316', '#06B6D4', '#14B8A6']
28
+ // The gray tail of the scale is reserved for "other"; component plates cycle the eight hues.
29
+ const colors = SAMPLE_COLOR_SCALE.slice(0, 8)
28
30
  return colors[index % colors.length]
29
31
  }
@@ -1,3 +1,4 @@
1
+ import { isObjectLike as isRecord } from '../utils/records'
1
2
  import { extractTemplateCollection } from './templateEnvelopes'
2
3
  import { getBioTemplateInfo } from './catalog'
3
4
  import { getBioTemplatePackInfo } from './packs'
@@ -64,6 +65,3 @@ function collectionPackName(value: unknown): string | undefined {
64
65
  return typeof value.metadata.pack === 'string' ? value.metadata.pack : undefined
65
66
  }
66
67
 
67
- function isRecord(value: unknown): value is Record<string, unknown> {
68
- return typeof value === 'object' && value !== null
69
- }
@@ -1,3 +1,4 @@
1
+ import { isObjectLike as isRecord } from '../utils/records'
1
2
  import {
2
3
  getBioTemplateInfo,
3
4
  } from './catalog'
@@ -82,6 +83,3 @@ function collectionPackName(value: unknown): string | undefined {
82
83
  return typeof value.metadata.pack === 'string' ? value.metadata.pack : undefined
83
84
  }
84
85
 
85
- function isRecord(value: unknown): value is Record<string, unknown> {
86
- return typeof value === 'object' && value !== null
87
- }
@@ -2,6 +2,7 @@ import type {
2
2
  PlateCondition,
3
3
  PlateMapEditorState,
4
4
  } from '../types'
5
+ import { SAMPLE_COLOR_SCALE } from '../utils/color'
5
6
  import { toPlateMapEditorState } from './plateMapAdapters'
6
7
  import { getTemplateData } from './templateEnvelopes'
7
8
  import { validateDoseResponseData } from './templateValidators'
@@ -11,18 +12,6 @@ import type {
11
12
  DoseResponseTemplateData,
12
13
  } from './types'
13
14
 
14
- const CONDITION_COLORS = [
15
- '#3B82F6',
16
- '#10B981',
17
- '#EF4444',
18
- '#F59E0B',
19
- '#8B5CF6',
20
- '#F97316',
21
- '#06B6D4',
22
- '#14B8A6',
23
- '#6B7280',
24
- ]
25
-
26
15
  export function toDoseConditions(
27
16
  template: DoseResponseTemplate | DoseResponseTemplateData
28
17
  ): DoseConditionsAdapterResult {
@@ -30,7 +19,7 @@ export function toDoseConditions(
30
19
  validateDoseResponseData(data)
31
20
  return data.compounds.map((compound, index): PlateCondition => ({
32
21
  label: compound.name,
33
- color: String(compound.metadata?.color ?? CONDITION_COLORS[index % CONDITION_COLORS.length]),
22
+ color: String(compound.metadata?.color ?? SAMPLE_COLOR_SCALE[index % SAMPLE_COLOR_SCALE.length]),
34
23
  concentrations: compound.concentrations,
35
24
  unit: data.unit,
36
25
  }))
@@ -1,5 +1,5 @@
1
1
  import { createAssayMatrixTemplate } from './assayMatrixBuilder'
2
- import { DEFAULT_SAMPLE_COLORS } from './builderDefaults'
2
+ import { SAMPLE_COLOR_SCALE } from '../utils/color'
3
3
  import { idFromName } from './builderIdUtils'
4
4
  import { createCalibrationCurveTemplate } from './calibrationCurveBuilder'
5
5
  import { createPlateMapTemplate } from './plateMapBuilder'
@@ -27,7 +27,7 @@ export function createElisaAssayCollection(
27
27
  ...sampleRecords.map((sample, index) => ({
28
28
  id: sample.sampleId,
29
29
  name: sample.name ?? sample.sampleId,
30
- color: DEFAULT_SAMPLE_COLORS[index % DEFAULT_SAMPLE_COLORS.length],
30
+ color: SAMPLE_COLOR_SCALE[index % SAMPLE_COLOR_SCALE.length],
31
31
  })),
32
32
  ],
33
33
  })
@@ -1,4 +1,4 @@
1
- import { DEFAULT_SAMPLE_COLORS } from './builderDefaults'
1
+ import { SAMPLE_COLOR_SCALE } from '../utils/color'
2
2
  import { sampleIdFromName } from './builderIdUtils'
3
3
  import { createTemplateEnvelope } from './templateEnvelopes'
4
4
  import type {
@@ -23,7 +23,7 @@ export function createPlateMapTemplate(
23
23
  return {
24
24
  id: sampleIdFromName(sample, index),
25
25
  name: sample,
26
- color: DEFAULT_SAMPLE_COLORS[index % DEFAULT_SAMPLE_COLORS.length],
26
+ color: SAMPLE_COLOR_SCALE[index % SAMPLE_COLOR_SCALE.length],
27
27
  }
28
28
  })
29
29
 
@@ -1,5 +1,5 @@
1
1
  import { idFromName } from './builderIdUtils'
2
- import { wellIdsForFormat } from './plateGeometry'
2
+ import { wellIdsForFormat } from '../components/WellPlate.geometry'
3
3
  import {
4
4
  normalizeQpcrSample,
5
5
  normalizeQpcrTarget,
@@ -12,7 +12,7 @@ import type {
12
12
  SampleSheetTemplateData,
13
13
  TimeCourseTemplateData,
14
14
  } from './types'
15
- import { assertWellInFormat } from './plateGeometry'
15
+ import { assertWellInFormat } from '../components/WellPlate.geometry'
16
16
 
17
17
  export function validatePlateMapData(data: PlateMapTemplateData): void {
18
18
  if (!Array.isArray(data.plates) || data.plates.length === 0) {
@@ -1,4 +1,4 @@
1
- import { DEFAULT_SAMPLE_COLORS } from './builderDefaults'
1
+ import { SAMPLE_COLOR_SCALE } from '../utils/color'
2
2
  import {
3
3
  idFromName,
4
4
  timepointId,
@@ -36,7 +36,7 @@ export function createTimeCourseTemplate(
36
36
  return {
37
37
  id: idFromName(condition, `condition-${index + 1}`),
38
38
  name: condition,
39
- color: DEFAULT_SAMPLE_COLORS[index % DEFAULT_SAMPLE_COLORS.length],
39
+ color: SAMPLE_COLOR_SCALE[index % SAMPLE_COLOR_SCALE.length],
40
40
  metadata: {},
41
41
  }
42
42
  })
@@ -1,4 +1,4 @@
1
- import { DEFAULT_SAMPLE_COLORS } from './builderDefaults'
1
+ import { SAMPLE_COLOR_SCALE } from '../utils/color'
2
2
  import { createDoseResponseTemplate } from './doseResponseBuilder'
3
3
  import { createPlateMapTemplate } from './plateMapBuilder'
4
4
  import { createSampleSheetTemplate } from './sampleSheetBuilder'
@@ -19,7 +19,7 @@ export function createWellPlateScreenCollection(
19
19
  samples: sampleRecords.map((sample, index) => ({
20
20
  id: sample.sampleId,
21
21
  name: sample.name ?? sample.sampleId,
22
- color: DEFAULT_SAMPLE_COLORS[index % DEFAULT_SAMPLE_COLORS.length],
22
+ color: SAMPLE_COLOR_SCALE[index % SAMPLE_COLOR_SCALE.length],
23
23
  })),
24
24
  })
25
25
  const sampleSheet = createSampleSheetTemplate({ samples: sampleRecords })
package/src/types/auth.ts CHANGED
@@ -6,6 +6,7 @@ export interface AuthConfig {
6
6
  passkeyEnabled: boolean
7
7
  passkeyRegistered: boolean
8
8
  registrationEnabled: boolean
9
+ databaseMode: string
9
10
  experimentVisibilityMode?: 'open' | 'restricted'
10
11
  }
11
12
 
@@ -11,6 +11,7 @@ export type FormFieldType =
11
11
  | 'text'
12
12
  | 'email'
13
13
  | 'password'
14
+ | 'secret'
14
15
  | 'number'
15
16
  | 'tel'
16
17
  | 'url'
@@ -1,3 +1,54 @@
1
+ /**
2
+ * Shared color scales and color math for the MINT SDK.
3
+ *
4
+ * ## Why the exported values are hex, not `var(--…)`
5
+ *
6
+ * Every scale below is mirrored by a CSS custom property in
7
+ * `styles/variables.css` (`--mint-sample-1…9`, `--mint-slot-r/g/b/y`), so
8
+ * stylesheets and `:style` bindings can stay theme-aware by referencing the
9
+ * token. The JavaScript constants deliberately carry the plain hex **fallback**
10
+ * for the same slot, because these values are also
11
+ *
12
+ * - persisted into experiment design data (`SampleType.color`), where a
13
+ * `var(--…)` string would be meaningless outside the browser, and
14
+ * - handed to canvas / SVG / export code paths, which cannot resolve CSS
15
+ * custom properties.
16
+ *
17
+ * Keep the two in sync: a change here must be mirrored in `variables.css`.
18
+ */
19
+
20
+ import type { SlotPosition } from '../types/componentLabTypes'
21
+
22
+ /**
23
+ * Canonical categorical scale for sample types, plate maps, dose-response
24
+ * series and legends. Mirrors `--mint-sample-1` … `--mint-sample-9`.
25
+ */
26
+ export const SAMPLE_COLOR_SCALE: readonly string[] = [
27
+ '#3B82F6', // blue
28
+ '#10B981', // green
29
+ '#EF4444', // red
30
+ '#F59E0B', // amber
31
+ '#8B5CF6', // purple
32
+ '#F97316', // orange
33
+ '#06B6D4', // cyan
34
+ '#14B8A6', // teal
35
+ '#6B7280', // gray
36
+ ]
37
+
38
+ /**
39
+ * Slot-position colors shared by `PlateMapEditor` and `RackEditor`.
40
+ * Mirrors `--mint-slot-r`, `--mint-slot-g`, `--mint-slot-b`, `--mint-slot-y`.
41
+ */
42
+ export const SLOT_COLORS: Record<SlotPosition, string> = {
43
+ R: '#ef4444', // red
44
+ G: '#22c55e', // green
45
+ B: '#3b82f6', // blue
46
+ Y: '#eab308', // yellow
47
+ }
48
+
49
+ /** Slot positions in their canonical display order. */
50
+ export const SLOT_ORDER: readonly SlotPosition[] = ['R', 'G', 'B', 'Y']
51
+
1
52
  /**
2
53
  * Color utilities for deriving same-hue-family shades.
3
54
  *
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The one place a thrown value is turned into a developer-facing message.
3
+ *
4
+ * Five copies of this logic drifted apart across the composables and stores
5
+ * (some checked a bare `{ message }` object, some did not); this export is the
6
+ * union of what they all accepted, so every caller now reads the same message
7
+ * from the same value.
8
+ */
9
+ export function readErrorMessage(value: unknown, fallback = 'Request failed.'): string {
10
+ if (value instanceof Error && value.message) {
11
+ return value.message
12
+ }
13
+
14
+ if (typeof value === 'string' && value.trim()) {
15
+ return value
16
+ }
17
+
18
+ if (
19
+ typeof value === 'object'
20
+ && value !== null
21
+ && 'message' in value
22
+ && typeof (value as { message?: unknown }).message === 'string'
23
+ && (value as { message: string }).message.trim()
24
+ ) {
25
+ return (value as { message: string }).message
26
+ }
27
+
28
+ return fallback
29
+ }
@@ -1,4 +1,5 @@
1
1
  import type { FormSchema } from '../types/form-builder'
2
+ import { isRecord } from './records'
2
3
 
3
4
  export function recordValuesEqualForKeys(
4
5
  left: Record<string, unknown>,
@@ -47,6 +48,3 @@ function valuesEqual(left: unknown, right: unknown): boolean {
47
48
  return false
48
49
  }
49
50
 
50
- function isRecord(value: unknown): value is Record<string, unknown> {
51
- return typeof value === 'object' && value !== null && !Array.isArray(value)
52
- }
@@ -1,3 +1,4 @@
1
+ import { isRecord } from './records'
1
2
  export type PluginIconFormat = 'path' | 'data-url' | 'asset-url' | 'structured' | 'fallback'
2
3
 
3
4
  export interface StructuredPluginIconStop {
@@ -177,9 +178,6 @@ function parseOffset(value: unknown): string | undefined {
177
178
  return undefined
178
179
  }
179
180
 
180
- function isRecord(value: unknown): value is Record<string, unknown> {
181
- return typeof value === 'object' && value !== null && !Array.isArray(value)
182
- }
183
181
 
184
182
  function isSafeColor(value: unknown): value is string {
185
183
  return typeof value === 'string' && COLOR_REGEX.test(value)
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Stable references for plugin secret settings.
3
+ *
4
+ * A settings response never carries a secret's value. Every secret leaf is a
5
+ * marker instead:
6
+ *
7
+ * - `{ "$secret": "sec_…", "set": true }` — a stored secret, referenced by a
8
+ * stable opaque id. Send the marker back unchanged to keep the stored value.
9
+ * - `null` — nothing stored at that position.
10
+ * - `{ "$secret": null, "locked": true }` — the effective value comes from the
11
+ * environment and is never written back.
12
+ *
13
+ * On save each secret leaf accepts the reference, a plain string (a new value),
14
+ * or `null` (clear). Payloads carry `secret_format: "ref"` so a `null` reads as
15
+ * a deliberate clear rather than the deprecated "unchanged" placeholder.
16
+ */
17
+
18
+ /** Reserved marker key that references a stored secret. */
19
+ export const PLUGIN_SECRET_REF_KEY = '$secret'
20
+
21
+ /** Reserved payload key declaring which secret wire format a client speaks. */
22
+ export const PLUGIN_SECRET_FORMAT_KEY = 'secret_format'
23
+
24
+ /** Wire format published and understood by this SDK. */
25
+ export const PLUGIN_SECRET_FORMAT_REF = 'ref'
26
+
27
+ /** One `$secret` marker as published by a settings response. */
28
+ export interface PluginSecretRef {
29
+ $secret: string | null
30
+ set?: boolean
31
+ locked?: boolean
32
+ }
33
+
34
+ /** What a settings form should tell the user about one secret field. */
35
+ export type PluginSecretState = 'set' | 'unset' | 'environment'
36
+
37
+ const MARKER_KEYS = new Set([PLUGIN_SECRET_REF_KEY, 'set', 'locked'])
38
+
39
+ /** Return whether one settings value is a `$secret` reference marker. */
40
+ export function isPluginSecretRef(value: unknown): value is PluginSecretRef {
41
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false
42
+ const record = value as Record<string, unknown>
43
+ if (!(PLUGIN_SECRET_REF_KEY in record)) return false
44
+ return Object.keys(record).every(key => MARKER_KEYS.has(key))
45
+ }
46
+
47
+ /** Return the stored secret id behind a marker, or `null` when nothing is stored. */
48
+ export function pluginSecretId(value: unknown): string | null {
49
+ if (!isPluginSecretRef(value)) return null
50
+ return typeof value.$secret === 'string' ? value.$secret : null
51
+ }
52
+
53
+ /** Classify one secret field for display: stored, unset, or environment-provided. */
54
+ export function pluginSecretState(value: unknown): PluginSecretState {
55
+ if (isPluginSecretRef(value)) {
56
+ if (value.locked) return 'environment'
57
+ return typeof value.$secret === 'string' ? 'set' : 'unset'
58
+ }
59
+ return typeof value === 'string' && value.length > 0 ? 'set' : 'unset'
60
+ }
61
+
62
+ /** Human label for one secret field's state. */
63
+ export function pluginSecretLabel(value: unknown): string {
64
+ const state = pluginSecretState(value)
65
+ if (state === 'environment') return 'Provided by environment'
66
+ return state === 'set' ? 'Set' : 'Not set'
67
+ }
68
+
69
+ /** Whether a secret field is read-only because the environment supplies it. */
70
+ export function isPluginSecretLocked(value: unknown): boolean {
71
+ return isPluginSecretRef(value) && value.locked === true
72
+ }
73
+
74
+ /**
75
+ * Value to submit for an untouched secret field: the reference, unchanged.
76
+ *
77
+ * A locked marker round-trips too, which is how the platform keeps a stored
78
+ * value that an environment variable currently hides.
79
+ */
80
+ export function keepPluginSecret(current: unknown): PluginSecretRef | null {
81
+ if (isPluginSecretRef(current)) return { ...current }
82
+ return null
83
+ }
84
+
85
+ /** Value to submit when the user typed a new secret. */
86
+ export function setPluginSecret(value: string): string {
87
+ return value
88
+ }
89
+
90
+ /** Value to submit when the user cleared a secret. */
91
+ export function clearPluginSecret(): null {
92
+ return null
93
+ }
94
+
95
+ /** Whether a settings response declares the `$secret` reference wire format. */
96
+ export function usesPluginSecretReferences(response: unknown): boolean {
97
+ if (!response || typeof response !== 'object') return false
98
+ return (
99
+ (response as Record<string, unknown>)[PLUGIN_SECRET_FORMAT_KEY]
100
+ === PLUGIN_SECRET_FORMAT_REF
101
+ )
102
+ }
@@ -0,0 +1,9 @@
1
+ /** Narrow an unknown value to a plain object (arrays and null excluded). */
2
+ export function isRecord(value: unknown): value is Record<string, unknown> {
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
4
+ }
5
+
6
+ /** Narrow an unknown value to any non-null object, arrays included. */
7
+ export function isObjectLike(value: unknown): value is Record<string, unknown> {
8
+ return typeof value === 'object' && value !== null
9
+ }