@morscherlab/mint-sdk 1.0.54 → 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 (28) 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/components/index.js +2 -2
  6. package/dist/{components-Lk_h_rON.js → components-BQwOeyiy.js} +5 -5
  7. package/dist/{components-Lk_h_rON.js.map → components-BQwOeyiy.js.map} +1 -1
  8. package/dist/composables/index.d.ts +2 -2
  9. package/dist/composables/index.js +4 -4
  10. package/dist/composables/useApi.d.ts +9 -0
  11. package/dist/composables/usePluginClient.d.ts +12 -2
  12. package/dist/{composables-GosFS8fM.js → composables-TpXyhRZZ.js} +77 -29
  13. package/dist/composables-TpXyhRZZ.js.map +1 -0
  14. package/dist/index.js +6 -6
  15. package/dist/install.js +2 -2
  16. package/dist/{useExperimentSelector-DdCy5VNv.js → useExperimentSelector-DRbj6vse.js} +33 -3
  17. package/dist/useExperimentSelector-DRbj6vse.js.map +1 -0
  18. package/dist/{useJobsStatusTray-DAH999_N.js → useJobsStatusTray-CVecN6Ao.js} +2 -2
  19. package/dist/{useJobsStatusTray-DAH999_N.js.map → useJobsStatusTray-CVecN6Ao.js.map} +1 -1
  20. package/package.json +1 -1
  21. package/src/__tests__/composables/useApi.test.ts +76 -2
  22. package/src/__tests__/composables/usePluginClient.test.ts +158 -0
  23. package/src/composables/index.ts +7 -1
  24. package/src/composables/pluginEndpointBuilder.ts +13 -4
  25. package/src/composables/useApi.ts +48 -1
  26. package/src/composables/usePluginClient.ts +125 -21
  27. package/dist/composables-GosFS8fM.js.map +0 -1
  28. package/dist/useExperimentSelector-DdCy5VNv.js.map +0 -1
