fumadocs-openapi 11.4.3 → 12.0.1
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 +85 -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 +2 -8
- 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 +29 -21
- 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,85 @@
|
|
|
1
|
+
import { OAuth2SecurityScheme, OperationObject, SecuritySchemeObject } from "../types.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { DataEngine, FieldKey } from "@fumari/stf";
|
|
4
|
+
//#region src/playground/auth.d.ts
|
|
5
|
+
export type OAuthFlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;
|
|
6
|
+
export interface OAuthFlowInput {
|
|
7
|
+
/** name of the security scheme */
|
|
8
|
+
schemeId: string;
|
|
9
|
+
scopes: string[];
|
|
10
|
+
clientId: string;
|
|
11
|
+
clientSecret: string;
|
|
12
|
+
username: string;
|
|
13
|
+
password: string;
|
|
14
|
+
/** where the password flow sends the client credentials */
|
|
15
|
+
clientAuth: 'body' | 'header';
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Run an OAuth flow and resolve its token.
|
|
19
|
+
*
|
|
20
|
+
* `implicit` and `authorizationCode` leave the page instead: the token is picked up on return,
|
|
21
|
+
* in `usePlaygroundAuth().store`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function requestOAuthToken(scheme: OAuth2SecurityScheme, type: OAuthFlowType, { schemeId, scopes, clientId, clientSecret, username, password, clientAuth }: OAuthFlowInput): Promise<string | undefined>;
|
|
24
|
+
/** scheme name -> token info */
|
|
25
|
+
type TokenStore = Record<string, TokenInfo | undefined>;
|
|
26
|
+
type TokenInfo = {
|
|
27
|
+
type: 'authorization_code';
|
|
28
|
+
redirect_uri: string;
|
|
29
|
+
client_id: string;
|
|
30
|
+
client_secret: string;
|
|
31
|
+
token: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'implicit';
|
|
34
|
+
client_id: string;
|
|
35
|
+
token: string;
|
|
36
|
+
};
|
|
37
|
+
interface AuthContextType {
|
|
38
|
+
store: TokenStore;
|
|
39
|
+
updatedSchemeId: string | null;
|
|
40
|
+
isLoading: boolean;
|
|
41
|
+
error?: unknown;
|
|
42
|
+
}
|
|
43
|
+
export declare function usePlaygroundAuth(): AuthContextType;
|
|
44
|
+
export interface AuthRequirement {
|
|
45
|
+
/** id of the security scheme */
|
|
46
|
+
id: string;
|
|
47
|
+
scopes: string[];
|
|
48
|
+
scheme: SecuritySchemeObject;
|
|
49
|
+
}
|
|
50
|
+
export interface AuthField {
|
|
51
|
+
schemeId: string;
|
|
52
|
+
scheme: SecuritySchemeObject;
|
|
53
|
+
scopes: string[];
|
|
54
|
+
/** the form field holding its value */
|
|
55
|
+
fieldName: FieldKey;
|
|
56
|
+
/** `localStorage` key of its persisted value */
|
|
57
|
+
storageKey: string;
|
|
58
|
+
defaultValue: unknown;
|
|
59
|
+
/** encode the value into request data, like the header of Basic auth */
|
|
60
|
+
mapOutput?: (value: unknown) => unknown;
|
|
61
|
+
}
|
|
62
|
+
export interface AuthFields {
|
|
63
|
+
/** the security requirements of the operation, one of them authorizes the request */
|
|
64
|
+
requirements: AuthRequirement[][];
|
|
65
|
+
/** index of the selected requirement, `-1` when the operation needs no authorization */
|
|
66
|
+
selected: number;
|
|
67
|
+
select: (index: number) => void;
|
|
68
|
+
/** the fields of the selected requirement */
|
|
69
|
+
fields: AuthField[];
|
|
70
|
+
/** encode the auth fields of form values into request data */
|
|
71
|
+
mapValues: <T>(values: T) => T;
|
|
72
|
+
/** write the persisted values into the form, returns a cleanup removing them */
|
|
73
|
+
init: () => () => void;
|
|
74
|
+
}
|
|
75
|
+
export interface AuthFieldsOptions {
|
|
76
|
+
/** the operation to authorize, defaults to the security of the document */
|
|
77
|
+
operation?: OperationObject;
|
|
78
|
+
/** customise the generated fields, like their default values */
|
|
79
|
+
transform?: (fields: AuthField[]) => AuthField[];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The auth fields of an API playground: the values it persists, and the request data they encode into.
|
|
83
|
+
*/
|
|
84
|
+
export declare function useAuthFields(engine: DataEngine, { operation, transform }?: AuthFieldsOptions): AuthFields;
|
|
85
|
+
//#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 { AuthField, AuthRequirement, OAuthFlowType, requestOAuthToken, useAuthFields, usePlaygroundAuth } from "./auth.js";
|
|
3
|
+
export { type AuthField, type AuthRequirement, type BrowserFetcherOptions, type FetchErrorResult, type FetchResponseResult, type FetchResult, type Fetcher, type OAuthFlowType, createBrowserFetcher, requestOAuthToken, useAuthFields, 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;
|