fumadocs-openapi 10.3.18 → 10.4.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.
- package/css/generated/shared.css +64 -15
- package/dist/i18n.d.ts +100 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +113 -0
- package/dist/i18n.js.map +1 -0
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +35 -23
- package/dist/playground/client.js.map +1 -1
- package/dist/playground/components/inputs.js +16 -12
- package/dist/playground/components/inputs.js.map +1 -1
- package/dist/playground/components/oauth-dialog.js +45 -44
- package/dist/playground/components/oauth-dialog.js.map +1 -1
- package/dist/playground/components/server-select.js +7 -4
- package/dist/playground/components/server-select.js.map +1 -1
- package/dist/playground/status-info.js +18 -11
- package/dist/playground/status-info.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/base.d.ts +7 -6
- package/dist/ui/base.d.ts.map +1 -1
- package/dist/ui/base.js +13 -7
- package/dist/ui/base.js.map +1 -1
- package/dist/ui/client/i18n.js +19 -0
- package/dist/ui/client/i18n.js.map +1 -0
- package/dist/ui/components/codeblock.d.ts +15 -0
- package/dist/ui/components/codeblock.d.ts.map +1 -0
- package/dist/ui/components/codeblock.js +27 -0
- package/dist/ui/components/codeblock.js.map +1 -0
- package/dist/ui/components/dialog.js +17 -13
- package/dist/ui/components/dialog.js.map +1 -1
- package/dist/ui/full.client.js +6 -7
- package/dist/ui/full.client.js.map +1 -1
- package/dist/ui/full.d.ts.map +1 -1
- package/dist/ui/full.js +8 -4
- package/dist/ui/full.js.map +1 -1
- package/dist/ui/operation/client.js +7 -8
- package/dist/ui/operation/client.js.map +1 -1
- package/dist/ui/operation/index.js +42 -19
- package/dist/ui/operation/index.js.map +1 -1
- package/dist/ui/operation/request-tabs.d.ts.map +1 -1
- package/dist/ui/operation/request-tabs.js +9 -8
- package/dist/ui/operation/request-tabs.js.map +1 -1
- package/dist/ui/operation/response-tabs.d.ts +1 -1
- package/dist/ui/operation/response-tabs.d.ts.map +1 -1
- package/dist/ui/operation/response-tabs.js +13 -12
- package/dist/ui/operation/response-tabs.js.map +1 -1
- package/dist/ui/operation/usage-tabs/client.js +4 -5
- package/dist/ui/operation/usage-tabs/client.js.map +1 -1
- package/dist/ui/schema/client.d.ts.map +1 -1
- package/dist/ui/schema/client.js +32 -21
- package/dist/ui/schema/client.js.map +1 -1
- package/dist/ui/schema/index.d.ts +1 -1
- package/dist/ui/schema/index.d.ts.map +1 -1
- package/dist/ui/schema/index.js +11 -10
- package/dist/ui/schema/index.js.map +1 -1
- package/dist/utils/process-document.d.ts +1 -1
- package/dist/utils/process-document.js +19 -15
- package/dist/utils/process-document.js.map +1 -1
- package/package.json +19 -12
|
@@ -2,44 +2,45 @@ import { cn } from "../../utils/cn.js";
|
|
|
2
2
|
import { useQuery } from "../../utils/use-query.js";
|
|
3
3
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
4
4
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
5
|
+
import { useTranslations } from "../../ui/client/i18n.js";
|
|
5
6
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
|
|
6
|
-
import { useEffect, useState } from "react";
|
|
7
|
+
import { useEffect, useMemo, useState } from "react";
|
|
7
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
9
10
|
import { useForm } from "react-hook-form";
|
|
10
11
|
//#region src/playground/components/oauth-dialog.tsx
|
|
11
|
-
const FlowTypes = {
|
|
12
|
-
password: {
|
|
13
|
-
name: "Resource Owner Password Flow",
|
|
14
|
-
description: "Authenticate using username and password.",
|
|
15
|
-
supported: true
|
|
16
|
-
},
|
|
17
|
-
clientCredentials: {
|
|
18
|
-
name: "Client Credentials",
|
|
19
|
-
description: "Intended for the server-to-server authentication.",
|
|
20
|
-
supported: true
|
|
21
|
-
},
|
|
22
|
-
authorizationCode: {
|
|
23
|
-
name: "Authorization code",
|
|
24
|
-
description: "Authenticate with 3rd party services",
|
|
25
|
-
supported: true
|
|
26
|
-
},
|
|
27
|
-
implicit: {
|
|
28
|
-
name: "Implicit",
|
|
29
|
-
description: "Retrieve the access token directly.",
|
|
30
|
-
supported: true
|
|
31
|
-
},
|
|
32
|
-
deviceAuthorization: {
|
|
33
|
-
name: "Device Authorization",
|
|
34
|
-
description: "Authenticate with device.",
|
|
35
|
-
supported: false
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
12
|
function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
39
13
|
const [type, setType] = useState(() => {
|
|
40
14
|
return Object.keys(scheme.flows)[0];
|
|
41
15
|
});
|
|
42
|
-
const
|
|
16
|
+
const t = useTranslations();
|
|
17
|
+
const allFlows = useMemo(() => ({
|
|
18
|
+
password: {
|
|
19
|
+
name: t.resourceOwnerPassword,
|
|
20
|
+
description: t.resourceOwnerPasswordDesc,
|
|
21
|
+
supported: true
|
|
22
|
+
},
|
|
23
|
+
clientCredentials: {
|
|
24
|
+
name: t.clientCredentials,
|
|
25
|
+
description: t.clientCredentialsDesc,
|
|
26
|
+
supported: true
|
|
27
|
+
},
|
|
28
|
+
authorizationCode: {
|
|
29
|
+
name: t.authorizationCode,
|
|
30
|
+
description: t.authorizationCodeDesc,
|
|
31
|
+
supported: true
|
|
32
|
+
},
|
|
33
|
+
implicit: {
|
|
34
|
+
name: t.implicit,
|
|
35
|
+
description: t.implicitDesc,
|
|
36
|
+
supported: true
|
|
37
|
+
},
|
|
38
|
+
deviceAuthorization: {
|
|
39
|
+
name: t.deviceAuthorization,
|
|
40
|
+
description: t.deviceAuthorizationDesc,
|
|
41
|
+
supported: false
|
|
42
|
+
}
|
|
43
|
+
}), [t]);
|
|
43
44
|
const form = useForm({ defaultValues: {
|
|
44
45
|
clientId: "",
|
|
45
46
|
clientSecret: "",
|
|
@@ -164,7 +165,7 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
164
165
|
return /* @__PURE__ */ jsxs(Dialog, {
|
|
165
166
|
open,
|
|
166
167
|
onOpenChange: setOpen,
|
|
167
|
-
children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children:
|
|
168
|
+
children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t.authorization }), /* @__PURE__ */ jsx(DialogDescription, { children: t.obtainAccessToken })] }), /* @__PURE__ */ jsxs("form", {
|
|
168
169
|
className: "flex flex-col gap-6",
|
|
169
170
|
onSubmit: (e) => {
|
|
170
171
|
onSubmit(e);
|
|
@@ -175,7 +176,7 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
175
176
|
value: type,
|
|
176
177
|
onValueChange: setType,
|
|
177
178
|
children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: Object.keys(scheme.flows).map((key) => {
|
|
178
|
-
const { name, description } =
|
|
179
|
+
const { name, description } = allFlows[key];
|
|
179
180
|
return /* @__PURE__ */ jsxs(SelectItem, {
|
|
180
181
|
value: key,
|
|
181
182
|
children: [/* @__PURE__ */ jsx("p", {
|
|
@@ -194,15 +195,15 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
194
195
|
/* @__PURE__ */ jsx("label", {
|
|
195
196
|
htmlFor: "client_id",
|
|
196
197
|
className: cn(labelVariants()),
|
|
197
|
-
children:
|
|
198
|
+
children: t.clientId
|
|
198
199
|
}),
|
|
199
200
|
/* @__PURE__ */ jsx("p", {
|
|
200
201
|
className: "text-fd-muted-foreground text-sm",
|
|
201
|
-
children:
|
|
202
|
+
children: t.clientIdHint
|
|
202
203
|
}),
|
|
203
204
|
/* @__PURE__ */ jsx(Input, {
|
|
204
205
|
id: "client_id",
|
|
205
|
-
placeholder:
|
|
206
|
+
placeholder: t.inputPlaceholder,
|
|
206
207
|
type: "text",
|
|
207
208
|
autoComplete: "off",
|
|
208
209
|
disabled: isLoading,
|
|
@@ -216,15 +217,15 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
216
217
|
/* @__PURE__ */ jsx("label", {
|
|
217
218
|
htmlFor: "client_secret",
|
|
218
219
|
className: cn(labelVariants()),
|
|
219
|
-
children:
|
|
220
|
+
children: t.clientSecret
|
|
220
221
|
}),
|
|
221
222
|
/* @__PURE__ */ jsx("p", {
|
|
222
223
|
className: "text-fd-muted-foreground text-sm",
|
|
223
|
-
children:
|
|
224
|
+
children: t.clientSecretHint
|
|
224
225
|
}),
|
|
225
226
|
/* @__PURE__ */ jsx(Input, {
|
|
226
227
|
id: "client_secret",
|
|
227
|
-
placeholder:
|
|
228
|
+
placeholder: t.inputPlaceholder,
|
|
228
229
|
type: "password",
|
|
229
230
|
autoComplete: "off",
|
|
230
231
|
disabled: isLoading,
|
|
@@ -237,10 +238,10 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
237
238
|
children: [/* @__PURE__ */ jsx("label", {
|
|
238
239
|
htmlFor: "username",
|
|
239
240
|
className: cn(labelVariants()),
|
|
240
|
-
children:
|
|
241
|
+
children: t.usernameField
|
|
241
242
|
}), /* @__PURE__ */ jsx(Input, {
|
|
242
243
|
id: "username",
|
|
243
|
-
placeholder:
|
|
244
|
+
placeholder: t.inputPlaceholder,
|
|
244
245
|
type: "text",
|
|
245
246
|
disabled: isLoading,
|
|
246
247
|
autoComplete: "off",
|
|
@@ -251,27 +252,27 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
|
|
|
251
252
|
children: [/* @__PURE__ */ jsx("label", {
|
|
252
253
|
htmlFor: "password",
|
|
253
254
|
className: cn(labelVariants()),
|
|
254
|
-
children:
|
|
255
|
+
children: t.clientSecret
|
|
255
256
|
}), /* @__PURE__ */ jsx(Input, {
|
|
256
257
|
id: "password",
|
|
257
|
-
placeholder:
|
|
258
|
+
placeholder: t.inputPlaceholder,
|
|
258
259
|
type: "password",
|
|
259
260
|
autoComplete: "off",
|
|
260
261
|
disabled: isLoading,
|
|
261
262
|
...form.register("password", { required: true })
|
|
262
263
|
})]
|
|
263
264
|
})] }),
|
|
264
|
-
supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
|
|
265
|
+
allFlows[type].supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
|
|
265
266
|
className: "text-red-400 font-medium text-sm",
|
|
266
267
|
children: String(error)
|
|
267
268
|
}) : null, /* @__PURE__ */ jsx("button", {
|
|
268
269
|
type: "submit",
|
|
269
270
|
disabled: isLoading,
|
|
270
271
|
className: cn(buttonVariants({ color: "primary" })),
|
|
271
|
-
children: authCodeCallback.isLoading ?
|
|
272
|
+
children: authCodeCallback.isLoading ? t.fetchingToken : t.submit
|
|
272
273
|
})] }) : /* @__PURE__ */ jsx("p", {
|
|
273
274
|
className: "text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border",
|
|
274
|
-
children:
|
|
275
|
+
children: t.unsupported
|
|
275
276
|
})
|
|
276
277
|
]
|
|
277
278
|
})] })]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-dialog.js","names":[],"sources":["../../../src/playground/components/oauth-dialog.tsx"],"sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { useForm } from 'react-hook-form';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useQuery } from '@/utils/use-query';\nimport { type ReactNode, useEffect, useState } from 'react';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport type { OAuth2SecurityScheme } from '@/types';\n\ntype FlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;\n\nexport interface AuthDialogProps {\n scheme: OAuth2SecurityScheme;\n scopes: string[];\n\n open: boolean;\n setOpen: (v: boolean) => void;\n setToken: (token: string) => void;\n children: ReactNode;\n}\n\ninterface FormValues {\n clientId: string;\n clientSecret: string;\n username: string;\n password: string;\n}\n\ninterface AuthCodeState {\n redirect_uri: string;\n client_id: string;\n client_secret: string;\n}\n\ninterface ImplicitState {\n redirect_uri: string;\n client_id: string;\n}\n\nconst FlowTypes = {\n password: {\n name: 'Resource Owner Password Flow',\n description: 'Authenticate using username and password.',\n supported: true,\n },\n clientCredentials: {\n name: 'Client Credentials',\n description: 'Intended for the server-to-server authentication.',\n supported: true,\n },\n authorizationCode: {\n name: 'Authorization code',\n description: 'Authenticate with 3rd party services',\n supported: true,\n },\n implicit: {\n name: 'Implicit',\n description: 'Retrieve the access token directly.',\n supported: true,\n },\n deviceAuthorization: {\n name: 'Device Authorization',\n description: 'Authenticate with device.',\n supported: false,\n },\n} as const;\n\nexport function OauthDialog({\n scheme,\n scopes,\n setToken,\n children,\n open,\n setOpen,\n}: AuthDialogProps) {\n const [type, setType] = useState(() => {\n return Object.keys(scheme.flows!)[0] as FlowType;\n });\n const { supported } = FlowTypes[type];\n const form = useForm<FormValues>({\n defaultValues: {\n clientId: '',\n clientSecret: '',\n username: '',\n password: '',\n },\n });\n\n const authCodeCallback = useQuery(async (code: string, state: AuthCodeState) => {\n const value = scheme.flows!.authorizationCode!;\n\n const res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n // note: `state` could be invalid, but server will check it\n redirect_uri: state.redirect_uri,\n client_id: state.client_id,\n client_secret: state.client_secret,\n }),\n });\n\n if (!res.ok) throw new Error(await res.text());\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n });\n\n useEffect(() => {\n if (scheme.flows!.authorizationCode) {\n const params = new URLSearchParams(window.location.search);\n const state = params.get('state');\n const code = params.get('code');\n\n if (state && code) {\n const parsedState = JSON.parse(state) as AuthCodeState;\n setOpen(true);\n\n form.setValue('clientId', parsedState.client_id);\n form.setValue('clientSecret', parsedState.client_secret);\n authCodeCallback.start(code, parsedState);\n window.history.replaceState(null, '', window.location.pathname);\n return;\n }\n }\n\n if (scheme.flows!.implicit && window.location.hash.length > 1) {\n const params = new URLSearchParams(window.location.hash.slice(1));\n const state = params.get('state');\n const token = params.get('access_token');\n const type = params.get('token_type') ?? 'Bearer';\n\n if (state && token) {\n const parsedState = JSON.parse(state) as ImplicitState;\n\n form.setValue('clientId', parsedState.client_id);\n setToken(`${type} ${token}`);\n window.history.replaceState(null, '', window.location.pathname);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only\n }, []);\n\n const authorize = useQuery(async (values: FormValues) => {\n if (type === 'implicit') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'token');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n redirect_uri: window.location.href,\n } satisfies ImplicitState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n if (type === 'authorizationCode') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'code');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n client_secret: values.clientSecret,\n redirect_uri: window.location.href,\n } satisfies AuthCodeState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n\n let res;\n if (type === 'password') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'password',\n username: values.username,\n password: values.password,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (type === 'clientCredentials') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: values.clientId,\n client_secret: values.clientSecret,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (res) {\n if (!res.ok) throw new Error(await res.text());\n\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n }\n });\n\n const onSubmit = form.handleSubmit((values) => {\n return authorize.start(values);\n });\n\n const isLoading = authorize.isLoading || authCodeCallback.isLoading;\n const error = authCodeCallback.error ?? authorize.error;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n {children}\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Authorization</DialogTitle>\n <DialogDescription>Obtain the access token for API.</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(e) => {\n void onSubmit(e);\n e.stopPropagation();\n }}\n >\n <Select value={type} onValueChange={setType as (s: string) => void}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(scheme.flows!).map((key) => {\n const { name, description } = FlowTypes[key as FlowType];\n\n return (\n <SelectItem key={key} value={key}>\n <p className=\"font-medium\">{name}</p>\n <p className=\"text-fd-muted-foreground\">{description}</p>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n\n {(type === 'authorizationCode' ||\n type === 'clientCredentials' ||\n type === 'implicit') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_id\" className={cn(labelVariants())}>\n Client ID\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">\n The client ID of your OAuth application.\n </p>\n <Input\n id=\"client_id\"\n placeholder=\"Enter value\"\n type=\"text\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientId', { required: true })}\n />\n </fieldset>\n )}\n {(type === 'authorizationCode' || type === 'clientCredentials') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_secret\" className={cn(labelVariants())}>\n Client Secret\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">\n The client secret of your OAuth application.\n </p>\n <Input\n id=\"client_secret\"\n placeholder=\"Enter value\"\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientSecret', { required: true })}\n />\n </fieldset>\n )}\n {type === 'password' && (\n <>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"username\" className={cn(labelVariants())}>\n Username\n </label>\n <Input\n id=\"username\"\n placeholder=\"Enter value\"\n type=\"text\"\n disabled={isLoading}\n autoComplete=\"off\"\n {...form.register('username', { required: true })}\n />\n </fieldset>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"password\" className={cn(labelVariants())}>\n Client Secret\n </label>\n <Input\n id=\"password\"\n placeholder=\"Enter value\"\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('password', { required: true })}\n />\n </fieldset>\n </>\n )}\n {supported ? (\n <>\n {error ? <p className=\"text-red-400 font-medium text-sm\">{String(error)}</p> : null}\n <button\n type=\"submit\"\n disabled={isLoading}\n className={cn(\n buttonVariants({\n color: 'primary',\n }),\n )}\n >\n {authCodeCallback.isLoading ? 'Fetching token...' : 'Submit'}\n </button>\n </>\n ) : (\n <p className=\"text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border\">\n Unsupported\n </p>\n )}\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport const OauthDialogTrigger = DialogTrigger;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oauth-dialog.js","names":[],"sources":["../../../src/playground/components/oauth-dialog.tsx"],"sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { useForm } from 'react-hook-form';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useQuery } from '@/utils/use-query';\nimport { type ReactNode, useEffect, useMemo, useState } from 'react';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport type { OAuth2SecurityScheme } from '@/types';\nimport { useTranslations } from '@/ui/client/i18n';\n\ntype FlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;\n\nexport interface AuthDialogProps {\n scheme: OAuth2SecurityScheme;\n scopes: string[];\n\n open: boolean;\n setOpen: (v: boolean) => void;\n setToken: (token: string) => void;\n children: ReactNode;\n}\n\ninterface FormValues {\n clientId: string;\n clientSecret: string;\n username: string;\n password: string;\n}\n\ninterface AuthCodeState {\n redirect_uri: string;\n client_id: string;\n client_secret: string;\n}\n\ninterface ImplicitState {\n redirect_uri: string;\n client_id: string;\n}\n\ninterface FlowInfo {\n name: ReactNode;\n description: ReactNode;\n supported: boolean;\n}\n\nexport function OauthDialog({\n scheme,\n scopes,\n setToken,\n children,\n open,\n setOpen,\n}: AuthDialogProps) {\n const [type, setType] = useState(() => {\n return Object.keys(scheme.flows!)[0] as FlowType;\n });\n const t = useTranslations();\n const allFlows: Record<FlowType, FlowInfo> = useMemo(\n () => ({\n password: {\n name: t.resourceOwnerPassword,\n description: t.resourceOwnerPasswordDesc,\n supported: true,\n },\n clientCredentials: {\n name: t.clientCredentials,\n description: t.clientCredentialsDesc,\n supported: true,\n },\n authorizationCode: {\n name: t.authorizationCode,\n description: t.authorizationCodeDesc,\n supported: true,\n },\n implicit: {\n name: t.implicit,\n description: t.implicitDesc,\n supported: true,\n },\n deviceAuthorization: {\n name: t.deviceAuthorization,\n description: t.deviceAuthorizationDesc,\n supported: false,\n },\n }),\n [t],\n );\n\n const form = useForm<FormValues>({\n defaultValues: {\n clientId: '',\n clientSecret: '',\n username: '',\n password: '',\n },\n });\n\n const authCodeCallback = useQuery(async (code: string, state: AuthCodeState) => {\n const value = scheme.flows!.authorizationCode!;\n\n const res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n // note: `state` could be invalid, but server will check it\n redirect_uri: state.redirect_uri,\n client_id: state.client_id,\n client_secret: state.client_secret,\n }),\n });\n\n if (!res.ok) throw new Error(await res.text());\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n });\n\n useEffect(() => {\n if (scheme.flows!.authorizationCode) {\n const params = new URLSearchParams(window.location.search);\n const state = params.get('state');\n const code = params.get('code');\n\n if (state && code) {\n const parsedState = JSON.parse(state) as AuthCodeState;\n setOpen(true);\n\n form.setValue('clientId', parsedState.client_id);\n form.setValue('clientSecret', parsedState.client_secret);\n authCodeCallback.start(code, parsedState);\n window.history.replaceState(null, '', window.location.pathname);\n return;\n }\n }\n\n if (scheme.flows!.implicit && window.location.hash.length > 1) {\n const params = new URLSearchParams(window.location.hash.slice(1));\n const state = params.get('state');\n const token = params.get('access_token');\n const type = params.get('token_type') ?? 'Bearer';\n\n if (state && token) {\n const parsedState = JSON.parse(state) as ImplicitState;\n\n form.setValue('clientId', parsedState.client_id);\n setToken(`${type} ${token}`);\n window.history.replaceState(null, '', window.location.pathname);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only\n }, []);\n\n const authorize = useQuery(async (values: FormValues) => {\n if (type === 'implicit') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'token');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n redirect_uri: window.location.href,\n } satisfies ImplicitState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n if (type === 'authorizationCode') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'code');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n client_secret: values.clientSecret,\n redirect_uri: window.location.href,\n } satisfies AuthCodeState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n\n let res;\n if (type === 'password') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'password',\n username: values.username,\n password: values.password,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (type === 'clientCredentials') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: values.clientId,\n client_secret: values.clientSecret,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (res) {\n if (!res.ok) throw new Error(await res.text());\n\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n }\n });\n\n const onSubmit = form.handleSubmit((values) => {\n return authorize.start(values);\n });\n\n const isLoading = authorize.isLoading || authCodeCallback.isLoading;\n const error = authCodeCallback.error ?? authorize.error;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n {children}\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t.authorization}</DialogTitle>\n <DialogDescription>{t.obtainAccessToken}</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(e) => {\n void onSubmit(e);\n e.stopPropagation();\n }}\n >\n <Select value={type} onValueChange={setType as (s: string) => void}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(scheme.flows!).map((key) => {\n const { name, description } = allFlows[key as FlowType];\n\n return (\n <SelectItem key={key} value={key}>\n <p className=\"font-medium\">{name}</p>\n <p className=\"text-fd-muted-foreground\">{description}</p>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n\n {(type === 'authorizationCode' ||\n type === 'clientCredentials' ||\n type === 'implicit') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_id\" className={cn(labelVariants())}>\n {t.clientId}\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">{t.clientIdHint}</p>\n <Input\n id=\"client_id\"\n placeholder={t.inputPlaceholder}\n type=\"text\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientId', { required: true })}\n />\n </fieldset>\n )}\n {(type === 'authorizationCode' || type === 'clientCredentials') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_secret\" className={cn(labelVariants())}>\n {t.clientSecret}\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">{t.clientSecretHint}</p>\n <Input\n id=\"client_secret\"\n placeholder={t.inputPlaceholder}\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientSecret', { required: true })}\n />\n </fieldset>\n )}\n {type === 'password' && (\n <>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"username\" className={cn(labelVariants())}>\n {t.usernameField}\n </label>\n <Input\n id=\"username\"\n placeholder={t.inputPlaceholder}\n type=\"text\"\n disabled={isLoading}\n autoComplete=\"off\"\n {...form.register('username', { required: true })}\n />\n </fieldset>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"password\" className={cn(labelVariants())}>\n {t.clientSecret}\n </label>\n <Input\n id=\"password\"\n placeholder={t.inputPlaceholder}\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('password', { required: true })}\n />\n </fieldset>\n </>\n )}\n {allFlows[type].supported ? (\n <>\n {error ? <p className=\"text-red-400 font-medium text-sm\">{String(error)}</p> : null}\n <button\n type=\"submit\"\n disabled={isLoading}\n className={cn(\n buttonVariants({\n color: 'primary',\n }),\n )}\n >\n {authCodeCallback.isLoading ? t.fetchingToken : t.submit}\n </button>\n </>\n ) : (\n <p className=\"text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border\">\n {t.unsupported}\n </p>\n )}\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport const OauthDialogTrigger = DialogTrigger;\n"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import { useServerContext, useServerSelectContext } from "../../ui/contexts/api.
|
|
|
4
4
|
import { cn } from "../../utils/cn.js";
|
|
5
5
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
|
|
6
6
|
import { Input, labelVariants } from "../../ui/components/input.js";
|
|
7
|
+
import { useTranslations } from "../../ui/client/i18n.js";
|
|
7
8
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
|
|
8
9
|
import { useEffect, useRef, useState } from "react";
|
|
9
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -15,6 +16,7 @@ function ServerSelect(props) {
|
|
|
15
16
|
const { server, setServer, setServerVariables } = useServerSelectContext();
|
|
16
17
|
const [open, setOpen] = useState(false);
|
|
17
18
|
const [isMounted, setIsMounted] = useState(false);
|
|
19
|
+
const t = useTranslations();
|
|
18
20
|
useEffect(() => {
|
|
19
21
|
setIsMounted(true);
|
|
20
22
|
}, []);
|
|
@@ -29,16 +31,16 @@ function ServerSelect(props) {
|
|
|
29
31
|
children: [
|
|
30
32
|
/* @__PURE__ */ jsx("span", {
|
|
31
33
|
className: "px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm",
|
|
32
|
-
children: server?.name ??
|
|
34
|
+
children: server?.name ?? t.serverUrl
|
|
33
35
|
}),
|
|
34
36
|
/* @__PURE__ */ jsx("code", {
|
|
35
37
|
className: "truncate min-w-0 flex-1",
|
|
36
|
-
children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) :
|
|
38
|
+
children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) : t.loading
|
|
37
39
|
}),
|
|
38
40
|
/* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
|
|
39
41
|
]
|
|
40
42
|
}), /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
41
|
-
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children:
|
|
43
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t.serverUrl }), /* @__PURE__ */ jsx(DialogDescription, { children: t.serverUrlDescription })] }),
|
|
42
44
|
/* @__PURE__ */ jsxs(Select, {
|
|
43
45
|
value: server?.url,
|
|
44
46
|
onValueChange: setServer,
|
|
@@ -99,6 +101,7 @@ function ServerSelectContent({ defaultValues, onChange, schema }) {
|
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
function Field({ fieldName, variable }) {
|
|
104
|
+
const t = useTranslations();
|
|
102
105
|
const [value, setValue] = useFieldValue([fieldName], { compute(currentValue) {
|
|
103
106
|
return typeof currentValue === "string" ? currentValue : void 0;
|
|
104
107
|
} });
|
|
@@ -117,7 +120,7 @@ function Field({ fieldName, variable }) {
|
|
|
117
120
|
id: fieldName,
|
|
118
121
|
value,
|
|
119
122
|
onChange: (e) => setValue(e.target.value),
|
|
120
|
-
placeholder:
|
|
123
|
+
placeholder: t.serverUrlFieldPlaceholder
|
|
121
124
|
});
|
|
122
125
|
}
|
|
123
126
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-select.js","names":[],"sources":["../../../src/playground/components/server-select.tsx"],"sourcesContent":["'use client';\nimport { useServerContext, useServerSelectContext } from '@/ui/contexts/api';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useEffect, useState, useRef, type ComponentProps } from 'react';\nimport { cn } from '@/utils/cn';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { resolveServerUrl, withBase } from '@/utils/url';\nimport type { ServerVariableObject } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { StfProvider, useFieldValue, useListener, useStf } from '@fumari/stf';\nimport { EditIcon } from 'lucide-react';\n\nexport default function ServerSelect(props: ComponentProps<typeof DialogTrigger>) {\n const { servers } = useServerContext();\n const { server, setServer, setServerVariables } = useServerSelectContext();\n const [open, setOpen] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n if (servers.length <= 0) return;\n const serverSchema = server ? servers.find((obj) => obj.url === server.url) : null;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger\n {...props}\n className={cn(\n 'flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground',\n props.className,\n )}\n >\n <span className=\"px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm\">\n {server?.name ??
|
|
1
|
+
{"version":3,"file":"server-select.js","names":[],"sources":["../../../src/playground/components/server-select.tsx"],"sourcesContent":["'use client';\nimport { useServerContext, useServerSelectContext } from '@/ui/contexts/api';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useEffect, useState, useRef, type ComponentProps } from 'react';\nimport { cn } from '@/utils/cn';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { resolveServerUrl, withBase } from '@/utils/url';\nimport type { ServerVariableObject } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { StfProvider, useFieldValue, useListener, useStf } from '@fumari/stf';\nimport { EditIcon } from 'lucide-react';\nimport { useTranslations } from '@/ui/client/i18n';\n\nexport default function ServerSelect(props: ComponentProps<typeof DialogTrigger>) {\n const { servers } = useServerContext();\n const { server, setServer, setServerVariables } = useServerSelectContext();\n const [open, setOpen] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const t = useTranslations();\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n if (servers.length <= 0) return;\n const serverSchema = server ? servers.find((obj) => obj.url === server.url) : null;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger\n {...props}\n className={cn(\n 'flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground',\n props.className,\n )}\n >\n <span className=\"px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm\">\n {server?.name ?? t.serverUrl}\n </span>\n <code className=\"truncate min-w-0 flex-1\">\n {isMounted\n ? withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n window.location.origin,\n )\n : t.loading}\n </code>\n <EditIcon className=\"size-4\" />\n </DialogTrigger>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t.serverUrl}</DialogTitle>\n <DialogDescription>{t.serverUrlDescription}</DialogDescription>\n </DialogHeader>\n <Select value={server?.url} onValueChange={setServer}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {servers.map((item) => (\n <SelectItem key={item.url} value={item.url!}>\n <code className=\"text-[0.8125rem]\">{item.url}</code>\n <p className=\"text-fd-muted-foreground\">{item.description}</p>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {server?.variables && serverSchema?.variables && (\n <ServerSelectContent\n key={server.url}\n defaultValues={server.variables}\n schema={serverSchema.variables}\n onChange={setServerVariables}\n />\n )}\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ServerSelectContent({\n defaultValues,\n onChange,\n schema,\n}: {\n defaultValues: Record<string, string>;\n onChange: (values: Record<string, string>) => void;\n schema: Record<string, NoReference<ServerVariableObject>>;\n}) {\n const stf = useStf({\n defaultValues: () => structuredClone(defaultValues),\n });\n const timerRef = useRef<number | null>(null);\n useListener({\n stf,\n onUpdate() {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n\n timerRef.current = window.setTimeout(\n () => onChange(stf.dataEngine.getData() as Record<string, string>),\n 500,\n );\n },\n });\n\n return (\n <StfProvider value={stf}>\n <div className=\"flex flex-col gap-4\">\n {Object.entries(schema).map(([key, variable]) => {\n return (\n <fieldset key={key} className=\"flex flex-col gap-1\">\n <label className={cn(labelVariants())} htmlFor={key}>\n {key}\n </label>\n <p className=\"text-xs text-fd-muted-foreground empty:hidden\">\n {variable.description}\n </p>\n <Field fieldName={key} variable={variable} />\n </fieldset>\n );\n })}\n </div>\n </StfProvider>\n );\n}\n\nfunction Field({\n fieldName,\n variable,\n}: {\n variable: NoReference<ServerVariableObject>;\n fieldName: string;\n}) {\n const t = useTranslations();\n const [value, setValue] = useFieldValue([fieldName], {\n compute(currentValue) {\n return typeof currentValue === 'string' ? currentValue : undefined;\n },\n });\n\n if (variable.enum) {\n return (\n <Select value={value} onValueChange={setValue}>\n <SelectTrigger id={fieldName}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {variable.enum.map((value) => (\n <SelectItem key={value} value={String(value)}>\n {value}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n }\n\n return (\n <Input\n id={fieldName}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder={t.serverUrlFieldPlaceholder}\n />\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
import { CircleCheck, CircleX } from "lucide-react";
|
|
2
2
|
//#region src/playground/status-info.tsx
|
|
3
|
-
const
|
|
3
|
+
const statusKeys = {
|
|
4
4
|
400: {
|
|
5
|
-
|
|
5
|
+
key: "statusBadRequest",
|
|
6
6
|
color: "text-red-500",
|
|
7
7
|
icon: CircleX
|
|
8
8
|
},
|
|
9
9
|
401: {
|
|
10
|
-
|
|
10
|
+
key: "statusUnauthorized",
|
|
11
11
|
color: "text-red-500",
|
|
12
12
|
icon: CircleX
|
|
13
13
|
},
|
|
14
14
|
403: {
|
|
15
|
-
|
|
15
|
+
key: "statusForbidden",
|
|
16
16
|
color: "text-red-500",
|
|
17
17
|
icon: CircleX
|
|
18
18
|
},
|
|
19
19
|
404: {
|
|
20
|
-
|
|
20
|
+
key: "statusNotFound",
|
|
21
21
|
color: "text-fd-muted-foreground",
|
|
22
22
|
icon: CircleX
|
|
23
23
|
},
|
|
24
24
|
500: {
|
|
25
|
-
|
|
25
|
+
key: "statusInternalServerError",
|
|
26
26
|
color: "text-red-500",
|
|
27
27
|
icon: CircleX
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
-
function getStatusInfo(status) {
|
|
31
|
-
if (status in
|
|
30
|
+
function getStatusInfo(status, t) {
|
|
31
|
+
if (status in statusKeys) {
|
|
32
|
+
const { key, color, icon } = statusKeys[status];
|
|
33
|
+
return {
|
|
34
|
+
description: t[key],
|
|
35
|
+
color,
|
|
36
|
+
icon
|
|
37
|
+
};
|
|
38
|
+
}
|
|
32
39
|
if (status >= 200 && status < 300) return {
|
|
33
|
-
description:
|
|
40
|
+
description: t.statusSuccessful,
|
|
34
41
|
color: "text-green-500",
|
|
35
42
|
icon: CircleCheck
|
|
36
43
|
};
|
|
37
44
|
if (status >= 400) return {
|
|
38
|
-
description:
|
|
45
|
+
description: t.statusError,
|
|
39
46
|
color: "text-red-500",
|
|
40
47
|
icon: CircleX
|
|
41
48
|
};
|
|
42
49
|
return {
|
|
43
|
-
description:
|
|
50
|
+
description: t.statusNoDescription,
|
|
44
51
|
color: "text-fd-muted-foreground",
|
|
45
52
|
icon: CircleX
|
|
46
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-info.js","names":[],"sources":["../../src/playground/status-info.tsx"],"sourcesContent":["import { CircleCheck, CircleX } from 'lucide-react';\n\ninterface StatusInfo {\n description: string;\n color: string;\n icon: React.ElementType;\n}\n\nconst
|
|
1
|
+
{"version":3,"file":"status-info.js","names":[],"sources":["../../src/playground/status-info.tsx"],"sourcesContent":["import { CircleCheck, CircleX } from 'lucide-react';\nimport type { Translations } from '@/i18n';\n\ninterface StatusInfo {\n description: string;\n color: string;\n icon: React.ElementType;\n}\n\nconst statusKeys: Record<\n number,\n { key: keyof Translations; color: string; icon: React.ElementType }\n> = {\n 400: { key: 'statusBadRequest', color: 'text-red-500', icon: CircleX },\n 401: { key: 'statusUnauthorized', color: 'text-red-500', icon: CircleX },\n 403: { key: 'statusForbidden', color: 'text-red-500', icon: CircleX },\n 404: { key: 'statusNotFound', color: 'text-fd-muted-foreground', icon: CircleX },\n 500: { key: 'statusInternalServerError', color: 'text-red-500', icon: CircleX },\n};\n\nexport function getStatusInfo(status: number, t: Translations): StatusInfo {\n if (status in statusKeys) {\n const { key, color, icon } = statusKeys[status];\n return { description: t[key], color, icon };\n }\n\n if (status >= 200 && status < 300) {\n return {\n description: t.statusSuccessful,\n color: 'text-green-500',\n icon: CircleCheck,\n };\n }\n\n if (status >= 400) {\n return { description: t.statusError, color: 'text-red-500', icon: CircleX };\n }\n\n return {\n description: t.statusNoDescription,\n color: 'text-fd-muted-foreground',\n icon: CircleX,\n };\n}\n"],"mappings":";;AASA,MAAM,aAGF;CACF,KAAK;EAAE,KAAK;EAAoB,OAAO;EAAgB,MAAM;EAAS;CACtE,KAAK;EAAE,KAAK;EAAsB,OAAO;EAAgB,MAAM;EAAS;CACxE,KAAK;EAAE,KAAK;EAAmB,OAAO;EAAgB,MAAM;EAAS;CACrE,KAAK;EAAE,KAAK;EAAkB,OAAO;EAA4B,MAAM;EAAS;CAChF,KAAK;EAAE,KAAK;EAA6B,OAAO;EAAgB,MAAM;EAAS;CAChF;AAED,SAAgB,cAAc,QAAgB,GAA6B;AACzE,KAAI,UAAU,YAAY;EACxB,MAAM,EAAE,KAAK,OAAO,SAAS,WAAW;AACxC,SAAO;GAAE,aAAa,EAAE;GAAM;GAAO;GAAM;;AAG7C,KAAI,UAAU,OAAO,SAAS,IAC5B,QAAO;EACL,aAAa,EAAE;EACf,OAAO;EACP,MAAM;EACP;AAGH,KAAI,UAAU,IACZ,QAAO;EAAE,aAAa,EAAE;EAAa,OAAO;EAAgB,MAAM;EAAS;AAG7E,QAAO;EACL,aAAa,EAAE;EACf,OAAO;EACP,MAAM;EACP"}
|
package/dist/types.d.ts
CHANGED
|
@@ -39,7 +39,9 @@ interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<RequireKe
|
|
|
39
39
|
*/
|
|
40
40
|
schema: ProcessedDocument;
|
|
41
41
|
mediaAdapters: Record<string, MediaAdapter>;
|
|
42
|
-
renderHeading: (depth: number, text: string, props?: HTMLAttributes<HTMLHeadingElement>
|
|
42
|
+
renderHeading: (depth: number, text: string | ReactNode, props?: HTMLAttributes<HTMLHeadingElement> & {
|
|
43
|
+
id?: string;
|
|
44
|
+
}) => ReactNode;
|
|
43
45
|
renderCodeBlock: (lang: string, code: string) => ReactNode;
|
|
44
46
|
}
|
|
45
47
|
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;KAUY,QAAA,GAAW,WAAA,CAAY,QAAA;AAAA,KACvB,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,oBAAA,GAAuB,WAAA,CAAY,oBAAA;AAAA,KACnC,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,cAAA,GAAiB,WAAA,CAAY,cAAA;AAAA,KAC7B,SAAA,GAAY,WAAA,CAAY,SAAA;AAAA,KACxB,YAAA,GAAe,WAAA,CAAY,YAAA;AAAA,KAC3B,cAAA,GAAiB,WAAA,CAAY,cAAA;AAAA,KAC7B,oBAAA,GAAuB,SAAA,CAAU,oBAAA;AAAA,KACjC,cAAA,GAAiB,WAAA,CAAY,cAAA;AAAA,KAC7B,oBAAA,GAAuB,WAAA,CAAY,oBAAA;AAAA,KACnC,WAAA,GAAc,WAAA,CAAY,WAAA;AAAA,KAC1B,aAAA,GAAgB,WAAA,CAAY,aAAA;AAAA,KAC5B,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,iBAAA,GAAoB,WAAA,CAAY,iBAAA;AAAA,KAEhC,iBAAA,GAAoB,WAAA,CAAY,eAAA;EAC1C,MAAA;EACA,eAAA,GAAkB,wBAAA;EAClB,sBAAA;EACA,uBAAA;AAAA;AAAA,KAGG,WAAA,oBAA+B,CAAA,IAAK,IAAA,CAAK,CAAA,EAAG,CAAA,IAAK,QAAA,CAAS,IAAA,CAAK,CAAA,EAAG,CAAA;AAAA,UAEtD,aAAA,SAEb,IAAA,CAAK,cAAA,eACL,IAAA,CACE,WAAA,CAAY,oBAAA;EAGhB,OAAA,EAAS,OAAA;;;;EAKT,MAAA,EAAQ,iBAAA;EAER,aAAA,EAAe,MAAA,SAAe,YAAA;EAE9B,aAAA,GACE,KAAA,UACA,IAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;KAUY,QAAA,GAAW,WAAA,CAAY,QAAA;AAAA,KACvB,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,oBAAA,GAAuB,WAAA,CAAY,oBAAA;AAAA,KACnC,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,cAAA,GAAiB,WAAA,CAAY,cAAA;AAAA,KAC7B,SAAA,GAAY,WAAA,CAAY,SAAA;AAAA,KACxB,YAAA,GAAe,WAAA,CAAY,YAAA;AAAA,KAC3B,cAAA,GAAiB,WAAA,CAAY,cAAA;AAAA,KAC7B,oBAAA,GAAuB,SAAA,CAAU,oBAAA;AAAA,KACjC,cAAA,GAAiB,WAAA,CAAY,cAAA;AAAA,KAC7B,oBAAA,GAAuB,WAAA,CAAY,oBAAA;AAAA,KACnC,WAAA,GAAc,WAAA,CAAY,WAAA;AAAA,KAC1B,aAAA,GAAgB,WAAA,CAAY,aAAA;AAAA,KAC5B,eAAA,GAAkB,WAAA,CAAY,eAAA;AAAA,KAC9B,iBAAA,GAAoB,WAAA,CAAY,iBAAA;AAAA,KAEhC,iBAAA,GAAoB,WAAA,CAAY,eAAA;EAC1C,MAAA;EACA,eAAA,GAAkB,wBAAA;EAClB,sBAAA;EACA,uBAAA;AAAA;AAAA,KAGG,WAAA,oBAA+B,CAAA,IAAK,IAAA,CAAK,CAAA,EAAG,CAAA,IAAK,QAAA,CAAS,IAAA,CAAK,CAAA,EAAG,CAAA;AAAA,UAEtD,aAAA,SAEb,IAAA,CAAK,cAAA,eACL,IAAA,CACE,WAAA,CAAY,oBAAA;EAGhB,OAAA,EAAS,OAAA;;;;EAKT,MAAA,EAAQ,iBAAA;EAER,aAAA,EAAe,MAAA,SAAe,YAAA;EAE9B,aAAA,GACE,KAAA,UACA,IAAA,WAAe,SAAA,EACf,KAAA,GAAQ,cAAA,CAAe,kBAAA;IAAwB,EAAA;EAAA,MAC5C,SAAA;EACL,eAAA,GAAkB,IAAA,UAAc,IAAA,aAAiB,SAAA;AAAA;AAAA,KAGvC,gBAAA,cAA8B,WAAA,IAAe,CAAA,mBAAoB,IAAA,CAAK,CAAA,EAAG,CAAA;AAAA,KACzE,SAAA,MAAe,CAAA,GAAI,OAAA,CAAQ,CAAA"}
|
package/dist/ui/base.d.ts
CHANGED
|
@@ -7,11 +7,12 @@ import { ExampleRequestItem } from "./operation/request-tabs.js";
|
|
|
7
7
|
import { APIPageClientOptions } from "./client/index.js";
|
|
8
8
|
import { SchemaUIOptions } from "./schema/index.js";
|
|
9
9
|
import { ResponseTab } from "./operation/response-tabs.js";
|
|
10
|
-
import {
|
|
10
|
+
import { ClientCodeBlockProvider } from "./components/codeblock.js";
|
|
11
|
+
import { Awaitable, MethodInformation, RenderContext } from "../types.js";
|
|
11
12
|
import { FC, HTMLAttributes, ReactNode } from "react";
|
|
12
|
-
import {
|
|
13
|
-
import { ResolvedShikiConfig } from "fumadocs-core/highlight/config";
|
|
13
|
+
import { ShikiFactory } from "fumadocs-core/highlight/shiki";
|
|
14
14
|
import { JSONSchema } from "json-schema-typed";
|
|
15
|
+
import { BundledTheme, CodeOptionsThemes, CodeToHastOptionsCommon } from "shiki";
|
|
15
16
|
|
|
16
17
|
//#region src/ui/base.d.ts
|
|
17
18
|
interface GenerateTypeScriptDefinitionsContext extends RenderContext {
|
|
@@ -49,9 +50,9 @@ interface CreateAPIPageOptions {
|
|
|
49
50
|
* Generate example code usage for each endpoint.
|
|
50
51
|
*/
|
|
51
52
|
generateCodeSamples?: (method: MethodInformation) => Awaitable<InlineCodeUsageGenerator[]>;
|
|
52
|
-
shiki:
|
|
53
|
+
shiki: ShikiFactory;
|
|
53
54
|
renderMarkdown?: (md: string) => ReactNode;
|
|
54
|
-
shikiOptions
|
|
55
|
+
shikiOptions: Omit<CodeToHastOptionsCommon, 'lang'> & CodeOptionsThemes<BundledTheme>;
|
|
55
56
|
/**
|
|
56
57
|
* Show full response schema instead of only example response & Typescript definitions.
|
|
57
58
|
*
|
|
@@ -153,5 +154,5 @@ interface CreateAPIPageOptions {
|
|
|
153
154
|
}
|
|
154
155
|
declare function createAPIPage(server: OpenAPIServer, options: CreateAPIPageOptions): FC<ApiPageProps>;
|
|
155
156
|
//#endregion
|
|
156
|
-
export { CreateAPIPageOptions, GenerateTypeScriptDefinitionsContext, createAPIPage };
|
|
157
|
+
export { ClientCodeBlockProvider, CreateAPIPageOptions, GenerateTypeScriptDefinitionsContext, createAPIPage };
|
|
157
158
|
//# sourceMappingURL=base.d.ts.map
|
package/dist/ui/base.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/ui/base.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"base.d.ts","names":[],"sources":["../../src/ui/base.tsx"],"mappings":"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"}
|
package/dist/ui/base.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defaultAdapters } from "../requests/media/adapter.js";
|
|
2
|
+
import { ClientCodeBlockProvider } from "./components/codeblock.js";
|
|
2
3
|
import { APIPage } from "./api-page.js";
|
|
3
4
|
import Slugger from "github-slugger";
|
|
4
5
|
import * as JsxRuntime from "react/jsx-runtime";
|
|
5
6
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
-
import { highlight } from "fumadocs-core/highlight/core";
|
|
7
7
|
import { Heading } from "fumadocs-ui/components/heading";
|
|
8
8
|
import { createRehypeCode } from "fumadocs-core/mdx-plugins/rehype-code.core";
|
|
9
9
|
import { remarkGfm } from "fumadocs-core/mdx-plugins/remark-gfm";
|
|
@@ -12,6 +12,7 @@ import { remark } from "remark";
|
|
|
12
12
|
import remarkRehype from "remark-rehype";
|
|
13
13
|
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
14
14
|
import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock";
|
|
15
|
+
import { highlightHast } from "fumadocs-core/highlight/shiki";
|
|
15
16
|
//#region src/ui/base.tsx
|
|
16
17
|
function createAPIPage(server, options) {
|
|
17
18
|
let processor;
|
|
@@ -28,7 +29,9 @@ function createAPIPage(server, options) {
|
|
|
28
29
|
}
|
|
29
30
|
return remark().use(remarkGfm).use(remarkRehype).use(createRehypeCode(options.shiki), {
|
|
30
31
|
langs: [],
|
|
31
|
-
lazy: true
|
|
32
|
+
lazy: true,
|
|
33
|
+
defaultColor: false,
|
|
34
|
+
...options.shikiOptions
|
|
32
35
|
}).use(rehypeReact);
|
|
33
36
|
}
|
|
34
37
|
return async function APIPageWrapper({ document, ...props }) {
|
|
@@ -46,7 +49,8 @@ function createAPIPage(server, options) {
|
|
|
46
49
|
},
|
|
47
50
|
slugger,
|
|
48
51
|
async renderHeading(depth, text, props) {
|
|
49
|
-
const id = slugger.slug(text);
|
|
52
|
+
const id = typeof text === "string" ? slugger.slug(text) : props?.id;
|
|
53
|
+
if (!id) throw new Error("missing 'id' for non-string children");
|
|
50
54
|
if (options.renderHeading) return options.renderHeading({
|
|
51
55
|
id,
|
|
52
56
|
children: text,
|
|
@@ -79,10 +83,12 @@ function createAPIPage(server, options) {
|
|
|
79
83
|
});
|
|
80
84
|
return /* @__PURE__ */ jsx(CodeBlock, {
|
|
81
85
|
className: "my-0",
|
|
82
|
-
children: await
|
|
86
|
+
children: toJsxRuntime(await highlightHast(await options.shiki.getOrInit(), code, {
|
|
83
87
|
lang,
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
defaultColor: false,
|
|
89
|
+
...options.shikiOptions
|
|
90
|
+
}), {
|
|
91
|
+
...JsxRuntime,
|
|
86
92
|
components: { pre: Pre }
|
|
87
93
|
})
|
|
88
94
|
});
|
|
@@ -95,6 +101,6 @@ function createAPIPage(server, options) {
|
|
|
95
101
|
};
|
|
96
102
|
}
|
|
97
103
|
//#endregion
|
|
98
|
-
export { createAPIPage };
|
|
104
|
+
export { ClientCodeBlockProvider, createAPIPage };
|
|
99
105
|
|
|
100
106
|
//# sourceMappingURL=base.js.map
|