fumadocs-openapi 11.4.2 → 12.0.0

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 (125) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/css/preset.css +0 -1
  3. package/dist/_virtual/_rolldown/runtime.js +10 -1
  4. package/dist/generate-file.d.ts +2 -2
  5. package/dist/generate-file.js +1 -1
  6. package/dist/i18n.d.ts +6 -8
  7. package/dist/i18n.js +2 -17
  8. package/dist/index.browser.d.ts +13 -0
  9. package/dist/index.browser.js +11 -0
  10. package/dist/index.d.ts +5 -2
  11. package/dist/index.js +3 -1
  12. package/dist/operation.d.ts +133 -0
  13. package/dist/operation.js +296 -0
  14. package/dist/packages/shared-api/dist/.translations/index.d.ts +29 -0
  15. package/dist/packages/shared-api/dist/.translations/keys.js +28 -0
  16. package/dist/packages/shared-api/dist/auto-anchor/client.js +20 -0
  17. package/dist/packages/shared-api/dist/auto-anchor/index.js +17 -0
  18. package/dist/packages/shared-api/dist/codegen.d.ts +42 -0
  19. package/dist/packages/shared-api/dist/codegen.js +35 -0
  20. package/dist/packages/shared-api/dist/components/accordion.js +71 -0
  21. package/dist/packages/shared-api/dist/components/badge.js +21 -0
  22. package/dist/packages/shared-api/dist/components/collapsible.d.ts +7 -0
  23. package/dist/packages/shared-api/dist/components/collapsible.js +16 -0
  24. package/dist/packages/shared-api/dist/components/defaults.d.ts +20 -0
  25. package/dist/packages/shared-api/dist/components/defaults.js +70 -0
  26. package/dist/packages/shared-api/dist/components/dialog.js +55 -0
  27. package/dist/packages/shared-api/dist/components/input.js +14 -0
  28. package/dist/packages/shared-api/dist/components/label.js +11 -0
  29. package/dist/packages/shared-api/dist/components/playground/inputs.js +439 -0
  30. package/dist/packages/shared-api/dist/components/playground/schema.js +112 -0
  31. package/dist/packages/shared-api/dist/components/popover.js +23 -0
  32. package/dist/packages/shared-api/dist/components/schema/client.d.ts +12 -0
  33. package/dist/packages/shared-api/dist/components/schema/client.js +508 -0
  34. package/dist/packages/shared-api/dist/components/schema/index.d.ts +9 -0
  35. package/dist/packages/shared-api/dist/components/schema/index.js +28 -0
  36. package/dist/packages/shared-api/dist/components/select-tab.js +54 -0
  37. package/dist/packages/shared-api/dist/components/select.js +70 -0
  38. package/dist/packages/shared-api/dist/components/spinner.js +14 -0
  39. package/dist/packages/shared-api/dist/i18n.d.ts +3 -0
  40. package/dist/packages/shared-api/dist/i18n.js +7 -0
  41. package/dist/packages/shared-api/dist/utils/cn.js +2 -0
  42. package/dist/packages/shared-api/dist/utils/id-to-title.js +12 -0
  43. package/dist/packages/shared-api/dist/utils/is-plain-object.js +8 -0
  44. package/dist/packages/shared-api/dist/utils/merge-refs.js +11 -0
  45. package/dist/packages/shared-api/dist/utils/url.js +13 -0
  46. package/dist/{utils → packages/shared-api/dist/utils}/use-query.js +2 -1
  47. package/dist/packages/shared-api/dist/utils/use-server-store.js +56 -0
  48. package/dist/playground/auth.d.ts +37 -0
  49. package/dist/playground/auth.js +216 -21
  50. package/dist/playground/fetcher.d.ts +11 -1
  51. package/dist/playground/index.d.ts +3 -0
  52. package/dist/playground/index.js +3 -0
  53. package/dist/requests/generators/csharp.js +0 -1
  54. package/dist/requests/generators/go.js +0 -1
  55. package/dist/requests/generators/index.d.ts +4 -4
  56. package/dist/requests/generators/index.js +2 -2
  57. package/dist/requests/generators/java.js +0 -1
  58. package/dist/requests/generators/javascript.js +0 -1
  59. package/dist/requests/generators/python.js +0 -1
  60. package/dist/requests/generators/rust.js +0 -1
  61. package/dist/requests/index.d.ts +4 -0
  62. package/dist/requests/index.js +3 -0
  63. package/dist/requests/media/adapter.d.ts +1 -0
  64. package/dist/requests/media/encode.d.ts +7 -2
  65. package/dist/requests/media/resolve-adapter.d.ts +20 -0
  66. package/dist/server/index.d.ts +4 -7
  67. package/dist/server/index.js +1 -7
  68. package/dist/types.d.ts +0 -14
  69. package/dist/ui/base.d.ts +3 -2
  70. package/dist/ui/base.js +15 -166
  71. package/dist/ui/components/codeblock.js +3 -10
  72. package/dist/ui/components/heading.js +10 -19
  73. package/dist/ui/components/markdown.js +4 -6
  74. package/dist/ui/components/method-label.js +2 -17
  75. package/dist/ui/components/schema.js +28 -0
  76. package/dist/ui/index.d.ts +7 -198
  77. package/dist/ui/index.js +1 -3
  78. package/dist/ui/operation/index.js +143 -231
  79. package/dist/ui/operation/request-tabs.js +15 -23
  80. package/dist/ui/operation/response-tabs.js +9 -53
  81. package/dist/ui/operation/usage-tabs.js +35 -93
  82. package/dist/{playground → ui/playground}/client.d.ts +10 -21
  83. package/dist/ui/playground/client.js +432 -0
  84. package/dist/{playground → ui/playground}/components/oauth-dialog.js +27 -92
  85. package/dist/{playground → ui/playground}/components/result-display.d.ts +2 -2
  86. package/dist/{playground → ui/playground}/components/result-display.js +7 -7
  87. package/dist/{playground → ui/playground}/components/server-select.js +12 -13
  88. package/dist/{playground → ui/playground}/status-info.js +2 -2
  89. package/dist/{scalar → ui/scalar}/client.js +8 -6
  90. package/dist/{scalar → ui/scalar}/index.d.ts +2 -2
  91. package/dist/{scalar → ui/scalar}/index.js +3 -7
  92. package/dist/utils/create-page.d.ts +216 -0
  93. package/dist/utils/create-page.js +221 -0
  94. package/dist/utils/document/dereference.d.ts +2 -2
  95. package/dist/utils/document/dereference.js +8 -3
  96. package/dist/utils/document/load.js +2 -2
  97. package/dist/utils/get-example-requests.js +11 -13
  98. package/dist/utils/pages/builder.d.ts +15 -2
  99. package/dist/utils/pages/builder.js +6 -6
  100. package/dist/utils/pages/preset-auto.d.ts +1 -1
  101. package/dist/utils/pages/preset-auto.js +3 -3
  102. package/dist/utils/pages/to-static-data.js +4 -4
  103. package/dist/utils/pages/to-text.d.ts +1 -1
  104. package/dist/utils/pages/to-text.js +3 -5
  105. package/dist/utils/schema.js +5 -5
  106. package/dist/utils/use-server.d.ts +24 -0
  107. package/dist/utils/use-server.js +57 -0
  108. package/package.json +31 -20
  109. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js +0 -508
  110. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js +0 -152
  111. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js +0 -61
  112. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +0 -25
  113. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +0 -15
  114. package/dist/playground/client.js +0 -574
  115. package/dist/ui/contexts/api.d.ts +0 -17
  116. package/dist/ui/contexts/api.js +0 -84
  117. package/dist/ui/create-client.d.ts +0 -9
  118. package/dist/ui/create-client.js +0 -7
  119. package/dist/ui/operation/context.d.ts +0 -15
  120. package/dist/ui/operation/context.js +0 -48
  121. package/dist/ui/operation/request-tabs.d.ts +0 -12
  122. package/dist/ui/operation/response-tabs.d.ts +0 -30
  123. package/dist/utils/get-example-requests.d.ts +0 -11
  124. package/dist/utils/schema.d.ts +0 -3
  125. package/dist/utils/storage-key.js +0 -15
