@morscherlab/mint-sdk 1.0.53 → 1.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +18 -0
  2. package/dist/{ExperimentSelectorModal-BwPbQN1g.js → ExperimentSelectorModal-Cg4-LXBD.js} +1 -1
  3. package/dist/{ExperimentSelectorModal-B2qek_YG.js → ExperimentSelectorModal-DZeSd-yr.js} +2 -2
  4. package/dist/{ExperimentSelectorModal-B2qek_YG.js.map → ExperimentSelectorModal-DZeSd-yr.js.map} +1 -1
  5. package/dist/__tests__/composables/resolvePluginFrontendBase.test.d.ts +1 -0
  6. package/dist/components/index.js +2 -2
  7. package/dist/{components-Lk_h_rON.js → components-BQwOeyiy.js} +5 -5
  8. package/dist/{components-Lk_h_rON.js.map → components-BQwOeyiy.js.map} +1 -1
  9. package/dist/composables/index.d.ts +3 -2
  10. package/dist/composables/index.js +4 -4
  11. package/dist/composables/pluginFrontendBase.d.ts +7 -0
  12. package/dist/composables/useApi.d.ts +9 -0
  13. package/dist/composables/usePluginClient.d.ts +12 -2
  14. package/dist/{composables-DyfGpYZw.js → composables-TpXyhRZZ.js} +97 -30
  15. package/dist/composables-TpXyhRZZ.js.map +1 -0
  16. package/dist/index.js +6 -6
  17. package/dist/install.js +2 -2
  18. package/dist/{useExperimentSelector-DdCy5VNv.js → useExperimentSelector-DRbj6vse.js} +33 -3
  19. package/dist/useExperimentSelector-DRbj6vse.js.map +1 -0
  20. package/dist/{useJobsStatusTray-DAH999_N.js → useJobsStatusTray-CVecN6Ao.js} +2 -2
  21. package/dist/{useJobsStatusTray-DAH999_N.js.map → useJobsStatusTray-CVecN6Ao.js.map} +1 -1
  22. package/package.json +1 -1
  23. package/src/__tests__/composables/resolvePluginFrontendBase.test.ts +65 -0
  24. package/src/__tests__/composables/useApi.test.ts +76 -2
  25. package/src/__tests__/composables/usePluginClient.test.ts +158 -0
  26. package/src/composables/index.ts +8 -1
  27. package/src/composables/pluginEndpointBuilder.ts +13 -4
  28. package/src/composables/pluginFrontendBase.ts +22 -0
  29. package/src/composables/useApi.ts +48 -1
  30. package/src/composables/usePluginClient.ts +125 -21
  31. package/dist/composables-DyfGpYZw.js.map +0 -1
  32. package/dist/useExperimentSelector-DdCy5VNv.js.map +0 -1
@@ -1,9 +1,10 @@
1
- export { useApi, type ApiClientOptions } from './useApi';
1
+ export { AuthenticationRequiredError, useApi, type ApiClientOptions, type UseApiReturn, } from './useApi';
2
2
  export { useAuth } from './useAuth';
3
3
  export { usePasskey } from './usePasskey';
4
4
  export { useTheme } from './useTheme';
5
5
  export { useToast } from './useToast';
6
6
  export { usePlatformContext } from './usePlatformContext';
7
+ export { resolvePluginFrontendBase } from './pluginFrontendBase';
7
8
  export { useForm, type ValidationRule, type FieldRules, type FieldState, type UseFormReturn, } from './useForm';
8
9
  export { useAsync, useAsyncBatch, type AsyncError, type AsyncState, type UseAsyncReturn, type UseAsyncOptions, } from './useAsync';
9
10
  export { useWellPlateEditor, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, } from './useWellPlateEditor';