@@ -1,4 +1,4 @@
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';
@@ -53,5 +53,5 @@ export { getBioTemplateComponentProps, getBioTemplateComponentBindings, toBioTem
53
53
  export { useBioTemplateWorkspace, type BioTemplateRendererBinding, type BioTemplateWorkspaceBindings, type BioTemplateWorkspaceTarget, type UseBioTemplateWorkspaceReturn, } from './useBioTemplateWorkspace';
54
54
  export { useBioTemplatePresetWorkspace, type BioTemplatePresetWorkspaceBindings, type UseBioTemplatePresetWorkspaceOptions, type UseBioTemplatePresetWorkspaceReturn, } from './useBioTemplatePresetWorkspace';
55
55
  export { useBioTemplatePackWorkspace, type UseBioTemplatePackWorkspaceOptions, type UseBioTemplatePackWorkspaceReturn, } from './useBioTemplatePackWorkspace';
56
- 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';
57
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 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-GosFS8fM.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, 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 };
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 };
@@ -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
@@ -1225,6 +1225,13 @@ function endpointParamName(param) {
1225
1225
  function endpointParamFieldName(param) {
1226
1226
  return typeof param === "string" ? param : param.fieldName ?? param.name;
1227
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
+ }
1228
1235
  /** Resolve the runtime plugin API base URL from env, explicit options, platform injection, or contract metadata. */
1229
1236
  function resolvePluginBaseUrl(contract, explicitBaseUrl) {
1230
1237
  if (explicitBaseUrl) return normalizeApiBaseUrl(explicitBaseUrl) ?? explicitBaseUrl;
@@ -1241,12 +1248,8 @@ function encodePath(path, payload, pathParams) {
1241
1248
  const value = payload[fieldName] ?? payload[name];
1242
1249
  if (value === void 0 || value === null) throw new Error(`[MINT SDK] Missing path parameter '${fieldName}' for plugin endpoint ${path}`);
1243
1250
  const encoded = encodeURIComponent(String(value));
1244
- nextPath = nextPath.replace(`{${name}}`, encoded);
1245
- nextPath = nextPath.replace(`:${name}`, encoded);
1246
- if (fieldName !== name) {
1247
- nextPath = nextPath.replace(`{${fieldName}}`, encoded);
1248
- nextPath = nextPath.replace(`:${fieldName}`, encoded);
1249
- }
1251
+ nextPath = replacePathParam(nextPath, name, encoded);
1252
+ if (fieldName !== name) nextPath = replacePathParam(nextPath, fieldName, encoded);
1250
1253
  }
1251
1254
  return nextPath;
1252
1255
  }
@@ -1366,9 +1369,26 @@ function buildPluginEndpointUrl(contract, endpoint, payload, options = {}) {
1366
1369
  function queryConfig(query) {
1367
1370
  return hasKeys(query) ? { params: query } : void 0;
1368
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
+ }
1369
1383
  function isFormData(value) {
1370
1384
  return typeof FormData !== "undefined" && value instanceof FormData;
1371
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
+ }
1372
1392
  function isBlob(value) {
1373
1393
  return typeof Blob !== "undefined" && value instanceof Blob;
1374
1394
  }
@@ -1430,28 +1450,32 @@ function getPluginPageSelectorItems(contract) {
1430
1450
  /** Create a typed plugin API client from a generated MINT plugin contract. */
1431
1451
  function createPluginClient(contract, options) {
1432
1452
  const client = {};
1433
- 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;
1434
1457
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1435
1458
  const api = useApi({ baseUrl: parts.baseUrl });
1436
- const queryConfig = hasKeys(parts.query) ? { params: parts.query } : void 0;
1437
- 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);
1438
1461
  if (endpoint.method === "delete") {
1439
- const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
1440
- const config = body === void 0 ? queryConfig : {
1441
- ...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),
1442
1466
  data: body
1443
1467
  };
1444
1468
  return api.delete(parts.path, config);
1445
1469
  }
1446
- const body = requestBodyFromPayload(payload, parts.requestPayload, endpoint);
1447
- if (endpoint.method === "post") return api.post(parts.path, body, queryConfig);
1448
- if (endpoint.method === "put") return api.put(parts.path, body, queryConfig);
1449
- 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);
1450
1474
  throw new Error(`[MINT SDK] Unsupported plugin endpoint method: ${endpoint.method}`);
1451
1475
  };
1452
1476
  return client;
1453
1477
  }
1454
- /** 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. */
1455
1479
  async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
1456
1480
  if (![
1457
1481
  "post",
@@ -1460,9 +1484,17 @@ async function uploadPluginEndpoint(contract, endpoint, payload, options = {}) {
1460
1484
  ].includes(endpoint.method)) throw new Error(`[MINT SDK] Plugin upload endpoints must use POST, PUT, or PATCH; got ${endpoint.method}`);
1461
1485
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1462
1486
  const api = useApi({ baseUrl: parts.baseUrl });
1463
- 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);
1464
1495
  const config = {
1465
1496
  ...queryConfig(parts.query) ?? {},
1497
+ ...options.signal ? { signal: options.signal } : {},
1466
1498
  headers: { "Content-Type": void 0 }
1467
1499
  };
1468
1500
  if (endpoint.method === "post") return api.post(parts.path, formData, config);
@@ -1474,6 +1506,7 @@ async function downloadPluginEndpoint(contract, endpoint, payload, options = {})
1474
1506
  const parts = pluginEndpointRequestParts(contract, endpoint, payload, options.baseUrl);
1475
1507
  const blob = await useApi({ baseUrl: parts.baseUrl }).get(parts.path, {
1476
1508
  ...queryConfig(parts.query) ?? {},
1509
+ ...options.signal ? { signal: options.signal } : {},
1477
1510
  responseType: "blob"
1478
1511
  });
1479
1512
  if (options.filename) downloadBlob(blob, options.filename, { revokeObjectUrlDelayMs: options.revokeObjectUrlDelayMs });
