fumadocs-openapi 10.6.6 → 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.
@@ -45,6 +45,7 @@
45
45
  @source inline("allFlows");
46
46
  @source inline("allOf");
47
47
  @source inline("already");
48
+ @source inline("alt");
48
49
  @source inline("and");
49
50
  @source inline("animate-spin");
50
51
  @source inline("another");
@@ -54,8 +55,11 @@
54
55
  @source inline("apiExample");
55
56
  @source inline("apiKey");
56
57
  @source inline("apiPlayground");
58
+ @source inline("application/javascript");
57
59
  @source inline("application/json");
60
+ @source inline("application/x-javascript");
58
61
  @source inline("application/x-www-form-urlencoded");
62
+ @source inline("application/xml");
59
63
  @source inline("apply");
60
64
  @source inline("aria-label");
61
65
  @source inline("array");
@@ -96,6 +100,7 @@
96
100
  @source inline("bg-fd-primary/10");
97
101
  @source inline("bg-fd-secondary");
98
102
  @source inline("binary");
103
+ @source inline("blob");
99
104
  @source inline("blue");
100
105
  @source inline("body");
101
106
  @source inline("bodyMediaType");
@@ -105,6 +110,7 @@
105
110
  @source inline("border");
106
111
  @source inline("border-b");
107
112
  @source inline("border-current");
113
+ @source inline("border-fd-border");
108
114
  @source inline("border-fd-primary/20");
109
115
  @source inline("border-s");
110
116
  @source inline("border-t");
@@ -112,11 +118,13 @@
112
118
  @source inline("border-y");
113
119
  @source inline("both");
114
120
  @source inline("boundary");
121
+ @source inline("buffer");
115
122
  @source inline("bundled");
116
123
  @source inline("but");
117
124
  @source inline("button");
118
125
  @source inline("buttonVariants");
119
126
  @source inline("by");
127
+ @source inline("byteLength");
120
128
  @source inline("cache");
121
129
  @source inline("cached");
122
130
  @source inline("call");
@@ -129,6 +137,7 @@
129
137
  @source inline("causes");
130
138
  @source inline("change");
131
139
  @source inline("changes");
140
+ @source inline("charset");
132
141
  @source inline("check");
133
142
  @source inline("child");
134
143
  @source inline("children");
@@ -142,6 +151,7 @@
142
151
  @source inline("clientId");
143
152
  @source inline("clientSecret");
144
153
  @source inline("client_credentials");
154
+ @source inline("client_error");
145
155
  @source inline("client_id");
146
156
  @source inline("client_secret");
147
157
  @source inline("cloned");
@@ -178,6 +188,7 @@
178
188
  @source inline("createRehypeCode");
179
189
  @source inline("credentials");
180
190
  @source inline("css");
191
+ @source inline("csv");
181
192
  @source inline("ctx");
182
193
  @source inline("current");
183
194
  @source inline("currentRef");
@@ -278,8 +289,10 @@
278
289
  @source inline("export");
279
290
  @source inline("extends");
280
291
  @source inline("factory");
292
+ @source inline("fall");
281
293
  @source inline("fallback");
282
294
  @source inline("false");
295
+ @source inline("fast-content-type-parse");
283
296
  @source inline("fetch");
284
297
  @source inline("fetchOptions");
285
298
  @source inline("fetcher");
@@ -364,7 +377,6 @@
364
377
  @source inline("getExampleRequests");
365
378
  @source inline("getSchema");
366
379
  @source inline("getSchemaId");
367
- @source inline("getStatusInfo");
368
380
  @source inline("ghost");
369
381
  @source inline("github-dark");
370
382
  @source inline("github-light");
@@ -454,6 +466,7 @@
454
466
  @source inline("items-end");
455
467
  @source inline("items-start");
456
468
  @source inline("j");
469
+ @source inline("js");
457
470
  @source inline("json");
458
471
  @source inline("json-schema-typed");
459
472
  @source inline("justify-between");
@@ -510,6 +523,7 @@
510
523
  @source inline("metaData");
511
524
  @source inline("method");
512
525
  @source inline("migrated");
526
+ @source inline("mime");
513
527
  @source inline("min");