@@ -0,0 +1,432 @@
1
+ "use client";
2
+ import { pathnameFromRequest } from "../../requests/generators/index.js";
3
+ import { useQuery } from "../../packages/shared-api/dist/utils/use-query.js";
4
+ import { useAuthFields, usePlaygroundAuth } from "../../playground/auth.js";
5
+ import { useServer } from "../../utils/use-server.js";
6
+ import { useOpenAPI } from "../../utils/create-page.js";
7
+ import { encodeRequestData } from "../../requests/media/encode.js";
8
+ import { useExampleRequests, useOperation } from "../../operation.js";
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../packages/shared-api/dist/components/select.js";
10
+ import { MethodLabel } from "../components/method-label.js";
11
+ import { cn } from "../../utils/cn.js";
12
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../packages/shared-api/dist/components/collapsible.js";
13
+ import { DefaultResultDisplay } from "./components/result-display.js";
14
+ import { SchemaProvider, anyFields, useResolvedSchema } from "../../packages/shared-api/dist/components/playground/schema.js";
15
+ import { Label } from "../../packages/shared-api/dist/components/label.js";
16
+ import ServerSelect from "./components/server-select.js";
17
+ import { FieldInput, FieldSet, JsonInput, ObjectInput } from "../../packages/shared-api/dist/components/playground/inputs.js";
18
+ import { OAuthDialog, OAuthDialogContent, OAuthDialogTrigger } from "./components/oauth-dialog.js";
19
+ import { Spinner } from "../../packages/shared-api/dist/components/spinner.js";
20
+ import { Fragment, createContext, use, useEffect, useMemo, useRef, useState } from "react";
21
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
22
+ import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
23
+ import { stringifyFieldKey } from "@fumari/stf/lib/utils";
24
+ import { useOnChange } from "fumadocs-core/utils/use-on-change";
25
+ import { useTranslations } from "@fuma-translate/react";
26
+ import { ChevronDown, LoaderCircle, PlusIcon } from "lucide-react";
27
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
28
+ //#region src/ui/playground/client.tsx
29
+ const OptionsContext = createContext({});
30
+ function usePlaygroundOptions() {
31
+ return use(OptionsContext);
32
+ }
33
+ function PlaygroundClient({ writeOnly, readOnly, transformAuthInputs, fetchOptions, components, renderParameterField, renderBodyField, ...rest }) {
34
+ const t = useTranslations({ note: "playground" });
35
+ const { doc, mediaAdapters, proxyUrl } = useOpenAPI();
36
+ const { dereferenced } = doc;
37
+ const { path: route, method, operation, parameters: groups, requestBody } = useOperation();
38
+ const options = useMemo(() => ({
39
+ transformAuthInputs,
40
+ fetchOptions,
41
+ components,
42
+ renderParameterField,
43
+ renderBodyField
44
+ }), [
45
+ transformAuthInputs,
46
+ fetchOptions,
47
+ components,
48
+ renderParameterField,
49
+ renderBodyField
50
+ ]);
51
+ const parameters = useMemo(() => groups.flatMap((group) => group.items), [groups]);
52
+ const body = useMemo(() => {
53
+ if (!requestBody) return;
54
+ const mediaType = "application/json" in requestBody.content ? "application/json" : Object.keys(requestBody.content)[0];
55
+ return {
56
+ mediaType,
57
+ schema: requestBody.content[mediaType].schema ?? true
58
+ };
59
+ }, [requestBody]);
60
+ const { items: examples, selected: exampleId, update } = useExampleRequests();
61
+ const { resolveUrl } = useServer();
62
+ const { ResultDisplay = DefaultResultDisplay, CollapsiblePanel = DefaultCollapsiblePanel } = components ?? {};
63
+ const defaultValues = useMemo(() => {
64
+ const requestData = examples.find((example) => example.id === exampleId)?.data;
65
+ return {
66
+ path: requestData?.path ?? {},
67
+ query: requestData?.query ?? {},
68
+ header: requestData?.header ?? {},
69
+ body: requestData?.body ?? {},
70
+ cookie: requestData?.cookie ?? {}
71
+ };
72
+ }, [examples, exampleId]);
73
+ const stf = useStf({ defaultValues });
74
+ const auth = useAuthFields(stf.dataEngine, {
75
+ operation,
76
+ transform: transformAuthInputs
77
+ });
78
+ const testQuery = useQuery(async (input) => {
79
+ const fetcher = await import("../../playground/fetcher.js").then((mod) => mod.createBrowserFetcher(mediaAdapters, {
80
+ proxyUrl,
81
+ ...fetchOptions
82
+ }));
83
+ const encoded = encodeRequestData({
84
+ ...auth.mapValues(input),
85
+ method,
86
+ bodyMediaType: body?.mediaType
87
+ }, mediaAdapters, parameters);
88
+ return fetcher.fetch(resolveUrl(pathnameFromRequest(route, encoded)), encoded);
89
+ });
90
+ const timerRef = useRef(null);
91
+ const stfSync = useRef(false);
92
+ function triggerExampleUpdate() {
93
+ const data = {
94
+ ...auth.mapValues(stf.dataEngine.getData()),
95
+ method,
96
+ bodyMediaType: body?.mediaType
97
+ };
98
+ update(data);
99
+ }
100
+ useListener({
101
+ stf,
102
+ onUpdate() {
103
+ if (!stfSync.current) return;
104
+ if (timerRef.current) window.clearTimeout(timerRef.current);
105
+ timerRef.current = window.setTimeout(triggerExampleUpdate, 400);
106
+ }
107
+ });
108
+ useEffect(() => {
109
+ if (stf.dataEngine.getData() === defaultValues) return;
110
+ stf.dataEngine.reset(defaultValues);
111
+ }, [defaultValues]);
112
+ useEffect(() => {
113
+ const reset = auth.init();
114
+ triggerExampleUpdate();
115
+ stfSync.current = true;
116
+ return () => {
117
+ stfSync.current = false;
118
+ reset();
119
+ };
120
+ }, [defaultValues, auth.init]);
121
+ return /* @__PURE__ */ jsx(OptionsContext, {
122
+ value: options,
123
+ children: /* @__PURE__ */ jsx(StfProvider, {
124
+ value: stf,
125
+ children: /* @__PURE__ */ jsx(SchemaProvider, {
126
+ docRoot: dereferenced,
127
+ writeOnly,
128
+ readOnly,
129
+ children: /* @__PURE__ */ jsxs("form", {
130
+ ...rest,
131
+ className: cn("not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground", rest.className),
132
+ onSubmit: (e) => {
133
+ testQuery.start(stf.dataEngine.getData());
134
+ e.preventDefault();
135
+ },
136
+ children: [
137
+ /* @__PURE__ */ jsx(ServerSelect, { className: "border-b" }),
138
+ /* @__PURE__ */ jsxs("div", {
139
+ className: "flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0",
140
+ children: [
141
+ /* @__PURE__ */ jsx(MethodLabel, { children: method }),
142
+ /* @__PURE__ */ jsx(Route, {
143
+ route,
144
+ className: cn("flex-1", operation.deprecated && "line-through")
145
+ }),
146
+ /* @__PURE__ */ jsx("button", {
147
+ type: "submit",
148
+ className: cn(buttonVariants({
149
+ variant: "default",
150
+ size: "sm"
151
+ }), "w-14 py-1.5"),
152
+ disabled: testQuery.isLoading,
153
+ children: testQuery.isLoading ? /* @__PURE__ */ jsx(LoaderCircle, { className: "size-4 animate-spin" }) : t("Send")
154
+ })
155
+ ]
156
+ }),
157
+ testQuery.data ? /* @__PURE__ */ jsx(ResultDisplay, {
158
+ data: testQuery.data,
159
+ reset: testQuery.reset
160
+ }) : null,
161
+ auth.requirements.length > 0 && /* @__PURE__ */ jsx(SecurityRequirements, {
162
+ requirements: auth.requirements,
163
+ selected: auth.selected,
164
+ select: auth.select,
165
+ children: auth.fields.map((field) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(AuthInput, { field }) }, stringifyFieldKey(field.fieldName)))
166
+ }),
167
+ /* @__PURE__ */ jsx(ParametersForm, { parameters }),
168
+ body && /* @__PURE__ */ jsx(CollapsiblePanel, {
169
+ "data-type": "body",
170
+ title: t("Body"),
171
+ children: renderBodyField ? renderBodyField("body", body) : /* @__PURE__ */ jsx(BodyInput, { field: body.schema })
172
+ })
173
+ ]
174
+ })
175
+ })
176
+ })
177
+ });
178
+ }
179
+ function SecurityRequirements({ requirements, select, selected, children }) {
180
+ const t = useTranslations({ note: "playground" });
181
+ const { isLoading, error } = usePlaygroundAuth();
182
+ const defaultOpen = isLoading || error != null;
183
+ const [open, setOpen] = useState(defaultOpen);
184
+ const { CollapsiblePanel = DefaultCollapsiblePanel } = usePlaygroundOptions().components ?? {};
185
+ useOnChange(defaultOpen, () => {
186
+ if (defaultOpen) setOpen(true);
187
+ });
188
+ const items = requirements.map((requirement, i) => {
189
+ if (requirement.length === 1) {
190
+ const { id, scheme } = requirement[0];
191
+ return {
192
+ value: i,
193
+ label: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
194
+ className: cn("font-mono font-medium", scheme.deprecated && "text-fd-muted-foreground line-through"),
195
+ children: id
196
+ }), /* @__PURE__ */ jsx("p", {
197
+ className: "text-fd-muted-foreground whitespace-pre-wrap",
198
+ children: scheme.description
199
+ })] })
200
+ };
201
+ }
202
+ return {
203
+ value: i,
204
+ label: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
205
+ className: "inline-flex items-center gap-1 font-mono font-medium",
206
+ children: requirement.map((item, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx(PlusIcon, { className: "text-fd-muted-foreground size-3.5" }), /* @__PURE__ */ jsx("span", {
207
+ className: cn(item.scheme.deprecated && "text-fd-muted-foreground line-through"),
208
+ children: item.id
209
+ })] }, i))
210
+ }), /* @__PURE__ */ jsx("ul", {
211
+ className: "text-fd-muted-foreground whitespace-pre-wrap list-disc list-inside",
212
+ children: requirement.map((item, i) => /* @__PURE__ */ jsx("li", {
213
+ className: "empty:hidden",
214
+ children: item.scheme.description
215
+ }, i))
216
+ })] })
217
+ };
218
+ });
219
+ return /* @__PURE__ */ jsxs(CollapsiblePanel, {
220
+ title: /* @__PURE__ */ jsxs(Fragment$1, { children: [t("Authorization"), isLoading && /* @__PURE__ */ jsxs("span", {
221
+ className: "border-s ps-2 inline-flex items-center gap-1.5 text-fd-muted-foreground text-xs font-mono",
222
+ children: [
223
+ /* @__PURE__ */ jsx(Spinner, {}),
224
+ " ",
225
+ t("Fetching token...")
226
+ ]
227
+ })] }),
228
+ "data-type": "authorization",
229
+ open,
230
+ onOpenChange: setOpen,
231
+ children: [
232
+ error != null && /* @__PURE__ */ jsxs("div", {
233
+ className: "p-2 border rounded-lg bg-fd-secondary",
234
+ children: [/* @__PURE__ */ jsx("p", {
235
+ className: "text-fd-muted-foreground font-medium mb-1",
236
+ children: t("Failed to fetch token")
237
+ }), /* @__PURE__ */ jsx("p", { children: String(error) })]
238
+ }),
239
+ /* @__PURE__ */ jsxs(Select, {
240
+ items,
241
+ value: selected,
242
+ onValueChange: (v) => v !== null && select(v),
243
+ children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: items.map(({ value, label }) => /* @__PURE__ */ jsx(SelectItem, {
244
+ value,
245
+ children: label
246
+ }, value)) })]
247
+ }),
248
+ children
249
+ ]
250
+ });
251
+ }
252
+ const ParamTypes = [
253
+ "path",
254
+ "header",
255
+ "cookie",
256
+ "query"
257
+ ];
258
+ function ParameterItem({ type, parameters }) {
259
+ const { renderParameterField } = usePlaygroundOptions();
260
+ return parameters.map((field) => {
261
+ const fieldName = [type, field.name];
262
+ if (renderParameterField) return renderParameterField(fieldName, field);
263
+ const contentTypes = field.content && Object.keys(field.content);
264
+ const schema = field.content && contentTypes && contentTypes.length > 0 ? field.content[contentTypes[0]].schema : field.schema;
265
+ return /* @__PURE__ */ jsx(FieldSet, {
266
+ name: field.name,
267
+ fieldName,
268
+ field: schema ?? anyFields,
269
+ isRequired: field.required
270
+ }, stringifyFieldKey(fieldName));
271
+ });
272
+ }
273
+ function ParametersForm({ parameters }) {
274
+ const { CollapsiblePanel = DefaultCollapsiblePanel } = usePlaygroundOptions().components ?? {};
275
+ const t = useTranslations({ note: "playground" });
276
+ const displayNames = {
277
+ header: t("Header"),
278
+ cookie: t("Cookies"),
279
+ query: t("Query"),
280
+ path: t("Path")
281
+ };
282
+ return ParamTypes.map((type) => {
283
+ const items = parameters.filter((v) => v.in === type);
284
+ if (items.length === 0) return;
285
+ return /* @__PURE__ */ jsx(CollapsiblePanel, {
286
+ "data-type": type,
287
+ title: displayNames[type],
288
+ children: /* @__PURE__ */ jsx(ParameterItem, {
289
+ parameters: items,
290
+ type
291
+ })
292
+ }, type);
293
+ });
294
+ }
295
+ function BodyInput({ field: _field }) {
296
+ const field = useResolvedSchema(_field);
297
+ const [isJson, setIsJson] = useState(false);
298
+ const t = useTranslations({ note: "playground" });
299
+ if (field.format === "binary") return /* @__PURE__ */ jsx(FieldSet, {
300
+ field,
301
+ fieldName: ["body"],
302
+ isRequired: true
303
+ });
304
+ if (isJson) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
305
+ className: cn(buttonVariants({
306
+ variant: "secondary",
307
+ size: "sm",
308
+ className: "w-fit font-mono p-2"
309
+ })),
310
+ onClick: () => setIsJson(false),
311
+ type: "button",
312
+ children: t("Close JSON Editor")
313
+ }), /* @__PURE__ */ jsx(JsonInput, { fieldName: ["body"] })] });
314
+ return /* @__PURE__ */ jsx(FieldSet, {
315
+ field,
316
+ fieldName: ["body"],
317
+ collapsible: false,
318
+ isRequired: true,
319
+ name: /* @__PURE__ */ jsx("button", {
320
+ type: "button",
321
+ className: cn(buttonVariants({
322
+ variant: "secondary",
323
+ size: "sm",
324
+ className: "p-2"
325
+ })),
326
+ onClick: () => setIsJson(true),
327
+ children: t("Open JSON Editor")
328
+ })
329
+ });
330
+ }
331
+ function AuthInput({ field }) {
332
+ const t = useTranslations({ note: "playground" });
333
+ const { fieldName, scheme } = field;
334
+ if (scheme.type === "oauth2") return /* @__PURE__ */ jsx(OAuth2Input, { field });
335
+ if (scheme.type === "http" && scheme.scheme === "basic") return /* @__PURE__ */ jsx(ObjectInput, {
336
+ field: {
337
+ type: "object",
338
+ properties: {
339
+ username: { type: "string" },
340
+ password: { type: "string" }
341
+ }
342
+ },
343
+ fieldName
344
+ });
345
+ if (scheme.type === "apiKey") return /* @__PURE__ */ jsx(FieldSet, {
346
+ fieldName,
347
+ name: `${scheme.name} (${scheme.in})`,
348
+ field: { type: "string" }
349
+ });
350
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FieldSet, {
351
+ name: `${t("Authorization")} (${t("Header")})`,
352
+ fieldName,
353
+ field: { type: "string" }
354
+ }), scheme.type !== "http" && /* @__PURE__ */ jsx("p", {
355
+ className: "text-fd-muted-foreground text-xs",
356
+ children: t("OpenID Connect is not supported at the moment, you can still set an access token here.")
357
+ })] });
358
+ }
359
+ function OAuth2Input({ field }) {
360
+ const { fieldName } = field;
361
+ const [open, setOpen] = useState(false);
362
+ const engine = useDataEngine();
363
+ const t = useTranslations({ note: "playground" });
364
+ return /* @__PURE__ */ jsxs("fieldset", {
365
+ className: "flex flex-col gap-2",
366
+ children: [/* @__PURE__ */ jsx(Label, {
367
+ htmlFor: stringifyFieldKey(fieldName),
368
+ children: t("Access Token")
369
+ }), /* @__PURE__ */ jsxs("div", {
370
+ className: "flex gap-2",
371
+ children: [/* @__PURE__ */ jsx(FieldInput, {
372
+ fieldName,
373
+ field: { type: "string" },
374
+ className: "flex-1"
375
+ }), /* @__PURE__ */ jsxs(OAuthDialog, {
376
+ open,
377
+ onOpenChange: setOpen,
378
+ children: [/* @__PURE__ */ jsx(OAuthDialogTrigger, {
379
+ type: "button",
380
+ className: cn(buttonVariants({
381
+ size: "sm",
382
+ variant: "secondary"
383
+ })),
384
+ children: t("Authorize")
385
+ }), /* @__PURE__ */ jsx(OAuthDialogContent, {
386
+ setOpen,
387
+ schemeId: field.schemeId,
388
+ scopes: field.scopes,
389
+ setToken: (token) => engine.update(["header", "Authorization"], token)
390
+ })]
391
+ })]
392
+ })]
393
+ });
394
+ }
395
+ function Route({ route, ...props }) {
396
+ return /* @__PURE__ */ jsx("div", {
397
+ ...props,
398
+ className: cn("flex flex-row items-center gap-0.5 overflow-auto text-nowrap", props.className),
399
+ children: route.split("/").map((part, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && /* @__PURE__ */ jsx("span", {
400
+ className: "text-fd-muted-foreground",
401
+ children: "/"
402
+ }), part.startsWith("{") && part.endsWith("}") ? /* @__PURE__ */ jsx("code", {
403
+ className: "bg-fd-primary/10 text-fd-primary",
404
+ children: part
405
+ }) : /* @__PURE__ */ jsx("code", {
406
+ className: "text-fd-foreground",
407
+ children: part
408
+ })] }, index))
409
+ });
410
+ }
411
+ function DefaultCollapsiblePanel({ title, children, ...props }) {
412
+ return /* @__PURE__ */ jsxs(Collapsible, {
413
+ ...props,
414
+ className: cn("border-b last:border-b-0", props.className),
415
+ children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
416
+ className: "group w-full flex items-center gap-2 p-3 text-sm font-medium",
417
+ children: [title, /* @__PURE__ */ jsx(ChevronDown, { className: "ms-auto size-3.5 text-fd-muted-foreground group-data-[panel-open]:rotate-180" })]
418
+ }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
419
+ className: "flex flex-col gap-3 p-3 pt-1",
420
+ children
421
+ }) })]
422
+ });
423
+ }
424
+ const Custom = { useController(fieldName, options) {
425
+ const [value, setValue] = useFieldValue(fieldName, options);
426
+ return {
427
+ value,
428
+ setValue
429
+ };
430
+ } };
431
+ //#endregion
432
+ export { Custom, DefaultCollapsiblePanel, DefaultResultDisplay, PlaygroundClient as default };
@@ -1,24 +1,25 @@
1
- import { useRenderContext } from "../../ui/contexts/api.js";
2
- import { cn } from "../../utils/cn.js";
3
- import { useQuery } from "../../utils/use-query.js";
4
- import { useAuth } from "../auth.js";
1
+ import { useQuery } from "../../../packages/shared-api/dist/utils/use-query.js";
2
+ import { requestOAuthToken, usePlaygroundAuth } from "../../../playground/auth.js";
3
+ import { useOpenAPI } from "../../../utils/create-page.js";
4
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../packages/shared-api/dist/components/select.js";
5
+ import { cn } from "../../../utils/cn.js";
6
+ import { Label } from "../../../packages/shared-api/dist/components/label.js";
7
+ import { Input } from "../../../packages/shared-api/dist/components/input.js";
8
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../../packages/shared-api/dist/components/dialog.js";
5
9
  import { useMemo, useState } from "react";
