fumadocs-openapi 10.6.5 → 10.6.7
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/css/generated/shared.css +59 -6
- package/dist/generate-file.js +3 -2
- package/dist/i18n.d.ts +3 -1
- package/dist/i18n.js +3 -1
- package/dist/playground/auth.js +92 -0
- package/dist/playground/client.d.ts +5 -12
- package/dist/playground/client.js +257 -217
- package/dist/playground/components/inputs.js +2 -2
- package/dist/playground/components/oauth-dialog.js +126 -163
- package/dist/playground/components/result-display.d.ts +16 -0
- package/dist/playground/components/result-display.js +141 -0
- package/dist/playground/components/server-select.js +1 -1
- package/dist/playground/components/spinner.js +14 -0
- package/dist/playground/fetcher.d.ts +9 -3
- package/dist/playground/fetcher.js +7 -18
- package/dist/playground/status-info.js +27 -23
- package/dist/requests/generators/csharp.js +2 -1
- package/dist/requests/generators/curl.js +5 -5
- package/dist/requests/generators/go.js +5 -5
- package/dist/requests/generators/java.js +4 -4
- package/dist/requests/generators/javascript.js +3 -3
- package/dist/requests/generators/python.js +5 -4
- package/dist/requests/media/adapter.js +7 -7
- package/dist/requests/string-utils.js +25 -4
- package/dist/requests/types.d.ts +3 -2
- package/dist/ui/api-page.js +3 -1
- package/dist/ui/base.d.ts +8 -4
- package/dist/ui/base.js +6 -1
- package/dist/ui/client/boundary.lazy.js +2 -1
- package/dist/ui/client/i18n.js +6 -4
- package/dist/ui/client/storage-key.js +1 -1
- package/dist/ui/components/dialog.js +1 -1
- package/dist/ui/contexts/api.d.ts +6 -3
- package/dist/ui/contexts/api.js +7 -2
- package/dist/ui/create-client.js +5 -0
- package/dist/ui/operation/client.js +1 -1
- package/dist/ui/operation/index.js +1 -1
- package/dist/ui/operation/request-tabs.d.ts +10 -0
- package/dist/ui/operation/request-tabs.js +44 -38
- package/dist/ui/operation/usage-tabs/client.js +1 -1
- package/dist/ui/schema/client.js +2 -2
- package/dist/ui/schema/index.js +1 -1
- package/dist/utils/pages/to-text.js +5 -4
- package/dist/utils/schema/index.d.ts +3 -4
- package/dist/utils/schema/index.js +4 -9
- package/dist/utils/use-query.js +2 -1
- package/package.json +11 -10
|
@@ -3,8 +3,9 @@ import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../util
|
|
|
3
3
|
import { getPreferredType } from "../utils/schema/index.js";
|
|
4
4
|
import { useStorageKey } from "../ui/client/storage-key.js";
|
|
5
5
|
import { useApiContext, useServerContext } from "../ui/contexts/api.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useTranslations } from "../ui/client/i18n.js";
|
|
7
7
|
import { cn } from "../utils/cn.js";
|
|
8
|
+
import { DefaultResultDisplay } from "./components/result-display.js";
|
|
8
9
|
import { MethodLabel } from "../ui/components/method-label.js";
|
|
9
10
|
import { useQuery } from "../utils/use-query.js";
|
|
10
11
|
import { encodeRequestData } from "../requests/media/encode.js";
|
|
@@ -12,19 +13,20 @@ import { dereferenceSwallow } from "../utils/schema/dereference.js";
|
|
|
12
13
|
import { SchemaProvider, anyFields, useResolvedSchema } from "./schema.js";
|
|
13
14
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/components/select.js";
|
|
14
15
|
import { labelVariants } from "../ui/components/input.js";
|
|
15
|
-
import { useTranslations } from "../ui/client/i18n.js";
|
|
16
16
|
import ServerSelect from "./components/server-select.js";
|
|
17
17
|
import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/inputs.js";
|
|
18
|
-
import { ClientCodeBlock } from "../ui/components/codeblock.js";
|
|
19
18
|
import { useOperationContext } from "../ui/operation/client.js";
|
|
20
|
-
import {
|
|
19
|
+
import { useAuth } from "./auth.js";
|
|
20
|
+
import { OAuthDialog, OAuthDialogContent, OAuthDialogTrigger } from "./components/oauth-dialog.js";
|
|
21
|
+
import { Spinner } from "./components/spinner.js";
|
|
21
22
|
import { Fragment, useEffect, useMemo, useRef, useState } from "react";
|
|
22
23
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
23
24
|
import { ChevronDown, LoaderCircle } from "lucide-react";
|
|
24
|
-
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
|
|
25
25
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
26
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
|
|
26
27
|
import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
|
|
27
|
-
import { objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
28
|
+
import { arrayStartsWith, objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
29
|
+
import { useOnChange } from "fumadocs-core/utils/use-on-change";
|
|
28
30
|
//#region src/playground/client.tsx
|
|
29
31
|
function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly, readOnly, ...rest }) {
|
|
30
32
|
const t = useTranslations();
|
|
@@ -51,13 +53,7 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
51
53
|
]);
|
|
52
54
|
const { example: exampleId, examples, setExampleData } = useOperationContext();
|
|
53
55
|
const { server } = useServerContext();
|
|
54
|
-
const
|
|
55
|
-
const { mediaAdapters, client: { playground: { components: { ResultDisplay = DefaultResultDisplay, CollapsiblePanel = DefaultCollapsiblePanel } = {}, requestTimeout, fetchOptions = { requestTimeout }, transformAuthInputs, renderBodyField } = {} } } = useApiContext();
|
|
56
|
-
const [securityId, setSecurityId] = useState(() => {
|
|
57
|
-
const idx = securities.findIndex((s) => s.every((entry) => !entry.deprecated));
|
|
58
|
-
return idx === -1 ? 0 : idx;
|
|
59
|
-
});
|
|
60
|
-
const { inputs, mapInputs, initAuthValues } = useAuthInputs(securities[securityId], transformAuthInputs);
|
|
56
|
+
const { mediaAdapters, client: { playground: { components: { ResultDisplay = DefaultResultDisplay, CollapsiblePanel = DefaultCollapsiblePanel } = {}, requestTimeout, fetchOptions = { requestTimeout }, renderBodyField } = {} } } = useApiContext();
|
|
61
57
|
const defaultValues = useMemo(() => {
|
|
62
58
|
const requestData = examples.find((example) => example.id === exampleId)?.data;
|
|
63
59
|
return {
|
|
@@ -69,6 +65,7 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
69
65
|
};
|
|
70
66
|
}, [examples, exampleId]);
|
|
71
67
|
const stf = useStf({ defaultValues });
|
|
68
|
+
const { inputs, requirementId, setRequirementId, mapInputs, initAuthInputs } = useAuthInputs(stf.dataEngine, securities);
|
|
72
69
|
const testQuery = useQuery(async (input) => {
|
|
73
70
|
const fetcher = await import("./fetcher.js").then((mod) => mod.createBrowserFetcher(mediaAdapters, {
|
|
74
71
|
proxyUrl,
|
|
@@ -82,23 +79,21 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
82
79
|
return fetcher.fetch(joinURL(withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin), resolveRequestData(route, encoded)), encoded);
|
|
83
80
|
});
|
|
84
81
|
const timerRef = useRef(null);
|
|
82
|
+
const stfSync = useRef(false);
|
|
83
|
+
function triggerExampleUpdate() {
|
|
84
|
+
const data = {
|
|
85
|
+
...mapInputs(stf.dataEngine.getData()),
|
|
86
|
+
method,
|
|
87
|
+
bodyMediaType: body?.mediaType
|
|
88
|
+
};
|
|
89
|
+
setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));
|
|
90
|
+
}
|
|
85
91
|
useListener({
|
|
86
92
|
stf,
|
|
87
93
|
onUpdate() {
|
|
94
|
+
if (!stfSync.current) return;
|
|
88
95
|
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
89
|
-
timerRef.current = window.setTimeout(
|
|
90
|
-
const values = stf.dataEngine.getData();
|
|
91
|
-
for (const item of inputs) {
|
|
92
|
-
const value = stf.dataEngine.get(item.fieldName);
|
|
93
|
-
if (value) localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));
|
|
94
|
-
}
|
|
95
|
-
const data = {
|
|
96
|
-
...mapInputs(values),
|
|
97
|
-
method,
|
|
98
|
-
bodyMediaType: body?.mediaType
|
|
99
|
-
};
|
|
100
|
-
setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));
|
|
101
|
-
}, timerRef.current ? 400 : 0);
|
|
96
|
+
timerRef.current = window.setTimeout(triggerExampleUpdate, 400);
|
|
102
97
|
}
|
|
103
98
|
});
|
|
104
99
|
useEffect(() => {
|
|
@@ -106,7 +101,13 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
106
101
|
stf.dataEngine.reset(defaultValues);
|
|
107
102
|
}, [defaultValues]);
|
|
108
103
|
useEffect(() => {
|
|
109
|
-
|
|
104
|
+
const reset = initAuthInputs();
|
|
105
|
+
triggerExampleUpdate();
|
|
106
|
+
stfSync.current = true;
|
|
107
|
+
return () => {
|
|
108
|
+
stfSync.current = false;
|
|
109
|
+
reset();
|
|
110
|
+
};
|
|
110
111
|
}, [defaultValues, inputs]);
|
|
111
112
|
return /* @__PURE__ */ jsx(StfProvider, {
|
|
112
113
|
value: stf,
|
|
@@ -118,7 +119,7 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
118
119
|
...rest,
|
|
119
120
|
className: cn("not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground", rest.className),
|
|
120
121
|
onSubmit: (e) => {
|
|
121
|
-
testQuery.start(
|
|
122
|
+
testQuery.start(stf.dataEngine.getData());
|
|
122
123
|
e.preventDefault();
|
|
123
124
|
},
|
|
124
125
|
children: [
|
|
@@ -146,10 +147,10 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
146
147
|
data: testQuery.data,
|
|
147
148
|
reset: testQuery.reset
|
|
148
149
|
}) : null,
|
|
149
|
-
securities.length > 0 && /* @__PURE__ */ jsx(
|
|
150
|
+
securities.length > 0 && /* @__PURE__ */ jsx(SecurityRequirements, {
|
|
150
151
|
securities,
|
|
151
|
-
securityId,
|
|
152
|
-
setSecurityId,
|
|
152
|
+
securityId: requirementId,
|
|
153
|
+
setSecurityId: setRequirementId,
|
|
153
154
|
children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, stringifyFieldKey(input.fieldName)))
|
|
154
155
|
}),
|
|
155
156
|
/* @__PURE__ */ jsx(ParametersForm, { parameters }),
|
|
@@ -163,50 +164,62 @@ function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly,
|
|
|
163
164
|
})
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
|
-
function
|
|
167
|
-
return /* @__PURE__ */ jsx("div", {
|
|
168
|
-
className: "flex flex-col gap-2 max-w-[600px]",
|
|
169
|
-
children: security.map((item) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
170
|
-
className: cn("font-mono font-medium", item.deprecated && "text-fd-muted-foreground line-through"),
|
|
171
|
-
children: item.id
|
|
172
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
173
|
-
className: "text-fd-muted-foreground whitespace-pre-wrap",
|
|
174
|
-
children: item.description
|
|
175
|
-
})] }, item.id))
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
function SecurityTabs({ securities, setSecurityId, securityId, children }) {
|
|
179
|
-
const [open, setOpen] = useState(false);
|
|
180
|
-
const engine = useDataEngine();
|
|
167
|
+
function SecurityRequirements({ securities, setSecurityId, securityId, children }) {
|
|
181
168
|
const t = useTranslations();
|
|
169
|
+
const { isLoading, error } = useAuth();
|
|
170
|
+
const defaultOpen = isLoading || error != null;
|
|
171
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
182
172
|
const { CollapsiblePanel = DefaultCollapsiblePanel } = useApiContext().client.playground?.components ?? {};
|
|
183
|
-
|
|
184
|
-
|
|
173
|
+
useOnChange(defaultOpen, () => {
|
|
174
|
+
if (defaultOpen) setOpen(true);
|
|
175
|
+
});
|
|
176
|
+
return /* @__PURE__ */ jsxs(CollapsiblePanel, {
|
|
177
|
+
title: /* @__PURE__ */ jsxs(Fragment$1, { children: [t.authorization, isLoading && /* @__PURE__ */ jsxs("span", {
|
|
178
|
+
className: "border-s ps-2 inline-flex items-center gap-1.5 text-fd-muted-foreground text-xs font-mono",
|
|
179
|
+
children: [
|
|
180
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
181
|
+
" ",
|
|
182
|
+
t.fetchingToken
|
|
183
|
+
]
|
|
184
|
+
})] }),
|
|
185
185
|
"data-type": "authorization",
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
children: /* @__PURE__ */ jsx(
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
open,
|
|
187
|
+
onOpenChange: setOpen,
|
|
188
|
+
children: [
|
|
189
|
+
error != null && /* @__PURE__ */ jsxs("div", {
|
|
190
|
+
className: "p-2 border rounded-lg bg-fd-secondary",
|
|
191
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
192
|
+
className: "text-fd-muted-foreground font-medium mb-1",
|
|
193
|
+
children: t.fetchTokenError
|
|
194
|
+
}), /* @__PURE__ */ jsx("p", { children: String(error) })]
|
|
195
|
+
}),
|
|
196
|
+
/* @__PURE__ */ jsxs(Select, {
|
|
197
|
+
value: securityId.toString(),
|
|
198
|
+
onValueChange: (v) => setSecurityId(Number(v)),
|
|
199
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { children: /* @__PURE__ */ jsx(SecurityRequirement, { requirement: securities[securityId] }) }) }), /* @__PURE__ */ jsx(SelectContent, { children: securities.map((security, i) => /* @__PURE__ */ jsx(SelectItem, {
|
|
200
|
+
value: i.toString(),
|
|
201
|
+
children: /* @__PURE__ */ jsx(SecurityRequirement, { requirement: security })
|
|
202
|
+
}, i)) })]
|
|
203
|
+
}),
|
|
204
|
+
children
|
|
205
|
+
]
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function SecurityRequirement({ requirement }) {
|
|
209
|
+
const { schemes } = useApiContext();
|
|
210
|
+
return /* @__PURE__ */ jsx("div", {
|
|
211
|
+
className: "flex flex-col gap-2 max-w-[600px]",
|
|
212
|
+
children: requirement.map((item) => {
|
|
213
|
+
const scheme = schemes[item.id];
|
|
214
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
215
|
+
className: cn("font-mono font-medium", scheme.deprecated && "text-fd-muted-foreground line-through"),
|
|
216
|
+
children: item.id
|
|
217
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
218
|
+
className: "text-fd-muted-foreground whitespace-pre-wrap",
|
|
219
|
+
children: scheme.description
|
|
220
|
+
})] }, item.id);
|
|
221
|
+
})
|
|
194
222
|
});
|
|
195
|
-
for (let i = 0; i < securities.length; i++) {
|
|
196
|
-
const security = securities[i];
|
|
197
|
-
for (const item of security) if (item.type === "oauth2") return /* @__PURE__ */ jsx(OauthDialog, {
|
|
198
|
-
scheme: item,
|
|
199
|
-
scopes: item.scopes,
|
|
200
|
-
open,
|
|
201
|
-
setOpen: (v) => {
|
|
202
|
-
setOpen(v);
|
|
203
|
-
if (v) setSecurityId(i);
|
|
204
|
-
},
|
|
205
|
-
setToken: (token) => engine.update(["header", "Authorization"], token),
|
|
206
|
-
children: result
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
return result;
|
|
210
223
|
}
|
|
211
224
|
const ParamTypes = [
|
|
212
225
|
"path",
|
|
@@ -287,98 +300,97 @@ function BodyInput({ field: _field }) {
|
|
|
287
300
|
})
|
|
288
301
|
});
|
|
289
302
|
}
|
|
290
|
-
function useAuthInputs(
|
|
303
|
+
function useAuthInputs(engine, requirements) {
|
|
304
|
+
const authCtx = useAuth();
|
|
291
305
|
const storageKeys = useStorageKey();
|
|
292
306
|
const t = useTranslations();
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
307
|
+
const { schemes, client: { playground: { transformAuthInputs } = {} } } = useApiContext();
|
|
308
|
+
const [requirementId, setRequirementId] = useState(() => {
|
|
309
|
+
if (requirements.length === 0) return -1;
|
|
310
|
+
const idx = requirements.findIndex((s) => s.every((item) => !schemes[item.id].deprecated));
|
|
311
|
+
return idx !== -1 ? idx : 0;
|
|
312
|
+
});
|
|
313
|
+
const requirement = requirementId === -1 ? null : requirements[requirementId];
|
|
314
|
+
let inputs = useMemo(() => {
|
|
315
|
+
if (!requirement) return [];
|
|
316
|
+
return requirement.map((item) => {
|
|
317
|
+
const scheme = schemes[item.id];
|
|
318
|
+
if (scheme.type === "http" && scheme.scheme === "basic") {
|
|
319
|
+
const fieldName = ["header", "Authorization"];
|
|
320
|
+
return {
|
|
321
|
+
fieldName,
|
|
322
|
+
schemeId: item.id,
|
|
323
|
+
storageKey: storageKeys.AuthField(item.id),
|
|
324
|
+
defaultValue: {
|
|
325
|
+
username: "",
|
|
326
|
+
password: ""
|
|
327
|
+
},
|
|
328
|
+
mapOutput(out) {
|
|
329
|
+
if (out && typeof out === "object") {
|
|
330
|
+
const obj = out;
|
|
331
|
+
return `Basic ${btoa(`${obj.username ?? ""}:${obj.password ?? ""}`)}`;
|
|
318
332
|
}
|
|
333
|
+
return out;
|
|
319
334
|
},
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
336
|
-
className: "flex gap-2",
|
|
337
|
-
children: [/* @__PURE__ */ jsx(FieldInput, {
|
|
338
|
-
fieldName,
|
|
339
|
-
field: { type: "string" },
|
|
340
|
-
className: "flex-1"
|
|
341
|
-
}), /* @__PURE__ */ jsx(OauthDialogTrigger, {
|
|
342
|
-
type: "button",
|
|
343
|
-
className: cn(buttonVariants({
|
|
344
|
-
size: "sm",
|
|
345
|
-
color: "secondary"
|
|
346
|
-
})),
|
|
347
|
-
children: t.authorize
|
|
348
|
-
})]
|
|
349
|
-
})]
|
|
350
|
-
})
|
|
351
|
-
});
|
|
352
|
-
} else if (security.type === "http") {
|
|
353
|
-
const fieldName = ["header", "Authorization"];
|
|
354
|
-
result.push({
|
|
355
|
-
fieldName,
|
|
356
|
-
original: security,
|
|
357
|
-
defaultValue: "Bearer ",
|
|
358
|
-
children: /* @__PURE__ */ jsx(FieldSet, {
|
|
359
|
-
name: `${t.authorization} (${t.header})`,
|
|
335
|
+
children: /* @__PURE__ */ jsx(ObjectInput, {
|
|
336
|
+
field: {
|
|
337
|
+
type: "object",
|
|
338
|
+
properties: {
|
|
339
|
+
username: { type: "string" },
|
|
340
|
+
password: { type: "string" }
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
fieldName
|
|
344
|
+
})
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (scheme.type === "oauth2") {
|
|
348
|
+
const fieldName = ["header", "Authorization"];
|
|
349
|
+
return {
|
|
360
350
|
fieldName,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
351
|
+
schemeId: item.id,
|
|
352
|
+
storageKey: storageKeys.AuthField(item.id),
|
|
353
|
+
defaultValue: "Bearer ",
|
|
354
|
+
children: /* @__PURE__ */ jsx(OAuth2Input, {
|
|
355
|
+
fieldName,
|
|
356
|
+
security: item
|
|
357
|
+
})
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
if (scheme.type === "http") {
|
|
361
|
+
const fieldName = ["header", "Authorization"];
|
|
362
|
+
return {
|
|
371
363
|
fieldName,
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
364
|
+
schemeId: item.id,
|
|
365
|
+
storageKey: storageKeys.AuthField(item.id),
|
|
366
|
+
defaultValue: "Bearer ",
|
|
367
|
+
children: /* @__PURE__ */ jsx(FieldSet, {
|
|
368
|
+
name: `${t.authorization} (${t.header})`,
|
|
369
|
+
fieldName,
|
|
370
|
+
field: { type: "string" }
|
|
371
|
+
})
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
if (scheme.type === "apiKey") {
|
|
375
|
+
const fieldName = [scheme.in, scheme.name];
|
|
376
|
+
return {
|
|
377
|
+
fieldName,
|
|
378
|
+
schemeId: item.id,
|
|
379
|
+
defaultValue: "",
|
|
380
|
+
storageKey: storageKeys.AuthField(item.id),
|
|
381
|
+
children: /* @__PURE__ */ jsx(FieldSet, {
|
|
382
|
+
fieldName,
|
|
383
|
+
name: `${scheme.name} (${scheme.in})`,
|
|
384
|
+
field: { type: "string" }
|
|
385
|
+
})
|
|
386
|
+
};
|
|
387
|
+
}
|
|
377
388
|
const fieldName = ["header", "Authorization"];
|
|
378
|
-
|
|
389
|
+
return {
|
|
379
390
|
fieldName,
|
|
391
|
+
schemeId: item.id,
|
|
380
392
|
defaultValue: "",
|
|
381
|
-
|
|
393
|
+
storageKey: storageKeys.AuthField(item.id),
|
|
382
394
|
children: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FieldSet, {
|
|
383
395
|
name: `${t.authorization} (${t.header})`,
|
|
384
396
|
fieldName,
|
|
@@ -387,45 +399,106 @@ function useAuthInputs(securities, transform) {
|
|
|
387
399
|
className: "text-fd-muted-foreground text-xs",
|
|
388
400
|
children: t.openIdUnsupported
|
|
389
401
|
})] })
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return transform ? transform(result) : result;
|
|
402
|
+
};
|
|
403
|
+
});
|
|
393
404
|
}, [
|
|
394
|
-
|
|
395
|
-
|
|
405
|
+
requirement,
|
|
406
|
+
storageKeys,
|
|
407
|
+
schemes,
|
|
396
408
|
t
|
|
397
409
|
]);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const initAuthValues = (stf) => {
|
|
407
|
-
const { dataEngine } = stf;
|
|
408
|
-
for (const item of inputs) {
|
|
409
|
-
const stored = localStorage.getItem(storageKeys.AuthField(item));
|
|
410
|
-
if (stored) {
|
|
411
|
-
const parsed = JSON.parse(stored);
|
|
412
|
-
if (typeof parsed === typeof item.defaultValue) {
|
|
413
|
-
dataEngine.init(item.fieldName, parsed);
|
|
414
|
-
continue;
|
|
415
|
-
}
|
|
410
|
+
if (transformAuthInputs) inputs = transformAuthInputs(inputs);
|
|
411
|
+
useListener({
|
|
412
|
+
stf: engine,
|
|
413
|
+
onUpdate(key) {
|
|
414
|
+
for (const item of inputs) {
|
|
415
|
+
if (!arrayStartsWith(item.fieldName, key)) continue;
|
|
416
|
+
const value = engine.get(item.fieldName);
|
|
417
|
+
if (value != null) localStorage.setItem(item.storageKey, JSON.stringify(value));
|
|
416
418
|
}
|
|
417
|
-
dataEngine.init(item.fieldName, item.defaultValue);
|
|
418
419
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
};
|
|
422
|
-
|
|
420
|
+
});
|
|
421
|
+
useOnChange(authCtx.updatedSchemeId, () => {
|
|
422
|
+
const { updatedSchemeId } = authCtx;
|
|
423
|
+
if (!updatedSchemeId) return;
|
|
424
|
+
const { token } = authCtx.store[updatedSchemeId];
|
|
425
|
+
const input = inputs.find((input) => input.schemeId === updatedSchemeId);
|
|
426
|
+
if (input) {
|
|
427
|
+
engine.update(input.fieldName, token);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const idx = requirements.findIndex((requirement) => requirement.some((item) => item.id === updatedSchemeId));
|
|
431
|
+
if (idx !== -1) {
|
|
432
|
+
localStorage.setItem(storageKeys.AuthField(updatedSchemeId), JSON.stringify(token));
|
|
433
|
+
setRequirementId(idx);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
423
436
|
return {
|
|
424
437
|
inputs,
|
|
425
|
-
|
|
426
|
-
|
|
438
|
+
requirementId,
|
|
439
|
+
setRequirementId,
|
|
440
|
+
mapInputs(values) {
|
|
441
|
+
const cloned = structuredClone(values);
|
|
442
|
+
for (const item of inputs) {
|
|
443
|
+
if (!item.mapOutput) continue;
|
|
444
|
+
objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));
|
|
445
|
+
}
|
|
446
|
+
return cloned;
|
|
447
|
+
},
|
|
448
|
+
initAuthInputs() {
|
|
449
|
+
for (const item of inputs) {
|
|
450
|
+
const stored = localStorage.getItem(item.storageKey);
|
|
451
|
+
if (stored) {
|
|
452
|
+
const parsed = JSON.parse(stored);
|
|
453
|
+
if (typeof parsed === typeof item.defaultValue) {
|
|
454
|
+
engine.init(item.fieldName, parsed);
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
engine.init(item.fieldName, item.defaultValue);
|
|
459
|
+
}
|
|
460
|
+
return () => {
|
|
461
|
+
for (const item of inputs) engine.delete(item.fieldName);
|
|
462
|
+
};
|
|
463
|
+
}
|
|
427
464
|
};
|
|
428
465
|
}
|
|
466
|
+
function OAuth2Input({ fieldName, security }) {
|
|
467
|
+
const [open, setOpen] = useState(false);
|
|
468
|
+
const engine = useDataEngine();
|
|
469
|
+
const t = useTranslations();
|
|
470
|
+
return /* @__PURE__ */ jsxs("fieldset", {
|
|
471
|
+
className: "flex flex-col gap-2",
|
|
472
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
473
|
+
htmlFor: stringifyFieldKey(fieldName),
|
|
474
|
+
className: cn(labelVariants()),
|
|
475
|
+
children: t.accessToken
|
|
476
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
477
|
+
className: "flex gap-2",
|
|
478
|
+
children: [/* @__PURE__ */ jsx(FieldInput, {
|
|
479
|
+
fieldName,
|
|
480
|
+
field: { type: "string" },
|
|
481
|
+
className: "flex-1"
|
|
482
|
+
}), /* @__PURE__ */ jsxs(OAuthDialog, {
|
|
483
|
+
open,
|
|
484
|
+
onOpenChange: setOpen,
|
|
485
|
+
children: [/* @__PURE__ */ jsx(OAuthDialogTrigger, {
|
|
486
|
+
type: "button",
|
|
487
|
+
className: cn(buttonVariants({
|
|
488
|
+
size: "sm",
|
|
489
|
+
color: "secondary"
|
|
490
|
+
})),
|
|
491
|
+
children: t.authorize
|
|
492
|
+
}), /* @__PURE__ */ jsx(OAuthDialogContent, {
|
|
493
|
+
setOpen,
|
|
494
|
+
schemeId: security.id,
|
|
495
|
+
scopes: security.scopes,
|
|
496
|
+
setToken: (token) => engine.update(["header", "Authorization"], token)
|
|
497
|
+
})]
|
|
498
|
+
})]
|
|
499
|
+
})]
|
|
500
|
+
});
|
|
501
|
+
}
|
|
429
502
|
function Route({ route, ...props }) {
|
|
430
503
|
return /* @__PURE__ */ jsx("div", {
|
|
431
504
|
...props,
|
|
@@ -442,39 +515,6 @@ function Route({ route, ...props }) {
|
|
|
442
515
|
})] }, index))
|
|
443
516
|
});
|
|
444
517
|
}
|
|
445
|
-
function DefaultResultDisplay({ data, reset, ...rest }) {
|
|
446
|
-
const t = useTranslations();
|
|
447
|
-
const statusInfo = useMemo(() => getStatusInfo(data.status, t), [data.status, t]);
|
|
448
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
449
|
-
...rest,
|
|
450
|
-
className: cn("flex flex-col gap-3 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground", rest.className),
|
|
451
|
-
children: [
|
|
452
|
-
/* @__PURE__ */ jsxs("div", {
|
|
453
|
-
className: "flex justify-between items-center",
|
|
454
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
455
|
-
className: "inline-flex items-center gap-1.5 text-sm font-medium",
|
|
456
|
-
children: [/* @__PURE__ */ jsx(statusInfo.icon, { className: cn("size-4", statusInfo.color) }), statusInfo.description]
|
|
457
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
458
|
-
type: "button",
|
|
459
|
-
className: cn(buttonVariants({
|
|
460
|
-
size: "sm",
|
|
461
|
-
variant: "outline"
|
|
462
|
-
})),
|
|
463
|
-
onClick: () => reset(),
|
|
464
|
-
children: t.close
|
|
465
|
-
})]
|
|
466
|
-
}),
|
|
467
|
-
/* @__PURE__ */ jsx("p", {
|
|
468
|
-
className: "text-sm text-fd-muted-foreground",
|
|
469
|
-
children: data.status
|
|
470
|
-
}),
|
|
471
|
-
data.data !== void 0 && /* @__PURE__ */ jsx(ClientCodeBlock, {
|
|
472
|
-
lang: typeof data.data === "string" && data.data.length > 5e4 ? "text" : data.type,
|
|
473
|
-
code: typeof data.data === "string" ? data.data : JSON.stringify(data.data, null, 2)
|
|
474
|
-
})
|
|
475
|
-
]
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
518
|
function DefaultCollapsiblePanel({ title, children, ...props }) {
|
|
479
519
|
return /* @__PURE__ */ jsxs(Collapsible, {
|
|
480
520
|
...props,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useTranslations } from "../../ui/client/i18n.js";
|
|
2
3
|
import { cn } from "../../utils/cn.js";
|
|
3
4
|
import { FormatFlags } from "../../utils/schema/to-string.js";
|
|
4
5
|
import { anyFields, useFieldInfo, useResolvedSchema, useSchemaScope, useSchemaUtils } from "../schema.js";
|
|
5
6
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
6
7
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
7
|
-
import { useTranslations } from "../../ui/client/i18n.js";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { ChevronRight, Plus, Trash2, X } from "lucide-react";
|
|
11
|
-
import { cva } from "class-variance-authority";
|
|
12
11
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
12
|
+
import { cva } from "class-variance-authority";
|
|
13
13
|
import { useArray, useDataEngine, useFieldValue, useObject } from "@fumari/stf";
|
|
14
14
|
import { stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
15
15
|
//#region src/playground/components/inputs.tsx
|