@@ -52,5 +53,5 @@ export { getBioTemplateComponentProps, getBioTemplateComponentBindings, toBioTem
52
53
  export { useBioTemplateWorkspace, type BioTemplateRendererBinding, type BioTemplateWorkspaceBindings, type BioTemplateWorkspaceTarget, type UseBioTemplateWorkspaceReturn, } from './useBioTemplateWorkspace';
53
54
  export { useBioTemplatePresetWorkspace, type BioTemplatePresetWorkspaceBindings, type UseBioTemplatePresetWorkspaceOptions, type UseBioTemplatePresetWorkspaceReturn, } from './useBioTemplatePresetWorkspace';
54
55
  export { useBioTemplatePackWorkspace, type UseBioTemplatePackWorkspaceOptions, type UseBioTemplatePackWorkspaceReturn, } from './useBioTemplatePackWorkspace';
55
- export { buildPluginEndpointUrl, createPluginClient, downloadBlob, downloadPluginEndpoint, getPluginPageSelectorItems, pluginFormDataFromPayload, resolvePluginBaseUrl, uploadPluginEndpoint, usePluginClient, usePluginEventStream, usePluginSettings, useCurrentExperiment, type BuildPluginEndpointUrlOptions, type DownloadBlobOptions, type DownloadPluginEndpointOptions, type PluginContract, type PluginEndpointContract, type PluginEndpointDefinition, type PluginHttpMethod, type PluginNavItemContract, type PluginEndpointRequestOptions, type PluginEventStreamMessage, type PluginEventStreamOptions, type PluginFormDataPayload, type PluginFormDataValue, type CreatePluginClientOptions, type UseCurrentExperimentOptions, type UseCurrentExperimentReturn, type UsePluginEventStreamReturn, type UsePluginSettingsOptions, type UsePluginSettingsReturn, } from './usePluginClient';
56
+ export { buildPluginEndpointUrl, createPluginClient, downloadBlob, downloadPluginEndpoint, getPluginPageSelectorItems, pluginFormDataFromPayload, resolvePluginBaseUrl, uploadPluginEndpoint, usePluginClient, usePluginEventStream, usePluginSettings, useCurrentExperiment, type BuildPluginEndpointUrlOptions, type DownloadBlobOptions, type DownloadPluginEndpointOptions, type PluginContract, type PluginClientRequestOptions, type PluginEndpointContract, type PluginEndpointDefinition, type PluginHttpMethod, type PluginNavItemContract, type PluginEndpointRequestOptions, type PluginEventStreamMessage, type PluginEventStreamOptions, type PluginFormDataPayload, type PluginFormDataValue, type CreatePluginClientOptions, type UseCurrentExperimentOptions, type UseCurrentExperimentReturn, type UsePluginEventStreamReturn, type UsePluginSettingsOptions, type UsePluginSettingsReturn, } from './usePluginClient';
56
57
  export { useJobsStatusTray, type JobsStatusTrayAdapter, type JobsStatusTrayTab, type JobStreamMessage, type UseJobsStatusTrayOptions, type UseJobsStatusTrayReturn, } from './useJobsStatusTray';
@@ -1,10 +1,10 @@
1
1
  import "../BaseSelect-ekgr9fDo.js";
2
2
  import { $ as parseTime, A as useConcentrationUnits, C as controlsToViewIds, D as getTypeDefault, E as getFieldRegistryEntry, F as ATOMIC_WEIGHTS, G as findAvailableSlots, H as addMinutes, I as useChemicalFormula, J as formatTime, K as findNearestTimeSlotIndex, N as useSequenceUtils, Q as isTimeInRange, S as controlsToTopBarSettingsConfig, T as getDefaultControlView, U as compareTime, W as durationMinutes, X as fromMinutes, Y as formatTimeSlot, Z as generateTimeSlots, _ as controlsToFormSchema, a as defineDoseCalculatorControlProps, b as controlsToSettingsSchema, c as defineWellPlateDoseComponentBindings, d as defineControlModel, et as rangesOverlap, h as controlValuesToComponentProps, i as useControlSchema, l as defineWellPlateDoseControlProps, m as controlValuesToComponentBindingsById, n as defineControls, nt as toMinutes, o as defineDoseDesignControlModel, ot as useListSelection, p as controlValuesToComponentBindings, q as formatDuration, r as getControlDefaults, rt as useTimeUtils, s as defineWellPlateControlProps, st as useSelectionLimit, t as defineControlComponentBindings, tt as snapToSlot, u as useControlWorkspace, v as controlsToSectionFormSchema, w as controlsToViewItems, x as controlsToSidebarPanels, y as controlsToSectionFormSchemas } from "../useControlSchema-BZNdalmL.js";
3
3
  import { t as useEventListener } from "../useEventListener-CfVkP9Xz.js";
4
- import { $ as useTheme, A as useExpansionSet, B as extractSamplesFromDesignData, C as useExperimentSave, E as useExperimentData, F as detectDelimiter, G as unwrapExperimentDesignData, I as parseDelimitedText, J as useDoseCalculator, K as DEFAULT_COLORS, L as readFileAsText, Q as useAppExperiment, R as useFileImport, S as useTemplateCollection, T as useExperimentSamples, U as extractSampleNamesFromDesignData, V as useAutoGroup, W as extractSampleOptionsFromDesignData, X as useMobileSupportGate, Y as DEFAULT_MOBILE_VIEWPORT_QUERY, Z as APP_EXPERIMENT_KEY, _ as useBioTemplateWorkspace, at as useSortedItems, b as useBioTemplateComponents, c as useProtocolTemplates, d as generateDilutionSeries, et as useToast, f as useReagentSeries, g as useBioTemplatePackWorkspace, h as useBioTemplatePresetWorkspace, it as compareSortValues, j as useSampleGroups, l as DEFAULT_PRESETS, m as useRackEditor, nt as normalizeSearchQuery, p as useGroupAssignment, q as useWellPlateEditor, rt as useTextSearch, t as useJobsStatusTray, tt as candidateMatchesSearch, u as DEFAULT_UNITS, v as getBioTemplateComponentProps, w as useScheduleDrag, x as useBioTemplateControls, y as toBioTemplateComponentPropsByComponent, z as validateImportFile } from "../useJobsStatusTray-DAH999_N.js";
4
+ import { $ as useTheme, A as useExpansionSet, B as extractSamplesFromDesignData, C as useExperimentSave, E as useExperimentData, F as detectDelimiter, G as unwrapExperimentDesignData, I as parseDelimitedText, J as useDoseCalculator, K as DEFAULT_COLORS, L as readFileAsText, Q as useAppExperiment, R as useFileImport, S as useTemplateCollection, T as useExperimentSamples, U as extractSampleNamesFromDesignData, V as useAutoGroup, W as extractSampleOptionsFromDesignData, X as useMobileSupportGate, Y as DEFAULT_MOBILE_VIEWPORT_QUERY, Z as APP_EXPERIMENT_KEY, _ as useBioTemplateWorkspace, at as useSortedItems, b as useBioTemplateComponents, c as useProtocolTemplates, d as generateDilutionSeries, et as useToast, f as useReagentSeries, g as useBioTemplatePackWorkspace, h as useBioTemplatePresetWorkspace, it as compareSortValues, j as useSampleGroups, l as DEFAULT_PRESETS, m as useRackEditor, nt as normalizeSearchQuery, p as useGroupAssignment, q as useWellPlateEditor, rt as useTextSearch, t as useJobsStatusTray, tt as candidateMatchesSearch, u as DEFAULT_UNITS, v as getBioTemplateComponentProps, w as useScheduleDrag, x as useBioTemplateControls, y as toBioTemplateComponentPropsByComponent, z as validateImportFile } from "../useJobsStatusTray-CVecN6Ao.js";
5
5
  import { i as usePlatformContext, n as evaluateCondition, r as useForm, t as useFormBuilder } from "../useFormBuilder-DKekvXRs.js";
6
6
  import { a as SORT_OPTIONS, c as formatExperimentStatus, i as EXPERIMENT_STATUS_VARIANT_MAP, l as getExperimentStatusVariant, n as EXPERIMENT_STATUS_LABELS, o as datePresetToISO, r as EXPERIMENT_STATUS_OPTIONS, s as formatExperimentDate, t as DATE_PRESET_OPTIONS, u as resolveExperimentCode } from "../experiment-utils-Bfa7CwPU.js";
7
- import { i as useApi, n as useDebouncedWatch, r as useRequestSyncState, t as useExperimentSelector } from "../useExperimentSelector-DdCy5VNv.js";
7
+ import { i as AuthenticationRequiredError, n as useDebouncedWatch, o as useApi, r as useRequestSyncState, t as useExperimentSelector } from "../useExperimentSelector-DRbj6vse.js";
8
8
  import { B as toBioTemplateComponentProps, H as toBioTemplateComponentPropsById, L as toBioTemplateComponentBindings, P as getBioTemplateComponentBindings, R as toBioTemplateComponentBindingsById, l as requireBioTemplateControlSchema, o as getBioTemplateControlSchema } from "../templates-CNbPQNID.js";
9
- import { A as usePasskey, C as createPluginResourceClient, D as usePluginConfig, E as useCommandHistory, O as useAsync, S as wellIdsInRectangle, T as useOptimisticMutation, _ as createWellPlateWells, a as pluginFormDataFromPayload, b as useWellPainting, c as usePluginClient, d as buildPluginEndpointUrl, f as resolvePluginBaseUrl, g as createRowConditions, h as createColumnConditions, i as getPluginPageSelectorItems, j as useAuth, k as useAsyncBatch, l as usePluginEventStream, m as useWellPlateValidation, n as downloadBlob, o as uploadPluginEndpoint, p as runWellPlateValidation, r as downloadPluginEndpoint, s as useCurrentExperiment, t as createPluginClient, u as usePluginSettings, v as useWellPlateAdapter, w as useResourceCrud, x as wellIdToCoordinate, y as coordinateToWellId } from "../composables-DyfGpYZw.js";
10
- export { APP_EXPERIMENT_KEY, ATOMIC_WEIGHTS, DATE_PRESET_OPTIONS, DEFAULT_COLORS, DEFAULT_MOBILE_VIEWPORT_QUERY, DEFAULT_PRESETS, DEFAULT_UNITS, EXPERIMENT_STATUS_LABELS, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, SORT_OPTIONS, addMinutes, buildPluginEndpointUrl, candidateMatchesSearch, compareSortValues, compareTime, controlValuesToComponentBindings, controlValuesToComponentBindingsById, controlValuesToComponentProps, controlsToFormSchema, controlsToSectionFormSchema, controlsToSectionFormSchemas, controlsToSettingsSchema, controlsToSidebarPanels, controlsToTopBarSettingsConfig, controlsToViewIds, controlsToViewItems, coordinateToWellId, createColumnConditions, createPluginClient, createPluginResourceClient, createRowConditions, createWellPlateWells, datePresetToISO, defineControlComponentBindings, defineControlModel, defineControls, defineDoseCalculatorControlProps, defineDoseDesignControlModel, defineWellPlateControlProps, defineWellPlateDoseComponentBindings, defineWellPlateDoseControlProps, detectDelimiter, downloadBlob, downloadPluginEndpoint, durationMinutes, evaluateCondition, extractSampleNamesFromDesignData, extractSampleOptionsFromDesignData, extractSamplesFromDesignData, findAvailableSlots, findNearestTimeSlotIndex, formatDuration, formatExperimentDate, formatExperimentStatus, formatTime, formatTimeSlot, fromMinutes, generateDilutionSeries, generateTimeSlots, getBioTemplateComponentBindings, getBioTemplateComponentProps, getBioTemplateControlSchema, getControlDefaults, getDefaultControlView, getExperimentStatusVariant, getFieldRegistryEntry, getPluginPageSelectorItems, getTypeDefault, isTimeInRange, normalizeSearchQuery, parseDelimitedText, parseTime, pluginFormDataFromPayload, rangesOverlap, readFileAsText, requireBioTemplateControlSchema, resolveExperimentCode, resolvePluginBaseUrl, runWellPlateValidation, snapToSlot, toBioTemplateComponentBindings, toBioTemplateComponentBindingsById, toBioTemplateComponentProps, toBioTemplateComponentPropsByComponent, toBioTemplateComponentPropsById, toMinutes, unwrapExperimentDesignData, uploadPluginEndpoint, useApi, useAppExperiment, useAsync, useAsyncBatch, useAuth, useAutoGroup, useBioTemplateComponents, useBioTemplateControls, useBioTemplatePackWorkspace, useBioTemplatePresetWorkspace, useBioTemplateWorkspace, useChemicalFormula, useCommandHistory, useConcentrationUnits, useControlSchema, useControlWorkspace, useCurrentExperiment, useDebouncedWatch, useDoseCalculator, useEventListener, useExpansionSet, useExperimentData, useExperimentSamples, useExperimentSave, useExperimentSelector, useFileImport, useForm, useFormBuilder, useGroupAssignment, useJobsStatusTray, useListSelection, useMobileSupportGate, useOptimisticMutation, usePasskey, usePlatformContext, usePluginClient, usePluginConfig, usePluginEventStream, usePluginSettings, useProtocolTemplates, useRackEditor, useReagentSeries, useRequestSyncState, useResourceCrud, useSampleGroups, useScheduleDrag, useSelectionLimit, useSequenceUtils, useSortedItems, useTemplateCollection, useTextSearch, useTheme, useTimeUtils, useToast, useWellPainting, useWellPlateAdapter, useWellPlateEditor, useWellPlateValidation, validateImportFile, wellIdToCoordinate, wellIdsInRectangle };
9
+ import { A as resolvePluginFrontendBase, C as createPluginResourceClient, D as usePluginConfig, E as useCommandHistory, M as useAuth, O as useAsync, S as wellIdsInRectangle, T as useOptimisticMutation, _ as createWellPlateWells, a as pluginFormDataFromPayload, b as useWellPainting, c as usePluginClient, d as buildPluginEndpointUrl, f as resolvePluginBaseUrl, g as createRowConditions, h as createColumnConditions, i as getPluginPageSelectorItems, j as usePasskey, k as useAsyncBatch, l as usePluginEventStream, m as useWellPlateValidation, n as downloadBlob, o as uploadPluginEndpoint, p as runWellPlateValidation, r as downloadPluginEndpoint, s as useCurrentExperiment, t as createPluginClient, u as usePluginSettings, v as useWellPlateAdapter, w as useResourceCrud, x as wellIdToCoordinate, y as coordinateToWellId } from "../composables-TpXyhRZZ.js";
10
+ export { APP_EXPERIMENT_KEY, ATOMIC_WEIGHTS, AuthenticationRequiredError, DATE_PRESET_OPTIONS, DEFAULT_COLORS, DEFAULT_MOBILE_VIEWPORT_QUERY, DEFAULT_PRESETS, DEFAULT_UNITS, EXPERIMENT_STATUS_LABELS, EXPERIMENT_STATUS_OPTIONS, EXPERIMENT_STATUS_VARIANT_MAP, SORT_OPTIONS, addMinutes, buildPluginEndpointUrl, candidateMatchesSearch, compareSortValues, compareTime, controlValuesToComponentBindings, controlValuesToComponentBindingsById, controlValuesToComponentProps, controlsToFormSchema, controlsToSectionFormSchema, controlsToSectionFormSchemas, controlsToSettingsSchema, controlsToSidebarPanels, controlsToTopBarSettingsConfig, controlsToViewIds, controlsToViewItems, coordinateToWellId, createColumnConditions, createPluginClient, createPluginResourceClient, createRowConditions, createWellPlateWells, datePresetToISO, defineControlComponentBindings, defineControlModel, defineControls, defineDoseCalculatorControlProps, defineDoseDesignControlModel, defineWellPlateControlProps, defineWellPlateDoseComponentBindings, defineWellPlateDoseControlProps, detectDelimiter, downloadBlob, downloadPluginEndpoint, durationMinutes, evaluateCondition, extractSampleNamesFromDesignData, extractSampleOptionsFromDesignData, extractSamplesFromDesignData, findAvailableSlots, findNearestTimeSlotIndex, formatDuration, formatExperimentDate, formatExperimentStatus, formatTime, formatTimeSlot, fromMinutes, generateDilutionSeries, generateTimeSlots, getBioTemplateComponentBindings, getBioTemplateComponentProps, getBioTemplateControlSchema, getControlDefaults, getDefaultControlView, getExperimentStatusVariant, getFieldRegistryEntry, getPluginPageSelectorItems, getTypeDefault, isTimeInRange, normalizeSearchQuery, parseDelimitedText, parseTime, pluginFormDataFromPayload, rangesOverlap, readFileAsText, requireBioTemplateControlSchema, resolveExperimentCode, resolvePluginBaseUrl, resolvePluginFrontendBase, runWellPlateValidation, snapToSlot, toBioTemplateComponentBindings, toBioTemplateComponentBindingsById, toBioTemplateComponentProps, toBioTemplateComponentPropsByComponent, toBioTemplateComponentPropsById, toMinutes, unwrapExperimentDesignData, uploadPluginEndpoint, useApi, useAppExperiment, useAsync, useAsyncBatch, useAuth, useAutoGroup, useBioTemplateComponents, useBioTemplateControls, useBioTemplatePackWorkspace, useBioTemplatePresetWorkspace, useBioTemplateWorkspace, useChemicalFormula, useCommandHistory, useConcentrationUnits, useControlSchema, useControlWorkspace, useCurrentExperiment, useDebouncedWatch, useDoseCalculator, useEventListener, useExpansionSet, useExperimentData, useExperimentSamples, useExperimentSave, useExperimentSelector, useFileImport, useForm, useFormBuilder, useGroupAssignment, useJobsStatusTray, useListSelection, useMobileSupportGate, useOptimisticMutation, usePasskey, usePlatformContext, usePluginClient, usePluginConfig, usePluginEventStream, usePluginSettings, useProtocolTemplates, useRackEditor, useReagentSeries, useRequestSyncState, useResourceCrud, useSampleGroups, useScheduleDrag, useSelectionLimit, useSequenceUtils, useSortedItems, useTemplateCollection, useTextSearch, useTheme, useTimeUtils, useToast, useWellPainting, useWellPlateAdapter, useWellPlateEditor, useWellPlateValidation, validateImportFile, wellIdToCoordinate, wellIdsInRectangle };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Resolve the Vue Router base for a plugin frontend.
3
+ *
4
+ * Integrated plugins use the platform-injected mount prefix. Standalone and
5
+ * development builds retain the caller's Vite base unchanged.
6
+ */
7
+ export declare function resolvePluginFrontendBase(fallbackBase?: string): string;
@@ -1,4 +1,13 @@
1
1
  import { AxiosInstance, AxiosRequestConfig } from 'axios';
2
+ /** Raised when an authenticated SDK request is rejected because the login is no longer valid. */
3
+ export declare class AuthenticationRequiredError extends Error {
4
+ readonly cause?: unknown | undefined;
5
+ readonly code = "AUTHENTICATION_REQUIRED";
6
+ readonly status = 401;
7
+ constructor(cause?: unknown | undefined);
8
+ }
9
+ /** @internal Convert a rejected authenticated request into the SDK's public auth error. */
10
+ export declare function authenticationRequiredError(cause: unknown, rejectedToken?: string): AuthenticationRequiredError;
2
11
  export interface ApiClientOptions {
3
12
  baseUrl?: string;
4
13
  timeout?: number;
@@ -9,7 +9,9 @@ export interface PluginEndpointContract {
9
9
  pathParams?: PluginEndpointParamContract[];
10
10
  queryParams?: PluginEndpointParamContract[];
11
11
  requestType?: string | null;
12
+ requestContentType?: string | null;
12
13
  responseType?: string | null;
14
+ responseContentType?: string | null;
13
15
  eventStream?: boolean;
14
16
  }
15
17
  export interface PluginEndpointParamContract {
@@ -58,8 +60,10 @@ export interface PluginEndpointDefinition {
58
60
  pathParams?: PluginEndpointParamDefinition[];
59
61
  queryParams?: PluginEndpointParamDefinition[];
60
62
  hasBody?: boolean;
63
+ requestContentType?: string | null;
61
64
  eventStream?: boolean;
62
65
  responseType?: string | null;
66
+ responseContentType?: string | null;
63
67
  }
64
68
  export type PluginEndpointParamDefinition = string | {
65
69
  name: string;
@@ -80,6 +84,12 @@ export interface BuildPluginEndpointUrlOptions {
80
84
  export interface PluginEndpointRequestOptions {
81
85
  /** Override the generated or platform-injected API base URL. */
82
86
  baseUrl?: string;
87
+ /** Cancel the request without changing its endpoint or authentication behavior. */
88
+ signal?: AbortSignal;
89
+ }
90
+ export interface PluginClientRequestOptions {
91
+ /** Cancel the generated endpoint request. */
92
+ signal?: AbortSignal;
83
93
  }
84
94
  export interface DownloadPluginEndpointOptions extends PluginEndpointRequestOptions {
85
95
  /** Browser download filename. When omitted, the blob is returned without triggering a download. */
@@ -189,7 +199,7 @@ export interface UseCurrentExperimentReturn<TExperiment = ExperimentSummary> {
189
199
  /** Refetch the currently resolved experiment id. */
190
200
  refresh: () => Promise<TExperiment | undefined>;
191
201
  }
192
- export type PluginEndpointCaller = (payload?: unknown) => Promise<unknown>;
202
+ export type PluginEndpointCaller = (payloadOrOptions?: unknown, options?: PluginClientRequestOptions) => Promise<unknown>;
193
203
  export type GeneratedPluginClient = Record<string, (...args: any[]) => Promise<any>>;
194
204
  /** Convert plain upload payloads into FormData using the same encoding across generated plugin clients. */
195
205
  export declare function pluginFormDataFromPayload(payload: unknown): FormData;
@@ -199,7 +209,7 @@ export declare function downloadBlob(blob: Blob, filename: string, options?: Dow
199
209
  export declare function getPluginPageSelectorItems(contract: PluginContract): PageSelectorItem[];
200
210
  /** Create a typed plugin API client from a generated MINT plugin contract. */
201
211
  export declare function createPluginClient<TClient extends object = GeneratedPluginClient>(contract: PluginContract, options: CreatePluginClientOptions): TClient;
202
- /** Send multipart form data to a generated plugin endpoint while reusing contract URL, query, and auth handling. */
212
+ /** Send multipart or raw binary data to a generated endpoint with contract URL, cancellation, and auth handling. */
203
213
  export declare function uploadPluginEndpoint<TResponse = unknown>(contract: PluginContract, endpoint: PluginEndpointDefinition, payload?: unknown, options?: PluginEndpointRequestOptions): Promise<TResponse>;
204
214
  /** Fetch a generated plugin endpoint as a Blob and optionally trigger a browser download. */
205
215
  export declare function downloadPluginEndpoint(contract: PluginContract, endpoint: PluginEndpointDefinition, payload?: unknown, options?: DownloadPluginEndpointOptions): Promise<Blob>;
@@ -1,7 +1,7 @@
1
- import { D as currentExperimentFromContext, O as getInjectedPlatformContext, k as resolveCurrentExperimentId } from "./useJobsStatusTray-DAH999_N.js";
1
+ import { D as currentExperimentFromContext, O as getInjectedPlatformContext, k as resolveCurrentExperimentId } from "./useJobsStatusTray-CVecN6Ao.js";
2
2
  import { r as useSettingsStore, t as useAuthStore } from "./auth-DZAwEeis.js";
3
3
  import { i as usePlatformContext } from "./useFormBuilder-DKekvXRs.js";
4
- import { i as useApi, r as useRequestSyncState } from "./useExperimentSelector-DdCy5VNv.js";
4
+ import { a as authenticationRequiredError, i as AuthenticationRequiredError, o as useApi, r as useRequestSyncState } from "./useExperimentSelector-DRbj6vse.js";
5
5
  import { computed, getCurrentInstance, onMounted, onUnmounted, ref, shallowRef, toValue, watch } from "vue";
6
6
  import axios from "axios";
7
7
  //#region src/composables/useAuth.ts
@@ -394,6 +394,25 @@ function usePasskey() {
394
394
  };
395
395
  }
396
396
  //#endregion
397
+ //#region src/composables/pluginFrontendBase.ts
398
+ function normalizePluginRoutePrefix(prefix) {
399
+ const candidate = prefix?.trim();
400
+ if (!candidate) return void 0;
401
+ const path = candidate.split("/").filter(Boolean).join("/");
402
+ return path ? `/${path}/` : "/";
403
+ }
404
+ /**
405
+ * Resolve the Vue Router base for a plugin frontend.
406
+ *
407
+ * Integrated plugins use the platform-injected mount prefix. Standalone and
408
+ * development builds retain the caller's Vite base unchanged.
409
+ */
410
+ function resolvePluginFrontendBase(fallbackBase = "/") {
411
+ const context = getInjectedPlatformContext();
412
+ if (!context?.isIntegrated) return fallbackBase;
413
+ return normalizePluginRoutePrefix(context.plugin?.route_prefix) ?? fallbackBase;
414
+ }
415
+ //#endregion
397
416
  //#region src/composables/useAsync.ts
398
417
  /**
399
418
  * Default error transformer.
@@ -1206,6 +1225,13 @@ function endpointParamName(param) {
1206
1225
  function endpointParamFieldName(param) {
1207
1226
  return typeof param === "string" ? param : param.fieldName ?? param.name;
1208
1227
  }
1228
+ function escapeRegExp(value) {
1229
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1230
+ }
1231
+ function replacePathParam(path, name, encoded) {
1232
+ const escapedName = escapeRegExp(name);
1233
+ return path.replace(new RegExp(`\\{${escapedName}(?::[^{}]+)?\\}`, "g"), () => encoded).replace(new RegExp(`:${escapedName}(?=/|$)`, "g"), () => encoded);
1234
+ }
1209
1235
  /** Resolve the runtime plugin API base URL from env, explicit options, platform injection, or contract metadata. */
1210
1236
  function resolvePluginBaseUrl(contract, explicitBaseUrl) {
1211
1237
  if (explicitBaseUrl) return normalizeApiBaseUrl(explicitBaseUrl) ?? explicitBaseUrl;
@@ -1222,12 +1248,8 @@ function encodePath(path, payload, pathParams) {
1222
1248
  const value = payload[fieldName] ?? payload[name];
1223
1249
  if (value === void 0 || value === null) throw new Error(`[MINT SDK] Missing path parameter '${fieldName}' for plugin endpoint ${path}`);
1224
1250
  const encoded = encodeURIComponent(String(value));
1225
- nextPath = nextPath.replace(`{${name}}`, encoded);
1226
- nextPath = nextPath.replace(`:${name}`, encoded);
1227
- if (fieldName !== name) {
1228
- nextPath = nextPath.replace(`{${fieldName}}`, encoded);
1229
- nextPath = nextPath.replace(`:${fieldName}`, encoded);
1230
- }
1251
+ nextPath = replacePathParam(nextPath, name, encoded);
1252
+ if (fieldName !== name) nextPath = replacePathParam(nextPath, fieldName, encoded);
1231
1253
  }
1232
1254
  return nextPath;
1233
1255
  }
@@ -1347,9 +1369,26 @@ function buildPluginEndpointUrl(contract, endpoint, payload, options = {}) {
1347
1369
  function queryConfig(query) {
1348
1370
  return hasKeys(query) ? { params: query } : void 0;
1349
1371
  }
1372
+ var OCTET_STREAM = "application/octet-stream";
1373
+ var MULTIPART_FORM_DATA = "multipart/form-data";
1374
+ function endpointRequestConfig(endpoint, query, options) {
1375
+ const config = {};
1376
+ if (hasKeys(query)) config.params = query;
1377
+ if (endpoint.requestContentType === OCTET_STREAM) config.headers = { "Content-Type": OCTET_STREAM };
1378
+ if (endpoint.requestContentType === MULTIPART_FORM_DATA) config.headers = { "Content-Type": void 0 };
1379
+ if (endpoint.responseContentType === OCTET_STREAM) config.responseType = "blob";
1380
+ if (options?.signal) config.signal = options.signal;
1381
+ return hasKeys(config) ? config : void 0;
1382
+ }
1350
1383
  function isFormData(value) {
1351
1384
  return typeof FormData !== "undefined" && value instanceof FormData;
1352
1385
  }
1386
+ function endpointRequestBody(endpoint, body) {
1387
+ return endpoint.requestContentType === MULTIPART_FORM_DATA ? pluginFormDataFromPayload(body) : body;
1388
+ }
1389
+ function endpointHasPayload(endpoint) {
1390
+ return Boolean(endpoint.hasBody || endpoint.pathParams?.length || endpoint.queryParams?.length);
1391
+ }
1353
1392
  function isBlob(value) {
1354
1393
  return typeof Blob !== "undefined" && value instanceof Blob;
1355
1394
  }
@@ -1411,28 +1450,32 @@ function getPluginPageSelectorItems(contract) {
1411
1450
  /** Create a typed plugin API client from a generated MINT plugin contract. */
1412
1451
  function createPluginClient(contract, options) {
1413
1452
  const client = {};
1414
- for (const [name, endpoint] of Object.entries(options.endpoints)) client[name] = async (payload) => {
1453
+ for (const [name, endpoint] of Object.entries(options.endpoints)) client[name] = async (payloadOrOptions, explicitOptions) => {
1454
+ const hasPayload = endpointHasPayload(endpoint);
1455
+ const payload = hasPayload ? payloadOrOptions : void 0;
1456
+ const callOptions = hasPayload ? explicitOptions : payloadOrOptions ?? explicitOptions;
1415
1457
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1416
1458
  const api = useApi({ baseUrl: parts.baseUrl });
1417
- const queryConfig = hasKeys(parts.query) ? { params: parts.query } : void 0;
1418
- if (endpoint.method === "get") return api.get(parts.path, queryConfig);
1459
+ const config = endpointRequestConfig(endpoint, parts.query, callOptions);
1460
+ if (endpoint.method === "get") return api.get(parts.path, config);
1419
1461
  if (endpoint.method === "delete") {
1420
- const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
1421
- const config = body === void 0 ? queryConfig : {
1422
- ...queryConfig,
1462
+ const rawBody = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
1463
+ const body = rawBody === void 0 ? void 0 : endpointRequestBody(endpoint, rawBody);
1464
+ const config = body === void 0 ? endpointRequestConfig(endpoint, parts.query, callOptions) : {
1465
+ ...endpointRequestConfig(endpoint, parts.query, callOptions),
1423
1466
  data: body
1424
1467
  };
1425
1468
  return api.delete(parts.path, config);
1426
1469
  }
1427
- const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
1428
- if (endpoint.method === "post") return api.post(parts.path, body, queryConfig);
1429
- if (endpoint.method === "put") return api.put(parts.path, body, queryConfig);
1430
- if (endpoint.method === "patch") return api.patch(parts.path, body, queryConfig);
1470
+ const body = endpointRequestBody(endpoint, requestBodyFromPayload(payload, parts.requestPayload, endpoint));
1471
+ if (endpoint.method === "post") return api.post(parts.path, body, config);
1472
+ if (endpoint.method === "put") return api.put(parts.path, body, config);
1473
+ if (endpoint.method === "patch") return api.patch(parts.path, body, config);
1431
1474
  throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`);
1432
1475
  };
1433
1476
  return client;
1434
1477
  }
1435
- /** Send multipart form data to a generated plugin endpoint while reusing contract URL, query, and auth handling. */
1478
+ /** Send multipart or raw binary data to a generated endpoint with contract URL, cancellation, and auth handling. */
1436
1479
  async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
1437
1480
  if (![
1438
1481
  "post",
@@ -1441,9 +1484,17 @@ async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
1441
1484
  ].includes(endpoint.method)) throw new Error(`[MINT SDK] Plugin upload endpoints must use POST, PUT, or PATCH; got ${endpoint.method}`);
1442
1485
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1443
1486
  const api = useApi({ baseUrl: parts.baseUrl });
1444
- const formData = pluginFormDataFromPayload(endpoint.hasBody ? requestBodyFromPayload(payload, parts.requestPayload, endpoint) : payload);
1487
+ const body = endpoint.hasBody ? requestBodyFromPayload(payload, parts.requestPayload, endpoint) : payload;
1488
+ if (endpoint.requestContentType === OCTET_STREAM) {
1489
+ const config = endpointRequestConfig(endpoint, parts.query, { signal: options.signal });
1490
+ if (endpoint.method === "post") return api.post(parts.path, body, config);
1491
+ if (endpoint.method === "put") return api.put(parts.path, body, config);
1492
+ return api.patch(parts.path, body, config);
1493
+ }
1494
+ const formData = pluginFormDataFromPayload(body);
1445
1495
  const config = {
1446
1496
  ...queryConfig(parts.query) ?? {},
1497
+ ...options.signal ? { signal: options.signal } : {},
1447
1498
  headers: { "Content-Type": void 0 }
1448
1499
  };
1449
1500
  if (endpoint.method === "post") return api.post(parts.path, formData, config);
@@ -1455,6 +1506,7 @@ async function downloadPluginEndpoint(contract, endpoint, payload, options = {})
1455
1506
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1456
1507
  const blob = await useApi({ baseUrl: parts.baseUrl }).get(parts.path, {
1457
1508
  ...queryConfig(parts.query) ?? {},
1509
+ ...options.signal ? { signal: options.signal } : {},
1458
1510
  responseType: "blob"
1459
1511
  });
1460
1512
  if (options.filename) downloadBlob(blob, options.filename, { revokeObjectUrlDelayMs: options.revokeObjectUrlDelayMs });
@@ -1564,13 +1616,17 @@ function usePluginSettings(options = {}) {
1564
1616
  reset
1565
1617
  };
1566
1618
  }
1567
- function streamHeaders(options) {
1619
+ function streamRequestAuth(options) {
1568
1620
  const headers = new Headers(options.headers);
1569
1621
  const authStore = useAuthStore();
1570
1622
  if (!authStore.isInitialized) authStore.initialize();
1571
1623
  if (authStore.token && !headers.has("Authorization")) headers.set("Authorization", `Bearer ${authStore.token}`);
1572
1624
  headers.set("Accept", "text/event-stream");
1573
- return headers;
1625
+ const token = authStore.token;
1626
+ return {
1627
+ headers,
1628
+ token: token && headers.get("Authorization") === `Bearer ${token}` ? token : void 0
1629
+ };
1574
1630
  }
1575
1631
  function parseSseEvent(block, parseJson) {
1576
1632
  let event = "message";
@@ -1659,16 +1715,24 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1659
1715
  if (!ownsConnection(connectionGeneration, connectionController)) return;
1660
1716
  error.value = null;
1661
1717
  if (!ownsConnection(connectionGeneration, connectionController)) return;
1718
+ let authenticationFailed = false;
1662
1719
  try {
1663
1720
  const url = buildPluginEndpointUrl(contract, endpoint, payload, { baseUrl: options.baseUrl });
1721
+ const requestAuth = streamRequestAuth(options);
1664
1722
  const response = await fetch(url, {
1665
1723
  method: "GET",
1666
- headers: streamHeaders(options),
1724
+ headers: requestAuth.headers,
1667
1725
  credentials: options.credentials ?? "same-origin",
1668
1726
  signal: connectionController.signal
1669
1727
  });
1670
1728
  if (!ownsConnection(connectionGeneration, connectionController)) return;
1671
- if (!response.ok) throw new Error(`Plugin event stream failed with HTTP ${response.status}`);
1729
+ if (!response.ok) {
1730
+ if (response.status === 401) {
1731
+ authenticationFailed = true;
1732
+ throw authenticationRequiredError(response, requestAuth.token);
1733
+ }
1734
+ throw new Error(`Plugin event stream failed with HTTP ${response.status}`);
1735
+ }
1672
1736
  if (!response.body) throw new Error("Plugin event stream response did not include a readable body.");
1673
1737
  isConnected.value = true;
1674
1738
  if (!ownsConnection(connectionGeneration, connectionController)) return;
@@ -1703,6 +1767,7 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1703
1767
  }
1704
1768
  }
1705
1769
  } catch (err) {
1770
+ if (err instanceof AuthenticationRequiredError) authenticationFailed = true;
1706
1771
  if (ownsConnection(connectionGeneration, connectionController) && !(err instanceof DOMException && err.name === "AbortError")) {
1707
1772
  error.value = err instanceof Error ? err.message : "Plugin event stream failed";
1708
1773
  if (ownsConnection(connectionGeneration, connectionController)) options.onError?.(err);
@@ -1714,7 +1779,8 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1714
1779
  isConnected.value = false;
1715
1780
  if (ownsConnection(connectionGeneration, connectionController)) {
1716
1781
  controller = null;
1717
- scheduleReconnect(connectionGeneration);
1782
+ if (authenticationFailed) stopped = true;
1783
+ else scheduleReconnect(connectionGeneration);
1718
1784
  }
1719
1785
  }
1720
1786
  }
@@ -1737,9 +1803,10 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1737
1803
  isConnecting.value = false;
1738
1804
  isConnected.value = false;
1739
1805
  }
1740
- if (options.immediate !== false && typeof window === "undefined") onMounted(start);
1741
- onUnmounted(stop);
1742
- if (options.immediate !== false && typeof window !== "undefined") start();
1806
+ const currentInstance = getCurrentInstance();
1807
+ if (currentInstance && options.immediate !== false && typeof window === "undefined") onMounted(start);
1808
+ if (currentInstance) onUnmounted(stop);
1809
+ if (options.immediate !== false && (typeof window !== "undefined" || !currentInstance)) start();
1743
1810
  return {
1744
1811
  isConnected,
1745
1812
  isConnecting,
@@ -1808,6 +1875,6 @@ function useCurrentExperiment(options = {}) {
1808
1875
  };
1809
1876
  }
1810
1877
  //#endregion
1811
- export { usePasskey as A, createPluginResourceClient as C, usePluginConfig as D, useCommandHistory as E, useAsync as O, wellIdsInRectangle as S, useOptimisticMutation as T, createWellPlateWells as _, pluginFormDataFromPayload as a, useWellPainting as b, usePluginClient as c, buildPluginEndpointUrl as d, resolvePluginBaseUrl as f, createRowConditions as g, createColumnConditions as h, getPluginPageSelectorItems as i, useAuth as j, useAsyncBatch as k, usePluginEventStream as l, useWellPlateValidation as m, downloadBlob as n, uploadPluginEndpoint as o, runWellPlateValidation as p, downloadPluginEndpoint as r, useCurrentExperiment as s, createPluginClient as t, usePluginSettings as u, useWellPlateAdapter as v, useResourceCrud as w, wellIdToCoordinate as x, coordinateToWellId as y };
1878
+ export { resolvePluginFrontendBase as A, createPluginResourceClient as C, usePluginConfig as D, useCommandHistory as E, useAuth as M, useAsync as O, wellIdsInRectangle as S, useOptimisticMutation as T, createWellPlateWells as _, pluginFormDataFromPayload as a, useWellPainting as b, usePluginClient as c, buildPluginEndpointUrl as d, resolvePluginBaseUrl as f, createRowConditions as g, createColumnConditions as h, getPluginPageSelectorItems as i, usePasskey as j, useAsyncBatch as k, usePluginEventStream as l, useWellPlateValidation as m, downloadBlob as n, uploadPluginEndpoint as o, runWellPlateValidation as p, downloadPluginEndpoint as r, useCurrentExperiment as s, createPluginClient as t, usePluginSettings as u, useWellPlateAdapter as v, useResourceCrud as w, wellIdToCoordinate as x, coordinateToWellId as y };
1812
1879
 
1813
- //# sourceMappingURL=composables-DyfGpYZw.js.map
1880
+ //# sourceMappingURL=composables-TpXyhRZZ.js.map