514
528
  @source inline("min-h-(--initial-height,0)");
515
529
  @source inline("min-w-0");
@@ -606,6 +620,7 @@
606
620
  @source inline("page-level");
607
621
  @source inline("pageData");
608
622
  @source inline("pages");
623
+ @source inline("panelVariants");
609
624
  @source inline("param");
610
625
  @source inline("paramTypeKeys");
611
626
  @source inline("parameter");
@@ -776,6 +791,7 @@
776
791
  @source inline("rounded-xl");
777
792
  @source inline("route");
778
793
  @source inline("s");
794
+ @source inline("safeParse");
779
795
  @source inline("same");
780
796
  @source inline("sample");
781
797
  @source inline("sampleKey");
@@ -837,6 +853,7 @@
837
853
  @source inline("setIsMounted");
838
854
  @source inline("setMounted");
839
855
  @source inline("setNextName");
856
+ @source inline("setObjectUrl");
840
857
  @source inline("setOpen");
841
858
  @source inline("setPath");
842
859
  @source inline("setRequirementId");
@@ -886,6 +903,7 @@
886
903
  @source inline("source");
887
904
  @source inline("spec");
888
905
  @source inline("specify");
906
+ @source inline("src");
889
907
  @source inline("state");
890
908
  @source inline("status");
891
909
  @source inline("statusBadRequest");
@@ -949,13 +967,17 @@
949
967
  @source inline("text-start");
950
968
  @source inline("text-xs");
951
969
  @source inline("text-yellow-600");
970
+ @source inline("text/css");
971
+ @source inline("text/csv");
952
972
  @source inline("text/html");
973
+ @source inline("text/plain");
953
974
  @source inline("that");
954
975
  @source inline("the");
955
976
  @source inline("their");
956
977
  @source inline("theme");
957
978
  @source inline("themes");
958
979
  @source inline("this");
980
+ @source inline("through");
959
981
  @source inline("throw");
960
982
  @source inline("timeout");
961
983
  @source inline("timerRef");
@@ -1032,6 +1054,7 @@
1032
1054
  @source inline("useResolvedSchema");
1033
1055
  @source inline("useServerContext");
1034
1056
  @source inline("useState");
1057
+ @source inline("useStatusInfo");
1035
1058
  @source inline("useStf");
1036
1059
  @source inline("useStorageKey");
1037
1060
  @source inline("useTheme");
@@ -1040,6 +1063,7 @@
1040
1063
  @source inline("used");
1041
1064
  @source inline("username");
1042
1065
  @source inline("using");
1066
+ @source inline("utf-8");
1043
1067
  @source inline("valid");
1044
1068
  @source inline("validateFormats");
1045
1069
  @source inline("validateSchema");
@@ -1069,6 +1093,7 @@
1069
1093
  @source inline("window");
1070
1094
  @source inline("with");
1071
1095
  @source inline("withBase");
1096
+ @source inline("withReplacements");
1072
1097
  @source inline("without");
1073
1098
  @source inline("wrap");
1074
1099
  @source inline("wrap-break-word");
@@ -1082,6 +1107,7 @@
1082
1107
  @source inline("x-exclusiveCodeSample");
1083
1108
  @source inline("x-playground-lazy");
1084
1109
  @source inline("x-selectedCodeSample");
1110
+ @source inline("xml");
1085
1111
  @source inline("yellow");
1086
1112
  @source inline("you");
1087
1113
  @source inline("your");