@@ -1583,13 +1616,17 @@ function usePluginSettings(options = {}) {
1583
1616
  reset
1584
1617
  };
1585
1618
  }
1586
- function streamHeaders(options) {
1619
+ function streamRequestAuth(options) {
1587
1620
  const headers = new Headers(options.headers);
1588
1621
  const authStore = useAuthStore();
1589
1622
  if (!authStore.isInitialized) authStore.initialize();
1590
1623
  if (authStore.token && !headers.has("Authorization")) headers.set("Authorization", `Bearer ${authStore.token}`);
1591
1624
  headers.set("Accept", "text/event-stream");
1592
- return headers;
1625
+ const token = authStore.token;
1626
+ return {
1627
+ headers,
1628
+ token: token && headers.get("Authorization") === `Bearer ${token}` ? token : void 0
1629
+ };
1593
1630
  }
1594
1631
  function parseSseEvent(block, parseJson) {
1595
1632
  let event = "message";
@@ -1678,16 +1715,24 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1678
1715
  if (!ownsConnection(connectionGeneration, connectionController)) return;
1679
1716
  error.value = null;
1680
1717
  if (!ownsConnection(connectionGeneration, connectionController)) return;
1718
+ let authenticationFailed = false;
1681
1719
  try {
1682
1720
  const url = buildPluginEndpointUrl(contract, endpoint, payload, { baseUrl: options.baseUrl });
1721
+ const requestAuth = streamRequestAuth(options);
1683
1722
  const response = await fetch(url, {
1684
1723
  method: "GET",
1685
- headers: streamHeaders(options),
1724
+ headers: requestAuth.headers,
1686
1725
  credentials: options.credentials ?? "same-origin",
1687
1726
  signal: connectionController.signal
1688
1727
  });
1689
1728
  if (!ownsConnection(connectionGeneration, connectionController)) return;
1690
- 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
+ }
1691
1736
  if (!response.body) throw new Error("Plugin event stream response did not include a readable body.");
1692
1737
  isConnected.value = true;
1693
1738
  if (!ownsConnection(connectionGeneration, connectionController)) return;
@@ -1722,6 +1767,7 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1722
1767
  }
1723
1768
  }
1724
1769
  } catch (err) {
1770
+ if (err instanceof AuthenticationRequiredError) authenticationFailed = true;
1725
1771
  if (ownsConnection(connectionGeneration, connectionController) && !(err instanceof DOMException && err.name === "AbortError")) {
1726
1772
  error.value = err instanceof Error ? err.message : "Plugin event stream failed";
1727
1773
  if (ownsConnection(connectionGeneration, connectionController)) options.onError?.(err);
@@ -1733,7 +1779,8 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1733
1779
  isConnected.value = false;
1734
1780
  if (ownsConnection(connectionGeneration, connectionController)) {
1735
1781
  controller = null;
1736
- scheduleReconnect(connectionGeneration);
1782
+ if (authenticationFailed) stopped = true;
1783
+ else scheduleReconnect(connectionGeneration);
1737
1784
  }
1738
1785
  }
1739
1786
  }
@@ -1756,9 +1803,10 @@ function usePluginEventStream(contract, endpoint, payloadOrOptions, maybeOptions
1756
1803
  isConnecting.value = false;
1757
1804
  isConnected.value = false;
1758
1805
  }
1759
- if (options.immediate !== false && typeof window === "undefined") onMounted(start);
1760
- onUnmounted(stop);
1761
- 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();
1762
1810
  return {
1763
1811
  isConnected,
1764
1812
  isConnecting,
@@ -1829,4 +1877,4 @@ function useCurrentExperiment(options = {}) {
1829
1877
  //#endregion
1830
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 };
1831
1879
 
1832
- //# sourceMappingURL=composables-GosFS8fM.js.map
1880
+ //# sourceMappingURL=composables-TpXyhRZZ.js.map