6
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
11
  import { useTranslations } from "@fuma-translate/react";
8
12
  import { buttonVariants } from "fumadocs-ui/components/ui/button";
9
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@fumadocs/api-docs/components/select";
10
- import { Input, labelVariants } from "@fumadocs/api-docs/components/input";
11
- import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@fumadocs/api-docs/components/dialog";
12
- //#region src/playground/components/oauth-dialog.tsx
13
+ //#region src/ui/playground/components/oauth-dialog.tsx
13
14
  const OAuthDialog = Dialog;
14
15
  function OAuthDialogContent(props) {
15
16
  const t = useTranslations({ note: "OAuth dialog" });
16
17
  return /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t("Authorization") }), /* @__PURE__ */ jsx(DialogDescription, { children: t("Obtain the access token for API.") })] }), /* @__PURE__ */ jsx(Content, { ...props })] });
17
18
  }
18
19
  function Content({ schemeId, scopes, setToken, setOpen }) {
19
- const { dereferenced, resolve } = useRenderContext().schema;
20
+ const { dereferenced, resolve } = useOpenAPI().doc;
20
21
  const schemes = dereferenced.components?.securitySchemes;
21
- const tokenInfo = useAuth().store[schemeId];
22
+ const tokenInfo = usePlaygroundAuth().store[schemeId];
22
23
  const scheme = resolve(schemes?.[schemeId]);
23
24
  if (!scheme || scheme.type !== "oauth2") throw new Error("unexpected schemaId: must be type oauth2");
24
25
  const [type, setType] = useState(() => {
@@ -72,77 +73,16 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
72
73
  };
73
74
  }, [tokenInfo]);
