@morscherlab/mint-sdk 1.1.25 → 1.2.0-beta.2
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/README.md +9 -7
- package/dist/{ExperimentSelectorModal-B6P2msT4.js → ExperimentSelectorModal-DyPAUCLw.js} +3 -3
- package/dist/{ExperimentSelectorModal-B6P2msT4.js.map → ExperimentSelectorModal-DyPAUCLw.js.map} +1 -1
- package/dist/{SettingsModal-BW3Ar-uy.js → SettingsModal-BgKY93zh.js} +4 -4
- package/dist/{SettingsModal-BW3Ar-uy.js.map → SettingsModal-BgKY93zh.js.map} +1 -1
- package/dist/__tests__/composables/useEventStream.test.d.ts +1 -0
- package/dist/components/AutoGroupModal.vue.d.ts +1 -1
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
- package/dist/components/JobsStatusTray.vue.d.ts +2 -9
- package/dist/components/SampleLegend.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +1 -1
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -1
- package/dist/components/index.js +4 -4
- package/dist/{components-DQt0tcpY.js → components-DkHddRMl.js} +10 -16
- package/dist/components-DkHddRMl.js.map +1 -0
- package/dist/composables/index.d.ts +2 -3
- package/dist/composables/index.js +8 -8
- package/dist/composables/useEventStream.d.ts +43 -0
- package/dist/composables/useGeneratedAnalysis.d.ts +1 -3
- package/dist/composables/useJobsStatusTray.d.ts +1 -25
- package/dist/composables/usePluginClient.d.ts +3 -18
- package/dist/{composables-CkXDe7nm.js → composables-C_i90sGS.js} +32 -308
- package/dist/composables-C_i90sGS.js.map +1 -0
- package/dist/{experiment-Y9Iz7KYi.js → experiment-Cq145oEW.js} +2 -2
- package/dist/{experiment-Y9Iz7KYi.js.map → experiment-Cq145oEW.js.map} +1 -1
- package/dist/index.js +12 -12
- package/dist/install.js +4 -4
- package/dist/stores/auth.d.ts +0 -6
- package/dist/stores/index.js +2 -2
- package/dist/templates/index.js +2 -2
- package/dist/{templates-CovvRZ-9.js → templates-DsP51i-S.js} +2 -2
- package/dist/{templates-CovvRZ-9.js.map → templates-DsP51i-S.js.map} +1 -1
- package/dist/types/auth.d.ts +0 -1
- package/dist/{useApi-CDBq6z23.js → useApi-J6zFkHmn.js} +1 -2
- package/dist/useApi-J6zFkHmn.js.map +1 -0
- package/dist/{useControlSchema-BhoJzWzx.js → useControlSchema-BDx2Olha.js} +239 -103
- package/dist/useControlSchema-BDx2Olha.js.map +1 -0
- package/dist/{useExperimentSelector-D0pjj9WH.js → useExperimentSelector-CV4iNfMS.js} +2 -2
- package/dist/{useExperimentSelector-D0pjj9WH.js.map → useExperimentSelector-CV4iNfMS.js.map} +1 -1
- package/dist/{useFormBuilder-DiEcDis2.js → useFormBuilder-BLxG3BOX.js} +2 -2
- package/dist/{useFormBuilder-DiEcDis2.js.map → useFormBuilder-BLxG3BOX.js.map} +1 -1
- package/dist/{useProtocolTemplates-DHwSveE6.js → useProtocolTemplates-CS_SQl6U.js} +22 -113
- package/dist/useProtocolTemplates-CS_SQl6U.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/components/GeneratedPluginView.test.ts +0 -5
- package/src/__tests__/components/JobsStatusTray.test.ts +20 -18
- package/src/__tests__/composables/useAuth.test.ts +23 -0
- package/src/__tests__/composables/useEventStream.test.ts +140 -0
- package/src/__tests__/composables/useGeneratedAnalysis.test.ts +103 -0
- package/src/__tests__/composables/useJobsStatusTray.test.ts +25 -161
- package/src/__tests__/composables/usePluginClient.test.ts +8 -13
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +22 -1
- package/src/components/JobsStatusTray.story.vue +6 -10
- package/src/components/JobsStatusTray.vue +1 -16
- package/src/composables/index.ts +0 -7
- package/src/composables/useAuth.ts +0 -3
- package/src/composables/useEventStream.ts +314 -0
- package/src/composables/useGeneratedAnalysis.ts +40 -109
- package/src/composables/useJobsStatusTray.ts +17 -184
- package/src/composables/usePluginClient.ts +45 -249
- package/src/stores/auth.ts +0 -1
- package/src/types/auth.ts +0 -1
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +0 -15
- package/dist/components-DQt0tcpY.js.map +0 -1
- package/dist/composables/usePluginConfig.d.ts +0 -25
- package/dist/composables-CkXDe7nm.js.map +0 -1
- package/dist/useApi-CDBq6z23.js.map +0 -1
- package/dist/useControlSchema-BhoJzWzx.js.map +0 -1
- package/dist/useProtocolTemplates-DHwSveE6.js.map +0 -1
- package/src/__tests__/composables/usePluginConfig.test.ts +0 -497
- package/src/composables/usePluginConfig.ts +0 -250
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
computed,
|
|
3
|
-
getCurrentInstance,
|
|
4
3
|
onMounted,
|
|
5
|
-
onUnmounted,
|
|
6
4
|
ref,
|
|
7
5
|
shallowRef,
|
|
8
6
|
watch,
|
|
@@ -28,6 +26,12 @@ import {
|
|
|
28
26
|
pluginEndpointRequestParts,
|
|
29
27
|
requestBodyFromPayload,
|
|
30
28
|
} from './pluginEndpointBuilder'
|
|
29
|
+
import {
|
|
30
|
+
useEventStream,
|
|
31
|
+
type EventStreamMessage,
|
|
32
|
+
type EventStreamTransport,
|
|
33
|
+
type UseEventStreamReturn,
|
|
34
|
+
} from './useEventStream'
|
|
31
35
|
import type {
|
|
32
36
|
ExperimentSummary,
|
|
33
37
|
GeneratedJobDefinition,
|
|
@@ -204,13 +208,7 @@ export interface UsePluginSettingsReturn<TSettings = Record<string, unknown>> {
|
|
|
204
208
|
reset: () => void
|
|
205
209
|
}
|
|
206
210
|
|
|
207
|
-
export
|
|
208
|
-
event: string
|
|
209
|
-
data: TData
|
|
210
|
-
id?: string
|
|
211
|
-
retry?: number
|
|
212
|
-
raw: string
|
|
213
|
-
}
|
|
211
|
+
export type PluginEventStreamMessage<TData = string> = EventStreamMessage<TData>
|
|
214
212
|
|
|
215
213
|
export interface PluginEventStreamOptions<TData = string> {
|
|
216
214
|
/** Override the generated or platform-injected API base URL. */
|
|
@@ -232,15 +230,7 @@ export interface PluginEventStreamOptions<TData = string> {
|
|
|
232
230
|
onError?: (error: unknown) => void
|
|
233
231
|
}
|
|
234
232
|
|
|
235
|
-
export
|
|
236
|
-
isConnected: Ref<boolean>
|
|
237
|
-
isConnecting: Ref<boolean>
|
|
238
|
-
error: Ref<string | null>
|
|
239
|
-
lastMessage: Ref<PluginEventStreamMessage<TData> | null>
|
|
240
|
-
lastEventId: Ref<string | null>
|
|
241
|
-
start: () => void
|
|
242
|
-
stop: () => void
|
|
243
|
-
}
|
|
233
|
+
export type UsePluginEventStreamReturn<TData = string> = UseEventStreamReturn<TData>
|
|
244
234
|
|
|
245
235
|
export type PluginFormDataValue =
|
|
246
236
|
| string
|
|
@@ -544,11 +534,6 @@ export async function downloadPluginEndpoint(
|
|
|
544
534
|
return blob
|
|
545
535
|
}
|
|
546
536
|
|
|
547
|
-
/** Return a generated plugin client from setup code with a stable typed identity. */
|
|
548
|
-
export function usePluginClient<TClient>(client: TClient): TClient {
|
|
549
|
-
return client
|
|
550
|
-
}
|
|
551
|
-
|
|
552
537
|
function normalizePluginSettingsOptions(options: UsePluginSettingsOptions | string = {}): UsePluginSettingsOptions {
|
|
553
538
|
return typeof options === 'string' ? { pluginName: options } : options
|
|
554
539
|
}
|
|
@@ -797,13 +782,13 @@ export function usePluginSettings<TSettings = Record<string, unknown>>(
|
|
|
797
782
|
}
|
|
798
783
|
|
|
799
784
|
function streamRequestAuth(
|
|
800
|
-
|
|
785
|
+
requestHeaders: HeadersInit | undefined,
|
|
801
786
|
policy: { requiresAuth: boolean },
|
|
802
787
|
): {
|
|
803
788
|
headers: Headers
|
|
804
789
|
token?: string
|
|
805
790
|
} {
|
|
806
|
-
const headers = new Headers(
|
|
791
|
+
const headers = new Headers(requestHeaders)
|
|
807
792
|
const authStore = useAuthStore()
|
|
808
793
|
if (!authStore.isInitialized) {
|
|
809
794
|
authStore.initialize()
|
|
@@ -811,7 +796,6 @@ function streamRequestAuth(
|
|
|
811
796
|
if (policy.requiresAuth && authStore.token && !headers.has('Authorization')) {
|
|
812
797
|
headers.set('Authorization', `Bearer ${authStore.token}`)
|
|
813
798
|
}
|
|
814
|
-
headers.set('Accept', 'text/event-stream')
|
|
815
799
|
const token = policy.requiresAuth ? authStore.token : undefined
|
|
816
800
|
return {
|
|
817
801
|
headers,
|
|
@@ -819,40 +803,22 @@ function streamRequestAuth(
|
|
|
819
803
|
}
|
|
820
804
|
}
|
|
821
805
|
|
|
822
|
-
function
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
let retry: number | undefined
|
|
829
|
-
const dataLines: string[] = []
|
|
830
|
-
|
|
831
|
-
for (const line of block.split(/\r?\n/)) {
|
|
832
|
-
if (!line || line.startsWith(':')) continue
|
|
833
|
-
const separator = line.indexOf(':')
|
|
834
|
-
const field = separator === -1 ? line : line.slice(0, separator)
|
|
835
|
-
const value = separator === -1
|
|
836
|
-
? ''
|
|
837
|
-
: line.slice(separator + 1).replace(/^ /, '')
|
|
838
|
-
|
|
839
|
-
if (field === 'event') event = value || 'message'
|
|
840
|
-
if (field === 'data') dataLines.push(value)
|
|
841
|
-
if (field === 'id') id = value
|
|
842
|
-
if (field === 'retry') {
|
|
843
|
-
const parsed = Number(value)
|
|
844
|
-
if (Number.isFinite(parsed)) retry = parsed
|
|
806
|
+
function pluginEventStreamTransport(
|
|
807
|
+
endpoint: PluginEndpointDefinition,
|
|
808
|
+
): EventStreamTransport {
|
|
809
|
+
return async (url, init = {}) => {
|
|
810
|
+
if (typeof fetch !== 'function') {
|
|
811
|
+
throw new Error('[MINT SDK] fetch is required for plugin event streams.')
|
|
845
812
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
raw: block,
|
|
813
|
+
const requestAuth = streamRequestAuth(
|
|
814
|
+
init.headers,
|
|
815
|
+
{ requiresAuth: endpoint.requiresAuth !== false },
|
|
816
|
+
)
|
|
817
|
+
const response = await fetch(url, { ...init, headers: requestAuth.headers })
|
|
818
|
+
if (response.status === 401) {
|
|
819
|
+
throw authenticationRequiredError(response, requestAuth.token)
|
|
820
|
+
}
|
|
821
|
+
return response
|
|
856
822
|
}
|
|
857
823
|
}
|
|
858
824
|
|
|
@@ -891,6 +857,9 @@ export function usePluginEventStream<TData = string>(
|
|
|
891
857
|
payloadOrOptions?: unknown,
|
|
892
858
|
maybeOptions?: PluginEventStreamOptions<TData>,
|
|
893
859
|
): UsePluginEventStreamReturn<TData> {
|
|
860
|
+
if (endpoint.method !== 'get') {
|
|
861
|
+
throw new Error(`[MINT SDK] Plugin event streams must use GET; got ${endpoint.method}`)
|
|
862
|
+
}
|
|
894
863
|
const payload = maybeOptions === undefined && looksLikeEventStreamOptions(payloadOrOptions)
|
|
895
864
|
? undefined
|
|
896
865
|
: payloadOrOptions
|
|
@@ -899,198 +868,25 @@ export function usePluginEventStream<TData = string>(
|
|
|
899
868
|
? payloadOrOptions
|
|
900
869
|
: maybeOptions ?? {}
|
|
901
870
|
) as PluginEventStreamOptions<TData>
|
|
902
|
-
const isConnected = ref(false)
|
|
903
|
-
const isConnecting = ref(false)
|
|
904
|
-
const error = ref<string | null>(null)
|
|
905
|
-
const lastMessage = shallowRef<PluginEventStreamMessage<TData> | null>(null)
|
|
906
|
-
const lastEventId = ref<string | null>(null)
|
|
907
871
|
const responseType = endpoint.responseType?.trim()
|
|
908
872
|
const parseJson = options.parseJson ?? Boolean(responseType && responseType !== 'string')
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
&& generation === connectionGeneration
|
|
927
|
-
&& controller === connectionController
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
function scheduleReconnect(connectionGeneration: number): void {
|
|
931
|
-
if (
|
|
932
|
-
stopped
|
|
933
|
-
|| generation !== connectionGeneration
|
|
934
|
-
|| options.reconnect === false
|
|
935
|
-
) return
|
|
936
|
-
clearReconnectTimer()
|
|
937
|
-
reconnectTimer = setTimeout(() => {
|
|
938
|
-
reconnectTimer = null
|
|
939
|
-
if (stopped || generation !== connectionGeneration) return
|
|
940
|
-
void connect(connectionGeneration)
|
|
941
|
-
}, options.reconnectDelayMs ?? 2000)
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
async function connect(connectionGeneration: number): Promise<void> {
|
|
945
|
-
if (stopped || generation !== connectionGeneration) return
|
|
946
|
-
if (endpoint.method !== 'get') {
|
|
947
|
-
throw new Error(`[MINT SDK] Plugin event streams must use GET; got ${endpoint.method}`)
|
|
948
|
-
}
|
|
949
|
-
if (typeof fetch !== 'function') {
|
|
950
|
-
throw new Error('[MINT SDK] fetch is required for plugin event streams.')
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
controller?.abort()
|
|
954
|
-
const connectionController = new AbortController()
|
|
955
|
-
controller = connectionController
|
|
956
|
-
isConnecting.value = true
|
|
957
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
958
|
-
error.value = null
|
|
959
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
960
|
-
|
|
961
|
-
let authenticationFailed = false
|
|
962
|
-
try {
|
|
963
|
-
const url = buildPluginEndpointUrl(contract, endpoint, payload, {
|
|
964
|
-
baseUrl: options.baseUrl,
|
|
965
|
-
})
|
|
966
|
-
const requestAuth = streamRequestAuth(
|
|
967
|
-
options as PluginEventStreamOptions<unknown>,
|
|
968
|
-
{ requiresAuth: endpoint.requiresAuth !== false },
|
|
969
|
-
)
|
|
970
|
-
const response = await fetch(url, {
|
|
971
|
-
method: 'GET',
|
|
972
|
-
headers: requestAuth.headers,
|
|
973
|
-
credentials: options.credentials ?? 'same-origin',
|
|
974
|
-
signal: connectionController.signal,
|
|
975
|
-
})
|
|
976
|
-
|
|
977
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
978
|
-
|
|
979
|
-
if (!response.ok) {
|
|
980
|
-
if (response.status === 401) {
|
|
981
|
-
authenticationFailed = true
|
|
982
|
-
throw authenticationRequiredError(response, requestAuth.token)
|
|
983
|
-
}
|
|
984
|
-
throw new Error(`Plugin event stream failed with HTTP ${response.status}`)
|
|
985
|
-
}
|
|
986
|
-
if (!response.body) {
|
|
987
|
-
throw new Error('Plugin event stream response did not include a readable body.')
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
isConnected.value = true
|
|
991
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
992
|
-
options.onOpen?.()
|
|
993
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
994
|
-
const reader = response.body.getReader()
|
|
995
|
-
const decoder = new TextDecoder()
|
|
996
|
-
let buffer = ''
|
|
997
|
-
|
|
998
|
-
for (;;) {
|
|
999
|
-
const { value, done } = await reader.read()
|
|
1000
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
1001
|
-
if (done) break
|
|
1002
|
-
buffer += decoder.decode(value, { stream: true })
|
|
1003
|
-
|
|
1004
|
-
let boundary = buffer.search(/\r?\n\r?\n/)
|
|
1005
|
-
while (boundary !== -1) {
|
|
1006
|
-
const block = buffer.slice(0, boundary)
|
|
1007
|
-
buffer = buffer.slice(buffer[boundary] === '\r' ? boundary + 4 : boundary + 2)
|
|
1008
|
-
const message = parseSseEvent<TData>(block, parseJson)
|
|
1009
|
-
if (message) {
|
|
1010
|
-
lastMessage.value = message
|
|
1011
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
1012
|
-
if (message.id !== undefined) {
|
|
1013
|
-
lastEventId.value = message.id
|
|
1014
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
1015
|
-
}
|
|
1016
|
-
if (message.retry !== undefined) {
|
|
1017
|
-
options.reconnectDelayMs = message.retry
|
|
1018
|
-
}
|
|
1019
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
1020
|
-
options.onMessage?.(message)
|
|
1021
|
-
if (!ownsConnection(connectionGeneration, connectionController)) return
|
|
1022
|
-
}
|
|
1023
|
-
boundary = buffer.search(/\r?\n\r?\n/)
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
} catch (err) {
|
|
1027
|
-
if (err instanceof AuthenticationRequiredError) authenticationFailed = true
|
|
1028
|
-
if (
|
|
1029
|
-
ownsConnection(connectionGeneration, connectionController)
|
|
1030
|
-
&& !(err instanceof DOMException && err.name === 'AbortError')
|
|
1031
|
-
) {
|
|
1032
|
-
const message = err instanceof Error ? err.message : 'Plugin event stream failed'
|
|
1033
|
-
error.value = message
|
|
1034
|
-
if (ownsConnection(connectionGeneration, connectionController)) {
|
|
1035
|
-
options.onError?.(err)
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
} finally {
|
|
1039
|
-
if (ownsConnection(connectionGeneration, connectionController)) {
|
|
1040
|
-
isConnecting.value = false
|
|
1041
|
-
if (ownsConnection(connectionGeneration, connectionController)) {
|
|
1042
|
-
isConnected.value = false
|
|
1043
|
-
if (ownsConnection(connectionGeneration, connectionController)) {
|
|
1044
|
-
controller = null
|
|
1045
|
-
if (authenticationFailed) {
|
|
1046
|
-
stopped = true
|
|
1047
|
-
} else {
|
|
1048
|
-
scheduleReconnect(connectionGeneration)
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
function start(): void {
|
|
1057
|
-
if (!stopped) return
|
|
1058
|
-
stopped = false
|
|
1059
|
-
clearReconnectTimer()
|
|
1060
|
-
generation += 1
|
|
1061
|
-
void connect(generation)
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
function stop(): void {
|
|
1065
|
-
if (stopped) return
|
|
1066
|
-
stopped = true
|
|
1067
|
-
generation += 1
|
|
1068
|
-
clearReconnectTimer()
|
|
1069
|
-
controller?.abort()
|
|
1070
|
-
controller = null
|
|
1071
|
-
isConnecting.value = false
|
|
1072
|
-
isConnected.value = false
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
const currentInstance = getCurrentInstance()
|
|
1076
|
-
if (currentInstance && options.immediate !== false && typeof window === 'undefined') {
|
|
1077
|
-
onMounted(start)
|
|
1078
|
-
}
|
|
1079
|
-
if (currentInstance) onUnmounted(stop)
|
|
1080
|
-
|
|
1081
|
-
if (options.immediate !== false && (typeof window !== 'undefined' || !currentInstance)) {
|
|
1082
|
-
start()
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
return {
|
|
1086
|
-
isConnected,
|
|
1087
|
-
isConnecting,
|
|
1088
|
-
error,
|
|
1089
|
-
lastMessage,
|
|
1090
|
-
lastEventId,
|
|
1091
|
-
start,
|
|
1092
|
-
stop,
|
|
1093
|
-
}
|
|
873
|
+
return useEventStream<TData>(
|
|
874
|
+
() => buildPluginEndpointUrl(contract, endpoint, payload, { baseUrl: options.baseUrl }),
|
|
875
|
+
{
|
|
876
|
+
transport: pluginEventStreamTransport(endpoint),
|
|
877
|
+
immediate: options.immediate,
|
|
878
|
+
reconnect: options.reconnect,
|
|
879
|
+
reconnectDelayMs: options.reconnectDelayMs,
|
|
880
|
+
parseJson,
|
|
881
|
+
credentials: options.credentials,
|
|
882
|
+
headers: options.headers,
|
|
883
|
+
shouldReconnect: cause => !(cause instanceof AuthenticationRequiredError),
|
|
884
|
+
onOpen: options.onOpen,
|
|
885
|
+
onMessage: options.onMessage,
|
|
886
|
+
onError: options.onError,
|
|
887
|
+
errorLabel: 'Plugin event stream',
|
|
888
|
+
},
|
|
889
|
+
)
|
|
1094
890
|
}
|
|
1095
891
|
|
|
1096
892
|
/** Read and optionally load the current platform experiment for integrated plugin views. */
|
package/src/stores/auth.ts
CHANGED
package/src/types/auth.ts
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for usePluginConfig.
|
|
3
|
-
*
|
|
4
|
-
* Covers the plugin settings life-cycle used by every plugin's
|
|
5
|
-
* settings pane:
|
|
6
|
-
*
|
|
7
|
-
* - resolvedName prefers explicit pluginName, falls back to platform plugin
|
|
8
|
-
* - load() populates config + savedConfig from /plugins/{name}/config
|
|
9
|
-
* - save() PATCHes the endpoint, updates savedConfig, returns true
|
|
10
|
-
* - isDirty reflects user edits vs last saved state
|
|
11
|
-
* - reset() restores config to savedConfig and clears error
|
|
12
|
-
* - lastLoadedAt / lastSavedAt track successful syncs
|
|
13
|
-
* - error messages bubble up from network failures
|
|
14
|
-
*/
|
|
15
|
-
export {};
|