fumadocs-openapi 11.4.3 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/generated/shared.css +1 -1
- package/css/preset.css +0 -1
- package/dist/_virtual/_rolldown/runtime.js +10 -1
- package/dist/generate-file.d.ts +2 -2
- package/dist/generate-file.js +1 -1
- package/dist/i18n.d.ts +6 -8
- package/dist/i18n.js +2 -17
- package/dist/index.browser.d.ts +13 -0
- package/dist/index.browser.js +11 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/operation.d.ts +133 -0
- package/dist/operation.js +296 -0
- package/dist/packages/shared-api/dist/.translations/index.d.ts +29 -0
- package/dist/packages/shared-api/dist/.translations/keys.js +28 -0
- package/dist/packages/shared-api/dist/auto-anchor/client.js +20 -0
- package/dist/packages/shared-api/dist/auto-anchor/index.js +17 -0
- package/dist/packages/shared-api/dist/codegen.d.ts +42 -0
- package/dist/packages/shared-api/dist/codegen.js +35 -0
- package/dist/packages/shared-api/dist/components/accordion.js +71 -0
- package/dist/packages/shared-api/dist/components/badge.js +21 -0
- package/dist/packages/shared-api/dist/components/collapsible.d.ts +7 -0
- package/dist/packages/shared-api/dist/components/collapsible.js +16 -0
- package/dist/packages/shared-api/dist/components/defaults.d.ts +20 -0
- package/dist/packages/shared-api/dist/components/defaults.js +70 -0
- package/dist/packages/shared-api/dist/components/dialog.js +55 -0
- package/dist/packages/shared-api/dist/components/input.js +14 -0
- package/dist/packages/shared-api/dist/components/label.js +11 -0
- package/dist/packages/shared-api/dist/components/playground/inputs.js +439 -0
- package/dist/packages/shared-api/dist/components/playground/schema.js +112 -0
- package/dist/packages/shared-api/dist/components/popover.js +23 -0
- package/dist/packages/shared-api/dist/components/schema/client.d.ts +12 -0
- package/dist/packages/shared-api/dist/components/schema/client.js +508 -0
- package/dist/packages/shared-api/dist/components/schema/index.d.ts +9 -0
- package/dist/packages/shared-api/dist/components/schema/index.js +28 -0
- package/dist/packages/shared-api/dist/components/select-tab.js +54 -0
- package/dist/packages/shared-api/dist/components/select.js +70 -0
- package/dist/packages/shared-api/dist/components/spinner.js +14 -0
- package/dist/packages/shared-api/dist/i18n.d.ts +3 -0
- package/dist/packages/shared-api/dist/i18n.js +7 -0
- package/dist/packages/shared-api/dist/utils/cn.js +2 -0
- package/dist/packages/shared-api/dist/utils/id-to-title.js +12 -0
- package/dist/packages/shared-api/dist/utils/is-plain-object.js +8 -0
- package/dist/packages/shared-api/dist/utils/merge-refs.js +11 -0
- package/dist/packages/shared-api/dist/utils/url.js +13 -0
- package/dist/{utils → packages/shared-api/dist/utils}/use-query.js +2 -1
- package/dist/packages/shared-api/dist/utils/use-server-store.js +56 -0
- package/dist/playground/auth.d.ts +37 -0
- package/dist/playground/auth.js +216 -21
- package/dist/playground/fetcher.d.ts +11 -1
- package/dist/playground/index.d.ts +3 -0
- package/dist/playground/index.js +3 -0
- package/dist/requests/generators/index.d.ts +4 -4
- package/dist/requests/generators/index.js +2 -2
- package/dist/requests/index.d.ts +4 -0
- package/dist/requests/index.js +3 -0
- package/dist/requests/media/adapter.d.ts +1 -0
- package/dist/requests/media/encode.d.ts +7 -2
- package/dist/requests/media/resolve-adapter.d.ts +20 -0
- package/dist/server/index.d.ts +4 -7
- package/dist/server/index.js +1 -7
- package/dist/types.d.ts +0 -14
- package/dist/ui/base.d.ts +3 -2
- package/dist/ui/base.js +15 -166
- package/dist/ui/components/codeblock.js +3 -10
- package/dist/ui/components/heading.js +10 -19
- package/dist/ui/components/markdown.js +4 -6
- package/dist/ui/components/method-label.js +2 -17
- package/dist/ui/components/schema.js +28 -0
- package/dist/ui/index.d.ts +7 -198
- package/dist/ui/index.js +1 -3
- package/dist/ui/operation/index.js +142 -229
- package/dist/ui/operation/request-tabs.js +15 -23
- package/dist/ui/operation/response-tabs.js +9 -53
- package/dist/ui/operation/usage-tabs.js +35 -93
- package/dist/{playground → ui/playground}/client.d.ts +10 -21
- package/dist/ui/playground/client.js +432 -0
- package/dist/{playground → ui/playground}/components/oauth-dialog.js +26 -91
- package/dist/{playground → ui/playground}/components/result-display.d.ts +2 -2
- package/dist/{playground → ui/playground}/components/result-display.js +7 -7
- package/dist/{playground → ui/playground}/components/server-select.js +12 -13
- package/dist/{playground → ui/playground}/status-info.js +2 -2
- package/dist/{scalar → ui/scalar}/client.js +7 -5
- package/dist/{scalar → ui/scalar}/index.d.ts +2 -2
- package/dist/{scalar → ui/scalar}/index.js +3 -7
- package/dist/utils/create-page.d.ts +216 -0
- package/dist/utils/create-page.js +221 -0
- package/dist/utils/document/dereference.d.ts +2 -2
- package/dist/utils/document/dereference.js +8 -3
- package/dist/utils/document/load.js +2 -2
- package/dist/utils/get-example-requests.js +11 -13
- package/dist/utils/pages/builder.d.ts +15 -2
- package/dist/utils/pages/builder.js +6 -6
- package/dist/utils/pages/preset-auto.d.ts +1 -1
- package/dist/utils/pages/preset-auto.js +3 -3
- package/dist/utils/pages/to-static-data.js +4 -4
- package/dist/utils/pages/to-text.d.ts +1 -1
- package/dist/utils/pages/to-text.js +3 -5
- package/dist/utils/schema.js +5 -5
- package/dist/utils/use-server.d.ts +24 -0
- package/dist/utils/use-server.js +57 -0
- package/package.json +28 -20
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js +0 -508
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js +0 -152
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js +0 -61
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +0 -25
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +0 -15
- package/dist/playground/client.js +0 -574
- package/dist/ui/contexts/api.d.ts +0 -17
- package/dist/ui/contexts/api.js +0 -84
- package/dist/ui/create-client.d.ts +0 -9
- package/dist/ui/create-client.js +0 -7
- package/dist/ui/operation/context.d.ts +0 -15
- package/dist/ui/operation/context.js +0 -48
- package/dist/ui/operation/request-tabs.d.ts +0 -12
- package/dist/ui/operation/response-tabs.d.ts +0 -30
- package/dist/utils/get-example-requests.d.ts +0 -11
- package/dist/utils/schema.d.ts +0 -3
- package/dist/utils/storage-key.js +0 -15
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region ../shared-api/dist/utils/id-to-title.js
|
|
2
|
+
function idToTitle(id) {
|
|
3
|
+
let result = [];
|
|
4
|
+
for (const c of id) if (result.length === 0) result.push(c.toLocaleUpperCase());
|
|
5
|
+
else if (c === ".") result = [];
|
|
6
|
+
else if (/^[A-Z]$/.test(c) && result.at(-1) !== " ") result.push(" ", c);
|
|
7
|
+
else if (c === "-") result.push(" ");
|
|
8
|
+
else result.push(c);
|
|
9
|
+
return result.join("");
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { idToTitle };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region ../shared-api/dist/utils/is-plain-object.js
|
|
2
|
+
function isPlainObject(value) {
|
|
3
|
+
if (typeof value !== "object" || value === null) return false;
|
|
4
|
+
const prototype = Object.getPrototypeOf(value);
|
|
5
|
+
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { isPlainObject };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region ../shared-api/dist/utils/merge-refs.js
|
|
2
|
+
function mergeRefs(...refs) {
|
|
3
|
+
return (value) => {
|
|
4
|
+
refs.forEach((ref) => {
|
|
5
|
+
if (typeof ref === "function") ref(value);
|
|
6
|
+
else if (ref != null) ref.current = value;
|
|
7
|
+
});
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { mergeRefs };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region ../shared-api/dist/utils/url.js
|
|
2
|
+
function joinURL(base, pathname) {
|
|
3
|
+
if (pathname.startsWith("/")) pathname = pathname.slice(1);
|
|
4
|
+
if (base.endsWith("/")) base = base.slice(0, -1);
|
|
5
|
+
if (pathname.length > 0) return base + "/" + pathname;
|
|
6
|
+
else return base;
|
|
7
|
+
}
|
|
8
|
+
function resolveServerUrl(template, variables) {
|
|
9
|
+
for (const [key, value] of Object.entries(variables)) template = template.replaceAll(`{${key}}`, value);
|
|
10
|
+
return template;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { joinURL, resolveServerUrl };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { isPlainObject } from "./is-plain-object.js";
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
//#region ../shared-api/dist/utils/use-server-store.js
|
|
5
|
+
/**
|
|
6
|
+
* The selected server of an API page, persisted in `localStorage`.
|
|
7
|
+
*/
|
|
8
|
+
function useServerStore({ storageKey, keyOf, resolve, defaultKey }) {
|
|
9
|
+
const [server, setServer] = useState(() => defaultKey !== void 0 ? resolve(defaultKey) : null);
|
|
10
|
+
const restored = useRef(void 0);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (restored.current === storageKey) return;
|
|
13
|
+
restored.current = storageKey;
|
|
14
|
+
const cached = localStorage.getItem(storageKey);
|
|
15
|
+
if (!cached) return;
|
|
16
|
+
try {
|
|
17
|
+
const value = JSON.parse(cached);
|
|
18
|
+
if (!isPlainObject(value) || !isPlainObject(value.variables)) return;
|
|
19
|
+
const server = resolve(keyOf(value));
|
|
20
|
+
if (server) setServer({
|
|
21
|
+
...server,
|
|
22
|
+
variables: value.variables
|
|
23
|
+
});
|
|
24
|
+
} catch {}
|
|
25
|
+
}, [
|
|
26
|
+
storageKey,
|
|
27
|
+
keyOf,
|
|
28
|
+
resolve
|
|
29
|
+
]);
|
|
30
|
+
return useMemo(() => ({
|
|
31
|
+
server,
|
|
32
|
+
setServer(key) {
|
|
33
|
+
const next = resolve(key);
|
|
34
|
+
if (!next) return;
|
|
35
|
+
localStorage.setItem(storageKey, JSON.stringify(next));
|
|
36
|
+
setServer(next);
|
|
37
|
+
},
|
|
38
|
+
setServerVariables(variables) {
|
|
39
|
+
setServer((prev) => {
|
|
40
|
+
if (!prev) return null;
|
|
41
|
+
const next = {
|
|
42
|
+
...prev,
|
|
43
|
+
variables
|
|
44
|
+
};
|
|
45
|
+
localStorage.setItem(storageKey, JSON.stringify(next));
|
|
46
|
+
return next;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}), [
|
|
50
|
+
server,
|
|
51
|
+
resolve,
|
|
52
|
+
storageKey
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { useServerStore };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SecuritySchemeObject } from "../types.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { FieldKey } from "@fumari/stf";
|
|
4
|
+
//#region src/playground/auth.d.ts
|
|
5
|
+
/** scheme name -> token info */
|
|
6
|
+
type TokenStore = Record<string, TokenInfo | undefined>;
|
|
7
|
+
type TokenInfo = {
|
|
8
|
+
type: 'authorization_code';
|
|
9
|
+
redirect_uri: string;
|
|
10
|
+
client_id: string;
|
|
11
|
+
client_secret: string;
|
|
12
|
+
token: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'implicit';
|
|
15
|
+
client_id: string;
|
|
16
|
+
token: string;
|
|
17
|
+
};
|
|
18
|
+
interface AuthContextType {
|
|
19
|
+
store: TokenStore;
|
|
20
|
+
updatedSchemeId: string | null;
|
|
21
|
+
isLoading: boolean;
|
|
22
|
+
error?: unknown;
|
|
23
|
+
}
|
|
24
|
+
export declare function usePlaygroundAuth(): AuthContextType;
|
|
25
|
+
export interface AuthField {
|
|
26
|
+
schemeId: string;
|
|
27
|
+
scheme: SecuritySchemeObject;
|
|
28
|
+
scopes: string[];
|
|
29
|
+
/** the form field holding its value */
|
|
30
|
+
fieldName: FieldKey;
|
|
31
|
+
/** `localStorage` key of its persisted value */
|
|
32
|
+
storageKey: string;
|
|
33
|
+
defaultValue: unknown;
|
|
34
|
+
/** encode the value into request data, like the header of Basic auth */
|
|
35
|
+
mapOutput?: (value: unknown) => unknown;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
package/dist/playground/auth.js
CHANGED
|
@@ -1,17 +1,86 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { createContext, use, useEffect, useMemo, useState } from "react";
|
|
2
|
+
import { useQuery } from "../packages/shared-api/dist/utils/use-query.js";
|
|
3
|
+
import { useOpenAPI } from "../utils/create-page.js";
|
|
4
|
+
import { createContext, use, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { useListener } from "@fumari/stf";
|
|
7
|
+
import { arrayStartsWith, objectGet, objectSet } from "@fumari/stf/lib/utils";
|
|
8
|
+
import { useOnChange } from "fumadocs-core/utils/use-on-change";
|
|
6
9
|
//#region src/playground/auth.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Run an OAuth flow and resolve its token.
|
|
12
|
+
*
|
|
13
|
+
* `implicit` and `authorizationCode` leave the page instead: the token is picked up on return,
|
|
14
|
+
* in `usePlaygroundAuth().store`.
|
|
15
|
+
*/
|
|
16
|
+
async function requestOAuthToken(scheme, type, { schemeId, scopes, clientId, clientSecret, username, password, clientAuth }) {
|
|
17
|
+
const flows = scheme.flows ?? {};
|
|
18
|
+
const scope = scopes.join("+");
|
|
19
|
+
const redirect_uri = window.location.href;
|
|
20
|
+
if (type === "implicit" || type === "authorizationCode") {
|
|
21
|
+
const flow = flows[type];
|
|
22
|
+
if (!flow) return;
|
|
23
|
+
const params = new URLSearchParams({
|
|
24
|
+
response_type: type === "implicit" ? "token" : "code",
|
|
25
|
+
client_id: clientId,
|
|
26
|
+
redirect_uri,
|
|
27
|
+
scope,
|
|
28
|
+
state: JSON.stringify(type === "implicit" ? {
|
|
29
|
+
scheme: schemeId,
|
|
30
|
+
client_id: clientId,
|
|
31
|
+
redirect_uri
|
|
32
|
+
} : {
|
|
33
|
+
scheme: schemeId,
|
|
34
|
+
client_id: clientId,
|
|
35
|
+
client_secret: clientSecret,
|
|
36
|
+
redirect_uri
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
window.location.replace(`${flow.authorizationUrl}?${params}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (type !== "password" && type !== "clientCredentials") return;
|
|
43
|
+
const flow = flows[type];
|
|
44
|
+
if (!flow) return;
|
|
45
|
+
const headers = {};
|
|
46
|
+
const body = new URLSearchParams({ scope });
|
|
47
|
+
if (type === "password") {
|
|
48
|
+
body.set("grant_type", "password");
|
|
49
|
+
body.set("username", username);
|
|
50
|
+
body.set("password", password);
|
|
51
|
+
if (clientAuth === "header") headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;
|
|
52
|
+
else {
|
|
53
|
+
if (clientId) body.set("client_id", clientId);
|
|
54
|
+
if (clientSecret) body.set("client_secret", clientSecret);
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
body.set("grant_type", "client_credentials");
|
|
58
|
+
body.set("client_id", clientId);
|
|
59
|
+
body.set("client_secret", clientSecret);
|
|
60
|
+
}
|
|
61
|
+
return fetchToken(flow.tokenUrl, body, headers);
|
|
62
|
+
}
|
|
63
|
+
async function fetchToken(tokenUrl, body, headers = {}) {
|
|
64
|
+
const res = await fetch(tokenUrl, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
...headers,
|
|
68
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
69
|
+
},
|
|
70
|
+
body
|
|
71
|
+
});
|
|
72
|
+
if (!res.ok) throw new Error(await res.text());
|
|
73
|
+
const { access_token, token_type = "Bearer" } = await res.json();
|
|
74
|
+
return `${token_type} ${access_token}`;
|
|
75
|
+
}
|
|
7
76
|
const AuthContext = createContext(null);
|
|
8
|
-
function
|
|
77
|
+
function usePlaygroundAuth() {
|
|
9
78
|
const ctx = use(AuthContext);
|
|
10
|
-
if (!ctx) throw new Error("must
|
|
79
|
+
if (!ctx) throw new Error("Component must be used under <OpenAPIProvider />");
|
|
11
80
|
return ctx;
|
|
12
81
|
}
|
|
13
82
|
function AuthProvider({ children }) {
|
|
14
|
-
const { dereferenced, resolve } =
|
|
83
|
+
const { dereferenced, resolve } = useOpenAPI().doc;
|
|
15
84
|
const schemes = dereferenced.components?.securitySchemes;
|
|
16
85
|
const [store, setStore] = useState({});
|
|
17
86
|
const authCodeQuery = useQuery(async (code, state) => {
|
|
@@ -19,23 +88,16 @@ function AuthProvider({ children }) {
|
|
|
19
88
|
if (!scheme || scheme.type !== "oauth2") return;
|
|
20
89
|
const value = scheme.flows?.authorizationCode;
|
|
21
90
|
if (!value) return;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
91
|
+
const info = {
|
|
92
|
+
type: "authorization_code",
|
|
93
|
+
...state,
|
|
94
|
+
token: await fetchToken(value.tokenUrl, new URLSearchParams({
|
|
26
95
|
grant_type: "authorization_code",
|
|
27
96
|
code,
|
|
28
97
|
redirect_uri: state.redirect_uri,
|
|
29
98
|
client_id: state.client_id,
|
|
30
99
|
client_secret: state.client_secret
|
|
31
|
-
})
|
|
32
|
-
});
|
|
33
|
-
if (!res.ok) throw new Error(await res.text());
|
|
34
|
-
const { access_token, token_type = "Bearer" } = await res.json();
|
|
35
|
-
const info = {
|
|
36
|
-
type: "authorization_code",
|
|
37
|
-
...state,
|
|
38
|
-
token: `${token_type} ${access_token}`
|
|
100
|
+
}))
|
|
39
101
|
};
|
|
40
102
|
setStore((s) => ({
|
|
41
103
|
...s,
|
|
@@ -72,8 +134,10 @@ function AuthProvider({ children }) {
|
|
|
72
134
|
}));
|
|
73
135
|
window.history.replaceState(null, "", window.location.pathname);
|
|
74
136
|
}
|
|
75
|
-
|
|
76
|
-
|
|
137
|
+
try {
|
|
138
|
+
if (window.location.search.length > 0) onQuery();
|
|
139
|
+
if (window.location.hash.length > 1) onHash();
|
|
140
|
+
} catch {}
|
|
77
141
|
}, []);
|
|
78
142
|
return /* @__PURE__ */ jsx(AuthContext, {
|
|
79
143
|
value: useMemo(() => ({
|
|
@@ -89,5 +153,136 @@ function AuthProvider({ children }) {
|
|
|
89
153
|
children
|
|
90
154
|
});
|
|
91
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* The auth fields of an API playground: the values it persists, and the request data they encode into.
|
|
158
|
+
*/
|
|
159
|
+
function useAuthFields(engine, { operation, transform } = {}) {
|
|
160
|
+
const auth = usePlaygroundAuth();
|
|
161
|
+
const { storageKeyPrefix, doc } = useOpenAPI();
|
|
162
|
+
const { dereferenced, resolve } = doc;
|
|
163
|
+
const schemes = dereferenced.components?.securitySchemes;
|
|
164
|
+
const requirements = useMemo(() => {
|
|
165
|
+
const out = [];
|
|
166
|
+
if (!schemes) return out;
|
|
167
|
+
for (const map of operation?.security ?? dereferenced.security ?? []) {
|
|
168
|
+
const list = [];
|
|
169
|
+
for (const [id, scopes] of Object.entries(map)) {
|
|
170
|
+
const scheme = resolve(schemes[id]);
|
|
171
|
+
if (scheme) list.push({
|
|
172
|
+
id,
|
|
173
|
+
scopes,
|
|
174
|
+
scheme
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (list.length > 0) out.push(list);
|
|
178
|
+
}
|
|
179
|
+
return out;
|
|
180
|
+
}, [
|
|
181
|
+
dereferenced.security,
|
|
182
|
+
operation?.security,
|
|
183
|
+
resolve,
|
|
184
|
+
schemes
|
|
185
|
+
]);
|
|
186
|
+
const [selected, select] = useState(() => {
|
|
187
|
+
if (requirements.length === 0) return -1;
|
|
188
|
+
const idx = requirements.findIndex((req) => req.every((item) => !item.scheme.deprecated));
|
|
189
|
+
return idx !== -1 ? idx : 0;
|
|
190
|
+
});
|
|
191
|
+
const requirement = selected === -1 ? null : requirements[selected];
|
|
192
|
+
const fields = useMemo(() => {
|
|
193
|
+
if (!requirement) return [];
|
|
194
|
+
const out = requirement.map(({ id, scheme, scopes }) => {
|
|
195
|
+
const shared = {
|
|
196
|
+
schemeId: id,
|
|
197
|
+
scheme,
|
|
198
|
+
scopes,
|
|
199
|
+
storageKey: `${storageKeyPrefix}auth-${id}`
|
|
200
|
+
};
|
|
201
|
+
if (scheme.type === "http" && scheme.scheme === "basic") return {
|
|
202
|
+
...shared,
|
|
203
|
+
fieldName: ["header", "Authorization"],
|
|
204
|
+
defaultValue: {
|
|
205
|
+
username: "",
|
|
206
|
+
password: ""
|
|
207
|
+
},
|
|
208
|
+
mapOutput(value) {
|
|
209
|
+
if (!value || typeof value !== "object") return value;
|
|
210
|
+
const { username = "", password = "" } = value;
|
|
211
|
+
return `Basic ${btoa(`${username}:${password}`)}`;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
if (scheme.type === "apiKey") return {
|
|
215
|
+
...shared,
|
|
216
|
+
fieldName: [scheme.in, scheme.name],
|
|
217
|
+
defaultValue: ""
|
|
218
|
+
};
|
|
219
|
+
return {
|
|
220
|
+
...shared,
|
|
221
|
+
fieldName: ["header", "Authorization"],
|
|
222
|
+
defaultValue: scheme.type === "http" || scheme.type === "oauth2" ? "Bearer " : ""
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
return transform ? transform(out) : out;
|
|
226
|
+
}, [
|
|
227
|
+
requirement,
|
|
228
|
+
storageKeyPrefix,
|
|
229
|
+
transform
|
|
230
|
+
]);
|
|
231
|
+
useListener({
|
|
232
|
+
stf: engine,
|
|
233
|
+
onUpdate(key) {
|
|
234
|
+
for (const field of fields) {
|
|
235
|
+
if (!arrayStartsWith(field.fieldName, key)) continue;
|
|
236
|
+
const value = engine.get(field.fieldName);
|
|
237
|
+
if (value != null) localStorage.setItem(field.storageKey, JSON.stringify(value));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
useOnChange(auth.updatedSchemeId, () => {
|
|
242
|
+
const { updatedSchemeId } = auth;
|
|
243
|
+
if (!updatedSchemeId) return;
|
|
244
|
+
const { token } = auth.store[updatedSchemeId];
|
|
245
|
+
const field = fields.find((field) => field.schemeId === updatedSchemeId);
|
|
246
|
+
if (field) {
|
|
247
|
+
engine.update(field.fieldName, token);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const idx = requirements.findIndex((req) => req.some((item) => item.id === updatedSchemeId));
|
|
251
|
+
if (idx !== -1) {
|
|
252
|
+
localStorage.setItem(`${storageKeyPrefix}auth-${updatedSchemeId}`, JSON.stringify(token));
|
|
253
|
+
select(idx);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return {
|
|
257
|
+
requirements,
|
|
258
|
+
selected,
|
|
259
|
+
select,
|
|
260
|
+
fields,
|
|
261
|
+
mapValues: useCallback((values) => {
|
|
262
|
+
const cloned = structuredClone(values);
|
|
263
|
+
for (const field of fields) {
|
|
264
|
+
if (!field.mapOutput) continue;
|
|
265
|
+
objectSet(cloned, field.fieldName, field.mapOutput(objectGet(cloned, field.fieldName)));
|
|
266
|
+
}
|
|
267
|
+
return cloned;
|
|
268
|
+
}, [fields]),
|
|
269
|
+
init: useCallback(() => {
|
|
270
|
+
for (const field of fields) {
|
|
271
|
+
const stored = localStorage.getItem(field.storageKey);
|
|
272
|
+
if (stored) {
|
|
273
|
+
const parsed = JSON.parse(stored);
|
|
274
|
+
if (typeof parsed === typeof field.defaultValue) {
|
|
275
|
+
engine.init(field.fieldName, parsed);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
engine.init(field.fieldName, field.defaultValue);
|
|
280
|
+
}
|
|
281
|
+
return () => {
|
|
282
|
+
for (const field of fields) engine.delete(field.fieldName);
|
|
283
|
+
};
|
|
284
|
+
}, [engine, fields])
|
|
285
|
+
};
|
|
286
|
+
}
|
|
92
287
|
//#endregion
|
|
93
|
-
export { AuthProvider,
|
|
288
|
+
export { AuthProvider, requestOAuthToken, useAuthFields, usePlaygroundAuth };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import "../requests/
|
|
1
|
+
import { MediaAdapter } from "../requests/media/adapter.js";
|
|
2
|
+
import { RequestData } from "../requests/types.js";
|
|
2
3
|
import { Awaitable } from "../types.js";
|
|
3
4
|
//#region src/playground/fetcher.d.ts
|
|
4
5
|
export type FetchResult = FetchResponseResult | FetchErrorResult;
|
|
@@ -14,6 +15,14 @@ export interface FetchResponseResult {
|
|
|
14
15
|
headers: Headers;
|
|
15
16
|
body: ArrayBuffer;
|
|
16
17
|
}
|
|
18
|
+
export interface Fetcher {
|
|
19
|
+
/**
|
|
20
|
+
* This method will not apply the path & search parameters from `options` to given `url`.
|
|
21
|
+
*
|
|
22
|
+
* @param url - The full URL of request.
|
|
23
|
+
*/
|
|
24
|
+
fetch: (url: string, data: RequestData) => Promise<FetchResult>;
|
|
25
|
+
}
|
|
17
26
|
export interface BrowserFetcherOptions {
|
|
18
27
|
/**
|
|
19
28
|
* Request timeout in seconds (default: 10s)
|
|
@@ -31,4 +40,5 @@ export interface BrowserFetcherOptions {
|
|
|
31
40
|
*/
|
|
32
41
|
onRequestInit?: (requestInit: RequestInit) => Awaitable<RequestInit>;
|
|
33
42
|
}
|
|
43
|
+
export declare function createBrowserFetcher(adapters: Record<string, MediaAdapter>, { proxyUrl, proxyForwardCookie, requestTimeout, onRequestInit }?: BrowserFetcherOptions): Fetcher;
|
|
34
44
|
//#endregion
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BrowserFetcherOptions, FetchErrorResult, FetchResponseResult, FetchResult, Fetcher, createBrowserFetcher } from "./fetcher.js";
|
|
2
|
+
import { usePlaygroundAuth } from "./auth.js";
|
|
3
|
+
export { type BrowserFetcherOptions, type FetchErrorResult, type FetchResponseResult, type FetchResult, type Fetcher, createBrowserFetcher, usePlaygroundAuth };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { MediaAdapter } from "../media/adapter.js";
|
|
2
2
|
import { RequestData } from "../types.js";
|
|
3
|
-
import
|
|
3
|
+
import { CodeUsageGenerator as CodeUsageGenerator$1, CodeUsageGeneratorRegistry as CodeUsageGeneratorRegistry$1, InlineCodeUsageGenerator as InlineCodeUsageGenerator$1, codegen_d_exports } from "../../packages/shared-api/dist/codegen.js";
|
|
4
4
|
//#region src/requests/generators/index.d.ts
|
|
5
5
|
export declare function pathnameFromRequest(pathname: string, { path, query }: RequestData): string;
|
|
6
|
-
export type CodeUsageGeneratorRegistry =
|
|
6
|
+
export type CodeUsageGeneratorRegistry = CodeUsageGeneratorRegistry$1<RequestData & {
|
|
7
7
|
url: string;
|
|
8
8
|
}, {
|
|
9
9
|
mediaAdapters: Record<string, MediaAdapter>;
|
|
@@ -12,7 +12,7 @@ export type CodeUsageGeneratorRegistry = Shared.CodeUsageGeneratorRegistry<Reque
|
|
|
12
12
|
/**
|
|
13
13
|
* Generate code example for given programming language
|
|
14
14
|
*/
|
|
15
|
-
export type CodeUsageGenerator =
|
|
15
|
+
export type CodeUsageGenerator = CodeUsageGenerator$1<RequestData & {
|
|
16
16
|
url: string;
|
|
17
17
|
}, {
|
|
18
18
|
mediaAdapters: Record<string, MediaAdapter>;
|
|
@@ -21,7 +21,7 @@ export type CodeUsageGenerator = Shared.CodeUsageGenerator<RequestData & {
|
|
|
21
21
|
/**
|
|
22
22
|
* Generate code example for given programming language
|
|
23
23
|
*/
|
|
24
|
-
export type InlineCodeUsageGenerator<T = unknown> =
|
|
24
|
+
export type InlineCodeUsageGenerator<T = unknown> = InlineCodeUsageGenerator$1<RequestData & {
|
|
25
25
|
url: string;
|
|
26
26
|
}, {
|
|
27
27
|
mediaAdapters: Record<string, MediaAdapter>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createCodeUsageGeneratorRegistry as createCodeUsageGeneratorRegistry$1 } from "../../packages/shared-api/dist/codegen.js";
|
|
2
2
|
//#region src/requests/generators/index.ts
|
|
3
3
|
function pathnameFromRequest(pathname, { path, query }) {
|
|
4
4
|
for (const key in path) {
|
|
@@ -16,7 +16,7 @@ function pathnameFromRequest(pathname, { path, query }) {
|
|
|
16
16
|
return searchParams.size > 0 ? `${pathPart}?${searchParams}` : pathPart;
|
|
17
17
|
}
|
|
18
18
|
function createCodeUsageGeneratorRegistry(inherit) {
|
|
19
|
-
return
|
|
19
|
+
return createCodeUsageGeneratorRegistry$1(inherit);
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
22
|
export { createCodeUsageGeneratorRegistry, pathnameFromRequest };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { isMediaTypeSupported, resolveMediaAdapter } from "./media/resolve-adapter.js";
|
|
2
|
+
import { EncodedParameter, EncodedParameterMultiple, encodeRequestData } from "./media/encode.js";
|
|
3
|
+
import { RawRequestData, RequestData } from "./types.js";
|
|
4
|
+
export { type EncodedParameter, type EncodedParameterMultiple, type RawRequestData, type RequestData, encodeRequestData, isMediaTypeSupported, resolveMediaAdapter };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import "
|
|
1
|
+
import { MediaAdapter } from "./adapter.js";
|
|
2
|
+
import { RawRequestData, RequestData } from "../types.js";
|
|
3
|
+
import { ParameterObject } from "../../types.js";
|
|
3
4
|
//#region src/requests/media/encode.d.ts
|
|
4
5
|
export interface EncodedParameter {
|
|
5
6
|
readonly value: string;
|
|
@@ -7,4 +8,8 @@ export interface EncodedParameter {
|
|
|
7
8
|
export interface EncodedParameterMultiple {
|
|
8
9
|
readonly values: string[];
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* serialize parameters, see https://swagger.io/docs/specification/v3_0/serialization.
|
|
13
|
+
*/
|
|
14
|
+
export declare function encodeRequestData(from: RawRequestData, adapters: Record<string, MediaAdapter>, parameters?: ParameterObject[]): RequestData;
|
|
10
15
|
//#endregion
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MediaAdapter } from "./adapter.js";
|
|
2
|
+
//#region src/requests/media/resolve-adapter.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a media adapter for a given media type.
|
|
5
|
+
* Supports exact matches and pattern matching (e.g., +json suffix).
|
|
6
|
+
*
|
|
7
|
+
* @param mediaType - The media type to resolve (e.g., "application/json", "application/json-patch+json")
|
|
8
|
+
* @param adapters - Record of media adapters
|
|
9
|
+
* @returns The resolved adapter or undefined if not found
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveMediaAdapter(mediaType: string, adapters: Record<string, MediaAdapter>): MediaAdapter | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Check if a media type is supported by the given adapters.
|
|
14
|
+
*
|
|
15
|
+
* @param mediaType - The media type to check
|
|
16
|
+
* @param adapters - Record of media adapters
|
|
17
|
+
* @returns true if the media type is supported
|
|
18
|
+
*/
|
|
19
|
+
export declare function isMediaTypeSupported(mediaType: string, adapters: Record<string, MediaAdapter>): boolean;
|
|
20
|
+
//#endregion
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { CreateProxyOptions, Proxy, createProxy } from "./proxy.js";
|
|
2
|
-
import { OpenAPIPageProps_Preloaded, OpenAPIPageProps_Spec } from "../ui/index.js";
|
|
3
|
-
import { SchemaToPagesOptions } from "../utils/pages/preset-auto.js";
|
|
4
1
|
import { Awaitable, Document } from "../types.js";
|
|
2
|
+
import { OpenAPIPageProps_Preloaded, OpenAPIPageProps_Spec } from "../utils/pages/builder.js";
|
|
3
|
+
import { SchemaToPagesOptions } from "../utils/pages/preset-auto.js";
|
|
4
|
+
import { CreateProxyOptions, Proxy, createProxy } from "./proxy.js";
|
|
5
|
+
import "../ui/index.js";
|
|
5
6
|
import { DynamicSource, LoaderPlugin, MetaData, Page, PageData, Source } from "fumadocs-core/source";
|
|
6
7
|
import { StructuredData } from "fumadocs-core/mdx-plugins/remark-structure";
|
|
7
8
|
import { TOCItemType } from "fumadocs-core/toc";
|
|
@@ -63,10 +64,6 @@ export interface OpenAPIPageData extends PageData {
|
|
|
63
64
|
structuredData: StructuredData;
|
|
64
65
|
toc: TOCItemType[];
|
|
65
66
|
_openapi: InternalOpenAPIMeta;
|
|
66
|
-
/** @deprecated use `getOpenAPIPageProps()` instead */
|
|
67
|
-
getAPIPageProps: () => OpenAPIPageProps_Spec;
|
|
68
|
-
/** @deprecated use `getOpenAPIPageProps()` instead */
|
|
69
|
-
getClientAPIPageProps: () => OpenAPIPageProps_Spec;
|
|
70
67
|
}
|
|
71
68
|
export type OpenAPISourceOptions = SchemaToPagesOptions & {
|
|
72
69
|
baseDir?: string;
|
package/dist/server/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { createAutoPreset } from "../utils/pages/preset-auto.js";
|
|
|
4
4
|
import { MethodLabel } from "../ui/components/method-label.js";
|
|
5
5
|
import { createProxy } from "./proxy.js";
|
|
6
6
|
import { loadDocument } from "../utils/document/load.js";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import { PathUtils } from "fumadocs-core/source";
|
|
9
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import fs from "node:fs";
|
|
11
11
|
//#region src/server/index.tsx
|
|
12
12
|
function createOpenAPI(options = {}) {
|
|
@@ -52,12 +52,6 @@ function createOpenAPI(options = {}) {
|
|
|
52
52
|
path: `${baseDir}/${entry.path}`,
|
|
53
53
|
data: {
|
|
54
54
|
...entry.info,
|
|
55
|
-
getAPIPageProps() {
|
|
56
|
-
return this.getOpenAPIPageProps();
|
|
57
|
-
},
|
|
58
|
-
getClientAPIPageProps() {
|
|
59
|
-
return this.getOpenAPIPageProps();
|
|
60
|
-
},
|
|
61
55
|
getOpenAPIPageProps() {
|
|
62
56
|
return {
|
|
63
57
|
payload: {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { OpenAPIV3, OpenAPIV3_2 } from "./types/openapi.js";
|
|
2
|
-
import { DereferencedDocument } from "./utils/document/dereference.js";
|
|
3
2
|
import { InlineCodeUsageGenerator } from "./requests/generators/index.js";
|
|
4
|
-
import { CreateOpenAPIPageOptions } from "./ui/index.js";
|
|
5
|
-
import { OpenAPIOptions } from "./server/index.js";
|
|
6
|
-
import { FC, ReactNode } from "react";
|
|
7
|
-
import { SchemaUIOptions } from "@fumadocs/api-docs/components/schema";
|
|
8
3
|
//#region src/types.d.ts
|
|
9
4
|
export type Document = OpenAPIV3_2.Document;
|
|
10
5
|
export type OperationObject = OpenAPIV3_2.OperationObject & {
|
|
@@ -26,15 +21,6 @@ export type HttpMethods = OpenAPIV3_2.HttpMethods;
|
|
|
26
21
|
export type ExampleObject = OpenAPIV3_2.ExampleObject;
|
|
27
22
|
export type MediaTypeObject = OpenAPIV3_2.MediaTypeObject;
|
|
28
23
|
export type RequestBodyObject = OpenAPIV3_2.RequestBodyObject;
|
|
29
|
-
type RequireKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
30
|
-
export interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<RequireKeys<CreateOpenAPIPageOptions, 'generateTypeScriptDefinitions' | 'mediaAdapters' | 'codeUsages' | 'shikiOptions' | 'shiki'>, 'schemaUI'> {
|
|
31
|
-
/**
|
|
32
|
-
* dereferenced schema
|
|
33
|
-
*/
|
|
34
|
-
schema: DereferencedDocument;
|
|
35
|
-
_default_processMarkdown: (md: string) => ReactNode;
|
|
36
|
-
SchemaUI: FC<Omit<SchemaUIOptions, 'renderMarkdown' | 'renderCodeblock'>>;
|
|
37
|
-
}
|
|
38
24
|
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
39
25
|
export type Awaitable<T> = T | Promise<T>;
|
|
40
26
|
//#endregion
|