package/dist/i18n.d.ts CHANGED
@@ -57,7 +57,8 @@ declare const defaultTranslations: {
57
57
  statusInternalServerError: string;
58
58
  statusSuccessful: string;
59
59
  statusError: string;
60
- statusNoDescription: string;
60
+ statusClientError: string;
61
+ statusBinaryBody: string;
61
62
  obtainAccessToken: string;
62
63
  resourceOwnerPassword: string;
63
64
  resourceOwnerPasswordDesc: string;
package/dist/i18n.js CHANGED
@@ -56,7 +56,8 @@ const defaultTranslations = {
56
56
  statusInternalServerError: "Internal Server Error",
57
57
  statusSuccessful: "Successful",
58
58
  statusError: "Error",
59
- statusNoDescription: "No Description",
59
+ statusClientError: "Client Error",
60
+ statusBinaryBody: "Binary response body, {length} bytes",
60
61
  obtainAccessToken: "Obtain the access token for API.",
61
62
  resourceOwnerPassword: "Resource Owner Password Flow",
62
63
  resourceOwnerPasswordDesc: "Authenticate using username and password.",
@@ -1,4 +1,5 @@
1
- import { BrowserFetcherOptions, FetchResult } from "./fetcher.js";
1
+ import { BrowserFetcherOptions } from "./fetcher.js";
2
+ import { DefaultResultDisplay, ResultDisplayProps } from "./components/result-display.js";
2
3
  import { SchemaScope } from "./schema.js";
3
4
  import { Document, HttpMethods, ParameterObject } from "../types.js";
4
5
  import { ParsedSchema, SecurityEntry } from "../utils/schema/index.js";
@@ -23,10 +24,6 @@ interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {
23
24
  doc: Document;
24
25
  proxyUrl?: string;
25
26
  }
26
- interface ResultDisplayProps extends ComponentProps<'div'> {
27
- data: FetchResult;
28
- reset: () => void;
29
- }
30
27
  interface CollapsiblePanelProps extends Omit<ComponentProps<typeof Collapsible>, 'title'> {
31
28
  'data-type': 'authorization' | 'body' | ParamType;
32
29
  title: ReactNode;
@@ -86,11 +83,6 @@ interface AuthField {
86
83
  children: ReactNode;
87
84
  mapOutput?: (values: unknown) => unknown;
88
85
  }
89
- declare function DefaultResultDisplay({
90
- data,
91
- reset,
92
- ...rest
93
- }: ResultDisplayProps): _$react_jsx_runtime0.JSX.Element;
94
86
  declare function DefaultCollapsiblePanel({
95
87
  title,
96
88
  children,
@@ -105,4 +97,4 @@ declare const Custom: {
105
97
  };
106
98
  };
107
99
  //#endregion
108
- export { AuthField, CollapsiblePanelProps, Custom, DefaultCollapsiblePanel, DefaultResultDisplay, FormValues, PlaygroundClientOptions, PlaygroundClientProps, ResultDisplayProps, PlaygroundClient as default };
100
+ export { AuthField, CollapsiblePanelProps, Custom, DefaultCollapsiblePanel, DefaultResultDisplay, FormValues, PlaygroundClientOptions, PlaygroundClientProps, type ResultDisplayProps, PlaygroundClient as default };
@@ -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 { getStatusInfo } from "./status-info.js";
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,10 +13,8 @@ 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
19
  import { useAuth } from "./auth.js";
21
20
  import { OAuthDialog, OAuthDialogContent, OAuthDialogTrigger } from "./components/oauth-dialog.js";
@@ -23,8 +22,8 @@ import { Spinner } from "./components/spinner.js";
23
22
  import { Fragment, useEffect, useMemo, useRef, useState } from "react";
24
23
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
25
24
  import { ChevronDown, LoaderCircle } from "lucide-react";
26
- import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
27
25
  import { buttonVariants } from "fumadocs-ui/components/ui/button";
26
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
28
27
  import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
29
28
  import { arrayStartsWith, objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
30
29
  import { useOnChange } from "fumadocs-core/utils/use-on-change";
@@ -516,39 +515,6 @@ function Route({ route, ...props }) {
516
515
  })] }, index))
517
516
  });
518
517
  }