74
75
  const authorize = useQuery(async (values) => {
75
- if (type === "implicit") {
76
- const value = scheme.flows[type];
77
- const params = new URLSearchParams();
78
- params.set("response_type", "token");
79
- params.set("client_id", values.clientId);
80
- params.set("redirect_uri", window.location.href);
81
- params.set("scope", scopes.join("+"));
82
- params.set("state", JSON.stringify({
83
- scheme: schemeId,
84
- client_id: values.clientId,
85
- redirect_uri: window.location.href
86
- }));
87
- window.location.replace(`${value.authorizationUrl}?${params.toString()}`);
88
- return;
89
- }
90
- if (type === "authorizationCode") {
91
- const value = scheme.flows[type];
92
- const params = new URLSearchParams();
93
- params.set("response_type", "code");
94
- params.set("client_id", values.clientId);
95
- params.set("redirect_uri", window.location.href);
96
- params.set("scope", scopes.join("+"));
97
- params.set("state", JSON.stringify({
98
- client_id: values.clientId,
99
- client_secret: values.clientSecret,
100
- redirect_uri: window.location.href,
101
- scheme: schemeId
102
- }));
103
- window.location.replace(`${value.authorizationUrl}?${params.toString()}`);
104
- return;
105
- }
106
- let res;
107
- if (type === "password") {
108
- const value = scheme.flows[type];
109
- const body = new URLSearchParams({
110
- grant_type: "password",
111
- username: values.username,
112
- password: values.password,
113
- scope: scopes.join("+")
114
- });
115
- const headers = { "Content-Type": "application/x-www-form-urlencoded" };
116
- if (clientAuth === "header") headers.Authorization = `Basic ${btoa(`${values.clientId}:${values.clientSecret}`)}`;
117
- else {
118
- if (values.clientId) body.set("client_id", values.clientId);
119
- if (values.clientSecret) body.set("client_secret", values.clientSecret);
120
- }
121
- res = await fetch(value.tokenUrl, {
122
- method: "POST",
123
- headers,
124
- body
125
- });
126
- }
127
- if (type === "clientCredentials") {
128
- const value = scheme.flows[type];
129
- res = await fetch(value.tokenUrl, {
130
- method: "POST",
131
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
132
- body: new URLSearchParams({
133
- grant_type: "client_credentials",
134
- client_id: values.clientId,
135
- client_secret: values.clientSecret,
136
- scope: scopes.join("+")
137
- })
138
- });
139
- }
140
- if (res) {
141
- if (!res.ok) throw new Error(await res.text());
142
- const { access_token, token_type = "Bearer" } = await res.json();
143
- setToken(`${token_type} ${access_token}`);
144
- setOpen(false);
145
- }
76
+ if (!type) return;
77
+ const token = await requestOAuthToken(scheme, type, {
78
+ ...values,
79
+ schemeId,
80
+ scopes,
81
+ clientAuth
82
+ });
83
+ if (!token) return;
84
+ setToken(token);
85
+ setOpen(false);
146
86
  });
