fumadocs-openapi 9.0.4 → 9.0.6
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/dist/playground/auth/oauth-dialog.d.ts +4 -2
- package/dist/playground/auth/oauth-dialog.d.ts.map +1 -1
- package/dist/playground/auth/oauth-dialog.js +113 -26
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +105 -69
- package/dist/playground/fetcher.d.ts +6 -1
- package/dist/playground/fetcher.d.ts.map +1 -1
- package/dist/playground/fetcher.js +2 -4
- package/dist/playground/index.js +26 -15
- package/dist/playground/inputs.d.ts +8 -2
- package/dist/playground/inputs.d.ts.map +1 -1
- package/dist/playground/inputs.js +32 -31
- package/dist/render/api-page.d.ts.map +1 -1
- package/dist/render/api-page.js +2 -10
- package/dist/render/heading.d.ts +1 -1
- package/dist/render/heading.d.ts.map +1 -1
- package/dist/render/heading.js +3 -3
- package/dist/render/markdown.d.ts +2 -2
- package/dist/render/markdown.d.ts.map +1 -1
- package/dist/render/markdown.js +4 -2
- package/dist/render/operation/index.d.ts.map +1 -1
- package/dist/render/operation/index.js +68 -58
- package/dist/render/renderer.d.ts.map +1 -1
- package/dist/render/renderer.js +3 -3
- package/dist/render/schema.d.ts.map +1 -1
- package/dist/render/schema.js +7 -8
- package/dist/requests/_shared.d.ts +0 -1
- package/dist/requests/_shared.d.ts.map +1 -1
- package/dist/requests/_shared.js +0 -4
- package/dist/requests/curl.d.ts.map +1 -1
- package/dist/requests/curl.js +3 -2
- package/dist/requests/go.d.ts.map +1 -1
- package/dist/requests/go.js +3 -2
- package/dist/requests/javascript.d.ts.map +1 -1
- package/dist/requests/javascript.js +3 -2
- package/dist/requests/python.d.ts.map +1 -1
- package/dist/requests/python.js +2 -2
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/components/accordion.d.ts +8 -0
- package/dist/ui/components/accordion.d.ts.map +1 -0
- package/dist/ui/components/accordion.js +20 -0
- package/dist/ui/components/input.js +1 -1
- package/dist/ui/components/select.js +1 -1
- package/dist/ui/contexts/api.js +1 -1
- package/dist/ui/contexts/code-example.d.ts.map +1 -1
- package/dist/ui/contexts/code-example.js +4 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +5 -3
- package/dist/ui/select-tabs.d.ts +13 -0
- package/dist/ui/select-tabs.d.ts.map +1 -0
- package/dist/ui/select-tabs.js +20 -0
- package/dist/ui/server-select.d.ts.map +1 -1
- package/dist/ui/server-select.js +24 -19
- package/dist/utils/schema-to-string.d.ts.map +1 -1
- package/dist/utils/schema-to-string.js +10 -1
- package/dist/utils/schema.d.ts +0 -1
- package/dist/utils/schema.d.ts.map +1 -1
- package/dist/utils/schema.js +0 -10
- package/dist/utils/url.d.ts +10 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +51 -0
- package/package.json +10 -9
- package/dist/utils/get-pathname-from-input.d.ts +0 -2
- package/dist/utils/get-pathname-from-input.d.ts.map +0 -1
- package/dist/utils/get-pathname-from-input.js +0 -27
- package/dist/utils/server-url.d.ts +0 -2
- package/dist/utils/server-url.d.ts.map +0 -1
- package/dist/utils/server-url.js +0 -7
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { OpenAPIV3_1 } from 'openapi-types';
|
|
2
2
|
export interface AuthDialogProps {
|
|
3
|
-
flow: keyof OpenAPIV3_1.OAuth2SecurityScheme['flows'];
|
|
4
3
|
scheme: OpenAPIV3_1.OAuth2SecurityScheme;
|
|
4
|
+
scopes: string[];
|
|
5
|
+
open: boolean;
|
|
6
|
+
setOpen: (v: boolean) => void;
|
|
5
7
|
setToken: (token: string) => void;
|
|
6
8
|
children: React.ReactNode;
|
|
7
9
|
}
|
|
8
|
-
export declare function OauthDialog({
|
|
10
|
+
export declare function OauthDialog({ scheme, scopes, setToken, children, open, setOpen, }: AuthDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
9
11
|
export declare const OauthDialogTrigger: import("react").ForwardRefExoticComponent<import("@radix-ui/react-dialog").DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
10
12
|
//# sourceMappingURL=oauth-dialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-dialog.d.ts","sourceRoot":"","sources":["../../../src/playground/auth/oauth-dialog.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth-dialog.d.ts","sourceRoot":"","sources":["../../../src/playground/auth/oauth-dialog.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAiBjD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,WAAW,CAAC,oBAAoB,CAAC;IACzC,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuCD,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,IAAI,EACJ,OAAO,GACR,EAAE,eAAe,2CAwSjB;AAED,eAAO,MAAM,kBAAkB,mJAAgB,CAAC"}
|
|
@@ -6,15 +6,38 @@ import { useQuery } from '../../utils/use-query.js';
|
|
|
6
6
|
import { useEffect, useState } from 'react';
|
|
7
7
|
import { cn } from 'fumadocs-ui/utils/cn';
|
|
8
8
|
import { buttonVariants } from 'fumadocs-ui/components/ui/button';
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../ui/components/select.js';
|
|
10
|
+
const FlowTypes = {
|
|
11
|
+
password: {
|
|
12
|
+
name: 'Resource Owner Password Flow',
|
|
13
|
+
description: 'Authenticate using username and password.',
|
|
14
|
+
},
|
|
15
|
+
clientCredentials: {
|
|
16
|
+
name: 'Client Credentials',
|
|
17
|
+
description: 'Intended for the server-to-server authentication.',
|
|
18
|
+
},
|
|
19
|
+
authorizationCode: {
|
|
20
|
+
name: 'Authorization code',
|
|
21
|
+
description: 'Authenticate with 3rd party services',
|
|
22
|
+
},
|
|
23
|
+
implicit: {
|
|
24
|
+
name: 'Implicit',
|
|
25
|
+
description: 'Retrieve the access token directly.',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
export function OauthDialog({ scheme, scopes, setToken, children, open, setOpen, }) {
|
|
29
|
+
const [type, setType] = useState(() => {
|
|
30
|
+
return Object.keys(scheme.flows)[0];
|
|
31
|
+
});
|
|
11
32
|
const form = useForm({
|
|
12
33
|
defaultValues: {
|
|
13
34
|
clientId: '',
|
|
14
35
|
clientSecret: '',
|
|
36
|
+
username: '',
|
|
37
|
+
password: '',
|
|
15
38
|
},
|
|
16
39
|
});
|
|
17
|
-
const
|
|
40
|
+
const authCodeCallback = useQuery(async (code, state) => {
|
|
18
41
|
const value = scheme.flows.authorizationCode;
|
|
19
42
|
const res = await fetch(value.tokenUrl, {
|
|
20
43
|
method: 'POST',
|
|
@@ -32,59 +55,123 @@ export function OauthDialog({ flow, scheme, setToken, children, }) {
|
|
|
32
55
|
});
|
|
33
56
|
if (!res.ok)
|
|
34
57
|
throw new Error(await res.text());
|
|
35
|
-
const { access_token } = (await res.json());
|
|
36
|
-
setToken(access_token);
|
|
58
|
+
const { access_token, token_type = 'Bearer' } = (await res.json());
|
|
59
|
+
setToken(`${token_type} ${access_token}`);
|
|
37
60
|
setOpen(false);
|
|
38
61
|
});
|
|
39
62
|
useEffect(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
if (scheme.flows.authorizationCode) {
|
|
64
|
+
const params = new URLSearchParams(window.location.search);
|
|
65
|
+
const state = params.get('state');
|
|
66
|
+
const code = params.get('code');
|
|
67
|
+
if (state && code) {
|
|
68
|
+
const parsedState = JSON.parse(state);
|
|
69
|
+
setOpen(true);
|
|
70
|
+
form.setValue('clientId', parsedState.client_id);
|
|
71
|
+
form.setValue('clientSecret', parsedState.client_secret);
|
|
72
|
+
authCodeCallback.start(code, parsedState);
|
|
73
|
+
window.history.replaceState(null, '', window.location.pathname);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (scheme.flows.implicit && window.location.hash.length > 1) {
|
|
78
|
+
const params = new URLSearchParams(window.location.hash.slice(1));
|
|
79
|
+
const state = params.get('state');
|
|
80
|
+
const token = params.get('access_token');
|
|
81
|
+
const type = params.get('token_type') ?? 'Bearer';
|
|
82
|
+
if (state && token) {
|
|
83
|
+
const parsedState = JSON.parse(state);
|
|
84
|
+
form.setValue('clientId', parsedState.client_id);
|
|
85
|
+
setToken(`${type} ${token}`);
|
|
86
|
+
window.history.replaceState(null, '', window.location.pathname);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
51
89
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only
|
|
52
90
|
}, []);
|
|
53
91
|
const authorize = useQuery(async (values) => {
|
|
54
|
-
if (
|
|
55
|
-
const value = scheme.flows[
|
|
92
|
+
if (type === 'implicit') {
|
|
93
|
+
const value = scheme.flows[type];
|
|
94
|
+
const params = new URLSearchParams();
|
|
95
|
+
params.set('response_type', 'token');
|
|
96
|
+
params.set('client_id', values.clientId);
|
|
97
|
+
params.set('redirect_uri', window.location.href);
|
|
98
|
+
params.set('scope', scopes.join('+'));
|
|
99
|
+
params.set('state', JSON.stringify({
|
|
100
|
+
client_id: values.clientId,
|
|
101
|
+
redirect_uri: window.location.href,
|
|
102
|
+
}));
|
|
103
|
+
window.location.replace(`${value.authorizationUrl}?${params.toString()}`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (type === 'authorizationCode') {
|
|
107
|
+
const value = scheme.flows[type];
|
|
56
108
|
const params = new URLSearchParams();
|
|
57
109
|
params.set('response_type', 'code');
|
|
58
110
|
params.set('client_id', values.clientId);
|
|
59
111
|
params.set('redirect_uri', window.location.href);
|
|
60
|
-
params.set('scope',
|
|
112
|
+
params.set('scope', scopes.join('+'));
|
|
61
113
|
params.set('state', JSON.stringify({
|
|
62
114
|
client_id: values.clientId,
|
|
63
115
|
client_secret: values.clientSecret,
|
|
64
116
|
redirect_uri: window.location.href,
|
|
65
117
|
}));
|
|
66
118
|
window.location.replace(`${value.authorizationUrl}?${params.toString()}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
let res;
|
|
122
|
+
if (type === 'password') {
|
|
123
|
+
const value = scheme.flows[type];
|
|
124
|
+
res = await fetch(value.tokenUrl, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: {
|
|
127
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
128
|
+
},
|
|
129
|
+
body: new URLSearchParams({
|
|
130
|
+
grant_type: 'password',
|
|
131
|
+
username: values.username,
|
|
132
|
+
password: values.password,
|
|
133
|
+
scope: scopes.join('+'),
|
|
134
|
+
}),
|
|
135
|
+
});
|
|
67
136
|
}
|
|
68
|
-
if (
|
|
69
|
-
const value = scheme.flows[
|
|
70
|
-
await fetch(value.tokenUrl, {
|
|
137
|
+
if (type === 'clientCredentials') {
|
|
138
|
+
const value = scheme.flows[type];
|
|
139
|
+
res = await fetch(value.tokenUrl, {
|
|
71
140
|
method: 'POST',
|
|
72
141
|
headers: {
|
|
73
142
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
74
143
|
},
|
|
75
144
|
body: new URLSearchParams({
|
|
76
145
|
grant_type: 'client_credentials',
|
|
77
|
-
|
|
146
|
+
client_id: values.clientId,
|
|
147
|
+
client_secret: values.clientSecret,
|
|
148
|
+
scope: scopes.join('+'),
|
|
78
149
|
}),
|
|
79
150
|
});
|
|
80
151
|
}
|
|
152
|
+
if (res) {
|
|
153
|
+
if (!res.ok)
|
|
154
|
+
throw new Error(await res.text());
|
|
155
|
+
const { access_token, token_type = 'Bearer' } = (await res.json());
|
|
156
|
+
setToken(`${token_type} ${access_token}`);
|
|
157
|
+
setOpen(false);
|
|
158
|
+
}
|
|
81
159
|
});
|
|
82
160
|
const onSubmit = form.handleSubmit((values) => {
|
|
83
161
|
return authorize.start(values);
|
|
84
162
|
});
|
|
85
|
-
const isLoading = authorize.isLoading ||
|
|
86
|
-
|
|
163
|
+
const isLoading = authorize.isLoading || authCodeCallback.isLoading;
|
|
164
|
+
const error = authCodeCallback.error ?? authorize.error;
|
|
165
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [children, _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Authorization" }), _jsx(DialogDescription, { children: "Obtain the access token for API." })] }), _jsxs("form", { className: "flex flex-col gap-6", onSubmit: (e) => {
|
|
166
|
+
void onSubmit(e);
|
|
167
|
+
e.stopPropagation();
|
|
168
|
+
}, children: [_jsxs(Select, { value: type, onValueChange: setType, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: Object.keys(scheme.flows).map((key) => {
|
|
169
|
+
const { name, description } = FlowTypes[key];
|
|
170
|
+
return (_jsxs(SelectItem, { value: key, children: [_jsx("p", { className: "font-medium", children: name }), _jsx("p", { className: "text-fd-muted-foreground", children: description })] }, key));
|
|
171
|
+
}) })] }), (type === 'authorizationCode' ||
|
|
172
|
+
type === 'clientCredentials' ||
|
|
173
|
+
type === 'implicit') && (_jsxs("fieldset", { className: "flex flex-col gap-1.5", children: [_jsx("label", { htmlFor: "client_id", className: cn(labelVariants()), children: "Client ID" }), _jsx("p", { className: "text-fd-muted-foreground text-sm", children: "The client ID of your OAuth application." }), _jsx(Input, { id: "client_id", placeholder: "Enter value", type: "text", autoComplete: "off", disabled: isLoading, ...form.register('clientId', { required: true }) })] })), (type === 'authorizationCode' || type === 'clientCredentials') && (_jsxs("fieldset", { className: "flex flex-col gap-1.5", children: [_jsx("label", { htmlFor: "client_secret", className: cn(labelVariants()), children: "Client Secret" }), _jsx("p", { className: "text-fd-muted-foreground text-sm", children: "The client secret of your OAuth application." }), _jsx(Input, { id: "client_secret", placeholder: "Enter value", type: "password", autoComplete: "off", disabled: isLoading, ...form.register('clientSecret', { required: true }) })] })), type === 'password' && (_jsxs(_Fragment, { children: [_jsxs("fieldset", { className: "flex flex-col gap-1.5", children: [_jsx("label", { htmlFor: "username", className: cn(labelVariants()), children: "Username" }), _jsx(Input, { id: "username", placeholder: "Enter value", type: "text", disabled: isLoading, autoComplete: "off", ...form.register('username', { required: true }) })] }), _jsxs("fieldset", { className: "flex flex-col gap-1.5", children: [_jsx("label", { htmlFor: "password", className: cn(labelVariants()), children: "Client Secret" }), _jsx(Input, { id: "password", placeholder: "Enter value", type: "password", autoComplete: "off", disabled: isLoading, ...form.register('password', { required: true }) })] })] })), error ? (_jsx("p", { className: "text-red-400 font-medium text-sm", children: String(error) })) : null, _jsx("button", { type: "submit", disabled: isLoading, className: cn(buttonVariants({
|
|
87
174
|
color: 'primary',
|
|
88
|
-
})), children:
|
|
175
|
+
})), children: authCodeCallback.isLoading ? 'Fetching token...' : 'Submit' })] })] })] }));
|
|
89
176
|
}
|
|
90
177
|
export const OauthDialogTrigger = DialogTrigger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/playground/client.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAAE,EAEP,KAAK,cAAc,EAEnB,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,EACT,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAQzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACd,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/playground/client.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAAE,EAEP,KAAK,cAAc,EAEnB,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,EACT,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAQzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACd,MAAM,oBAAoB,CAAC;AAwC5B,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI;IACpE,MAAM,EAAE,CAAC,KAAK,EAAE;QACd;;WAEG;QACH,IAAI,EAAE,IAAI,CAAC;QACX,KAAK,EAAE,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAChD,UAAU,EAAE,oBAAoB,CAAC;QACjC,SAAS,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;KAC3C,KAAK,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,eAAe,CAAC;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,UAAU,EAAE,aAAa,EAAE,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,aAAa,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,WAAW,CACrB,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,EACnC,cAAc,CACf,CAAC;QACF,IAAI,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC,CAAC;QACzD,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;KAC3C,CAAC;IAEF,UAAU,CAAC,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,EAAE,CAAC;YAAE,IAAI,EAAE,WAAW,CAAA;SAAE,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ;AAgCD,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAC7B,KAAK,EACL,MAAc,EACd,UAAU,EACV,UAAU,EACV,IAAI,EACJ,MAAM,EACN,UAAU,EACV,QAAQ,EACR,UAAU,EAAE,EAAE,aAAoC,EAAO,EACzD,GAAG,IAAI,EACR,EAAE,WAAW,2CA2Kb"}
|
|
@@ -3,9 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { Fragment, lazy, useEffect, useMemo, useState, } from 'react';
|
|
4
4
|
import { Controller, FormProvider, useForm, useFormContext, } from 'react-hook-form';
|
|
5
5
|
import { useApiContext, useServerSelectContext } from '../ui/contexts/api.js';
|
|
6
|
-
import { FieldSet, JsonInput } from './inputs.js';
|
|
6
|
+
import { FieldInput, FieldSet, JsonInput, ObjectInput } from './inputs.js';
|
|
7
7
|
import { getStatusInfo } from './status-info.js';
|
|
8
|
-
import {
|
|
8
|
+
import { joinURL, resolveRequestData, resolveServerUrl, withBase, } from '../utils/url.js';
|
|
9
9
|
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
|
|
10
10
|
import { MethodLabel } from '../ui/components/method-label.js';
|
|
11
11
|
import { useQuery } from '../utils/use-query.js';
|
|
@@ -17,6 +17,8 @@ import { SchemaProvider, useResolvedSchema, } from '../playground/schema.js';
|
|
|
17
17
|
import { useRequestDataUpdater, useRequestInitialData, } from '../ui/contexts/code-example.js';
|
|
18
18
|
import { useEffectEvent } from 'fumadocs-core/utils/use-effect-event';
|
|
19
19
|
import { useOnChange } from 'fumadocs-core/utils/use-on-change';
|
|
20
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../ui/components/select.js';
|
|
21
|
+
import { labelVariants } from '../ui/components/input.js';
|
|
20
22
|
const AuthPrefix = '__fumadocs_auth';
|
|
21
23
|
function toRequestData(method, mediaType, value) {
|
|
22
24
|
return {
|
|
@@ -30,6 +32,12 @@ function toRequestData(method, mediaType, value) {
|
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
const ServerSelect = lazy(() => import('../ui/server-select.js'));
|
|
35
|
+
const OauthDialog = lazy(() => import('./auth/oauth-dialog.js').then((mod) => ({
|
|
36
|
+
default: mod.OauthDialog,
|
|
37
|
+
})));
|
|
38
|
+
const OauthDialogTrigger = lazy(() => import('./auth/oauth-dialog.js').then((mod) => ({
|
|
39
|
+
default: mod.OauthDialogTrigger,
|
|
40
|
+
})));
|
|
33
41
|
export default function Client({ route, method = 'GET', securities, parameters, body, fields, references, proxyUrl, components: { ResultDisplay = DefaultResultDisplay } = {}, ...rest }) {
|
|
34
42
|
const { server } = useServerSelectContext();
|
|
35
43
|
const requestData = useRequestInitialData();
|
|
@@ -50,37 +58,51 @@ export default function Client({ route, method = 'GET', securities, parameters,
|
|
|
50
58
|
});
|
|
51
59
|
const testQuery = useQuery(async (input) => {
|
|
52
60
|
const fetcher = await import('./fetcher.js').then((mod) => mod.createBrowserFetcher(mediaAdapters));
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
: window.location.origin;
|
|
56
|
-
return fetcher.fetch(`${serverUrl}${route}`, {
|
|
61
|
+
const data = toRequestData(method, body?.mediaType, input);
|
|
62
|
+
return fetcher.fetch(joinURL(withBase(server ? resolveServerUrl(server.url, server.variables) : '/', window.location.origin), resolveRequestData(route, data)), {
|
|
57
63
|
proxyUrl,
|
|
58
|
-
...
|
|
64
|
+
...data,
|
|
59
65
|
});
|
|
60
66
|
});
|
|
61
|
-
function initAuthValues() {
|
|
67
|
+
function initAuthValues(values, inputs) {
|
|
62
68
|
for (const item of inputs) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
manipulateValues(values, item.fieldName, () => {
|
|
70
|
+
const stored = localStorage.getItem(AuthPrefix + item.original.id);
|
|
71
|
+
if (stored) {
|
|
72
|
+
const parsed = JSON.parse(stored);
|
|
73
|
+
if (typeof parsed === typeof item.defaultValue)
|
|
74
|
+
return parsed;
|
|
75
|
+
}
|
|
76
|
+
return item.defaultValue;
|
|
77
|
+
});
|
|
72
78
|
}
|
|
79
|
+
return values;
|
|
73
80
|
}
|
|
74
81
|
useOnChange(defaultValues, () => {
|
|
75
82
|
fieldInfoMap.clear();
|
|
76
|
-
form.reset(defaultValues);
|
|
77
|
-
|
|
83
|
+
form.reset(initAuthValues(defaultValues, inputs));
|
|
84
|
+
});
|
|
85
|
+
useOnChange(inputs, (current, previous) => {
|
|
86
|
+
form.reset((values) => {
|
|
87
|
+
for (const item of previous) {
|
|
88
|
+
if (current.some(({ original }) => original.id === item.original.id)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
manipulateValues(values, item.fieldName, () => undefined);
|
|
92
|
+
}
|
|
93
|
+
return initAuthValues(values, current);
|
|
94
|
+
});
|
|
78
95
|
});
|
|
79
|
-
|
|
80
|
-
for (const item of
|
|
81
|
-
|
|
96
|
+
const onUpdateDebounced = useEffectEvent((values) => {
|
|
97
|
+
for (const item of inputs) {
|
|
98
|
+
const value = item.fieldName
|
|
99
|
+
.split('.')
|
|
100
|
+
.reduce((v, seg) => v[seg], values);
|
|
101
|
+
if (value) {
|
|
102
|
+
localStorage.setItem(AuthPrefix + item.original.id, JSON.stringify(value));
|
|
103
|
+
}
|
|
82
104
|
}
|
|
83
|
-
|
|
105
|
+
updater.setData(toRequestData(method, body?.mediaType, mapInputs(values)));
|
|
84
106
|
});
|
|
85
107
|
useEffect(() => {
|
|
86
108
|
let timer = null;
|
|
@@ -91,27 +113,36 @@ export default function Client({ route, method = 'GET', securities, parameters,
|
|
|
91
113
|
callback({ values }) {
|
|
92
114
|
if (timer)
|
|
93
115
|
window.clearTimeout(timer);
|
|
94
|
-
timer = window.setTimeout(() =>
|
|
95
|
-
for (const item of inputs) {
|
|
96
|
-
const value = item.fieldName
|
|
97
|
-
.split('.')
|
|
98
|
-
.reduce((v, seg) => v[seg], values);
|
|
99
|
-
if (value) {
|
|
100
|
-
localStorage.setItem(AuthPrefix + item.original.id, JSON.stringify(value));
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
updater.setData(toRequestData(method, body?.mediaType, mapInputs(values)));
|
|
104
|
-
}, timer ? 400 : 0);
|
|
116
|
+
timer = window.setTimeout(() => onUpdateDebounced(values), timer ? 400 : 0);
|
|
105
117
|
},
|
|
106
118
|
});
|
|
107
|
-
initAuthValues();
|
|
119
|
+
form.reset((values) => initAuthValues(values, inputs));
|
|
108
120
|
return () => subscription();
|
|
109
121
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- mounted once only
|
|
110
122
|
}, []);
|
|
111
123
|
const onSubmit = form.handleSubmit((value) => {
|
|
112
124
|
testQuery.start(mapInputs(value));
|
|
113
125
|
});
|
|
114
|
-
return (_jsx(FormProvider, { ...form, children: _jsx(SchemaProvider, { fieldInfoMap: fieldInfoMap, references: references, children: _jsxs("form", { ...rest, className: cn('not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground', rest.className), onSubmit: onSubmit, children: [_jsx(ServerSelect, {}), _jsxs("div", { className: "flex flex-row items-center gap-2 text-sm p-3 pb-0", children: [_jsx(MethodLabel, { children: method }), _jsx(Route, { route: route, className: "flex-1" }), _jsx("button", { type: "submit", className: cn(buttonVariants({ color: 'primary', size: 'sm' }), 'px-3 py-1.5'), disabled: testQuery.isLoading, children: testQuery.isLoading ? (_jsx(LoaderCircle, { className: "size-4 animate-spin" })) : ('Send') })] }), securities.length > 0 && (
|
|
126
|
+
return (_jsx(FormProvider, { ...form, children: _jsx(SchemaProvider, { fieldInfoMap: fieldInfoMap, references: references, children: _jsxs("form", { ...rest, className: cn('not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground', rest.className), onSubmit: onSubmit, children: [_jsx(ServerSelect, {}), _jsxs("div", { className: "flex flex-row items-center gap-2 text-sm p-3 pb-0", children: [_jsx(MethodLabel, { children: method }), _jsx(Route, { route: route, className: "flex-1" }), _jsx("button", { type: "submit", className: cn(buttonVariants({ color: 'primary', size: 'sm' }), 'px-3 py-1.5'), disabled: testQuery.isLoading, children: testQuery.isLoading ? (_jsx(LoaderCircle, { className: "size-4 animate-spin" })) : ('Send') })] }), securities.length > 0 && (_jsx(SecurityTabs, { securities: securities, securityId: securityId, setSecurityId: setSecurityId, children: inputs.map((input) => (_jsx(Fragment, { children: input.children }, input.fieldName))) })), _jsx(FormBody, { body: body, fields: fields, parameters: parameters }), testQuery.data ? _jsx(ResultDisplay, { data: testQuery.data }) : null] }) }) }));
|
|
127
|
+
}
|
|
128
|
+
function SecurityTabs({ securities, setSecurityId, securityId, children, }) {
|
|
129
|
+
const [open, setOpen] = useState(false);
|
|
130
|
+
const form = useFormContext();
|
|
131
|
+
const result = (_jsxs(CollapsiblePanel, { title: "Authorization", children: [_jsxs(Select, { value: securityId.toString(), onValueChange: (v) => setSecurityId(Number(v)), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: securities.map((security, i) => (_jsx(SelectItem, { value: i.toString(), children: security.map((item) => item.id).join(' & ') }, i))) })] }), children] }));
|
|
132
|
+
for (let i = 0; i < securities.length; i++) {
|
|
133
|
+
const security = securities[i];
|
|
134
|
+
for (const item of security) {
|
|
135
|
+
if (item.type === 'oauth2') {
|
|
136
|
+
return (_jsx(OauthDialog, { scheme: item, scopes: item.scopes, open: open, setOpen: (v) => {
|
|
137
|
+
setOpen(v);
|
|
138
|
+
if (v) {
|
|
139
|
+
setSecurityId(i);
|
|
140
|
+
}
|
|
141
|
+
}, setToken: (token) => form.setValue('header.Authorization', token), children: result }));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
115
146
|
}
|
|
116
147
|
const paramNames = ['Headers', 'Cookies', 'Query', 'Path'];
|
|
117
148
|
const paramTypes = ['header', 'cookie', 'query', 'path'];
|
|
@@ -142,7 +173,7 @@ function BodyInput({ field: _field }) {
|
|
|
142
173
|
color: 'ghost',
|
|
143
174
|
size: 'sm',
|
|
144
175
|
className: 'p-2',
|
|
145
|
-
})), onClick: () => setIsJson(false), type: "button", children: "Close JSON Editor" }) })) : (_jsx(FieldSet, { field: field, fieldName: "body", name: _jsx("button", { className: cn(buttonVariants({
|
|
176
|
+
})), onClick: () => setIsJson(false), type: "button", children: "Close JSON Editor" }) })) : (_jsx(FieldSet, { field: field, fieldName: "body", collapsible: false, name: _jsx("button", { className: cn(buttonVariants({
|
|
146
177
|
color: 'secondary',
|
|
147
178
|
size: 'sm',
|
|
148
179
|
className: 'p-2',
|
|
@@ -153,15 +184,16 @@ function BodyInput({ field: _field }) {
|
|
|
153
184
|
*
|
|
154
185
|
* @returns a new manipulated object
|
|
155
186
|
*/
|
|
156
|
-
function manipulateValues(values, fieldName, update) {
|
|
157
|
-
const root = { ...values };
|
|
187
|
+
function manipulateValues(values, fieldName, update, clone = false) {
|
|
188
|
+
const root = clone ? { ...values } : values;
|
|
158
189
|
let current = root;
|
|
159
190
|
const segments = fieldName.split('.');
|
|
160
191
|
for (let i = 0; i < segments.length; i++) {
|
|
161
192
|
const segment = segments[i];
|
|
162
193
|
if (i !== segments.length - 1) {
|
|
163
194
|
let v = current[segment];
|
|
164
|
-
|
|
195
|
+
if (clone)
|
|
196
|
+
v = { ...v };
|
|
165
197
|
current[segment] = v;
|
|
166
198
|
current = v;
|
|
167
199
|
continue;
|
|
@@ -197,10 +229,8 @@ function useAuthInputs(securities) {
|
|
|
197
229
|
}
|
|
198
230
|
return out;
|
|
199
231
|
},
|
|
200
|
-
children: (_jsx(
|
|
232
|
+
children: (_jsx(ObjectInput, { field: {
|
|
201
233
|
type: 'object',
|
|
202
|
-
required: ['username', 'password'],
|
|
203
|
-
description: security.description,
|
|
204
234
|
properties: {
|
|
205
235
|
username: {
|
|
206
236
|
type: 'string',
|
|
@@ -212,16 +242,29 @@ function useAuthInputs(securities) {
|
|
|
212
242
|
}, fieldName: fieldName })),
|
|
213
243
|
});
|
|
214
244
|
}
|
|
215
|
-
else if (security.type === '
|
|
245
|
+
else if (security.type === 'oauth2') {
|
|
216
246
|
const fieldName = 'header.Authorization';
|
|
217
247
|
result.push({
|
|
218
248
|
fieldName: fieldName,
|
|
219
249
|
original: security,
|
|
220
250
|
defaultValue: 'Bearer ',
|
|
221
|
-
children: (_jsxs(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
251
|
+
children: (_jsxs("fieldset", { className: "flex flex-col gap-2", children: [_jsx("label", { htmlFor: fieldName, className: cn(labelVariants()), children: "Access Token" }), _jsxs("div", { className: "flex gap-2", children: [_jsx(FieldInput, { fieldName: fieldName, isRequired: true, field: {
|
|
252
|
+
type: 'string',
|
|
253
|
+
}, className: "flex-1" }), _jsx(OauthDialogTrigger, { type: "button", className: cn(buttonVariants({
|
|
254
|
+
size: 'sm',
|
|
255
|
+
color: 'secondary',
|
|
256
|
+
})), children: "Authorize" })] })] })),
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else if (security.type === 'http') {
|
|
260
|
+
const fieldName = 'header.Authorization';
|
|
261
|
+
result.push({
|
|
262
|
+
fieldName: fieldName,
|
|
263
|
+
original: security,
|
|
264
|
+
defaultValue: 'Bearer ',
|
|
265
|
+
children: (_jsx(FieldSet, { name: "Authorization (header)", fieldName: fieldName, isRequired: true, field: {
|
|
266
|
+
type: 'string',
|
|
267
|
+
} })),
|
|
225
268
|
});
|
|
226
269
|
}
|
|
227
270
|
else if (security.type === 'apiKey') {
|
|
@@ -230,13 +273,22 @@ function useAuthInputs(securities) {
|
|
|
230
273
|
fieldName,
|
|
231
274
|
defaultValue: '',
|
|
232
275
|
original: security,
|
|
233
|
-
children: (_jsx(FieldSet, { fieldName: fieldName, name: security.name, field: {
|
|
276
|
+
children: (_jsx(FieldSet, { fieldName: fieldName, name: `${security.name} (${security.in})`, isRequired: true, field: {
|
|
234
277
|
type: 'string',
|
|
235
|
-
description: security.description ?? `The API key in ${security.in}.`,
|
|
236
278
|
} })),
|
|
237
279
|
});
|
|
238
280
|
}
|
|
239
|
-
|
|
281
|
+
else {
|
|
282
|
+
const fieldName = 'header.Authorization';
|
|
283
|
+
result.push({
|
|
284
|
+
fieldName,
|
|
285
|
+
defaultValue: '',
|
|
286
|
+
original: security,
|
|
287
|
+
children: (_jsxs(_Fragment, { children: [_jsx(FieldSet, { name: "Authorization (header)", isRequired: true, fieldName: fieldName, field: {
|
|
288
|
+
type: 'string',
|
|
289
|
+
} }), _jsx("p", { className: "text-fd-muted-foreground text-xs", children: "OpenID Connect is not supported at the moment, you can still set an access token here." })] })),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
240
292
|
}
|
|
241
293
|
return result;
|
|
242
294
|
}, [securities]);
|
|
@@ -244,7 +296,7 @@ function useAuthInputs(securities) {
|
|
|
244
296
|
for (const item of inputs) {
|
|
245
297
|
if (!item.mapOutput)
|
|
246
298
|
continue;
|
|
247
|
-
values = manipulateValues(values, item.fieldName, item.mapOutput);
|
|
299
|
+
values = manipulateValues(values, item.fieldName, item.mapOutput, true);
|
|
248
300
|
}
|
|
249
301
|
return values;
|
|
250
302
|
});
|
|
@@ -255,22 +307,6 @@ function renderCustomField(fieldName, info, field, key) {
|
|
|
255
307
|
// @ts-expect-error we use string here
|
|
256
308
|
render: (props) => field.render({ ...props, info }), name: fieldName }, key));
|
|
257
309
|
}
|
|
258
|
-
const OauthDialog = lazy(() => import('./auth/oauth-dialog.js').then((mod) => ({
|
|
259
|
-
default: mod.OauthDialog,
|
|
260
|
-
})));
|
|
261
|
-
const OauthDialogTrigger = lazy(() => import('./auth/oauth-dialog.js').then((mod) => ({
|
|
262
|
-
default: mod.OauthDialogTrigger,
|
|
263
|
-
})));
|
|
264
|
-
function OAuth({ authorization }) {
|
|
265
|
-
const form = useFormContext();
|
|
266
|
-
if (authorization.type !== 'oauth2')
|
|
267
|
-
return;
|
|
268
|
-
// only the first one, so it looks simpler :)
|
|
269
|
-
const flow = Object.keys(authorization.flows)[0];
|
|
270
|
-
return (_jsx(OauthDialog, { flow: flow, scheme: authorization, setToken: (token) => form.setValue('authorization', `Bearer ${token}`), children: _jsx(OauthDialogTrigger, { type: "button", className: cn(buttonVariants({
|
|
271
|
-
color: 'secondary',
|
|
272
|
-
})), children: "Auth Settings" }) }));
|
|
273
|
-
}
|
|
274
310
|
function Route({ route, ...props }) {
|
|
275
311
|
const segments = route.split('/').filter((part) => part.length > 0);
|
|
276
312
|
return (_jsx("div", { ...props, className: cn('flex flex-row items-center gap-0.5 overflow-auto text-nowrap', props.className), children: segments.map((part, index) => (_jsxs(Fragment, { children: [_jsx("span", { className: "text-fd-muted-foreground", children: "/" }), part.startsWith('{') && part.endsWith('}') ? (_jsx("code", { className: "bg-fd-primary/10 text-fd-primary", children: part })) : (_jsx("code", { className: "text-fd-foreground", children: part }))] }, index))) }));
|
|
@@ -278,7 +314,7 @@ function Route({ route, ...props }) {
|
|
|
278
314
|
function DefaultResultDisplay({ data }) {
|
|
279
315
|
const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);
|
|
280
316
|
const { shikiOptions } = useApiContext();
|
|
281
|
-
return (_jsxs("div", { className: "flex flex-col gap-3
|
|
317
|
+
return (_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("div", { className: "inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground", children: [_jsx(statusInfo.icon, { className: cn('size-4', statusInfo.color) }), statusInfo.description] }), _jsx("p", { className: "text-sm text-fd-muted-foreground", children: data.status }), data.data ? (_jsx(DynamicCodeBlock, { lang: typeof data.data === 'string' && data.data.length > 50000
|
|
282
318
|
? 'text'
|
|
283
319
|
: data.type, code: typeof data.data === 'string'
|
|
284
320
|
? data.data
|
|
@@ -9,7 +9,12 @@ export interface FetchResult {
|
|
|
9
9
|
data: unknown;
|
|
10
10
|
}
|
|
11
11
|
export interface Fetcher {
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* This method will not apply the path & search parameters from `options` to given `url`.
|
|
14
|
+
*
|
|
15
|
+
* @param url - The full URL of request.
|
|
16
|
+
*/
|
|
17
|
+
fetch: (url: string, options: FetchOptions) => Promise<FetchResult>;
|
|
13
18
|
}
|
|
14
19
|
export declare function createBrowserFetcher(adapters: Record<string, MediaAdapter>): Fetcher;
|
|
15
20
|
//# sourceMappingURL=fetcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/playground/fetcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/playground/fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB;;;;OAIG;IACH,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACrE;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACrC,OAAO,CAgGT"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getPathnameFromInput } from '../utils/get-pathname-from-input.js';
|
|
2
1
|
export function createBrowserFetcher(adapters) {
|
|
3
2
|
return {
|
|
4
|
-
async fetch(
|
|
3
|
+
async fetch(url, options) {
|
|
5
4
|
const headers = new Headers();
|
|
6
5
|
if (options.bodyMediaType)
|
|
7
6
|
headers.append('Content-Type', options.bodyMediaType);
|
|
@@ -11,9 +10,8 @@ export function createBrowserFetcher(adapters) {
|
|
|
11
10
|
headers.append(key, paramValue.toString());
|
|
12
11
|
}
|
|
13
12
|
const proxyUrl = options.proxyUrl
|
|
14
|
-
? new URL(options.proxyUrl,
|
|
13
|
+
? new URL(options.proxyUrl, document.baseURI)
|
|
15
14
|
: null;
|
|
16
|
-
let url = getPathnameFromInput(route, options.path, options.query);
|
|
17
15
|
if (proxyUrl) {
|
|
18
16
|
proxyUrl.searchParams.append('url', url);
|
|
19
17
|
url = proxyUrl.toString();
|
package/dist/playground/index.js
CHANGED
|
@@ -47,22 +47,32 @@ function writeReferences(schema, ctx, stack = new WeakMap()) {
|
|
|
47
47
|
}
|
|
48
48
|
const output = { ...schema };
|
|
49
49
|
stack.set(schema, output);
|
|
50
|
-
for (const
|
|
50
|
+
for (const _n in output) {
|
|
51
|
+
const name = _n;
|
|
51
52
|
if (!output[name])
|
|
52
53
|
continue;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
switch (name) {
|
|
55
|
+
case 'oneOf':
|
|
56
|
+
case 'allOf':
|
|
57
|
+
case 'anyOf':
|
|
58
|
+
output[name] = output[name].map((item) => writeReferences(item, ctx, stack));
|
|
59
|
+
continue;
|
|
60
|
+
case 'items':
|
|
61
|
+
case 'additionalProperties':
|
|
62
|
+
case 'not':
|
|
63
|
+
output[name] = writeReferences(output[name], ctx, stack);
|
|
64
|
+
continue;
|
|
65
|
+
case 'properties':
|
|
66
|
+
case 'patternProperties':
|
|
67
|
+
output[name] = { ...output[name] };
|
|
68
|
+
for (const key in output[name]) {
|
|
69
|
+
output[name][key] = writeReferences(output[name][key], ctx, stack);
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
default:
|
|
73
|
+
if (typeof output[name] === 'object' && !Array.isArray(output[name])) {
|
|
74
|
+
output[name] = { ...output[name] };
|
|
75
|
+
}
|
|
66
76
|
}
|
|
67
77
|
}
|
|
68
78
|
return output;
|
|
@@ -84,7 +94,8 @@ function parseSecurities(method, { schema: { document } }) {
|
|
|
84
94
|
id: key,
|
|
85
95
|
});
|
|
86
96
|
}
|
|
87
|
-
|
|
97
|
+
if (list.length > 0)
|
|
98
|
+
result.push(list);
|
|
88
99
|
}
|
|
89
100
|
return result;
|
|
90
101
|
}
|