@morscherlab/mint-sdk 1.3.0-beta.9 → 1.3.1
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.
- package/dist/__tests__/components/AutoGroupModal.anatomy.test.d.ts +1 -0
- package/dist/__tests__/components/AutoGroupModal.wiring.test.d.ts +1 -0
- package/dist/__tests__/composables/autoGroup/fieldEdits.test.d.ts +1 -0
- package/dist/__tests__/composables/autoGroup/golden.test.d.ts +1 -0
- package/dist/components/AutoGroupModal.adapter.d.ts +27 -4
- package/dist/components/SmartGroup.types.d.ts +22 -0
- package/dist/components/SmartGroupFieldRecipe.groups.d.ts +10 -2
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -0
- package/dist/components/index.js +1 -1
- package/dist/{components-GDDvof8D.js → components-bbanLd1u.js} +510 -287
- package/dist/components-bbanLd1u.js.map +1 -0
- package/dist/composables/autoGroup/classify.d.ts +7 -1
- package/dist/composables/autoGroup/columns.d.ts +16 -1
- package/dist/composables/autoGroup/index.d.ts +5 -7
- package/dist/composables/autoGroup/tokenize.d.ts +36 -1
- package/dist/composables/index.js +2 -2
- package/dist/composables/useAutoGroup.d.ts +13 -2
- package/dist/{composables-D6uqp0UF.js → composables-BbHozlA7.js} +2 -2
- package/dist/{composables-D6uqp0UF.js.map → composables-BbHozlA7.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/install.js +1 -1
- package/dist/permissions.js +2 -2
- package/dist/permissions.js.map +1 -1
- package/dist/styles.css +129 -96
- package/dist/types/auto-group.d.ts +1 -1
- package/dist/{validation-Dmp9Q5W0.js → validation-CukfLjy-.js} +323 -187
- package/dist/validation-CukfLjy-.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/components/AppTopBarPageSelector.test.ts +4 -4
- package/src/__tests__/components/AutoGroupModal.anatomy.test.ts +86 -0
- package/src/__tests__/components/AutoGroupModal.wiring.test.ts +53 -0
- package/src/__tests__/components/SampleSelector.test.ts +14 -16
- package/src/__tests__/components/SmartGroupFieldRecipe.groups.test.ts +23 -0
- package/src/__tests__/components/SmartGroupFieldRecipe.test.ts +176 -0
- package/src/__tests__/composables/autoGroup/columns.test.ts +100 -11
- package/src/__tests__/composables/autoGroup/fieldEdits.test.ts +74 -0
- package/src/__tests__/composables/autoGroup/fingerprint.test.ts +9 -0
- package/src/__tests__/composables/autoGroup/golden.test.ts +187 -0
- package/src/__tests__/composables/autoGroup/groupByOrder.test.ts +7 -7
- package/src/__tests__/composables/autoGroup/tokenLength.test.ts +7 -0
- package/src/__tests__/composables/autoGroup/tokenize.test.ts +78 -1
- package/src/__tests__/composables/useAutoGroup.test.ts +2 -1
- package/src/__tests__/fixtures/auto-group/share-exp021.txt +103 -0
- package/src/__tests__/fixtures/auto-group/share-exp031.txt +39 -0
- package/src/__tests__/fixtures/auto-group/share-exp114.txt +123 -0
- package/src/__tests__/fixtures/auto-group/share-exp214.txt +63 -0
- package/src/__tests__/utils/permissions.test.ts +15 -0
- package/src/components/AutoGroupModal.adapter.ts +80 -9
- package/src/components/AutoGroupModal.vue +41 -8
- package/src/components/SmartGroup.types.ts +23 -0
- package/src/components/SmartGroupFieldRecipe.groups.ts +14 -2
- package/src/components/SmartGroupFieldRecipe.vue +289 -169
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +3 -6
- package/src/composables/autoGroup/classify.ts +26 -7
- package/src/composables/autoGroup/columns.ts +144 -36
- package/src/composables/autoGroup/compose.ts +8 -10
- package/src/composables/autoGroup/fingerprint.ts +1 -1
- package/src/composables/autoGroup/index.ts +5 -12
- package/src/composables/autoGroup/tokenLength.ts +8 -0
- package/src/composables/autoGroup/tokenize.ts +148 -1
- package/src/composables/autoGroup/vocab.json +5 -11
- package/src/composables/useAutoGroup.ts +92 -79
- package/src/permissions.ts +3 -2
- package/src/styles/components/app-page-selector.css +58 -14
- package/src/styles/components/smart-group.css +71 -82
- package/src/types/auto-group.ts +1 -0
- package/dist/components-GDDvof8D.js.map +0 -1
- package/dist/composables/autoGroup/replicatePreGroup.d.ts +0 -36
- package/dist/validation-Dmp9Q5W0.js.map +0 -1
- package/src/composables/autoGroup/replicatePreGroup.ts +0 -124
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-CukfLjy-.js","names":[],"sources":["../src/composables/useRovingFocus.ts","../src/composables/useSortedItems.ts","../src/composables/useTextSearch.ts","../src/composables/useToast.ts","../src/composables/useTheme.ts","../src/composables/usePlatformContext.ts","../src/composables/usePresenceHeartbeat.ts","../src/composables/useRuntimeAlignment.ts","../src/composables/useAppExperiment.ts","../src/composables/controlWorkspaceOptions.ts","../src/composables/controlComponentBindings.ts","../src/composables/controlSchemaModel.ts","../src/composables/useControlWorkspace.ts","../src/composables/controlSchemaDoseDesign.ts","../src/composables/useFormValidation.ts","../src/composables/useForm.ts","../src/composables/formBuilderSchema.ts","../src/composables/useFormBuilder.ts","../src/composables/useMobileSupportGate.ts","../src/components/PluginWorkspaceView.controls.ts","../src/components/PluginWorkspaceView.navigation.ts","../src/components/PluginWorkspaceView.shell.ts","../src/composables/usePluginWorkspace.ts","../src/composables/useRequestSyncState.ts","../src/composables/pluginEndpointBuilder.ts","../src/composables/usePluginClient.ts","../src/composables/useJobsStatusTray.ts","../src/composables/useDoseCalculator.ts","../src/composables/useListReorder.ts","../src/composables/useRackEditor.ts","../src/composables/autoGroup/classKey.ts","../src/composables/autoGroup/vocab.json","../src/composables/autoGroup/classify.ts","../src/composables/autoGroup/tokenize.ts","../src/composables/autoGroup/columns.ts","../src/composables/autoGroup/cooccurrence.ts","../src/composables/autoGroup/colors.ts","../src/composables/autoGroup/compose.ts","../src/composables/autoGroup/fingerprint.ts","../src/composables/autoGroup/template.ts","../src/composables/autoGroup/tokenLength.ts","../src/composables/experimentDesignData.ts","../src/composables/useAutoGroup.ts","../src/composables/useFileImport.ts","../src/utils/sampleGroupPath.ts","../src/composables/useSampleGroups.ts","../src/composables/useExpansionSet.ts","../src/composables/useExperimentData.ts","../src/composables/useExperimentSamples.ts","../src/composables/useScheduleDrag.ts","../src/composables/useExperimentSave.ts","../src/composables/useTemplateCollection.ts","../src/composables/useBioTemplateControls.ts","../src/composables/useBioTemplateComponents.ts","../src/composables/flattenWorkspaceBindings.ts","../src/composables/useBioTemplateWorkspace.ts","../src/composables/useBioTemplatePackWorkspace.ts","../src/composables/useBioTemplatePresetWorkspace.ts","../src/composables/useGroupAssignment.ts","../src/composables/useReagentSeries.ts","../src/composables/protocolTemplateCatalog.ts","../src/composables/useProtocolTemplates.ts","../src/composables/useDebouncedWatch.ts","../src/composables/useExperimentSelector.ts","../src/composables/useAnalysisArtifacts.ts","../src/composables/filePicker/validation.ts"],"sourcesContent":["import { nextTick } from 'vue'\n\nexport interface UseRovingFocusOptions {\n /** Selectable item ids, in DOM order. Already excludes items skipped entirely (e.g. disabled tabs). */\n ids: () => string[]\n /** The id that is currently active/selected. */\n activeId: () => string | undefined\n /** Activates an id (e.g. emit `update:modelValue`). The composable focuses the matching element afterward. */\n activate: (id: string) => void\n /** Returns the focusable element for an id, queried lazily so it reflects the post-activation DOM. */\n getElement: (id: string) => HTMLElement | null | undefined\n /** Arrow-key axis: `'horizontal'` (Left/Right, default) or `'vertical'` (Up/Down). */\n orientation?: 'horizontal' | 'vertical'\n}\n\nexport interface UseRovingFocusReturn {\n /** Bind to each item's `@keydown`. */\n handleKeydown: (event: KeyboardEvent) => void\n}\n\n/**\n * WAI-ARIA roving-tabindex navigation with automatic activation (the tabs pattern):\n * Left/Right (or Up/Down when `orientation` is `'vertical'`) move to the adjacent item\n * and activate it immediately, wrapping past the ends; Home/End jump to the first/last\n * item. Only the active item should carry `tabindex=\"0\"`; give every other item\n * `tabindex=\"-1\"`. Used by BaseTabs.\n */\nexport function useRovingFocus(options: UseRovingFocusOptions): UseRovingFocusReturn {\n const orientation = options.orientation ?? 'horizontal'\n const prevKey = orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft'\n const nextKey = orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight'\n\n function moveTo(id: string | undefined) {\n if (id === undefined) return\n options.activate(id)\n void nextTick(() => options.getElement(id)?.focus())\n }\n\n function handleKeydown(event: KeyboardEvent) {\n const ids = options.ids()\n if (ids.length === 0) return\n const currentIndex = ids.indexOf(options.activeId() ?? '')\n\n if (event.key === 'Home') {\n event.preventDefault()\n moveTo(ids[0])\n return\n }\n if (event.key === 'End') {\n event.preventDefault()\n moveTo(ids[ids.length - 1])\n return\n }\n if (event.key === prevKey) {\n event.preventDefault()\n moveTo(ids[currentIndex <= 0 ? ids.length - 1 : currentIndex - 1])\n return\n }\n if (event.key === nextKey) {\n event.preventDefault()\n moveTo(ids[currentIndex === -1 || currentIndex >= ids.length - 1 ? 0 : currentIndex + 1])\n }\n }\n\n return { handleKeydown }\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type SortedItemsSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport type SortOrder = 'asc' | 'desc'\n\nexport interface SortDescriptor<TKey extends string = string> {\n key: TKey\n direction?: SortOrder | null\n}\n\nexport interface CompareSortValuesOptions {\n caseSensitive?: boolean\n}\n\nexport interface SortComparatorContext<TItem, TKey extends string = string> {\n key: TKey\n direction: SortOrder\n a: TItem\n b: TItem\n}\n\nexport type SortComparator<TItem, TKey extends string = string> = (\n aValue: unknown,\n bValue: unknown,\n context: SortComparatorContext<TItem, TKey>,\n) => number\n\nexport interface UseSortedItemsOptions<TItem, TKey extends string = string> {\n items: SortedItemsSource<readonly TItem[]>\n sort: SortedItemsSource<SortDescriptor<TKey> | null | undefined>\n enabled?: SortedItemsSource<boolean | null | undefined>\n caseSensitive?: SortedItemsSource<boolean | null | undefined>\n getValue: (item: TItem, key: TKey) => unknown\n compare?: SortComparator<TItem, TKey>\n}\n\nexport interface UseSortedItemsReturn<TItem, TKey extends string = string> {\n sort: ComputedRef<SortDescriptor<TKey> | null | undefined>\n sortedItems: ComputedRef<TItem[]>\n}\n\n/** Shared sorting for SDK tables and lists with stable empty-value handling. */\nexport function useSortedItems<TItem, TKey extends string = string>(\n options: UseSortedItemsOptions<TItem, TKey>,\n): UseSortedItemsReturn<TItem, TKey> {\n const sort = computed(() => toValue(options.sort))\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n const sortedItems = computed(() => {\n const items = [...toValue(options.items)]\n const activeSort = sort.value\n\n if (!enabled.value || !activeSort?.key || !activeSort.direction) return items\n\n const direction = activeSort.direction\n const caseSensitive = toValue(options.caseSensitive) ?? true\n\n return items.sort((a, b) => {\n const aValue = options.getValue(a, activeSort.key)\n const bValue = options.getValue(b, activeSort.key)\n\n if (options.compare) {\n return options.compare(aValue, bValue, {\n key: activeSort.key,\n direction,\n a,\n b,\n })\n }\n\n return compareSortValues(aValue, bValue, direction, { caseSensitive })\n })\n })\n\n return {\n sort,\n sortedItems,\n }\n}\n\nexport function compareSortValues(\n aValue: unknown,\n bValue: unknown,\n direction: SortOrder = 'asc',\n options: CompareSortValuesOptions = {},\n): number {\n const aEmpty = aValue === null || aValue === undefined\n const bEmpty = bValue === null || bValue === undefined\n\n if (aEmpty && bEmpty) return 0\n if (aEmpty) return 1\n if (bEmpty) return -1\n\n const aComparable = toComparableSortValue(aValue, options)\n const bComparable = toComparableSortValue(bValue, options)\n\n let comparison = 0\n if (typeof aComparable === 'number' && typeof bComparable === 'number') {\n comparison = aComparable - bComparable\n } else {\n comparison = String(aComparable).localeCompare(String(bComparable))\n }\n\n return direction === 'asc' ? comparison : -comparison\n}\n\nfunction toComparableSortValue(value: unknown, options: CompareSortValuesOptions): unknown {\n if (value instanceof Date) return value.getTime()\n if (typeof value === 'string' && options.caseSensitive === false) {\n return value.toLowerCase()\n }\n return value\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\n\nexport type TextSearchSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport type TextSearchCandidate = unknown | readonly unknown[]\n\nexport interface UseTextSearchOptions<TItem> {\n items: TextSearchSource<readonly TItem[]>\n query: TextSearchSource<string | null | undefined>\n enabled?: TextSearchSource<boolean | null | undefined>\n getText: (item: TItem) => TextSearchCandidate\n}\n\nexport interface UseTextSearchReturn<TItem> {\n query: ComputedRef<string>\n filteredItems: ComputedRef<TItem[]>\n matches: (item: TItem, query?: string | null | undefined) => boolean\n}\n\n/** Shared text-search filtering for tables, lists, selectors, and chip inputs. */\nexport function useTextSearch<TItem>(options: UseTextSearchOptions<TItem>): UseTextSearchReturn<TItem> {\n const query = computed(() => normalizeSearchQuery(toValue(options.query)))\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n function matches(item: TItem, overrideQuery?: string | null | undefined): boolean {\n const activeQuery = overrideQuery === undefined ? query.value : normalizeSearchQuery(overrideQuery)\n if (!activeQuery) return true\n return candidateMatchesSearch(options.getText(item), activeQuery)\n }\n\n const filteredItems = computed(() => {\n const items = [...toValue(options.items)]\n if (!enabled.value || !query.value) return items\n return items.filter(item => matches(item))\n })\n\n return {\n query,\n filteredItems,\n matches,\n }\n}\n\nexport function normalizeSearchQuery(value: string | null | undefined): string {\n return (value ?? '').trim().toLowerCase()\n}\n\nexport function candidateMatchesSearch(candidate: TextSearchCandidate, query: string): boolean {\n const normalizedQuery = normalizeSearchQuery(query)\n if (!normalizedQuery) return true\n const values = Array.isArray(candidate) ? candidate : [candidate]\n return values.some((value) => {\n if (value === null || value === undefined) return false\n return String(value).toLowerCase().includes(normalizedQuery)\n })\n}\n","import { ref } from 'vue'\nimport type { Toast, ToastOptions } from '../types'\n\nconst toasts = ref<Toast[]>([])\nlet nextId = 0\n\n/** Reactive global toast queue with success/error/warning/info variants and auto-dismiss timers. */\nexport function useToast() {\n /** Push a structured toast. `progress: 'indeterminate'` is the in-progress form and never auto-dismisses. */\n function push(options: ToastOptions): number {\n const id = nextId++\n const duration = options.duration ?? 3500\n toasts.value.push({\n id,\n type: 'success',\n ...options,\n message: options.message ?? options.title,\n duration,\n actions: options.actions?.slice(0, 2),\n })\n if (options.progress !== 'indeterminate') {\n setTimeout(() => dismiss(id), duration)\n }\n return id\n }\n\n function show(message: string, type: Toast['type'] = 'success', duration = 3500) {\n push({ title: message, type, duration })\n }\n\n function success(message: string, duration = 3500) {\n show(message, 'success', duration)\n }\n\n function error(message: string, duration = 5000) {\n show(message, 'error', duration)\n }\n\n function warning(message: string, duration = 4000) {\n show(message, 'warning', duration)\n }\n\n function info(message: string, duration = 3500) {\n show(message, 'info', duration)\n }\n\n function dismiss(id: number) {\n toasts.value = toasts.value.filter(t => t.id !== id)\n }\n\n function clear() {\n toasts.value = []\n }\n\n return { toasts, push, show, success, error, warning, info, dismiss, clear }\n}\n","import { computed, type Ref } from 'vue'\nimport { useSettingsStore } from '../stores/settings'\n\nexport interface UseThemeReturn {\n isDark: Ref<boolean>\n toggleTheme: () => void\n setTheme: (theme: 'light' | 'dark') => void\n}\n\n/** Reads and toggles the active theme (light/dark/system) with reactivity to OS preference changes. */\nexport function useTheme(): UseThemeReturn {\n const settings = useSettingsStore()\n\n // Load persisted theme from localStorage (idempotent — safe to call multiple times)\n settings.initialize()\n\n const isDark = computed(() => settings.isDark())\n\n function toggleTheme() {\n settings.theme = isDark.value ? 'light' : 'dark'\n }\n\n function setTheme(theme: 'light' | 'dark') {\n settings.theme = theme\n }\n\n return {\n isDark,\n toggleTheme,\n setTheme,\n }\n}\n","import { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { PlatformContext, PlatformContextOptions, PlatformEvent } from '../types'\n\nconst DEFAULT_CONTEXT: PlatformContext = {\n isIntegrated: false,\n theme: 'system',\n}\n\nconst platformContext = ref<PlatformContext>({ ...DEFAULT_CONTEXT })\n\n// Track allowed origins for postMessage security.\n// Inferred origins come from platform injection and URL params.\n// Consumer origins and allowAnyOrigin are tracked per composable instance.\nlet inferredOrigins: Set<string> = new Set()\nlet allowedOrigins: Set<string> = new Set()\nlet allowAnyOrigin = false\nlet initialized = false\nlet listenerCount = 0\nlet nextConsumerId = 0\nlet currentHandler: ((event: MessageEvent) => void) | null = null\nconst consumerOrigins: Map<number, Set<string>> = new Map()\nconst allowAnyOriginConsumers: Set<number> = new Set()\n\n/**\n * Derive origin from URL (protocol + host)\n */\nfunction getOriginFromUrl(url: string): string | null {\n try {\n const parsed = new URL(url)\n return parsed.origin\n } catch {\n return null\n }\n}\n\nfunction normalizeAllowedOrigins(origins: string[] | undefined): Set<string> {\n const normalized = new Set<string>()\n if (!origins) {\n return normalized\n }\n\n for (const origin of origins) {\n normalized.add(getOriginFromUrl(origin) || origin)\n }\n return normalized\n}\n\nfunction recomputeOriginPolicy(): void {\n allowedOrigins = new Set(inferredOrigins)\n for (const origins of consumerOrigins.values()) {\n for (const origin of origins) {\n allowedOrigins.add(origin)\n }\n }\n allowAnyOrigin = allowAnyOriginConsumers.size > 0\n}\n\nfunction resetPlatformContextState(): void {\n inferredOrigins = new Set()\n allowedOrigins = new Set()\n allowAnyOrigin = false\n initialized = false\n listenerCount = 0\n currentHandler = null\n consumerOrigins.clear()\n allowAnyOriginConsumers.clear()\n platformContext.value = { ...DEFAULT_CONTEXT }\n}\n\n/**\n * Check if an origin is allowed for postMessage communication\n */\nfunction isOriginAllowed(origin: string): boolean {\n // Development mode: allow any origin (must be explicitly enabled)\n if (allowAnyOrigin) {\n console.warn('[MINT SDK] postMessage origin validation disabled - only use in development')\n return true\n }\n\n // Same origin is always allowed\n if (origin === window.location.origin) {\n return true\n }\n\n // Check against allowed origins list\n return allowedOrigins.has(origin)\n}\n\n/**\n * Platform context composable for plugin integration with MINT Platform.\n *\n * Provides secure communication with the parent platform via postMessage.\n *\n * @param options - Configuration options\n * @param options.allowedOrigins - List of allowed origins for postMessage\n * @param options.allowAnyOrigin - Allow any origin (UNSAFE, development only)\n *\n * @example\n * ```typescript\n * // Basic usage - derives origin from platform injection\n * const { isIntegrated, user, theme } = usePlatformContext()\n *\n * // With explicit allowed origins\n * const { isIntegrated } = usePlatformContext({\n * allowedOrigins: ['https://mint.example.com']\n * })\n *\n * // Development mode (UNSAFE)\n * const { isIntegrated } = usePlatformContext({\n * allowAnyOrigin: import.meta.env.DEV\n * })\n * ```\n */\n/** Connects a plugin to the MINT platform via postMessage, exposing user, theme, and experiment context. */\nexport function usePlatformContext(options: PlatformContextOptions = {}) {\n const consumerId = ++nextConsumerId\n const instanceOrigins = normalizeAllowedOrigins(options.allowedOrigins)\n const instanceAllowAnyOrigin = options.allowAnyOrigin === true\n\n function detectPlatform(): void {\n const detectedOrigins = new Set<string>()\n\n // Check if running under MINT Platform by looking for platform-injected global\n const platformData = (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n\n if (platformData) {\n platformContext.value = {\n ...platformData,\n isIntegrated: true,\n }\n\n // Derive platform origin from injected data\n if (platformData.platformOrigin) {\n detectedOrigins.add(platformData.platformOrigin)\n } else if (platformData.platformApiUrl) {\n const origin = getOriginFromUrl(platformData.platformApiUrl)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n } else {\n // Check for platform indicator in URL or localStorage\n const urlParams = new URLSearchParams(window.location.search)\n const hasPluginParam = urlParams.has('mint-plugin')\n\n // Try to get platform origin from URL parameter\n const platformOrigin = urlParams.get('mint-origin')\n if (platformOrigin) {\n const origin = getOriginFromUrl(platformOrigin)\n if (origin) {\n detectedOrigins.add(origin)\n }\n }\n\n platformContext.value = {\n isIntegrated: hasPluginParam,\n theme: (() => {\n try {\n const s = localStorage.getItem('mint-settings')\n if (s) return (JSON.parse(s).theme as 'light' | 'dark' | 'system') || 'system'\n } catch { /* ignore */ }\n return 'system'\n })(),\n platformOrigin: platformOrigin || undefined,\n }\n }\n\n inferredOrigins = detectedOrigins\n }\n\n function handlePlatformMessage(event: MessageEvent): void {\n // Only accept messages from parent window (platform)\n if (event.source !== window.parent) return\n\n // Validate origin for security\n if (!isOriginAllowed(event.origin)) {\n console.warn(`[MINT SDK] Rejected postMessage from untrusted origin: ${event.origin}`)\n return\n }\n\n try {\n const platformEvent = event.data as PlatformEvent\n if (!platformEvent.type?.startsWith('mint:')) return\n\n switch (platformEvent.type) {\n case 'mint:theme-changed':\n platformContext.value.theme = platformEvent.payload as 'light' | 'dark' | 'system'\n break\n case 'mint:user-changed':\n platformContext.value.user = platformEvent.payload as PlatformContext['user']\n break\n }\n } catch {\n // Ignore invalid messages\n }\n }\n\n /**\n * Send a message to the parent platform.\n * Uses validated target origin for security.\n */\n function sendToPlatform(event: PlatformEvent): void {\n if (!platformContext.value.isIntegrated || window.parent === window) {\n return\n }\n\n // Determine target origin\n let targetOrigin: string\n\n if (platformContext.value.platformOrigin) {\n // Use explicitly configured platform origin\n targetOrigin = platformContext.value.platformOrigin\n } else if (allowedOrigins.size > 0) {\n // Use first allowed origin (typically the platform)\n targetOrigin = allowedOrigins.values().next().value as string\n } else if (allowAnyOrigin) {\n // Development mode fallback\n targetOrigin = '*'\n console.warn('[MINT SDK] Using wildcard origin for postMessage - only use in development')\n } else {\n // Safety: if no origin is configured, log warning and don't send\n console.warn('[MINT SDK] Cannot send postMessage: no platform origin configured')\n return\n }\n\n window.parent.postMessage(event, targetOrigin)\n }\n\n /**\n * Request navigation to a path in the platform.\n */\n function navigate(path: string): void {\n sendToPlatform({\n type: 'mint:navigate',\n payload: path,\n })\n }\n\n /**\n * Show a notification in the platform.\n */\n function notify(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {\n sendToPlatform({\n type: 'mint:notification',\n payload: { message, type },\n })\n }\n\n onMounted(() => {\n consumerOrigins.set(consumerId, instanceOrigins)\n if (instanceAllowAnyOrigin) {\n allowAnyOriginConsumers.add(consumerId)\n }\n\n if (!initialized) {\n detectPlatform()\n currentHandler = handlePlatformMessage\n window.addEventListener('message', handlePlatformMessage)\n initialized = true\n }\n\n listenerCount++\n recomputeOriginPolicy()\n })\n\n onUnmounted(() => {\n consumerOrigins.delete(consumerId)\n allowAnyOriginConsumers.delete(consumerId)\n\n listenerCount = Math.max(0, listenerCount - 1)\n if (listenerCount === 0) {\n if (currentHandler) {\n window.removeEventListener('message', currentHandler)\n }\n resetPlatformContextState()\n return\n }\n\n recomputeOriginPolicy()\n })\n\n const isIntegrated = computed(() => platformContext.value.isIntegrated)\n const plugin = computed(() => platformContext.value.plugin)\n const user = computed(() => platformContext.value.user)\n const theme = computed(() => platformContext.value.theme)\n const features = computed(() => platformContext.value.features)\n\n return {\n context: platformContext,\n isIntegrated,\n plugin,\n user,\n theme,\n features,\n navigate,\n notify,\n sendToPlatform,\n }\n}\n","import {\n computed,\n onMounted,\n onScopeDispose,\n readonly,\n ref,\n toValue,\n watch,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\n\nimport { useApi } from './useApi'\n\nconst PRESENCE_CLIENT_ID_KEY = 'mint:presence:client-id'\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000\n\nlet pageFallbackClientId: string | null = null\n\nexport interface PresenceHeartbeatPayload {\n client_id: string\n scope: string\n}\n\nexport interface PresenceHeartbeatResponse {\n frontend_revision?: string | null\n}\n\ninterface PresenceDocument {\n readonly visibilityState: DocumentVisibilityState\n addEventListener(type: 'visibilitychange', listener: EventListener): void\n removeEventListener(type: 'visibilitychange', listener: EventListener): void\n}\n\ninterface PresenceStorage {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n}\n\nexport interface PresenceHeartbeatOptions {\n /** Platform, plugin id, or plugin name reported for this browser tab. */\n scope: MaybeRefOrGetter<string | null | undefined>\n /** Disable all traffic, including for standalone plugins. */\n enabled?: MaybeRefOrGetter<boolean>\n /** Heartbeat interval. Defaults to 30 seconds. */\n intervalMs?: number\n /** Test or host storage seam. Defaults to sessionStorage. */\n storage?: PresenceStorage | null\n /** Test or host document seam. Defaults to the current document. */\n document?: PresenceDocument | null\n /** Test seam for generating the per-tab id. */\n createClientId?: () => string\n /** Test or custom transport seam. Defaults to authenticated POST /api/presence/heartbeat. */\n send?: (payload: PresenceHeartbeatPayload) => Promise<unknown> | unknown\n /** Observe the authenticated response without adding another poller. */\n onResponse?: (response: PresenceHeartbeatResponse | unknown) => void\n /** Test timing seam. Defaults to the browser scheduler. */\n setInterval?: (callback: () => void, intervalMs: number) => unknown\n /** Test timing seam. Defaults to the browser scheduler. */\n clearInterval?: (intervalId: unknown) => void\n}\n\nexport interface UsePresenceHeartbeatReturn {\n clientId: string\n isRunning: Readonly<Ref<boolean>>\n sendNow: () => Promise<void>\n}\n\nfunction defaultClientId(): string {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID()\n }\n return `presence-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nfunction defaultStorage(): PresenceStorage | null {\n try {\n return globalThis.sessionStorage ?? null\n } catch {\n return null\n }\n}\n\nfunction defaultDocument(): PresenceDocument | null {\n return typeof globalThis.document === 'undefined' ? null : globalThis.document\n}\n\n/** Return the stable id shared by presence callers in the current browser tab. */\nexport function getPresenceClientId(\n storage: PresenceStorage | null = defaultStorage(),\n createClientId: () => string = defaultClientId,\n): string {\n try {\n const stored = storage?.getItem(PRESENCE_CLIENT_ID_KEY)\n if (stored) return stored\n } catch {\n // Keep the tab usable when storage is blocked.\n }\n\n const nextClientId = createClientId()\n try {\n if (storage) {\n storage.setItem(PRESENCE_CLIENT_ID_KEY, nextClientId)\n return nextClientId\n }\n } catch {\n // Fall through to the page-local fallback when storage is blocked.\n }\n\n if (!pageFallbackClientId) pageFallbackClientId = nextClientId\n return pageFallbackClientId\n}\n\n/** Report one visible integrated MINT browser tab to the platform presence tracker. */\nexport function usePresenceHeartbeat(\n options: PresenceHeartbeatOptions,\n): UsePresenceHeartbeatReturn {\n const presenceDocument = options.document === undefined ? defaultDocument() : options.document\n const clientId = getPresenceClientId(\n options.storage === undefined ? defaultStorage() : options.storage,\n options.createClientId ?? defaultClientId,\n )\n const intervalMs = options.intervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS\n const scheduleInterval = options.setInterval ?? ((callback: () => void, delayMs: number) => (\n globalThis.setInterval(callback, delayMs)\n ))\n const cancelInterval = options.clearInterval ?? ((intervalId: unknown) => {\n globalThis.clearInterval(intervalId as ReturnType<typeof globalThis.setInterval>)\n })\n if (intervalMs <= 0) throw new Error('Presence heartbeat interval must be positive')\n\n const api = options.send ? null : useApi({ baseUrl: '/api' })\n const send = options.send ?? ((payload: PresenceHeartbeatPayload) => (\n api!.post('/presence/heartbeat', payload)\n ))\n const enabled = computed(() => toValue(options.enabled ?? true))\n const scope = computed(() => toValue(options.scope)?.trim() ?? '')\n const isRunning = ref(false)\n let intervalId: unknown | null = null\n let sending = false\n let mounted = false\n\n function isVisible(): boolean {\n return presenceDocument?.visibilityState !== 'hidden'\n }\n\n function shouldRun(): boolean {\n return mounted && enabled.value && Boolean(scope.value) && isVisible()\n }\n\n async function sendNow(): Promise<void> {\n if (!shouldRun() || sending) return\n sending = true\n try {\n const response = await send({ client_id: clientId, scope: scope.value })\n options.onResponse?.(response)\n } catch {\n // Presence is advisory and must never break plugin or platform UI.\n } finally {\n sending = false\n }\n }\n\n function stop(): void {\n if (intervalId !== null) cancelInterval(intervalId)\n intervalId = null\n isRunning.value = false\n }\n\n function start(): void {\n stop()\n if (!shouldRun()) return\n isRunning.value = true\n void sendNow()\n intervalId = scheduleInterval(() => void sendNow(), intervalMs)\n }\n\n function handleVisibilityChange(): void {\n start()\n }\n\n watch([enabled, scope], start)\n\n onMounted(() => {\n mounted = true\n presenceDocument?.addEventListener('visibilitychange', handleVisibilityChange)\n start()\n })\n\n onScopeDispose(() => {\n mounted = false\n presenceDocument?.removeEventListener('visibilitychange', handleVisibilityChange)\n stop()\n })\n\n return {\n clientId,\n isRunning: readonly(isRunning),\n sendNow,\n }\n}\n","import {\n computed,\n onMounted,\n onScopeDispose,\n readonly,\n ref,\n toValue,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\n\nconst RUNTIME_RELOAD_KEY_PREFIX = 'mint:runtime-reload:'\nconst REVISION_QUERY_KEY = '__mint_revision'\nconst inMemoryReloadGuards = new Set<string>()\n\ninterface RuntimeStorage {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n}\n\ninterface RuntimeEventTarget {\n addEventListener(type: 'vite:preloadError', listener: EventListener): void\n removeEventListener(type: 'vite:preloadError', listener: EventListener): void\n}\n\ninterface RuntimeVisibilityTarget {\n addEventListener(type: 'visibilitychange', listener: EventListener): void\n removeEventListener(type: 'visibilitychange', listener: EventListener): void\n}\n\nexport interface RuntimeRevisionResponse {\n frontend_revision?: string | null\n}\n\nexport interface RuntimeAlignmentOptions {\n /** Revision embedded in the HTML that booted this tab. */\n currentRevision?: MaybeRefOrGetter<string | null | undefined>\n /** Browser visibility seam. */\n visibility?: () => DocumentVisibilityState\n /** Current location seam. */\n currentUrl?: () => string\n /** Location replacement seam. */\n replace?: (url: string) => void\n /** Per-tab recovery guard storage. */\n storage?: RuntimeStorage | null\n /** Vite preload error source. */\n eventTarget?: RuntimeEventTarget | null\n /** Browser visibility event source. */\n visibilityTarget?: RuntimeVisibilityTarget | null\n}\n\nexport interface UseRuntimeAlignmentReturn {\n updateAvailable: Readonly<Ref<boolean>>\n nextRevision: Readonly<Ref<string | null>>\n observe: (response: RuntimeRevisionResponse | unknown) => void\n reload: () => void\n recoverMissingChunk: () => void\n}\n\nfunction browserStorage(): RuntimeStorage | null {\n try {\n return globalThis.sessionStorage ?? null\n } catch {\n return null\n }\n}\n\nfunction browserEventTarget(): RuntimeEventTarget | null {\n return typeof globalThis.window === 'undefined' ? null : globalThis.window\n}\n\nfunction browserVisibilityTarget(): RuntimeVisibilityTarget | null {\n return typeof globalThis.document === 'undefined' ? null : globalThis.document\n}\n\nfunction responseRevision(response: RuntimeRevisionResponse | unknown): string | null {\n if (!response || typeof response !== 'object') return null\n const value = (response as RuntimeRevisionResponse).frontend_revision\n return typeof value === 'string' && value ? value : null\n}\n\n/** Keep a loaded MINT frontend aligned with the backend revision serving its scope. */\nexport function useRuntimeAlignment(\n options: RuntimeAlignmentOptions = {},\n): UseRuntimeAlignmentReturn {\n const storage = options.storage === undefined ? browserStorage() : options.storage\n const eventTarget = options.eventTarget === undefined ? browserEventTarget() : options.eventTarget\n const visibilityTarget = options.visibilityTarget === undefined\n ? browserVisibilityTarget()\n : options.visibilityTarget\n const visibility = options.visibility ?? (() => globalThis.document?.visibilityState ?? 'visible')\n const currentUrl = options.currentUrl ?? (() => globalThis.location?.href ?? '/')\n const replace = options.replace ?? ((url: string) => globalThis.location?.replace(url))\n const initialRevision = computed(() => toValue(options.currentRevision) ?? null)\n const baselineRevision = ref<string | null>(initialRevision.value)\n const nextRevision = ref<string | null>(null)\n const updateAvailable = computed(() => nextRevision.value !== null)\n let wasHidden = false\n\n function reloadTo(revision: string, guardKind: 'revision' | 'chunk'): void {\n const guardKey = `${RUNTIME_RELOAD_KEY_PREFIX}${guardKind}:${revision}`\n const url = new URL(currentUrl(), globalThis.location?.origin ?? 'http://localhost')\n if (url.searchParams.get(REVISION_QUERY_KEY) === revision) return\n if (inMemoryReloadGuards.has(guardKey)) return\n try {\n if (storage?.getItem(guardKey)) {\n inMemoryReloadGuards.add(guardKey)\n return\n }\n storage?.setItem(guardKey, '1')\n } catch {\n // A blocked sessionStorage must not block recovery.\n }\n inMemoryReloadGuards.add(guardKey)\n url.searchParams.set(REVISION_QUERY_KEY, revision)\n replace(url.toString())\n }\n\n function observe(response: RuntimeRevisionResponse | unknown): void {\n const revision = responseRevision(response)\n if (!revision) return\n const current = initialRevision.value ?? baselineRevision.value\n if (!current) {\n baselineRevision.value = revision\n return\n }\n if (revision === current) {\n wasHidden = false\n return\n }\n if (wasHidden || visibility() === 'hidden') {\n wasHidden = false\n reloadTo(revision, 'revision')\n return\n }\n nextRevision.value = revision\n }\n\n function reload(): void {\n if (nextRevision.value) reloadTo(nextRevision.value, 'revision')\n }\n\n function recoverMissingChunk(): void {\n reloadTo(baselineRevision.value ?? initialRevision.value ?? 'unknown', 'chunk')\n }\n\n function handlePreloadError(event: Event): void {\n event.preventDefault()\n recoverMissingChunk()\n }\n\n function handleVisibilityChange(): void {\n if (visibility() === 'hidden') wasHidden = true\n }\n\n onMounted(() => {\n eventTarget?.addEventListener('vite:preloadError', handlePreloadError)\n visibilityTarget?.addEventListener('visibilitychange', handleVisibilityChange)\n })\n onScopeDispose(() => {\n eventTarget?.removeEventListener('vite:preloadError', handlePreloadError)\n visibilityTarget?.removeEventListener('visibilitychange', handleVisibilityChange)\n })\n\n return {\n updateAvailable: readonly(updateAvailable),\n nextRevision: readonly(nextRevision),\n observe,\n reload,\n recoverMissingChunk,\n }\n}\n\n/** Read the revision injected into the HTML that started this browser tab. */\nexport function getInjectedFrontendRevision(): string | null {\n if (typeof globalThis.window === 'undefined') return null\n const runtimeWindow = globalThis.window as typeof globalThis.window & {\n __MINT_FRONTEND_REVISION__?: string\n __MINT_PLATFORM__?: { plugin?: { frontend_revision?: string } }\n }\n return runtimeWindow.__MINT_PLATFORM__?.plugin?.frontend_revision\n ?? runtimeWindow.__MINT_FRONTEND_REVISION__\n ?? null\n}\n","import {\n ref,\n computed,\n provide,\n toValue,\n watch,\n onScopeDispose,\n type Ref,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\nimport type { ExperimentSummary, ExperimentStatus } from '../types'\nimport { useExperimentStore } from '../stores/experiment'\nimport { resolveExperimentCode } from './experiment-utils'\n\nexport interface UseAppExperimentOptions {\n /**\n * Called when the shared store adopts an experiment — a modal selection or a\n * resolved deep link. The record always comes from the platform.\n */\n onSelect?: (experiment: ExperimentSummary) => void | Promise<void>\n onSave?: () => string | null | Promise<string | null>\n onDetach?: () => void\n saveDisabled?: Ref<boolean> | ComputedRef<boolean>\n saveDisabledMessage?: string | Ref<string | undefined> | ComputedRef<string | undefined>\n}\n\nexport interface AppExperimentPopoverBinding {\n experimentName?: string\n experimentCode?: string\n experimentStatus?: ExperimentStatus\n /** An experiment is bound but its record has not arrived yet. */\n isResolving: boolean\n /** Resolution failed; the binding is kept so the user can retry or detach. */\n error?: string\n showSave: boolean\n showDetach: boolean\n saveDisabled: boolean\n saveDisabledMessage?: string\n saveLoading: boolean\n saveSuccessMessage?: string\n}\n\nexport interface AppExperimentSelectorModalBinding {\n modelValue: boolean\n currentExperimentId: number | null\n}\n\nexport interface UseAppExperimentReturn {\n experimentName: ComputedRef<string | undefined>\n experimentCode: ComputedRef<string | undefined>\n experimentStatus: ComputedRef<ExperimentStatus | undefined>\n experimentId: ComputedRef<number | null>\n isResolving: ComputedRef<boolean>\n error: ComputedRef<string | null>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n closeModal: () => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport interface AppExperimentState {\n experimentName: ComputedRef<string | undefined>\n experimentCode: ComputedRef<string | undefined>\n experimentStatus: ComputedRef<ExperimentStatus | undefined>\n experimentId: ComputedRef<number | null>\n isResolving: ComputedRef<boolean>\n error: ComputedRef<string | null>\n showModal: Ref<boolean>\n saveLoading: Ref<boolean>\n saveSuccessMessage: Ref<string | undefined>\n showSave: Ref<boolean>\n showDetach: ComputedRef<boolean>\n closeModal: () => void\n saveDisabled: ComputedRef<boolean>\n saveDisabledMessage: ComputedRef<string | undefined>\n popover: ComputedRef<AppExperimentPopoverBinding>\n selectorModal: ComputedRef<AppExperimentSelectorModalBinding>\n openModal: () => void\n handleSave: () => Promise<void>\n handleDetach: () => void\n}\n\nexport const APP_EXPERIMENT_KEY: InjectionKey<AppExperimentState> = Symbol('app-experiment')\n\n/**\n * Projects the current experiment from the shared store into an AppTopBar app\n * shell, and owns the shell-local concerns the store has no opinion on: the\n * selector modal's open state and the save flow.\n *\n * The composable never writes a selection of its own. `ExperimentSelectorModal`\n * commits to the store and this reads back, so a displayed name can only ever\n * have come from the platform.\n *\n * @example Recommended\n * ```ts\n * const appExperiment = useAppExperiment({\n * onSelect: experiment => loadExperiment(experiment.id),\n * })\n * ```\n */\nexport function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppExperimentReturn {\n const store = useExperimentStore()\n\n const showModal = ref(false)\n const saveLoading = ref(false)\n const saveSuccessMessage = ref<string | undefined>()\n\n let successTimer: ReturnType<typeof setTimeout> | null = null\n\n const experimentName = computed(() => store.current?.name)\n const experimentCode = computed(() =>\n store.current ? resolveExperimentCode(store.current) : undefined,\n )\n const experimentStatus = computed(() => store.current?.status)\n // Set while resolving and after a failed resolve, so the shell can tell\n // \"nothing selected\" apart from \"selected but not resolved\".\n const experimentId = computed(() => store.currentId)\n const isResolving = computed(() => store.isResolving)\n const error = computed(() => store.error)\n\n const showSave = ref(!!options.onSave)\n const showDetach = computed(() => experimentId.value !== null)\n const saveDisabled = computed(() => toValue(options.saveDisabled) ?? false)\n const saveDisabledMessage = computed(() => toValue(options.saveDisabledMessage))\n const popover = computed<AppExperimentPopoverBinding>(() => ({\n experimentName: experimentName.value,\n experimentCode: experimentCode.value,\n experimentStatus: experimentStatus.value,\n isResolving: isResolving.value,\n error: error.value ?? undefined,\n showSave: showSave.value,\n showDetach: showDetach.value,\n saveDisabled: saveDisabled.value,\n saveDisabledMessage: saveDisabledMessage.value,\n saveLoading: saveLoading.value,\n saveSuccessMessage: saveSuccessMessage.value,\n }))\n const selectorModal = computed<AppExperimentSelectorModalBinding>(() => ({\n modelValue: showModal.value,\n currentExperimentId: experimentId.value,\n }))\n\n if (options.onSelect) {\n watch(\n () => store.current,\n (experiment) => {\n if (experiment) void options.onSelect?.(experiment)\n },\n )\n }\n\n function openModal() {\n showModal.value = true\n }\n\n function closeModal() {\n showModal.value = false\n }\n\n async function handleSave() {\n if (!options.onSave || saveLoading.value) return\n saveLoading.value = true\n try {\n const message = await options.onSave()\n if (message) {\n saveSuccessMessage.value = message\n if (successTimer) clearTimeout(successTimer)\n successTimer = setTimeout(() => {\n saveSuccessMessage.value = undefined\n successTimer = null\n }, 3000)\n }\n } finally {\n saveLoading.value = false\n }\n }\n\n function handleDetach() {\n store.clear()\n options.onDetach?.()\n }\n\n onScopeDispose(() => {\n if (successTimer) clearTimeout(successTimer)\n })\n\n const state: AppExperimentState = {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n isResolving,\n error,\n showModal,\n saveLoading,\n saveSuccessMessage,\n showSave,\n showDetach,\n saveDisabled,\n saveDisabledMessage,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSave,\n handleDetach,\n }\n\n provide(APP_EXPERIMENT_KEY, state)\n\n return {\n experimentName,\n experimentCode,\n experimentStatus,\n experimentId,\n isResolving,\n error,\n popover,\n selectorModal,\n openModal,\n closeModal,\n handleSave,\n handleDetach,\n }\n}\n","import type {\n ControlWorkspaceOptions,\n} from './controlSchemaTypes'\n\nexport function mergeControlWorkspaceOptions(\n base?: ControlWorkspaceOptions,\n override?: ControlWorkspaceOptions,\n): ControlWorkspaceOptions {\n return {\n ...(base ?? {}),\n ...(override ?? {}),\n initialValues: {\n ...(base?.initialValues ?? {}),\n ...(override?.initialValues ?? {}),\n },\n topBarSettings: {\n ...(base?.topBarSettings ?? {}),\n ...(override?.topBarSettings ?? {}),\n },\n }\n}\n","import type {\n ControlComponentBinding,\n ControlComponentBindingConfig,\n ControlComponentBindingRecordConfig,\n ControlComponentBindingsById,\n ControlComponentBindingsConfig,\n ControlComponentPropsMap,\n ControlComponentPropSource,\n} from './controlSchemaTypes'\n\n/** Map control workspace values into component props for direct `v-bind` usage. */\nexport function controlValuesToComponentProps<TValues extends Record<string, unknown>>(\n values: TValues,\n mapping?: ControlComponentPropsMap<TValues>,\n): Record<string, unknown> {\n if (mapping === undefined) return { ...values }\n\n if (Array.isArray(mapping)) {\n const props: Record<string, unknown> = {}\n for (const key of mapping) {\n props[key] = values[key]\n }\n return props\n }\n\n const props: Record<string, unknown> = {}\n for (const [prop, source] of Object.entries(mapping) as Array<[string, ControlComponentPropSource<TValues>]>) {\n props[prop] = typeof source === 'function' ? source(values) : values[source]\n }\n return props\n}\n\n/** Map control workspace values into named SDK component bindings for direct slot rendering. */\nexport function controlValuesToComponentBindings<TValues extends Record<string, unknown>>(\n values: TValues,\n bindings?: ControlComponentBindingsConfig<TValues>,\n): ControlComponentBinding[] {\n if (bindings === undefined) return []\n\n return normalizeControlComponentBindingConfigs(bindings).map(binding => ({\n id: binding.id,\n component: binding.component,\n props: controlValuesToComponentProps(values, binding.props),\n }))\n}\n\n/** Map control workspace values into SDK component bindings keyed by binding id. */\nexport function controlValuesToComponentBindingsById<TValues extends Record<string, unknown>>(\n values: TValues,\n bindings?: ControlComponentBindingsConfig<TValues>,\n): ControlComponentBindingsById {\n return Object.fromEntries(\n controlValuesToComponentBindings(values, bindings).map(binding => [binding.id, binding]),\n )\n}\n\nfunction normalizeControlComponentBindingConfigs<TValues extends Record<string, unknown>>(\n bindings: ControlComponentBindingsConfig<TValues>,\n): Array<Required<Pick<ControlComponentBindingConfig<TValues>, 'id' | 'component'>> & Pick<ControlComponentBindingConfig<TValues>, 'props'>> {\n if (Array.isArray(bindings)) {\n const usedIds = new Map<string, number>()\n return bindings.map(binding => ({\n id: uniqueComponentBindingId(binding.id ?? binding.component, usedIds),\n component: binding.component,\n props: binding.props,\n }))\n }\n\n return Object.entries(bindings).map(([id, binding]: [string, ControlComponentBindingRecordConfig<TValues>]) => ({\n id,\n component: binding.component,\n props: binding.props,\n }))\n}\n\nfunction uniqueComponentBindingId(id: string, usedIds: Map<string, number>): string {\n const count = usedIds.get(id) ?? 0\n usedIds.set(id, count + 1)\n return count === 0 ? id : `${id}-${count + 1}`\n}\n","import type {\n ControlModel,\n ControlModelBinding,\n ControlModelSectionConfig,\n ControlSchema,\n ControlSectionConfig,\n ControlSidebarConfig,\n ControlViewConfig,\n ControlWorkspaceOptions,\n} from './controlSchemaTypes'\nimport {\n normalizeControlDefinition,\n} from './controlSchemaNormalize'\nimport {\n omitUndefined,\n} from './controlSchemaUtils'\n\nexport function isControlModelBinding<TBinding extends ControlModelBinding = ControlModelBinding>(\n model: unknown,\n): model is TBinding {\n return (\n typeof model === 'object'\n && model !== null\n && 'controls' in model\n && 'controlOptions' in model\n )\n}\n\nexport function resolveControlModel(\n model: ControlModel | ControlModelBinding | undefined,\n): ControlModelBinding | undefined {\n if (model === undefined) return undefined\n return isControlModelBinding(model) ? model : defineControlModel(model)\n}\n\n/**\n * Create a complete workspace component binding from a simple controls data model for ControlWorkspaceView, generated forms, and sidebars.\n *\n * @example Recommended\n * ```ts\n * const workspaceModel = defineControlModel({\n * controls: { threshold: { type: 'number', default: 0.05 } },\n * })\n * ```\n */\nexport function defineControlModel(model: ControlModel): ControlModelBinding {\n const {\n controls: rootControls,\n sections: rootSections,\n views: modelViews,\n components,\n componentBindings,\n componentProps,\n componentPropsById,\n ...baseOptions\n } = model\n const resolvedComponentBindings = componentBindings ?? components\n const controls: ControlSchema = {}\n const views: Record<string, ControlViewConfig> = {}\n const sections: Record<string, ControlSectionConfig> = {}\n\n const defaultViewId = model.view ?? 'default'\n const defaultSectionId = model.section ?? 'controls'\n\n if (rootControls) {\n registerSectionOptions(sections, defaultSectionId, {\n id: defaultSectionId,\n label: model.sectionLabel,\n title: model.sectionLabel,\n columns: model.columns,\n })\n appendModelControls(controls, rootControls, defaultViewId, defaultSectionId)\n }\n\n for (const [sectionId, section] of Object.entries(rootSections ?? {})) {\n registerSectionOptions(sections, sectionId, controlModelSectionOptions(section))\n appendModelControls(controls, section.controls, defaultViewId, sectionId, section.sidebar)\n }\n\n for (const [viewId, view] of Object.entries(modelViews ?? {})) {\n const {\n controls: viewControls,\n sections: viewSections,\n section,\n sectionLabel,\n sectionDescription,\n ...viewConfig\n } = view\n\n views[viewId] = omitUndefined(viewConfig)\n\n if (viewControls) {\n const sectionId = section ?? `${viewId}-controls`\n const label = sectionLabel ?? view.label\n registerSectionOptions(sections, sectionId, {\n id: sectionId,\n label,\n title: label,\n description: sectionDescription,\n columns: model.columns,\n })\n appendModelControls(controls, viewControls, viewId, sectionId)\n }\n\n for (const [sectionKey, sectionConfig] of Object.entries(viewSections ?? {})) {\n const sectionId = sectionConfig.id ?? `${viewId}-${sectionKey}`\n registerSectionOptions(sections, sectionId, controlModelSectionOptions(sectionConfig))\n appendModelControls(controls, sectionConfig.controls, viewId, sectionId, sectionConfig.sidebar)\n }\n }\n\n const controlOptions: ControlWorkspaceOptions = {\n ...baseOptions,\n }\n\n if (Object.keys(views).length > 0) {\n controlOptions.views = views\n }\n\n if (Object.keys(sections).length > 0) {\n controlOptions.sections = sections\n }\n\n return {\n controls,\n controlOptions,\n ...(resolvedComponentBindings === undefined ? {} : { componentBindings: resolvedComponentBindings }),\n ...(componentProps === undefined ? {} : { componentProps }),\n ...(componentPropsById === undefined ? {} : { componentPropsById }),\n }\n}\n\nfunction appendModelControls(\n target: ControlSchema,\n source: ControlSchema,\n viewId: string,\n sectionId: string,\n sidebar?: boolean | ControlSidebarConfig,\n): void {\n for (const [name, input] of Object.entries(source)) {\n if (Object.prototype.hasOwnProperty.call(target, name)) {\n throw new Error(\n `Duplicate control \"${name}\" in defineControlModel(). Control names must be unique across views and sections.`,\n )\n }\n\n const definition = normalizeControlDefinition(input)\n target[name] = omitUndefined({\n ...definition,\n view: definition.view ?? viewId,\n section: definition.section ?? sectionId,\n sidebar: definition.sidebar ?? sidebar,\n })\n }\n}\n\nfunction controlModelSectionOptions(section: ControlModelSectionConfig): ControlSectionConfig {\n const { controls: _controls, sidebar: _sidebar, ...options } = section\n return omitUndefined(options)\n}\n\nfunction registerSectionOptions(\n target: Record<string, ControlSectionConfig>,\n sectionId: string,\n options: ControlSectionConfig,\n): void {\n target[sectionId] = omitUndefined({\n ...(target[sectionId] ?? {}),\n ...options,\n id: sectionId,\n })\n}\n","import {\n computed,\n reactive,\n ref,\n watch,\n} from 'vue'\nimport type {\n PillNavItem,\n TopBarSettingsConfig,\n} from '../types'\nimport {\n replaceRecord,\n} from './controlSchemaUtils'\nimport {\n mergeControlWorkspaceOptions,\n} from './controlWorkspaceOptions'\nimport {\n controlValuesToComponentBindings,\n controlValuesToComponentBindingsById,\n controlValuesToComponentProps,\n} from './controlComponentBindings'\nimport {\n isControlModelBinding,\n} from './controlSchemaModel'\nimport {\n useControlSchema,\n} from './useControlSchema'\nimport type {\n ControlComponentBinding,\n ControlComponentBindingsById,\n ControlComponentBindingsConfig,\n ControlComponentPropsByIdMap,\n ControlComponentPropsMap,\n ControlModelBinding,\n ControlSchema,\n ControlValues,\n ControlWorkspaceComponentBindings,\n ControlWorkspaceFormBinding,\n ControlWorkspaceOptions,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlWorkspaceReturn,\n} from './controlSchemaTypes'\n\n/**\n * Prepare shared reactive values plus AppTopBar/AppSidebar/FormBuilder bindings from one simple controls data model.\n *\n * @example Recommended\n * ```ts\n * const workspace = useControlWorkspace(workspaceModel)\n * const { form, sidebar, topBar } = workspace.bindings\n * ```\n */\nexport function useControlWorkspace<TControls extends ControlSchema>(\n controlsOrModel: TControls | (ControlModelBinding & { controls: TControls }),\n options: ControlWorkspaceOptions = {},\n): UseControlWorkspaceReturn<TControls> {\n const model = isControlModelBinding<ControlModelBinding & { controls: TControls }>(controlsOrModel)\n ? controlsOrModel\n : undefined\n const controls: TControls = model ? model.controls : controlsOrModel as TControls\n const workspaceOptions = model\n ? mergeControlWorkspaceOptions(model.controlOptions, options)\n : options\n const { initialValues, topBarSettings, ...schemaOptions } = workspaceOptions\n const schema = useControlSchema(controls, schemaOptions)\n const activeView = ref(schema.defaultView)\n const values = reactive({\n ...schema.initialValues,\n ...(initialValues ?? {}),\n }) as ControlValues<TControls> & Record<string, unknown>\n\n function setActiveView(viewId: string) {\n syncActiveView(viewId)\n }\n\n function syncActiveView(viewId: string) {\n if (!schema.viewIds.includes(viewId)) return\n if (activeView.value !== viewId) activeView.value = viewId\n if (sidebar.activeView !== viewId) sidebar.activeView = viewId\n if (pillNav.currentItemId !== viewId) pillNav.currentItemId = viewId\n }\n\n function setValues(nextValues: Record<string, unknown>) {\n Object.assign(values, nextValues)\n }\n\n function resetValues(nextValues: Record<string, unknown> = {}) {\n replaceRecord(values, {\n ...schema.initialValues,\n ...nextValues,\n })\n }\n\n function getComponentProps(\n mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>,\n ): Record<string, unknown> {\n return controlValuesToComponentProps(values, mapping)\n }\n\n function getComponentPropsById(\n mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>,\n ): Record<string, Record<string, unknown>> {\n if (mappings === undefined) return {}\n\n return Object.fromEntries(\n Object.entries(mappings).map(([id, mapping]) => [\n id,\n controlValuesToComponentProps(values, mapping),\n ]),\n )\n }\n\n function getComponentBindings(\n bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,\n ): ControlComponentBinding[] {\n return controlValuesToComponentBindings(values, bindings)\n }\n\n function getComponentBindingsById(\n bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,\n ): ControlComponentBindingsById {\n return controlValuesToComponentBindingsById(values, bindings)\n }\n\n const componentProps = computed(() => (\n model?.componentProps === undefined ? {} : getComponentProps(model.componentProps)\n ))\n const componentPropsById = computed(() => getComponentPropsById(model?.componentPropsById))\n const componentBindings = computed(() => getComponentBindings(model?.componentBindings))\n const componentBindingsById = computed(() => getComponentBindingsById(model?.componentBindings))\n const form = {\n ...schema.form,\n modelValue: values,\n 'onUpdate:modelValue': setValues,\n } as ControlWorkspaceFormBinding\n\n const topBarSettingsConfig: TopBarSettingsConfig = {\n ...schema.topBarSettingsConfig,\n ...(topBarSettings ?? {}),\n values,\n }\n const sidebar = reactive({\n ...schema.sidebar,\n activeView: activeView.value,\n modelValue: values,\n 'onUpdate:modelValue': setValues,\n values,\n 'onUpdate:values': setValues,\n }) as ControlWorkspaceSidebarBinding\n const pillNav = reactive({\n items: schema.viewItems,\n currentItemId: activeView.value,\n onSelect: (item: PillNavItem) => setActiveView(item.id),\n }) as ControlWorkspacePillNavBinding\n const topBarSettingsBinding = {\n showSettings: true,\n settingsConfig: topBarSettingsConfig,\n onSettingsValuesChange: setValues,\n } as ControlWorkspaceTopBarSettingsBinding\n const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({\n pillNav: pillNav.items,\n currentPillId: pillNav.currentItemId,\n onPillSelect: pillNav.onSelect,\n ...topBarSettingsBinding,\n }))\n const bindings: ControlWorkspaceComponentBindings = {\n form,\n sidebar,\n topBar: topBarProps,\n topBarSettings: topBarSettingsBinding,\n pillNav,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n }\n\n watch(activeView, syncActiveView, { flush: 'sync' })\n watch(() => sidebar.activeView, syncActiveView, { flush: 'sync' })\n watch(() => pillNav.currentItemId, syncActiveView, { flush: 'sync' })\n\n return {\n ...schema,\n schema,\n values,\n activeView,\n topBarSettingsConfig,\n form,\n sidebar,\n topBar: topBarProps,\n pillNav,\n topBarSettings: topBarSettingsBinding,\n bindings,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n setActiveView,\n setValues,\n resetValues,\n getComponentProps,\n getComponentPropsById,\n getComponentBindings,\n getComponentBindingsById,\n }\n}\n","import type {\n ControlComponentBindingsConfig,\n ControlComponentPropSource,\n ControlComponentPropsByIdMap,\n ControlComponentPropsMap,\n ControlModelBinding,\n ControlSchema,\n DoseCalculatorControlPropsOptions,\n DoseDesignControlModelOptions,\n WellPlateControlPropsOptions,\n WellPlateDoseControlPropsOptions,\n} from './controlSchemaTypes'\nimport type { WellConcentration } from './useDoseCalculator'\nimport {\n defineControlModel,\n} from './controlSchemaModel'\nimport {\n recordValue,\n} from './controlSchemaUtils'\n\n/** Return a default WellPlate prop mapping for generated control workspaces. */\nexport function defineWellPlateControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(\n options: WellPlateControlPropsOptions<TValues> = {},\n): ControlComponentPropsMap<TValues> {\n const selectedWells = options.selectedWells ?? sourceKey<TValues>('selectedWells')\n const onUpdateModelValue = options.onUpdateModelValue === false\n ? undefined\n : options.onUpdateModelValue ?? updateControlValueSource(selectedWells)\n\n return compactComponentPropsMap<TValues>({\n modelValue: selectedWells,\n 'onUpdate:modelValue': onUpdateModelValue,\n format: options.format ?? sourceKey<TValues>('plateFormat'),\n wells: options.wells ?? sourceKey<TValues>('wells'),\n disabled: options.disabled ?? sourceKey<TValues>('disabled'),\n readonly: options.readonly ?? sourceKey<TValues>('readonly'),\n showLegend: options.showLegend,\n showSampleTypeIndicator: options.showSampleTypeIndicator,\n })\n}\n\n/** Return a default DoseCalculator prop mapping for generated control workspaces. */\nexport function defineDoseCalculatorControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(\n options: DoseCalculatorControlPropsOptions<TValues> = {},\n): ControlComponentPropsMap<TValues> {\n const targetWells = options.targetWells ?? sourceKey<TValues>('selectedWells')\n const wells = options.wells ?? sourceKey<TValues>('wells')\n const onApplyToWells = options.onApplyToWells === false\n ? undefined\n : options.onApplyToWells ?? defaultDoseApplyHandler(wells, targetWells)\n\n return compactComponentPropsMap<TValues>({\n mode: options.mode ?? sourceKey<TValues>('doseMode'),\n targetWells,\n disabled: options.disabled ?? sourceKey<TValues>('disabled'),\n molecularWeight: options.molecularWeight,\n onApplyToWells,\n })\n}\n\n/** Return named WellPlate + DoseCalculator prop mappings for one dose-design control model. */\nexport function defineWellPlateDoseControlProps<TValues extends Record<string, unknown> = Record<string, unknown>>(\n options: WellPlateDoseControlPropsOptions<TValues> = {},\n): ControlComponentPropsByIdMap<TValues> {\n return {\n [options.plateId ?? 'plate']: defineWellPlateControlProps(options.plate),\n [options.doseId ?? 'dose']: defineDoseCalculatorControlProps(options.dose),\n }\n}\n\n/** Return named WellPlate + DoseCalculator component bindings for one dose-design control model. */\nexport function defineWellPlateDoseComponentBindings<TValues extends Record<string, unknown> = Record<string, unknown>>(\n options: WellPlateDoseControlPropsOptions<TValues> = {},\n): ControlComponentBindingsConfig<TValues> {\n return [\n {\n id: options.plateId ?? 'plate',\n component: 'WellPlate',\n props: defineWellPlateControlProps(options.plate),\n },\n {\n id: options.doseId ?? 'dose',\n component: 'DoseCalculator',\n props: defineDoseCalculatorControlProps(options.dose),\n },\n ]\n}\n\n/**\n * Return a complete ControlWorkspaceView model for WellPlate + DoseCalculator dose design.\n *\n * @example Recommended\n * ```ts\n * const workspaceModel = defineDoseDesignControlModel({ selectedWells: ['A1', 'A2'] })\n * ```\n */\nexport function defineDoseDesignControlModel(\n options: DoseDesignControlModelOptions = {},\n): ControlModelBinding {\n const viewId = options.viewId ?? 'design'\n const sectionId = options.sectionId ?? 'dose'\n const doseControls: ControlSchema = {\n selectedWells: {\n type: 'tags',\n label: 'Selected wells',\n default: [...(options.selectedWells ?? ['A1', 'A2'])],\n },\n plateFormat: {\n label: 'Plate format',\n default: options.plateFormat ?? 96,\n options: options.plateFormats ?? [96, 384],\n },\n doseMode: {\n label: 'Dose mode',\n default: options.doseMode ?? 'serial',\n options: options.doseModes ?? ['serial', 'dilution', 'conversion'],\n },\n disabled: {\n label: 'Disable tools',\n default: options.disabled ?? false,\n },\n }\n\n if (options.includeMolecularWeight) {\n doseControls.molecularWeight = {\n type: 'number',\n label: 'Molecular weight',\n default: options.molecularWeight ?? 300,\n min: 0,\n }\n }\n\n const componentProps: WellPlateDoseControlPropsOptions = {\n ...options.componentProps,\n dose: {\n ...(options.componentProps?.dose ?? {}),\n ...(options.includeMolecularWeight && options.componentProps?.dose?.molecularWeight === undefined\n ? { molecularWeight: 'molecularWeight' }\n : {}),\n },\n }\n\n return defineControlModel({\n componentBindings: defineWellPlateDoseComponentBindings(componentProps),\n componentPropsById: defineWellPlateDoseControlProps(componentProps),\n views: {\n [viewId]: {\n label: options.viewLabel ?? 'Design',\n sections: {\n [sectionId]: {\n label: options.sectionLabel ?? 'Dose design',\n description: options.sectionDescription ?? 'Well selection and dose calculator controls',\n controls: doseControls,\n },\n },\n },\n },\n })\n}\n\nfunction compactComponentPropsMap<TValues extends Record<string, unknown>>(\n mapping: Record<string, ControlComponentPropSource<TValues> | undefined>,\n): ControlComponentPropsMap<TValues> {\n return Object.fromEntries(\n Object.entries(mapping).filter((entry): entry is [string, ControlComponentPropSource<TValues>] =>\n entry[1] !== undefined\n ),\n )\n}\n\nfunction sourceKey<TValues extends Record<string, unknown>>(key: string): keyof TValues & string {\n return key as keyof TValues & string\n}\n\nfunction updateControlValueSource<TValues extends Record<string, unknown>>(\n source: ControlComponentPropSource<TValues>,\n): ((values: TValues) => (value: string[]) => void) | undefined {\n if (typeof source !== 'string') return undefined\n return values => (value: string[]) => {\n const writableValues = values as Record<string, unknown>\n writableValues[source] = value\n }\n}\n\nfunction defaultDoseApplyHandler<TValues extends Record<string, unknown>>(\n wells: ControlComponentPropSource<TValues>,\n targetWells: ControlComponentPropSource<TValues>,\n): ((values: TValues) => (results: WellConcentration[]) => void) | undefined {\n if (wells === targetWells) return undefined\n return updateWellsFromDoseResults(wells)\n}\n\nfunction updateWellsFromDoseResults<TValues extends Record<string, unknown>>(\n source: ControlComponentPropSource<TValues>,\n): ((values: TValues) => (results: WellConcentration[]) => void) | undefined {\n if (typeof source !== 'string') return undefined\n return values => (results: WellConcentration[]) => {\n const writableValues = values as Record<string, unknown>\n const currentWells = recordValue(writableValues[source])\n const nextWells: Record<string, Record<string, unknown>> = {}\n for (const [wellId, well] of Object.entries(currentWells)) {\n nextWells[wellId] = recordValue(well)\n }\n\n for (const result of results) {\n const existing = recordValue(nextWells[result.wellId])\n const metadata = recordValue(existing.metadata)\n nextWells[result.wellId] = {\n ...existing,\n state: 'filled',\n value: result.concentration.value,\n metadata: {\n ...metadata,\n concentration: result.concentration,\n ...(result.volume === undefined ? {} : { volume: result.volume }),\n },\n }\n }\n\n writableValues[source] = nextWells\n }\n}\n","/**\n * Validation rule function type.\n * Returns error message string if invalid, undefined/null if valid.\n */\nexport type ValidationRule<T = unknown> = (value: T, formData: Record<string, unknown>) => string | undefined | null\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldRules<T = unknown> {\n required?: boolean | string\n minLength?: number | { value: number; message: string }\n maxLength?: number | { value: number; message: string }\n min?: number | { value: number; message: string }\n max?: number | { value: number; message: string }\n pattern?: RegExp | { value: RegExp; message: string }\n email?: boolean | string\n custom?: ValidationRule<T> | ValidationRule<T>[]\n}\n\nconst validators = {\n required: (value: unknown, message = 'This field is required'): string | null => {\n if (value === null || value === undefined || value === '') {\n return message\n }\n if (Array.isArray(value) && value.length === 0) {\n return message\n }\n return null\n },\n\n minLength: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length < min) {\n return message || `Must be at least ${min} characters`\n }\n return null\n },\n\n maxLength: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (value.length > max) {\n return message || `Must be at most ${max} characters`\n }\n return null\n },\n\n min: (value: unknown, min: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value < min) {\n return message || `Must be at least ${min}`\n }\n return null\n },\n\n max: (value: unknown, max: number, message?: string): string | null => {\n if (typeof value !== 'number') return null\n if (value > max) {\n return message || `Must be at most ${max}`\n }\n return null\n },\n\n pattern: (value: unknown, pattern: RegExp, message?: string): string | null => {\n if (typeof value !== 'string') return null\n if (!pattern.test(value)) {\n return message || 'Invalid format'\n }\n return null\n },\n\n email: (value: unknown, message = 'Invalid email address'): string | null => {\n if (typeof value !== 'string' || !value) return null\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(value)) {\n return message\n }\n return null\n },\n}\n\nexport function validateFieldValue(\n value: unknown,\n fieldRules: FieldRules | undefined,\n formData: Record<string, unknown>,\n): string | null {\n if (!fieldRules) return null\n\n if (fieldRules.required) {\n const message = typeof fieldRules.required === 'string' ? fieldRules.required : undefined\n const error = validators.required(value, message)\n if (error) return error\n }\n\n if (value === null || value === undefined || value === '') {\n return null\n }\n\n if (fieldRules.minLength !== undefined) {\n const config = typeof fieldRules.minLength === 'number'\n ? { value: fieldRules.minLength, message: undefined }\n : fieldRules.minLength\n const error = validators.minLength(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.maxLength !== undefined) {\n const config = typeof fieldRules.maxLength === 'number'\n ? { value: fieldRules.maxLength, message: undefined }\n : fieldRules.maxLength\n const error = validators.maxLength(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.min !== undefined) {\n const config = typeof fieldRules.min === 'number'\n ? { value: fieldRules.min, message: undefined }\n : fieldRules.min\n const error = validators.min(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.max !== undefined) {\n const config = typeof fieldRules.max === 'number'\n ? { value: fieldRules.max, message: undefined }\n : fieldRules.max\n const error = validators.max(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.pattern !== undefined) {\n const config = fieldRules.pattern instanceof RegExp\n ? { value: fieldRules.pattern, message: undefined }\n : fieldRules.pattern\n const error = validators.pattern(value, config.value, config.message)\n if (error) return error\n }\n\n if (fieldRules.email) {\n const message = typeof fieldRules.email === 'string' ? fieldRules.email : undefined\n const error = validators.email(value, message)\n if (error) return error\n }\n\n if (fieldRules.custom) {\n const customRules = Array.isArray(fieldRules.custom) ? fieldRules.custom : [fieldRules.custom]\n for (const rule of customRules) {\n const error = rule(value, formData)\n if (error) return error\n }\n }\n\n return null\n}\n","import { ref, reactive, computed, toRaw, watch, type Ref } from 'vue'\nimport { validateFieldValue, type FieldRules } from './useFormValidation'\n\nexport type { FieldRules, ValidationRule } from './useFormValidation'\n\n/**\n * Field validation rules configuration.\n */\nexport interface FieldState {\n value: unknown\n error: string | null\n touched: boolean\n dirty: boolean\n}\n\n/**\n * Form state and methods.\n */\nexport interface UseFormReturn<T extends Record<string, unknown>> {\n // Form data (reactive)\n data: T\n\n // Field errors\n errors: Record<string, string | null>\n\n // Field touched state\n touched: Record<string, boolean>\n\n // Field dirty state (value changed from initial)\n dirty: Record<string, boolean>\n\n // Overall form state\n isValid: Ref<boolean>\n isDirty: Ref<boolean>\n isSubmitting: Ref<boolean>\n\n // Methods\n setFieldValue: <K extends keyof T>(field: K, value: T[K]) => void\n setFieldError: (field: string, error: string | null) => void\n setFieldTouched: (field: string, touched?: boolean) => void\n validateField: (field: string) => boolean\n validate: () => boolean\n reset: (values?: Partial<T>) => void\n /** Replace the full form state and treat the provided values as the new clean baseline. */\n replaceState: (values: T) => void\n handleSubmit: (onSubmit: (data: T) => Promise<void> | void) => (e?: Event) => Promise<void>\n getFieldProps: <K extends keyof T>(field: K) => {\n modelValue: T[K]\n 'onUpdate:modelValue': (value: T[K]) => void\n onBlur: () => void\n error: string | null\n }\n}\n\n/**\n * Form state management composable with validation.\n *\n * @param initialValues - Initial form values\n * @param rules - Validation rules for each field\n *\n * @example\n * ```typescript\n * const { data, errors, isValid, handleSubmit, getFieldProps } = useForm(\n * { email: '', password: '' },\n * {\n * email: { required: true, email: true },\n * password: { required: true, minLength: 8 },\n * }\n * )\n *\n * // In template\n * <BaseInput v-bind=\"getFieldProps('email')\" label=\"Email\" />\n * <BaseInput v-bind=\"getFieldProps('password')\" type=\"password\" label=\"Password\" />\n * <BaseButton @click=\"handleSubmit(onSubmit)\" :disabled=\"!isValid\">Submit</BaseButton>\n * ```\n */\n/** Reactive form state with field-level validation, dirty tracking, and submit handling. */\nexport function useForm<T extends Record<string, unknown>>(\n initialValues: T,\n rules: Partial<Record<keyof T, FieldRules>> = {}\n): UseFormReturn<T> {\n const cloneableInitialValues = deepToRaw(initialValues) as T\n\n // Deep copy initial values so nested objects are not shared\n let _initialValues = structuredClone(cloneableInitialValues)\n\n // Reactive form data\n const data = reactive(structuredClone(cloneableInitialValues)) as T\n\n // Field state - use simple Record types for better TS compatibility\n const errors = reactive<Record<string, string | null>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = null\n return acc\n }, {} as Record<string, string | null>)\n )\n\n const touched = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const dirty = reactive<Record<string, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => {\n acc[key] = false\n return acc\n }, {} as Record<string, boolean>)\n )\n\n const isSubmitting = ref(false)\n\n // Watch data changes to track dirty state\n watch(\n () => ({ ...data }),\n (newData) => {\n for (const key of Object.keys(newData)) {\n dirty[key] = newData[key as keyof T] !== _initialValues[key as keyof T]\n }\n },\n { deep: true }\n )\n\n // Validate a single field\n function validateField(field: string): boolean {\n const value = data[field as keyof T]\n const fieldRules = rules[field as keyof T]\n const error = validateFieldValue(value, fieldRules, data as Record<string, unknown>)\n errors[field] = error\n return error === null\n }\n\n // Validate all fields\n function validate(): boolean {\n let isAllValid = true\n for (const field of Object.keys(data)) {\n if (!validateField(field)) {\n isAllValid = false\n }\n }\n return isAllValid\n }\n\n // Computed overall validity\n const isValid = computed(() => {\n return Object.values(errors).every(error => error === null)\n })\n\n // Computed overall dirty state\n const isDirty = computed(() => {\n return Object.values(dirty).some(d => d)\n })\n\n // Set field value\n function setFieldValue<K extends keyof T>(field: K, value: T[K]): void {\n ;(data as Record<string, unknown>)[field as string] = value\n if (touched[field as string]) {\n validateField(field as string)\n }\n }\n\n // Set field error\n function setFieldError(field: string, error: string | null): void {\n errors[field] = error\n }\n\n // Set field touched\n function setFieldTouched(field: string, isTouched = true): void {\n touched[field] = isTouched\n if (isTouched) {\n validateField(field)\n }\n }\n\n // Reset form\n function reset(values?: Partial<T>): void {\n const resetValues = values ? { ..._initialValues, ...values } : _initialValues\n for (const key of Object.keys(data)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(resetValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n function replaceState(values: T): void {\n const nextValues = structuredClone(deepToRaw(values)) as T\n _initialValues = structuredClone(nextValues)\n\n for (const key of Object.keys(data)) {\n if (key in nextValues) continue\n delete (data as Record<string, unknown>)[key]\n delete errors[key]\n delete touched[key]\n delete dirty[key]\n }\n\n for (const key of Object.keys(nextValues)) {\n ;(data as Record<string, unknown>)[key] = structuredClone(deepToRaw(nextValues[key as keyof T]))\n errors[key] = null\n touched[key] = false\n dirty[key] = false\n }\n }\n\n // Handle submit\n function handleSubmit(onSubmit: (data: T) => Promise<void> | void) {\n return async (e?: Event): Promise<void> => {\n e?.preventDefault()\n\n // Mark all fields as touched\n for (const field of Object.keys(data)) {\n touched[field] = true\n }\n\n if (!validate()) {\n return\n }\n\n isSubmitting.value = true\n try {\n await onSubmit(data)\n } finally {\n isSubmitting.value = false\n }\n }\n }\n\n // Get props for a field (for v-bind)\n function getFieldProps<K extends keyof T>(field: K) {\n const fieldStr = field as string\n return {\n modelValue: data[field],\n 'onUpdate:modelValue': (value: T[K]) => setFieldValue(field, value),\n onBlur: () => setFieldTouched(fieldStr),\n error: touched[fieldStr] ? errors[fieldStr] : null,\n }\n }\n\n return {\n data,\n errors,\n touched,\n dirty,\n isValid,\n isDirty,\n isSubmitting,\n setFieldValue,\n setFieldError,\n setFieldTouched,\n validateField,\n validate,\n reset,\n replaceState,\n handleSubmit,\n getFieldProps,\n }\n}\n\nfunction deepToRaw(value: unknown): unknown {\n const raw = toRaw(value)\n\n if (Array.isArray(raw)) {\n return raw.map(item => deepToRaw(item))\n }\n\n if (isPlainRecord(raw)) {\n return Object.fromEntries(\n Object.entries(raw).map(([key, item]) => [key, deepToRaw(item)])\n )\n }\n\n return raw\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return Object.prototype.toString.call(value) === '[object Object]'\n}\n","import { getTypeDefault } from './formBuilderRegistry'\nimport type { FieldRules } from './useForm'\nimport type {\n FieldCondition,\n FieldValidation,\n FormEnhancements,\n FormFieldSchema,\n FormSchema,\n FormSectionSchema,\n} from '../types/form-builder'\n\n/**\n * Evaluate a JSON-serializable field condition against the current form data.\n *\n * Supports logical operators (`and`, `or`, `not`) and comparison operators\n * (`eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `in`, `notIn`, `truthy`, `falsy`,\n * `contains`). Returns `true` if the condition passes.\n */\nexport function evaluateCondition(\n condition: FieldCondition,\n data: Record<string, unknown>,\n): boolean {\n if ('and' in condition) {\n return condition.and.every((c) => evaluateCondition(c, data))\n }\n if ('or' in condition) {\n return condition.or.some((c) => evaluateCondition(c, data))\n }\n if ('not' in condition) {\n return !evaluateCondition(condition.not, data)\n }\n\n const value = data[condition.field]\n\n if ('eq' in condition) return value === condition.eq\n if ('neq' in condition) return value !== condition.neq\n if ('gt' in condition) return typeof value === 'number' && value > condition.gt\n if ('lt' in condition) return typeof value === 'number' && value < condition.lt\n if ('gte' in condition) return typeof value === 'number' && value >= condition.gte\n if ('lte' in condition) return typeof value === 'number' && value <= condition.lte\n if ('in' in condition) return condition.in.includes(value)\n if ('notIn' in condition) return !condition.notIn.includes(value)\n if ('truthy' in condition) return !!value\n if ('falsy' in condition) return !value\n if ('contains' in condition) {\n if (typeof value === 'string') return value.includes(condition.contains)\n if (Array.isArray(value)) return value.includes(condition.contains)\n return false\n }\n\n return true\n}\n\n/** Return all sections across steps (wizard) or directly from a flat schema. */\nexport function collectSections(schema: FormSchema): FormSectionSchema[] {\n return schema.steps ? schema.steps.flatMap((step) => step.sections) : schema.sections\n}\n\n/** Return all field schemas in schema order, flattening sections and steps. */\nexport function flattenFields(schema: FormSchema): FormFieldSchema[] {\n return collectSections(schema).flatMap((section) => section.fields)\n}\n\n/** Convert a JSON-safe `FieldValidation` descriptor to a runtime `FieldRules` object. */\nfunction convertValidation(v: FieldValidation): FieldRules {\n const rules: FieldRules = {}\n\n if (v.required !== undefined) rules.required = v.required\n if (v.minLength !== undefined) rules.minLength = v.minLength\n if (v.maxLength !== undefined) rules.maxLength = v.maxLength\n if (v.min !== undefined) rules.min = v.min\n if (v.max !== undefined) rules.max = v.max\n if (v.email !== undefined) rules.email = v.email\n\n if (v.pattern !== undefined) {\n rules.pattern =\n typeof v.pattern === 'string'\n ? new RegExp(v.pattern)\n : { value: new RegExp(v.pattern.value), message: v.pattern.message }\n }\n\n return rules\n}\n\nexport function buildInitialValues<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n initialData?: Partial<T>,\n): Record<string, unknown> {\n const initialValues = {} as Record<string, unknown>\n\n for (const field of fields) {\n const key = field.name\n if (initialData && hasOwnKey(initialData, key)) {\n initialValues[key] = (initialData as Record<string, unknown>)[key]\n } else if (field.defaultValue !== undefined) {\n initialValues[key] = field.defaultValue\n } else {\n initialValues[key] = getTypeDefault(field.type)\n }\n }\n\n return initialValues\n}\n\nexport function buildRules<T extends Record<string, unknown>>(\n fields: readonly FormFieldSchema[],\n enhancements?: FormEnhancements<T>,\n): Partial<Record<string, FieldRules>> {\n const rules: Partial<Record<string, FieldRules>> = {}\n\n for (const field of fields) {\n const base: FieldRules = field.validation ? convertValidation(field.validation) : {}\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n\n const customValidators: Array<(\n value: unknown,\n formData: Record<string, unknown>,\n ) => string | undefined | null> = []\n\n if (enhancement?.validate) {\n const fn = enhancement.validate\n customValidators.push((value, formData) => fn(value, formData as T))\n }\n\n if (customValidators.length > 0) {\n base.custom = customValidators\n }\n\n if (Object.keys(base).length > 0) {\n rules[field.name] = base\n }\n }\n\n return rules\n}\n\nexport function replaceArray<T>(target: T[], values: readonly T[]): void {\n target.splice(0, target.length, ...values)\n}\n\nexport function replaceRecord<TValue>(\n target: Partial<Record<string, TValue>>,\n source: Partial<Record<string, TValue>>,\n): void {\n for (const key of Object.keys(target)) {\n delete target[key]\n }\n Object.assign(target, source)\n}\n\nfunction hasOwnKey(source: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(source, key)\n}\n","import { reactive, ref, computed, shallowRef, watch } from 'vue'\nimport { useForm, type FieldRules, type UseFormReturn } from './useForm'\nimport { getFieldRegistryEntry } from './formBuilderRegistry'\nimport {\n buildInitialValues,\n buildRules,\n collectSections,\n evaluateCondition,\n flattenFields,\n replaceArray,\n replaceRecord,\n} from './formBuilderSchema'\nimport type {\n FormSchema,\n FormFieldSchema,\n FormSectionSchema,\n FormOptionInput,\n FormEnhancements,\n UseFormBuilderReturn,\n} from '../types/form-builder'\n\nexport { evaluateCondition } from './formBuilderSchema'\n\n// ---------------------------------------------------------------------------\n// useFormBuilder\n// ---------------------------------------------------------------------------\n\n/**\n * Drive a `FormSchema` as reactive form state.\n *\n * Builds initial values from schema defaults and `initialData`, derives\n * validation rules from `FieldValidation` descriptors and enhancement\n * validators, evaluates `FieldCondition` expressions for field/section\n * visibility, and wires wizard step navigation when `schema.steps` is set.\n *\n * @param schema - Declarative form or wizard schema.\n * @param initialData - Values that override schema defaults.\n * @param enhancements - TypeScript-only callbacks (dynamic options, validators,\n * submit handler, transform, field-change watcher).\n */\n/** Drives a declarative FormSchema as reactive state with conditional fields, wizard steps, and validation. */\nexport function useFormBuilder<T extends Record<string, unknown> = Record<string, unknown>>(\n schema: FormSchema,\n initialData?: Partial<T>,\n enhancements?: FormEnhancements<T>,\n): UseFormBuilderReturn<T> {\n const currentSchema = shallowRef(schema)\n const fields = reactive<FormFieldSchema[]>(flattenFields(schema))\n const sections = reactive<FormSectionSchema[]>(collectSections(schema))\n const rules = reactive<Partial<Record<string, FieldRules>>>(buildRules(fields, enhancements))\n\n // -- Create form -----------------------------------------------------------\n const form = useForm(\n buildInitialValues<T>(fields, initialData) as T,\n rules as Partial<Record<keyof T, FieldRules>>,\n )\n\n // -- Visibility ------------------------------------------------------------\n function isFieldVisible(name: string): boolean {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.visible) {\n return enhancement.visible(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.condition) {\n return evaluateCondition(field.condition, form.data as Record<string, unknown>)\n }\n\n return true\n }\n\n function isSectionVisible(id: string): boolean {\n const section = sections.find((s) => s.id === id)\n if (section?.condition) {\n return evaluateCondition(section.condition, form.data as Record<string, unknown>)\n }\n return true\n }\n\n // -- Resolved field props --------------------------------------------------\n function getResolvedFieldProps(field: FormFieldSchema): Record<string, unknown> {\n const entry = getFieldRegistryEntry(field.type)\n const formProps = form.getFieldProps(field.name as keyof T)\n\n const merged: Record<string, unknown> = {\n ...entry.defaults,\n ...(field.props ?? {}),\n }\n\n // Dynamic enhancement props\n const enhancement = enhancements?.fields?.[field.name as keyof T]\n if (enhancement?.props) {\n Object.assign(merged, enhancement.props(form.data as T))\n }\n\n // Dynamic options\n const options = getFieldOptions(field.name)\n if (options) {\n merged.options = options\n }\n\n // Form field bindings\n if (entry.vModel) {\n merged.modelValue = formProps.modelValue\n merged['onUpdate:modelValue'] = formProps['onUpdate:modelValue']\n }\n merged.onBlur = formProps.onBlur\n\n // Error as boolean for components that use boolean error prop\n const errorMsg = formProps.error\n if (errorMsg) {\n merged.error = true\n }\n\n // Schema-level props\n if (field.placeholder) merged.placeholder = field.placeholder\n if (field.size) merged.size = field.size\n if (field.disabled) merged.disabled = true\n if (field.readonly) merged.readonly = true\n\n // Radio group needs a name prop\n if (field.type === 'radio' && !merged.name) {\n merged.name = field.name\n }\n\n return merged\n }\n\n function getFieldOptions(name: string): FormOptionInput[] | undefined {\n const enhancement = enhancements?.fields?.[name as keyof T]\n if (enhancement?.options) {\n return enhancement.options(form.data as T)\n }\n\n const field = fields.find((f) => f.name === name)\n if (field?.props?.options) {\n return field.props.options as FormOptionInput[]\n }\n\n return undefined\n }\n\n // -- Wizard state ----------------------------------------------------------\n const currentStep = ref(0)\n\n const isCurrentStepValid = computed(() => {\n if (!currentSchema.value.steps) return form.isValid.value\n\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return true\n\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n if (!form.validateField(field.name)) return false\n }\n }\n return true\n })\n\n function goNext(): boolean {\n if (!currentSchema.value.steps) return false\n\n // Touch and validate all visible fields in current step\n const step = currentSchema.value.steps[currentStep.value]\n if (!step) return false\n\n let valid = true\n for (const section of step.sections) {\n if (!isSectionVisible(section.id)) continue\n for (const field of section.fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) valid = false\n }\n }\n\n if (!valid) return false\n\n if (currentStep.value < currentSchema.value.steps.length - 1) {\n currentStep.value++\n }\n return true\n }\n\n function goBack(): void {\n if (currentStep.value > 0) {\n currentStep.value--\n }\n }\n\n function goToStep(index: number): void {\n if (!currentSchema.value.steps) return\n if (index >= 0 && index < currentSchema.value.steps.length) {\n currentStep.value = index\n }\n }\n\n // -- Validate (skip hidden fields) -----------------------------------------\n function validate(): boolean {\n let allValid = true\n for (const field of fields) {\n if (!isFieldVisible(field.name)) continue\n form.setFieldTouched(field.name, true)\n if (!form.validateField(field.name)) {\n allValid = false\n }\n }\n return allValid\n }\n\n // -- Submit ----------------------------------------------------------------\n async function submit(): Promise<void> {\n if (!validate()) return\n\n // Build submission data excluding hidden fields\n let submitData = {} as Record<string, unknown>\n for (const field of fields) {\n if (isFieldVisible(field.name)) {\n submitData[field.name] = (form.data as Record<string, unknown>)[field.name]\n }\n }\n\n if (enhancements?.transform) {\n submitData = enhancements.transform(submitData as T) as Record<string, unknown>\n }\n\n if (enhancements?.onSubmit) {\n form.isSubmitting.value = true\n try {\n await enhancements.onSubmit(submitData as T)\n } finally {\n form.isSubmitting.value = false\n }\n }\n }\n\n // -- Reset -----------------------------------------------------------------\n function reset(values?: Partial<T>): void {\n form.reset(values)\n currentStep.value = 0\n }\n\n function updateSchema(nextSchema: FormSchema, nextData?: Partial<T>): void {\n currentSchema.value = nextSchema\n\n const nextFields = flattenFields(nextSchema)\n replaceArray(fields, nextFields)\n replaceArray(sections, collectSections(nextSchema))\n replaceRecord(rules, buildRules(nextFields, enhancements))\n form.replaceState(buildInitialValues<T>(nextFields, nextData) as T)\n currentStep.value = 0\n }\n\n // -- onFieldChange wiring --------------------------------------------------\n if (enhancements?.onFieldChange) {\n const callback = enhancements.onFieldChange\n watch(\n () => ({ ...(form.data as Record<string, unknown>) }),\n (newData, oldData) => {\n if (!oldData) return\n for (const key of Object.keys(newData)) {\n if (newData[key] !== oldData[key]) {\n callback(key as keyof T, newData[key], newData as T)\n }\n }\n },\n { deep: true },\n )\n }\n\n return {\n form: form as UseFormReturn<T>,\n rules: rules as Partial<Record<keyof T, FieldRules>>,\n isFieldVisible,\n isSectionVisible,\n fields,\n getResolvedFieldProps,\n getFieldOptions,\n currentStep,\n isCurrentStepValid,\n goNext,\n goBack,\n goToStep,\n validate,\n reset,\n submit,\n updateSchema,\n }\n}\n","import { computed, onMounted, onUnmounted, ref, unref, watch, type ComputedRef, type Ref } from 'vue'\n\nexport const DEFAULT_MOBILE_VIEWPORT_QUERY = '(max-width: 767px)'\n\nexport type MobileSupportSource = boolean | Ref<boolean> | ComputedRef<boolean>\nexport type MobileViewportQuerySource = string | Ref<string> | ComputedRef<string>\n\nexport interface UseMobileSupportGateOptions {\n supported?: MobileSupportSource\n mediaQuery?: MobileViewportQuerySource\n}\n\nexport interface UseMobileSupportGateReturn {\n isMobileViewport: Ref<boolean>\n isSupported: ComputedRef<boolean>\n shouldShowUnsupported: ComputedRef<boolean>\n}\n\nexport function useMobileSupportGate(options: UseMobileSupportGateOptions = {}): UseMobileSupportGateReturn {\n const isMobileViewport = ref(false)\n\n const mediaQuery = computed(() => {\n const value = unref(options.mediaQuery)\n return value?.trim() || DEFAULT_MOBILE_VIEWPORT_QUERY\n })\n\n const isSupported = computed(() => {\n if (options.supported === undefined) return true\n return Boolean(unref(options.supported))\n })\n\n const shouldShowUnsupported = computed(() => isMobileViewport.value && !isSupported.value)\n\n let mediaQueryList: MediaQueryList | null = null\n let removeMediaListener: (() => void) | undefined\n\n const syncMobileState = (event?: MediaQueryListEvent | MediaQueryList) => {\n isMobileViewport.value = Boolean(event?.matches ?? mediaQueryList?.matches)\n }\n\n const unbindMediaQuery = () => {\n removeMediaListener?.()\n removeMediaListener = undefined\n mediaQueryList = null\n }\n\n const bindMediaQuery = () => {\n unbindMediaQuery()\n\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n isMobileViewport.value = false\n return\n }\n\n const queryList = window.matchMedia(mediaQuery.value)\n mediaQueryList = queryList\n syncMobileState(queryList)\n\n const handleChange = (event: MediaQueryListEvent) => syncMobileState(event)\n\n if (typeof queryList.addEventListener === 'function') {\n queryList.addEventListener('change', handleChange)\n removeMediaListener = () => queryList.removeEventListener('change', handleChange)\n return\n }\n\n queryList.addListener(handleChange)\n removeMediaListener = () => queryList.removeListener(handleChange)\n }\n\n onMounted(bindMediaQuery)\n watch(mediaQuery, bindMediaQuery, { flush: 'post' })\n onUnmounted(unbindMediaQuery)\n\n return {\n isMobileViewport,\n isSupported,\n shouldShowUnsupported,\n }\n}\n","import { computed, reactive, watch } from 'vue'\nimport type { ComputedRef } from 'vue'\nimport type { PillNavItem } from '../types'\nimport type {\n ControlComponentBinding,\n ControlComponentBindingsById,\n ControlComponentBindingsConfig,\n ControlComponentPropsByIdMap,\n ControlComponentPropsMap,\n ControlModel,\n ControlModelBinding,\n ControlSchema,\n ControlWorkspaceOptions,\n} from '../composables/useControlSchema'\nimport {\n controlValuesToComponentBindings,\n controlValuesToComponentBindingsById,\n controlValuesToComponentProps,\n controlsToViewItems,\n getControlDefaults,\n getDefaultControlView,\n mergeControlWorkspaceOptions,\n resolveControlModel,\n} from '../composables/useControlSchema'\n\nexport interface PluginWorkspaceControlsOptions {\n model: () => ControlModel | ControlModelBinding | undefined\n controls: () => ControlSchema | undefined\n controlOptions: () => ControlWorkspaceOptions\n modelValue: () => Record<string, unknown> | undefined\n values: () => Record<string, unknown> | undefined\n componentBindings: () => ControlComponentBindingsConfig | undefined\n componentProps: () => ControlComponentPropsMap | undefined\n componentPropsById: () => ControlComponentPropsByIdMap | undefined\n emitValues: (values: Record<string, unknown>) => void\n}\n\nexport interface PluginWorkspaceControls {\n resolvedModel: ComputedRef<ControlModelBinding | undefined>\n resolvedControls: ComputedRef<ControlSchema | undefined>\n resolvedControlOptions: ComputedRef<ControlWorkspaceOptions>\n generatedPillNav: ComputedRef<PillNavItem[]>\n generatedDefaultView: ComputedRef<string>\n internalControlValues: Record<string, unknown>\n resolvedComponentBindings: ComputedRef<ControlComponentBinding[]>\n resolvedComponentBindingsById: ComputedRef<ControlComponentBindingsById>\n resolvedComponentProps: ComputedRef<Record<string, unknown>>\n resolvedComponentPropsById: ComputedRef<Record<string, Record<string, unknown>>>\n handleControlValuesUpdate: (values: Record<string, unknown>) => void\n}\n\nexport function usePluginWorkspaceControls(\n options: PluginWorkspaceControlsOptions,\n): PluginWorkspaceControls {\n const resolvedModel = computed<ControlModelBinding | undefined>(() =>\n resolveControlModel(options.model()),\n )\n\n const resolvedControls = computed<ControlSchema | undefined>(() =>\n options.controls() ?? resolvedModel.value?.controls,\n )\n\n const resolvedControlOptions = computed<ControlWorkspaceOptions>(() =>\n mergeControlWorkspaceOptions(resolvedModel.value?.controlOptions ?? {}, options.controlOptions()),\n )\n\n const externalControlValues = computed(() => options.modelValue() ?? options.values())\n const internalControlValues = reactive<Record<string, unknown>>({})\n let syncingControlValues = false\n\n const generatedControlDefaults = computed<Record<string, unknown>>(() => {\n if (!resolvedControls.value) return {}\n return {\n ...getControlDefaults(resolvedControls.value),\n ...(resolvedControlOptions.value.initialValues ?? {}),\n }\n })\n\n function replaceControlValues(values: Record<string, unknown>) {\n for (const key of Object.keys(internalControlValues)) {\n if (!(key in values)) {\n delete internalControlValues[key]\n }\n }\n Object.assign(internalControlValues, values)\n }\n\n function emitControlValues() {\n options.emitValues({ ...internalControlValues })\n }\n\n function syncResolvedControlValues() {\n syncingControlValues = true\n replaceControlValues({\n ...generatedControlDefaults.value,\n ...(externalControlValues.value === undefined ? internalControlValues : externalControlValues.value),\n })\n syncingControlValues = false\n }\n\n function handleControlValuesUpdate(values: Record<string, unknown>) {\n syncingControlValues = true\n replaceControlValues({\n ...generatedControlDefaults.value,\n ...values,\n })\n syncingControlValues = false\n emitControlValues()\n }\n\n const resolvedComponentBindings = computed(() =>\n controlValuesToComponentBindings(\n internalControlValues,\n options.componentBindings() ?? resolvedModel.value?.componentBindings,\n ),\n )\n\n const resolvedComponentBindingsById = computed(() =>\n controlValuesToComponentBindingsById(\n internalControlValues,\n options.componentBindings() ?? resolvedModel.value?.componentBindings,\n ),\n )\n\n const resolvedComponentProps = computed(() => {\n const mapping = options.componentProps() ?? resolvedModel.value?.componentProps\n return mapping === undefined ? {} : controlValuesToComponentProps(internalControlValues, mapping)\n })\n\n const resolvedComponentPropsById = computed(() => {\n const mappings = options.componentPropsById() ?? resolvedModel.value?.componentPropsById\n if (mappings === undefined) return {}\n\n return Object.fromEntries(\n Object.entries(mappings).map(([id, mapping]) => [\n id,\n controlValuesToComponentProps(internalControlValues, mapping),\n ]),\n )\n })\n\n const generatedPillNav = computed<PillNavItem[]>(() => {\n if (!resolvedControls.value) return []\n return controlsToViewItems(resolvedControls.value, resolvedControlOptions.value)\n })\n\n const generatedDefaultView = computed(() => {\n if (!resolvedControls.value) return ''\n return getDefaultControlView(resolvedControls.value, resolvedControlOptions.value)\n })\n\n syncResolvedControlValues()\n\n watch(\n [generatedControlDefaults, externalControlValues],\n syncResolvedControlValues,\n { deep: true },\n )\n\n watch(\n internalControlValues,\n () => {\n if (syncingControlValues) return\n emitControlValues()\n },\n { deep: true, flush: 'sync' },\n )\n\n return {\n resolvedModel,\n resolvedControls,\n resolvedControlOptions,\n generatedPillNav,\n generatedDefaultView,\n internalControlValues,\n resolvedComponentBindings,\n resolvedComponentBindingsById,\n resolvedComponentProps,\n resolvedComponentPropsById,\n handleControlValuesUpdate,\n }\n}\n","import { computed, ref, type ComputedRef, type Ref, type WritableComputedRef } from 'vue'\nimport type {\n PageSelectorItem,\n PageSelectorItemInput,\n PillNavItem,\n PillNavItemInput,\n} from '../types'\n\ntype ReadableRef<T> = Readonly<Ref<T>>\n\nexport interface PluginWorkspaceNavigationOptions {\n activeView: () => string | undefined\n defaultActiveView: () => string | undefined\n currentPillId: () => string | undefined\n currentPageSelectorId: () => string | undefined\n pillNav: () => PillNavItemInput[] | undefined\n pageSelector: () => PageSelectorItemInput[] | undefined\n panelIds: () => string[]\n generatedPillNav: ReadableRef<readonly PillNavItem[]>\n generatedDefaultView: ReadableRef<string>\n emitActiveView: (viewId: string) => void\n emitPageSelectorSelect: (page: PageSelectorItem) => void\n emitPillSelect: (item: PillNavItem) => void\n}\n\nexport interface PluginWorkspaceNavigation {\n resolvedPillNav: ComputedRef<PillNavItemInput[] | undefined>\n firstConfiguredViewId: ComputedRef<string>\n resolvedActiveView: WritableComputedRef<string>\n resolvedCurrentPillId: ComputedRef<string>\n resolvedCurrentPageSelectorId: ComputedRef<string>\n setActiveView: (viewId: string) => void\n handlePageSelectorSelect: (page: PageSelectorItem) => void\n handlePillSelect: (item: PillNavItem) => void\n}\n\nexport function usePluginWorkspaceNavigation(\n options: PluginWorkspaceNavigationOptions,\n): PluginWorkspaceNavigation {\n const internalActiveView = ref(options.defaultActiveView())\n\n const resolvedPillNav = computed<PillNavItemInput[] | undefined>(() => {\n if (options.pillNav() !== undefined) return options.pillNav()\n return options.generatedPillNav.value.length > 0\n ? [...options.generatedPillNav.value]\n : undefined\n })\n\n const firstConfiguredViewId = computed(() =>\n options.defaultActiveView()\n ?? firstItemId(options.pillNav())\n ?? options.generatedDefaultView.value\n ?? firstItemId(options.pageSelector())\n ?? options.panelIds()[0]\n ?? '',\n )\n\n const resolvedActiveView = computed({\n get: () =>\n options.activeView()\n ?? options.currentPillId()\n ?? options.currentPageSelectorId()\n ?? internalActiveView.value\n ?? firstConfiguredViewId.value,\n set: (value: string) => {\n internalActiveView.value = value\n options.emitActiveView(value)\n },\n })\n\n const resolvedCurrentPillId = computed(() => options.currentPillId() ?? resolvedActiveView.value)\n const resolvedCurrentPageSelectorId = computed(() =>\n options.currentPageSelectorId() ?? resolvedActiveView.value,\n )\n\n function setActiveView(viewId: string) {\n resolvedActiveView.value = viewId\n }\n\n function handlePageSelectorSelect(page: PageSelectorItem) {\n setActiveView(page.id)\n options.emitPageSelectorSelect(page)\n }\n\n function handlePillSelect(item: PillNavItem) {\n setActiveView(item.id)\n options.emitPillSelect(item)\n }\n\n return {\n resolvedPillNav,\n firstConfiguredViewId,\n resolvedActiveView,\n resolvedCurrentPillId,\n resolvedCurrentPageSelectorId,\n setActiveView,\n handlePageSelectorSelect,\n handlePillSelect,\n }\n}\n\nfunction firstItemId(items?: readonly (string | { id: string })[]): string | undefined {\n const item = items?.[0]\n if (item === undefined) return undefined\n return typeof item === 'string' ? item : item.id\n}\n","const topBarForwardedSlots = new Set([\n 'icon',\n 'logo',\n 'page-selector-icon',\n 'page-selector-item-icon',\n 'nav',\n 'center',\n 'actions',\n 'account-menu-items',\n 'account-menu-item-icon',\n 'settings-appearance',\n])\n\nconst sidebarForwardedSlots = new Set([\n 'header',\n 'collapsed',\n 'collapsed-footer',\n 'footer',\n])\n\ntype SlotKeyMap = Readonly<Record<string, unknown>>\n\nexport interface PluginWorkspaceSidebarSurfaceOptions {\n showSidebar: boolean\n panels: Record<string, unknown>\n forms: Record<string, unknown>\n model: unknown\n controls: unknown\n showSidebarWhenEmpty: boolean\n sidebarContentId?: string\n sidebarTitle?: string\n sidebarSubtitle?: string\n sidebarBadge?: string | number\n hasSidebarSlot: boolean\n sidebarSlotCount: number\n}\n\nexport function getPluginWorkspaceTopBarSlotNames(slots: SlotKeyMap): string[] {\n return Object.keys(slots).filter(name =>\n topBarForwardedSlots.has(name) || name.startsWith('settings-tab-'),\n )\n}\n\nexport function getPluginWorkspaceSidebarSlotNames(slots: SlotKeyMap): string[] {\n return Object.keys(slots).filter(name =>\n sidebarForwardedSlots.has(name) || name.startsWith('section-'),\n )\n}\n\nexport function hasPluginWorkspaceSidebarSurface(\n options: PluginWorkspaceSidebarSurfaceOptions,\n): boolean {\n if (!options.showSidebar) return false\n return (\n Object.keys(options.panels).length > 0\n || Object.keys(options.forms).length > 0\n || options.model !== undefined\n || options.controls !== undefined\n || options.showSidebarWhenEmpty\n || options.sidebarContentId !== undefined\n || options.sidebarTitle !== undefined\n || options.sidebarSubtitle !== undefined\n || options.sidebarBadge !== undefined\n || options.hasSidebarSlot\n || options.sidebarSlotCount > 0\n )\n}\n","import { computed } from 'vue'\nimport type { ComputedRef } from 'vue'\nimport type { PageSelectorItem, PillNavItem } from '../types'\nimport type {\n PluginWorkspaceViewEmit,\n PluginWorkspaceViewProps,\n} from '../components/PluginWorkspaceView.props'\nimport { usePluginWorkspaceControls } from '../components/PluginWorkspaceView.controls'\nimport { usePluginWorkspaceNavigation } from '../components/PluginWorkspaceView.navigation'\nimport {\n getPluginWorkspaceSidebarSlotNames,\n getPluginWorkspaceTopBarSlotNames,\n hasPluginWorkspaceSidebarSurface,\n} from '../components/PluginWorkspaceView.shell'\nimport type {\n PluginWorkspaceControlsModel,\n PluginWorkspaceShellModel,\n PluginWorkspaceSidebarModel,\n} from './pluginWorkspaceModel'\n\n/**\n * Loosely-typed view of a component's `useSlots()` result: only slot presence and names are\n * read here, so this accepts any `defineSlots()` shape without fighting Vue's `Slot` render\n * function type. Mirrors the `SlotKeyMap` helper type in PluginWorkspaceView.shell.ts.\n */\nexport type PluginWorkspaceSlotsLike = Readonly<Record<string, unknown>>\n\nexport interface UsePluginWorkspaceOptions {\n /** PluginWorkspaceView's own reactive props object (from `defineProps`). */\n props: PluginWorkspaceViewProps\n /** PluginWorkspaceView's own slots (from `useSlots()`), used to detect provided passthrough slots. */\n slots: PluginWorkspaceSlotsLike\n /** PluginWorkspaceView's own typed `emit` function (from `defineEmits<PluginWorkspaceViewEmits>()`). */\n emit: PluginWorkspaceViewEmit\n}\n\nexport interface UsePluginWorkspaceReturn {\n /** Model consumed by WorkspaceShellInternal's `shell` prop. */\n shell: ComputedRef<PluginWorkspaceShellModel>\n /** Model consumed by WorkspaceSidebarInternal's `sidebar` prop. */\n sidebar: ComputedRef<PluginWorkspaceSidebarModel>\n /** Model consumed by WorkspaceControlsInternal's `controls` prop, and by the raw `default` slot. */\n controls: ComputedRef<PluginWorkspaceControlsModel>\n /** Whether AppLayout should render a sidebar surface at all. */\n hasSidebarSurface: ComputedRef<boolean>\n /** Applies an AppSidebar `update:model-value` payload to the shared control values and emits `update:modelValue`/`update:values`. */\n handleControlValuesUpdate: (values: Record<string, unknown>) => void\n /** Resolves an AppTopBar `page-selector-select` payload into the active view and emits `page-selector-select`. */\n handlePageSelectorSelect: (page: PageSelectorItem) => void\n /** Resolves an AppTopBar `pill-select` payload into the active view and emits `pill-select`. */\n handlePillSelect: (item: PillNavItem) => void\n}\n\n/**\n * Maps PluginWorkspaceView's flat 72-prop surface into the three typed model objects\n * (`shell`, `sidebar`, `controls`) rendered by its internal pieces\n * (WorkspaceShellInternal, WorkspaceSidebarInternal, WorkspaceControlsInternal). Reuses the\n * existing `usePluginWorkspaceControls` / `usePluginWorkspaceNavigation` composables and the\n * PluginWorkspaceView.shell slot-detection helpers, so it changes only how that state is\n * assembled and exposed, not the underlying behavior.\n *\n * @example Recommended\n * ```ts\n * const props = withDefaults(defineProps<PluginWorkspaceViewProps>(), { ... })\n * const emit = defineEmits<PluginWorkspaceViewEmits>()\n * const slots = useSlots()\n * const { shell, sidebar, controls } = usePluginWorkspace({ props, slots, emit })\n * ```\n */\nexport function usePluginWorkspace(options: UsePluginWorkspaceOptions): UsePluginWorkspaceReturn {\n const { props, slots, emit } = options\n\n const controlsState = usePluginWorkspaceControls({\n model: () => props.model,\n controls: () => props.controls,\n controlOptions: () => props.controlOptions ?? {},\n modelValue: () => props.modelValue,\n values: () => props.values,\n componentBindings: () => props.componentBindings,\n componentProps: () => props.componentProps,\n componentPropsById: () => props.componentPropsById,\n emitValues: (values) => {\n emit('update:modelValue', values)\n emit('update:values', values)\n },\n })\n\n const navigationState = usePluginWorkspaceNavigation({\n activeView: () => props.activeView,\n defaultActiveView: () => props.defaultActiveView,\n currentPillId: () => props.currentPillId,\n currentPageSelectorId: () => props.currentPageSelectorId,\n pillNav: () => props.pillNav,\n pageSelector: () => props.pageSelector,\n panelIds: () => Object.keys(props.panels ?? {}),\n generatedPillNav: controlsState.generatedPillNav,\n generatedDefaultView: controlsState.generatedDefaultView,\n emitActiveView: viewId => emit('update:activeView', viewId),\n emitPageSelectorSelect: page => emit('page-selector-select', page),\n emitPillSelect: item => emit('pill-select', item),\n })\n\n const topBarSlotNames = computed<string[]>(() => getPluginWorkspaceTopBarSlotNames(slots))\n const sidebarSlotNames = computed<string[]>(() => getPluginWorkspaceSidebarSlotNames(slots))\n\n const hasSidebarSurface = computed(() => hasPluginWorkspaceSidebarSurface({\n showSidebar: props.showSidebar ?? true,\n panels: props.panels ?? {},\n forms: props.forms ?? {},\n model: props.model,\n controls: props.controls,\n showSidebarWhenEmpty: props.showSidebarWhenEmpty ?? false,\n sidebarContentId: props.sidebarContentId,\n sidebarTitle: props.sidebarTitle,\n sidebarSubtitle: props.sidebarSubtitle,\n sidebarBadge: props.sidebarBadge,\n hasSidebarSlot: Boolean(slots.sidebar),\n sidebarSlotCount: sidebarSlotNames.value.length,\n }))\n\n const controls = computed<PluginWorkspaceControlsModel>(() => ({\n activeView: navigationState.resolvedActiveView.value,\n setActiveView: navigationState.setActiveView,\n values: controlsState.internalControlValues,\n componentBindings: controlsState.resolvedComponentBindings.value,\n componentBindingsById: controlsState.resolvedComponentBindingsById.value,\n componentProps: controlsState.resolvedComponentProps.value,\n componentPropsById: controlsState.resolvedComponentPropsById.value,\n }))\n\n const shell = computed<PluginWorkspaceShellModel>(() => ({\n sidebarPosition: props.sidebarPosition ?? 'left',\n sidebarWidth: props.sidebarWidth,\n floating: props.floating ?? true,\n responsiveSidebar: props.responsiveSidebar ?? true,\n sidebarToggleLabel: props.sidebarToggleLabel ?? 'Open workspace sidebar',\n sidebarCloseLabel: props.sidebarCloseLabel ?? 'Close workspace sidebar',\n hasSidebarSurface: hasSidebarSurface.value,\n title: props.title ?? 'Workspace',\n subtitle: props.subtitle,\n topBarVariant: props.topBarVariant ?? 'card',\n homePath: props.homePath ?? '/',\n showLogo: props.showLogo ?? true,\n pageSelector: props.pageSelector,\n currentPageSelectorId: navigationState.resolvedCurrentPageSelectorId.value,\n pillNav: navigationState.resolvedPillNav.value,\n currentPillId: navigationState.resolvedCurrentPillId.value,\n showThemeToggle: props.showThemeToggle ?? true,\n showSettings: props.showSettings ?? true,\n settingsConfig: props.settingsConfig,\n showStandaloneLabel: props.showStandaloneLabel ?? false,\n standaloneLabel: props.standaloneLabel ?? 'Standalone',\n accountMenu: props.accountMenu,\n showNotifications: props.showNotifications ?? false,\n hasNotificationDot: props.hasNotificationDot ?? false,\n showAdmin: props.showAdmin ?? false,\n adminPath: props.adminPath ?? '/admin',\n userName: props.userName,\n userInitial: props.userInitial,\n userEmail: props.userEmail,\n topBarSlotNames: topBarSlotNames.value,\n controls: controls.value,\n }))\n\n const sidebar = computed<PluginWorkspaceSidebarModel>(() => ({\n title: props.sidebarTitle,\n subtitle: props.sidebarSubtitle,\n badge: props.sidebarBadge,\n panels: props.panels ?? {},\n activeView: navigationState.resolvedActiveView.value,\n floating: false,\n dense: props.dense ?? true,\n width: props.sidebarWidth,\n side: props.sidebarPosition ?? 'left',\n forms: props.forms ?? {},\n contentId: props.sidebarContentId,\n showWhenEmpty: (props.showSidebarWhenEmpty ?? false) || props.sidebarContentId !== undefined,\n model: props.model,\n controlSchema: props.controls,\n controlOptions: props.controlOptions ?? {},\n values: controlsState.internalControlValues,\n formEnhancements: props.formEnhancements,\n showFormActions: props.showFormActions ?? false,\n formLoading: props.formLoading ?? false,\n formDisabled: props.formDisabled ?? false,\n formReadonly: props.formReadonly ?? false,\n formSize: props.formSize ?? 'sm',\n collapsible: props.sidebarCollapsible ?? true,\n collapsed: props.sidebarCollapsed,\n defaultCollapsed: props.defaultSidebarCollapsed ?? false,\n collapsedWidth: props.sidebarCollapsedWidth ?? '3rem',\n collapseButtonLabel: props.sidebarCollapseButtonLabel ?? 'Collapse sidebar',\n expandButtonLabel: props.sidebarExpandButtonLabel ?? 'Expand sidebar',\n slotNames: sidebarSlotNames.value,\n }))\n\n return {\n shell,\n sidebar,\n controls,\n hasSidebarSurface,\n handleControlValuesUpdate: controlsState.handleControlValuesUpdate,\n handlePageSelectorSelect: navigationState.handlePageSelectorSelect,\n handlePillSelect: navigationState.handlePillSelect,\n }\n}\n","import { ref, type Ref } from 'vue'\nimport { readErrorMessage as readSharedErrorMessage } from '../utils/errors'\n\nexport type RequestSyncSuccessKind = 'load' | 'save' | 'run'\n\n/**\n * The unit of work `run()` drives.\n *\n * It receives an `AbortSignal` that fires when the run is superseded by a\n * newer `run()` or by `cancel()`. Zero-argument operations stay valid and\n * simply ignore it.\n */\nexport type RequestSyncOperation<T> = (signal: AbortSignal) => Promise<T>\n\nexport interface RequestSyncRunOptions {\n success?: RequestSyncSuccessKind\n errorMessage?: string\n /**\n * Abort the previously started run when this one starts. Default `true`;\n * pass `false` to let overlapping runs finish their own work (the stale\n * guard on shared state still applies either way).\n */\n abortPrevious?: boolean\n /** Caller-owned signal; aborting it aborts this run's signal too. */\n signal?: AbortSignal\n}\n\nexport interface UseRequestSyncStateReturn {\n /** Whether a request is in progress. */\n loading: Ref<boolean>\n /** Message from the last failed request, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load operation, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save operation, or null. */\n lastSavedAt: Ref<Date | null>\n /** Timestamp of the last successful run operation, or null. */\n lastRunAt: Ref<Date | null>\n /** Clear the current error without changing loading or timestamps. */\n clearError: () => void\n /** Convert thrown values into a developer-facing error message. */\n readErrorMessage: (value: unknown, fallback?: string) => string\n /** Store and return a normalized error message. */\n setError: (value: unknown, fallback?: string) => string\n /** Mark the resource as successfully loaded. */\n markLoaded: (date?: Date) => void\n /** Mark the resource as successfully saved. */\n markSaved: (date?: Date) => void\n /** Mark the operation as successfully run. */\n markRun: (date?: Date) => void\n /**\n * Run a request with shared loading/error handling and optional sync marking.\n *\n * ## Stale-response semantics\n *\n * Every call takes a monotonically increasing token. Starting a run\n * supersedes any run started before it, and a superseded run writes **no**\n * shared state when it finally settles: it does not clear `loading`, does not\n * set `error`, and does not move `lastLoadedAt` / `lastSavedAt` / `lastRunAt`.\n * Only the newest run owns those.\n *\n * The caller's own promise is untouched by the guard — a superseded run still\n * resolves with its value or rejects with its own error, exactly as the\n * operation did. The guard never invents a rejection, so a caller awaiting\n * `run()` never sees a \"superseded\" error it did not cause.\n *\n * The operation additionally receives an `AbortSignal` that fires when its\n * run is superseded or `cancel()` is called, so an operation that forwards\n * the signal (`fetch(url, { signal })`) stops work instead of racing.\n */\n run: <T>(operation: RequestSyncOperation<T>, options?: RequestSyncRunOptions) => Promise<T>\n /**\n * Abort the in-flight run and drop `loading`. The aborted run's completion\n * is treated as stale and writes no state.\n */\n cancel: () => void\n}\n\n/** Shared loading/error/timestamp state for generated plugin request helpers. */\nexport function useRequestSyncState(\n defaultErrorMessage = 'Request failed.',\n): UseRequestSyncStateReturn {\n const loading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedAt = ref<Date | null>(null)\n const lastSavedAt = ref<Date | null>(null)\n const lastRunAt = ref<Date | null>(null)\n\n function clearError(): void {\n error.value = null\n }\n\n function readErrorMessage(value: unknown, fallback = defaultErrorMessage): string {\n return readSharedErrorMessage(value, fallback)\n }\n\n function setError(value: unknown, fallback?: string): string {\n const message = readErrorMessage(value, fallback)\n error.value = message\n return message\n }\n\n function markLoaded(date = new Date()): void {\n lastLoadedAt.value = date\n }\n\n function markSaved(date = new Date()): void {\n lastSavedAt.value = date\n }\n\n function markRun(date = new Date()): void {\n lastRunAt.value = date\n }\n\n // Monotonic token guarding every write to the shared loading/error/timestamp\n // state. Overlapping runs settle in any order, and a superseded one must not\n // clear a newer run's loading flag or overwrite its error.\n let runToken = 0\n let activeController: AbortController | null = null\n\n function cancel(): void {\n runToken += 1\n activeController?.abort()\n activeController = null\n loading.value = false\n }\n\n async function run<T>(\n operation: RequestSyncOperation<T>,\n options: RequestSyncRunOptions = {},\n ): Promise<T> {\n if (options.abortPrevious !== false) {\n activeController?.abort()\n }\n\n const token = (runToken += 1)\n const controller = new AbortController()\n activeController = controller\n\n const callerSignal = options.signal\n if (callerSignal) {\n if (callerSignal.aborted) controller.abort(callerSignal.reason)\n else callerSignal.addEventListener(\n 'abort',\n () => controller.abort(callerSignal.reason),\n { once: true },\n )\n }\n\n const isCurrent = (): boolean => token === runToken\n\n loading.value = true\n clearError()\n try {\n const response = await operation(controller.signal)\n if (isCurrent()) {\n if (options.success === 'load') {\n markLoaded()\n } else if (options.success === 'save') {\n markSaved()\n } else if (options.success === 'run') {\n markRun()\n }\n }\n return response\n } catch (err) {\n if (isCurrent()) {\n setError(err, options.errorMessage)\n }\n throw err\n } finally {\n if (isCurrent()) {\n loading.value = false\n }\n if (activeController === controller) {\n activeController = null\n }\n }\n }\n\n return {\n loading,\n error,\n lastLoadedAt,\n lastSavedAt,\n lastRunAt,\n clearError,\n readErrorMessage,\n setError,\n markLoaded,\n markSaved,\n markRun,\n run,\n cancel,\n }\n}\n","import {\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\nimport type {\n BuildPluginEndpointUrlOptions,\n PluginContract,\n PluginEndpointDefinition,\n PluginEndpointParamDefinition,\n} from './usePluginClient'\n\nfunction normalizeApiBaseUrl(baseUrl: string | undefined): string | undefined {\n if (!baseUrl) return undefined\n return baseUrl.length > 1 ? baseUrl.replace(/\\/+$/, '') : baseUrl\n}\n\nfunction normalizeApiPrefix(prefix: string | undefined): string | undefined {\n if (!prefix) return undefined\n if (prefix.startsWith('/api/')) return normalizeApiBaseUrl(prefix)\n if (prefix === '/api') return prefix\n if (prefix.startsWith('/')) return normalizeApiBaseUrl(`/api${prefix}`)\n return normalizeApiBaseUrl(`/api/${prefix}`)\n}\n\nfunction endpointParamName(param: PluginEndpointParamDefinition): string {\n return typeof param === 'string' ? param : param.name\n}\n\nfunction endpointParamFieldName(param: PluginEndpointParamDefinition): string {\n return typeof param === 'string' ? param : param.fieldName ?? param.name\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction replacePathParam(path: string, name: string, encoded: string): string {\n const escapedName = escapeRegExp(name)\n return path\n .replace(new RegExp(`\\\\{${escapedName}(?::[^{}]+)?\\\\}`, 'g'), () => encoded)\n .replace(new RegExp(`:${escapedName}(?=/|$)`, 'g'), () => encoded)\n}\n\n/** Resolve the runtime plugin API base URL from env, explicit options, platform injection, or contract metadata. */\nexport function resolvePluginBaseUrl(contract: PluginContract, explicitBaseUrl?: string): string {\n const envPrefix = (import.meta.env?.VITE_API_PREFIX as string | undefined) || undefined\n if (envPrefix) return normalizeApiBaseUrl(envPrefix) ?? envPrefix\n if (explicitBaseUrl) return normalizeApiBaseUrl(explicitBaseUrl) ?? explicitBaseUrl\n\n const injected = getInjectedPlatformContext()\n const platformPrefix =\n normalizeApiBaseUrl(injected?.plugin?.api_prefix) ||\n normalizeApiPrefix(injected?.plugin?.route_prefix)\n if (platformPrefix) return platformPrefix\n\n return normalizeApiBaseUrl(contract.plugin.apiPrefix) || '/api'\n}\n\nfunction encodePath(\n path: string,\n payload: Record<string, unknown>,\n pathParams: PluginEndpointParamDefinition[],\n): string {\n let nextPath = path\n for (const param of pathParams) {\n const name = endpointParamName(param)\n const fieldName = endpointParamFieldName(param)\n const value = payload[fieldName] ?? payload[name]\n if (value === undefined || value === null) {\n throw new Error(`[MINT SDK] Missing path parameter '${fieldName}' for plugin endpoint ${path}`)\n }\n const encoded = encodeURIComponent(String(value))\n nextPath = replacePathParam(nextPath, name, encoded)\n if (fieldName !== name) {\n nextPath = replacePathParam(nextPath, fieldName, encoded)\n }\n }\n return nextPath\n}\n\nfunction withDefaultPathParams(\n payload: Record<string, unknown>,\n pathParams: PluginEndpointParamDefinition[],\n): Record<string, unknown> {\n if (!pathParams.length) return payload\n const nextPayload = { ...payload }\n for (const param of pathParams) {\n const name = endpointParamName(param)\n const fieldName = endpointParamFieldName(param)\n if (\n (nextPayload[fieldName] !== undefined && nextPayload[fieldName] !== null)\n || (nextPayload[name] !== undefined && nextPayload[name] !== null)\n ) {\n continue\n }\n if (isExperimentPathParam(fieldName) || isExperimentPathParam(name)) {\n const experimentId = resolveCurrentExperimentId()\n if (experimentId !== undefined) {\n nextPayload[fieldName] = experimentId\n }\n }\n }\n return nextPayload\n}\n\nfunction isExperimentPathParam(param: string): boolean {\n return param === 'experimentId' || param === 'experiment_id'\n}\n\nfunction withoutPathParams(payload: Record<string, unknown>, pathParams: PluginEndpointParamDefinition[]) {\n const copy = { ...payload }\n for (const param of pathParams) {\n delete copy[endpointParamFieldName(param)]\n delete copy[endpointParamName(param)]\n }\n return copy\n}\n\nfunction queryParamsFromPayload(\n payload: Record<string, unknown>,\n pathParams: PluginEndpointParamDefinition[],\n queryParams?: PluginEndpointParamDefinition[],\n endpointPath?: string,\n includeUnspecifiedParams = false,\n) {\n if (!queryParams?.length) {\n return includeUnspecifiedParams ? withoutPathParams(payload, pathParams) : {}\n }\n\n const query: Record<string, unknown> = {}\n for (const param of queryParams) {\n const name = typeof param === 'string' ? param : param.name\n const fieldName = typeof param === 'string' ? param : param.fieldName ?? param.name\n const required = typeof param !== 'string' && param.required === true\n const value = payload[fieldName]\n if (value === undefined || value === null) {\n if (required) {\n throw new Error(\n `[MINT SDK] Missing query parameter '${fieldName}' for plugin endpoint ${endpointPath ?? ''}`,\n )\n }\n continue\n }\n query[name] = value\n }\n return query\n}\n\nexport function hasKeys(value: Record<string, unknown>): boolean {\n return Object.keys(value).length > 0\n}\n\nfunction isPlainPayloadObject(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction hasOwn(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key)\n}\n\nfunction normalizeStructuredEndpointPayload(payload: Record<string, unknown>): Record<string, unknown> {\n const pathParamPayload = payload.pathParams\n const queryPayload = payload.query\n const hasStructuredPathParams = hasOwn(payload, 'pathParams') && isPlainPayloadObject(pathParamPayload)\n const hasStructuredQuery = hasOwn(payload, 'query') && isPlainPayloadObject(queryPayload)\n if (!hasStructuredPathParams && !hasStructuredQuery) return payload\n\n const nextPayload = { ...payload }\n delete nextPayload.pathParams\n delete nextPayload.query\n\n if (hasStructuredPathParams) {\n Object.assign(nextPayload, pathParamPayload)\n }\n if (hasStructuredQuery) {\n Object.assign(nextPayload, queryPayload)\n }\n\n return nextPayload\n}\n\nexport function requestBodyFromPayload(\n payload: unknown,\n requestPayload: Record<string, unknown>,\n endpoint: PluginEndpointDefinition,\n): unknown {\n if (!endpoint.hasBody) return undefined\n const body = endpoint.pathParams?.length || endpoint.queryParams?.length\n ? requestPayload.body\n : payload\n if (body === undefined || body === null) {\n throw new Error(`[MINT SDK] Missing request body for plugin endpoint ${endpoint.path}`)\n }\n return body\n}\n\nexport function pluginEndpointRequestParts(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n explicitBaseUrl?: string,\n) {\n const payloadObject = isPlainPayloadObject(payload)\n ? normalizeStructuredEndpointPayload(payload)\n : {}\n const pathParams = endpoint.pathParams ?? []\n const requestPayload = withDefaultPathParams(payloadObject, pathParams)\n const path = encodePath(endpoint.path, requestPayload, pathParams)\n const query = queryParamsFromPayload(\n requestPayload,\n pathParams,\n endpoint.queryParams,\n endpoint.path,\n endpoint.method === 'get',\n )\n\n return {\n baseUrl: resolvePluginBaseUrl(contract, explicitBaseUrl),\n path,\n query,\n requestPayload,\n }\n}\n\nfunction appendQueryValue(params: URLSearchParams, key: string, value: unknown): void {\n if (value === undefined || value === null) return\n if (Array.isArray(value)) {\n for (const item of value) {\n appendQueryValue(params, key, item)\n }\n return\n }\n if (typeof value === 'object') {\n params.append(key, JSON.stringify(value))\n return\n }\n params.append(key, String(value))\n}\n\nfunction queryString(query: Record<string, unknown>): string {\n const params = new URLSearchParams()\n for (const [key, value] of Object.entries(query)) {\n appendQueryValue(params, key, value)\n }\n const serialized = params.toString()\n return serialized ? `?${serialized}` : ''\n}\n\nfunction joinBaseUrl(baseUrl: string, path: string): string {\n if (!baseUrl) return path\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n return `${normalizedBase}${normalizedPath}`\n}\n\n/** Build the concrete URL for a generated plugin endpoint without making a request. */\nexport function buildPluginEndpointUrl(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: BuildPluginEndpointUrlOptions = {},\n): string {\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const pathWithQuery = `${parts.path}${queryString(parts.query)}`\n if (options.includeBaseUrl === false) return pathWithQuery\n return joinBaseUrl(parts.baseUrl, pathWithQuery)\n}\n","import {\n computed,\n onMounted,\n ref,\n shallowRef,\n watch,\n type ComputedRef,\n type Ref,\n} from 'vue'\nimport {\n AuthenticationRequiredError,\n authenticationRequiredError,\n useApi,\n} from './useApi'\nimport { usePlatformContext } from './usePlatformContext'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { useAuthStore } from '../stores/auth'\nimport { PLUGIN_SECRET_FORMAT_KEY } from '../utils/pluginSecrets'\nimport {\n currentExperimentFromContext,\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\nimport {\n buildPluginEndpointUrl,\n hasKeys,\n pluginEndpointRequestParts,\n requestBodyFromPayload,\n} from './pluginEndpointBuilder'\nimport {\n useEventStream,\n type EventStreamMessage,\n type EventStreamTransport,\n type UseEventStreamReturn,\n} from './useEventStream'\nimport type {\n ExperimentSummary,\n GeneratedJobDefinition,\n PageSelectorItem,\n SettingsModalSchema,\n TopBarSettingsConfig,\n} from '../types'\n\nexport {\n buildPluginEndpointUrl,\n resolvePluginBaseUrl,\n} from './pluginEndpointBuilder'\n\nexport type PluginHttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'\n\nexport interface PluginEndpointContract {\n name: string\n operationId?: string\n method: PluginHttpMethod\n path: string\n requiresAuth?: boolean\n pathParams?: PluginEndpointParamContract[]\n queryParams?: PluginEndpointParamContract[]\n requestType?: string | null\n requestContentType?: string | null\n responseType?: string | null\n responseContentType?: string | null\n eventStream?: boolean\n}\n\nexport interface PluginEndpointParamContract {\n name: string\n fieldName: string\n type?: string\n required?: boolean\n}\n\nexport interface PluginNavItemContract {\n path: string\n label: string\n id?: string\n icon?: string\n description?: string\n requiresAuth?: boolean\n requiresAdmin?: boolean\n requiresFeature?: string\n}\n\nexport interface PluginContractSettings {\n modelName: string | null\n /** Pydantic JSON Schema used to generate typed settings values. */\n valueSchema: Record<string, unknown> | null\n /** SDK SettingsModal schema used to render the settings form. */\n formSchema: SettingsModalSchema | null\n}\n\nexport interface PluginContract {\n schemaVersion: 2\n plugin: {\n name?: string\n packageName?: string\n version?: string\n description?: string\n routesPrefix: string\n apiPrefix: string\n type: 'analysis' | 'experiment-design' | string\n analysisType?: string\n icon?: string\n color?: string\n navItems?: PluginNavItemContract[]\n analysisResultReaders?: string[]\n analysisResultWriters?: string[]\n capabilities?: Record<string, unknown>\n }\n settings: PluginContractSettings\n endpoints: PluginEndpointContract[]\n schemas?: Record<string, Record<string, unknown>>\n jobs?: GeneratedJobDefinition[]\n hash: string\n}\n\nexport interface PluginEndpointDefinition {\n method: PluginHttpMethod\n path: string\n requiresAuth?: boolean\n pathParams?: PluginEndpointParamDefinition[]\n queryParams?: PluginEndpointParamDefinition[]\n hasBody?: boolean\n requestContentType?: string | null\n eventStream?: boolean\n responseType?: string | null\n responseContentType?: string | null\n}\n\nexport type PluginEndpointParamDefinition = string | {\n name: string\n fieldName?: string\n type?: string\n required?: boolean\n}\n\nexport interface CreatePluginClientOptions {\n endpoints: Record<string, PluginEndpointDefinition>\n baseUrl?: string\n}\n\nexport interface BuildPluginEndpointUrlOptions {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Return only the endpoint path and query string instead of base URL + path. */\n includeBaseUrl?: boolean\n}\n\nexport interface PluginEndpointRequestOptions {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Cancel the request without changing its endpoint or authentication behavior. */\n signal?: AbortSignal\n}\n\nexport interface PluginClientRequestOptions {\n /** Cancel the generated endpoint request. */\n signal?: AbortSignal\n}\n\nexport interface DownloadPluginEndpointOptions extends PluginEndpointRequestOptions {\n /** Browser download filename. When omitted, the blob is returned without triggering a download. */\n filename?: string\n /** Delay before revoking the object URL after a browser download is triggered. */\n revokeObjectUrlDelayMs?: number\n}\n\nexport interface DownloadBlobOptions {\n /** Delay before revoking the object URL after a browser download is triggered. */\n revokeObjectUrlDelayMs?: number\n}\n\nexport type PluginSettingsValues<TSettings> = Partial<TSettings> & Record<string, unknown>\n\nexport interface UsePluginSettingsOptions {\n /** Plugin name for platform persistence. Defaults to the integrated platform plugin name. */\n pluginName?: string\n /** Plugin API base URL for standalone/local settings routes. Generated clients pass pluginApiPrefix. */\n apiBaseUrl?: string\n /** Platform API base URL for /plugins/{name}/config. Defaults to the injected platform API URL. */\n platformApiBaseUrl?: string\n /** SettingsModal schema generated from the backend plugin config model. */\n schema?: SettingsModalSchema | null\n /** SettingsModal title when using settingsConfig. */\n title?: string\n /** Whether SettingsModal should include SDK appearance controls. */\n showAppearance?: boolean\n /** Load persisted values on component mount. */\n loadOnMount?: boolean\n}\n\nexport interface UsePluginSettingsReturn<TSettings = Record<string, unknown>> {\n /** Current typed settings values. */\n settings: ComputedRef<PluginSettingsValues<TSettings>>\n /** Editable settings values for SettingsModal. */\n values: Ref<PluginSettingsValues<TSettings>>\n /** Alias for values, kept for callers that think in platform config terms. */\n config: Ref<PluginSettingsValues<TSettings>>\n /** Ready-to-pass AppTopBar/PluginWorkspaceView settingsConfig. */\n settingsConfig: ComputedRef<TopBarSettingsConfig>\n isLoading: Ref<boolean>\n isSaving: Ref<boolean>\n error: Ref<string | null>\n lastLoadedAt: Ref<Date | null>\n lastSavedAt: Ref<Date | null>\n isDirty: ComputedRef<boolean>\n setValues: (values: Record<string, unknown>) => void\n load: () => Promise<void>\n save: (values?: Record<string, unknown>) => Promise<boolean>\n reset: () => void\n}\n\nexport type PluginEventStreamMessage<TData = string> = EventStreamMessage<TData>\n\nexport interface PluginEventStreamOptions<TData = string> {\n /** Override the generated or platform-injected API base URL. */\n baseUrl?: string\n /** Start the stream immediately. Defaults to true. */\n immediate?: boolean\n /** Reconnect after errors or server closes. Defaults to true. */\n reconnect?: boolean\n /** Delay before reconnecting after a stream failure or close. Defaults to 2000ms. */\n reconnectDelayMs?: number\n /** Parse `data:` as JSON. Defaults to true for typed endpoints and false otherwise. */\n parseJson?: boolean\n /** Fetch credentials mode. Defaults to same-origin. */\n credentials?: RequestCredentials\n /** Extra request headers. Authorization is injected unless already supplied. */\n headers?: Record<string, string>\n onOpen?: () => void\n onMessage?: (message: PluginEventStreamMessage<TData>) => void\n onError?: (error: unknown) => void\n}\n\nexport type UsePluginEventStreamReturn<TData = string> = UseEventStreamReturn<TData>\n\nexport type PluginFormDataValue =\n | string\n | number\n | boolean\n | Blob\n | null\n | undefined\n | Record<string, unknown>\n\nexport type PluginFormDataPayload = Record<string, PluginFormDataValue | PluginFormDataValue[]>\n\nexport interface UseCurrentExperimentOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseCurrentExperimentReturn<TExperiment = ExperimentSummary> {\n /** Current experiment id resolved from platform injection or URL conventions. */\n experimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasExperiment: ComputedRef<boolean>\n /** Current experiment payload, if injected or successfully fetched. */\n experiment: Ref<TExperiment | undefined>\n /** Whether the current experiment is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed current-experiment fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful current-experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Return the current experiment id or throw a clear SDK error when absent. */\n requireExperimentId: () => number\n /** Fetch a specific experiment id, defaulting to the current experiment id. */\n fetch: (experimentId?: number) => Promise<TExperiment | undefined>\n /** Refetch the currently resolved experiment id. */\n refresh: () => Promise<TExperiment | undefined>\n}\n\nexport type PluginEndpointCaller = (\n payloadOrOptions?: unknown,\n options?: PluginClientRequestOptions,\n) => Promise<unknown>\nexport type GeneratedPluginClient = Record<string, (...args: any[]) => Promise<any>>\n\nfunction queryConfig(query: Record<string, unknown>) {\n return hasKeys(query) ? { params: query } : undefined\n}\n\nconst OCTET_STREAM = 'application/octet-stream'\nconst MULTIPART_FORM_DATA = 'multipart/form-data'\n\nfunction endpointRequestConfig(\n endpoint: PluginEndpointDefinition,\n query: Record<string, unknown>,\n options?: PluginClientRequestOptions,\n) {\n const config: Record<string, unknown> = {}\n if (hasKeys(query)) config.params = query\n if (endpoint.requestContentType === OCTET_STREAM) {\n config.headers = { 'Content-Type': OCTET_STREAM }\n }\n if (endpoint.requestContentType === MULTIPART_FORM_DATA) {\n config.headers = { 'Content-Type': undefined }\n }\n if (endpoint.responseContentType === OCTET_STREAM) {\n config.responseType = 'blob'\n }\n if (options?.signal) config.signal = options.signal\n return hasKeys(config) ? config : undefined\n}\n\nfunction isFormData(value: unknown): value is FormData {\n return typeof FormData !== 'undefined' && value instanceof FormData\n}\n\nfunction endpointRequestBody(endpoint: PluginEndpointDefinition, body: unknown): unknown {\n return endpoint.requestContentType === MULTIPART_FORM_DATA\n ? pluginFormDataFromPayload(body)\n : body\n}\n\nfunction endpointHasPayload(endpoint: PluginEndpointDefinition): boolean {\n return Boolean(\n endpoint.hasBody\n || endpoint.pathParams?.length\n || endpoint.queryParams?.length,\n )\n}\n\nfunction isBlob(value: unknown): value is Blob {\n return typeof Blob !== 'undefined' && value instanceof Blob\n}\n\nfunction appendFormDataValue(formData: FormData, key: string, value: PluginFormDataValue | PluginFormDataValue[]): void {\n if (value === undefined || value === null) return\n\n if (Array.isArray(value)) {\n for (const item of value) {\n appendFormDataValue(formData, key, item)\n }\n return\n }\n\n if (isBlob(value)) {\n formData.append(key, value)\n return\n }\n\n if (typeof value === 'object') {\n formData.append(key, JSON.stringify(value))\n return\n }\n\n formData.append(key, String(value))\n}\n\n/** Convert plain upload payloads into FormData using the same encoding across generated plugin clients. */\nexport function pluginFormDataFromPayload(payload: unknown): FormData {\n if (isFormData(payload)) return payload\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n throw new Error('[MINT SDK] Plugin upload endpoints require a FormData or plain object payload.')\n }\n\n const formData = new FormData()\n for (const [key, value] of Object.entries(payload as PluginFormDataPayload)) {\n appendFormDataValue(formData, key, value)\n }\n return formData\n}\n\n/** Trigger a browser download for an already-created Blob. */\nexport function downloadBlob(blob: Blob, filename: string, options: DownloadBlobOptions = {}): void {\n if (typeof document === 'undefined' || typeof URL === 'undefined') {\n throw new Error('[MINT SDK] Cannot trigger a file download outside a browser.')\n }\n\n const blobUrl = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = filename\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n setTimeout(() => URL.revokeObjectURL(blobUrl), options.revokeObjectUrlDelayMs ?? 100)\n}\n\nfunction normalizePluginNavPath(path: string): string {\n const raw = path.trim() || '/'\n const prefixed = raw.startsWith('/') ? raw : `/${raw}`\n return prefixed.replace(/\\/+$/, '') || '/'\n}\n\nfunction pluginPageIdFromPath(path: string, fallbackIndex: number): string {\n const normalizedPath = normalizePluginNavPath(path)\n if (normalizedPath === '/') return 'dashboard'\n return normalizedPath.replace(/^\\/+/, '').replace(/\\/+/g, '-') || `page-${fallbackIndex + 1}`\n}\n\n/** Convert resolved @mint_plugin nav_items into page selectors for the topbar and homepage PluginCards. */\nexport function getPluginPageSelectorItems(contract: PluginContract): PageSelectorItem[] {\n const pluginIcon = contract.plugin.icon ?? ''\n const navItems = contract.plugin.navItems ?? []\n return navItems.map((item, index) => ({\n id: item.id || pluginPageIdFromPath(item.path, index),\n label: item.label,\n to: normalizePluginNavPath(item.path),\n icon: item.icon || pluginIcon || undefined,\n }))\n}\n\n/** Create a typed plugin API client from a generated MINT plugin contract. */\nexport function createPluginClient<TClient extends object = GeneratedPluginClient>(\n contract: PluginContract,\n options: CreatePluginClientOptions,\n): TClient {\n const client: Record<string, PluginEndpointCaller> = {}\n\n for (const [name, endpoint] of Object.entries(options.endpoints)) {\n client[name] = async (\n payloadOrOptions?: unknown,\n explicitOptions?: PluginClientRequestOptions,\n ) => {\n const hasPayload = endpointHasPayload(endpoint)\n const payload = hasPayload ? payloadOrOptions : undefined\n const callOptions = hasPayload\n ? explicitOptions\n : (payloadOrOptions as PluginClientRequestOptions | undefined) ?? explicitOptions\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({\n baseUrl: parts.baseUrl,\n withAuth: endpoint.requiresAuth !== false,\n typedErrors: true,\n })\n const config = endpointRequestConfig(endpoint, parts.query, callOptions)\n\n if (endpoint.method === 'get') {\n return api.get(parts.path, config)\n }\n\n if (endpoint.method === 'delete') {\n const rawBody = requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n const body = rawBody === undefined ? undefined : endpointRequestBody(endpoint, rawBody)\n const config = body === undefined\n ? endpointRequestConfig(endpoint, parts.query, callOptions)\n : { ...endpointRequestConfig(endpoint, parts.query, callOptions), data: body }\n return api.delete(parts.path, config)\n }\n\n const body = endpointRequestBody(\n endpoint,\n requestBodyFromPayload(payload, parts.requestPayload, endpoint),\n )\n\n if (endpoint.method === 'post') return api.post(parts.path, body, config)\n if (endpoint.method === 'put') return api.put(parts.path, body, config)\n if (endpoint.method === 'patch') return api.patch(parts.path, body, config)\n throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`)\n }\n }\n\n return client as TClient\n}\n\n/** Send multipart or raw binary data to a generated endpoint with contract URL, cancellation, and auth handling. */\nexport async function uploadPluginEndpoint<TResponse = unknown>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: PluginEndpointRequestOptions = {},\n): Promise<TResponse> {\n if (!['post', 'put', 'patch'].includes(endpoint.method)) {\n throw new Error(`[MINT SDK] Plugin upload endpoints must use POST, PUT, or PATCH; got ${endpoint.method}`)\n }\n\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({\n baseUrl: parts.baseUrl,\n withAuth: endpoint.requiresAuth !== false,\n typedErrors: true,\n })\n const body = endpoint.hasBody\n ? requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n : payload\n if (endpoint.requestContentType === OCTET_STREAM) {\n const config = endpointRequestConfig(endpoint, parts.query, { signal: options.signal })\n if (endpoint.method === 'post') return api.post<TResponse>(parts.path, body, config)\n if (endpoint.method === 'put') return api.put<TResponse>(parts.path, body, config)\n return api.patch<TResponse>(parts.path, body, config)\n }\n const formData = pluginFormDataFromPayload(body)\n const config = {\n ...(queryConfig(parts.query) ?? {}),\n ...(options.signal ? { signal: options.signal } : {}),\n // Let Axios/browser set multipart boundaries.\n headers: { 'Content-Type': undefined },\n }\n\n if (endpoint.method === 'post') return api.post<TResponse>(parts.path, formData, config)\n if (endpoint.method === 'put') return api.put<TResponse>(parts.path, formData, config)\n return api.patch<TResponse>(parts.path, formData, config)\n}\n\n/** Fetch a generated plugin endpoint as a Blob and optionally trigger a browser download. */\nexport async function downloadPluginEndpoint(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options: DownloadPluginEndpointOptions = {},\n): Promise<Blob> {\n if (endpoint.requestContentType === MULTIPART_FORM_DATA) {\n throw new Error('[MINT SDK] Plugin download endpoints do not support multipart request bodies')\n }\n\n const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl)\n const api = useApi({\n baseUrl: parts.baseUrl,\n withAuth: endpoint.requiresAuth !== false,\n typedErrors: true,\n })\n const config = {\n ...(endpointRequestConfig(endpoint, parts.query, { signal: options.signal }) ?? {}),\n responseType: 'blob' as const,\n }\n const rawBody = requestBodyFromPayload(payload, parts.requestPayload, endpoint)\n const body = rawBody === undefined ? undefined : endpointRequestBody(endpoint, rawBody)\n let blob: Blob\n\n if (endpoint.method === 'get') blob = await api.get<Blob>(parts.path, config)\n else if (endpoint.method === 'post') blob = await api.post<Blob>(parts.path, body, config)\n else if (endpoint.method === 'put') blob = await api.put<Blob>(parts.path, body, config)\n else if (endpoint.method === 'patch') blob = await api.patch<Blob>(parts.path, body, config)\n else if (endpoint.method === 'delete') {\n blob = await api.delete<Blob>(parts.path, body === undefined ? config : { ...config, data: body })\n } else {\n throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`)\n }\n\n if (options.filename) {\n downloadBlob(blob, options.filename, {\n revokeObjectUrlDelayMs: options.revokeObjectUrlDelayMs,\n })\n }\n\n return blob\n}\n\nfunction normalizePluginSettingsOptions(options: UsePluginSettingsOptions | string = {}): UsePluginSettingsOptions {\n return typeof options === 'string' ? { pluginName: options } : options\n}\n\n/** @deprecated Removed in MINT 1.4; use `useGeneratedPluginClient()` for generated clients. */\nexport function usePluginClient<TClient>(client: TClient): TClient {\n return client\n}\n\nconst PLATFORM_OWNED_SETTINGS_KEY = 'allowed_experiment_types'\n\n/**\n * Secret settings travel as `{ \"$secret\": \"<id>\" }` references, so an untouched\n * secret round-trips without ever exposing its value. Declaring the format on\n * every write keeps a `null` unambiguous: it clears the stored secret instead of\n * meaning \"unchanged\", which is what the deprecated placeholder form meant.\n */\nfunction withSecretFormat(\n payload: Record<string, unknown>,\n secretFormat: string | null,\n): Record<string, unknown> {\n if (!secretFormat) return payload\n return { ...payload, [PLUGIN_SECRET_FORMAT_KEY]: secretFormat }\n}\n\nfunction responseSecretFormat(response: unknown): string | null {\n if (!response || typeof response !== 'object') return null\n const format = (response as Record<string, unknown>)[PLUGIN_SECRET_FORMAT_KEY]\n return typeof format === 'string' && format ? format : null\n}\n\nfunction cloneRecord(value: Record<string, unknown>): Record<string, unknown> {\n return JSON.parse(JSON.stringify(value)) as Record<string, unknown>\n}\n\nfunction hasOwnSetting(settings: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(settings, key)\n}\n\nfunction responseSettingsPayload(response: unknown): Record<string, unknown> {\n if (!response || typeof response !== 'object') return {}\n const data = response as {\n config?: unknown\n settings?: unknown\n }\n if (data.config && typeof data.config === 'object') {\n return cloneRecord(data.config as Record<string, unknown>)\n }\n if (data.settings && typeof data.settings === 'object') {\n return cloneRecord(data.settings as Record<string, unknown>)\n }\n return {}\n}\n\nfunction responseSettingsRevision(response: unknown): string | null {\n if (!response || typeof response !== 'object') return null\n const revision = (response as { revision?: unknown }).revision\n return typeof revision === 'string' && revision ? revision : null\n}\n\nfunction topLevelSettingsPatch(\n current: Record<string, unknown>,\n keys: Iterable<string>,\n): Record<string, unknown> {\n return Object.fromEntries(\n [...keys].map(key => [\n key,\n hasOwnSetting(current, key) ? current[key] : null,\n ]),\n )\n}\n\nfunction changedTopLevelSettingKeys(\n current: Record<string, unknown>,\n saved: Record<string, unknown>,\n): Set<string> {\n return new Set(\n [...new Set([...Object.keys(current), ...Object.keys(saved)])].filter(\n key => JSON.stringify(current[key]) !== JSON.stringify(saved[key]),\n ),\n )\n}\n\nfunction platformOwnedSettingsPatch(settings: Record<string, unknown>): Record<string, unknown> {\n return {\n [PLATFORM_OWNED_SETTINGS_KEY]: hasOwnSetting(settings, PLATFORM_OWNED_SETTINGS_KEY)\n ? settings[PLATFORM_OWNED_SETTINGS_KEY]\n : null,\n }\n}\n\n/** Load, edit, and persist plugin settings from platform config or the plugin-local settings router. */\nexport function usePluginSettings<TSettings = Record<string, unknown>>(\n options: UsePluginSettingsOptions | string = {},\n): UsePluginSettingsReturn<TSettings> {\n const resolvedOptions = normalizePluginSettingsOptions(options)\n const injectedContext = getInjectedPlatformContext()\n const { plugin, isIntegrated } = usePlatformContext()\n const platformApi = useApi({ baseUrl: resolvedOptions.platformApiBaseUrl ?? injectedContext?.platformApiUrl })\n const pluginApi = useApi({ baseUrl: resolvedOptions.apiBaseUrl ?? injectedContext?.plugin?.api_prefix })\n\n const values = ref({}) as Ref<PluginSettingsValues<TSettings>>\n const savedValues = shallowRef<Record<string, unknown>>({})\n const revision = ref<string | null>(null)\n const secretFormat = ref<string | null>(null)\n const request = useRequestSyncState('Plugin settings request failed.')\n const isLoading = ref(false)\n const isSaving = ref(false)\n\n const resolvedPluginName = computed(() =>\n resolvedOptions.pluginName ?? plugin.value?.name ?? injectedContext?.plugin?.name ?? '',\n )\n const usesPluginSettingsApi = computed(() => {\n const currentPlugin = injectedContext?.plugin ?? plugin.value\n return currentPlugin?.settings_api === 'plugin'\n && resolvedPluginName.value === currentPlugin.name\n })\n const usesPlatformConfig = computed(() =>\n Boolean(\n (isIntegrated.value || injectedContext?.isIntegrated)\n && resolvedPluginName.value\n && !usesPluginSettingsApi.value,\n ),\n )\n const settings = computed(() => values.value)\n const isDirty = computed(() => JSON.stringify(values.value) !== JSON.stringify(savedValues.value))\n const settingsConfig = computed<TopBarSettingsConfig>(() => ({\n title: resolvedOptions.title,\n schema: resolvedOptions.schema ?? undefined,\n showAppearance: resolvedOptions.showAppearance,\n values: values.value,\n }))\n\n function setValues(nextValues: Record<string, unknown>): void {\n values.value = cloneRecord(nextValues) as PluginSettingsValues<TSettings>\n }\n\n function applyLoaded(\n nextValues: Record<string, unknown>,\n nextRevision: string | null,\n nextSecretFormat: string | null = secretFormat.value,\n ): void {\n const cloned = cloneRecord(nextValues)\n values.value = cloned as PluginSettingsValues<TSettings>\n savedValues.value = cloneRecord(cloned)\n revision.value = nextRevision\n secretFormat.value = nextSecretFormat\n }\n\n async function load(): Promise<void> {\n isLoading.value = true\n try {\n const response = usesPlatformConfig.value\n ? await request.run(\n () => platformApi.get<{ plugin_name: string; config: Record<string, unknown> }>(\n `/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`,\n ),\n { success: 'load', errorMessage: 'Failed to load plugin settings' },\n )\n : await request.run(\n () => pluginApi.get<{ settings: Record<string, unknown>; mode?: string }>('/settings'),\n { success: 'load', errorMessage: 'Failed to load plugin settings' },\n )\n applyLoaded(\n responseSettingsPayload(response),\n responseSettingsRevision(response),\n responseSecretFormat(response),\n )\n } catch {\n // Error state is handled by request.run().\n } finally {\n isLoading.value = false\n }\n }\n\n async function save(nextValues?: Record<string, unknown>): Promise<boolean> {\n if (nextValues) {\n setValues(nextValues)\n }\n\n isSaving.value = true\n try {\n const payload = cloneRecord(values.value)\n let response: unknown\n if (usesPlatformConfig.value) {\n const dirtyKeys = changedTopLevelSettingKeys(payload, savedValues.value)\n const platformOwnedChanged = dirtyKeys.has(PLATFORM_OWNED_SETTINGS_KEY)\n const typedKeys = [...dirtyKeys].filter(\n key => key !== PLATFORM_OWNED_SETTINGS_KEY,\n )\n let nextRevision = revision.value\n\n if (typedKeys.length) {\n response = await request.run(\n () => platformApi.patch<{\n plugin_name: string\n config: Record<string, unknown>\n revision?: string\n }>(\n `/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`,\n {\n config: withSecretFormat(\n topLevelSettingsPatch(payload, typedKeys),\n secretFormat.value,\n ),\n },\n ),\n { success: 'save', errorMessage: 'Failed to save plugin settings' },\n )\n nextRevision = responseSettingsRevision(response) ?? nextRevision\n }\n\n if (platformOwnedChanged) {\n response = await request.run(\n () => platformApi.patch<{\n plugin_name: string\n config: Record<string, unknown>\n revision?: string\n }>(\n `/plugins/${encodeURIComponent(resolvedPluginName.value)}/config`,\n { config: platformOwnedSettingsPatch(payload) },\n ),\n { success: 'save', errorMessage: 'Failed to save plugin settings' },\n )\n nextRevision = responseSettingsRevision(response) ?? nextRevision\n }\n\n if (!response) return true\n applyLoaded(\n responseSettingsPayload(response),\n nextRevision,\n responseSecretFormat(response) ?? secretFormat.value,\n )\n return true\n } else {\n const ifMatch = revision.value\n ? { headers: { 'If-Match': `\"${revision.value}\"` } }\n : undefined\n response = await request.run(\n () => pluginApi.put<{\n settings: Record<string, unknown>\n mode?: string\n revision?: string\n }>('/settings', withSecretFormat(payload, secretFormat.value), ifMatch),\n { success: 'save', errorMessage: 'Failed to save plugin settings' },\n )\n }\n applyLoaded(\n responseSettingsPayload(response),\n responseSettingsRevision(response) ?? revision.value,\n responseSecretFormat(response) ?? secretFormat.value,\n )\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n function reset(): void {\n values.value = cloneRecord(savedValues.value) as PluginSettingsValues<TSettings>\n request.clearError()\n }\n\n onMounted(() => {\n if (resolvedOptions.loadOnMount !== false) {\n void load()\n }\n })\n\n return {\n settings,\n values,\n config: values,\n settingsConfig,\n isLoading,\n isSaving,\n error: request.error,\n lastLoadedAt: request.lastLoadedAt,\n lastSavedAt: request.lastSavedAt,\n isDirty,\n setValues,\n load,\n save,\n reset,\n }\n}\n\nfunction streamRequestAuth(\n requestHeaders: HeadersInit | undefined,\n policy: { requiresAuth: boolean },\n): {\n headers: Headers\n token?: string\n} {\n const headers = new Headers(requestHeaders)\n const authStore = useAuthStore()\n if (!authStore.isInitialized) {\n authStore.initialize()\n }\n if (policy.requiresAuth && authStore.token && !headers.has('Authorization')) {\n headers.set('Authorization', `Bearer ${authStore.token}`)\n }\n const token = policy.requiresAuth ? authStore.token : undefined\n return {\n headers,\n token: token && headers.get('Authorization') === `Bearer ${token}` ? token : undefined,\n }\n}\n\nfunction pluginEventStreamTransport(\n endpoint: PluginEndpointDefinition,\n): EventStreamTransport {\n return async (url, init = {}) => {\n if (typeof fetch !== 'function') {\n throw new Error('[MINT SDK] fetch is required for plugin event streams.')\n }\n const requestAuth = streamRequestAuth(\n init.headers,\n { requiresAuth: endpoint.requiresAuth !== false },\n )\n const response = await fetch(url, { ...init, headers: requestAuth.headers })\n if (response.status === 401) {\n throw authenticationRequiredError(response, requestAuth.token)\n }\n return response\n }\n}\n\nfunction looksLikeEventStreamOptions(value: unknown): value is PluginEventStreamOptions {\n if (!value || typeof value !== 'object') return false\n const candidate = value as Record<string, unknown>\n return [\n 'baseUrl',\n 'immediate',\n 'reconnect',\n 'reconnectDelayMs',\n 'parseJson',\n 'credentials',\n 'headers',\n 'onOpen',\n 'onMessage',\n 'onError',\n ].some(key => key in candidate)\n}\n\n/** Consume a generated plugin SSE endpoint with auth headers, reconnect, and teardown. */\nexport function usePluginEventStream<TData = string>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n options?: PluginEventStreamOptions<TData>,\n): UsePluginEventStreamReturn<TData>\nexport function usePluginEventStream<TData = string>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payload?: unknown,\n options?: PluginEventStreamOptions<TData>,\n): UsePluginEventStreamReturn<TData>\nexport function usePluginEventStream<TData = string>(\n contract: PluginContract,\n endpoint: PluginEndpointDefinition,\n payloadOrOptions?: unknown,\n maybeOptions?: PluginEventStreamOptions<TData>,\n): UsePluginEventStreamReturn<TData> {\n if (endpoint.method !== 'get') {\n throw new Error(`[MINT SDK] Plugin event streams must use GET; got ${endpoint.method}`)\n }\n const payload = maybeOptions === undefined && looksLikeEventStreamOptions(payloadOrOptions)\n ? undefined\n : payloadOrOptions\n const options = (\n maybeOptions === undefined && looksLikeEventStreamOptions(payloadOrOptions)\n ? payloadOrOptions\n : maybeOptions ?? {}\n ) as PluginEventStreamOptions<TData>\n const responseType = endpoint.responseType?.trim()\n const parseJson = options.parseJson ?? Boolean(responseType && responseType !== 'string')\n return useEventStream<TData>(\n () => buildPluginEndpointUrl(contract, endpoint, payload, { baseUrl: options.baseUrl }),\n {\n transport: pluginEventStreamTransport(endpoint),\n immediate: options.immediate,\n reconnect: options.reconnect,\n reconnectDelayMs: options.reconnectDelayMs,\n parseJson,\n credentials: options.credentials,\n headers: options.headers,\n shouldReconnect: cause => !(cause instanceof AuthenticationRequiredError),\n onOpen: options.onOpen,\n onMessage: options.onMessage,\n onError: options.onError,\n errorLabel: 'Plugin event stream',\n },\n )\n}\n\n/** Read and optionally load the current platform experiment for integrated plugin views. */\nexport function useCurrentExperiment<TExperiment = ExperimentSummary>(\n options: UseCurrentExperimentOptions = {},\n): UseCurrentExperimentReturn<TExperiment> {\n const api = useApi({ baseUrl: options.apiBaseUrl ?? getInjectedPlatformContext()?.platformApiUrl })\n const experiment = shallowRef<TExperiment | undefined>(currentExperimentFromContext<TExperiment>())\n const request = useRequestSyncState('Failed to load current experiment')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n\n const experimentId = computed<number | undefined>(() => {\n return resolveCurrentExperimentId()\n })\n const hasExperiment = computed(() => experimentId.value !== undefined)\n\n function requireExperimentId(): number {\n const id = experimentId.value\n if (id === undefined) {\n throw new Error('[MINT SDK] No current experiment is selected.')\n }\n return id\n }\n\n async function fetchExperiment(id = experimentId.value): Promise<TExperiment | undefined> {\n if (id === undefined) {\n experiment.value = currentExperimentFromContext<TExperiment>()\n return experiment.value\n }\n\n try {\n const result = await request.run(\n () => api.get<TExperiment>(`/experiments/${id}`),\n { success: 'load', errorMessage: 'Failed to load current experiment' },\n )\n experiment.value = result\n return result\n } catch (e) {\n experiment.value = undefined\n return undefined\n }\n }\n\n async function refresh(): Promise<TExperiment | undefined> {\n return fetchExperiment()\n }\n\n watch(\n experimentId,\n (id) => {\n if (options.immediate === false) return\n if (id === undefined) {\n experiment.value = currentExperimentFromContext<TExperiment>()\n return\n }\n void fetchExperiment(id)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n hasExperiment,\n experiment,\n isLoading,\n error,\n lastLoadedAt,\n requireExperimentId,\n fetch: fetchExperiment,\n refresh,\n }\n}\n","import {\n computed,\n onMounted,\n onUnmounted,\n ref,\n shallowRef,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n type ShallowRef,\n} from 'vue'\n\nimport { isActiveJobStatus, normalizeJobState } from '../jobs'\nimport type {\n JobListPayload,\n JobState,\n JobStateInput,\n JobStreamData,\n} from '../types/jobs'\nimport type {\n PluginEventStreamMessage,\n UsePluginEventStreamReturn,\n} from './usePluginClient'\n\nexport type JobsStatusTrayTab = 'active' | 'history'\n\n/**\n * The canonical owner of a collection of plugin jobs.\n *\n * Sources, rather than job-center UI, own polling, event streams, and all job\n * mutations. This keeps components and consumers on one reactive job graph.\n */\nexport interface PluginJobCenterSource {\n jobs: MaybeRefOrGetter<readonly JobStateInput[]>\n refreshJobs?: () => Promise<JobListPayload | readonly JobStateInput[] | void>\n cancelJob?: (jobId: string) => Promise<JobStateInput | void>\n deleteJob?: (jobId: string) => Promise<boolean | void>\n clearFinishedJobs?: () => Promise<number | void>\n dispose?: () => void\n}\n\nexport interface CombinedPluginJobCenterSource extends PluginJobCenterSource {\n jobs: ComputedRef<readonly JobStateInput[]>\n}\n\n/**\n * Combines independent job runtimes without copying their reactive state.\n *\n * Job ids must be globally unique across the sources. A duplicate id throws\n * when jobs are read or an id-routed action is requested, rather than silently\n * dispatching a mutation to the wrong owner.\n */\nexport function combinePluginJobSources(\n sources: readonly PluginJobCenterSource[],\n): CombinedPluginJobCenterSource {\n const jobs = computed<readonly JobStateInput[]>(() => {\n const combined: JobStateInput[] = []\n const owners = new Set<string>()\n for (const source of sources) {\n for (const job of toValue(source.jobs)) {\n if (owners.has(job.job_id)) throw duplicatePluginJobId(job.job_id)\n owners.add(job.job_id)\n combined.push(job)\n }\n }\n return combined\n })\n\n function ownerFor(jobId: string): PluginJobCenterSource {\n let owner: PluginJobCenterSource | undefined\n for (const source of sources) {\n if (!toValue(source.jobs).some(job => job.job_id === jobId)) continue\n if (owner) throw duplicatePluginJobId(jobId)\n owner = source\n }\n if (!owner) throw new Error(`Unknown plugin job id: ${jobId}`)\n return owner\n }\n\n const combined: CombinedPluginJobCenterSource = { jobs }\n if (sources.some(source => source.refreshJobs)) {\n combined.refreshJobs = async () => {\n await Promise.all(sources.map(source => source.refreshJobs?.()))\n return jobs.value\n }\n }\n if (sources.some(source => source.cancelJob)) {\n combined.cancelJob = async (jobId) => {\n const owner = ownerFor(jobId)\n if (!owner.cancelJob) throw new Error(`Job ${jobId} cannot be cancelled by its source`)\n return owner.cancelJob(jobId)\n }\n }\n if (sources.length > 0 && sources.every(source => source.deleteJob)) {\n combined.deleteJob = async (jobId) => {\n const owner = ownerFor(jobId)\n if (!owner.deleteJob) throw new Error(`Job ${jobId} cannot be deleted by its source`)\n return owner.deleteJob(jobId)\n }\n }\n // Never report a successful combined clear after mutating only a subset.\n // Without bulk support from every source, the job center can still fall\n // back to this source's id-routed deleteJob method when all owners expose it.\n if (sources.length > 0 && sources.every(source => source.clearFinishedJobs)) {\n combined.clearFinishedJobs = async () => {\n const results = await Promise.all(\n sources.map(source => source.clearFinishedJobs!()),\n )\n return results.every((result): result is number => typeof result === 'number')\n ? results.reduce((total, result) => total + result, 0)\n : undefined\n }\n }\n if (sources.some(source => source.dispose)) {\n combined.dispose = () => {\n const errors: unknown[] = []\n for (const source of sources) {\n try {\n source.dispose?.()\n } catch (cause) {\n errors.push(cause)\n }\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) throw new PluginJobSourceDisposeError(errors)\n }\n }\n return combined\n}\n\nclass PluginJobSourceDisposeError extends Error {\n readonly cause: unknown\n readonly errors: readonly unknown[]\n\n constructor(errors: readonly unknown[]) {\n super('Failed to dispose plugin job sources')\n this.name = 'PluginJobSourceDisposeError'\n this.cause = errors[0]\n this.errors = Object.freeze([...errors])\n }\n}\n\nfunction duplicatePluginJobId(jobId: string): Error {\n return new Error(`Duplicate plugin job id across combined sources: ${jobId}`)\n}\n\n/** @deprecated Removed in MINT 1.4; prefer a {@link PluginJobCenterSource}. */\nexport interface JobsStatusTrayAdapter {\n listJobs?: () => Promise<JobListPayload | readonly JobStateInput[]>\n cancelJob?: (job: JobState) => Promise<JobStateInput | void>\n deleteJob?: (job: JobState) => Promise<boolean | void>\n clearFinishedJobs?: (jobs: readonly JobState[]) => Promise<number | void>\n}\n\nexport interface UsePluginJobCenterOptions {\n source?: MaybeRefOrGetter<PluginJobCenterSource | undefined>\n /** @deprecated Removed in MINT 1.4; pass a source with its canonical jobs ref. */\n jobs?: MaybeRefOrGetter<readonly JobStateInput[] | undefined>\n /** @deprecated Removed in MINT 1.4; pass source actions instead. */\n adapter?: MaybeRefOrGetter<JobsStatusTrayAdapter | undefined>\n /** @deprecated Removed in MINT 1.4; event handling belongs to the source runtime. */\n eventStream?: MaybeRefOrGetter<UsePluginEventStreamReturn<JobStreamData> | undefined>\n loadOnMount?: boolean\n}\n\nexport interface UseJobsStatusTrayOptions extends UsePluginJobCenterOptions {}\n\nexport interface JobStreamMessage {\n event: string\n data: JobStreamData\n}\n\nexport interface UsePluginJobCenterReturn {\n jobs: ComputedRef<JobState[]>\n activeJobs: ComputedRef<JobState[]>\n historyJobs: ComputedRef<JobState[]>\n deletableJobs: ComputedRef<JobState[]>\n featuredJob: ComputedRef<JobState | null>\n canRefresh: ComputedRef<boolean>\n canCancel: ComputedRef<boolean>\n canDelete: ComputedRef<boolean>\n canClearFinished: ComputedRef<boolean>\n isOpen: Ref<boolean>\n activeTab: Ref<JobsStatusTrayTab>\n isLoading: Ref<boolean>\n error: ShallowRef<string | null>\n pendingJobIds: Ref<Set<string>>\n open: () => void\n close: () => void\n toggle: () => void\n refresh: () => Promise<boolean>\n applyStreamMessage: (message: JobStreamMessage) => void\n cancelJob: (job: JobState) => Promise<boolean>\n deleteJob: (job: JobState) => Promise<boolean>\n clearFinished: () => Promise<boolean>\n isPending: (job: JobState) => boolean\n}\n\nexport type UseJobsStatusTrayReturn = UsePluginJobCenterReturn\n\ninterface LegacyJobsOverride {\n readonly input: readonly JobStateInput[] | undefined\n readonly jobs: JobState[]\n}\n\nfunction responseJobs(\n response: JobListPayload | readonly JobStateInput[],\n): readonly JobStateInput[] {\n return 'jobs' in response ? response.jobs : response\n}\n\nfunction isSnapshotPayload(data: JobStreamData): data is { jobs: JobStateInput[] } {\n return 'jobs' in data && Array.isArray(data.jobs)\n}\n\nfunction errorMessage(error: unknown, fallback: string): string {\n return error instanceof Error ? error.message : fallback\n}\n\n/**\n * Headless controller for plugin job presentation and actions.\n *\n * When a source is supplied, every job list is derived directly from that\n * source. The controller never mirrors source jobs into another ref.\n */\nexport function usePluginJobCenter(\n options: UsePluginJobCenterOptions = {},\n): UsePluginJobCenterReturn {\n const legacyOverride = shallowRef<LegacyJobsOverride | null>(null)\n const isOpen = ref(false)\n const activeTab = ref<JobsStatusTrayTab>('active')\n const isLoading = ref(false)\n const error = shallowRef<string | null>(null)\n const pendingJobIds = ref(new Set<string>())\n const jobRevisions = new Map<string, number>()\n let stateRevision = 0\n let requestGeneration = 0\n let active = true\n const source = computed(() => toValue(options.source))\n const adapter = computed(() => toValue(options.adapter))\n\n const jobs = computed<JobState[]>(() => {\n const currentSource = source.value\n if (currentSource) {\n return [...toValue(currentSource.jobs)].map(normalizeJobState)\n }\n const input = toValue(options.jobs)\n const override = legacyOverride.value\n if (override && override.input === input) return override.jobs\n return input ? [...input].map(normalizeJobState) : []\n })\n const activeJobs = computed(() => jobs.value.filter(job => isActiveJobStatus(job.status)))\n const historyJobs = computed(() => jobs.value.filter(job => !isActiveJobStatus(job.status)))\n const deletableJobs = computed(() => historyJobs.value.filter(job => job.can_delete))\n const featuredJob = computed(() => activeJobs.value[0] ?? historyJobs.value[0] ?? null)\n const canRefresh = computed(() => Boolean(source.value?.refreshJobs || adapter.value?.listJobs))\n const canCancel = computed(() => Boolean(source.value?.cancelJob || adapter.value?.cancelJob))\n const canDelete = computed(() => Boolean(source.value?.deleteJob || adapter.value?.deleteJob))\n const canClearFinished = computed(() => Boolean(\n source.value?.clearFinishedJobs\n || source.value?.deleteJob\n || adapter.value?.clearFinishedJobs\n || adapter.value?.deleteJob,\n ))\n\n function bumpJobRevision(jobId: string): void {\n jobRevisions.set(jobId, (jobRevisions.get(jobId) ?? 0) + 1)\n }\n\n function replaceLegacyJobs(nextJobs: readonly JobStateInput[]): void {\n const normalized = nextJobs.map(normalizeJobState)\n const touchedJobIds = new Set([\n ...jobs.value.map(job => job.job_id),\n ...normalized.map(job => job.job_id),\n ])\n touchedJobIds.forEach(bumpJobRevision)\n legacyOverride.value = {\n input: toValue(options.jobs),\n jobs: normalized,\n }\n stateRevision += 1\n }\n\n function upsertLegacyJob(nextJob: JobStateInput): void {\n const normalized = normalizeJobState(nextJob)\n const existingIndex = jobs.value.findIndex(job => job.job_id === normalized.job_id)\n const nextJobs = [...jobs.value]\n if (existingIndex === -1) nextJobs.unshift(normalized)\n else nextJobs[existingIndex] = normalized\n legacyOverride.value = {\n input: toValue(options.jobs),\n jobs: nextJobs,\n }\n bumpJobRevision(normalized.job_id)\n stateRevision += 1\n }\n\n function removeLegacyJobs(jobIds: Set<string>): void {\n legacyOverride.value = {\n input: toValue(options.jobs),\n jobs: jobs.value.filter(job => !jobIds.has(job.job_id)),\n }\n jobIds.forEach(bumpJobRevision)\n stateRevision += 1\n }\n\n function setPending(jobId: string, pending: boolean): void {\n const next = new Set(pendingJobIds.value)\n if (pending) next.add(jobId)\n else next.delete(jobId)\n pendingJobIds.value = next\n }\n\n function applyStreamMessage(message: JobStreamMessage): void {\n if (!active || source.value) return\n if (message.event === 'snapshot' && isSnapshotPayload(message.data)) {\n replaceLegacyJobs(message.data.jobs)\n return\n }\n if (\n (message.event === 'job' || message.event === 'terminal')\n && !isSnapshotPayload(message.data)\n ) {\n upsertLegacyJob(message.data)\n }\n }\n\n async function refresh(): Promise<boolean> {\n const currentSource = source.value\n const listJobs = currentSource?.refreshJobs ?? adapter.value?.listJobs\n if (!listJobs) return false\n const generation = ++requestGeneration\n const revision = stateRevision\n isLoading.value = true\n error.value = null\n try {\n const response = await listJobs()\n if (!active || generation !== requestGeneration || revision !== stateRevision) {\n return false\n }\n if (!currentSource && response) replaceLegacyJobs(responseJobs(response))\n return true\n } catch (cause) {\n if (active && generation === requestGeneration) {\n error.value = errorMessage(cause, 'Failed to load jobs')\n }\n return false\n } finally {\n if (active && generation === requestGeneration) isLoading.value = false\n }\n }\n\n async function cancelJob(job: JobState): Promise<boolean> {\n const sourceCancel = source.value?.cancelJob\n const adapterCancel = adapter.value?.cancelJob\n if (!job.can_cancel || (!sourceCancel && !adapterCancel) || pendingJobIds.value.has(job.job_id)) {\n return false\n }\n const revision = jobRevisions.get(job.job_id) ?? 0\n setPending(job.job_id, true)\n error.value = null\n try {\n const updated = sourceCancel\n ? await sourceCancel(job.job_id)\n : await adapterCancel!(job)\n if (!active) return false\n if (!sourceCancel && revision === (jobRevisions.get(job.job_id) ?? 0)) {\n if (updated) upsertLegacyJob(updated)\n else await refresh()\n }\n return true\n } catch (cause) {\n if (active) error.value = errorMessage(cause, 'Failed to cancel job')\n return false\n } finally {\n if (active) setPending(job.job_id, false)\n }\n }\n\n async function deleteJob(job: JobState): Promise<boolean> {\n const sourceDelete = source.value?.deleteJob\n const adapterDelete = adapter.value?.deleteJob\n if (!job.can_delete || (!sourceDelete && !adapterDelete) || pendingJobIds.value.has(job.job_id)) {\n return false\n }\n setPending(job.job_id, true)\n error.value = null\n try {\n const deleted = sourceDelete\n ? await sourceDelete(job.job_id)\n : await adapterDelete!(job)\n if (!active) return false\n if (!sourceDelete) {\n if (deleted === false) await refresh()\n else removeLegacyJobs(new Set([job.job_id]))\n }\n return deleted !== false\n } catch (cause) {\n if (active) error.value = errorMessage(cause, 'Failed to delete job')\n return false\n } finally {\n if (active) setPending(job.job_id, false)\n }\n }\n\n async function clearFinished(): Promise<boolean> {\n const targets = deletableJobs.value\n if (targets.length === 0) return false\n error.value = null\n try {\n const currentSource = source.value\n if (currentSource?.clearFinishedJobs) {\n const deleted = await currentSource.clearFinishedJobs()\n if (!active) return false\n return typeof deleted !== 'number' || deleted === targets.length\n }\n if (currentSource?.deleteJob) {\n const results = await Promise.all(targets.map(job => deleteJob(job)))\n return results.every(Boolean)\n }\n const currentAdapter = adapter.value\n if (currentAdapter?.clearFinishedJobs) {\n const deleted = await currentAdapter.clearFinishedJobs(targets)\n if (!active) return false\n if (typeof deleted === 'number' && deleted !== targets.length) {\n await refresh()\n return false\n }\n removeLegacyJobs(new Set(targets.map(job => job.job_id)))\n return true\n }\n if (!currentAdapter?.deleteJob) return false\n const results = await Promise.all(targets.map(job => deleteJob(job)))\n return results.every(Boolean)\n } catch (cause) {\n if (active) error.value = errorMessage(cause, 'Failed to clear jobs')\n return false\n }\n }\n\n if (options.eventStream !== undefined) {\n watch(\n () => toValue(options.eventStream)?.lastMessage.value ?? null,\n (message: PluginEventStreamMessage<JobStreamData> | null) => {\n if (message) applyStreamMessage(message)\n },\n { immediate: true },\n )\n }\n\n onMounted(() => {\n if (options.loadOnMount !== false) void refresh()\n })\n onUnmounted(() => {\n active = false\n requestGeneration += 1\n })\n\n return {\n jobs,\n activeJobs,\n historyJobs,\n deletableJobs,\n featuredJob,\n canRefresh,\n canCancel,\n canDelete,\n canClearFinished,\n isOpen,\n activeTab,\n isLoading,\n error,\n pendingJobIds,\n open: () => { isOpen.value = true },\n close: () => { isOpen.value = false },\n toggle: () => { isOpen.value = !isOpen.value },\n refresh,\n applyStreamMessage,\n cancelJob,\n deleteJob,\n clearFinished,\n isPending: job => pendingJobIds.value.has(job.job_id),\n }\n}\n\n/** @deprecated Removed in MINT 1.4; use `usePluginJobCenter()` for the plugin job-center controller. */\nexport function useJobsStatusTray(\n options: UseJobsStatusTrayOptions = {},\n): UseJobsStatusTrayReturn {\n return usePluginJobCenter(options)\n}\n","import {\n useConcentrationUnits,\n type ConcentrationValue,\n type MolarityUnit,\n type MassVolumeUnit,\n} from './useConcentrationUnits'\n\n// Volume units\nexport type VolumeUnit = 'µL' | 'mL' | 'L'\n\nexport interface VolumeValue {\n value: number\n unit: VolumeUnit\n}\n\n// Dilution calculation types\nexport interface DilutionParams {\n stockConcentration: ConcentrationValue\n finalConcentration: ConcentrationValue\n finalVolume: VolumeValue\n}\n\nexport interface DilutionResult {\n stockVolume: VolumeValue\n diluentVolume: VolumeValue\n dilutionFactor: number\n valid: boolean\n error?: string\n}\n\n// Serial dilution types\nexport interface SerialDilutionParams {\n startingConcentration: ConcentrationValue\n dilutionFactor: number\n numberOfDilutions: number\n volumePerWell: VolumeValue\n}\n\nexport interface SerialDilutionStep {\n stepNumber: number\n concentration: ConcentrationValue\n transferVolume: VolumeValue\n diluentVolume: VolumeValue\n}\n\nexport interface SerialDilutionResult {\n steps: SerialDilutionStep[]\n totalStockVolume: VolumeValue\n valid: boolean\n error?: string\n}\n\n// Conversion types\nexport interface ConversionResult {\n result: ConcentrationValue\n valid: boolean\n error?: string\n}\n\n// Well concentration for plate integration\nexport interface WellConcentration {\n wellId: string\n concentration: ConcentrationValue\n volume?: VolumeValue\n}\n\nexport interface UseDoseCalculatorReturn {\n volumeUnits: VolumeUnit[]\n calculateDilution: (params: DilutionParams) => DilutionResult\n calculateSerialDilution: (params: SerialDilutionParams) => SerialDilutionResult\n convertMassToMolar: (\n mass: number,\n massUnit: MassVolumeUnit,\n mw: number\n ) => ConcentrationValue\n convertMolarToMass: (\n molar: number,\n molarUnit: MolarityUnit,\n mw: number\n ) => ConcentrationValue\n convertVolume: (value: number, from: VolumeUnit, to: VolumeUnit) => number\n formatVolume: (volume: VolumeValue, precision?: number) => string\n generateWellConcentrations: (\n result: SerialDilutionResult,\n wellIds: string[]\n ) => WellConcentration[]\n}\n\nconst VOLUME_UNITS: VolumeUnit[] = ['µL', 'mL', 'L']\n\nconst VOLUME_FACTORS: Record<VolumeUnit, number> = {\n 'µL': 1e-6,\n 'mL': 1e-3,\n 'L': 1,\n}\n\n/** Calculates single dilutions, serial dilution series, and plate-filling volumes for dose-response experiments. */\nexport function useDoseCalculator(): UseDoseCalculatorReturn {\n const { convert } = useConcentrationUnits()\n\n function convertVolume(value: number, from: VolumeUnit, to: VolumeUnit): number {\n if (from === to) return value\n const baseValue = value * VOLUME_FACTORS[from]\n return baseValue / VOLUME_FACTORS[to]\n }\n\n function formatVolume(volume: VolumeValue, precision: number = 3): string {\n const { value, unit } = volume\n if (value === 0) return `0 ${unit}`\n\n let formattedValue: string\n if (Math.abs(value) >= 1000) {\n formattedValue = value.toExponential(precision - 1)\n } else if (Math.abs(value) < 0.001) {\n formattedValue = value.toExponential(precision - 1)\n } else {\n formattedValue = value.toPrecision(precision)\n }\n\n // Remove trailing zeros\n formattedValue = formattedValue.replace(/\\.?0+$/, '')\n formattedValue = formattedValue.replace(/\\.?0+e/, 'e')\n\n return `${formattedValue} ${unit}`\n }\n\n function calculateDilution(params: DilutionParams): DilutionResult {\n const { stockConcentration, finalConcentration, finalVolume } = params\n\n // Validate inputs\n if (stockConcentration.value <= 0) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Stock concentration must be positive',\n }\n }\n\n if (finalConcentration.value <= 0) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Final concentration must be positive',\n }\n }\n\n if (finalVolume.value <= 0) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Final volume must be positive',\n }\n }\n\n // Convert concentrations to same unit\n const convertedFinal = convert(\n finalConcentration.value,\n finalConcentration.unit,\n stockConcentration.unit\n )\n\n if (convertedFinal === null) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Cannot convert between concentration units. Provide molecular weight for mass↔molarity conversion.',\n }\n }\n\n // Check that stock is more concentrated than final\n if (convertedFinal >= stockConcentration.value) {\n return {\n stockVolume: { value: 0, unit: 'µL' },\n diluentVolume: { value: 0, unit: 'µL' },\n dilutionFactor: 0,\n valid: false,\n error: 'Stock concentration must be higher than final concentration',\n }\n }\n\n // Calculate using C1V1 = C2V2\n const dilutionFactor = stockConcentration.value / convertedFinal\n const finalVolumeInL = convertVolume(finalVolume.value, finalVolume.unit, 'L')\n const stockVolumeInL = finalVolumeInL / dilutionFactor\n const diluentVolumeInL = finalVolumeInL - stockVolumeInL\n\n // Convert to appropriate unit (µL for small volumes, mL for larger)\n let outputUnit: VolumeUnit = 'µL'\n if (stockVolumeInL >= 0.001) outputUnit = 'mL'\n if (stockVolumeInL >= 1) outputUnit = 'L'\n\n return {\n stockVolume: {\n value: convertVolume(stockVolumeInL, 'L', outputUnit),\n unit: outputUnit,\n },\n diluentVolume: {\n value: convertVolume(diluentVolumeInL, 'L', outputUnit),\n unit: outputUnit,\n },\n dilutionFactor,\n valid: true,\n }\n }\n\n function calculateSerialDilution(params: SerialDilutionParams): SerialDilutionResult {\n const { startingConcentration, dilutionFactor, numberOfDilutions, volumePerWell } = params\n\n // Validate inputs\n if (startingConcentration.value <= 0) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Starting concentration must be positive',\n }\n }\n\n if (dilutionFactor <= 1) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Dilution factor must be greater than 1',\n }\n }\n\n if (numberOfDilutions < 1) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Number of dilutions must be at least 1',\n }\n }\n\n if (volumePerWell.value <= 0) {\n return {\n steps: [],\n totalStockVolume: { value: 0, unit: 'µL' },\n valid: false,\n error: 'Volume per well must be positive',\n }\n }\n\n const steps: SerialDilutionStep[] = []\n let currentConcentration = startingConcentration.value\n const transferVolume = volumePerWell.value / (dilutionFactor - 1)\n const diluentVolume = volumePerWell.value - transferVolume\n\n for (let i = 0; i < numberOfDilutions; i++) {\n steps.push({\n stepNumber: i + 1,\n concentration: {\n value: currentConcentration,\n unit: startingConcentration.unit,\n },\n transferVolume: {\n value: i === 0 ? volumePerWell.value : transferVolume,\n unit: volumePerWell.unit,\n },\n diluentVolume: {\n value: i === 0 ? 0 : diluentVolume,\n unit: volumePerWell.unit,\n },\n })\n currentConcentration /= dilutionFactor\n }\n\n // Total stock needed for first well\n const totalStockVolume: VolumeValue = {\n value: volumePerWell.value + (transferVolume * (numberOfDilutions - 1)),\n unit: volumePerWell.unit,\n }\n\n return {\n steps,\n totalStockVolume,\n valid: true,\n }\n }\n\n function convertMassToMolar(\n mass: number,\n massUnit: MassVolumeUnit,\n mw: number\n ): ConcentrationValue {\n // Convert mass to g/mL, then to M using MW\n const converted = convert(mass, massUnit, 'µM', mw)\n if (converted !== null) {\n return { value: converted, unit: 'µM' }\n }\n // Fallback to manual calculation\n // mass (g/mL) / MW (g/mol) = mol/L = M\n const massInGML = mass * getMassVolumeFactor(massUnit)\n const molarConc = massInGML / mw\n return { value: molarConc * 1e6, unit: 'µM' }\n }\n\n function convertMolarToMass(\n molar: number,\n molarUnit: MolarityUnit,\n mw: number\n ): ConcentrationValue {\n // Convert M to mass using MW\n const converted = convert(molar, molarUnit, 'µg/mL', mw)\n if (converted !== null) {\n return { value: converted, unit: 'µg/mL' }\n }\n // Fallback to manual calculation\n // mol/L * MW (g/mol) = g/L = mg/mL\n const molarInM = molar * getMolarityFactor(molarUnit)\n const massConc = molarInM * mw * 1e6 // µg/mL\n return { value: massConc, unit: 'µg/mL' }\n }\n\n function getMassVolumeFactor(unit: MassVolumeUnit): number {\n const factors: Record<MassVolumeUnit, number> = {\n 'pg/mL': 1e-12,\n 'ng/mL': 1e-9,\n 'µg/mL': 1e-6,\n 'mg/mL': 1e-3,\n 'g/mL': 1,\n }\n return factors[unit]\n }\n\n function getMolarityFactor(unit: MolarityUnit): number {\n const factors: Record<MolarityUnit, number> = {\n 'pM': 1e-12,\n 'nM': 1e-9,\n 'µM': 1e-6,\n 'mM': 1e-3,\n 'M': 1,\n }\n return factors[unit]\n }\n\n function generateWellConcentrations(\n result: SerialDilutionResult,\n wellIds: string[]\n ): WellConcentration[] {\n if (!result.valid || result.steps.length === 0) return []\n\n return result.steps.slice(0, wellIds.length).map((step, index) => ({\n wellId: wellIds[index],\n concentration: step.concentration,\n volume: step.transferVolume,\n }))\n }\n\n return {\n volumeUnits: VOLUME_UNITS,\n calculateDilution,\n calculateSerialDilution,\n convertMassToMolar,\n convertMolarToMass,\n convertVolume,\n formatVolume,\n generateWellConcentrations,\n }\n}\n","import { nextTick, ref, type Ref } from 'vue'\n\n/** Inline style for a visually hidden `aria-live` region (no global utility class in the SDK). */\nexport const REORDER_ANNOUNCER_STYLE = Object.freeze({\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: '0',\n})\n\nexport interface UseReorderAnnouncerReturn {\n /** Bind to a polite live region's text content. */\n announcement: Ref<string>\n /** Publishes a message to the live region. */\n announce: (message: string) => void\n /** Bind to the live region's `style` so it stays visually hidden. */\n announcerStyle: typeof REORDER_ANNOUNCER_STYLE\n}\n\n/**\n * Screen-reader announcements for drag/keyboard move interactions. Bind\n * `announcement` to a `role=\"status\" aria-live=\"polite\"` element styled with\n * `announcerStyle`.\n */\nexport function useReorderAnnouncer(): UseReorderAnnouncerReturn {\n const announcement = ref('')\n\n function announce(message: string) {\n // Re-announce identical consecutive messages by clearing first.\n if (announcement.value === message) announcement.value = ''\n void nextTick(() => {\n announcement.value = message\n })\n }\n\n return { announcement, announce, announcerStyle: REORDER_ANNOUNCER_STYLE }\n}\n\nexport interface ListReorderMove<T> {\n /** Index the item moved from, within `items()`. */\n fromIndex: number\n /** Index the item moved to, within `items()`. */\n toIndex: number\n /** The reordered array (a copy — `items()` is never mutated). */\n items: T[]\n /** Whether the move came from the keyboard or a pointer drag. */\n source: 'keyboard' | 'drag'\n}\n\nexport interface UseListReorderOptions<T> {\n /** The list being reordered, in its canonical (not merely rendered) order. */\n items: () => T[]\n /** Stable id for an item; falls back to the render index when ids repeat. */\n getId: (item: T, index: number) => string\n /** Applies the move. The composable never mutates the source array. */\n onReorder: (move: ListReorderMove<T>) => void\n /** Human-readable name used in announcements. Defaults to the item's id. */\n getLabel?: (item: T, index: number) => string\n /** Blocks every reorder while it returns `true` (readonly / non-sortable lists). */\n disabled?: () => boolean\n /** Resolves the focusable element for an id so keyboard moves keep focus on the item. */\n getElement?: (id: string) => HTMLElement | null | undefined\n /** Noun used in announcements, e.g. `'Reagent'`. Default `'Item'`. */\n itemNoun?: string\n}\n\nexport interface UseListReorderReturn<T> {\n /** Id of the item currently being dragged, or `null`. */\n draggingId: Ref<string | null>\n /** Id of the item the pointer is hovering as a drop target, or `null`. */\n dragOverId: Ref<string | null>\n isDragging: (id: string) => boolean\n isDragOver: (id: string) => boolean\n announcement: Ref<string>\n announcerStyle: typeof REORDER_ANNOUNCER_STYLE\n announce: (message: string) => void\n /** Bind to the draggable element's `@dragstart`. */\n onDragStart: (event: DragEvent, item: T, index: number) => void\n /** Bind to `@dragover` — calls `preventDefault()` so the drop is accepted. */\n onDragOver: (event: DragEvent, item: T, index: number) => void\n /** Bind to `@dragleave`. */\n onDragLeave: () => void\n /** Bind to `@drop`. */\n onDrop: (event: DragEvent, item: T, index: number) => void\n /** Bind to `@dragend`. */\n onDragEnd: () => void\n /**\n * Bind to the item's (or its drag handle's) `@keydown`: Alt+ArrowUp / Alt+ArrowLeft\n * moves the item one position earlier, Alt+ArrowDown / Alt+ArrowRight one later.\n */\n onKeydown: (event: KeyboardEvent, item: T, index: number) => void\n /** Moves an item between two indices of `items()` programmatically. */\n move: (fromIndex: number, toIndex: number, source?: 'keyboard' | 'drag') => void\n}\n\n/** Pure helper: a copy of `items` with the entry at `from` moved to `to`. */\nexport function reorderList<T>(items: T[], from: number, to: number): T[] {\n const next = [...items]\n const [moved] = next.splice(from, 1)\n next.splice(to, 0, moved)\n return next\n}\n\n/**\n * Keyboard-accessible list reordering shared by the SDK's drag-to-reorder lists.\n * It owns the HTML5 drag state, the drop-index maths, and an Alt+Arrow keyboard\n * alternative that announces every move through a polite live region — so a\n * reorder never depends on a pointer.\n */\nexport function useListReorder<T>(options: UseListReorderOptions<T>): UseListReorderReturn<T> {\n const draggingId = ref<string | null>(null)\n const dragOverId = ref<string | null>(null)\n const { announcement, announce, announcerStyle } = useReorderAnnouncer()\n const noun = options.itemNoun ?? 'Item'\n\n function isDisabled(): boolean {\n return options.disabled?.() === true\n }\n\n function idFor(item: T, index: number): string {\n return options.getId(item, index)\n }\n\n /** Index within `items()`, resolved by id so filtered/sorted renders still map back. */\n function indexOf(item: T, renderIndex: number): number {\n const id = idFor(item, renderIndex)\n const found = options.items().findIndex((candidate, index) => idFor(candidate, index) === id)\n return found === -1 ? renderIndex : found\n }\n\n function labelFor(index: number): string {\n const item = options.items()[index]\n if (item === undefined) return noun\n return options.getLabel?.(item, index) ?? idFor(item, index)\n }\n\n function clearDragState() {\n draggingId.value = null\n dragOverId.value = null\n }\n\n function move(fromIndex: number, toIndex: number, source: 'keyboard' | 'drag' = 'keyboard') {\n if (isDisabled()) return\n const items = options.items()\n if (\n fromIndex === toIndex ||\n fromIndex < 0 ||\n toIndex < 0 ||\n fromIndex >= items.length ||\n toIndex >= items.length\n ) return\n\n const movedId = idFor(items[fromIndex], fromIndex)\n const label = labelFor(fromIndex)\n options.onReorder({\n fromIndex,\n toIndex,\n items: reorderList(items, fromIndex, toIndex),\n source,\n })\n announce(`${label} moved to position ${toIndex + 1} of ${items.length}.`)\n void nextTick(() => options.getElement?.(movedId)?.focus())\n }\n\n function onDragStart(event: DragEvent, item: T, index: number) {\n if (isDisabled()) return\n const id = idFor(item, index)\n draggingId.value = id\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', id)\n }\n }\n\n function onDragOver(event: DragEvent, item: T, index: number) {\n if (isDisabled() || draggingId.value === null) return\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n const id = idFor(item, index)\n dragOverId.value = id === draggingId.value ? null : id\n }\n\n function onDragLeave() {\n dragOverId.value = null\n }\n\n function onDrop(event: DragEvent, item: T, index: number) {\n if (isDisabled() || draggingId.value === null) {\n clearDragState()\n return\n }\n event.preventDefault()\n\n const items = options.items()\n const fromIndex = items.findIndex((candidate, i) => idFor(candidate, i) === draggingId.value)\n const toIndex = indexOf(item, index)\n clearDragState()\n if (fromIndex === -1) return\n move(fromIndex, toIndex, 'drag')\n }\n\n function onDragEnd() {\n clearDragState()\n }\n\n function onKeydown(event: KeyboardEvent, item: T, index: number) {\n if (isDisabled() || !event.altKey) return\n const direction =\n event.key === 'ArrowUp' || event.key === 'ArrowLeft'\n ? -1\n : event.key === 'ArrowDown' || event.key === 'ArrowRight'\n ? 1\n : 0\n if (direction === 0) return\n\n event.preventDefault()\n const fromIndex = indexOf(item, index)\n move(fromIndex, fromIndex + direction, 'keyboard')\n }\n\n return {\n draggingId,\n dragOverId,\n isDragging: (id: string) => draggingId.value === id,\n isDragOver: (id: string) => dragOverId.value === id,\n announcement,\n announcerStyle,\n announce,\n onDragStart,\n onDragOver,\n onDragLeave,\n onDrop,\n onDragEnd,\n onKeydown,\n move,\n }\n}\n","import { ref, computed, watch, type Ref, type ComputedRef } from 'vue'\nimport type { Rack, SlotPosition, WellEditData, WellPlateFormat, WellSampleDropData, Well } from '../types'\nimport { PLATE_CONFIGS, rowIndex, rowLabel as plateRowLabel } from '../components/WellPlate.geometry'\n\nexport interface UseRackEditorOptions {\n defaultFormat?: WellPlateFormat\n defaultInjectionVolume?: number\n maxRacks?: number\n minRacks?: number\n}\n\nexport interface UseRackEditorReturn {\n racks: Ref<Rack[]>\n activeRack: ComputedRef<Rack | undefined>\n activeRackId: Ref<string>\n\n addRack(name?: string): Rack\n removeRack(rackId: string): void\n reorderRacks(fromIndex: number, toIndex: number): void\n updateRack(rackId: string, data: Partial<Rack>): void\n setActiveRack(rackId: string): void\n\n setWellData(rackId: string, wellId: string, data: Partial<Well>): void\n clearWell(rackId: string, wellId: string): void\n clearAllWells(rackId: string): void\n fillSeries(rackId: string, prefix?: string): void\n /** Swaps two wells (a move when the target is empty). */\n moveWell(rackId: string, sourceWellId: string, targetWellId: string): void\n /** Puts every well in group `groupId` (an empty well becomes a sample); `undefined` empties them. */\n assignWells(rackId: string, wellIds: string[], groupId: string | undefined): void\n\n /**\n * Applies every PlateEditor intent to this state, so the component can hold\n * data it never mutates itself:\n * `<PlateEditor :model-value=\"racks\" :active-rack-id=\"activeRackId\" v-on=\"plateEditorListeners\" />`\n */\n plateEditorListeners: PlateEditorListeners\n\n /** Steps back through every change to `racks` (at most 50), restoring the plate that was showing. */\n undo(): void\n redo(): void\n canUndo: ComputedRef<boolean>\n canRedo: ComputedRef<boolean>\n /** Forgets every undo and redo step, e.g. after loading unrelated plates. */\n clearHistory(): void\n\n getAllWells(): Array<{ rackId: string; wellId: string; well: Partial<Well> }>\n totalSampleCount: ComputedRef<number>\n reset(): void\n}\n\n/** Handlers for PlateEditor's intent events, keyed by event name (bind with `v-on`). */\nexport interface PlateEditorListeners {\n 'update:activeRackId': (rackId: string) => void\n 'rack-add': () => void\n 'rack-remove': (rackId: string) => void\n 'rack-reorder': (rackIds: string[]) => void\n 'update:format': (rackId: string, format: WellPlateFormat) => void\n 'update:slot': (rackId: string, slot: SlotPosition) => void\n 'well-edit': (rackId: string, wellId: string, data: WellEditData) => void\n 'well-clear': (rackId: string, wellId: string) => void\n 'well-move': (rackId: string, sourceWellId: string, targetWellId: string) => void\n 'sample-drop': (rackId: string, wellId: string, data: WellSampleDropData, event: DragEvent) => void\n 'assign': (rackId: string, wellIds: string[], groupId: string | undefined) => void\n 'clear': (rackId: string) => void\n 'fill-series': (rackId: string) => void\n 'undo': () => void\n 'redo': () => void\n}\n\nconst HISTORY_LIMIT = 50\n\nconst SLOT_CYCLE: SlotPosition[] = ['R', 'G', 'B', 'Y']\n\nfunction wellFromEditData(data: WellEditData): Partial<Well> {\n return {\n state: 'filled',\n sampleType: data.sampleType || undefined,\n metadata: {\n label: data.label,\n injectionVolume: data.injectionVolume,\n injectionCount: data.injectionCount,\n customMethod: data.customMethod || null,\n },\n }\n}\n\nfunction wellFromDrop(data: WellSampleDropData, rack: Rack): Partial<Well> | null {\n const label = (data.label ?? data.sampleName ?? data.id ?? '').trim()\n if (!label) return null\n return {\n state: 'filled',\n sampleType: data.sampleType ?? 'sample',\n metadata: {\n label,\n injectionVolume: data.injectionVolume ?? rack.injectionVolume,\n injectionCount: data.injectionCount ?? 1,\n customMethod: data.customMethod ?? null,\n },\n }\n}\n\n\nlet globalIdCounter = 0\n\nfunction generateId(): string {\n globalIdCounter++\n return `rack-${Date.now()}-${globalIdCounter}`\n}\n\n/** Manages a set of sample racks with well-level assignment, series fill, and multi-rack reordering. */\nexport function useRackEditor(\n initialRacks?: Rack[],\n options?: UseRackEditorOptions,\n): UseRackEditorReturn {\n const defaultFormat = options?.defaultFormat ?? 54\n const defaultInjVol = options?.defaultInjectionVolume ?? 5\n const maxRacks = options?.maxRacks ?? 10\n const minRacks = options?.minRacks ?? 1\n\n function createDefaultRack(name?: string, slotIndex?: number): Rack {\n const slot = SLOT_CYCLE[(slotIndex ?? 0) % SLOT_CYCLE.length]!\n return {\n id: generateId(),\n name: name ?? `Rack ${racks.value.length + 1}`,\n format: defaultFormat,\n slot,\n injectionVolume: defaultInjVol,\n wells: {},\n }\n }\n\n const racks = ref<Rack[]>(\n initialRacks && initialRacks.length > 0\n ? initialRacks.map(r => ({ ...r, wells: { ...r.wells } }))\n : [createDefaultRack('Rack 1', 0)]\n ) as Ref<Rack[]>\n\n const activeRackId = ref<string>(racks.value[0]?.id ?? '')\n\n const activeRack = computed(() =>\n racks.value.find(r => r.id === activeRackId.value) ?? racks.value[0]\n )\n\n function addRack(name?: string): Rack {\n if (racks.value.length >= maxRacks) {\n return racks.value[racks.value.length - 1]!\n }\n const rack = createDefaultRack(name, racks.value.length)\n racks.value.push(rack)\n activeRackId.value = rack.id\n return rack\n }\n\n function removeRack(rackId: string): void {\n if (racks.value.length <= minRacks) return\n const index = racks.value.findIndex(r => r.id === rackId)\n if (index === -1) return\n racks.value.splice(index, 1)\n if (activeRackId.value === rackId && racks.value[0]) {\n activeRackId.value = racks.value[0].id\n }\n }\n\n function reorderRacks(fromIndex: number, toIndex: number): void {\n if (fromIndex < 0 || fromIndex >= racks.value.length) return\n if (toIndex < 0 || toIndex >= racks.value.length) return\n if (fromIndex === toIndex) return\n const [moved] = racks.value.splice(fromIndex, 1)\n if (moved) {\n racks.value.splice(toIndex, 0, moved)\n }\n }\n\n function updateRack(rackId: string, data: Partial<Rack>): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n if (data.name !== undefined) rack.name = data.name\n if (data.format !== undefined) rack.format = data.format\n if (data.slot !== undefined) rack.slot = data.slot\n if (data.injectionVolume !== undefined) rack.injectionVolume = data.injectionVolume\n if (data.wells !== undefined) rack.wells = data.wells\n }\n\n function setActiveRack(rackId: string): void {\n if (racks.value.some(r => r.id === rackId)) {\n activeRackId.value = rackId\n }\n }\n\n function setWellData(rackId: string, wellId: string, data: Partial<Well>): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n rack.wells[wellId] = { ...rack.wells[wellId], ...data }\n }\n\n function clearWell(rackId: string, wellId: string): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n delete rack.wells[wellId]\n }\n\n function clearAllWells(rackId: string): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n rack.wells = {}\n }\n\n function fillSeries(rackId: string, prefix: string = 'S'): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n\n const config = PLATE_CONFIGS[rack.format]\n if (!config) return\n\n let counter = 1\n for (let row = 0; row < config.rows; row++) {\n for (let col = 0; col < config.cols; col++) {\n const wellId = `${plateRowLabel(row)}${col + 1}`\n // Only fill empty wells\n if (!rack.wells[wellId]?.sampleType) {\n const paddedNum = String(counter).padStart(3, '0')\n rack.wells[wellId] = {\n id: wellId,\n row,\n col,\n state: 'filled',\n sampleType: 'sample',\n metadata: {\n label: `${prefix}${paddedNum}`,\n injectionVolume: rack.injectionVolume,\n injectionCount: 1,\n },\n }\n }\n counter++\n }\n }\n }\n\n function moveWell(rackId: string, sourceWellId: string, targetWellId: string): void {\n const rack = racks.value.find(r => r.id === rackId)\n if (!rack) return\n const { [sourceWellId]: source, [targetWellId]: target } = rack.wells\n delete rack.wells[sourceWellId]\n delete rack.wells[targetWellId]\n if (target) rack.wells[sourceWellId] = placed(target, sourceWellId)\n if (source) rack.wells[targetWellId] = placed(source, targetWellId)\n }\n\n /** A moved well keeps its position fields in step with its new key. */\n function placed(well: Partial<Well>, wellId: string): Partial<Well> {\n if (well.id === undefined) return well\n const [, row = '', col = ''] = /^([A-Z]+)(\\d+)$/.exec(wellId) ?? []\n return { ...well, id: wellId, row: rowIndex(row), col: Number(col) - 1 }\n }\n\n function assignWells(rackId: string, wellIds: string[], groupId: string | undefined): void {\n const rack = racks.value.find(r => r.id === rackId)\n for (const wellId of wellIds) {\n const sampleType = rack?.wells[wellId]?.sampleType ?? 'sample'\n if (groupId) setWellData(rackId, wellId, { state: 'filled', sampleType, group: groupId })\n else clearWell(rackId, wellId)\n }\n }\n\n // History: the serialized racks before each change, with the plate that was showing.\n // Every change counts, not just the intents: each public mutator call is its own step,\n // and a change made outside them (an import assigning `racks`) becomes one at the next\n // tick, so undo never skips past it.\n interface Snapshot { racks: string; activeRackId: string }\n const undoStack = ref<Snapshot[]>([])\n const redoStack = ref<Snapshot[]>([])\n const canUndo = computed(() => undoStack.value.length > 0)\n const canRedo = computed(() => redoStack.value.length > 0)\n /** The racks as the history last saw them. */\n let known = JSON.stringify(racks.value)\n\n function pushUndo(snapshot: Snapshot): void {\n undoStack.value = [...undoStack.value, snapshot].slice(-HISTORY_LIMIT)\n redoStack.value = []\n }\n\n /** Records a change made since the history last looked, as its own step. */\n function absorb(): void {\n const now = JSON.stringify(racks.value)\n if (now === known) return\n pushUndo({ racks: known, activeRackId: activeRackId.value })\n known = now\n }\n watch(racks, absorb, { deep: true })\n\n function step(from: Ref<Snapshot[]>, to: Ref<Snapshot[]>): void {\n absorb()\n const snapshot = from.value.pop()\n if (snapshot === undefined) return\n to.value.push({ racks: known, activeRackId: activeRackId.value })\n racks.value = JSON.parse(snapshot.racks) as Rack[]\n known = snapshot.racks\n activeRackId.value = racks.value.some(rack => rack.id === snapshot.activeRackId)\n ? snapshot.activeRackId\n : racks.value[0]?.id ?? ''\n }\n\n const undo = (): void => step(undoStack, redoStack)\n const redo = (): void => step(redoStack, undoStack)\n\n function clearHistory(): void {\n undoStack.value = []\n redoStack.value = []\n known = JSON.stringify(racks.value)\n }\n\n /** Runs `apply` and records the prior state when it changed anything. */\n function recorded<Args extends unknown[], Result>(apply: (...args: Args) => Result) {\n return (...args: Args): Result => {\n absorb()\n const before = { racks: known, activeRackId: activeRackId.value }\n const result = apply(...args)\n const after = JSON.stringify(racks.value)\n if (after !== known) {\n pushUndo(before)\n known = after\n }\n return result\n }\n }\n\n const plateEditorListeners: PlateEditorListeners = {\n 'update:activeRackId': setActiveRack,\n 'rack-add': recorded(() => { addRack() }),\n 'rack-remove': recorded(removeRack),\n 'rack-reorder': recorded((rackIds: string[]) => {\n racks.value = rackIds.flatMap(id => racks.value.filter(rack => rack.id === id))\n }),\n 'update:format': recorded((rackId: string, format: WellPlateFormat) => updateRack(rackId, { format })),\n 'update:slot': recorded((rackId: string, slot: SlotPosition) => updateRack(rackId, { slot })),\n 'well-edit': recorded((rackId: string, wellId: string, data: WellEditData) => setWellData(rackId, wellId, wellFromEditData(data))),\n 'well-clear': recorded(clearWell),\n 'well-move': recorded(moveWell),\n 'sample-drop': recorded((rackId: string, wellId: string, data: WellSampleDropData) => {\n const rack = racks.value.find(r => r.id === rackId)\n const well = rack && wellFromDrop(data, rack)\n if (well) setWellData(rackId, wellId, well)\n }),\n 'assign': recorded(assignWells),\n 'clear': recorded(clearAllWells),\n 'fill-series': recorded((rackId: string) => fillSeries(rackId)),\n 'undo': undo,\n 'redo': redo,\n }\n\n function getAllWells(): Array<{ rackId: string; wellId: string; well: Partial<Well> }> {\n const result: Array<{ rackId: string; wellId: string; well: Partial<Well> }> = []\n for (const rack of racks.value) {\n for (const [wellId, well] of Object.entries(rack.wells)) {\n result.push({ rackId: rack.id, wellId, well })\n }\n }\n return result\n }\n\n const totalSampleCount = computed(() => {\n let count = 0\n for (const rack of racks.value) {\n count += Object.keys(rack.wells).length\n }\n return count\n })\n\n function reset(): void {\n const rack = createDefaultRack('Rack 1', 0)\n racks.value = [rack]\n activeRackId.value = rack.id\n clearHistory()\n }\n\n return {\n racks,\n activeRack,\n activeRackId,\n // Wrapped here, not at the definitions, so assignWells' inner calls stay one step.\n addRack: recorded(addRack),\n removeRack: recorded(removeRack),\n reorderRacks: recorded(reorderRacks),\n updateRack: recorded(updateRack),\n setActiveRack,\n setWellData: recorded(setWellData),\n clearWell: recorded(clearWell),\n clearAllWells: recorded(clearAllWells),\n fillSeries: recorded(fillSeries),\n moveWell: recorded(moveWell),\n assignWells: recorded(assignWells),\n plateEditorListeners,\n undo,\n redo,\n canUndo,\n canRedo,\n clearHistory,\n getAllWells,\n totalSampleCount,\n reset,\n }\n}\n","import type { SampleClass } from '../../types/auto-group'\n\nexport function classKey(\n c: Pick<SampleClass, 'kind'> & { subKind?: string; tokenLength?: number },\n): string {\n const base = c.subKind ? `${c.kind}:${c.subKind}` : c.kind\n return c.tokenLength != null ? `${base}#${c.tokenLength}` : base\n}\n","{\n \"$schema\": \"./vocab.schema.json\",\n \"_doc\": {\n \"purpose\": \"Sample-name classification vocabulary for the auto-group pipeline. Edit this file to teach the classifier new sample types or matrices without changing TypeScript. All matching is case-insensitive unless a pattern's regex flags say otherwise.\",\n \"patterns\": \"Regex source strings (no surrounding slashes). Compiled with the `i` flag at load time.\",\n \"standardAllow\": \"Tokens that should be classified as Standard even when they don't match `patterns.standard`. Case-sensitive — use the exact spelling that appears in your filenames.\",\n \"matrixVocab\": \"Lowercase token → canonical display name. Tokens are normalised to lowercase before lookup, so adding 'tissues' handles 'Tissues' / 'TISSUES' / 'tissues' uniformly. Multiple aliases map to one canonical (e.g. cell + cells → Cells).\",\n \"ionizationModes\": \"Lowercase polarity tokens (pos / positive / neg / negative). Suffixed to the subKind so POS and NEG acquisitions get independent schemas.\",\n \"tissueParentTokens\": \"Tokens that flag the immediately-following token as the organ subKind (so `tissues / kidney` becomes Biological/Tissues, tagging both positions).\",\n \"replicateToken\": \"Regex source for a token that names a replicate: rep1, Rep2, replicate3, R1, T1 (technical replicate). A column whose values all match is a replicate column: it stays a visible field and is left out of the default group key. B<n> is not in the pattern: on the lab share B13 / S13 are label tokens.\"\n },\n\n \"patterns\": {\n \"blank\": \"^(blank|blk|solv?blank|matrix.?blank)$\",\n \"iqc\": \"^(iqc|qc|pqc|pooled.?qc)$\",\n \"eqc\": \"^eqc$\",\n \"standard\": \"^(standards?|stds?\\\\d*|istd|cal(?:ibrator)?\\\\d*|.+standard)$\",\n \"spikeIn\": \"spike.?in\",\n \"stock\": \"^stock$\"\n },\n\n \"standardAllow\": [\n \"ExtractionS\",\n \"IS\",\n \"internal.standard\"\n ],\n\n \"matrixVocab\": {\n \"plasma\": \"Plasma\",\n \"serum\": \"Serum\",\n \"tissue\": \"Tissue\",\n \"tissues\": \"Tissues\",\n \"kidney\": \"Kidney\",\n \"liver\": \"Liver\",\n \"tumor\": \"Tumor\",\n \"urine\": \"Urine\",\n \"brain\": \"Brain\",\n \"muscle\": \"Muscle\",\n \"adipose\": \"Adipose\",\n \"csf\": \"CSF\",\n \"feces\": \"Feces\",\n \"faeces\": \"Faeces\",\n \"cells\": \"Cells\",\n \"cell\": \"Cells\",\n \"media\": \"Media\",\n \"medium\": \"Medium\",\n \"extract\": \"Extract\"\n },\n\n \"ionizationModes\": {\n \"pos\": \"POS\",\n \"positive\": \"POS\",\n \"neg\": \"NEG\",\n \"negative\": \"NEG\"\n },\n\n \"tissueParentTokens\": [\"tissue\", \"tissues\"],\n\n \"replicateToken\": \"^(?:rep(?:licate)?|r|t)\\\\d+$\"\n}\n","import type { SampleClass, SampleClassKind, ClassDisposition } from '../../types/auto-group'\nimport { classKey } from './classKey'\nimport vocabData from './vocab.json'\n\nexport interface ClassVocab {\n blankPattern: RegExp\n iqcPattern: RegExp\n eqcPattern: RegExp\n standardPattern: RegExp\n standardAllow: Set<string>\n spikeInPattern: RegExp\n stockPattern: RegExp\n /**\n * Matrix lookup: lowercase token → canonical display name. Matching is\n * case-insensitive, and several aliases can collapse to one display name\n * (cell → Cells, medium → Medium).\n */\n matrixVocab: Map<string, string>\n /** Lowercase polarity tokens → POS / NEG. */\n ionizationModes: Map<string, 'POS' | 'NEG'>\n /** Lowercase tokens that flag the next token as the organ subKind. */\n tissueParentTokens: Set<string>\n}\n\ntype VocabFile = typeof vocabData\ntype IonMode = 'POS' | 'NEG'\n\nfunction compileVocab(data: VocabFile): ClassVocab {\n return {\n blankPattern: new RegExp(data.patterns.blank, 'i'),\n iqcPattern: new RegExp(data.patterns.iqc, 'i'),\n eqcPattern: new RegExp(data.patterns.eqc, 'i'),\n standardPattern: new RegExp(data.patterns.standard, 'i'),\n spikeInPattern: new RegExp(data.patterns.spikeIn, 'i'),\n stockPattern: new RegExp(data.patterns.stock, 'i'),\n standardAllow: new Set(data.standardAllow),\n matrixVocab: new Map(Object.entries(data.matrixVocab)),\n ionizationModes: new Map(\n Object.entries(data.ionizationModes).map(([k, v]) => [k, v as IonMode]),\n ),\n tissueParentTokens: new Set(data.tissueParentTokens),\n }\n}\n\nexport const classVocab: ClassVocab = compileVocab(vocabData)\n\nfunction matrixCanonical(token: string, vocab: ClassVocab): string | undefined {\n return vocab.matrixVocab.get(token.toLowerCase())\n}\n\nfunction isTissueParentToken(token: string, vocab: ClassVocab): boolean {\n return vocab.tissueParentTokens.has(token.toLowerCase())\n}\n\nexport interface DetectClassOptions {\n vocab?: Partial<ClassVocab>\n /** Per-sample explicit `sample_type` hint (e.g. from experiment design data). */\n sampleTypeHints?: (string | undefined)[]\n /** Number of leading tokens that all samples share (`TokenizedBatch.sharedPrefix`). */\n sharedPrefix?: number\n}\n\n/** A token that names a QC-type class (blank, QC, standard, spike-in, stock). */\nexport function isClassMarker(token: string, vocab: ClassVocab = classVocab): boolean {\n return (\n vocab.blankPattern.test(token) || vocab.iqcPattern.test(token) || vocab.eqcPattern.test(token)\n || vocab.standardPattern.test(token) || vocab.standardAllow.has(token)\n || vocab.spikeInPattern.test(token) || vocab.stockPattern.test(token)\n )\n}\n\n/** Kinds that form experimental groups; all other kinds are QC-type overlay classes. */\nexport function isExperimentalKind(kind: SampleClassKind): boolean {\n return kind === 'biological' || kind === 'unknown'\n}\n\nconst DEFAULT_DISPOSITION: Record<SampleClassKind, ClassDisposition> = {\n biological: 'group',\n iqc: 'overlay',\n eqc: 'overlay',\n standard: 'overlay',\n 'spike-in': 'overlay',\n stock: 'overlay',\n blank: 'overlay',\n unknown: 'group',\n}\n\nfunction classifyTokens(\n tokens: string[],\n vocab: ClassVocab,\n qcFrom: number,\n): { kind: SampleClassKind; subKind?: string; tagPositions: number[] } {\n // First-match-wins ordering: Blank → IQC → EQC → Standard → SpikeIn → Stock → Biological → Unknown.\n // QC kinds are read from `qcFrom`: a token that all names share (the\n // experiment title) cannot mark one sample as QC.\n for (let i = qcFrom; i < tokens.length; i++) {\n if (vocab.blankPattern.test(tokens[i])) return { kind: 'blank', tagPositions: [i] }\n }\n for (let i = qcFrom; i < tokens.length; i++) {\n if (vocab.iqcPattern.test(tokens[i])) return { kind: 'iqc', tagPositions: [i] }\n }\n for (let i = qcFrom; i < tokens.length; i++) {\n if (vocab.eqcPattern.test(tokens[i])) return { kind: 'eqc', tagPositions: [i] }\n }\n for (let i = qcFrom; i < tokens.length; i++) {\n if (vocab.standardPattern.test(tokens[i]) || vocab.standardAllow.has(tokens[i])) {\n return { kind: 'standard', tagPositions: [i] }\n }\n }\n for (let i = qcFrom; i < tokens.length; i++) {\n if (vocab.spikeInPattern.test(tokens[i])) return { kind: 'spike-in', tagPositions: [i] }\n }\n for (let i = qcFrom; i < tokens.length; i++) {\n if (vocab.stockPattern.test(tokens[i])) return { kind: 'stock', tagPositions: [i] }\n }\n for (let i = 0; i < tokens.length; i++) {\n const canonical = matrixCanonical(tokens[i], vocab)\n if (canonical) {\n const isTissueParent = isTissueParentToken(tokens[i], vocab)\n const tagPositions = [i]\n if (isTissueParent) {\n // \"Tissues\"/\"Tissue\" is the parent group; tag the next token (organ name) as well.\n if (i + 1 < tokens.length) tagPositions.push(i + 1)\n return { kind: 'biological', subKind: 'Tissues', tagPositions }\n }\n // Non-parent matrix token: tag any immediately preceding \"Tissues\"/\"Tissue\" parent.\n if (i > 0 && isTissueParentToken(tokens[i - 1], vocab)) {\n tagPositions.unshift(i - 1)\n return { kind: 'biological', subKind: 'Tissues', tagPositions }\n }\n return { kind: 'biological', subKind: canonical, tagPositions }\n }\n }\n return { kind: 'unknown', tagPositions: [] }\n}\n\n/**\n * LC-MS batches run positive- and negative-ion-mode acquisitions separately,\n * and the two produce different feature tables that should never be grouped\n * together. When a POS / NEG / positive / negative token is present we suffix\n * it to the class label so the schema builder treats each mode as its own class.\n */\nfunction ionizationModeFor(\n tokens: string[],\n vocab: ClassVocab,\n): { mode: IonMode; position: number } | undefined {\n for (let i = 0; i < tokens.length; i++) {\n const mode = vocab.ionizationModes.get(tokens[i].toLowerCase())\n if (mode) return { mode, position: i }\n }\n return undefined\n}\n\nfunction labelFor(kind: SampleClassKind, subKind?: string): string {\n const base: Record<SampleClassKind, string> = {\n biological: 'Biological',\n iqc: 'IQC',\n eqc: 'EQC',\n standard: 'Standard',\n 'spike-in': 'SpikeIn',\n stock: 'Stock',\n blank: 'Blank',\n unknown: 'Unknown',\n }\n return subKind ? `${base[kind]} / ${subKind}` : base[kind]\n}\n\n/** Classify each tokenized sample into a SampleClass. */\nexport function detectClass(\n tokenizedSamples: string[][],\n options: DetectClassOptions,\n): SampleClass[] {\n const vocab = { ...classVocab, ...(options.vocab ?? {}) }\n const hints = options.sampleTypeHints ?? []\n const buckets = new Map<string, SampleClass>()\n\n for (let i = 0; i < tokenizedSamples.length; i++) {\n const hint = hints[i]?.toLowerCase()\n let kind: SampleClassKind\n let subKind: string | undefined\n let tagPositions: number[]\n\n if (hint === 'qc') {\n kind = 'iqc'\n tagPositions = []\n } else if (hint === 'blank') {\n kind = 'blank'\n tagPositions = []\n } else {\n const r = classifyTokens(tokenizedSamples[i], vocab, options.sharedPrefix ?? 0)\n kind = r.kind\n subKind = r.subKind\n tagPositions = r.tagPositions\n }\n\n // Split classes by ionization mode (POS / NEG) so the two acquisitions get\n // independent schemas even when they share a matrix and sample-type vocab.\n const mode = ionizationModeFor(tokenizedSamples[i], vocab)\n if (mode) {\n subKind = subKind ? `${subKind} / ${mode.mode}` : mode.mode\n if (!tagPositions.includes(mode.position)) tagPositions.push(mode.position)\n }\n\n const key = classKey({ kind, subKind })\n const bucket = buckets.get(key)\n if (bucket) {\n bucket.members.push(i)\n for (const p of tagPositions) {\n if (!bucket.classTagPositions.includes(p)) bucket.classTagPositions.push(p)\n }\n } else {\n buckets.set(key, {\n kind,\n subKind,\n label: labelFor(kind, subKind),\n members: [i],\n classTagPositions: [...tagPositions],\n disposition: DEFAULT_DISPOSITION[kind],\n })\n }\n }\n\n return [...buckets.values()]\n}\n","import { isClassMarker } from './classify'\n\nconst DELIMITER_CANDIDATES = ['_', '-', ' ', '.'] as const\nexport type Delimiter = (typeof DELIMITER_CANDIDATES)[number]\n\n/** Pick the delimiter whose split produces the most consistent field count across `lines`. */\nexport function pickPrimaryDelimiter(lines: string[]): Delimiter {\n if (lines.length === 0) return '_'\n\n let best: Delimiter = '_'\n let bestScore = -1\n\n for (const candidate of DELIMITER_CANDIDATES) {\n const counts = lines.map(l => l.split(candidate).length)\n const frequency = new Map<number, number>()\n for (const c of counts) frequency.set(c, (frequency.get(c) ?? 0) + 1)\n\n // Mode and its frequency\n let mode = 1\n let modeFreq = 0\n for (const [c, f] of frequency) {\n if (f > modeFreq || (f === modeFreq && c > mode)) {\n mode = c\n modeFreq = f\n }\n }\n\n // A delimiter that produces field count 1 didn't split anything — score 0.\n const score = mode > 1 ? modeFreq / lines.length : 0\n if (score > bestScore) {\n best = candidate\n bestScore = score\n }\n }\n\n return best\n}\n\n/** Split a single sample name on `delimiter`. Empty input returns `['']` so callers\n * always receive at least one token. */\nexport function splitMulti(name: string, delimiter: Delimiter): string[] {\n return name.split(delimiter)\n}\n\n/** The `exp<NNN>_<date>_<operator>` fields at the start of a sample name. */\nexport interface ExperimentHeader {\n code?: string\n /** ISO date. Names carry it as YYMMDD, YYYYMMDD or DDMMYYYY. */\n date?: string\n operator?: string\n}\n\nexport interface TokenizedBatch {\n delimiter: Delimiter\n /** One row of tokens for each input name, in input order. */\n rows: string[][]\n /** Header fields with one value in the batch. They are not in `rows`. */\n experiment: ExperimentHeader\n /**\n * Number of leading tokens that all rows share (normally the experiment\n * title). They cannot tell a QC sample from a study sample.\n */\n sharedPrefix: number\n}\n\nconst HEADER_FIELDS = ['code', 'date', 'operator'] as const\n// Share of the names with a header that must carry the same operator before it\n// leaves the rows. The rest allows for stray names such as `exp157_test_blank_1`.\nconst OPERATOR_AGREEMENT = 0.9\n// Outside this window a 6-digit token is read day-first: `091123` is 2023-11-09, not 2009.\nconst FIRST_PLAUSIBLE_YEAR = 2015\n\nfunction isoDate(year: number, month: number, day: number): string | undefined {\n const lastYear = new Date().getFullYear() + 1\n if (year < FIRST_PLAUSIBLE_YEAR || year > lastYear) return undefined\n // `Date` rolls an impossible day over to the next month; reject that.\n const date = new Date(Date.UTC(year, month - 1, day))\n if (date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return undefined\n return date.toISOString().slice(0, 10)\n}\n\n/** Read a 6- or 8-digit date token; year-first is tried before day-first. */\nexport function parseDateToken(token: string): string | undefined {\n const n = (from: number, to: number): number => Number(token.slice(from, to))\n if (/^\\d{8}$/.test(token)) return isoDate(n(0, 4), n(4, 6), n(6, 8)) ?? isoDate(n(4, 8), n(2, 4), n(0, 2))\n if (/^\\d{6}$/.test(token)) return isoDate(2000 + n(0, 2), n(2, 4), n(4, 6)) ?? isoDate(2000 + n(4, 6), n(2, 4), n(0, 2))\n return undefined\n}\n\ntype HeaderField = (typeof HEADER_FIELDS)[number]\n\n/**\n * Read the experiment code, date and operator from the left of a name, in any\n * order. `position` holds the token index of each field. A name with no code\n * and no date has no header, so `WT_Ctrl_1` keeps `WT` as a sample token.\n */\nfunction readHeader(tokens: string[]): { fields: ExperimentHeader; position: Partial<Record<HeaderField, number>> } {\n const fields: ExperimentHeader = {}\n const position: Partial<Record<HeaderField, number>> = {}\n let i = 0\n if (tokens.length > 1 && /^exp\\d+$/i.test(tokens[0])) {\n fields.code = tokens[0].toLowerCase()\n position.code = i++\n }\n for (; i < tokens.length - 1; i++) {\n const date = fields.date ? undefined : parseDateToken(tokens[i])\n if (date) {\n fields.date = date\n position.date = i\n } else if (!fields.operator && /^[A-Z]{2,3}$/.test(tokens[i]) && !isClassMarker(tokens[i])) {\n fields.operator = tokens[i]\n position.operator = i\n } else {\n break\n }\n }\n if (!fields.code && !fields.date) return { fields: {}, position: {} }\n return { fields, position }\n}\n\nconst MS_FILE_EXTENSION = /\\.(raw|mzml|mzxml|mzdata|wiff2?|d|mgf|csv|tsv|txt)$/i\n\n/** Drop a mass-spec file extension from each name, and any other extension that all names share. */\nfunction stripExtensions(names: string[]): string[] {\n const bare = names.map(name => name.replace(MS_FILE_EXTENSION, ''))\n const ext = /\\.[A-Za-z][A-Za-z0-9]{0,4}$/.exec(bare[0] ?? '')?.[0]\n return ext && bare.every(name => name.endsWith(ext)) ? bare.map(name => name.slice(0, -ext.length)) : bare\n}\n\n/**\n * Sample names → token rows.\n *\n * 1. Trim; drop a file extension that all names share.\n * 2. Split on runs of the primary delimiter.\n * 3. Drop a trailing 14-digit acquisition stamp.\n * 4. Read the experiment header. A field moves to `experiment` when the batch\n * has one value for it. Any other field stays in the rows as written, so\n * `QC` or `WT` after the date in some names is not taken for operator\n * initials.\n * 5. Count the tokens that all names share after the header (the experiment\n * title), so a title word such as `std` cannot classify the batch as QC.\n */\nexport function tokenizeBatch(names: string[]): TokenizedBatch {\n const cleaned = stripExtensions(names.map(name => name.trim()))\n const delimiter = pickPrimaryDelimiter(cleaned)\n const parsed = cleaned.map(name => {\n const split = name.split(delimiter).filter(Boolean)\n if (split.length > 1 && /^\\d{14}$/.test(split[split.length - 1])) split.pop()\n const tokens = split.length > 0 ? split : [name]\n return { tokens, ...readHeader(tokens) }\n })\n\n const experiment: ExperimentHeader = {}\n for (const field of ['code', 'date'] as const) {\n const values = new Set(parsed.map(({ fields }) => fields[field]).filter(Boolean))\n if (values.size === 1) experiment[field] = [...values][0]\n }\n // `exp<NNN>` and a date are clear by their form. Operator initials are not:\n // `QC`, `WT` or `KO` look the same. The operator is the caps token that\n // (almost) all complete headers carry; any other caps token stays in its row.\n const dated = parsed.filter(({ fields }) => fields.date)\n const complete = dated.length > 0 ? dated : parsed.filter(({ fields }) => fields.code)\n const operatorCounts = new Map<string, number>()\n for (const { fields } of complete) {\n if (fields.operator) operatorCounts.set(fields.operator, (operatorCounts.get(fields.operator) ?? 0) + 1)\n }\n const [operator, count] = [...operatorCounts].sort((a, b) => b[1] - a[1])[0] ?? []\n if (operator && count >= complete.length * OPERATOR_AGREEMENT) experiment.operator = operator\n\n const rows = parsed.map(({ tokens, fields, position }) => {\n const moved = new Set(\n HEADER_FIELDS.filter(field => experiment[field] && fields[field] === experiment[field]).map(field => position[field]),\n )\n return tokens.filter((_, index) => !moved.has(index))\n })\n\n // A title exists only after a header; without one a shared first token can\n // be the QC marker of a QC-only paste.\n let sharedPrefix = 0\n if (rows.length > 1 && Object.keys(experiment).length > 0) {\n while (rows.every(row => row.length > sharedPrefix + 1 && row[sharedPrefix] === rows[0][sharedPrefix])) sharedPrefix++\n // When only numbers follow, the shared tokens are the sample description\n // (a QC-only batch: `QC_1`, `QC_2`), not a title.\n if (rows.every(row => row.slice(sharedPrefix).every(token => /^\\d+[A-Za-z]?$/.test(token)))) sharedPrefix = 0\n }\n\n return { delimiter, experiment, rows, sharedPrefix }\n}\n","import type {\n ColumnInfo,\n ColumnRole,\n ClassSchema,\n NumericParse,\n SampleClassKind,\n} from '../../types/auto-group'\nimport vocabData from './vocab.json'\n\nconst NUMERIC_VALUE_UNIT = /^(\\d+(?:(?:dot|\\.)\\d+)?)([A-Za-z%/μ]+)$/\nconst RATIO = /^(\\d+)to(\\d+)$/\nconst RUN_ORDER_PATTERN = /^\\d{2,4}[A-Z]?$/\n// Explicit replicate-token vocabulary: rep1 / Rep2 / replicate1 / R1 / T1.\n// These tokens almost always identify a within-group replicate dimension that\n// users do NOT want in the default group key — e.g. ctrl/rep1, ctrl/rep2\n// should land in one Ctrl group with two replicates, not two singleton groups.\nconst REPLICATE_TOKEN_PATTERN = new RegExp(vocabData.replicateToken, 'i')\n/**\n * A replicate counter is a dense run of small numbers or letters: `1, 2, 3`,\n * `01, 02, 03` or `A, B, C`. A quarter of the run can be missing (a failed\n * sample). `1, 5, 10` is a dose and `1, 2, 6, 7` an animal number: too sparse.\n */\nfunction isCounterRun(values: string[]): boolean {\n if (!values.every(value => /^(\\d{1,2}|[A-Za-z])$/.test(value))) return false\n // One batch can count some replicates 1, 2, 3 and others a, b, c.\n const ranks = [...new Set(values.map(value => (/\\d/.test(value) ? Number(value) : value.toUpperCase().charCodeAt(0) - 64)))]\n const allowedGaps = Math.max(1, Math.floor(ranks.length / 4))\n return Math.min(...ranks) >= 1 && Math.max(...ranks) <= ranks.length + allowedGaps\n}\n\n// A stem with a counter attached: C1, C2, H1.\nconst STEM_COUNTER_PATTERN = /^([A-Za-z]+)(\\d{1,2})$/\n// Share of a column that must agree before the column is split or read as\n// one-value-for-each-sample. The rest allows for odd names and re-injections.\nconst COLUMN_AGREEMENT = 0.9\nconst ID_MIN_CLASS_SIZE = 4\n\n/** Roles the Field Recipe offers as grouping fields. `replicate` and `id` are off by default. */\nexport const GROUPING_FIELD_ROLES: ReadonlySet<ColumnRole | undefined> = new Set<ColumnRole>([\n 'factor', 'numeric', 'replicate', 'id',\n])\n\n// Real-world LC-MS batches often have 30+ distinct conditions (subject IDs,\n// calibration levels, treatment combinations) in a single class. The earlier\n// cutoff of 20 routed everything above it to `ignore`, leaving such columns\n// out of the default groupBy — meaning a single giant group with no useful\n// split. 50 covers the common cases without making singleton-heavy columns\n// (sample IDs, timestamps) into factors.\nconst DEFAULT_FACTOR_CARDINALITY_MAX = 50\n// Numerics with only a handful of distinct levels (e.g. `5min` / `10min`,\n// `1nM` / `5nM` / `25nM`) read as factor levels by default. Users opt into\n// numeric binning explicitly via the column popover when they want it.\nconst LOW_CARDINALITY_NUMERIC_AS_FACTOR_MAX = 5\n\nexport function parseNumeric(token: string): NumericParse | null {\n const ratio = RATIO.exec(token)\n if (ratio) {\n const num = Number(ratio[1])\n const den = Number(ratio[2])\n if (den === 0) return null\n return { value: num / den, unit: 'ratio', raw: token }\n }\n const m = NUMERIC_VALUE_UNIT.exec(token)\n if (!m) return null\n const valueStr = m[1].replace(/dot/g, '.')\n const value = Number(valueStr)\n if (Number.isNaN(value)) return null\n return { value, unit: m[2], raw: token }\n}\n\nexport interface InferRoleInput {\n values: string[]\n position: number\n totalPositions: number\n classSize: number\n /** The column ends a name or a split token, where replicate counters sit. Defaults to the last position. */\n tail?: boolean\n}\n\nexport function inferRole(input: InferRoleInput): ColumnRole {\n const { values, position, totalPositions, classSize } = input\n const tail = input.tail ?? position === totalPositions - 1\n const unique = new Set(values)\n const cardinality = unique.size\n\n if (cardinality === 1) return 'constant'\n\n // replicate: explicit names (rep1, R1, T1), or a small counter that repeats\n // at the end of a name (1, 2, 3, 1, 2, 3). Empty cells come from names that\n // a column split did not match.\n const present = values.filter(Boolean)\n if (present.every(v => REPLICATE_TOKEN_PATTERN.test(v))) return 'replicate'\n if (tail && cardinality * 2 <= values.length && isCounterRun(present)) return 'replicate'\n\n // run-order: trailing position, injection-like values and high cardinality.\n // Numbers repeat when one batch holds two experiments, so half is enough.\n if (position === totalPositions - 1) {\n const allRunLike = values.every(v => RUN_ORDER_PATTERN.test(v))\n if (allRunLike && cardinality >= classSize * 0.5) return 'run-order'\n }\n\n // numeric: every value parses as value+unit (or ratio).\n const allNumeric = values.every(v => parseNumeric(v) !== null)\n if (allNumeric) {\n // A column like 5min / 10min reads as a factor in practice — users want to\n // group on the timepoint, not bin it.\n if (cardinality <= LOW_CARDINALITY_NUMERIC_AS_FACTOR_MAX) return 'factor'\n return 'numeric'\n }\n\n // id: one value for (almost) each sample, (almost) all with a digit — an\n // animal or sample number (212, M10, C01). Grouping by it gives groups of\n // one, so it is off by default. Unique words (Ctrl, DrugA, DrugB) are\n // conditions of a design with no replicates and stay a factor.\n if (\n values.length >= ID_MIN_CLASS_SIZE\n && cardinality >= values.length * COLUMN_AGREEMENT\n && values.filter(v => /\\d/.test(v)).length >= values.length * COLUMN_AGREEMENT\n ) return 'id'\n\n if (cardinality <= DEFAULT_FACTOR_CARDINALITY_MAX) return 'factor'\n\n return 'ignore'\n}\n\n/**\n * How a column splits when most of its values agree: on `-` into equal parts\n * (`2-1` → `2`, `1`), or into stem + counter (`C1` → `C`, `1`) when two or more\n * stems repeat with different counters. `D1`/`D3` (one stem) and `B13`/`S13`\n * (one counter for each stem) stay whole.\n */\nfunction columnSplitter(values: string[]): ((value: string) => string[]) | undefined {\n const agree = (test: (value: string) => boolean): boolean =>\n values.filter(test).length >= values.length * COLUMN_AGREEMENT\n\n const partCounts = new Map<number, number>()\n for (const value of values) {\n const parts = value.split('-').length\n partCounts.set(parts, (partCounts.get(parts) ?? 0) + 1)\n }\n const parts = [...partCounts].sort((a, b) => b[1] - a[1])[0]?.[0] ?? 1\n if (parts > 1 && agree(value => value.split('-').length === parts)) {\n return value => {\n const pieces = value.split('-')\n return pieces.length === parts ? pieces : [value, ...Array<string>(parts - 1).fill('')]\n }\n }\n\n const countersByStem = new Map<string, Set<string>>()\n for (const value of values) {\n const match = STEM_COUNTER_PATTERN.exec(value)\n if (match) countersByStem.set(match[1], (countersByStem.get(match[1]) ?? new Set()).add(match[2]))\n }\n const repeated = [...countersByStem.values()].filter(counters => counters.size > 1).length\n if (countersByStem.size > 1 && repeated * 2 >= countersByStem.size && agree(value => STEM_COUNTER_PATTERN.test(value))) {\n return value => STEM_COUNTER_PATTERN.exec(value)?.slice(1) ?? [value, '']\n }\n return undefined\n}\n\nexport interface ColumnSplit {\n rows: string[][]\n /** `origin[newIndex]` = index of the source column before the split. */\n origin: number[]\n /** New indices that end a split token. */\n tail: number[]\n}\n\n/** Split the columns of one class (rows of equal length) that hold two fields in one token. */\nexport function splitColumns(rows: string[][]): ColumnSplit {\n const width = rows[0]?.length ?? 0\n const splitters = Array.from({ length: width }, (_, col) => columnSplitter(rows.map(row => row[col] ?? '')))\n const origin: number[] = []\n const tail: number[] = []\n splitters.forEach((splitter, col) => {\n const parts = splitter ? splitter(rows[0][col]).length : 1\n for (let part = 0; part < parts; part++) origin.push(col)\n if (parts > 1) tail.push(origin.length - 1)\n })\n return {\n rows: rows.map(row => row.flatMap((token, col) => splitters[col]?.(token) ?? [token])),\n origin,\n tail,\n }\n}\n\n/**\n * Auto-detect a friendlier column name from the column's values + role.\n * Returns null when nothing matches, so callers can fall back to \"Field N\".\n *\n * Heuristics are content-derived and deterministic. They cover the common\n * LC-MS / proteomics naming conventions; users can override anything via\n * the column popover (rename input).\n */\nfunction inferColumnName(\n values: string[],\n uniqueValues: string[],\n role: ColumnRole,\n): string | null {\n if (uniqueValues.length === 0) return null\n\n // Numeric+unit columns name themselves by the dominant unit category.\n // We tally all values so a mixed-unit column (`1uL`, `1nM`) picks the\n // majority rather than the first sample's unit.\n const allNumeric = (role === 'numeric' || role === 'factor') && values.every(v => parseNumeric(v) !== null)\n if (allNumeric) {\n const categoryFor = (u: string): string | null => {\n const ul = u.toLowerCase()\n if (['min', 'sec', 's', 'hr', 'h', 'd', 'day', 'days', 'wk', 'week', 'hour', 'hours'].includes(ul)) return 'Timepoint'\n if (['nm', 'um', 'mm', 'm', 'molar', 'mol'].includes(ul)) return 'Concentration'\n if (['mg', 'g', 'kg', 'ng', 'ug', 'pg'].includes(ul)) return 'Mass'\n if (['ml', 'l', 'ul', 'nl', 'pl'].includes(ul)) return 'Volume'\n if (ul === '%') return 'Percentage'\n if (['c', 'k', 'celsius', 'kelvin'].includes(ul)) return 'Temperature'\n return null\n }\n const tally = new Map<string, number>()\n for (const v of values) {\n const p = parseNumeric(v)\n const cat = p ? categoryFor(p.unit) : null\n if (cat) tally.set(cat, (tally.get(cat) ?? 0) + 1)\n }\n let best: { cat: string; count: number } | null = null\n for (const [cat, count] of tally) {\n if (!best || count > best.count) best = { cat, count }\n }\n if (best && best.count >= values.length / 2) return best.cat\n }\n\n // Date-like all-digits tokens (YYMMDD or YYYYMMDD).\n if (values.every(v => /^\\d{6}$/.test(v) || /^\\d{8}$/.test(v))) return 'Date'\n\n // Run-order column = the trailing injection / acquisition sequence number.\n if (role === 'run-order') return 'Injection #'\n\n // Polarity tokens (POS/NEG/positive/negative).\n if (values.every(v => /^(pos|neg|positive|negative)$/i.test(v))) return 'Polarity'\n\n // Common biological matrices — kept in sync with classify.ts matrixVocab.\n if (values.every(v => /^(plasma|serum|tissue|tissues|kidney|liver|tumor|urine|brain|muscle|adipose|csf|feces|faeces|cells?|media|medium|extract)$/i.test(v))) {\n return 'Matrix'\n }\n\n // Experiment / study identifiers (exp268, study42, expt7).\n if (values.every(v => /^(exp|expt|study)\\d+$/i.test(v))) return 'Experiment'\n\n // Operator / Username: a constant column of 2-3 uppercase letters is almost\n // always operator initials (LCK, JD, AB). A column with two or more values\n // (WT / KO) is a factor and gets no name here.\n if (uniqueValues.length === 1 && /^[A-Z]{2,3}$/.test(uniqueValues[0])) return 'Username'\n\n if (role === 'replicate') return 'Replicate'\n if (role === 'id') return 'Sample ID'\n\n return null\n}\n\nexport function buildClassSchema(\n tokenizedMembers: string[][],\n classKind: SampleClassKind,\n subKind: string | undefined,\n classTagPositions: number[],\n /** Positions that end a split token (from `splitColumns`). */\n tailPositions: number[] = [],\n): ClassSchema {\n const totalPositions = tokenizedMembers[0]?.length ?? 0\n const classSize = tokenizedMembers.length\n\n const columns: ColumnInfo[] = []\n const tagSet = new Set(classTagPositions)\n // Replicate counters sit at the end of a name: the last position, or the one\n // before the injection number.\n const tailSet = new Set([...tailPositions, totalPositions - 1])\n\n // Right to left, so the injection column is known before its neighbour.\n for (let pos = totalPositions - 1; pos >= 0; pos--) {\n const values = tokenizedMembers.map(t => t[pos] ?? '')\n const uniqueValues = [...new Set(values)]\n\n let role: ColumnRole\n if (tagSet.has(pos) && uniqueValues.length === 1) {\n // Only constant tag positions become class-tag; multi-valued positions (e.g. organ\n // type within a Tissues class) fall through to normal role inference so they can be\n // used as factor columns for grouping.\n role = 'class-tag'\n } else {\n role = inferRole({ values, position: pos, totalPositions, classSize, tail: tailSet.has(pos) })\n }\n // Injection numbers with no zero padding (7, 18, 20) read as an id column\n // at the last position; a counter can sit before either form.\n const lastPosition = pos === totalPositions - 1\n if (role === 'run-order' || (lastPosition && role === 'id')) tailSet.add(pos - 1)\n\n const numeric =\n role === 'numeric'\n ? {\n byValue: Object.fromEntries(\n uniqueValues\n .map(v => [v, parseNumeric(v)] as const)\n .filter((e): e is readonly [string, NumericParse] => e[1] !== null),\n ),\n }\n : undefined\n\n const inferredName = inferColumnName(values, uniqueValues, role)\n columns.unshift({\n index: pos,\n name: inferredName ?? `Field ${pos + 1}`,\n sourceIndices: [pos],\n uniqueValues,\n cardinality: uniqueValues.length,\n role,\n numeric,\n // Legacy field\n type: pos === 0 ? 'prefix' : 'suffix',\n })\n }\n\n // The name is the field's identity across classes, so it must be unique in\n // a schema: a second `Date` or `Replicate` becomes `Date 2`. Grouping fields\n // take their names first, so a card keeps `Matrix` and the constant class\n // tag beside it becomes `Matrix 2`.\n const nameCounts = new Map<string, number>()\n const isField = (c: ColumnInfo): boolean => GROUPING_FIELD_ROLES.has(c.role)\n for (const c of [...columns.filter(isField), ...columns.filter(c => !isField(c))]) {\n const count = (nameCounts.get(c.name) ?? 0) + 1\n nameCounts.set(c.name, count)\n if (count > 1) c.name = `${c.name} ${count}`\n }\n\n const groupBy = columns.filter(c => c.role === 'factor' || c.role === 'numeric').map(c => c.index)\n\n return { classKind, subKind, columns, groupBy }\n}\n","import type { ClassSchema, MergeSuggestion } from '../../types/auto-group'\n\nconst THRESHOLD = 0.95\nconst MIN_CLASS_SIZE = 4\n\nfunction functionalDependency(rows: string[][], srcIdx: number, dstIdx: number): number {\n const map = new Map<string, Set<string>>()\n for (const row of rows) {\n const a = row[srcIdx] ?? ''\n const b = row[dstIdx] ?? ''\n const set = map.get(a)\n if (set) set.add(b)\n else map.set(a, new Set([b]))\n }\n if (map.size === 0) return 0\n let functional = 0\n for (const set of map.values()) if (set.size === 1) functional++\n return functional / map.size\n}\n\nexport function findMerges(schema: ClassSchema, rows: string[][]): MergeSuggestion[] {\n if (rows.length < MIN_CLASS_SIZE) return []\n\n const out: MergeSuggestion[] = []\n for (let i = 0; i < schema.columns.length - 1; i++) {\n const a = schema.columns[i]\n const b = schema.columns[i + 1]\n if (a.role !== 'factor' && b.role !== 'factor') continue\n\n const forward = functionalDependency(rows, a.index, b.index)\n const backward = functionalDependency(rows, b.index, a.index)\n if (forward < THRESHOLD || backward < THRESHOLD) continue\n\n const merged = new Set(rows.map(r => `${r[a.index] ?? ''}_${r[b.index] ?? ''}`))\n if (merged.size < 2) continue\n\n out.push({\n classKind: schema.classKind,\n subKind: schema.subKind,\n columnIndices: [a.index, b.index],\n proposedName: `Column ${a.index + 1}–${b.index + 1}`,\n confidence: Math.min(forward, backward),\n })\n }\n return out\n}\n","export const DEFAULT_COLORS = [\n '#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6',\n '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1',\n]\n\nexport const QC_OVERLAY_COLOR = '#6B7280'\n","import type {\n AutoGroupResult,\n ClassSchema,\n ColumnInfo,\n MetadataRow,\n NumericBinning,\n SampleClass,\n} from '../../types/auto-group'\nimport type { SampleGroup } from '../../types/components'\nimport type { TreeNode } from '../../types/componentLabTypes'\nimport { DEFAULT_COLORS, QC_OVERLAY_COLOR } from './colors'\nimport { classKey } from './classKey'\n\nexport interface ComposeInput {\n tokenizedSamples: string[][]\n sampleNames: string[]\n schemas: Record<string, ClassSchema>\n classes: SampleClass[]\n prefixClassLabels?: boolean\n missingGroupName?: string\n}\n\n/** Apply the operation pipeline to a single raw token value:\n * numeric-parse → alias → exclude → bin\n * Returns null if the row is excluded.\n */\nfunction applyOps(col: ColumnInfo, raw: string): string | null {\n let value = raw\n\n // alias (operates on raw source value)\n if (col.ops?.alias && raw in col.ops.alias) {\n value = col.ops.alias[raw]\n }\n\n // exclude (post-alias)\n if (col.ops?.exclude?.includes(raw) || col.ops?.exclude?.includes(value)) {\n return null\n }\n\n // bin (only when role === 'numeric' and binning.mode === 'binned')\n if (col.role === 'numeric' && col.binning?.mode === 'binned') {\n const parsed = col.numeric?.byValue[raw]\n if (parsed && col.binning.edges) {\n const bin = pickBin(parsed.value, col.binning)\n if (bin !== null) value = bin\n }\n }\n\n return value\n}\n\nfunction pickBin(value: number, b: NumericBinning): string | null {\n if (!b.edges || b.edges.length === 0) return null\n for (let i = 0; i < b.edges.length; i++) {\n if (value < b.edges[i]) {\n return b.labels?.[i] ?? `< ${b.edges[i]}`\n }\n }\n const last = b.edges[b.edges.length - 1]\n return b.labels?.[b.edges.length] ?? `> ${last}`\n}\n\nexport function composeGroups(input: ComposeInput): AutoGroupResult {\n const experimentalGroups: SampleGroup[] = []\n const qcGroups: SampleGroup[] = []\n const excludedSamples: string[] = []\n const metadata: MetadataRow[] = []\n let colorIdx = 0\n\n // Class-label prefixing exists ONLY to disambiguate group names when several\n // experimental classes could emit the same factor key (e.g. a Liver class and\n // a Kidney class both producing \"5min / High\"). With a single experimental\n // class there is nothing to disambiguate, so groups start directly at the\n // user's first layer and the sample selector's major-group slot is not\n // wasted on a constant root. When a prefix IS needed it should occupy ONE\n // hierarchy layer, so prefer the short distinguishing `subKind` (\"Liver\")\n // over the full label (\"Biological / Liver\") — falling back to the full\n // label when two classes share a subKind (e.g. token-length splits).\n const experimentalClasses = input.classes.filter(\n c => c.disposition === 'group' && input.schemas[classKey(c)],\n )\n const classPrefix = new Map<SampleClass, string>()\n if (input.prefixClassLabels !== false && experimentalClasses.length > 1) {\n const shortCounts = new Map<string, number>()\n for (const c of experimentalClasses) {\n const short = c.subKind ?? c.label\n shortCounts.set(short, (shortCounts.get(short) ?? 0) + 1)\n }\n for (const c of experimentalClasses) {\n const short = c.subKind ?? c.label\n classPrefix.set(c, (shortCounts.get(short) ?? 0) > 1 ? c.label : short)\n }\n }\n\n // Nested hierarchy (class → groupBy levels → sample leaves) built alongside\n // the flat groups. `treeIndex` lets repeated members reuse the same path node.\n // PATH_SEP is a control char so it never collides with a real token value.\n const PATH_SEP = String.fromCharCode(1)\n const groupTree: TreeNode[] = []\n const treeIndex = new Map<string, TreeNode>()\n let treeColorIdx = 0\n\n for (const cls of input.classes) {\n const schema = input.schemas[classKey(cls)]\n if (!schema) continue\n\n if (cls.disposition === 'exclude') {\n for (const m of cls.members) excludedSamples.push(input.sampleNames[m])\n continue\n }\n\n // Per-class group map. group key built from enabled (groupBy) columns,\n // joined with ' / ' for hierarchical display.\n const groupMap = new Map<string, { name: string; samples: string[] }>()\n const colByIdx = new Map(schema.columns.map(c => [c.index, c]))\n\n // Only experimental (group) classes form the nested tree; overlay/QC stay flat.\n const buildsTree = cls.disposition === 'group'\n const runCol = schema.columns.find(c => c.role === 'run-order')\n const classNodeId = classKey(cls)\n let classNode: TreeNode | null = null\n\n for (const m of cls.members) {\n const tokens = input.tokenizedSamples[m]\n const rowName = input.sampleNames[m]\n let excluded = false\n const fieldValues: Record<string, string> = {}\n\n for (const col of schema.columns) {\n const sourceValues = col.sourceIndices.map(idx => tokens[idx] ?? '')\n const raw = sourceValues.join('_') // merged columns join their source tokens\n const display = applyOps(col, raw)\n if (display === null) {\n excluded = true\n break\n }\n fieldValues[col.displayName ?? col.name] = display\n }\n\n if (excluded) {\n excludedSamples.push(rowName)\n continue\n }\n\n const keyParts: string[] =\n cls.disposition === 'group'\n ? schema.groupBy.map(idx => {\n const col = colByIdx.get(idx)!\n return fieldValues[col.displayName ?? col.name]\n })\n : [cls.label]\n\n // Prepend the class's short distinguishing label (see `classPrefix`\n // above) so group names from different classes don't collide when they\n // share a factor value (e.g. two tissue classes both emitting \"5min\").\n //\n // Only fires for disposition === 'group' classes (`classPrefix` holds no\n // other class): overlay/exclude classes already use cls.label AS their\n // single key part, so prefixing again would produce \"IQC / IQC\". A class\n // with one condition has no factor keyParts and is named by the prefix\n // alone (\"Brain\" next to \"Liver / Ctrl\"). The Unknown class opts out —\n // its label (\"Unknown\") adds no signal.\n const hasMissingGroupPart =\n input.missingGroupName &&\n cls.disposition === 'group' &&\n keyParts.some(part => part.trim().length === 0)\n const prefix = cls.kind !== 'unknown' ? classPrefix.get(cls) : undefined\n const groupKey = hasMissingGroupPart\n ? input.missingGroupName!\n : [...(prefix ? [prefix] : []), ...keyParts].join(' / ') || cls.label\n\n const bucket = groupMap.get(groupKey)\n if (bucket) {\n bucket.samples.push(rowName)\n } else {\n groupMap.set(groupKey, { name: groupKey, samples: [rowName] })\n }\n\n metadata.push({ sampleName: rowName, fields: fieldValues, group: groupKey })\n\n // Grow the nested tree: class root → one node per groupBy column → leaf.\n if (buildsTree) {\n if (!classNode) {\n classNode = {\n id: classNodeId,\n label: cls.label,\n badge: 0,\n children: [],\n metadata: { color: DEFAULT_COLORS[treeColorIdx++ % DEFAULT_COLORS.length] },\n }\n treeIndex.set(classNodeId, classNode)\n groupTree.push(classNode)\n }\n classNode.badge = (classNode.badge as number) + 1\n let cursor = classNode\n let pathId = classNodeId\n // Reuse the already-computed groupBy values (`keyParts`) so the tree\n // levels can never drift from the flat group key.\n for (const val of keyParts) {\n pathId += PATH_SEP + val\n let node = treeIndex.get(pathId)\n if (!node) {\n node = { id: pathId, label: val, badge: 0, children: [] }\n cursor.children!.push(node)\n treeIndex.set(pathId, node)\n }\n node.badge = (node.badge as number) + 1\n cursor = node\n }\n // Injection value goes through the column's op pipeline (alias/exclude)\n // via `fieldValues`, matching what every other surface shows.\n const injection = runCol ? fieldValues[runCol.displayName ?? runCol.name] : undefined\n const leaf: TreeNode = { id: pathId + PATH_SEP + rowName, label: rowName, type: 'sample' }\n if (injection) {\n leaf.badge = injection\n leaf.metadata = { injection }\n }\n cursor.children!.push(leaf)\n }\n }\n\n for (const { name, samples } of groupMap.values()) {\n const color =\n cls.disposition === 'overlay'\n ? QC_OVERLAY_COLOR\n : DEFAULT_COLORS[colorIdx++ % DEFAULT_COLORS.length]\n const g: SampleGroup = { name, color, samples }\n if (cls.disposition === 'overlay') qcGroups.push(g)\n else experimentalGroups.push(g)\n }\n }\n\n return {\n groups: [...experimentalGroups, ...qcGroups],\n experimentalGroups,\n qcGroups,\n metadata,\n excludedSamples,\n schemas: Object.values(input.schemas),\n groupTree,\n }\n}\n","import type { ClassSchema, SchemaFingerprint } from '../../types/auto-group'\n\nexport function serializeFingerprint(schemas: ClassSchema[]): SchemaFingerprint {\n return {\n version: 1,\n classes: schemas.map(s => ({\n kind: s.classKind,\n subKind: s.subKind,\n tokenLength: s.tokenLength,\n columns: s.columns.map(c => ({\n name: c.displayName ?? c.name,\n role: c.role ?? 'factor',\n sourceIndices: c.sourceIndices,\n binning: c.binning,\n ops: c.ops,\n })),\n groupBy: s.groupBy,\n })),\n }\n}\n\nexport function restoreFingerprint(\n fp: SchemaFingerprint,\n current: ClassSchema[],\n): ClassSchema[] {\n return fp.classes.map(snap => {\n // Match on token length too when the snapshot carries one, so length-split\n // classes sharing a (kind, subKind) restore to the right schema. Snapshots\n // saved before token-length splitting have no `tokenLength`; for those we\n // match on (kind, subKind) and prefer the candidate with the same column\n // count, so an old single-class fingerprint lands on the compatible split\n // instead of throwing on the first (wrong-arity) hit.\n const candidates = current.filter(\n c =>\n c.classKind === snap.kind &&\n c.subKind === snap.subKind &&\n (snap.tokenLength == null || c.tokenLength == null || c.tokenLength === snap.tokenLength),\n )\n const target =\n candidates.find(c => c.columns.length === snap.columns.length) ?? candidates[0]\n if (!target) {\n throw new Error(\n `Fingerprint class not present in current input: ${snap.kind}${snap.subKind ? '/' + snap.subKind : ''}`,\n )\n }\n if (target.columns.length !== snap.columns.length) {\n throw new Error(\n `Saved schema expects ${snap.columns.length} columns, current data has ${target.columns.length} for class ${snap.kind}${snap.subKind ? '/' + snap.subKind : ''}. column count mismatch`,\n )\n }\n return {\n ...target,\n groupBy: snap.groupBy,\n columns: target.columns.map((col, i) => ({\n ...col,\n displayName: snap.columns[i].name,\n role: snap.columns[i].role,\n binning: snap.columns[i].binning,\n ops: snap.columns[i].ops,\n })),\n }\n })\n}\n","import type { ClassSchema, ColumnInfo, SampleClass } from '../../types/auto-group'\nimport { classKey } from './classKey'\n\nexport interface TemplateOptions {\n mode: 'blank' | 'prefilled'\n format: 'csv' | 'tsv'\n /** For prefilled mode. Indexed parallel to `samples`. */\n tokenizedSamples?: string[][]\n /** Used to compute the filename; omitted → falls back to `sample_metadata_<date>`. */\n experimentCode?: string\n /** Override the blank-mode suggested headers. Defaults to ['group','class','replicate','notes']. */\n suggestedColumns?: string[]\n}\n\nconst DEFAULT_BLANK_HEADERS = ['group', 'class', 'replicate', 'notes']\n\nfunction rfc4180Quote(cell: string): string {\n if (/[\",\\n]/.test(cell)) {\n return `\"${cell.replace(/\"/g, '\"\"')}\"`\n }\n return cell\n}\n\nfunction joinRow(cells: string[], sep: string): string {\n return sep === ','\n ? cells.map(rfc4180Quote).join(',')\n : cells.join('\\t')\n}\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nexport function composeTemplate(\n samples: string[],\n schemas: ClassSchema[] | null,\n classes: SampleClass[] | null,\n options: TemplateOptions,\n): { content: string; filename: string } {\n const sep = options.format === 'tsv' ? '\\t' : ','\n const ext = options.format === 'tsv' ? 'tsv' : 'csv'\n\n const stem = options.experimentCode ? `${options.experimentCode}_metadata` : 'sample_metadata'\n const filename = `${stem}_${today()}.${ext}`\n\n if (options.mode === 'blank' || !schemas || !classes) {\n const headers = ['sample_name', ...(options.suggestedColumns ?? DEFAULT_BLANK_HEADERS)]\n const rows = samples.map(s => {\n const r = [s, ...Array(headers.length - 1).fill('')]\n return joinRow(r, sep)\n })\n return { content: [joinRow(headers, sep), ...rows].join('\\n'), filename }\n }\n\n // Prefilled mode: union of all class columns, wide layout.\n const tokenized = options.tokenizedSamples ?? []\n const allColumns: { schemaKey: string; colName: string }[] = []\n\n // Hoist: build lookup maps before the per-sample loop.\n const sampleToClass = new Map<number, SampleClass>()\n for (const cls of classes) for (const m of cls.members) sampleToClass.set(m, cls)\n\n const schemaByKey = new Map<string, ClassSchema>()\n for (const s of schemas) {\n const k = classKey({ kind: s.classKind, subKind: s.subKind, tokenLength: s.tokenLength })\n schemaByKey.set(k, s)\n }\n\n const colByNameByKey = new Map<string, Map<string, ColumnInfo>>()\n const groupBySetByKey = new Map<string, Set<number>>()\n for (const s of schemas) {\n const k = classKey({ kind: s.classKind, subKind: s.subKind, tokenLength: s.tokenLength })\n const m = new Map<string, ColumnInfo>()\n for (const c of s.columns) m.set(c.displayName ?? c.name, c)\n colByNameByKey.set(k, m)\n groupBySetByKey.set(k, new Set(s.groupBy))\n // Collect allColumns with dedup via Set\n const seenColNames = new Set<string>()\n for (const c of s.columns) {\n const name = c.displayName ?? c.name\n if (!seenColNames.has(name)) {\n seenColNames.add(name)\n if (!allColumns.some(x => x.colName === name)) {\n allColumns.push({ schemaKey: k, colName: name })\n }\n }\n }\n }\n\n const headers = ['sample_name', 'class', ...allColumns.map(c => c.colName), 'group', 'notes']\n\n const rows: string[] = []\n for (let i = 0; i < samples.length; i++) {\n const cls = sampleToClass.get(i)\n const classLabel = cls?.label ?? ''\n const tokens = tokenized[i] ?? []\n const cells: string[] = [samples[i], classLabel]\n\n if (cls) {\n const k = classKey(cls)\n const groupBySet = groupBySetByKey.get(k)\n const colByName: Map<string, ColumnInfo> | undefined = colByNameByKey.get(k)\n const keyParts: string[] = []\n for (const col of allColumns) {\n if (col.schemaKey === k && colByName) {\n const schemaCol = colByName.get(col.colName)\n const raw =\n schemaCol?.sourceIndices.map(idx => tokens[idx] ?? '').join('_') ?? ''\n cells.push(raw)\n if (schemaCol && groupBySet?.has(schemaCol.index)) keyParts.push(raw)\n } else {\n cells.push('')\n }\n }\n cells.push(keyParts.join(' / '))\n } else {\n for (const _ of allColumns) cells.push('')\n cells.push('')\n }\n\n cells.push('') // notes\n rows.push(joinRow(cells, sep))\n }\n\n return { content: [joinRow(headers, sep), ...rows].join('\\n'), filename }\n}\n","import type { SampleClass } from '../../types/auto-group'\nimport { isExperimentalKind } from './classify'\n\n/**\n * Token-length pre-grouping.\n *\n * After type classification (`detectClass`), members of one class can still have\n * different token counts — e.g. a Plasma batch where some names carry an extra\n * descriptor field. Splitting each class so every member shares the same token\n * length is the \"group same token-length sample, then extract tokens inside the\n * group\" step: it guarantees `buildClassSchema` sees a rectangular token matrix,\n * so column index N means the same field for every sample in the group.\n *\n * Each output class carries `tokenLength`; `classKey` folds that into the schema\n * key so length-split classes never collide. The label only gains a `· N fields`\n * suffix when a (kind, subKind) genuinely spans more than one length, keeping the\n * common (uniform) case visually identical to before.\n */\nexport function splitByTokenLength(\n classes: SampleClass[],\n tokenized: string[][],\n): SampleClass[] {\n const out: SampleClass[] = []\n\n for (const cls of classes) {\n // QC-kind classes (QC, blank, standard) are one group named by the class\n // label and never group by column, so they need no rectangular matrix.\n if (!isExperimentalKind(cls.kind)) {\n out.push(cls)\n continue\n }\n\n // Bucket members by token count, preserving first-seen order of lengths.\n const byLength = new Map<number, number[]>()\n const lengthOrder: number[] = []\n for (const m of cls.members) {\n const len = tokenized[m]?.length ?? 0\n const bucket = byLength.get(len)\n if (bucket) {\n bucket.push(m)\n } else {\n byLength.set(len, [m])\n lengthOrder.push(len)\n }\n }\n\n const multipleLengths = lengthOrder.length > 1\n for (const len of lengthOrder) {\n out.push({\n ...cls,\n members: byLength.get(len)!,\n tokenLength: len,\n // Drop class-tag positions that fall outside this split's token range.\n classTagPositions: cls.classTagPositions.filter(p => p < len),\n label: multipleLengths ? `${cls.label} · ${len} fields` : cls.label,\n })\n }\n }\n\n return out\n}\n","import type { SelectOption } from '../types'\nimport { isRecord } from '../utils/records'\n\nexport interface ExperimentDesignDataResponse {\n experiment_id?: number\n plugin_id?: string\n data?: Record<string, unknown>\n schema_version?: string\n updated_at?: string | null\n}\n\nexport interface ExtractExperimentSamplesOptions {\n includeControls?: boolean\n}\n\n\nfunction isPlatformDesignDataResponse(value: Record<string, unknown>): boolean {\n return (\n 'data' in value\n && (\n 'experiment_id' in value\n || 'plugin_id' in value\n || 'schema_version' in value\n || 'updated_at' in value\n )\n )\n}\n\n/** Return the plugin-defined design_data payload from common platform and plugin response shapes. */\nexport function unwrapExperimentDesignData(\n rawData: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null {\n if (!rawData) return null\n\n if (isRecord(rawData.data) && isPlatformDesignDataResponse(rawData)) {\n return rawData.data\n }\n\n if (isRecord(rawData.design_data)) {\n return rawData.design_data\n }\n\n if (isRecord(rawData.designData)) {\n return rawData.designData\n }\n\n return rawData\n}\n\nfunction shouldIncludeSample(record: Record<string, unknown>, options: ExtractExperimentSamplesOptions): boolean {\n if (options.includeControls) return true\n const rawType = record.sample_type ?? record.sampleType ?? record.type ?? record.well_type ?? record.wellType\n const type = typeof rawType === 'string' ? rawType.toLowerCase() : ''\n return !['blank', 'qc'].includes(type)\n}\n\nfunction readSampleValue(record: Record<string, unknown>): string | null {\n const candidates = [\n record.sample_name,\n record.sampleName,\n record.sample_id,\n record.sampleId,\n record.name,\n record.id,\n record.label,\n ]\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim()) {\n return candidate\n }\n if (typeof candidate === 'number' && Number.isFinite(candidate)) {\n return String(candidate)\n }\n }\n\n return null\n}\n\nfunction readSampleLabel(record: Record<string, unknown>, fallback: string): string {\n const label = record.name ?? record.label ?? record.sample_name ?? record.sampleName\n return typeof label === 'string' && label.trim() ? label : fallback\n}\n\nfunction readSampleDescription(record: Record<string, unknown>): string | undefined {\n const parts = [\n record.group,\n record.batch,\n record.batch_id,\n record.batchId,\n record.plate_id,\n record.plateId,\n record.well_id,\n record.wellId,\n ].filter((value): value is string | number =>\n (typeof value === 'string' && value.trim().length > 0)\n || typeof value === 'number',\n )\n\n return parts.length > 0 ? parts.map(String).join(' / ') : undefined\n}\n\nfunction addSampleRecord(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed)\n options.push({ value: trimmed, label: trimmed })\n }\n return\n }\n\n if (!isRecord(value) || !shouldIncludeSample(value, extractOptions)) return\n\n const sampleValue = readSampleValue(value)\n if (!sampleValue || seen.has(sampleValue)) return\n\n seen.add(sampleValue)\n options.push({\n value: sampleValue,\n label: readSampleLabel(value, sampleValue),\n description: readSampleDescription(value),\n })\n}\n\nfunction addSampleArray(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (!Array.isArray(value)) return\n for (const sample of value) {\n addSampleRecord(options, seen, sample, extractOptions)\n }\n}\n\n/** Extract selectable sample options from raw or wrapped experiment design_data. */\nexport function extractSampleOptionsFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): SelectOption<string>[] {\n const designData = unwrapExperimentDesignData(rawData)\n if (!designData) return []\n\n const sampleOptions: SelectOption<string>[] = []\n const seen = new Set<string>()\n\n addSampleArray(sampleOptions, seen, designData.samples, options)\n\n if (isRecord(designData.templates)) {\n for (const template of Object.values(designData.templates)) {\n if (!isRecord(template)) continue\n const templateData = isRecord(template.data) ? template.data : template\n addSampleArray(sampleOptions, seen, templateData.samples, options)\n }\n }\n\n if (Array.isArray(designData.plates)) {\n for (const plate of designData.plates) {\n if (!isRecord(plate)) continue\n addSampleArray(sampleOptions, seen, plate.samples, options)\n }\n }\n\n return sampleOptions\n}\n\n/** Extract SampleSelector-compatible string values from raw or wrapped experiment design_data. */\nexport function extractSampleNamesFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): string[] {\n return extractSampleOptionsFromDesignData(rawData, options).map(sample => sample.value)\n}\n","import { computed, ref } from 'vue'\nimport type {\n AutoGroupResult,\n ClassDisposition,\n ClassSchema,\n ColumnInfo,\n ColumnRole,\n InputMode,\n MergeSuggestion,\n NumericBinning,\n OutlierAction,\n OutlierInfo,\n ParsedCsvData,\n SampleClass,\n SchemaFingerprint,\n ValueOps,\n} from '../types/auto-group'\nimport {\n GROUPING_FIELD_ROLES,\n buildClassSchema,\n classKey,\n composeGroups,\n composeTemplate,\n detectClass,\n findMerges,\n isExperimentalKind,\n restoreFingerprint,\n serializeFingerprint,\n splitByTokenLength,\n splitColumns,\n tokenizeBatch,\n type Delimiter,\n type ExperimentHeader,\n type TemplateOptions,\n} from './autoGroup'\nimport { unwrapExperimentDesignData } from './experimentDesignData'\n\nexport { DEFAULT_COLORS } from './autoGroup'\n\nconst STRUCTURED_MISSING_GROUP = 'Outlier'\n\ntype ParsedExperimentCsvData = ParsedCsvData & { sampleTypeHints: (string | undefined)[] }\n\ninterface LoadExperimentDataOptions {\n samples?: readonly string[]\n}\n\nlet deprecationWarned = false\nlet outlierDeprecationWarned = false\nfunction warnDeprecated(api: string) {\n if (deprecationWarned) return\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return\n console.warn(\n `[useAutoGroup] ${api} is deprecated; use the new class-first API (setClassDisposition / toggleGroupBy / setValueOps).`,\n )\n deprecationWarned = true\n}\n\n// Re-export `parseCSV` for callers that imported it from this file.\nexport { parseCSV } from './autoGroup/csv-shim'\n\n/**\n * Sample-grouping engine behind `AutoGroupModal`.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useAutoGroup() {\n const inputMode = ref<InputMode>('paste')\n const rawText = ref('')\n const csvData = ref<ParsedCsvData | null>(null)\n const sampleTypeHints = ref<(string | undefined)[]>([])\n\n const classes = ref<SampleClass[]>([])\n const schemas = ref<Record<string, ClassSchema>>({})\n const activeClassKey = ref<string>('')\n\n const samples = computed(() => {\n if (csvData.value) {\n return csvData.value.rows.map(r => r[csvData.value!.sampleColumn] ?? '')\n }\n return rawText.value.split('\\n').map(l => l.trim()).filter(l => l.length > 0)\n })\n\n const tokenized = ref<string[][]>([])\n const delimiter = ref<Delimiter>('_')\n // Experiment code / date / operator that all pasted names share. Empty for\n // CSV and experiment input.\n const experiment = ref<ExperimentHeader>({})\n\n function parseInput() {\n if ((inputMode.value === 'csv' || inputMode.value === 'experiment') && csvData.value) {\n parseInputFromCsv()\n return\n }\n parseInputFromPaste()\n }\n\n function parseInputFromCsv() {\n experiment.value = {}\n const csv = csvData.value!\n const nonSampleCols = csv.columns.filter(c => c !== csv.sampleColumn && c !== 'sample_type')\n if (nonSampleCols.length === 0) {\n // No metadata columns — degenerate, single Unknown class\n tokenized.value = csv.rows.map(() => [])\n classes.value = [{\n kind: 'unknown',\n label: 'Unknown',\n members: csv.rows.map((_, i) => i),\n classTagPositions: [],\n disposition: 'group',\n }]\n schemas.value = { unknown: { classKind: 'unknown', columns: [], groupBy: [] } }\n activeClassKey.value = 'unknown'\n return\n }\n const tokens = csv.rows.map(r => nonSampleCols.map(col => r[col] ?? ''))\n tokenized.value = tokens\n const structuredClass: SampleClass = {\n kind: 'unknown',\n label: 'Unknown',\n members: csv.rows.map((_, i) => i),\n classTagPositions: [],\n disposition: 'group',\n }\n classes.value = [structuredClass]\n\n const schema = buildClassSchema(tokens, 'unknown', undefined, [])\n schema.columns = schema.columns.map((c, i) => ({\n ...c,\n name: nonSampleCols[i] ?? c.name,\n originalName: nonSampleCols[i],\n }))\n // CSV headers are already the user-authored hierarchy. Default to every\n // metadata column so N CSV columns produce N visible grouping levels.\n schema.groupBy = schema.columns.map(c => c.index)\n schemas.value = { unknown: schema }\n activeClassKey.value = 'unknown'\n }\n\n function parseInputFromPaste() {\n const lines = samples.value\n if (lines.length === 0) {\n classes.value = []\n schemas.value = {}\n experiment.value = {}\n return\n }\n // One token row for each sample. Replicate tokens, sample numbers and the\n // injection number stay in the row and get a column role below\n // ('replicate', 'id', 'run-order'), which keeps them out of the default\n // group key. Nothing is removed from a name before the user sees it.\n const batch = tokenizeBatch(lines)\n delimiter.value = batch.delimiter\n experiment.value = batch.experiment\n const tokens = batch.rows\n // Classify by sample type, THEN split each experimental class by token\n // length so every member of a class shares the same field count. This\n // keeps the per-class token matrix rectangular, so column index N means\n // the same field for every sample.\n const detected = splitByTokenLength(\n detectClass(tokens, { sampleTypeHints: sampleTypeHints.value, sharedPrefix: batch.sharedPrefix }),\n tokens,\n )\n const newSchemas: Record<string, ClassSchema> = {}\n for (const cls of detected) {\n let memberTokens = cls.members.map(i => tokens[i])\n let tailPositions: number[] = []\n const experimental = isExperimentalKind(cls.kind)\n if (experimental) {\n // Tokens that hold two fields (`2-1`, `C1`) become two columns.\n const split = splitColumns(memberTokens)\n cls.members.forEach((member, row) => { tokens[member] = split.rows[row] })\n cls.classTagPositions = split.origin.flatMap((source, index) =>\n cls.classTagPositions.includes(source) ? [index] : [],\n )\n memberTokens = split.rows\n tailPositions = split.tail\n }\n const schema = buildClassSchema(\n memberTokens,\n cls.kind,\n cls.subKind,\n cls.classTagPositions,\n tailPositions,\n )\n // A QC-kind class is one group named by the class label, also when the\n // user routes it into the groups.\n if (!experimental) schema.groupBy = []\n newSchemas[classKey(cls)] = { ...schema, tokenLength: cls.tokenLength }\n }\n tokenized.value = tokens\n classes.value = detected\n schemas.value = newSchemas\n if (detected.length > 0) {\n activeClassKey.value = classKey(detected[0])\n }\n }\n\n const activeSchema = computed<ClassSchema | null>(() => schemas.value[activeClassKey.value] ?? null)\n\n const suggestions = computed<MergeSuggestion[]>(() => {\n const schema = activeSchema.value\n if (!schema) return []\n const activeClass = classes.value.find(\n c => classKey(c) === activeClassKey.value,\n )\n if (!activeClass) return []\n const memberTokens = activeClass.members.map(i => tokenized.value[i])\n return findMerges(schema, memberTokens)\n })\n\n function composeWith(withSchemas: Record<string, ClassSchema>): AutoGroupResult {\n return composeGroups({\n tokenizedSamples: tokenized.value,\n sampleNames: samples.value,\n schemas: withSchemas,\n classes: classes.value,\n prefixClassLabels: !(csvData.value && (inputMode.value === 'csv' || inputMode.value === 'experiment')),\n missingGroupName: csvData.value && (inputMode.value === 'csv' || inputMode.value === 'experiment')\n ? STRUCTURED_MISSING_GROUP\n : undefined,\n })\n }\n\n const result = computed<AutoGroupResult>(() => composeWith(schemas.value))\n\n const fingerprint = computed<SchemaFingerprint>(() =>\n serializeFingerprint(result.value.schemas ?? []),\n )\n\n const groups = computed(() => result.value.groups)\n const qcGroups = computed(() => result.value.qcGroups ?? [])\n const metadata = computed(() => result.value.metadata)\n const excludedSamples = computed(() => result.value.excludedSamples)\n\n // ----- Mutators -----\n\n function setClassDisposition(key: string, disposition: ClassDisposition) {\n const target = classes.value.find(c => classKey(c) === key)\n if (!target || target.disposition === disposition) return\n classes.value = classes.value.map(c =>\n classKey(c) === key ? { ...c, disposition } : c,\n )\n }\n\n function setClassDispositions(\n predicate: (c: SampleClass) => boolean,\n disposition: ClassDisposition,\n ) {\n let changed = false\n const next = classes.value.map(c => {\n if (predicate(c) && c.disposition !== disposition) {\n changed = true\n return { ...c, disposition }\n }\n return c\n })\n if (changed) classes.value = next\n }\n\n // `groupBy` is an ORDERED layer list: entry N is hierarchy layer N of the\n // composed group names (layer 1 = the sample selector's major group). A\n // column toggled back on therefore appends as the LAST layer rather than\n // returning to its token position.\n function toggleGroupBy(key: string, idx: number) {\n const schema = schemas.value[key]\n if (!schema) return\n const groupBy = schema.groupBy.includes(idx)\n ? schema.groupBy.filter(i => i !== idx)\n : [...schema.groupBy, idx]\n schemas.value = {\n ...schemas.value,\n [key]: { ...schema, groupBy },\n }\n }\n\n /** Move an enabled column one step up (toward layer 1) or down in the layer order. */\n function moveGroupBy(key: string, idx: number, direction: 'up' | 'down') {\n const schema = schemas.value[key]\n if (!schema) return\n const from = schema.groupBy.indexOf(idx)\n if (from === -1) return\n const to = direction === 'up' ? from - 1 : from + 1\n if (to < 0 || to >= schema.groupBy.length) return\n const groupBy = [...schema.groupBy]\n ;[groupBy[from], groupBy[to]] = [groupBy[to], groupBy[from]]\n schemas.value = {\n ...schemas.value,\n [key]: { ...schema, groupBy },\n }\n }\n\n // The Field Recipe presents ONE set of grouping fields for the whole batch,\n // but classes each own a schema — so a field edit must reach every class that\n // exposes that field, or a multi-class batch ends up with divergent layer\n // orders (half the groups reordered). Fields are matched by display identity\n // rather than column index, since a class split off by token length can carry\n // the same field at a different position.\n function schemasExposing(fieldKey: string): { key: string; index: number }[] {\n return Object.entries(schemas.value).flatMap(([key, schema]) => {\n // An overlay class is one group; its columns are not grouping fields.\n if (!isExperimentalKind(schema.classKind)) return []\n const col = schema.columns.find(c =>\n (c.displayName ?? c.name) === fieldKey\n && (GROUPING_FIELD_ROLES.has(c.role) || schema.groupBy.includes(c.index)),\n )\n return col ? [{ key, index: col.index }] : []\n })\n }\n\n function fieldIdentity(schema: ClassSchema, index: number): string | undefined {\n const column = schema.columns.find(candidate => candidate.index === index)\n return column ? (column.displayName ?? column.name) : undefined\n }\n\n /**\n * Toggle a grouping field across every class exposing it. The batch card is\n * on when any schema groups by the field, so clicking it disables all such\n * schemas; only a fully disabled field is enabled across the batch.\n */\n function toggleGroupByField(fieldKey: string) {\n const targets = schemasExposing(fieldKey)\n if (targets.length === 0) return\n const enable = !targets.some(({ key, index }) => schemas.value[key]?.groupBy.includes(index))\n for (const { key, index } of targets) {\n const schema = schemas.value[key]\n if (!schema || schema.groupBy.includes(index) === enable) continue\n toggleGroupBy(key, index)\n }\n }\n\n /**\n * Rename a grouping field in every class exposing it. A blank name, or a\n * name that a column of any experimental class has, changes nothing: the\n * name is the field's identity across classes, and the cards merge by it.\n */\n function renameGroupByField(fieldKey: string, name: string) {\n const next = name.trim()\n const targets = schemasExposing(fieldKey)\n if (!next || next === fieldKey || targets.length === 0) return\n const taken = Object.values(schemas.value).some(schema =>\n isExperimentalKind(schema.classKind) && schema.columns.some(c => (c.displayName ?? c.name) === next),\n )\n if (taken) return\n for (const { key, index } of targets) setColumnName(key, index, next)\n }\n\n /** Number of experimental groups that remain when the field is switched off in every class. */\n function groupCountWithout(fieldKey: string): number {\n const targets = new Map(schemasExposing(fieldKey).map(({ key, index }) => [key, index]))\n const without = Object.fromEntries(\n Object.entries(schemas.value).map(([key, schema]) => [\n key,\n targets.has(key) ? { ...schema, groupBy: schema.groupBy.filter(i => i !== targets.get(key)) } : schema,\n ]),\n )\n return composeWith(without).experimentalGroups?.length ?? 0\n }\n\n /**\n * Move a grouping field in the active schema, then project that visible field\n * order across every class. Class-only fields keep their relative order after\n * the shared fields because the Field Recipe has no card with which to place\n * them explicitly.\n */\n function moveGroupByField(fieldKey: string, direction: 'up' | 'down') {\n const targets = schemasExposing(fieldKey)\n if (targets.length === 0) return\n const active = targets.find(target =>\n target.key === activeClassKey.value && schemas.value[target.key]?.groupBy.includes(target.index),\n ) ?? targets.find(target => schemas.value[target.key]?.groupBy.includes(target.index)) ?? targets[0]\n const activeSchema = schemas.value[active.key]\n if (!activeSchema) return\n const from = activeSchema.groupBy.indexOf(active.index)\n if (from === -1) return\n const to = direction === 'up' ? from - 1 : from + 1\n if (to < 0 || to >= activeSchema.groupBy.length) return\n\n const activeOrder = [...activeSchema.groupBy]\n ;[activeOrder[from], activeOrder[to]] = [activeOrder[to], activeOrder[from]]\n const desiredRank = new Map(\n activeOrder.flatMap((index, rank) => {\n const identity = fieldIdentity(activeSchema, index)\n return identity === undefined ? [] : [[identity, rank] as const]\n }),\n )\n\n let changed = false\n const nextSchemas = { ...schemas.value }\n for (const [key, schema] of Object.entries(schemas.value)) {\n const shared: Array<{ index: number; rank: number }> = []\n const classOnly: number[] = []\n for (const index of schema.groupBy) {\n const identity = fieldIdentity(schema, index)\n const rank = identity === undefined ? undefined : desiredRank.get(identity)\n if (rank === undefined) classOnly.push(index)\n else shared.push({ index, rank })\n }\n shared.sort((left, right) => left.rank - right.rank)\n const groupBy = [...shared.map(entry => entry.index), ...classOnly]\n if (groupBy.every((index, position) => index === schema.groupBy[position])) continue\n nextSchemas[key] = { ...schema, groupBy }\n changed = true\n }\n if (changed) schemas.value = nextSchemas\n }\n\n function updateColumn(key: string, idx: number, patch: Partial<ColumnInfo>) {\n const schema = schemas.value[key]\n if (!schema) return\n const col = schema.columns.find(c => c.index === idx)\n if (!col) return\n let changed = false\n for (const k of Object.keys(patch) as (keyof ColumnInfo)[]) {\n if ((col as unknown as Record<string, unknown>)[k as string] !== (patch as unknown as Record<string, unknown>)[k as string]) {\n changed = true\n break\n }\n }\n if (!changed) return\n schemas.value = {\n ...schemas.value,\n [key]: {\n ...schema,\n columns: schema.columns.map(c => (c.index === idx ? { ...c, ...patch } : c)),\n },\n }\n }\n\n function setRole(key: string, idx: number, role: ColumnRole) {\n updateColumn(key, idx, { role })\n }\n\n function setColumnName(key: string, idx: number, name: string) {\n updateColumn(key, idx, { displayName: name })\n }\n\n function setValueOps(key: string, idx: number, ops: ValueOps) {\n updateColumn(key, idx, { ops })\n }\n\n function setBinning(key: string, idx: number, binning: NumericBinning) {\n updateColumn(key, idx, { binning })\n }\n\n function mergeColumns(key: string, indices: number[]) {\n const schema = schemas.value[key]\n if (!schema || indices.length < 2) return\n const sorted = [...indices].sort((a, b) => a - b)\n const start = sorted[0]\n const merged: ColumnInfo = {\n index: start,\n name: `Column ${sorted.map(i => i + 1).join('–')}`,\n sourceIndices: sorted.flatMap(i => schema.columns.find(c => c.index === i)?.sourceIndices ?? [i]),\n uniqueValues: [],\n cardinality: 0,\n role: 'factor',\n }\n const dropped = new Set(sorted)\n schemas.value = {\n ...schemas.value,\n [key]: {\n ...schema,\n columns: [merged, ...schema.columns.filter(c => !dropped.has(c.index))]\n .sort((a, b) => a.index - b.index),\n groupBy: schema.groupBy.filter(i => !dropped.has(i) || i === start),\n },\n }\n }\n\n function loadFingerprint(fp: SchemaFingerprint) {\n const restored = restoreFingerprint(fp, Object.values(schemas.value))\n const next: Record<string, ClassSchema> = {}\n for (const s of restored) {\n next[classKey({ kind: s.classKind, subKind: s.subKind, tokenLength: s.tokenLength })] = s\n }\n schemas.value = next\n }\n\n // ----- Template download -----\n\n const canDownloadTemplate = computed(() => samples.value.length > 0)\n\n function downloadTemplate(mode: 'blank' | 'prefilled' = 'prefilled', format: 'csv' | 'tsv' = 'csv') {\n const { content, filename } = composeTemplate(\n samples.value,\n mode === 'prefilled' ? Object.values(schemas.value) : null,\n mode === 'prefilled' ? classes.value : null,\n { mode, format, tokenizedSamples: tokenized.value },\n )\n const blob = new Blob([content], { type: format === 'tsv' ? 'text/tab-separated-values' : 'text/csv' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n }\n\n /** Test seam — exposes the template content/filename without triggering a browser download. */\n function composeTemplateForTest(opts: Pick<TemplateOptions, 'mode' | 'format'>) {\n return composeTemplate(\n samples.value,\n opts.mode === 'prefilled' ? Object.values(schemas.value) : null,\n opts.mode === 'prefilled' ? classes.value : null,\n { ...opts, tokenizedSamples: tokenized.value },\n )\n }\n\n // ----- Legacy public refs and shims -----\n\n const outliers = ref<OutlierInfo[]>([])\n const hasOutliers = computed(() => outliers.value.length > 0)\n const conformingSamples = computed(() => samples.value)\n const dominantFieldCount = computed(() => tokenized.value[0]?.length ?? 0)\n const minFieldCount = computed(() => {\n if (tokenized.value.length === 0) return 0\n return Math.min(...tokenized.value.map(t => t.length))\n })\n const fields = computed(() => activeSchema.value?.columns ?? [])\n const fieldNames = computed<Record<number, string>>(() => {\n const out: Record<number, string> = {}\n for (const c of fields.value) out[c.index] = c.displayName ?? c.name\n return out\n })\n const enabledFields = computed<Set<number>>(() =>\n activeSchema.value ? new Set(activeSchema.value.groupBy) : new Set(),\n )\n const effectiveColumns = fields\n const allSingletons = computed(\n () => groups.value.length > 1 && groups.value.every(g => g.samples.length === 1),\n )\n\n function setOutlierAction(_: number, __: OutlierAction) {\n if (!outlierDeprecationWarned) {\n if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') {\n console.warn(\n `[useAutoGroup] setOutlierAction is deprecated AND inactive in the class-first redesign. ` +\n `Use setClassDisposition('iqc' | 'eqc' | …, 'group' | 'overlay' | 'exclude') instead.`,\n )\n outlierDeprecationWarned = true\n }\n }\n }\n\n function setAllOutlierActions(__: OutlierAction) {\n if (!outlierDeprecationWarned) {\n if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') {\n console.warn(\n `[useAutoGroup] setAllOutlierActions is deprecated AND inactive in the class-first redesign. ` +\n `Use setClassDisposition('iqc' | 'eqc' | …, 'group' | 'overlay' | 'exclude') instead.`,\n )\n outlierDeprecationWarned = true\n }\n }\n }\n\n function toggleField(index: number) {\n warnDeprecated('toggleField')\n if (activeClassKey.value) toggleGroupBy(activeClassKey.value, index)\n }\n\n function renameField(index: number, name: string) {\n warnDeprecated('renameField')\n if (activeClassKey.value) setColumnName(activeClassKey.value, index, name)\n }\n\n function loadExperimentData(\n rawData: Record<string, unknown>,\n options: LoadExperimentDataOptions = {},\n ): boolean {\n const parsed = extractSamplesFromDesignData(rawData, options)\n if (!parsed) return false\n inputMode.value = 'experiment'\n csvData.value = parsed\n sampleTypeHints.value = parsed.sampleTypeHints\n parseInput()\n return true\n }\n\n function reset() {\n rawText.value = ''\n csvData.value = null\n classes.value = []\n schemas.value = {}\n activeClassKey.value = ''\n tokenized.value = []\n experiment.value = {}\n outliers.value = []\n sampleTypeHints.value = []\n }\n\n return {\n // State\n inputMode, rawText, csvData, sampleTypeHints,\n classes, schemas, activeClassKey,\n delimiter, experiment, dominantFieldCount, minFieldCount,\n // Computed\n samples, tokenized, activeSchema, suggestions,\n groups, qcGroups, metadata, excludedSamples, result, fingerprint,\n fields, fieldNames, enabledFields, effectiveColumns,\n hasOutliers, outliers, conformingSamples, allSingletons,\n canDownloadTemplate,\n // Mutators\n setClassDisposition, setClassDispositions, toggleGroupBy, moveGroupBy,\n toggleGroupByField, moveGroupByField, renameGroupByField, groupCountWithout,\n setRole, setColumnName, setValueOps, setBinning,\n mergeColumns, loadFingerprint,\n // Actions\n parseInput, downloadTemplate, composeTemplateForTest, loadExperimentData, reset,\n // Deprecated shims\n setOutlierAction, setAllOutlierActions, toggleField, renameField,\n }\n}\n\n/**\n * Reads experiment `design_data` samples into the `useAutoGroup` CSV shape.\n *\n * @deprecated Scheduled for removal in MINT 1.4 together with `useAutoGroup`.\n */\nexport function extractSamplesFromDesignData(\n rawData: Record<string, unknown>,\n options: LoadExperimentDataOptions = {},\n): ParsedExperimentCsvData | null {\n const designData = unwrapExperimentDesignData(rawData)\n if (!designData) return null\n const samples = designData.samples\n if (!Array.isArray(samples) || samples.length === 0) return null\n const allConditionKeys: string[] = []\n const keySet = new Set<string>()\n const sampleTypeHints: (string | undefined)[] = []\n for (const sample of samples) {\n const rawType = (sample as Record<string, unknown>).sample_type\n sampleTypeHints.push(typeof rawType === 'string' ? rawType.toLowerCase() : undefined)\n const conditions = (sample as Record<string, unknown>).conditions as Record<string, string> | undefined\n if (conditions && typeof conditions === 'object') {\n for (const key of Object.keys(conditions)) {\n if (!keySet.has(key)) {\n keySet.add(key)\n allConditionKeys.push(key)\n }\n }\n }\n }\n if (allConditionKeys.length === 0) return null\n const columns = ['sample_name', ...allConditionKeys, 'sample_type']\n const rows = (samples as Record<string, unknown>[]).map(s => {\n const conditions = (s.conditions as Record<string, string>) ?? {}\n const row: Record<string, string> = {\n sample_name: String(s.sample_name ?? ''),\n sample_type: String(s.sample_type ?? 'sample'),\n }\n for (const key of allConditionKeys) row[key] = conditions[key] ?? ''\n return row\n })\n return constrainParsedSamplesToInput(\n { columns, rows, sampleColumn: 'sample_name', delimiter: ',', sampleTypeHints },\n options.samples,\n )\n}\n\nfunction constrainParsedSamplesToInput(\n parsed: ParsedExperimentCsvData,\n samples: readonly string[] | undefined,\n): ParsedExperimentCsvData {\n const requested = samples\n ?.map(sample => sample.trim())\n .filter(sample => sample.length > 0)\n if (!requested || requested.length === 0) return parsed\n\n const rowBySample = new Map<string, { row: Record<string, string>; hint: string | undefined }>()\n parsed.rows.forEach((row, index) => {\n const sample = row[parsed.sampleColumn]\n if (sample && !rowBySample.has(sample)) {\n rowBySample.set(sample, { row, hint: parsed.sampleTypeHints[index] })\n }\n })\n\n const metadataColumns = parsed.columns.filter(\n column => column !== parsed.sampleColumn && column !== 'sample_type',\n )\n const rows: Record<string, string>[] = []\n const sampleTypeHints: (string | undefined)[] = []\n\n for (const sample of requested) {\n const match = rowBySample.get(sample)\n if (match) {\n rows.push(match.row)\n sampleTypeHints.push(match.hint)\n continue\n }\n\n const outlierRow: Record<string, string> = {\n [parsed.sampleColumn]: sample,\n sample_type: 'sample',\n }\n for (const column of metadataColumns) outlierRow[column] = ''\n rows.push(outlierRow)\n sampleTypeHints.push(undefined)\n }\n\n return { ...parsed, rows, sampleTypeHints }\n}\n","import { ref, shallowRef, type Ref, type ShallowRef } from 'vue'\nimport { readErrorMessage } from '../utils/errors'\n\nexport interface DelimitedTable {\n columns: string[]\n rows: Record<string, string>[]\n rawRows: string[][]\n delimiter: string\n}\n\nexport interface ParseDelimitedTextOptions {\n delimiter?: string\n headers?: readonly string[]\n hasHeaderRow?: boolean\n trim?: boolean\n}\n\nexport interface FileImportValidationOptions {\n accept?: string | readonly string[]\n maxSizeBytes?: number\n}\n\nexport interface FileImportOptions<TResult = string> extends FileImportValidationOptions {\n encoding?: string\n parse?: (text: string, file: File) => TResult | Promise<TResult>\n}\n\nexport interface UseFileImportReturn<TResult> {\n loading: ShallowRef<boolean>\n error: Ref<string | null>\n fileName: Ref<string>\n result: Ref<TResult | null>\n importFile: (file: File) => Promise<TResult>\n clear: () => void\n}\n\n/** Stateful file reader for plugin import flows with shared validation and error handling. */\nexport function useFileImport<TResult = string>(\n options: FileImportOptions<TResult> = {},\n): UseFileImportReturn<TResult> {\n const loading = shallowRef(false)\n const error = ref<string | null>(null)\n const fileName = ref('')\n const result = ref<TResult | null>(null) as Ref<TResult | null>\n\n function clear(): void {\n loading.value = false\n error.value = null\n fileName.value = ''\n result.value = null\n }\n\n async function importFile(file: File): Promise<TResult> {\n loading.value = true\n error.value = null\n fileName.value = file.name\n\n try {\n validateImportFile(file, options)\n const text = await readFileAsText(file, options.encoding)\n const parsed = options.parse\n ? await options.parse(text, file)\n : text as TResult\n result.value = parsed\n return parsed\n } catch (err) {\n const message = readErrorMessage(err, 'Failed to import file.')\n error.value = message\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n fileName,\n result,\n importFile,\n clear,\n }\n}\n\nexport function validateImportFile(file: File, options: FileImportValidationOptions = {}): void {\n if (options.maxSizeBytes !== undefined && file.size > options.maxSizeBytes) {\n throw new Error(`File is too large. Maximum size is ${formatBytes(options.maxSizeBytes)}.`)\n }\n\n const accept = normalizeAccept(options.accept)\n if (accept.length === 0) return\n\n const name = file.name.toLowerCase()\n const type = file.type.toLowerCase()\n const matches = accept.some((entry) => {\n if (entry.startsWith('.')) return name.endsWith(entry)\n if (entry.endsWith('/*')) return type.startsWith(entry.slice(0, -1))\n return type === entry\n })\n\n if (!matches) {\n throw new Error(`Unsupported file type. Expected ${accept.join(', ')}.`)\n }\n}\n\nexport function readFileAsText(file: File, encoding?: string): Promise<string> {\n if (typeof FileReader === 'undefined' && typeof file.text === 'function') {\n return file.text()\n }\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = () => resolve(String(reader.result ?? ''))\n reader.onerror = () => reject(reader.error ?? new Error('Failed to read file.'))\n reader.readAsText(file, encoding)\n })\n}\n\nexport function parseDelimitedText(\n text: string,\n options: ParseDelimitedTextOptions = {},\n): DelimitedTable {\n const trim = options.trim ?? true\n const delimiter = options.delimiter ?? detectDelimiter(text)\n const rawRows = parseDelimitedRows(text, delimiter)\n .filter(row => row.some(cell => cell.trim().length > 0))\n .map(row => trim ? row.map(cell => cell.trim()) : row)\n\n const hasHeaderRow = options.hasHeaderRow ?? !options.headers\n const columns = options.headers\n ? [...options.headers]\n : hasHeaderRow\n ? rawRows[0] ?? []\n : createColumnNames(maxRowLength(rawRows))\n\n const dataRows = hasHeaderRow && !options.headers ? rawRows.slice(1) : rawRows\n const rows = dataRows.map(row => Object.fromEntries(\n columns.map((column, index) => [column, row[index] ?? '']),\n ))\n\n return {\n columns,\n rows,\n rawRows,\n delimiter,\n }\n}\n\nexport function detectDelimiter(text: string): string {\n const firstLine = text.split(/\\r?\\n/, 1)[0] ?? ''\n const commaCount = countChar(firstLine, ',')\n const tabCount = countChar(firstLine, '\\t')\n const semicolonCount = countChar(firstLine, ';')\n if (tabCount > commaCount && tabCount >= semicolonCount) return '\\t'\n if (semicolonCount > commaCount) return ';'\n return ','\n}\n\nfunction parseDelimitedRows(text: string, delimiter: string): string[][] {\n const rows: string[][] = []\n let row: string[] = []\n let field = ''\n let quoted = false\n\n for (let index = 0; index < text.length; index++) {\n const char = text[index]\n const next = text[index + 1]\n\n if (char === '\"') {\n if (quoted && next === '\"') {\n field += '\"'\n index++\n } else {\n quoted = !quoted\n }\n continue\n }\n\n if (!quoted && char === delimiter) {\n row.push(field)\n field = ''\n continue\n }\n\n if (!quoted && (char === '\\n' || char === '\\r')) {\n if (char === '\\r' && next === '\\n') index++\n row.push(field)\n rows.push(row)\n row = []\n field = ''\n continue\n }\n\n field += char\n }\n\n row.push(field)\n rows.push(row)\n return rows\n}\n\nfunction normalizeAccept(accept: string | readonly string[] | undefined): string[] {\n if (!accept) return []\n const entries = typeof accept === 'string' ? accept.split(',') : [...accept]\n return entries\n .map((entry: string) => entry.trim().toLowerCase())\n .filter(Boolean)\n}\n\nfunction createColumnNames(count: number): string[] {\n return Array.from({ length: count }, (_, index) => `column_${index + 1}`)\n}\n\nfunction maxRowLength(rows: readonly string[][]): number {\n return rows.reduce((max, row) => Math.max(max, row.length), 0)\n}\n\nfunction countChar(value: string, char: string): number {\n return [...value].filter(candidate => candidate === char).length\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`\n return `${Math.round(bytes / (1024 * 1024))} MB`\n}\n","/** Split a group name into normalized hierarchy segments. */\nexport function splitSampleGroupPath(groupName: string, separator: string): string[] {\n const parts = groupName\n .split(separator)\n .map(part => part.trim())\n .filter(part => part.length > 0)\n return parts.length > 0 ? parts : [groupName]\n}\n\n/** First normalized hierarchy segment, used as the reorderable family key. */\nexport function getSampleGroupMajorPrefix(groupName: string, separator: string): string {\n return splitSampleGroupPath(groupName, separator)[0]\n}\n\n/** Normalized path above a concrete leaf group. */\nexport function getSampleGroupParentPath(groupName: string, separator: string): string {\n const parts = splitSampleGroupPath(groupName, separator)\n return parts.length > 1 ? parts.slice(0, -1).join(separator) : ''\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport type { SampleGroup } from '../types'\nimport { deriveShade } from '../utils/color'\nimport { splitSampleGroupPath } from '../utils/sampleGroupPath'\n\nexport type SampleGroupSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface DisplaySampleSubGroup extends SampleGroup {\n displayColor: string\n displayBg: string\n displayBorder: string\n}\n\nexport interface SampleMajorGroup {\n name: string\n color: string\n subGroups: DisplaySampleSubGroup[]\n allSamples: string[]\n}\n\n/**\n * One node of the sample-group display hierarchy. Interior nodes are path\n * prefixes of the group names (`Liver`, `Liver / High`); leaves carry the\n * concrete group. A group's `name` stays the full path on its leaf because\n * every mutation — drag, delete, colour, selection — resolves groups by name.\n */\nexport interface SampleGroupNode {\n /** Unique across the tree; use for `:key` and expansion state. */\n key: string\n /** This node's own path segment, not the full path. */\n label: string\n color: string\n displayBg: string\n displayBorder: string\n /** Every sample beneath this node, in group order. */\n allSamples: string[]\n /** Empty for leaves. */\n children: SampleGroupNode[]\n /** Present only on leaves. */\n group?: DisplaySampleSubGroup\n}\n\nexport interface UseSampleGroupsOptions {\n groups: SampleGroupSource<readonly SampleGroup[]>\n samples?: SampleGroupSource<readonly string[]>\n separator?: SampleGroupSource<string | null | undefined>\n fallbackColor?: SampleGroupSource<string | null | undefined>\n}\n\nexport interface UseSampleGroupsReturn {\n groups: ComputedRef<SampleGroup[]>\n separator: ComputedRef<string>\n /** Full N-layer display hierarchy; one level per group-name segment. */\n groupTree: ComputedRef<SampleGroupNode[]>\n /** Deepest layer count across the tree (1 when groups are flat). */\n maxDepth: ComputedRef<number>\n hierarchicalGroups: ComputedRef<SampleMajorGroup[]>\n showHierarchy: ComputedRef<boolean>\n groupedSamples: ComputedRef<Set<string>>\n ungroupedSamples: ComputedRef<string[]>\n findGroup: (groupName: string) => SampleGroup | undefined\n getGroupColor: (groupName: string) => string\n}\n\n/** Shared sample-group hierarchy, color, and ungrouped-sample derivation for lab selectors. */\nexport function useSampleGroups(options: UseSampleGroupsOptions): UseSampleGroupsReturn {\n const groups = computed(() => [...toValue(options.groups)])\n const samples = computed(() => [...(toValue(options.samples) ?? [])])\n const fallbackColor = computed(() => toValue(options.fallbackColor) || '#3B82F6')\n const separator = computed(() => {\n const explicit = toValue(options.separator)\n if (explicit) return explicit\n return groups.value.some(group => group.name.includes('/')) ? '/' : '_'\n })\n\n // Groups are bucketed by their first segment (the major/family), then each\n // family is expanded into a full prefix tree. Shades are assigned per family\n // across its leaves so a family keeps one hue with a light→dark gradient,\n // exactly as the two-level model did.\n const families = computed(() => {\n const byMajor = new Map<string, SampleGroup[]>()\n for (const group of groups.value) {\n const majorName = getMajorGroupName(group.name, separator.value)\n const existing = byMajor.get(majorName)\n if (existing) existing.push(group)\n else byMajor.set(majorName, [group])\n }\n return [...byMajor.entries()].map(([name, members]) => {\n const color = members[0]?.color || fallbackColor.value\n return {\n name,\n color,\n subGroups: members.map((group, index) => {\n const displayColor = deriveShade(color, index, members.length)\n return {\n ...group,\n displayColor,\n displayBg: displayColor + '20',\n displayBorder: displayColor + '40',\n }\n }),\n }\n })\n })\n\n const groupTree = computed<SampleGroupNode[]>(() => {\n const roots: SampleGroupNode[] = []\n\n for (const family of families.value) {\n // Interior nodes are shared by path so siblings collapse into one parent;\n // leaves are keyed separately so a group whose full path equals an\n // interior path (e.g. \"Liver\" alongside \"Liver / High\") stays reachable\n // instead of being swallowed by the prefix node.\n const interior = new Map<string, SampleGroupNode>()\n\n for (const subGroup of family.subGroups) {\n const segments = splitSampleGroupPath(subGroup.name, separator.value)\n const leafLabel = segments[segments.length - 1] ?? subGroup.name\n let siblings = roots\n let path = ''\n\n for (const segment of segments.slice(0, -1)) {\n path = path ? `${path}/${segment}` : segment\n let node = interior.get(path)\n if (!node) {\n node = {\n key: `node:${family.name}/${path}`,\n label: segment,\n color: family.color,\n displayBg: family.color + '20',\n displayBorder: family.color + '40',\n allSamples: [],\n children: [],\n }\n interior.set(path, node)\n siblings.push(node)\n }\n node.allSamples.push(...subGroup.samples)\n siblings = node.children\n }\n\n siblings.push({\n key: `leaf:${subGroup.name}`,\n label: leafLabel,\n color: subGroup.displayColor,\n displayBg: subGroup.displayBg,\n displayBorder: subGroup.displayBorder,\n allSamples: [...subGroup.samples],\n children: [],\n group: subGroup,\n })\n }\n }\n\n return roots\n })\n\n const maxDepth = computed(() => {\n const depthOf = (nodes: SampleGroupNode[]): number =>\n nodes.reduce((deepest, node) => Math.max(deepest, 1 + depthOf(node.children)), 0)\n return depthOf(groupTree.value)\n })\n\n const hierarchicalGroups = computed<SampleMajorGroup[]>(() =>\n families.value.map(family => ({\n name: family.name,\n color: family.color,\n subGroups: family.subGroups,\n allSamples: family.subGroups.flatMap(group => group.samples),\n })),\n )\n\n const showHierarchy = computed(() => maxDepth.value > 1)\n\n const groupedSamples = computed(() =>\n new Set(groups.value.flatMap(group => group.samples))\n )\n\n const ungroupedSamples = computed(() =>\n samples.value.filter(sample => !groupedSamples.value.has(sample))\n )\n\n function findGroup(groupName: string): SampleGroup | undefined {\n return groups.value.find(group => group.name === groupName)\n }\n\n function getGroupColor(groupName: string): string {\n return findGroup(groupName)?.color || fallbackColor.value\n }\n\n return {\n groups,\n separator,\n groupTree,\n maxDepth,\n hierarchicalGroups,\n showHierarchy,\n groupedSamples,\n ungroupedSamples,\n findGroup,\n getGroupColor,\n }\n}\n\nfunction getMajorGroupName(groupName: string, separator: string): string {\n return splitSampleGroupPath(groupName, separator)[0]\n}\n","import { computed, ref, toValue, watch, type ComputedRef, type Ref } from 'vue'\n\nexport type ExpansionSetSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface UseExpansionSetOptions {\n defaultIds?: ExpansionSetSource<readonly string[] | null | undefined>\n allIds?: ExpansionSetSource<readonly string[] | null | undefined>\n expandAll?: ExpansionSetSource<boolean | null | undefined>\n}\n\nexport interface UseExpansionSetReturn {\n expandedIds: Ref<Set<string>>\n expandedList: ComputedRef<string[]>\n isExpanded: (id: string) => boolean\n expand: (id: string) => void\n collapse: (id: string) => void\n toggle: (id: string) => boolean\n expandMany: (ids: readonly string[]) => void\n setExpanded: (ids: readonly string[]) => void\n collapseAll: () => void\n reset: () => void\n}\n\n/** Shared expansion state for trees, grouped selectors, and disclosure lists. */\nexport function useExpansionSet(options: UseExpansionSetOptions = {}): UseExpansionSetReturn {\n const expandedIds = ref(new Set(normalizeIds(toValue(options.defaultIds))))\n const expandedList = computed(() => [...expandedIds.value])\n\n if (options.expandAll !== undefined) {\n watch(\n () => toValue(options.expandAll),\n (shouldExpandAll) => {\n if (shouldExpandAll === undefined || shouldExpandAll === null) return\n if (shouldExpandAll) {\n setExpanded(normalizeIds(toValue(options.allIds)))\n } else {\n reset()\n }\n },\n { immediate: true },\n )\n }\n\n if (options.allIds !== undefined) {\n watch(\n () => normalizeIds(toValue(options.allIds)),\n (ids) => {\n if (toValue(options.expandAll)) {\n setExpanded(ids)\n }\n },\n )\n }\n\n function isExpanded(id: string): boolean {\n return expandedIds.value.has(id)\n }\n\n function expand(id: string) {\n if (expandedIds.value.has(id)) return\n expandedIds.value = new Set([...expandedIds.value, id])\n }\n\n function collapse(id: string) {\n if (!expandedIds.value.has(id)) return\n const next = new Set(expandedIds.value)\n next.delete(id)\n expandedIds.value = next\n }\n\n function toggle(id: string): boolean {\n if (expandedIds.value.has(id)) {\n collapse(id)\n return false\n }\n expand(id)\n return true\n }\n\n function expandMany(ids: readonly string[]) {\n expandedIds.value = new Set([...expandedIds.value, ...normalizeIds(ids)])\n }\n\n function setExpanded(ids: readonly string[]) {\n expandedIds.value = new Set(normalizeIds(ids))\n }\n\n function collapseAll() {\n expandedIds.value = new Set()\n }\n\n function reset() {\n setExpanded(normalizeIds(toValue(options.defaultIds)))\n }\n\n return {\n expandedIds,\n expandedList,\n isExpanded,\n expand,\n collapse,\n toggle,\n expandMany,\n setExpanded,\n collapseAll,\n reset,\n }\n}\n\nfunction normalizeIds(ids: readonly string[] | null | undefined): string[] {\n if (!ids) return []\n return [...new Set(ids.filter(Boolean))]\n}\n","import { shallowRef, computed, type Ref, type ComputedRef } from 'vue'\nimport { useApi, type UseApiReturn } from './useApi'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n} from './experimentDesignData'\nimport type { TreeNode, SummaryData, SelectOption } from '../types'\n\nexport interface UseExperimentDataOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseExperimentDataReturn {\n /** Raw experiment data response from `/experiments/{id}/data`, or null. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload unwrapped from platform response shapes, or null. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** Sample values extracted from design_data for SampleSelector-style components. */\n sampleNames: ComputedRef<string[]>\n /** Sample options extracted from design_data for select/dropdown components. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n /** Hierarchy tree rows normalised from `tree_data` or `treeData`. */\n treeData: ComputedRef<TreeNode[]>\n /** Table rows normalised from `table_data` or `tableData`. */\n tableData: ComputedRef<Record<string, unknown>[]>\n /** Summary payload normalised from `summary_data` or `summaryData`, or null. */\n summaryData: ComputedRef<SummaryData | null>\n /** Whether experiment data is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment data fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Fetch experiment data for an experiment id. */\n fetch: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Refetch the most recently fetched experiment id. */\n refresh: () => Promise<void>\n /** Clear local experiment data and current fetch target. */\n clear: () => void\n}\n\n/** Fetches and normalises experiment output data (tree, table, summary) from the platform API. */\nexport function useExperimentData(\n options: UseExperimentDataOptions = {},\n): UseExperimentDataReturn {\n const data = shallowRef<Record<string, unknown> | null>(null)\n const request = useRequestSyncState('Failed to fetch experiment data')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n let lastExperimentId: number | null = null\n let api: UseApiReturn | null = null\n\n function getApi(): UseApiReturn {\n api ??= useApi({ baseUrl: options.apiBaseUrl })\n return api\n }\n\n const designData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(data.value),\n )\n\n const sampleNames = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value),\n )\n\n const treeData = computed<TreeNode[]>(() => {\n if (!designData.value) return []\n const tree = designData.value.tree_data ?? designData.value.treeData\n return Array.isArray(tree) ? tree as TreeNode[] : []\n })\n\n const tableData = computed<Record<string, unknown>[]>(() => {\n if (!designData.value) return []\n const table = designData.value.table_data ?? designData.value.tableData\n return Array.isArray(table) ? table as Record<string, unknown>[] : []\n })\n\n const summaryData = computed<SummaryData | null>(() => {\n if (!designData.value) return null\n const summary = designData.value.summary_data ?? designData.value.summaryData\n if (summary && typeof summary === 'object' && 'metadata' in (summary as Record<string, unknown>)) {\n return summary as SummaryData\n }\n return null\n })\n\n async function fetchData(experimentId: number): Promise<Record<string, unknown> | null> {\n lastExperimentId = experimentId\n try {\n data.value = await request.run(\n () => getApi().get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { success: 'load', errorMessage: 'Failed to fetch experiment data' },\n )\n return data.value\n } catch {\n data.value = null\n return null\n }\n }\n\n async function refresh(): Promise<void> {\n if (lastExperimentId !== null) {\n await fetchData(lastExperimentId)\n }\n }\n\n function clear(): void {\n data.value = null\n lastExperimentId = null\n request.clearError()\n }\n\n return {\n data,\n designData,\n sampleNames,\n sampleOptions,\n treeData,\n tableData,\n summaryData,\n isLoading,\n error,\n lastLoadedAt,\n fetch: fetchData,\n refresh,\n clear,\n }\n}\n","import {\n computed,\n inject,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport type { SelectOption } from '../types'\nimport { APP_EXPERIMENT_KEY } from './useAppExperiment'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n type ExtractExperimentSamplesOptions,\n} from './experimentDesignData'\nimport { parseExperimentId } from './platformContextHelpers'\nimport { useExperimentData } from './useExperimentData'\n\nexport type ExperimentIdSource = MaybeRefOrGetter<number | string | null | undefined>\nexport type ExperimentDesignDataSource = MaybeRefOrGetter<Record<string, unknown> | null | undefined>\n\nexport interface UseExperimentSamplesOptions extends ExtractExperimentSamplesOptions {\n /** Experiment id to load from `/experiments/{id}/data`; defaults to provided AppExperiment context. */\n experimentId?: ExperimentIdSource\n /** Pre-fetched design_data or full platform design-data response. */\n designData?: ExperimentDesignDataSource\n /** API base URL override for platform calls. */\n apiBaseUrl?: string\n /** Auto-load when an experiment id becomes available. Defaults to true. */\n immediate?: boolean\n /** Enable or disable automatic loading while keeping derived samples reactive. Defaults to true. */\n enabled?: MaybeRefOrGetter<boolean>\n /** Use `useAppExperiment` provided state when `experimentId` is not set. Defaults to true. */\n syncAppExperiment?: boolean\n}\n\nexport interface UseExperimentSamplesReturn {\n /** Experiment id currently used for automatic sample loading. */\n experimentId: ComputedRef<number | undefined>\n /** Raw `/experiments/{id}/data` response when loaded through the platform API. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload from props or platform response. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** SampleSelector-compatible string values extracted from design_data. */\n samples: ComputedRef<string[]>\n /** Select/dropdown-friendly sample options extracted from design_data. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n isLoading: Ref<boolean>\n error: Ref<string | null>\n lastLoadedAt: Ref<Date | null>\n /** Fetch samples for a specific experiment id, defaulting to the resolved id. */\n fetch: (experimentId?: number | string | null) => Promise<Record<string, unknown> | null>\n /** Refetch the current experiment id. */\n refresh: () => Promise<void>\n /** Clear fetched platform data. */\n clear: () => void\n}\n\n/** Loads experiment design_data and derives samples for SampleSelector-style UIs. */\nexport function useExperimentSamples(\n options: UseExperimentSamplesOptions = {},\n): UseExperimentSamplesReturn {\n const appExperiment = options.syncAppExperiment === false\n ? undefined\n : inject(APP_EXPERIMENT_KEY, undefined)\n const experimentData = useExperimentData({ apiBaseUrl: options.apiBaseUrl })\n\n const experimentId = computed<number | undefined>(() => {\n const explicitId = parseExperimentId(toValue(options.experimentId))\n return explicitId ?? parseExperimentId(appExperiment?.experimentId.value)\n })\n\n const explicitDesignData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(toValue(options.designData) ?? null),\n )\n\n const designData = computed<Record<string, unknown> | null>(() =>\n explicitDesignData.value ?? experimentData.designData.value,\n )\n\n const extractOptions = computed<ExtractExperimentSamplesOptions>(() => ({\n includeControls: options.includeControls,\n }))\n\n const samples = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value, extractOptions.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value, extractOptions.value),\n )\n\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n async function fetchSamples(\n id: number | string | null | undefined = experimentId.value,\n ): Promise<Record<string, unknown> | null> {\n const parsedId = parseExperimentId(id)\n if (parsedId === undefined) {\n experimentData.clear()\n return null\n }\n return experimentData.fetch(parsedId)\n }\n\n watch(\n () => ({\n designData: explicitDesignData.value,\n enabled: enabled.value,\n experimentId: experimentId.value,\n }),\n ({ designData: currentDesignData, enabled: isEnabled, experimentId: currentExperimentId }) => {\n if (options.immediate === false || !isEnabled) return\n if (currentDesignData) {\n experimentData.clear()\n return\n }\n if (currentExperimentId === undefined) {\n experimentData.clear()\n return\n }\n void experimentData.fetch(currentExperimentId)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n data: experimentData.data,\n designData,\n samples,\n sampleOptions,\n isLoading: experimentData.isLoading,\n error: experimentData.error,\n lastLoadedAt: experimentData.lastLoadedAt,\n fetch: fetchSamples,\n refresh: experimentData.refresh,\n clear: experimentData.clear,\n }\n}\n","import { ref, computed, onUnmounted, type Ref } from 'vue'\nimport type { ScheduleEvent } from '../types/components'\n\nexport type DragType = 'create' | 'resize-top' | 'resize-bottom' | 'move'\n\nexport interface DragState {\n type: DragType\n event?: ScheduleEvent\n startDate: Date\n startY: number\n currentY: number\n dayIndex: number\n currentDayIndex: number\n}\n\nexport interface GhostEvent {\n start: Date\n end: Date\n dayIndex: number\n style: Record<string, string>\n}\n\nexport interface UseScheduleDragOptions {\n slotDuration: Ref<number>\n dayStartHour: Ref<number>\n dayEndHour: Ref<number>\n readonly: Ref<boolean>\n slotHeight: Ref<number>\n blockedSlots?: Ref<{ start: string; end: string; label?: string }[]>\n onCreateComplete?: (start: Date, end: Date) => void\n onMoveComplete?: (event: ScheduleEvent, newStart: Date, newEnd: Date) => void\n onResizeComplete?: (event: ScheduleEvent, newStart: Date, newEnd: Date) => void\n}\n\n/** Handles pointer-driven create, move, and resize drag interactions for the ScheduleCalendar grid. */\nexport function useScheduleDrag(options: UseScheduleDragOptions) {\n const isDragging = ref(false)\n const dragState = ref<DragState | null>(null)\n\n const ghost = computed<GhostEvent | null>(() => {\n if (!dragState.value) return null\n const state = dragState.value\n const slotH = options.slotHeight.value\n const slotMin = options.slotDuration.value\n const dayStart = options.dayStartHour.value * 60\n\n if (state.type === 'create') {\n const deltaY = state.currentY - state.startY\n const startOffset = state.startY\n const endOffset = startOffset + deltaY\n\n const topPx = Math.min(startOffset, endOffset)\n const bottomPx = Math.max(startOffset, endOffset)\n\n const startMinutes = dayStart + Math.round((topPx / slotH) * slotMin)\n const endMinutes = dayStart + Math.round((bottomPx / slotH) * slotMin)\n\n const snappedStart = snapMinutes(startMinutes, slotMin)\n const snappedEnd = Math.max(snapMinutes(endMinutes, slotMin), snappedStart + slotMin)\n\n const snappedTopPx = ((snappedStart - dayStart) / slotMin) * slotH\n const snappedHeightPx = ((snappedEnd - snappedStart) / slotMin) * slotH\n\n return {\n start: minutesToDate(state.startDate, snappedStart),\n end: minutesToDate(state.startDate, snappedEnd),\n dayIndex: state.dayIndex,\n style: {\n top: `${snappedTopPx}px`,\n height: `${snappedHeightPx}px`,\n },\n }\n }\n\n if (state.type === 'move' && state.event) {\n const deltaY = state.currentY - state.startY\n const eventStart = dateToMinutes(new Date(state.event.start))\n const eventEnd = dateToMinutes(new Date(state.event.end))\n const duration = eventEnd - eventStart\n const pixelDelta = Math.round((deltaY / slotH) * slotMin)\n const newStart = snapMinutes(eventStart + pixelDelta, slotMin)\n const newEnd = newStart + duration\n\n const clamped = clampRange(newStart, newEnd, dayStart, options.dayEndHour.value * 60)\n const topPx = ((clamped.start - dayStart) / slotMin) * slotH\n const heightPx = ((clamped.end - clamped.start) / slotMin) * slotH\n\n return {\n start: minutesToDate(state.startDate, clamped.start),\n end: minutesToDate(state.startDate, clamped.end),\n dayIndex: state.currentDayIndex,\n style: {\n top: `${topPx}px`,\n height: `${heightPx}px`,\n },\n }\n }\n\n if ((state.type === 'resize-top' || state.type === 'resize-bottom') && state.event) {\n const eventStart = dateToMinutes(new Date(state.event.start))\n const eventEnd = dateToMinutes(new Date(state.event.end))\n const deltaY = state.currentY - state.startY\n const pixelDelta = Math.round((deltaY / slotH) * slotMin)\n\n let newStart = eventStart\n let newEnd = eventEnd\n\n if (state.type === 'resize-top') {\n newStart = snapMinutes(eventStart + pixelDelta, slotMin)\n newStart = Math.min(newStart, newEnd - slotMin)\n } else {\n newEnd = snapMinutes(eventEnd + pixelDelta, slotMin)\n newEnd = Math.max(newEnd, newStart + slotMin)\n }\n\n const clamped = clampRange(newStart, newEnd, dayStart, options.dayEndHour.value * 60)\n const topPx = ((clamped.start - dayStart) / slotMin) * slotH\n const heightPx = ((clamped.end - clamped.start) / slotMin) * slotH\n\n return {\n start: minutesToDate(state.startDate, clamped.start),\n end: minutesToDate(state.startDate, clamped.end),\n dayIndex: state.dayIndex,\n style: {\n top: `${topPx}px`,\n height: `${heightPx}px`,\n },\n }\n }\n\n return null\n })\n\n function startCreate(date: Date, y: number, dayIndex: number) {\n if (options.readonly.value) return\n isDragging.value = true\n dragState.value = {\n type: 'create',\n startDate: date,\n startY: y,\n currentY: y,\n dayIndex,\n currentDayIndex: dayIndex,\n }\n addListeners()\n }\n\n function startMove(event: ScheduleEvent, y: number, dayIndex: number) {\n if (options.readonly.value || event.draggable === false) return\n isDragging.value = true\n dragState.value = {\n type: 'move',\n event,\n startDate: new Date(event.start),\n startY: y,\n currentY: y,\n dayIndex,\n currentDayIndex: dayIndex,\n }\n addListeners()\n }\n\n function startResize(event: ScheduleEvent, edge: 'top' | 'bottom', y: number, dayIndex: number) {\n if (options.readonly.value || event.resizable === false) return\n isDragging.value = true\n dragState.value = {\n type: edge === 'top' ? 'resize-top' : 'resize-bottom',\n event,\n startDate: new Date(event.start),\n startY: y,\n currentY: y,\n dayIndex,\n currentDayIndex: dayIndex,\n }\n addListeners()\n }\n\n function onPointerMove(e: PointerEvent) {\n if (!dragState.value) return\n dragState.value = { ...dragState.value, currentY: e.clientY }\n }\n\n function onPointerUp() {\n if (!dragState.value || !ghost.value) {\n cleanup()\n return\n }\n\n const g = ghost.value\n const state = dragState.value\n\n if (state.type === 'create' && options.onCreateComplete) {\n options.onCreateComplete(g.start, g.end)\n } else if (state.type === 'move' && state.event && options.onMoveComplete) {\n options.onMoveComplete(state.event, g.start, g.end)\n } else if ((state.type === 'resize-top' || state.type === 'resize-bottom') && state.event && options.onResizeComplete) {\n options.onResizeComplete(state.event, g.start, g.end)\n }\n\n cleanup()\n }\n\n /**\n * Keyboard alternative to the pointer drag: shifts an event by one slot\n * (`mode: 'move'`) or grows/shrinks its end by one slot (`mode: 'resize'`),\n * staying inside the visible day. Returns whether the nudge was applied.\n */\n function nudgeEvent(\n event: ScheduleEvent,\n direction: -1 | 1,\n mode: 'move' | 'resize' = 'move',\n ): boolean {\n if (options.readonly.value) return false\n if (mode === 'move' && event.draggable === false) return false\n if (mode === 'resize' && event.resizable === false) return false\n\n const slotMin = options.slotDuration.value\n const dayStart = options.dayStartHour.value * 60\n const dayEnd = options.dayEndHour.value * 60\n const start = dateToMinutes(new Date(event.start))\n const end = dateToMinutes(new Date(event.end))\n\n const nextStart = mode === 'move' ? start + direction * slotMin : start\n const nextEnd = mode === 'move'\n ? end + direction * slotMin\n : Math.max(start + slotMin, end + direction * slotMin)\n\n if (nextStart < dayStart || nextEnd > dayEnd || nextEnd <= nextStart) return false\n\n const base = new Date(event.start)\n const newStart = minutesToDate(base, nextStart)\n const newEnd = minutesToDate(base, nextEnd)\n\n if (mode === 'move') options.onMoveComplete?.(event, newStart, newEnd)\n else options.onResizeComplete?.(event, newStart, newEnd)\n return true\n }\n\n function addListeners() {\n document.addEventListener('pointermove', onPointerMove)\n document.addEventListener('pointerup', onPointerUp)\n }\n\n function cleanup() {\n isDragging.value = false\n dragState.value = null\n document.removeEventListener('pointermove', onPointerMove)\n document.removeEventListener('pointerup', onPointerUp)\n }\n\n onUnmounted(cleanup)\n\n return {\n isDragging,\n dragState,\n ghost,\n startCreate,\n startMove,\n startResize,\n nudgeEvent,\n }\n}\n\nfunction snapMinutes(minutes: number, step: number): number {\n return Math.round(minutes / step) * step\n}\n\nfunction dateToMinutes(date: Date): number {\n return date.getHours() * 60 + date.getMinutes()\n}\n\nfunction minutesToDate(baseDate: Date, minutes: number): Date {\n const d = new Date(baseDate)\n d.setHours(Math.floor(minutes / 60), minutes % 60, 0, 0)\n return d\n}\n\nfunction clampRange(start: number, end: number, min: number, max: number) {\n const s = Math.max(start, min)\n const e = Math.min(end, max)\n return { start: s, end: Math.max(e, s) }\n}\n","import { computed, ref, type ComputedRef, type Ref } from 'vue'\nimport { useApi } from './useApi'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { createBioTemplatePresetCollection } from '../templates'\nimport type {\n CreateLcmsBatchCollectionOptions,\n CreateQpcrExpressionCollectionOptions,\n CreateWellPlateScreenCollectionOptions,\n TemplatePresetId,\n} from '../templates'\nimport {\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\n\ntype TemplatePresetCollectionOptions =\n | CreateWellPlateScreenCollectionOptions\n | CreateQpcrExpressionCollectionOptions\n | CreateLcmsBatchCollectionOptions\n\nexport interface UseExperimentSaveOptions {\n /** Default plugin_id for all save/load calls. */\n pluginId?: string\n /** Default schema version for design saves (defaults to \"1.0\"). */\n schemaVersion?: string\n /** Override API base URL. */\n apiBaseUrl?: string\n}\n\nexport interface UseExperimentSaveReturn {\n /** Current experiment id from platform injection, URL query, or URL path. */\n currentExperimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasCurrentExperiment: ComputedRef<boolean>\n /** Whether a save operation is in progress. */\n isSaving: Ref<boolean>\n /** Whether a load or delete operation is in progress. */\n isLoading: Ref<boolean>\n /** Error message from the last failed operation, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save, or null. */\n lastSavedAt: Ref<Date | null>\n /** Save design data for an experiment. */\n saveDesign: (experimentId: number, data: Record<string, unknown>) => Promise<boolean>\n /** Save design data for the current experiment. */\n saveCurrentDesign: (data: Record<string, unknown>) => Promise<boolean>\n /** Create and save a built-in biology template preset as experiment design data. */\n saveTemplatePreset: (\n experimentId: number,\n name: TemplatePresetId | string,\n options?: TemplatePresetCollectionOptions,\n ) => Promise<boolean>\n /** Create and save a built-in biology template preset for the current experiment. */\n saveCurrentTemplatePreset: (\n name: TemplatePresetId | string,\n options?: TemplatePresetCollectionOptions,\n ) => Promise<boolean>\n /** Save analysis result for an experiment. */\n saveAnalysis: (experimentId: number, result: Record<string, unknown>) => Promise<boolean>\n /** Save analysis result for the current experiment. */\n saveCurrentAnalysis: (result: Record<string, unknown>) => Promise<boolean>\n /** Save design and/or analysis in one call. */\n save: (experimentId: number, opts: {\n design?: Record<string, unknown>\n analysis?: Record<string, unknown>\n }) => Promise<boolean>\n /** Load design data for an experiment. */\n loadDesign: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Load design data for the current experiment. */\n loadCurrentDesign: () => Promise<Record<string, unknown> | null>\n /** Load analysis result for an experiment. */\n loadAnalysis: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Load analysis result for the current experiment. */\n loadCurrentAnalysis: () => Promise<Record<string, unknown> | null>\n /** Delete design data for an experiment. */\n deleteDesign: (experimentId: number) => Promise<boolean>\n /** Delete design data for the current experiment. */\n deleteCurrentDesign: () => Promise<boolean>\n /** Delete analysis result for an experiment. */\n deleteAnalysis: (experimentId: number) => Promise<boolean>\n /** Delete analysis result for the current experiment. */\n deleteCurrentAnalysis: () => Promise<boolean>\n /** Require and return the current experiment id, or throw when missing. */\n requireCurrentExperimentId: () => number\n}\n\n/**\n * Persists experiment design, analysis, and built-in template preset data through the platform API.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useExperimentSave(\n options: UseExperimentSaveOptions = {},\n): UseExperimentSaveReturn {\n const injectedContext = getInjectedPlatformContext()\n const api = useApi({ baseUrl: options.apiBaseUrl ?? injectedContext?.platformApiUrl })\n const pluginId = options.pluginId ?? injectedContext?.plugin?.id\n const schemaVersion = options.schemaVersion ?? '1.0'\n const currentExperimentId = computed<number | undefined>(() => {\n return resolveCurrentExperimentId(injectedContext)\n })\n const hasCurrentExperiment = computed(() => currentExperimentId.value !== undefined)\n\n const request = useRequestSyncState('Experiment request failed.')\n const isSaving = ref(false)\n const isLoading = ref(false)\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const lastSavedAt = request.lastSavedAt\n\n function requireCurrentExperimentId(): number {\n const id = currentExperimentId.value\n if (id === undefined) {\n throw new Error('[MINT SDK] No current experiment is selected.')\n }\n return id\n }\n\n function currentExperimentIdOrError(action: string): number | undefined {\n const id = currentExperimentId.value\n if (id === undefined) {\n request.setError(`No current experiment is selected for ${action}`)\n return undefined\n }\n return id\n }\n\n async function saveDesign(\n experimentId: number,\n data: Record<string, unknown>,\n ): Promise<boolean> {\n if (!pluginId) {\n request.setError('pluginId is required for saveDesign')\n return false\n }\n isSaving.value = true\n try {\n await request.run(async () => {\n await api.put(`/experiments/${experimentId}/data`, {\n plugin_id: pluginId,\n data,\n schema_version: schemaVersion,\n })\n }, { success: 'save' })\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n async function saveCurrentDesign(data: Record<string, unknown>): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('saveDesign')\n return experimentId === undefined ? false : saveDesign(experimentId, data)\n }\n\n async function saveTemplatePreset(\n experimentId: number,\n name: TemplatePresetId | string,\n presetOptions: TemplatePresetCollectionOptions = {},\n ): Promise<boolean> {\n const collection = createBioTemplatePresetCollection(name, presetOptions)\n return saveDesign(experimentId, collection as unknown as Record<string, unknown>)\n }\n\n async function saveCurrentTemplatePreset(\n name: TemplatePresetId | string,\n presetOptions: TemplatePresetCollectionOptions = {},\n ): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('saveTemplatePreset')\n return experimentId === undefined ? false : saveTemplatePreset(experimentId, name, presetOptions)\n }\n\n async function saveAnalysis(\n experimentId: number,\n result: Record<string, unknown>,\n ): Promise<boolean> {\n if (!pluginId) {\n request.setError('pluginId is required for saveAnalysis')\n return false\n }\n isSaving.value = true\n try {\n await request.run(async () => {\n await api.put(`/experiments/${experimentId}/results/${pluginId}`, {\n result,\n })\n }, { success: 'save' })\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n async function saveCurrentAnalysis(result: Record<string, unknown>): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('saveAnalysis')\n return experimentId === undefined ? false : saveAnalysis(experimentId, result)\n }\n\n async function save(\n experimentId: number,\n opts: { design?: Record<string, unknown>; analysis?: Record<string, unknown> },\n ): Promise<boolean> {\n if ((opts.design || opts.analysis) && !pluginId) {\n request.setError('pluginId is required for save')\n return false\n }\n isSaving.value = true\n try {\n await request.run(async () => {\n if (opts.design) {\n await api.put(`/experiments/${experimentId}/data`, {\n plugin_id: pluginId,\n data: opts.design,\n schema_version: schemaVersion,\n })\n }\n if (opts.analysis) {\n await api.put(`/experiments/${experimentId}/results/${pluginId}`, {\n result: opts.analysis,\n })\n }\n }, { success: 'save' })\n return true\n } catch {\n return false\n } finally {\n isSaving.value = false\n }\n }\n\n async function loadDesign(\n experimentId: number,\n ): Promise<Record<string, unknown> | null> {\n isLoading.value = true\n try {\n return await request.run(\n () => api.get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { success: 'load' },\n )\n } catch {\n return null\n } finally {\n isLoading.value = false\n }\n }\n\n async function loadCurrentDesign(): Promise<Record<string, unknown> | null> {\n const experimentId = currentExperimentIdOrError('loadDesign')\n return experimentId === undefined ? null : loadDesign(experimentId)\n }\n\n async function loadAnalysis(\n experimentId: number,\n ): Promise<Record<string, unknown> | null> {\n if (!pluginId) {\n request.setError('pluginId is required for loadAnalysis')\n return null\n }\n isLoading.value = true\n try {\n return await request.run(\n () => api.get<Record<string, unknown>>(\n `/experiments/${experimentId}/results/${pluginId}`,\n ),\n { success: 'load' },\n )\n } catch {\n return null\n } finally {\n isLoading.value = false\n }\n }\n\n async function loadCurrentAnalysis(): Promise<Record<string, unknown> | null> {\n const experimentId = currentExperimentIdOrError('loadAnalysis')\n return experimentId === undefined ? null : loadAnalysis(experimentId)\n }\n\n async function deleteDesign(experimentId: number): Promise<boolean> {\n isLoading.value = true\n try {\n await request.run(() => api.delete(`/experiments/${experimentId}/data`))\n return true\n } catch {\n return false\n } finally {\n isLoading.value = false\n }\n }\n\n async function deleteCurrentDesign(): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('deleteDesign')\n return experimentId === undefined ? false : deleteDesign(experimentId)\n }\n\n async function deleteAnalysis(experimentId: number): Promise<boolean> {\n if (!pluginId) {\n request.setError('pluginId is required for deleteAnalysis')\n return false\n }\n isLoading.value = true\n try {\n await request.run(() => api.delete(`/experiments/${experimentId}/results/${pluginId}`))\n return true\n } catch {\n return false\n } finally {\n isLoading.value = false\n }\n }\n\n async function deleteCurrentAnalysis(): Promise<boolean> {\n const experimentId = currentExperimentIdOrError('deleteAnalysis')\n return experimentId === undefined ? false : deleteAnalysis(experimentId)\n }\n\n return {\n currentExperimentId,\n hasCurrentExperiment,\n isSaving,\n isLoading,\n error,\n lastLoadedAt,\n lastSavedAt,\n saveDesign,\n saveCurrentDesign,\n saveTemplatePreset,\n saveCurrentTemplatePreset,\n saveAnalysis,\n saveCurrentAnalysis,\n save,\n loadDesign,\n loadCurrentDesign,\n loadAnalysis,\n loadCurrentAnalysis,\n deleteDesign,\n deleteCurrentDesign,\n deleteAnalysis,\n deleteCurrentAnalysis,\n requireCurrentExperimentId,\n }\n}\n","import { computed, ref, type ComputedRef, type Ref } from 'vue'\nimport { useExperimentSave, type UseExperimentSaveOptions } from './useExperimentSave'\nimport {\n createTemplateCollection,\n ensureTemplateFromCollection,\n extractTemplateCollection,\n type BioTemplateEnvelope,\n type TemplateCollection,\n type TemplateCollectionEnvelope,\n} from '../templates'\n\nexport type TemplateCollectionInput =\n | TemplateCollectionEnvelope\n | BioTemplateEnvelope<unknown>\n | Array<BioTemplateEnvelope<unknown>>\n\nexport interface UseTemplateCollectionOptions extends UseExperimentSaveOptions {\n /** Initial template collection or factory; defaults to an empty collection. */\n initial?: TemplateCollectionInput | (() => TemplateCollectionInput)\n}\n\nexport interface UseTemplateCollectionReturn {\n /** Current experiment id from platform injection, URL query, or URL path. */\n currentExperimentId: ComputedRef<number | undefined>\n /** Whether a current experiment id is available. */\n hasCurrentExperiment: ComputedRef<boolean>\n /** Full template collection envelope ready to save into design_data. */\n templateCollection: Ref<TemplateCollectionEnvelope>\n /** Template map keyed by template_id. */\n templates: ComputedRef<TemplateCollection>\n /** Collection-level metadata, or an empty object. */\n metadata: ComputedRef<Record<string, unknown>>\n /** Template ids currently present in the collection. */\n templateIds: ComputedRef<string[]>\n /** Whether the collection contains at least one template. */\n hasTemplates: ComputedRef<boolean>\n /** Whether a load or delete operation is in progress. */\n isLoading: Ref<boolean>\n /** Whether a save operation is in progress. */\n isSaving: Ref<boolean>\n /** Error message from the last failed operation, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Timestamp of the last successful save, or null. */\n lastSavedAt: Ref<Date | null>\n /** Replace local state from a template envelope, collection envelope, or raw design_data. */\n apply: (value: unknown, metadata?: Record<string, unknown>) => TemplateCollectionEnvelope\n /** Reset local state to the configured initial collection. */\n reset: () => TemplateCollectionEnvelope\n /** Add or replace one template in the local collection. */\n setTemplate: (template: BioTemplateEnvelope<unknown>) => TemplateCollectionEnvelope\n /** Remove one template from the local collection. */\n removeTemplate: (templateId: string) => boolean\n /** Read one template from the local collection, returning null when missing. */\n getTemplate: <TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>>(\n templateId: string,\n ) => TTemplate | null\n /** Read one template from the local collection, throwing when missing or mismatched. */\n requireTemplate: <TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>>(\n templateId: string,\n ) => TTemplate\n /** Load template design_data for an experiment and apply it locally. */\n load: (experimentId: number) => Promise<TemplateCollectionEnvelope | null>\n /** Load template design_data for the current experiment and apply it locally. */\n loadCurrent: () => Promise<TemplateCollectionEnvelope | null>\n /** Save the local template collection as experiment design_data. */\n save: (experimentId: number) => Promise<boolean>\n /** Save the local template collection as current experiment design_data. */\n saveCurrent: () => Promise<boolean>\n /** Require and return the current experiment id, or throw when missing. */\n requireCurrentExperimentId: () => number\n}\n\n/**\n * Manages a biology template collection in the current experiment's design_data.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useTemplateCollection(\n options: UseTemplateCollectionOptions = {},\n): UseTemplateCollectionReturn {\n const experimentSave = useExperimentSave(options)\n const templateCollection = ref<TemplateCollectionEnvelope>(createInitialCollection(options))\n const templates = computed(() => extractTemplateCollection(templateCollection.value))\n const metadata = computed(() => templateCollection.value.metadata ?? {})\n const templateIds = computed(() => Object.keys(templates.value))\n const hasTemplates = computed(() => templateIds.value.length > 0)\n\n function apply(value: unknown, metadata?: Record<string, unknown>): TemplateCollectionEnvelope {\n templateCollection.value = normalizeTemplateCollection(value, metadata)\n return templateCollection.value\n }\n\n function reset(): TemplateCollectionEnvelope {\n templateCollection.value = createInitialCollection(options)\n return templateCollection.value\n }\n\n function setTemplate(template: BioTemplateEnvelope<unknown>): TemplateCollectionEnvelope {\n const nextTemplates = {\n ...templates.value,\n [template.template_id]: template,\n }\n templateCollection.value = createTemplateCollectionEnvelope(\n Object.values(nextTemplates),\n templateCollection.value.metadata,\n )\n return templateCollection.value\n }\n\n function removeTemplate(templateId: string): boolean {\n if (!templates.value[templateId]) return false\n const nextTemplates = { ...templates.value }\n delete nextTemplates[templateId]\n templateCollection.value = createTemplateCollectionEnvelope(\n Object.values(nextTemplates),\n templateCollection.value.metadata,\n )\n return true\n }\n\n function getTemplate<\n TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>,\n >(templateId: string): TTemplate | null {\n return (templates.value[templateId] as TTemplate | undefined) ?? null\n }\n\n function requireTemplate<\n TTemplate extends BioTemplateEnvelope<unknown> = BioTemplateEnvelope<unknown>,\n >(templateId: string): TTemplate {\n return ensureTemplateFromCollection<TTemplate>(templateCollection.value, templateId)\n }\n\n async function load(experimentId: number): Promise<TemplateCollectionEnvelope | null> {\n const data = await experimentSave.loadDesign(experimentId)\n return data === null ? null : apply(data)\n }\n\n async function loadCurrent(): Promise<TemplateCollectionEnvelope | null> {\n const data = await experimentSave.loadCurrentDesign()\n return data === null ? null : apply(data)\n }\n\n async function save(experimentId: number): Promise<boolean> {\n return experimentSave.saveDesign(\n experimentId,\n templateCollection.value as unknown as Record<string, unknown>,\n )\n }\n\n async function saveCurrent(): Promise<boolean> {\n return experimentSave.saveCurrentDesign(\n templateCollection.value as unknown as Record<string, unknown>,\n )\n }\n\n return {\n currentExperimentId: experimentSave.currentExperimentId,\n hasCurrentExperiment: experimentSave.hasCurrentExperiment,\n templateCollection,\n templates,\n metadata,\n templateIds,\n hasTemplates,\n isLoading: experimentSave.isLoading,\n isSaving: experimentSave.isSaving,\n error: experimentSave.error,\n lastLoadedAt: experimentSave.lastLoadedAt,\n lastSavedAt: experimentSave.lastSavedAt,\n apply,\n reset,\n setTemplate,\n removeTemplate,\n getTemplate,\n requireTemplate,\n load,\n loadCurrent,\n save,\n saveCurrent,\n requireCurrentExperimentId: experimentSave.requireCurrentExperimentId,\n }\n}\n\nfunction createInitialCollection(options: UseTemplateCollectionOptions): TemplateCollectionEnvelope {\n const initial = typeof options.initial === 'function' ? options.initial() : options.initial\n if (initial === undefined) return { templates: {} }\n return normalizeTemplateCollection(initial)\n}\n\nfunction normalizeTemplateCollection(\n value: unknown,\n metadata?: Record<string, unknown>,\n): TemplateCollectionEnvelope {\n if (Array.isArray(value)) {\n return createTemplateCollectionEnvelope(value, metadata)\n }\n\n return createTemplateCollectionEnvelope(\n Object.values(extractTemplateCollection(value)),\n readCollectionMetadata(value) ?? metadata,\n )\n}\n\nfunction createTemplateCollectionEnvelope(\n templates: Array<BioTemplateEnvelope<unknown>>,\n metadata?: Record<string, unknown>,\n): TemplateCollectionEnvelope {\n return metadata === undefined\n ? createTemplateCollection(templates)\n : createTemplateCollection(templates, metadata)\n}\n\nfunction readCollectionMetadata(value: unknown): Record<string, unknown> | undefined {\n if (\n typeof value !== 'object'\n || value === null\n || Array.isArray(value)\n || !('metadata' in value)\n ) {\n return undefined\n }\n\n const metadata = (value as { metadata?: unknown }).metadata\n if (\n typeof metadata === 'object'\n && metadata !== null\n && !Array.isArray(metadata)\n ) {\n return metadata as Record<string, unknown>\n }\n return undefined\n}\n","import {\n createBioTemplateControlToolkit,\n getBioTemplateControlSchema,\n requireBioTemplateControlSchema,\n type BioTemplateControlSchema,\n type BioTemplateControlTarget,\n} from '../templates/controlSchemas'\nimport type {\n ControlSchemaOptions,\n ControlWorkspaceOptions,\n UseControlSchemaReturn,\n} from './controlSchemaTypes'\n\nexport {\n getBioTemplateControlSchema,\n requireBioTemplateControlSchema,\n}\n\nexport type {\n BioTemplateControlSchema,\n BioTemplateControlTarget,\n}\n\n/**\n * Build FormBuilder schema, AppSidebar panels, and defaults for a built-in biology template or preset.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useBioTemplateControls(\n target: BioTemplateControlTarget,\n options: ControlWorkspaceOptions = {},\n): UseControlSchemaReturn<BioTemplateControlSchema> {\n const { initialValues, topBarSettings: _topBarSettings, ...schemaOptions } = options\n const controls = createBioTemplateControlToolkit(target, schemaOptions as ControlSchemaOptions)\n\n if (initialValues === undefined) return controls\n\n return {\n ...controls,\n initialValues: {\n ...controls.initialValues,\n ...initialValues,\n },\n }\n}\n","import {\n getBioTemplateComponentBindings,\n getBioTemplateComponentProps as getTemplateComponentProps,\n toBioTemplateComponentImports,\n toBioTemplateComponentBindings,\n toBioTemplateComponentBindingsById,\n toBioTemplateComponentProps,\n toBioTemplateComponentPropsByComponent as toTemplateComponentPropsByComponent,\n toBioTemplateComponentPropsById,\n toBioTemplateComponentSnippets,\n toBioTemplateComponentUsage,\n type BioTemplateComponentBinding,\n type BioTemplateComponentBindingsById,\n type BioTemplateComponentImport,\n type BioTemplateComponentPropsByComponent,\n type BioTemplateComponentPropsBinding,\n type BioTemplateComponentPropsById,\n type BioTemplateComponentPropsLookupOptions,\n type BioTemplateResolvedComponentBinding,\n type BioTemplateComponentSnippet,\n type BioTemplateComponentTarget,\n type BioTemplateComponentUsage,\n} from '../templates/componentBindings'\nimport type {\n BioTemplateEnvelope,\n TemplateCollectionEnvelope,\n} from '../templates/types'\n\nexport {\n getBioTemplateComponentBindings,\n toBioTemplateComponentBindings,\n toBioTemplateComponentBindingsById,\n toBioTemplateComponentImports,\n toBioTemplateComponentProps,\n toBioTemplateComponentPropsById,\n toBioTemplateComponentSnippets,\n toBioTemplateComponentUsage,\n}\n\nexport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentPropsLookupOptions,\n BioTemplateResolvedComponentBinding,\n BioTemplateComponentSnippet,\n BioTemplateComponentTarget,\n BioTemplateComponentUsage,\n}\n\nexport interface UseBioTemplateComponentsReturn {\n bindings: BioTemplateComponentBinding[]\n imports: BioTemplateComponentImport[]\n componentBindings: BioTemplateResolvedComponentBinding[]\n componentBindingsById: BioTemplateComponentBindingsById\n componentProps: BioTemplateComponentPropsBinding[]\n componentPropsById: BioTemplateComponentPropsById\n componentPropsByComponent: BioTemplateComponentPropsByComponent\n snippets: BioTemplateComponentSnippet[]\n usage: BioTemplateComponentUsage | null\n getComponentProps: (\n component: string,\n options?: BioTemplateComponentPropsLookupOptions,\n ) => Record<string, unknown> | undefined\n}\n\n/**\n * Return component props grouped by SDK component name for direct WellPlate/DoseCalculator binding.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function toBioTemplateComponentPropsByComponent(\n target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,\n): BioTemplateComponentPropsByComponent {\n return toTemplateComponentPropsByComponent(target)\n}\n\n/**\n * Return the first props object for an SDK component, optionally restricted by template id or binding id.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function getBioTemplateComponentProps(\n target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope,\n component: string,\n options: BioTemplateComponentPropsLookupOptions = {},\n): Record<string, unknown> | undefined {\n return getTemplateComponentProps(target, component, options)\n}\n\n/**\n * Map built-in biology templates to SDK components such as WellPlate, DataFrame, DoseCalculator, and PlateEditor.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useBioTemplateComponents(\n target: BioTemplateComponentTarget\n): UseBioTemplateComponentsReturn {\n return {\n bindings: getBioTemplateComponentBindings(target),\n imports: toBioTemplateComponentImports(target),\n componentBindings: typeof target === 'string' ? [] : toBioTemplateComponentBindings(target),\n componentBindingsById: typeof target === 'string' ? {} : toBioTemplateComponentBindingsById(target),\n componentProps: typeof target === 'string' ? [] : toBioTemplateComponentProps(target),\n componentPropsById: typeof target === 'string' ? {} : toBioTemplateComponentPropsById(target),\n componentPropsByComponent: typeof target === 'string' ? {} : toBioTemplateComponentPropsByComponent(target),\n snippets: typeof target === 'string' ? [] : toBioTemplateComponentSnippets(target),\n usage: typeof target === 'string' ? null : toBioTemplateComponentUsage(target),\n getComponentProps: (component, options) =>\n typeof target === 'string'\n ? undefined\n : getBioTemplateComponentProps(target, component, options),\n }\n}\n","import { computed } from 'vue'\nimport type { ComputedRef } from 'vue'\nimport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentPropsLookupOptions,\n BioTemplateComponentSnippet,\n BioTemplateComponentUsage,\n} from './useBioTemplateComponents'\n\n/**\n * The template-component slice of `UseBioTemplateWorkspaceReturn`: the ~9 keys every\n * bio-template workspace composable (`useBioTemplateWorkspace`, `useBioTemplatePackWorkspace`,\n * `useBioTemplatePresetWorkspace`) re-exposes verbatim from `useBioTemplateComponents()`.\n */\nexport interface BioTemplateWorkspaceComponentBindings {\n componentBindings: BioTemplateComponentBinding[]\n componentBindingsById: BioTemplateComponentBindingsById\n componentImports: BioTemplateComponentImport[]\n componentProps: BioTemplateComponentPropsBinding[]\n componentPropsById: BioTemplateComponentPropsById\n componentPropsByComponent: BioTemplateComponentPropsByComponent\n componentSnippets: BioTemplateComponentSnippet[]\n componentUsage: BioTemplateComponentUsage | null\n getComponentProps: (component: string, options?: BioTemplateComponentPropsLookupOptions) => Record<string, unknown> | undefined\n}\n\n/** Structural source shape accepted by {@link flattenWorkspaceComponentBindings}. */\nexport interface BioTemplateWorkspaceComponentSource {\n componentBindings: BioTemplateComponentBinding[]\n componentBindingsById: BioTemplateComponentBindingsById\n componentImports: BioTemplateComponentImport[]\n componentProps: BioTemplateComponentPropsBinding[]\n componentPropsById: BioTemplateComponentPropsById\n componentPropsByComponent: BioTemplateComponentPropsByComponent\n componentSnippets: BioTemplateComponentSnippet[]\n componentUsage: BioTemplateComponentUsage | null\n getComponentProps: (component: string, options?: BioTemplateComponentPropsLookupOptions) => Record<string, unknown> | undefined\n}\n\n/**\n * Pick the shared template-component binding keys off a resolved bio-template workspace\n * (or its `components` source directly), so composables that build on `useBioTemplateWorkspace`\n * spread one object instead of re-listing all 9 keys by hand.\n *\n * @example Recommended\n * ```ts\n * const bindings = { renderer, ...flattenWorkspaceComponentBindings(components) }\n * ```\n */\nexport function flattenWorkspaceComponentBindings(\n source: BioTemplateWorkspaceComponentSource,\n): BioTemplateWorkspaceComponentBindings {\n return {\n componentBindings: source.componentBindings,\n componentBindingsById: source.componentBindingsById,\n componentImports: source.componentImports,\n componentProps: source.componentProps,\n componentPropsById: source.componentPropsById,\n componentPropsByComponent: source.componentPropsByComponent,\n componentSnippets: source.componentSnippets,\n componentUsage: source.componentUsage,\n getComponentProps: source.getComponentProps,\n }\n}\n\n/** Keys of {@link BioTemplateWorkspaceComponentBindings} that are plain (non-reactive) values, lifted to `ComputedRef`s by {@link liftWorkspaceComponentBindings}. */\nexport type LiftedBioTemplateWorkspaceComponentBindings =\n { [K in Exclude<keyof BioTemplateWorkspaceComponentBindings, 'getComponentProps'>]: ComputedRef<BioTemplateWorkspaceComponentBindings[K]> }\n & { getComponentProps: BioTemplateWorkspaceComponentBindings['getComponentProps'] }\n\n/**\n * `computed()`-lifted version of {@link flattenWorkspaceComponentBindings} for composables\n * that hold their resolved workspace behind a `ComputedRef` (e.g. a regenerated workspace\n * swapped in via `shallowRef`/`effectScope`), so each key stays independently reactive\n * instead of forcing consumers to unwrap the whole workspace to read one field.\n * `getComponentProps` stays a plain callable function, matching the un-lifted composables.\n *\n * @example Recommended\n * ```ts\n * const workspace = computed(() => workspaceRef.value)\n * const { componentBindings, componentProps, getComponentProps } = liftWorkspaceComponentBindings(workspace)\n * ```\n */\nexport function liftWorkspaceComponentBindings<TSource extends BioTemplateWorkspaceComponentSource>(\n workspace: ComputedRef<TSource>,\n): LiftedBioTemplateWorkspaceComponentBindings {\n return {\n componentBindings: computed(() => workspace.value.componentBindings),\n componentBindingsById: computed(() => workspace.value.componentBindingsById),\n componentImports: computed(() => workspace.value.componentImports),\n componentProps: computed(() => workspace.value.componentProps),\n componentPropsById: computed(() => workspace.value.componentPropsById),\n componentPropsByComponent: computed(() => workspace.value.componentPropsByComponent),\n componentSnippets: computed(() => workspace.value.componentSnippets),\n componentUsage: computed(() => workspace.value.componentUsage),\n getComponentProps: (component: string, options?: BioTemplateComponentPropsLookupOptions) =>\n workspace.value.getComponentProps(component, options),\n }\n}\n","import type {\n BioTemplateEnvelope,\n TemplateCollectionEnvelope,\n} from '../templates'\nimport type {\n ControlWorkspaceFormBinding,\n ControlWorkspaceOptions,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlSchemaReturn,\n UseControlWorkspaceReturn,\n} from './controlSchemaTypes'\nimport {\n useControlWorkspace,\n} from './useControlSchema'\nimport {\n useBioTemplateControls,\n type BioTemplateControlSchema,\n type BioTemplateControlTarget,\n} from './useBioTemplateControls'\nimport {\n useBioTemplateComponents,\n type UseBioTemplateComponentsReturn,\n} from './useBioTemplateComponents'\nimport {\n flattenWorkspaceComponentBindings,\n type BioTemplateWorkspaceComponentBindings,\n} from './flattenWorkspaceBindings'\n\nexport type BioTemplateWorkspaceTarget = BioTemplateControlTarget\n\nexport interface BioTemplateRendererBinding {\n target: BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope\n}\n\nexport interface BioTemplateWorkspaceBindings extends BioTemplateWorkspaceComponentBindings {\n renderer: BioTemplateRendererBinding | null\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: UseControlWorkspaceReturn<BioTemplateControlSchema>['bindings']['topBar']\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n pillNav: ControlWorkspacePillNavBinding\n}\n\nexport interface UseBioTemplateWorkspaceReturn extends BioTemplateWorkspaceComponentBindings {\n target: BioTemplateWorkspaceTarget\n controls: UseControlSchemaReturn<BioTemplateControlSchema>\n workspace: UseControlWorkspaceReturn<BioTemplateControlSchema>\n controlSchema: BioTemplateControlSchema\n components: UseBioTemplateComponentsReturn\n values: UseControlWorkspaceReturn<BioTemplateControlSchema>['values']\n activeView: UseControlWorkspaceReturn<BioTemplateControlSchema>['activeView']\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: UseControlWorkspaceReturn<BioTemplateControlSchema>['topBar']\n pillNav: ControlWorkspacePillNavBinding\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n bindings: BioTemplateWorkspaceBindings\n renderer: BioTemplateRendererBinding | null\n}\n\n/**\n * One-stop wiring for BioTemplateRenderer, FormBuilder, AppSidebar, and template-aware SDK components.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useBioTemplateWorkspace(\n target: BioTemplateWorkspaceTarget,\n options: ControlWorkspaceOptions = {}\n): UseBioTemplateWorkspaceReturn {\n const controls = useBioTemplateControls(target, options)\n const workspace = useControlWorkspace(controls.controls, options)\n const components = useBioTemplateComponents(target)\n const renderer = isTemplateObjectTarget(target) ? { target } : null\n const componentBindings = flattenWorkspaceComponentBindings({\n componentBindings: components.bindings,\n componentBindingsById: components.componentBindingsById,\n componentImports: components.imports,\n componentProps: components.componentProps,\n componentPropsById: components.componentPropsById,\n componentPropsByComponent: components.componentPropsByComponent,\n componentSnippets: components.snippets,\n componentUsage: components.usage,\n getComponentProps: components.getComponentProps,\n })\n const bindings: BioTemplateWorkspaceBindings = {\n renderer,\n form: workspace.bindings.form,\n sidebar: workspace.bindings.sidebar,\n topBar: workspace.bindings.topBar,\n topBarSettings: workspace.bindings.topBarSettings,\n pillNav: workspace.bindings.pillNav,\n ...componentBindings,\n }\n\n return {\n target,\n controls,\n workspace,\n controlSchema: controls.controls,\n components,\n values: workspace.values,\n activeView: workspace.activeView,\n form: workspace.form,\n sidebar: workspace.sidebar,\n topBar: workspace.topBar,\n pillNav: workspace.pillNav,\n topBarSettings: workspace.topBarSettings,\n bindings,\n renderer,\n ...componentBindings,\n }\n}\n\nfunction isTemplateObjectTarget(\n target: BioTemplateWorkspaceTarget\n): target is BioTemplateEnvelope<unknown> | TemplateCollectionEnvelope {\n return typeof target !== 'string'\n}\n","import {\n computed,\n effectScope,\n getCurrentScope,\n onScopeDispose,\n shallowRef,\n watch,\n type ComputedRef,\n type EffectScope,\n type Ref,\n} from 'vue'\nimport {\n createBioTemplatePackCollection,\n getBioTemplatePackInfo,\n type BioTemplatePackEntry,\n type TemplateCollectionEnvelope,\n type TemplatePackId,\n} from '../templates'\nimport {\n useTemplateCollection,\n type UseTemplateCollectionOptions,\n type UseTemplateCollectionReturn,\n} from './useTemplateCollection'\nimport {\n useBioTemplateWorkspace,\n type BioTemplateRendererBinding,\n type BioTemplateWorkspaceBindings,\n type UseBioTemplateWorkspaceReturn,\n} from './useBioTemplateWorkspace'\nimport {\n liftWorkspaceComponentBindings,\n} from './flattenWorkspaceBindings'\nimport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentSnippet,\n BioTemplateComponentUsage,\n} from './useBioTemplateComponents'\n\nexport type UseBioTemplatePackWorkspaceOptions = UseTemplateCollectionOptions\n\nexport interface UseBioTemplatePackWorkspaceReturn {\n packId: TemplatePackId\n pack: BioTemplatePackEntry\n collection: Ref<TemplateCollectionEnvelope>\n templates: UseTemplateCollectionReturn['templates']\n templateIds: UseTemplateCollectionReturn['templateIds']\n currentExperimentId: UseTemplateCollectionReturn['currentExperimentId']\n hasCurrentExperiment: UseTemplateCollectionReturn['hasCurrentExperiment']\n loading: UseTemplateCollectionReturn['isLoading']\n saving: UseTemplateCollectionReturn['isSaving']\n error: UseTemplateCollectionReturn['error']\n lastLoadedAt: UseTemplateCollectionReturn['lastLoadedAt']\n lastSavedAt: UseTemplateCollectionReturn['lastSavedAt']\n renderer: ComputedRef<BioTemplateRendererBinding>\n workspace: ComputedRef<UseBioTemplateWorkspaceReturn>\n form: ComputedRef<UseBioTemplateWorkspaceReturn['form']>\n sidebar: ComputedRef<UseBioTemplateWorkspaceReturn['sidebar']>\n topBar: ComputedRef<UseBioTemplateWorkspaceReturn['topBar']['value']>\n pillNav: ComputedRef<UseBioTemplateWorkspaceReturn['pillNav']>\n topBarSettings: ComputedRef<UseBioTemplateWorkspaceReturn['topBarSettings']>\n bindings: ComputedRef<BioTemplateWorkspaceBindings>\n componentBindings: ComputedRef<BioTemplateComponentBinding[]>\n componentBindingsById: ComputedRef<BioTemplateComponentBindingsById>\n componentImports: ComputedRef<BioTemplateComponentImport[]>\n componentProps: ComputedRef<BioTemplateComponentPropsBinding[]>\n componentPropsById: ComputedRef<BioTemplateComponentPropsById>\n componentPropsByComponent: ComputedRef<BioTemplateComponentPropsByComponent>\n componentSnippets: ComputedRef<BioTemplateComponentSnippet[]>\n componentUsage: ComputedRef<BioTemplateComponentUsage | null>\n getComponentProps: UseBioTemplateWorkspaceReturn['getComponentProps']\n applyCollection: (value: unknown, metadata?: Record<string, unknown>) => TemplateCollectionEnvelope\n resetToDefaultCollection: () => TemplateCollectionEnvelope\n save: UseTemplateCollectionReturn['save']\n saveCurrent: UseTemplateCollectionReturn['saveCurrent']\n load: UseTemplateCollectionReturn['load']\n loadCurrent: UseTemplateCollectionReturn['loadCurrent']\n requireCurrentExperimentId: UseTemplateCollectionReturn['requireCurrentExperimentId']\n}\n\n/**\n * Create a complete workspace for a curated biology template pack from a single pack id.\n *\n * @example Recommended\n * ```ts\n * const pack = useBioTemplatePackWorkspace('cell-culture-screen')\n * await pack.loadCurrent()\n * ```\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useBioTemplatePackWorkspace(\n packId: TemplatePackId | string,\n options: UseBioTemplatePackWorkspaceOptions = {},\n): UseBioTemplatePackWorkspaceReturn {\n const pack = getBioTemplatePackInfo(packId)\n if (!pack) {\n throw new Error(`Unknown template pack '${packId}'.`)\n }\n const resolvedPack = pack\n\n const templateCollection = useTemplateCollection({\n ...options,\n initial: createDefaultCollection,\n })\n const collection = templateCollection.templateCollection\n let workspaceScope: EffectScope | undefined\n\n function createWorkspace(value: TemplateCollectionEnvelope): UseBioTemplateWorkspaceReturn {\n workspaceScope?.stop()\n workspaceScope = effectScope()\n return workspaceScope.run(() => useBioTemplateWorkspace(value))!\n }\n\n const workspaceRef = shallowRef<UseBioTemplateWorkspaceReturn>(createWorkspace(collection.value))\n const workspace = computed(() => workspaceRef.value)\n const renderer = computed<BioTemplateRendererBinding>(() => ({ target: collection.value }))\n const form = computed(() => workspace.value.form)\n const sidebar = computed(() => workspace.value.sidebar)\n const topBar = computed(() => workspace.value.topBar.value)\n const pillNav = computed(() => workspace.value.pillNav)\n const topBarSettings = computed(() => workspace.value.topBarSettings)\n const bindings = computed(() => workspace.value.bindings)\n const {\n componentBindings,\n componentBindingsById,\n componentImports,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps: getWorkspaceComponentProps,\n } = liftWorkspaceComponentBindings(workspace)\n\n watch(collection, value => {\n workspaceRef.value = createWorkspace(value)\n })\n\n if (getCurrentScope()) {\n onScopeDispose(() => workspaceScope?.stop())\n }\n\n function createDefaultCollection(): TemplateCollectionEnvelope {\n return createBioTemplatePackCollection(resolvedPack.name)\n }\n\n function applyCollection(\n value: unknown,\n metadata?: Record<string, unknown>,\n ): TemplateCollectionEnvelope {\n return templateCollection.apply(value, metadata)\n }\n\n function resetToDefaultCollection(): TemplateCollectionEnvelope {\n return templateCollection.apply(createDefaultCollection())\n }\n\n return {\n packId: resolvedPack.name,\n pack: resolvedPack,\n collection,\n templates: templateCollection.templates,\n templateIds: templateCollection.templateIds,\n currentExperimentId: templateCollection.currentExperimentId,\n hasCurrentExperiment: templateCollection.hasCurrentExperiment,\n loading: templateCollection.isLoading,\n saving: templateCollection.isSaving,\n error: templateCollection.error,\n lastLoadedAt: templateCollection.lastLoadedAt,\n lastSavedAt: templateCollection.lastSavedAt,\n renderer,\n workspace,\n form,\n sidebar,\n topBar,\n pillNav,\n topBarSettings,\n bindings,\n componentBindings,\n componentBindingsById,\n componentImports,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps: getWorkspaceComponentProps,\n applyCollection,\n resetToDefaultCollection,\n save: templateCollection.save,\n saveCurrent: templateCollection.saveCurrent,\n load: templateCollection.load,\n loadCurrent: templateCollection.loadCurrent,\n requireCurrentExperimentId: templateCollection.requireCurrentExperimentId,\n }\n}\n","import {\n computed,\n reactive,\n ref,\n watch,\n type ComputedRef,\n type Ref,\n} from 'vue'\nimport type { PillNavItem } from '../types'\nimport {\n createBioTemplatePresetCollectionFromControls,\n getBioTemplatePresetInfo,\n type BioTemplateControlValues,\n type BioTemplatePresetEntry,\n type TemplateCollectionEnvelope,\n type TemplatePresetId,\n} from '../templates'\nimport type {\n ControlWorkspaceOptions,\n ControlWorkspaceFormBinding,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlSchemaReturn,\n} from './controlSchemaTypes'\nimport {\n useTemplateCollection,\n type UseTemplateCollectionOptions,\n type UseTemplateCollectionReturn,\n} from './useTemplateCollection'\nimport {\n useBioTemplateWorkspace,\n type BioTemplateRendererBinding,\n type UseBioTemplateWorkspaceReturn,\n} from './useBioTemplateWorkspace'\nimport {\n liftWorkspaceComponentBindings,\n} from './flattenWorkspaceBindings'\nimport type {\n BioTemplateComponentBinding,\n BioTemplateComponentBindingsById,\n BioTemplateComponentImport,\n BioTemplateComponentPropsByComponent,\n BioTemplateComponentPropsBinding,\n BioTemplateComponentPropsById,\n BioTemplateComponentSnippet,\n BioTemplateComponentUsage,\n} from './useBioTemplateComponents'\nimport type {\n BioTemplateControlSchema,\n} from './useBioTemplateControls'\n\nexport interface UseBioTemplatePresetWorkspaceOptions extends UseTemplateCollectionOptions {\n /** Optional schema-rendering options for the generated FormBuilder/AppSidebar controls. */\n controlOptions?: ControlWorkspaceOptions\n /** Initial control values for the generated preset. Merged over controlOptions.initialValues. */\n initialValues?: BioTemplateControlValues\n}\n\nexport interface UseBioTemplatePresetWorkspaceReturn {\n presetId: TemplatePresetId\n presetInfo: ComputedRef<BioTemplatePresetEntry | undefined>\n presetLabel: ComputedRef<string>\n collection: Ref<TemplateCollectionEnvelope>\n templates: UseTemplateCollectionReturn['templates']\n templateIds: UseTemplateCollectionReturn['templateIds']\n currentExperimentId: UseTemplateCollectionReturn['currentExperimentId']\n hasCurrentExperiment: UseTemplateCollectionReturn['hasCurrentExperiment']\n saving: UseTemplateCollectionReturn['isSaving']\n error: UseTemplateCollectionReturn['error']\n lastSavedAt: UseTemplateCollectionReturn['lastSavedAt']\n controls: UseControlSchemaReturn<BioTemplateControlSchema>\n controlSchema: BioTemplateControlSchema\n controlValues: Ref<BioTemplateControlValues>\n controlViewIds: ComputedRef<string[]>\n controlViewItems: ComputedRef<PillNavItem[]>\n activeControlView: Ref<string>\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: ComputedRef<ControlWorkspaceTopBarBinding>\n pillNav: ControlWorkspacePillNavBinding\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n bindings: BioTemplatePresetWorkspaceBindings\n renderer: ComputedRef<BioTemplateRendererBinding>\n workspace: ComputedRef<UseBioTemplateWorkspaceReturn>\n componentBindings: ComputedRef<BioTemplateComponentBinding[]>\n componentBindingsById: ComputedRef<BioTemplateComponentBindingsById>\n componentImports: ComputedRef<BioTemplateComponentImport[]>\n componentProps: ComputedRef<BioTemplateComponentPropsBinding[]>\n componentPropsById: ComputedRef<BioTemplateComponentPropsById>\n componentPropsByComponent: ComputedRef<BioTemplateComponentPropsByComponent>\n componentSnippets: ComputedRef<BioTemplateComponentSnippet[]>\n componentUsage: ComputedRef<BioTemplateComponentUsage | null>\n getComponentProps: UseBioTemplateWorkspaceReturn['getComponentProps']\n setActiveControlView: (viewId: string) => void\n setControlValues: (values: BioTemplateControlValues) => TemplateCollectionEnvelope\n updateControlValues: (values: Partial<BioTemplateControlValues>) => TemplateCollectionEnvelope\n applyCollection: (value: TemplateCollectionEnvelope) => TemplateCollectionEnvelope\n resetToDefaultCollection: () => TemplateCollectionEnvelope\n save: UseTemplateCollectionReturn['save']\n saveCurrent: UseTemplateCollectionReturn['saveCurrent']\n}\n\nexport interface BioTemplatePresetWorkspaceBindings {\n renderer: ComputedRef<BioTemplateRendererBinding>\n form: ControlWorkspaceFormBinding\n sidebar: ControlWorkspaceSidebarBinding\n topBar: ComputedRef<ControlWorkspaceTopBarBinding>\n topBarSettings: ControlWorkspaceTopBarSettingsBinding\n pillNav: ControlWorkspacePillNavBinding\n componentBindings: ComputedRef<BioTemplateComponentBinding[]>\n componentBindingsById: ComputedRef<BioTemplateComponentBindingsById>\n componentProps: ComputedRef<BioTemplateComponentPropsBinding[]>\n componentPropsById: ComputedRef<BioTemplateComponentPropsById>\n componentPropsByComponent: ComputedRef<BioTemplateComponentPropsByComponent>\n componentSnippets: ComputedRef<BioTemplateComponentSnippet[]>\n componentUsage: ComputedRef<BioTemplateComponentUsage | null>\n getComponentProps: UseBioTemplateWorkspaceReturn['getComponentProps']\n}\n\n/**\n * Create a complete editable WellPlate/DoseCalculator workspace for dose design from a built-in biology template preset with current-experiment save wiring.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useBioTemplatePresetWorkspace(\n presetId: TemplatePresetId,\n options: UseBioTemplatePresetWorkspaceOptions = {},\n): UseBioTemplatePresetWorkspaceReturn {\n const { controlOptions, initialValues, ...collectionOptions } = options\n const resolvedControlOptions = mergeInitialValues(controlOptions, initialValues)\n const presetWorkspace = useBioTemplateWorkspace(presetId, resolvedControlOptions)\n const presetInfo = computed(() => getBioTemplatePresetInfo(presetId))\n const presetLabel = computed(() => presetInfo.value?.label ?? humanizePresetId(presetId))\n const controls = presetWorkspace.controls\n const controlValues = ref<BioTemplateControlValues>({ ...controls.initialValues })\n const controlViewIds = computed(() => controls.viewIds)\n const controlViewItems = computed(() => controls.viewItems)\n const activeControlView = ref(controls.defaultView)\n const templateCollection = useTemplateCollection({\n ...collectionOptions,\n initial: createDefaultCollection,\n })\n const collection = templateCollection.templateCollection\n const workspace = computed(() => useBioTemplateWorkspace(collection.value, resolvedControlOptions))\n const renderer = computed<BioTemplateRendererBinding>(() => ({ target: collection.value }))\n const {\n componentBindings,\n componentBindingsById,\n componentImports,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps,\n } = liftWorkspaceComponentBindings(workspace)\n const form = reactive({\n ...controls.form,\n modelValue: controlValues.value,\n 'onUpdate:modelValue': setControlValues,\n }) as ControlWorkspaceFormBinding\n const sidebar = reactive({\n ...controls.sidebar,\n activeView: activeControlView.value,\n modelValue: controlValues.value,\n 'onUpdate:modelValue': setControlValues,\n values: controlValues.value,\n 'onUpdate:values': setControlValues,\n }) as ControlWorkspaceSidebarBinding\n const pillNav = reactive({\n items: controls.viewItems,\n currentItemId: activeControlView.value,\n onSelect: (item: { id: string }) => setActiveControlView(item.id),\n }) as ControlWorkspacePillNavBinding\n const topBarSettings = reactive({\n showSettings: true,\n settingsConfig: {\n ...controls.topBarSettingsConfig,\n values: controlValues.value,\n },\n onSettingsValuesChange: setControlValues,\n }) as ControlWorkspaceTopBarSettingsBinding\n const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({\n pillNav: pillNav.items,\n currentPillId: pillNav.currentItemId,\n onPillSelect: pillNav.onSelect,\n ...topBarSettings,\n }))\n\n const bindings: BioTemplatePresetWorkspaceBindings = {\n renderer,\n form,\n sidebar,\n topBar: topBarProps,\n topBarSettings,\n pillNav,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps,\n }\n\n function createDefaultCollection(): TemplateCollectionEnvelope {\n return createBioTemplatePresetCollectionFromControls(presetId, controls.initialValues)\n }\n\n watch(\n controlValues,\n (values) => {\n syncControlValueBindings(values)\n templateCollection.apply(createBioTemplatePresetCollectionFromControls(presetId, values))\n },\n { deep: true },\n )\n\n watch(activeControlView, (viewId) => {\n sidebar.activeView = viewId\n pillNav.currentItemId = viewId\n }, { flush: 'sync' })\n watch(() => sidebar.activeView, setActiveControlView, { flush: 'sync' })\n watch(() => pillNav.currentItemId, setActiveControlView, { flush: 'sync' })\n\n function applyCollection(value: TemplateCollectionEnvelope): TemplateCollectionEnvelope {\n return templateCollection.apply(value)\n }\n\n function setActiveControlView(viewId: string): void {\n if (!controlViewIds.value.includes(viewId)) return\n activeControlView.value = viewId\n }\n\n function setControlValues(values: BioTemplateControlValues): TemplateCollectionEnvelope {\n const nextValues = { ...values }\n controlValues.value = nextValues\n syncControlValueBindings(nextValues)\n return templateCollection.apply(createBioTemplatePresetCollectionFromControls(presetId, nextValues))\n }\n\n function updateControlValues(values: Partial<BioTemplateControlValues>): TemplateCollectionEnvelope {\n return setControlValues({\n ...controlValues.value,\n ...values,\n })\n }\n\n function resetToDefaultCollection(): TemplateCollectionEnvelope {\n return setControlValues({ ...controls.initialValues })\n }\n\n function syncControlValueBindings(values: BioTemplateControlValues): void {\n form.modelValue = values\n sidebar.modelValue = values\n sidebar.values = values\n topBarSettings.settingsConfig = {\n ...topBarSettings.settingsConfig,\n values,\n }\n }\n\n return {\n presetId,\n presetInfo,\n presetLabel,\n collection,\n templates: templateCollection.templates,\n templateIds: templateCollection.templateIds,\n currentExperimentId: templateCollection.currentExperimentId,\n hasCurrentExperiment: templateCollection.hasCurrentExperiment,\n saving: templateCollection.isSaving,\n error: templateCollection.error,\n lastSavedAt: templateCollection.lastSavedAt,\n controls,\n controlSchema: controls.controls,\n controlValues,\n controlViewIds,\n controlViewItems,\n activeControlView,\n form,\n sidebar,\n topBar: topBarProps,\n pillNav,\n topBarSettings,\n bindings,\n renderer,\n workspace,\n componentBindings,\n componentBindingsById,\n componentImports,\n componentProps,\n componentPropsById,\n componentPropsByComponent,\n componentSnippets,\n componentUsage,\n getComponentProps,\n setActiveControlView,\n setControlValues,\n updateControlValues,\n applyCollection,\n resetToDefaultCollection,\n save: templateCollection.save,\n saveCurrent: templateCollection.saveCurrent,\n }\n}\n\nfunction humanizePresetId(value: string): string {\n return value\n .replace(/[-_]+/g, ' ')\n .replace(/\\b\\w/g, match => match.toUpperCase())\n}\n\nfunction mergeInitialValues(\n controlOptions: ControlWorkspaceOptions | undefined,\n initialValues: BioTemplateControlValues | undefined,\n): ControlWorkspaceOptions | undefined {\n if (initialValues === undefined) return controlOptions\n return {\n ...(controlOptions ?? {}),\n initialValues: {\n ...(controlOptions?.initialValues ?? {}),\n ...initialValues,\n },\n }\n}\n","import { computed, toValue, type ComputedRef, type Ref } from 'vue'\nimport type { GroupItem } from '../types'\n\nexport type GroupAssignmentZone = 'zone1' | 'zone2'\n\nexport type GroupAssignmentSource<T> =\n | T\n | Ref<T>\n | ComputedRef<T>\n | (() => T)\n\nexport interface GroupAssignmentState {\n group1: string[]\n group2: string[]\n}\n\nexport interface UseGroupAssignmentOptions {\n groups: GroupAssignmentSource<readonly GroupItem[]>\n group1: GroupAssignmentSource<readonly string[]>\n group2: GroupAssignmentSource<readonly string[]>\n label1?: GroupAssignmentSource<string | null | undefined>\n label2?: GroupAssignmentSource<string | null | undefined>\n minPerGroup?: GroupAssignmentSource<number | null | undefined>\n}\n\nexport interface UseGroupAssignmentReturn {\n unassignedGroups: ComputedRef<GroupItem[]>\n zone1Groups: ComputedRef<GroupItem[]>\n zone2Groups: ComputedRef<GroupItem[]>\n zone1Count: ComputedRef<number>\n zone2Count: ComputedRef<number>\n isValid: ComputedRef<boolean>\n validationMessage: ComputedRef<string | null>\n getZoneForGroup: (groupName: string) => GroupAssignmentZone | null\n assignToZone: (groupName: string, zone: GroupAssignmentZone) => GroupAssignmentState\n removeFromZone: (groupName: string, zone: GroupAssignmentZone) => GroupAssignmentState\n clearAll: () => GroupAssignmentState\n}\n\n/**\n * Shared two-zone group assignment model for control/treatment style workflows.\n *\n * @deprecated Scheduled for removal in MINT 1.4; no SDK replacement.\n */\nexport function useGroupAssignment(options: UseGroupAssignmentOptions): UseGroupAssignmentReturn {\n const groups = computed(() => [...toValue(options.groups)])\n const group1 = computed(() => [...toValue(options.group1)])\n const group2 = computed(() => [...toValue(options.group2)])\n const label1 = computed(() => toValue(options.label1) || 'Control')\n const label2 = computed(() => toValue(options.label2) || 'Treatment')\n const minPerGroup = computed(() => normalizeMinimum(toValue(options.minPerGroup)))\n const group1Set = computed(() => new Set(group1.value))\n const group2Set = computed(() => new Set(group2.value))\n\n const unassignedGroups = computed(() =>\n groups.value.filter(group => !group1Set.value.has(group.name) && !group2Set.value.has(group.name))\n )\n\n const zone1Groups = computed(() =>\n groups.value.filter(group => group1Set.value.has(group.name))\n )\n\n const zone2Groups = computed(() =>\n groups.value.filter(group => group2Set.value.has(group.name))\n )\n\n const zone1Count = computed(() =>\n zone1Groups.value.reduce((sum, group) => sum + group.count, 0)\n )\n\n const zone2Count = computed(() =>\n zone2Groups.value.reduce((sum, group) => sum + group.count, 0)\n )\n\n const isValid = computed(() =>\n group1.value.length >= minPerGroup.value &&\n group2.value.length >= minPerGroup.value\n )\n\n const validationMessage = computed(() => {\n if (isValid.value) return null\n const missing1 = Math.max(0, minPerGroup.value - group1.value.length)\n const missing2 = Math.max(0, minPerGroup.value - group2.value.length)\n const parts: string[] = []\n if (missing1 > 0) parts.push(`${missing1} more to ${label1.value}`)\n if (missing2 > 0) parts.push(`${missing2} more to ${label2.value}`)\n return `Add ${parts.join(' and ')}`\n })\n\n function getZoneForGroup(groupName: string): GroupAssignmentZone | null {\n if (group1Set.value.has(groupName)) return 'zone1'\n if (group2Set.value.has(groupName)) return 'zone2'\n return null\n }\n\n function assignToZone(groupName: string, zone: GroupAssignmentZone): GroupAssignmentState {\n const next = removeFromBoth(groupName)\n if (zone === 'zone1') {\n return {\n group1: [...next.group1, groupName],\n group2: next.group2,\n }\n }\n return {\n group1: next.group1,\n group2: [...next.group2, groupName],\n }\n }\n\n function removeFromZone(groupName: string, zone: GroupAssignmentZone): GroupAssignmentState {\n if (zone === 'zone1') {\n return {\n group1: group1.value.filter(name => name !== groupName),\n group2: group2.value,\n }\n }\n return {\n group1: group1.value,\n group2: group2.value.filter(name => name !== groupName),\n }\n }\n\n function clearAll(): GroupAssignmentState {\n return { group1: [], group2: [] }\n }\n\n function removeFromBoth(groupName: string): GroupAssignmentState {\n return {\n group1: group1.value.filter(name => name !== groupName),\n group2: group2.value.filter(name => name !== groupName),\n }\n }\n\n return {\n unassignedGroups,\n zone1Groups,\n zone2Groups,\n zone1Count,\n zone2Count,\n isValid,\n validationMessage,\n getZoneForGroup,\n assignToZone,\n removeFromZone,\n clearAll,\n }\n}\n\nfunction normalizeMinimum(value: number | null | undefined): number {\n if (value === null || value === undefined || !Number.isFinite(value)) return 1\n return Math.max(0, Math.floor(value))\n}\n","/**\n * Composable for generating dilution series used in plate-based experiments.\n * Provides geometric series generation from presets (2x, 3x, ½ log, 10x)\n * and utility functions for series manipulation.\n */\n\nexport interface LevelEntry {\n value: number\n replicates: number\n}\n\nexport interface DilutionPreset {\n label: string\n factor: number | 'half-log'\n}\n\nexport const DEFAULT_PRESETS: DilutionPreset[] = [\n { label: '2x', factor: 2 },\n { label: '3x', factor: 3 },\n { label: '½ log', factor: 'half-log' },\n { label: '10x', factor: 10 },\n]\n\nexport const DEFAULT_UNITS = ['µM', 'nM', 'mM', 'pM']\n\nfunction resolveFactor(factor: number | 'half-log'): number {\n return factor === 'half-log' ? Math.sqrt(10) : factor\n}\n\nfunction roundToSignificant(value: number, digits: number = 4): number {\n if (value === 0) return 0\n const magnitude = Math.floor(Math.log10(Math.abs(value))) + 1\n const factor = Math.pow(10, digits - magnitude)\n return Math.round(value * factor) / factor\n}\n\nexport function generateDilutionSeries(\n startConcentration: number,\n count: number,\n factor: number | 'half-log',\n defaultReplicates: number = 1,\n): LevelEntry[] {\n if (count < 1 || startConcentration <= 0) return []\n\n const divisor = resolveFactor(factor)\n const levels: LevelEntry[] = []\n\n for (let i = 0; i < count; i++) {\n levels.push({\n value: roundToSignificant(startConcentration / Math.pow(divisor, i)),\n replicates: defaultReplicates,\n })\n }\n\n return levels\n}\n\nexport interface UseReagentSeriesReturn {\n generateSeries: (\n start: number,\n count: number,\n factor: number | 'half-log',\n defaultReplicates?: number,\n ) => LevelEntry[]\n sortLevels: (levels: LevelEntry[], order?: 'asc' | 'desc') => LevelEntry[]\n totalPositions: (levels: LevelEntry[]) => number\n}\n\n/** Generates and sorts geometric dilution series (2x, 3x, ½ log, 10x) for plate-based experiments. */\nexport function useReagentSeries(): UseReagentSeriesReturn {\n function generateSeries(\n start: number,\n count: number,\n factor: number | 'half-log',\n defaultReplicates: number = 1,\n ): LevelEntry[] {\n return generateDilutionSeries(start, count, factor, defaultReplicates)\n }\n\n function sortLevels(levels: LevelEntry[], order: 'asc' | 'desc' = 'desc'): LevelEntry[] {\n return [...levels].sort((a, b) =>\n order === 'desc' ? b.value - a.value : a.value - b.value,\n )\n }\n\n function totalPositions(levels: LevelEntry[]): number {\n return levels.reduce((sum, l) => sum + l.replicates, 0)\n }\n\n return { generateSeries, sortLevels, totalPositions }\n}\n","import type { ProtocolStepType } from '../types'\n\n// Parameter definition for step templates\nexport interface ParameterDefinition {\n key: string\n label: string\n type: 'number' | 'text' | 'select' | 'concentration' | 'temperature' | 'duration' | 'reagent'\n unit?: string\n options?: Array<{ value: string; label: string }>\n required?: boolean\n default?: unknown\n min?: number\n max?: number\n placeholder?: string\n}\n\n// Step template definition\nexport interface StepTemplate {\n id: string\n type: ProtocolStepType\n name: string\n description?: string\n defaultDuration?: number\n parameters: ParameterDefinition[]\n isBuiltIn?: boolean\n}\n\nexport const BUILT_IN_PROTOCOL_TEMPLATES: StepTemplate[] = [\n {\n id: 'builtin-incubation',\n type: 'incubation',\n name: 'Incubation',\n description: 'Incubate samples at specified conditions',\n defaultDuration: 60,\n isBuiltIn: true,\n parameters: [\n {\n key: 'temperature',\n label: 'Temperature',\n type: 'temperature',\n unit: '°C',\n required: true,\n default: 37,\n min: -80,\n max: 100,\n },\n {\n key: 'duration',\n label: 'Duration',\n type: 'duration',\n unit: 'hours',\n required: true,\n default: 24,\n min: 0,\n },\n {\n key: 'co2',\n label: 'CO2',\n type: 'number',\n unit: '%',\n required: false,\n default: 5,\n min: 0,\n max: 100,\n },\n {\n key: 'humidity',\n label: 'Humidity',\n type: 'number',\n unit: '%',\n required: false,\n default: 95,\n min: 0,\n max: 100,\n },\n ],\n },\n {\n id: 'builtin-wash',\n type: 'wash',\n name: 'Wash',\n description: 'Wash samples with buffer',\n defaultDuration: 5,\n isBuiltIn: true,\n parameters: [\n {\n key: 'buffer',\n label: 'Buffer',\n type: 'select',\n required: true,\n default: 'PBS',\n options: [\n { value: 'PBS', label: 'PBS' },\n { value: 'PBST', label: 'PBST' },\n { value: 'TBS', label: 'TBS' },\n { value: 'TBST', label: 'TBST' },\n { value: 'Water', label: 'Water' },\n { value: 'Other', label: 'Other' },\n ],\n },\n {\n key: 'volume',\n label: 'Volume',\n type: 'number',\n unit: 'µL',\n required: true,\n default: 200,\n min: 0,\n },\n {\n key: 'cycles',\n label: 'Wash Cycles',\n type: 'number',\n required: true,\n default: 3,\n min: 1,\n max: 10,\n },\n ],\n },\n {\n id: 'builtin-addition',\n type: 'addition',\n name: 'Addition',\n description: 'Add reagent or compound to samples',\n defaultDuration: 5,\n isBuiltIn: true,\n parameters: [\n {\n key: 'reagent',\n label: 'Reagent',\n type: 'text',\n required: true,\n placeholder: 'Enter reagent name',\n },\n {\n key: 'volume',\n label: 'Volume',\n type: 'number',\n unit: 'µL',\n required: true,\n default: 100,\n min: 0,\n },\n {\n key: 'concentration',\n label: 'Concentration',\n type: 'concentration',\n required: false,\n },\n ],\n },\n {\n id: 'builtin-measurement',\n type: 'measurement',\n name: 'Measurement',\n description: 'Take measurements using specified instrument',\n defaultDuration: 15,\n isBuiltIn: true,\n parameters: [\n {\n key: 'instrument',\n label: 'Instrument',\n type: 'select',\n required: true,\n options: [\n { value: 'plate_reader', label: 'Plate Reader' },\n { value: 'microscope', label: 'Microscope' },\n { value: 'flow_cytometer', label: 'Flow Cytometer' },\n { value: 'spectrophotometer', label: 'Spectrophotometer' },\n { value: 'other', label: 'Other' },\n ],\n },\n {\n key: 'readout',\n label: 'Readout Type',\n type: 'text',\n required: false,\n placeholder: 'e.g., Absorbance 450nm',\n },\n {\n key: 'notes',\n label: 'Parameters',\n type: 'text',\n required: false,\n placeholder: 'Additional parameters',\n },\n ],\n },\n {\n id: 'builtin-centrifuge',\n type: 'centrifuge',\n name: 'Centrifuge',\n description: 'Centrifuge samples',\n defaultDuration: 10,\n isBuiltIn: true,\n parameters: [\n {\n key: 'speed',\n label: 'Speed',\n type: 'number',\n unit: 'RPM',\n required: true,\n default: 1000,\n min: 100,\n max: 20000,\n },\n {\n key: 'duration',\n label: 'Duration',\n type: 'number',\n unit: 'min',\n required: true,\n default: 5,\n min: 1,\n },\n {\n key: 'temperature',\n label: 'Temperature',\n type: 'temperature',\n unit: '°C',\n required: false,\n default: 4,\n min: -10,\n max: 40,\n },\n ],\n },\n {\n id: 'builtin-transfer',\n type: 'transfer',\n name: 'Transfer',\n description: 'Transfer samples between containers',\n defaultDuration: 10,\n isBuiltIn: true,\n parameters: [\n {\n key: 'source',\n label: 'Source',\n type: 'text',\n required: true,\n placeholder: 'Source container',\n },\n {\n key: 'destination',\n label: 'Destination',\n type: 'text',\n required: true,\n placeholder: 'Destination container',\n },\n {\n key: 'volume',\n label: 'Volume',\n type: 'number',\n unit: 'µL',\n required: true,\n default: 100,\n min: 0,\n },\n ],\n },\n {\n id: 'builtin-mix',\n type: 'mix',\n name: 'Mix',\n description: 'Mix samples',\n defaultDuration: 5,\n isBuiltIn: true,\n parameters: [\n {\n key: 'method',\n label: 'Method',\n type: 'select',\n required: true,\n default: 'pipette',\n options: [\n { value: 'pipette', label: 'Pipette mixing' },\n { value: 'vortex', label: 'Vortex' },\n { value: 'shaker', label: 'Orbital shaker' },\n { value: 'inversion', label: 'Inversion' },\n ],\n },\n {\n key: 'duration',\n label: 'Duration',\n type: 'number',\n unit: 'sec',\n required: false,\n default: 30,\n min: 1,\n },\n {\n key: 'speed',\n label: 'Speed/Intensity',\n type: 'text',\n required: false,\n placeholder: 'e.g., 300 RPM',\n },\n ],\n },\n {\n id: 'builtin-custom',\n type: 'custom',\n name: 'Custom Step',\n description: 'Custom protocol step',\n defaultDuration: 15,\n isBuiltIn: true,\n parameters: [\n {\n key: 'description',\n label: 'Description',\n type: 'text',\n required: true,\n placeholder: 'Describe the step',\n },\n {\n key: 'notes',\n label: 'Notes',\n type: 'text',\n required: false,\n placeholder: 'Additional notes',\n },\n ],\n },\n]\n","import { ref, computed, type Ref, type ComputedRef } from 'vue'\nimport type { ProtocolStep, ProtocolStepType, ProtocolStepStatus } from '../types'\nimport {\n BUILT_IN_PROTOCOL_TEMPLATES,\n type ParameterDefinition,\n type StepTemplate,\n} from './protocolTemplateCatalog'\n\nexport type { ParameterDefinition, StepTemplate } from './protocolTemplateCatalog'\n\n// Validation result\nexport interface ValidationResult {\n valid: boolean\n errors: Record<string, string>\n}\n\nexport interface UseProtocolTemplatesReturn {\n builtInTemplates: StepTemplate[]\n customTemplates: Ref<StepTemplate[]>\n allTemplates: ComputedRef<StepTemplate[]>\n getTemplateByType: (type: ProtocolStepType) => StepTemplate | undefined\n getTemplateById: (id: string) => StepTemplate | undefined\n saveCustomTemplate: (template: StepTemplate) => void\n deleteCustomTemplate: (templateId: string) => void\n validateStep: (step: ProtocolStep, template: StepTemplate) => ValidationResult\n createStepFromTemplate: (template: StepTemplate, overrides?: Partial<ProtocolStep>) => ProtocolStep\n formatParameterValue: (value: unknown, param: ParameterDefinition) => string\n}\n\n// Storage key for custom templates\nconst STORAGE_KEY = 'mint-custom-protocol-templates'\n\nfunction isStepTemplate(value: unknown): value is StepTemplate {\n if (!value || typeof value !== 'object') return false\n const candidate = value as Partial<StepTemplate>\n return (\n typeof candidate.id === 'string'\n && typeof candidate.type === 'string'\n && typeof candidate.name === 'string'\n && Array.isArray(candidate.parameters)\n )\n}\n\nfunction loadCustomTemplates(): StepTemplate[] {\n try {\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored) {\n const parsed = JSON.parse(stored)\n return Array.isArray(parsed) ? parsed.filter(isStepTemplate) : []\n }\n } catch {\n // Ignore errors\n }\n return []\n}\n\nfunction saveCustomTemplatesToStorage(templates: StepTemplate[]) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(templates))\n } catch {\n // Ignore errors\n }\n}\n\n/** Provides built-in and custom protocol step templates with validation and step creation helpers. */\nexport function useProtocolTemplates(): UseProtocolTemplatesReturn {\n const customTemplates = ref<StepTemplate[]>(loadCustomTemplates())\n\n const allTemplates = computed(() => {\n return [...BUILT_IN_PROTOCOL_TEMPLATES, ...customTemplates.value]\n })\n\n function getTemplateByType(type: ProtocolStepType): StepTemplate | undefined {\n // First check custom templates, then built-in\n return (\n customTemplates.value.find((t) => t.type === type) ||\n BUILT_IN_PROTOCOL_TEMPLATES.find((t) => t.type === type)\n )\n }\n\n function getTemplateById(id: string): StepTemplate | undefined {\n return (\n customTemplates.value.find((t) => t.id === id) ||\n BUILT_IN_PROTOCOL_TEMPLATES.find((t) => t.id === id)\n )\n }\n\n function saveCustomTemplate(template: StepTemplate) {\n const newTemplate = {\n ...template,\n isBuiltIn: false,\n id: template.id || `custom-${Date.now()}`,\n }\n\n const index = customTemplates.value.findIndex((t) => t.id === newTemplate.id)\n if (index >= 0) {\n customTemplates.value[index] = newTemplate\n } else {\n customTemplates.value.push(newTemplate)\n }\n\n saveCustomTemplatesToStorage(customTemplates.value)\n }\n\n function deleteCustomTemplate(templateId: string) {\n const index = customTemplates.value.findIndex((t) => t.id === templateId)\n if (index >= 0) {\n customTemplates.value.splice(index, 1)\n saveCustomTemplatesToStorage(customTemplates.value)\n }\n }\n\n function validateStep(step: ProtocolStep, template: StepTemplate): ValidationResult {\n const errors: Record<string, string> = {}\n\n if (!step.name || step.name.trim() === '') {\n errors.name = 'Step name is required'\n }\n\n for (const param of template.parameters) {\n if (param.required) {\n const value = step.parameters?.[param.key]\n if (value === undefined || value === null || value === '') {\n errors[param.key] = `${param.label} is required`\n }\n }\n\n if (param.type === 'number' || param.type === 'temperature' || param.type === 'duration') {\n const value = step.parameters?.[param.key]\n if (value !== undefined && value !== null && value !== '') {\n const numValue = Number(value)\n if (isNaN(numValue)) {\n errors[param.key] = `${param.label} must be a number`\n } else {\n if (param.min !== undefined && numValue < param.min) {\n errors[param.key] = `${param.label} must be at least ${param.min}`\n }\n if (param.max !== undefined && numValue > param.max) {\n errors[param.key] = `${param.label} must be at most ${param.max}`\n }\n }\n }\n }\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors,\n }\n }\n\n function createStepFromTemplate(\n template: StepTemplate,\n overrides?: Partial<ProtocolStep>\n ): ProtocolStep {\n // Build default parameters from template\n const parameters: Record<string, unknown> = {}\n for (const param of template.parameters) {\n if (param.default !== undefined) {\n parameters[param.key] = param.default\n }\n }\n\n return {\n id: `step-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n type: template.type,\n name: template.name,\n description: template.description,\n duration: template.defaultDuration,\n status: 'pending' as ProtocolStepStatus,\n parameters,\n order: 0,\n ...overrides,\n }\n }\n\n function formatParameterValue(value: unknown, param: ParameterDefinition): string {\n if (value === undefined || value === null || value === '') {\n return '-'\n }\n\n if (param.type === 'select' && param.options) {\n const option = param.options.find((o) => o.value === value)\n if (option) return option.label\n }\n\n if (param.type === 'concentration' && typeof value === 'object') {\n const conc = value as { value: number; unit: string }\n return `${conc.value} ${conc.unit}`\n }\n\n const strValue = String(value)\n if (param.unit) {\n return `${strValue} ${param.unit}`\n }\n\n return strValue\n }\n\n return {\n builtInTemplates: BUILT_IN_PROTOCOL_TEMPLATES,\n customTemplates,\n allTemplates,\n getTemplateByType,\n getTemplateById,\n saveCustomTemplate,\n deleteCustomTemplate,\n validateStep,\n createStepFromTemplate,\n formatParameterValue,\n }\n}\n","import {\n onScopeDispose,\n ref,\n watch,\n type Ref,\n type WatchOptions,\n type WatchSource,\n type WatchStopHandle,\n} from 'vue'\n\nexport type DebouncedWatchCleanup = () => void\nexport type DebouncedWatchSource<T> = WatchSource<T> | WatchSource<unknown>[] | (() => T)\nexport type DebouncedWatchCallback<T> = (\n value: T,\n oldValue: T | undefined,\n onCleanup: (cleanup: DebouncedWatchCleanup) => void,\n) => void | Promise<void>\n\nexport interface UseDebouncedWatchOptions extends WatchOptions {\n /** Debounce interval in milliseconds. */\n delay?: number\n}\n\nexport interface UseDebouncedWatchReturn {\n /** Whether a callback is currently scheduled. */\n isPending: Ref<boolean>\n /** Cancel the pending callback without stopping the watcher. */\n cancel: () => void\n /** Run the pending callback immediately, if one is scheduled. */\n flush: () => void\n /** Stop the watcher and clear pending callbacks. */\n stop: WatchStopHandle\n}\n\n/** Watch a Vue source with debounced callback execution and explicit cancel/flush controls. */\nexport function useDebouncedWatch<T>(\n source: DebouncedWatchSource<T>,\n callback: DebouncedWatchCallback<T>,\n options: UseDebouncedWatchOptions = {},\n): UseDebouncedWatchReturn {\n const { delay = 300, ...watchOptions } = options\n const isPending = ref(false)\n\n let timer: ReturnType<typeof setTimeout> | null = null\n let hasLatestValue = false\n let latestValue: T\n let latestOldValue: T | undefined\n let callbackCleanup: DebouncedWatchCleanup | null = null\n let stopped = false\n\n function clearTimer(): void {\n if (timer) {\n clearTimeout(timer)\n timer = null\n }\n isPending.value = false\n }\n\n function runCallbackCleanup(): void {\n if (!callbackCleanup) return\n callbackCleanup()\n callbackCleanup = null\n }\n\n function cancel(): void {\n clearTimer()\n hasLatestValue = false\n latestOldValue = undefined\n }\n\n function flush(): void {\n if (!hasLatestValue) return\n const value = latestValue\n const oldValue = latestOldValue\n cancel()\n runCallbackCleanup()\n void callback(value, oldValue, (cleanup) => {\n callbackCleanup = cleanup\n })\n }\n\n function schedule(value: T, oldValue: T | undefined): void {\n cancel()\n hasLatestValue = true\n latestValue = value\n latestOldValue = oldValue\n isPending.value = true\n timer = setTimeout(flush, delay)\n }\n\n const stopWatch = watch(\n source as WatchSource<unknown> | WatchSource<unknown>[],\n (value, oldValue, onCleanup) => {\n schedule(value as T, oldValue as T | undefined)\n onCleanup(() => {\n cancel()\n runCallbackCleanup()\n })\n },\n watchOptions,\n )\n\n function stop(): void {\n if (stopped) return\n stopped = true\n stopWatch()\n cancel()\n runCallbackCleanup()\n }\n\n onScopeDispose(stop)\n\n return {\n isPending,\n cancel,\n flush,\n stop,\n }\n}\n","import { ref, reactive, computed, watch, type Ref, type ComputedRef } from 'vue'\nimport { useApi } from './useApi'\nimport { useDebouncedWatch } from './useDebouncedWatch'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport { datePresetToISO } from './experiment-utils'\nimport type {\n ExperimentSummary,\n ExperimentListResponse,\n ExperimentFilters,\n ExperimentTypeOption,\n ExperimentSortField,\n PlatformContext,\n SelectOption,\n} from '../types'\n\nfunction getPlatformContext(): PlatformContext | undefined {\n if (typeof window === 'undefined') return undefined\n return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__\n}\n\nfunction getPlatformApiUrl(): string | undefined {\n return getPlatformContext()?.platformApiUrl\n}\n\nexport interface UseExperimentSelectorOptions {\n experimentType?: string\n allowedExperimentTypes?: string[] | null\n apiBaseUrl?: string\n limit?: number\n immediate?: boolean\n}\n\nexport interface UseExperimentSelectorReturn {\n /** Current page of fetched experiment rows. */\n experiments: Ref<ExperimentSummary[]>\n /** Total matching experiment count reported by the platform. */\n total: Ref<number>\n /** Currently selected experiment, or null. */\n selectedExperiment: Ref<ExperimentSummary | null>\n /** Mutable filters used for the next fetch. */\n filters: ExperimentFilters\n /** Whether experiment rows are currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Current zero-based page index. */\n page: Ref<number>\n /** Whether another page can be loaded. */\n hasMore: ComputedRef<boolean>\n // Sort\n /** Combined sort key in the form `<field>:<asc|desc>`. */\n sortKey: Ref<string>\n // Filter options\n /** Available experiment type options for filter UI. */\n experimentTypes: Ref<ExperimentTypeOption[]>\n /** Available project options for filter UI. */\n projects: Ref<SelectOption<string>[]>\n // Grouped view\n /** Fetched experiments grouped by project name. */\n groupedByProject: ComputedRef<[string, ExperimentSummary[]][]>\n // Methods\n /** Fetch the current page with the current filters. */\n fetch: () => Promise<void>\n /** Fetch and append the next page when available. */\n loadMore: () => Promise<void>\n /** Clear fetched rows and refetch page zero. */\n reset: () => void\n /** Select an experiment. */\n select: (experiment: ExperimentSummary) => void\n /** Clear selection and filters. */\n clear: () => void\n /** Fetch experiment type and project filter options. */\n fetchFilterOptions: () => Promise<void>\n}\n\n/** Fetches a paginated, filtered experiment list from the platform API for picker and selector UIs. */\nexport function useExperimentSelector(\n options: UseExperimentSelectorOptions = {},\n): UseExperimentSelectorReturn {\n const {\n limit = 100,\n immediate = false,\n experimentType,\n allowedExperimentTypes: optionAllowedExperimentTypes,\n apiBaseUrl,\n } = options\n const platformBase = apiBaseUrl ?? getPlatformApiUrl()\n const api = useApi()\n\n const experiments = ref<ExperimentSummary[]>([])\n const total = ref(0)\n const selectedExperiment = ref<ExperimentSummary | null>(null)\n const request = useRequestSyncState('Failed to fetch experiments')\n const isLoading = request.loading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n const page = ref(0)\n let fetchGeneration = 0\n\n // Sort: combined key like \"created_at:desc\"\n const sortKey = ref<string>('created_at:desc')\n\n // Filter option data (fetched once, cached)\n const experimentTypes = ref<ExperimentTypeOption[]>([])\n const projects = ref<SelectOption<string>[]>([])\n let filterOptionsFetched = false\n\n const hasMore = computed(() => experiments.value.length < total.value)\n\n const filters: ExperimentFilters = reactive({\n search: undefined,\n status: undefined,\n project: undefined,\n experimentType: undefined,\n datePreset: undefined,\n })\n\n function normalizeExperimentTypes(values: string[] | null | undefined): string[] | null {\n if (values == null) return null\n return [...new Set(values.filter((value): value is string => typeof value === 'string' && value.length > 0))]\n }\n\n function currentAllowedExperimentTypes(): string[] | null {\n if (optionAllowedExperimentTypes !== undefined) {\n return normalizeExperimentTypes(optionAllowedExperimentTypes)\n }\n return normalizeExperimentTypes(getPlatformContext()?.allowedExperimentTypes)\n }\n\n function parseSortKey(): { sortBy: ExperimentSortField; sortOrder: 'asc' | 'desc' } {\n const [field, order] = sortKey.value.split(':')\n return {\n sortBy: (field || 'created_at') as ExperimentSortField,\n sortOrder: (order || 'desc') as 'asc' | 'desc',\n }\n }\n\n type ExperimentTypeScope =\n | { kind: 'all' }\n | { kind: 'blocked' }\n | { kind: 'single'; experimentType: string }\n | { kind: 'multi'; experimentTypes: string[] }\n\n function resolveExperimentTypeScope(): ExperimentTypeScope {\n const allowedTypes = currentAllowedExperimentTypes()\n const selectedType = experimentType ?? filters.experimentType ?? undefined\n\n if (selectedType) {\n if (allowedTypes && !allowedTypes.includes(selectedType)) {\n return { kind: 'blocked' }\n }\n return { kind: 'single', experimentType: selectedType }\n }\n\n if (allowedTypes) {\n if (allowedTypes.length === 0) return { kind: 'blocked' }\n if (allowedTypes.length === 1) return { kind: 'single', experimentType: allowedTypes[0] }\n return { kind: 'multi', experimentTypes: allowedTypes }\n }\n\n return { kind: 'all' }\n }\n\n function buildExperimentListUrl(typeFilter: string | undefined, skip: number, pageLimit: number): string {\n const params = new URLSearchParams()\n if (typeFilter) params.set('experiment_type', typeFilter)\n if (filters.status) params.set('status', filters.status)\n if (filters.search) params.set('search', filters.search)\n if (filters.project) params.set('project', filters.project)\n\n const { sortBy, sortOrder } = parseSortKey()\n params.set('sort_by', sortBy)\n params.set('sort_order', sortOrder)\n\n if (filters.datePreset) {\n params.set('created_after', datePresetToISO(filters.datePreset))\n }\n\n params.set('limit', String(pageLimit))\n params.set('skip', String(skip))\n\n const query = params.toString()\n const base = platformBase ?? ''\n return `${base}/experiments${query ? `?${query}` : ''}`\n }\n\n function sortExperiments(items: ExperimentSummary[]): ExperimentSummary[] {\n const { sortBy, sortOrder } = parseSortKey()\n const direction = sortOrder === 'desc' ? -1 : 1\n return [...items].sort((a, b) => {\n const aValue = a[sortBy] ?? ''\n const bValue = b[sortBy] ?? ''\n if (aValue < bValue) return -1 * direction\n if (aValue > bValue) return 1 * direction\n return 0\n })\n }\n\n async function fetchExperimentList(typeFilter: string | undefined, skip: number, pageLimit: number) {\n return await api.get<ExperimentListResponse>(buildExperimentListUrl(typeFilter, skip, pageLimit))\n }\n\n async function fetchScopedExperimentPage(\n requestedPage: number,\n ): Promise<ExperimentListResponse> {\n const scope = resolveExperimentTypeScope()\n const pageSkip = requestedPage * limit\n\n if (scope.kind === 'blocked') {\n return { experiments: [], total: 0 }\n }\n\n if (scope.kind === 'multi') {\n const perTypeLimit = pageSkip + limit\n const responses = await Promise.all(\n scope.experimentTypes.map(type => fetchExperimentList(type, 0, perTypeLimit)),\n )\n const merged = sortExperiments(responses.flatMap(response => response.experiments))\n return {\n experiments: merged.slice(pageSkip, pageSkip + limit),\n total: responses.reduce((sum, response) => sum + response.total, 0),\n }\n }\n\n return await fetchExperimentList(\n scope.kind === 'single' ? scope.experimentType : undefined,\n pageSkip,\n limit,\n )\n }\n\n async function fetchExperiments(): Promise<void> {\n const generation = ++fetchGeneration\n const requestedPage = page.value\n isLoading.value = true\n request.clearError()\n try {\n const data = await fetchScopedExperimentPage(requestedPage)\n if (generation !== fetchGeneration) return\n if (requestedPage === 0) {\n experiments.value = data.experiments\n } else {\n experiments.value = [...experiments.value, ...data.experiments]\n }\n total.value = data.total\n request.markLoaded()\n } catch (err) {\n if (generation !== fetchGeneration) return\n request.setError(err, 'Failed to fetch experiments')\n if (requestedPage === 0) {\n experiments.value = []\n total.value = 0\n }\n } finally {\n if (generation === fetchGeneration) {\n isLoading.value = false\n }\n }\n }\n\n function invalidateFetch(): void {\n fetchGeneration += 1\n isLoading.value = false\n }\n\n async function fetchFilterOptions(): Promise<void> {\n if (filterOptionsFetched) return\n filterOptionsFetched = true\n\n const base = platformBase ?? ''\n const [typesRes, projectsRes] = await Promise.allSettled([\n api.get<Array<{ value: string; label: string; color?: string }>>(`${base}/experiments/experiment-types`),\n api.get<{ projects: Array<{ id: number; name: string }>; total: number }>(`${base}/projects`),\n ])\n\n if (typesRes.status === 'fulfilled' && Array.isArray(typesRes.value)) {\n const allowedTypes = currentAllowedExperimentTypes()\n const allowedSet = allowedTypes ? new Set(allowedTypes) : null\n experimentTypes.value = typesRes.value\n .filter(t => !allowedSet || allowedSet.has(t.value))\n .map(t => ({\n value: t.value,\n label: t.label,\n color: t.color,\n }))\n if (filters.experimentType && allowedSet && !allowedSet.has(filters.experimentType)) {\n filters.experimentType = undefined\n }\n }\n\n if (projectsRes.status === 'fulfilled' && projectsRes.value?.projects && Array.isArray(projectsRes.value.projects)) {\n projects.value = projectsRes.value.projects.map(p => ({\n value: p.name,\n label: p.name,\n }))\n }\n }\n\n async function loadMore(): Promise<void> {\n if (!hasMore.value || isLoading.value) return\n page.value++\n await fetchExperiments()\n }\n\n function reset(): void {\n page.value = 0\n experiments.value = []\n total.value = 0\n fetchExperiments()\n }\n\n function select(experiment: ExperimentSummary): void {\n selectedExperiment.value = experiment\n }\n\n function clear(): void {\n invalidateFetch()\n selectedExperiment.value = null\n filters.search = undefined\n filters.status = undefined\n filters.project = undefined\n filters.experimentType = undefined\n filters.datePreset = undefined\n sortKey.value = 'created_at:desc'\n page.value = 0\n request.clearError()\n }\n\n // Group experiments by project (client-side)\n const groupedByProject = computed<[string, ExperimentSummary[]][]>(() => {\n const groups = new Map<string, ExperimentSummary[]>()\n for (const exp of experiments.value) {\n const key = exp.project_name ?? exp.project ?? 'No project'\n const list = groups.get(key)\n if (list) {\n list.push(exp)\n } else {\n groups.set(key, [exp])\n }\n }\n // Sort alphabetically, \"No project\" last\n return [...groups.entries()].sort(([a], [b]) => {\n if (a === 'No project') return 1\n if (b === 'No project') return -1\n return a.localeCompare(b)\n })\n })\n\n watch(\n () => [\n filters.search,\n filters.status,\n filters.project,\n filters.experimentType,\n filters.datePreset,\n sortKey.value,\n ],\n () => invalidateFetch(),\n { flush: 'sync' },\n )\n\n const searchWatch = useDebouncedWatch(\n () => filters.search,\n () => {\n page.value = 0\n fetchExperiments()\n },\n { delay: 300 },\n )\n\n // Immediate watch on discrete filters and sort (cancel any pending search debounce)\n watch(\n () => [filters.status, filters.project, filters.experimentType, filters.datePreset, sortKey.value],\n () => {\n searchWatch.cancel()\n page.value = 0\n fetchExperiments()\n },\n )\n\n if (immediate) {\n fetchExperiments()\n }\n\n return {\n experiments,\n total,\n selectedExperiment,\n filters,\n isLoading,\n error,\n lastLoadedAt,\n page,\n hasMore,\n sortKey,\n experimentTypes,\n projects,\n groupedByProject,\n fetch: fetchExperiments,\n loadMore,\n reset,\n select,\n clear,\n fetchFilterOptions,\n }\n}\n","import {\n computed,\n ref,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport { useApi } from './useApi'\nimport { useRequestSyncState } from './useRequestSyncState'\nimport {\n getInjectedPlatformContext,\n resolveCurrentExperimentId,\n} from './platformContextHelpers'\nimport type {\n AnalysisArtifactDetail,\n AnalysisArtifactListResponse,\n AnalysisArtifactMetadataUpdate,\n AnalysisArtifactStatusFilter,\n AnalysisArtifactSummary,\n AnalysisArtifactTarget,\n} from '../types/analysisArtifactTypes'\n\nexport { ANALYSIS_FILE_ARTIFACT_SCHEMA } from '../types/analysisArtifactTypes'\n\nexport interface UseAnalysisArtifactsOptions {\n /** Experiment id; defaults to platform injection or URL. Refetches when it changes. */\n experimentId?: MaybeRefOrGetter<number | undefined>\n /** Override API base URL. */\n apiBaseUrl?: string\n /** Scope to a single owning plugin; omit or null to keep all plugins. */\n pluginId?: MaybeRefOrGetter<string | null | undefined>\n /** Always request archived artifacts alongside active ones. */\n includeArchived?: MaybeRefOrGetter<boolean | undefined>\n /** Fetch as soon as an experiment id is available. */\n immediate?: boolean\n}\n\nexport interface UseAnalysisArtifactsReturn {\n /** Fetched artifacts, scoped to pluginId when set. */\n artifacts: ComputedRef<AnalysisArtifactSummary[]>\n /** Artifacts after applying statusFilter, pluginFilter, and search. */\n visibleArtifacts: ComputedRef<AnalysisArtifactSummary[]>\n /** Detail loaded by the last successful getDetail call, or null. */\n selectedDetail: Ref<AnalysisArtifactDetail | null>\n /** Resolved experiment id from options, platform injection, or URL. */\n currentExperimentId: ComputedRef<number | undefined>\n /** Whether an experiment id is available. */\n hasCurrentExperiment: ComputedRef<boolean>\n /** Whether any list or detail fetch is in progress. */\n isLoading: ComputedRef<boolean>\n /** Whether any archive/restore/metadata mutation is in progress. */\n isMutating: ComputedRef<boolean>\n /** Error message from the last failed operation, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful load, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Case-insensitive filter over display_name and artifact_key. */\n search: Ref<string>\n /** Lifecycle filter; widening past \"active\" refetches with include_archived. */\n statusFilter: Ref<AnalysisArtifactStatusFilter>\n /** Plugin filter applied to visibleArtifacts, or null for all plugins. */\n pluginFilter: Ref<string | null>\n /** Fetch the artifact list for the current experiment. */\n list: () => Promise<AnalysisArtifactSummary[]>\n /** Alias of list. */\n refresh: () => Promise<AnalysisArtifactSummary[]>\n /** Fetch one artifact with its result payload; null when it fails or is superseded. */\n getDetail: (artifactId: number) => Promise<AnalysisArtifactDetail | null>\n /** Resolve and fetch the exact stable artifact identity. */\n resolveTarget: (target: AnalysisArtifactTarget) => Promise<AnalysisArtifactDetail | null>\n /** Update display_name and/or note; resolves to the updated summary or null. */\n updateMetadata: (\n artifactId: number,\n updates: AnalysisArtifactMetadataUpdate,\n ) => Promise<AnalysisArtifactSummary | null>\n /** Archive an artifact; resolves to the updated summary or null. */\n archive: (artifactId: number) => Promise<AnalysisArtifactSummary | null>\n /** Restore an archived artifact; resolves to the updated summary or null. */\n restore: (artifactId: number) => Promise<AnalysisArtifactSummary | null>\n /** Whether a key exists in the loaded artifacts (no network call). */\n hasArtifactKey: (artifactKey: string) => boolean\n /** Reset artifacts, selection, and error. */\n clear: () => void\n}\n\n/**\n * Lists and manages analysis artifacts through the user-facing platform API.\n *\n * @example Recommended\n * ```ts\n * const artifacts = useAnalysisArtifacts({ pluginId: 'LEAF' })\n * await artifacts.list()\n * ```\n */\nexport function useAnalysisArtifacts(\n options: UseAnalysisArtifactsOptions = {},\n): UseAnalysisArtifactsReturn {\n const injectedContext = getInjectedPlatformContext()\n const api = useApi({ baseUrl: options.apiBaseUrl ?? injectedContext?.platformApiUrl })\n\n const currentExperimentId = computed<number | undefined>(\n () => toValue(options.experimentId) ?? resolveCurrentExperimentId(injectedContext),\n )\n const hasCurrentExperiment = computed(() => currentExperimentId.value !== undefined)\n const scopePluginId = computed(() => toValue(options.pluginId) ?? null)\n\n const request = useRequestSyncState('Analysis artifact request failed.')\n const fetchedArtifacts = ref<AnalysisArtifactSummary[]>([])\n const selectedDetail = ref<AnalysisArtifactDetail | null>(null)\n\n // Counters, not booleans: overlapping requests must not clear each other's flag.\n const loadingCount = ref(0)\n const mutatingCount = ref(0)\n const isLoading = computed(() => loadingCount.value > 0)\n const isMutating = computed(() => mutatingCount.value > 0)\n\n const search = ref('')\n const statusFilter = ref<AnalysisArtifactStatusFilter>('active')\n const pluginFilter = ref<string | null>(null)\n\n const needsArchived = computed(\n () => Boolean(toValue(options.includeArchived)) || statusFilter.value !== 'active',\n )\n\n const artifacts = computed(() => (\n scopePluginId.value\n ? fetchedArtifacts.value.filter((artifact) => artifact.plugin_id === scopePluginId.value)\n : fetchedArtifacts.value\n ))\n\n const visibleArtifacts = computed(() => {\n const query = search.value.trim().toLowerCase()\n return artifacts.value.filter((artifact) => {\n if (statusFilter.value !== 'all' && artifact.status !== statusFilter.value) return false\n if (pluginFilter.value && artifact.plugin_id !== pluginFilter.value) return false\n if (!query) return true\n return (\n artifact.display_name.toLowerCase().includes(query)\n || artifact.artifact_key.toLowerCase().includes(query)\n )\n })\n })\n\n // Generation tokens: a superseded response must commit nothing — not rows, not the\n // shared error, not lastLoadedAt — or a late failure would bury fresh results.\n let listToken = 0\n let detailToken = 0\n const hasRequestedList = ref(false)\n\n function currentExperimentIdOrError(action: string): number | undefined {\n const id = currentExperimentId.value\n if (id === undefined) {\n request.setError(`No current experiment is selected for ${action}`)\n return undefined\n }\n return id\n }\n\n function replaceArtifact(summary: AnalysisArtifactSummary): void {\n const index = fetchedArtifacts.value.findIndex((artifact) => artifact.id === summary.id)\n if (index >= 0) {\n fetchedArtifacts.value.splice(index, 1, summary)\n }\n }\n\n async function list(): Promise<AnalysisArtifactSummary[]> {\n const experimentId = currentExperimentIdOrError('listing analysis artifacts')\n if (experimentId === undefined) {\n fetchedArtifacts.value = []\n return []\n }\n const token = ++listToken\n hasRequestedList.value = true\n loadingCount.value += 1\n request.clearError()\n try {\n const data = await api.get<AnalysisArtifactListResponse>(\n `/experiments/${experimentId}/analysis-artifacts?include_archived=${needsArchived.value}`,\n )\n if (token !== listToken) return artifacts.value\n // Copy: replaceArtifact splices in place, and the response array is not ours.\n fetchedArtifacts.value = [...(data?.artifacts ?? [])]\n request.markLoaded()\n return artifacts.value\n } catch (err) {\n if (token !== listToken) return []\n request.setError(err)\n fetchedArtifacts.value = []\n return []\n } finally {\n loadingCount.value -= 1\n }\n }\n\n async function getDetail(artifactId: number): Promise<AnalysisArtifactDetail | null> {\n const experimentId = currentExperimentIdOrError('loading an analysis artifact')\n if (experimentId === undefined) return null\n const token = ++detailToken\n loadingCount.value += 1\n request.clearError()\n try {\n const detail = await api.get<AnalysisArtifactDetail>(\n `/experiments/${experimentId}/analysis-artifacts/${artifactId}`,\n )\n if (token !== detailToken) return null\n selectedDetail.value = detail\n request.markLoaded()\n return detail\n } catch (err) {\n if (token !== detailToken) return null\n request.setError(err)\n return null\n } finally {\n loadingCount.value -= 1\n }\n }\n\n async function resolveTarget(\n target: AnalysisArtifactTarget,\n ): Promise<AnalysisArtifactDetail | null> {\n const experimentId = currentExperimentId.value\n if (experimentId !== target.experimentId) {\n request.setError(\n `Analysis artifact target belongs to experiment ${target.experimentId}, not `\n + `${experimentId ?? 'the current selection'}.`,\n )\n return null\n }\n\n const available = await list()\n const summary = available.find((artifact) => (\n artifact.plugin_id === target.artifactPluginId\n && artifact.artifact_key === target.artifactKey\n && artifact.status === 'active'\n ))\n if (!summary) {\n request.setError(\n `Analysis artifact ${target.artifactPluginId}/${target.artifactKey} is not available.`,\n )\n return null\n }\n\n const detail = await getDetail(summary.id)\n if (\n detail\n && (\n detail.experiment_id !== target.experimentId\n || detail.plugin_id !== target.artifactPluginId\n || detail.artifact_key !== target.artifactKey\n )\n ) {\n selectedDetail.value = null\n request.setError(\n `Analysis artifact ${target.artifactPluginId}/${target.artifactKey} did not `\n + 'match the requested identity.',\n )\n return null\n }\n return detail\n }\n\n async function mutate(\n action: string,\n operation: (experimentId: number) => Promise<AnalysisArtifactSummary>,\n ): Promise<AnalysisArtifactSummary | null> {\n const experimentId = currentExperimentIdOrError(action)\n if (experimentId === undefined) return null\n mutatingCount.value += 1\n request.clearError()\n try {\n const summary = await operation(experimentId)\n replaceArtifact(summary)\n request.markSaved()\n return summary\n } catch (err) {\n request.setError(err)\n return null\n } finally {\n mutatingCount.value -= 1\n }\n }\n\n async function updateMetadata(\n artifactId: number,\n updates: AnalysisArtifactMetadataUpdate,\n ): Promise<AnalysisArtifactSummary | null> {\n return mutate('updating artifact metadata', (experimentId) =>\n api.patch<AnalysisArtifactSummary>(\n `/experiments/${experimentId}/analysis-artifacts/${artifactId}`,\n updates,\n ))\n }\n\n async function archive(artifactId: number): Promise<AnalysisArtifactSummary | null> {\n return mutate('archiving an analysis artifact', (experimentId) =>\n api.post<AnalysisArtifactSummary>(\n `/experiments/${experimentId}/analysis-artifacts/${artifactId}/archive`,\n ))\n }\n\n async function restore(artifactId: number): Promise<AnalysisArtifactSummary | null> {\n return mutate('restoring an analysis artifact', (experimentId) =>\n api.post<AnalysisArtifactSummary>(\n `/experiments/${experimentId}/analysis-artifacts/${artifactId}/restore`,\n ))\n }\n\n function hasArtifactKey(artifactKey: string): boolean {\n return artifacts.value.some((artifact) => artifact.artifact_key === artifactKey)\n }\n\n /** Drop experiment-scoped state and orphan every in-flight response. */\n function clear(): void {\n listToken += 1\n detailToken += 1\n fetchedArtifacts.value = []\n selectedDetail.value = null\n request.clearError()\n }\n\n // Refetch when the scope changes or archived rows are newly needed. `immediate`\n // covers a late-resolving experiment id; otherwise stay quiet until something\n // has asked for a list at least once.\n watch([currentExperimentId, needsArchived], ([experimentId], [previousExperimentId]) => {\n if (experimentId !== previousExperimentId) {\n // Scope changed: the previous experiment's rows and any in-flight reply for\n // them must not survive into the new one.\n clear()\n }\n if (experimentId === undefined) return\n if (options.immediate || hasRequestedList.value) {\n void list()\n }\n }, { immediate: options.immediate })\n\n return {\n artifacts,\n visibleArtifacts,\n selectedDetail,\n currentExperimentId,\n hasCurrentExperiment,\n isLoading,\n isMutating,\n error: request.error,\n lastLoadedAt: request.lastLoadedAt,\n search,\n statusFilter,\n pluginFilter,\n list,\n refresh: list,\n getDetail,\n resolveTarget,\n updateMetadata,\n archive,\n restore,\n hasArtifactKey,\n clear,\n }\n}\n","import type { PickerCapability, PickerExcluded, PickerNode } from '../../types/filePicker'\n\nexport function normalizePickerFormat(format: string): string {\n return format.trim().replace(/^\\./, '').toLowerCase()\n}\n\nexport function pickerExclusion(\n node: PickerNode,\n capability?: PickerCapability,\n skipBlanks = false,\n): PickerExcluded | null {\n const base = { path: node.path, name: node.name }\n if (node.unavailableReason) return { ...base, reason: 'unreadable' }\n if (skipBlanks && capability?.isBlank?.(node)) return { ...base, reason: 'blank' }\n if (node.kind === 'folder') return null\n const formats = capability?.formats.map(normalizePickerFormat) ?? []\n if (formats.length && !formats.some((format) => node.name.toLowerCase().endsWith(`.${format}`))) {\n return { ...base, reason: 'unsupported' }\n }\n if (capability?.maxBytes != null && node.bytes != null && node.bytes > capability.maxBytes) {\n return { ...base, reason: 'tooLarge' }\n }\n return null\n}\n\nexport function pickerReason(excluded: PickerExcluded | null, node?: PickerNode): string {\n if (!excluded) return ''\n return {\n unsupported: 'This format is not supported by this source.',\n tooLarge: 'This file exceeds the size limit for this source.',\n blank: 'Skipped by the blank-file rule.',\n unreadable: node?.unavailableReason || 'This item cannot be read.',\n deselected: 'Removed from the selection.',\n forbidden: 'This item is not permitted by the system filter.',\n }[excluded.reason]\n}\n\nexport function pickerFormat(name: string): string {\n const compound = /\\.(mzml|mzxml)\\.gz$/i.exec(name)\n return compound ? `${compound[1]}.gz` : name.includes('.') ? name.split('.').pop()! : ''\n}\n"],"mappings":"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ACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;GACP;GACA;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;IACL,KAAK;GACP;EACF;CACF;CACA;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY;GACV;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;GACf;GACA;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;GACP;EACF;CACF;CACA;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY;GACV;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,SAAS;IACT,SAAS;KACP;MAAE,OAAO;MAAW,OAAO;KAAiB;KAC5C;MAAE,OAAO;MAAU,OAAO;KAAS;KACnC;MAAE,OAAO;MAAU,OAAO;KAAiB;KAC3C;MAAE,OAAO;MAAa,OAAO;KAAY;IAC3C;GACF;GACA;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,KAAK;GACP;GACA;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;GACf;EACF;CACF;CACA;EACE,IAAI;EACJ,MAAM;EACN,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,WAAW;EACX,YAAY,CACV;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,UAAU;GACV,aAAa;EACf,GACA;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,UAAU;GACV,aAAa;EACf,CACF;CACF;AACF;;;ACtSA,IAAM,cAAc;AAEpB,SAAS,eAAe,OAAuC;CAC7D,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAChD,MAAM,YAAY;CAClB,OACE,OAAO,UAAU,OAAO,YAC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"}
|