147
87
  const isLoading = authorize.isLoading;
148
88
  return /* @__PURE__ */ jsxs("form", {
@@ -187,9 +127,8 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
187
127
  (type === "authorizationCode" || type === "clientCredentials" || type === "implicit" || type === "password") && /* @__PURE__ */ jsxs("fieldset", {
188
128
  className: "flex flex-col gap-1.5",
189
129
  children: [
190
- /* @__PURE__ */ jsx("label", {
130
+ /* @__PURE__ */ jsx(Label, {
191
131
  htmlFor: "client_id",
192
- className: cn(labelVariants()),
193
132
  children: t("Client ID")
194
133
  }),
195
134
  /* @__PURE__ */ jsx("p", {
@@ -211,9 +150,8 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
211
150
  (type === "authorizationCode" || type === "clientCredentials" || type === "password") && /* @__PURE__ */ jsxs("fieldset", {
212
151
  className: "flex flex-col gap-1.5",
213
152
  children: [
214
- /* @__PURE__ */ jsx("label", {
153
+ /* @__PURE__ */ jsx(Label, {
215
154
  htmlFor: "client_secret",
216
- className: cn(labelVariants()),
217
155
  children: t("Client Secret")
218
156
  }),
219
157
  /* @__PURE__ */ jsx("p", {
@@ -235,9 +173,8 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
235
173
  type === "password" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
236
174
  /* @__PURE__ */ jsxs("fieldset", {
237
175
  className: "flex flex-col gap-1.5",
238
- children: [/* @__PURE__ */ jsx("label", {
176
+ children: [/* @__PURE__ */ jsx(Label, {
239
177
  htmlFor: "client_auth",
240
- className: cn(labelVariants()),
241
178
  children: t("Client Authentication")
242
179
  }), /* @__PURE__ */ jsxs(Select, {
243
180
  items: Object.entries(clientAuthMethods).map(([key, method]) => ({
@@ -270,9 +207,8 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
270
207
  }),
271
208
  /* @__PURE__ */ jsxs("fieldset", {
272
209
  className: "flex flex-col gap-1.5",
273
- children: [/* @__PURE__ */ jsx("label", {
210
+ children: [/* @__PURE__ */ jsx(Label, {
274
211
  htmlFor: "username",
275
- className: cn(labelVariants()),
276
212
  children: t("Username")
277
213
  }), /* @__PURE__ */ jsx(Input, {
278
214
  id: "username",
@@ -287,9 +223,8 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
287
223
  }),
288
224
  /* @__PURE__ */ jsxs("fieldset", {
289
225
  className: "flex flex-col gap-1.5",
290
- children: [/* @__PURE__ */ jsx("label", {
226
+ children: [/* @__PURE__ */ jsx(Label, {
291
227
  htmlFor: "password",
292
- className: cn(labelVariants()),
293
228
  children: t("Password")
294
229
  }), /* @__PURE__ */ jsx(Input, {
295
230
  id: "password",
@@ -308,7 +243,7 @@ function Content({ schemeId, scopes, setToken, setOpen }) {
308
243
  children: String(authorize.error)
309
244
  }) : null, /* @__PURE__ */ jsx("button", {
310
245
  type: "submit",
311
- className: cn(buttonVariants({ color: "primary" })),
246
+ className: cn(buttonVariants({ variant: "default" })),
312
247
  children: t("Submit")
313
248
  })] }) : /* @__PURE__ */ jsx("p", {
314
249
  className: "text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border",
@@ -1,6 +1,6 @@
1
- import { FetchResult } from "../fetcher.js";
1
+ import { FetchResult } from "../../../playground/fetcher.js";
2
2
  import { ComponentProps } from "react";
3
- //#region src/playground/components/result-display.d.ts
3
+ //#region src/ui/playground/components/result-display.d.ts
4
4
  export interface ResultDisplayProps extends ComponentProps<'div'> {
5
5
  data: FetchResult;
6
6
  reset: () => void;
@@ -1,16 +1,16 @@
1
1
  "use client";
2
+ import { ClientCodeBlock } from "../../components/codeblock.js";
3
+ import { cn } from "../../../utils/cn.js";
2
4
  import { useStatusInfo } from "../status-info.js";
3
- import { cn } from "../../utils/cn.js";
4
- import { ClientCodeBlock } from "../../ui/components/codeblock.js";
5
- import { require_fast_content_type_parse } from "../../node_modules/.pnpm/fast-content-type-parse@4.0.0/node_modules/fast-content-type-parse/index.js";
5
+ import { require_fast_content_type_parse } from "../../../node_modules/.pnpm/fast-content-type-parse@4.0.0/node_modules/fast-content-type-parse/index.js";
6
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../../packages/shared-api/dist/components/collapsible.js";
6
7
  import { Fragment, useEffect, useMemo, useState } from "react";
7
8
  import { jsx, jsxs } from "react/jsx-runtime";
8
- import { ChevronDown, CircleX, SignpostIcon } from "lucide-react";
9
9
  import { useTranslations } from "@fuma-translate/react";
10
- import { buttonVariants } from "fumadocs-ui/components/ui/button";
10
+ import { ChevronDown, CircleX, SignpostIcon } from "lucide-react";
11
11
  import { cva } from "class-variance-authority";
12
- import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@fumadocs/api-docs/components/collapsible";
13
- //#region src/playground/components/result-display.tsx
12
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
13
+ //#region src/ui/playground/components/result-display.tsx
14
14
  var import_fast_content_type_parse = require_fast_content_type_parse();
15
15
  const panelVariants = cva("flex flex-col gap-3 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground");
16
16
  function DefaultResultDisplay({ data, reset, ...rest }) {