519
- function DefaultResultDisplay({ data, reset, ...rest }) {
520
- const t = useTranslations();
521
- const statusInfo = useMemo(() => getStatusInfo(data.status, t), [data.status, t]);
522
- return /* @__PURE__ */ jsxs("div", {
523
- ...rest,
524
- className: cn("flex flex-col gap-3 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground", rest.className),
525
- children: [
526
- /* @__PURE__ */ jsxs("div", {
527
- className: "flex justify-between items-center",
528
- children: [/* @__PURE__ */ jsxs("div", {
529
- className: "inline-flex items-center gap-1.5 text-sm font-medium",
530
- children: [/* @__PURE__ */ jsx(statusInfo.icon, { className: cn("size-4", statusInfo.color) }), statusInfo.description]
531
- }), /* @__PURE__ */ jsx("button", {
532
- type: "button",
533
- className: cn(buttonVariants({
534
- size: "sm",
535
- variant: "outline"
536
- })),
537
- onClick: () => reset(),
538
- children: t.close
539
- })]
540
- }),
541
- /* @__PURE__ */ jsx("p", {
542
- className: "text-sm text-fd-muted-foreground",
543
- children: data.status
544
- }),
545
- data.data !== void 0 && /* @__PURE__ */ jsx(ClientCodeBlock, {
546
- lang: typeof data.data === "string" && data.data.length > 5e4 ? "text" : data.type,
547
- code: typeof data.data === "string" ? data.data : JSON.stringify(data.data, null, 2)
548
- })
549
- ]
550
- });
551
- }
552
518
  function DefaultCollapsiblePanel({ title, children, ...props }) {
553
519
  return /* @__PURE__ */ jsxs(Collapsible, {
554
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
@@ -1,9 +1,9 @@
1
1
  import { useApiContext } from "../../ui/contexts/api.js";
2
+ import { useTranslations } from "../../ui/client/i18n.js";
2
3
  import { cn } from "../../utils/cn.js";
3
4
  import { useQuery } from "../../utils/use-query.js";
4
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
5
6
  import { Input, labelVariants } from "../../ui/components/input.js";
6
- import { useTranslations } from "../../ui/client/i18n.js";
7
7
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
8
8
  import { useAuth } from "../auth.js";
9
9
  import { useMemo, useState } from "react";
@@ -0,0 +1,16 @@
1
+ import { FetchResult } from "../fetcher.js";
2
+ import { ComponentProps } from "react";
3
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/playground/components/result-display.d.ts
6
+ interface ResultDisplayProps extends ComponentProps<'div'> {
7
+ data: FetchResult;
8
+ reset: () => void;
9
+ }
10
+ declare function DefaultResultDisplay({
11
+ data,
12
+ reset,
13
+ ...rest
14
+ }: ResultDisplayProps): _$react_jsx_runtime0.JSX.Element;
15
+ //#endregion
16
+ export { DefaultResultDisplay, ResultDisplayProps };
@@ -0,0 +1,141 @@
1
+ "use client";
2
+ import { useTranslations, withReplacements } from "../../ui/client/i18n.js";
3
+ import { useStatusInfo } from "../status-info.js";
4
+ import { cn } from "../../utils/cn.js";
5
+ import { ClientCodeBlock } from "../../ui/components/codeblock.js";
6
+ import { useEffect, useMemo, useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { CircleX } from "lucide-react";
9
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
10
+ import { safeParse } from "fast-content-type-parse";
11
+ import { cva } from "class-variance-authority";
12
+ //#region src/playground/components/result-display.tsx
13
+ const panelVariants = cva("flex flex-col gap-2 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground");
14
+ function DefaultResultDisplay({ data, reset, ...rest }) {
15
+ const t = useTranslations();
16
+ if (data.type === "client_error") return /* @__PURE__ */ jsxs("div", {
17
+ ...rest,
18
+ className: cn(panelVariants(), rest.className),
19
+ children: [/* @__PURE__ */ jsxs("div", {
20
+ className: "flex gap-1.5 items-center",
21
+ children: [
22
+ /* @__PURE__ */ jsx(CircleX, { className: "size-4 text-red-500" }),
23
+ /* @__PURE__ */ jsx("p", {
24
+ className: "text-sm font-medium me-auto",
25
+ children: t.statusClientError
26
+ }),
27
+ /* @__PURE__ */ jsx("button", {
28
+ type: "button",
29
+ className: cn(buttonVariants({
30
+ size: "sm",
31
+ variant: "outline"
32
+ })),
33
+ onClick: () => reset(),
34
+ children: t.close
35
+ })
36
+ ]
37
+ }), /* @__PURE__ */ jsx("p", { children: data.message })]
38
+ });
39
+ return /* @__PURE__ */ jsx(ResponseResult, {
40
+ data,
41
+ reset,
42
+ ...rest
43
+ });
44
+ }
45
+ function getTextFormat(mime) {
46
+ switch (mime) {
47
+ case "application/json": return "json";
48
+ case "text/html": return "html";
49
+ case "text/css": return "css";
50
+ case "text/csv": return "csv";
51
+ case "application/javascript":
52
+ case "application/x-javascript": return "js";
53
+ case "application/xml": return "xml";
54
+ }
55
+ if (mime.endsWith("+json")) return "json";
56
+ if (mime.endsWith("+xml")) return "xml";
57
+ if (mime.startsWith("text/")) return "text";
58
+ return null;
59
+ }
60
+ function ResponseResult({ data, reset, ...rest }) {
61
+ const t = useTranslations();
62
+ const statusInfo = useStatusInfo(data.status);
63
+ const { parameters, type } = useMemo(() => safeParse(data.headers.get("Content-Type") ?? "text/plain"), [data.headers]);
64
+ let content;
65
+ if (type.startsWith("image/")) content = /* @__PURE__ */ jsx(ImageResult, {
66
+ mime: type,
67
+ buffer: data.body
68
+ });
69
+ else if (data.body.byteLength > 0) {
70
+ const lang = getTextFormat(type);
71
+ if (lang) content = /* @__PURE__ */ jsx(TextResult, {
72
+ lang,
73
+ charset: parameters.charset,
74
+ data
75
+ });
76
+ else content = /* @__PURE__ */ jsx("p", {
77
+ className: "p-2 border rounded-lg bg-fd-card text-fd-card-foreground",
78
+ children: withReplacements(t.statusBinaryBody, { length: String(data.body.byteLength) })
79
+ });
80
+ }
81
+ return /* @__PURE__ */ jsxs("div", {
82
+ ...rest,
83
+ className: cn(panelVariants(), rest.className),
84
+ children: [/* @__PURE__ */ jsxs("div", {
85
+ className: "flex items-center gap-1.5",
86
+ children: [
87
+ /* @__PURE__ */ jsx(statusInfo.icon, { className: cn("size-4 shrink-0", statusInfo.color) }),
88
+ /* @__PURE__ */ jsxs("p", {
89
+ className: "text-sm font-medium text-nowrap",
90
+ children: [
91
+ data.status,
92
+ " ",
93
+ statusInfo.description
94
+ ]
95
+ }),
96
+ /* @__PURE__ */ jsx("code", {
97
+ className: "ms-auto text-xs text-fd-muted-foreground truncate",
98
+ children: type
99
+ }),
100
+ /* @__PURE__ */ jsx("button", {
101
+ type: "button",
102
+ className: cn(buttonVariants({
103
+ size: "sm",
104
+ variant: "outline"
105
+ })),
106
+ onClick: () => reset(),
107
+ children: t.close
108
+ })
109
+ ]
110
+ }), content]
111
+ });
112
+ }
113
+ function TextResult({ lang, charset, data }) {
114
+ const code = useMemo(() => {
115
+ if (charset) try {
116
+ return new TextDecoder(charset).decode(data.body);
117
+ } catch {}
118
+ return new TextDecoder("utf-8").decode(data.body);
119
+ }, [charset, data.body]);
120
+ return /* @__PURE__ */ jsx(ClientCodeBlock, {
121
+ lang: code.length > 5e3 ? "text" : lang,
122
+ code
123
+ });
124
+ }
125
+ function ImageResult({ mime, buffer }) {
126
+ const [objectUrl, setObjectUrl] = useState(null);
127
+ useEffect(() => {
128
+ const blob = new Blob([buffer], { type: mime });
129
+ const url = URL.createObjectURL(blob);
130
+ setObjectUrl(url);
131
+ return () => URL.revokeObjectURL(url);
132
+ }, [mime, buffer]);
133
+ if (!objectUrl) return;
134
+ return /* @__PURE__ */ jsx("img", {
135
+ src: objectUrl,
136
+ alt: "",
137
+ className: "w-full rounded-md border border-fd-border"
138
+ });
139
+ }
140
+ //#endregion
141
+ export { DefaultResultDisplay };
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { resolveServerUrl, withBase } from "../../utils/url.js";
3
3
  import { useServerContext } from "../../ui/contexts/api.js";
4
+ import { useTranslations } from "../../ui/client/i18n.js";
4
5
  import { cn } from "../../utils/cn.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 { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
9
9
  import { useEffect, useRef, useState } from "react";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,10 +1,16 @@
1
1
  import { Awaitable } from "../types.js";
2
2
 
3
3
  //#region src/playground/fetcher.d.ts
4
- interface FetchResult {
4
+ type FetchResult = FetchResponseResult | FetchErrorResult;
5
+ interface FetchErrorResult {
6
+ type: 'client_error';
7
+ message: string;
8
+ }
9
+ interface FetchResponseResult {
10
+ type: 'response';
5
11
  status: number;
6
- type: 'json' | 'html' | 'text';
7
- data: unknown;
12
+ headers: Headers;
13
+ body: ArrayBuffer;
8
14
  }
9
15
  interface BrowserFetcherOptions {
10
16
  /**
@@ -21,9 +21,8 @@ function createBrowserFetcher(adapters, { proxyUrl, proxyForwardCookie = true, r
21
21
  if (data.bodyMediaType && data.body) {
22
22
  const adapter = resolveMediaAdapter(data.bodyMediaType, adapters);
23
23
  if (!adapter) return {
24
- status: 400,
25
- type: "text",
26
- data: `[Fumadocs] No adapter for ${data.bodyMediaType}, you need to specify one from 'createOpenAPI()'.`
24
+ type: "client_error",
25
+ message: `[Fumadocs] No adapter for ${data.bodyMediaType}, you need to specify one from 'createOpenAPI()'.`
27
26
  };
28
27
  if (data.bodyMediaType !== "multipart/form-data") headers.append("Content-Type", data.bodyMediaType);
29
28
  requestInit.body = adapter.encode(data);
@@ -41,26 +40,16 @@ function createBrowserFetcher(adapters, { proxyUrl, proxyForwardCookie = true, r
41
40
  }
42
41
  if (onRequestInit) requestInit = await onRequestInit(requestInit);
43
42
  return fetch(requestUrl, requestInit).then(async (res) => {
44
- const contentType = res.headers.get("Content-Type") ?? "";
45
- let type;
46
- let data;
47
- if (contentType.startsWith("application/json")) {
48
- type = "json";
49
- data = await res.json();
50
- } else {
51
- type = contentType.startsWith("text/html") ? "html" : "text";
52
- data = await res.text();
53
- }
54
43
  return {
44
+ type: "response",
55
45
  status: res.status,
56
- type,
57
- data
46
+ headers: res.headers,
47
+ body: await res.arrayBuffer()
58
48
  };
59
49
  }).catch((e) => {
60
50
  return {
61
- status: 400,
62
- type: "text",
63
- data: `Client side error: ${e instanceof Error ? `[${e.name}] ${e.message}` : e.toString()}`
51
+ type: "client_error",
52
+ message: `Client side error: ${e instanceof Error ? `[${e.name}] ${e.message}` : e.toString()}`
64
53
  };
65
54
  });
66
55
  } };
@@ -1,3 +1,5 @@
1
+ import { useTranslations } from "../ui/client/i18n.js";
2
+ import { useMemo } from "react";
1
3
  import { CircleCheck, CircleX } from "lucide-react";
2
4
  //#region src/playground/status-info.tsx
3
5
  const statusKeys = {
@@ -27,30 +29,32 @@ const statusKeys = {
27
29
  icon: CircleX
28
30
  }
29
31
  };
30
- function getStatusInfo(status, t) {
31
- if (status in statusKeys) {
32
- const { key, color, icon } = statusKeys[status];
32
+ function useStatusInfo(status) {
33
+ const t = useTranslations();
34
+ return useMemo(() => {
35
+ if (status in statusKeys) {
36
+ const { key, color, icon } = statusKeys[status];
37
+ return {
38
+ description: t[key],
39
+ color,
40
+ icon
41
+ };
42
+ }
43
+ if (status >= 200 && status < 300) return {
44
+ description: t.statusSuccessful,
45
+ color: "text-green-500",
46
+ icon: CircleCheck
47
+ };
48
+ if (status >= 400) return {
49
+ description: t.statusError,
50
+ color: "text-red-500",
51
+ icon: CircleX
52
+ };
33
53
  return {
34
- description: t[key],
35
- color,
36
- icon
54
+ color: "text-fd-muted-foreground",
55
+ icon: CircleX
37
56
  };
38
- }
39
- if (status >= 200 && status < 300) return {
40
- description: t.statusSuccessful,
41
- color: "text-green-500",
42
- icon: CircleCheck
43
- };
44
- if (status >= 400) return {
45
- description: t.statusError,
46
- color: "text-red-500",
47
- icon: CircleX
48
- };
49
- return {
50
- description: t.statusNoDescription,
51
- color: "text-fd-muted-foreground",
52
- icon: CircleX
53
- };
57
+ }, [t, status]);
54
58
  }
55
59
  //#endregion
56
- export { getStatusInfo };
60
+ export { useStatusInfo };
package/dist/ui/base.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { parseSecurities } from "../utils/schema/index.js";
2
2
  import { defaultAdapters } from "../requests/media/adapter.js";
3
- import { encodeInternalRef } from "../utils/schema/ref.js";
4
3
  import { ClientCodeBlockProvider } from "./components/codeblock.js";
4
+ import { encodeInternalRef } from "../utils/schema/ref.js";
5
5
  import { APIPage } from "./api-page.js";
6
6
  import { pickSchema } from "../utils/schema/pick.js";
7
7
  import { PlaygroundAuthProvider } from "./client/boundary.lazy.js";
@@ -9,9 +9,11 @@ function useTranslations() {
9
9
  * Renders a translated string. Use in server components so the label is resolved on the client from the current locale.
10
10
  */
11
11
  function I18nLabel({ label, replacements = {} }) {
12
- let value = useTranslations()[label];
13
- for (const [k, v] of Object.entries(replacements)) value = value.replaceAll(`{${k}}`, v);
14
- return value;
12
+ return withReplacements(useTranslations()[label], replacements);
13
+ }
14
+ function withReplacements(t, replacements) {
15
+ for (const [k, v] of Object.entries(replacements)) t = t.replaceAll(`{${k}}`, v);
16
+ return t;
15
17
  }
16
18
  //#endregion
17
- export { I18nLabel, useTranslations };
19
+ export { I18nLabel, useTranslations, withReplacements };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { cn } from "../../utils/cn.js";
3
2
  import { useTranslations } from "../client/i18n.js";
3
+ import { cn } from "../../utils/cn.js";
4
4
  import * as React from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { X } from "lucide-react";
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { cn } from "../../utils/cn.js";
3
2
  import { useTranslations } from "../client/i18n.js";
3
+ import { cn } from "../../utils/cn.js";
4
4
  import { createContext, use, useMemo, useRef, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Check, Copy } from "lucide-react";
@@ -2,9 +2,9 @@ import { idToTitle } from "../../utils/id-to-title.js";
2
2
  import { createMethod, methodKeys } from "../../utils/schema/index.js";
3
3
  import { isMediaTypeSupported } from "../../requests/media/resolve-adapter.js";
4
4
  import "../../requests/media/adapter.js";
5
+ import { I18nLabel } from "../client/i18n.js";
5
6
  import { cn } from "../../utils/cn.js";
6
7
  import { Badge, MethodLabel } from "../components/method-label.js";
7
- import { I18nLabel } from "../client/i18n.js";
8
8
  import { CopyTypeScriptPanel, OperationProvider } from "./client.js";
9
9
  import { Schema } from "../schema/index.js";
10
10
  import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
@@ -1,6 +1,6 @@
1
1
  import { resolveRequestData } from "../../utils/url.js";
2
- import { MethodLabel } from "../components/method-label.js";
3
2
  import { I18nLabel } from "../client/i18n.js";
3
+ import { MethodLabel } from "../components/method-label.js";
4
4
  import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "fumadocs-ui/components/tabs";
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../../../utils/url.js";
3
3
  import { useApiContext, useServerContext } from "../../contexts/api.js";
4
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../components/select.js";
5
4
  import { ClientCodeBlock } from "../../components/codeblock.js";
5
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../components/select.js";
6
6
  import { useOperationContext } from "../client.js";
7
7
  import { useEffect, useMemo, useState } from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,13 +1,13 @@
1
1
  "use client";
2
+ import { useTranslations } from "../client/i18n.js";
2
3
  import { cn } from "../../utils/cn.js";
3
4
  import { Badge } from "../components/method-label.js";
4
- import { useTranslations } from "../client/i18n.js";
5
5
  import { Fragment, Suspense, createContext, use, useCallback, useDeferredValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
6
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { ChevronDown, FilterIcon } from "lucide-react";
8
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
8
9
  import { cva } from "class-variance-authority";
9
10
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
10
- import { buttonVariants } from "fumadocs-ui/components/ui/button";
11
11
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "fumadocs-ui/components/tabs";
12
12
  import { Popover, PopoverContent, PopoverTrigger } from "fumadocs-ui/components/ui/popover";
13
13
  //#region src/ui/schema/client.tsx
@@ -1,6 +1,6 @@
1
+ import { I18nLabel } from "../client/i18n.js";
1
2
  import { mergeAllOf } from "../../utils/schema/merge.js";
2
3
  import { FormatFlags, schemaToString } from "../../utils/schema/to-string.js";
3
- import { I18nLabel } from "../client/i18n.js";
4
4
  import { useMemo } from "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/ui/schema/index.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-openapi",
3
- "version": "10.6.6",
3
+ "version": "10.6.7",
4
4
  "description": "Generate MDX docs for your OpenAPI spec",
5
5
  "keywords": [
6
6
  "Docs",
@@ -49,18 +49,19 @@
49
49
  "@radix-ui/react-dialog": "^1.1.15",
50
50
  "@radix-ui/react-select": "^2.2.6",
51
51
  "@radix-ui/react-slot": "^1.2.4",
52
- "@scalar/json-magic": "^0.12.4",
53
- "@scalar/openapi-upgrader": "^0.2.2",
52
+ "@scalar/json-magic": "^0.12.5",
53
+ "@scalar/openapi-upgrader": "^0.2.4",
54
54
  "ajv": "^8.18.0",
55
55
  "chokidar": "^5.0.0",
56
56
  "class-variance-authority": "^0.7.1",
57
+ "fast-content-type-parse": "^3.0.0",
57
58
  "github-slugger": "^2.0.0",
58
59
  "hast-util-to-jsx-runtime": "^2.3.6",
59
60
  "js-yaml": "^4.1.1",
60
61
  "lucide-react": "^1.7.0",
61
62
  "next-themes": "^0.4.6",
62
63
  "openapi-sampler": "^1.7.2",
63
- "react-hook-form": "^7.72.0",
64
+ "react-hook-form": "^7.72.1",
64
65
  "remark": "^15.0.1",
65
66
  "remark-rehype": "^11.1.2",
66
67
  "tailwind-merge": "^3.5.0",
@@ -68,18 +69,18 @@
68
69
  "@fumari/stf": "1.0.4"
69
70
  },
70
71
  "devDependencies": {
71
- "@scalar/api-client-react": "^1.4.15",
72
+ "@scalar/api-client-react": "^1.4.20",
72
73
  "@types/js-yaml": "^4.0.9",
73
- "@types/node": "25.5.0",
74
+ "@types/node": "25.5.2",
74
75
  "@types/openapi-sampler": "^1.0.3",
75
76
  "@types/react": "^19.2.14",
76
77
  "json-schema-typed": "^8.0.2",
77
78
  "shiki": "^4.0.2",
78
79
  "tailwindcss": "^4.2.2",
79
- "tsdown": "0.21.6",
80
+ "tsdown": "0.21.7",
80
81
  "@fumadocs/tailwind": "0.0.3",
81
- "fumadocs-core": "16.7.10",
82
- "fumadocs-ui": "16.7.10",
82
+ "fumadocs-core": "16.7.11",
83
+ "fumadocs-ui": "16.7.11",
83
84
  "tsconfig": "0.0.0"
84
85
  },
85
86
  "peerDependencies": {