fumadocs-openapi 5.8.2 → 5.10.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/dist/index.d.ts +5 -0
- package/dist/index.js +14 -12
- package/dist/server/index.d.ts +15 -1
- package/dist/server/index.js +90 -25
- package/dist/ui/{client-client-D5WUNeFS.js → client-client-DTw64k7r.js} +2 -2
- package/dist/ui/fetcher-BuBL-ccr.js +138 -0
- package/dist/ui/{playground-client-JckpOPq4.js → index-client-Br05jF3h.js} +102 -187
- package/dist/ui/index.d.ts +7 -2
- package/dist/ui/index.js +4 -4
- package/package.json +10 -10
package/dist/index.d.ts
CHANGED
|
@@ -58,6 +58,7 @@ interface APIPlaygroundProps {
|
|
|
58
58
|
header?: PrimitiveRequestField[];
|
|
59
59
|
body?: RequestSchema;
|
|
60
60
|
schemas: Record<string, RequestSchema>;
|
|
61
|
+
proxyUrl?: string;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
interface ResponsesProps {
|
|
@@ -191,6 +192,10 @@ type Awaitable<T> = T | Promise<T>;
|
|
|
191
192
|
*/
|
|
192
193
|
type DereferenceMap = Map<unknown, string>;
|
|
193
194
|
interface RenderContext {
|
|
195
|
+
/**
|
|
196
|
+
* The url of proxy to avoid CORS issues
|
|
197
|
+
*/
|
|
198
|
+
proxyUrl?: string;
|
|
194
199
|
renderer: Renderer;
|
|
195
200
|
/**
|
|
196
201
|
* dereferenced schema
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { resolve, join, parse, dirname } from 'node:path';
|
|
2
2
|
import { dump } from 'js-yaml';
|
|
3
3
|
import Slugger from 'github-slugger';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import { load, upgrade, dereference as dereference$1 } from '@scalar/openapi-parser';
|
|
5
|
+
import { fetchUrls } from '@scalar/openapi-parser/plugins/fetch-urls';
|
|
6
|
+
import { readFiles } from '@scalar/openapi-parser/plugins/read-files';
|
|
6
7
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
7
8
|
import fg from 'fast-glob';
|
|
8
9
|
|
|
@@ -141,17 +142,18 @@ const cache = new Map();
|
|
|
141
142
|
*/ async function processDocument(document, disableCache = false) {
|
|
142
143
|
const cached = !disableCache && typeof document === 'string' ? cache.get(document) : null;
|
|
143
144
|
if (cached) return cached;
|
|
144
|
-
let bundled = await Parser.bundle(document, {
|
|
145
|
-
mutateInputSchema: false
|
|
146
|
-
});
|
|
147
|
-
bundled = upgrade(bundled).specification;
|
|
148
145
|
const dereferenceMap = new Map();
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
const loaded = await load(document, {
|
|
147
|
+
plugins: [
|
|
148
|
+
readFiles(),
|
|
149
|
+
fetchUrls()
|
|
150
|
+
]
|
|
151
|
+
});
|
|
152
|
+
// upgrade
|
|
153
|
+
loaded.specification = upgrade(loaded.specification).specification;
|
|
154
|
+
const { schema: dereferenced } = await dereference$1(loaded.filesystem, {
|
|
155
|
+
onDereference ({ ref, schema }) {
|
|
156
|
+
dereferenceMap.set(schema, ref);
|
|
155
157
|
}
|
|
156
158
|
});
|
|
157
159
|
const processed = {
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ComponentType, ReactNode, FC } from 'react';
|
|
|
2
2
|
import { OpenAPIV3_1, OpenAPIV3 } from 'openapi-types';
|
|
3
3
|
import Slugger from 'github-slugger';
|
|
4
4
|
import { CodeToHastOptionsCommon, CodeOptionsThemes, BuiltinTheme } from 'shiki';
|
|
5
|
+
import { NextRequest } from 'next/server';
|
|
5
6
|
import { BuildPageTreeOptions } from 'fumadocs-core/source';
|
|
6
7
|
|
|
7
8
|
interface BaseRequestField {
|
|
@@ -59,6 +60,7 @@ interface APIPlaygroundProps {
|
|
|
59
60
|
header?: PrimitiveRequestField[];
|
|
60
61
|
body?: RequestSchema;
|
|
61
62
|
schemas: Record<string, RequestSchema>;
|
|
63
|
+
proxyUrl?: string;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
interface ResponsesProps {
|
|
@@ -177,6 +179,10 @@ type Awaitable<T> = T | Promise<T>;
|
|
|
177
179
|
*/
|
|
178
180
|
type DereferenceMap = Map<unknown, string>;
|
|
179
181
|
interface RenderContext {
|
|
182
|
+
/**
|
|
183
|
+
* The url of proxy to avoid CORS issues
|
|
184
|
+
*/
|
|
185
|
+
proxyUrl?: string;
|
|
180
186
|
renderer: Renderer;
|
|
181
187
|
/**
|
|
182
188
|
* dereferenced schema
|
|
@@ -204,7 +210,8 @@ interface RenderContext {
|
|
|
204
210
|
|
|
205
211
|
type DocumentInput = string | OpenAPIV3_1.Document | OpenAPIV3.Document;
|
|
206
212
|
|
|
207
|
-
|
|
213
|
+
type ApiPageContextProps = Pick<Partial<RenderContext>, 'shikiOptions' | 'generateTypeScriptSchema' | 'generateCodeSamples' | 'proxyUrl'>;
|
|
214
|
+
interface ApiPageProps extends ApiPageContextProps {
|
|
208
215
|
document: DocumentInput;
|
|
209
216
|
hasHead: boolean;
|
|
210
217
|
renderer?: Partial<Renderer>;
|
|
@@ -227,6 +234,12 @@ interface OperationItem {
|
|
|
227
234
|
method: OpenAPIV3_1.HttpMethods;
|
|
228
235
|
}
|
|
229
236
|
|
|
237
|
+
declare const keys: readonly ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"];
|
|
238
|
+
type Proxy = {
|
|
239
|
+
[K in (typeof keys)[number]]: (req: NextRequest) => Promise<Response>;
|
|
240
|
+
};
|
|
241
|
+
declare function createProxy(allowedUrls?: string[]): Proxy;
|
|
242
|
+
|
|
230
243
|
interface OpenAPIOptions extends Omit<Partial<ApiPageProps>, 'document'> {
|
|
231
244
|
/**
|
|
232
245
|
* @deprecated Pass document to `APIPage` instead
|
|
@@ -235,6 +248,7 @@ interface OpenAPIOptions extends Omit<Partial<ApiPageProps>, 'document'> {
|
|
|
235
248
|
}
|
|
236
249
|
interface OpenAPIServer {
|
|
237
250
|
APIPage: FC<ApiPageProps>;
|
|
251
|
+
createProxy: typeof createProxy;
|
|
238
252
|
}
|
|
239
253
|
declare function createOpenAPI(options?: OpenAPIOptions): OpenAPIServer;
|
|
240
254
|
|
package/dist/server/index.js
CHANGED
|
@@ -14,8 +14,9 @@ import { Accordions, Accordion } from 'fumadocs-ui/components/accordion';
|
|
|
14
14
|
import * as Base from 'fumadocs-ui/components/codeblock';
|
|
15
15
|
import { highlight } from 'fumadocs-core/server';
|
|
16
16
|
import { Root, API, APIInfo, APIExample as APIExample$1, Property, ObjectCollapsible, APIPlayground } from '../ui/index.js';
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
17
|
+
import { load, upgrade, dereference } from '@scalar/openapi-parser';
|
|
18
|
+
import { fetchUrls } from '@scalar/openapi-parser/plugins/fetch-urls';
|
|
19
|
+
import { readFiles } from '@scalar/openapi-parser/plugins/read-files';
|
|
19
20
|
import { cva } from 'class-variance-authority';
|
|
20
21
|
|
|
21
22
|
function getPreferredType(body) {
|
|
@@ -301,13 +302,14 @@ function Playground({ path, method, ctx }) {
|
|
|
301
302
|
const mediaType = bodyContent ? getPreferredType(bodyContent) : undefined;
|
|
302
303
|
const context = {
|
|
303
304
|
allowFile: mediaType === 'multipart/form-data',
|
|
304
|
-
|
|
305
|
+
references: {},
|
|
305
306
|
nextId () {
|
|
306
307
|
return String(currentId++);
|
|
307
308
|
},
|
|
308
309
|
registered: new WeakMap(),
|
|
309
310
|
render: ctx
|
|
310
311
|
};
|
|
312
|
+
const bodySchema = bodyContent && mediaType && bodyContent[mediaType].schema ? toSchema(bodyContent[mediaType].schema, true, context) : undefined;
|
|
311
313
|
const props = {
|
|
312
314
|
authorization: getAuthorizationField(method, ctx),
|
|
313
315
|
method: method.method,
|
|
@@ -316,8 +318,9 @@ function Playground({ path, method, ctx }) {
|
|
|
316
318
|
path: method.parameters?.filter((v)=>v.in === 'path').map((v)=>parameterToField(v, context)),
|
|
317
319
|
query: method.parameters?.filter((v)=>v.in === 'query').map((v)=>parameterToField(v, context)),
|
|
318
320
|
header: method.parameters?.filter((v)=>v.in === 'header').map((v)=>parameterToField(v, context)),
|
|
319
|
-
body:
|
|
320
|
-
schemas: context.
|
|
321
|
+
body: bodySchema,
|
|
322
|
+
schemas: context.references,
|
|
323
|
+
proxyUrl: ctx.proxyUrl
|
|
321
324
|
};
|
|
322
325
|
return /*#__PURE__*/ jsx(ctx.renderer.APIPlayground, {
|
|
323
326
|
...props
|
|
@@ -343,7 +346,7 @@ function getIdFromSchema(schema, required, ctx) {
|
|
|
343
346
|
if (registered === undefined) {
|
|
344
347
|
const id = ctx.nextId();
|
|
345
348
|
ctx.registered.set(schema, id);
|
|
346
|
-
ctx.
|
|
349
|
+
ctx.references[id] = toSchema(schema, required, ctx);
|
|
347
350
|
return id;
|
|
348
351
|
}
|
|
349
352
|
return registered;
|
|
@@ -384,7 +387,7 @@ function toSchema(schema, required, ctx) {
|
|
|
384
387
|
const additional = schema.additionalProperties;
|
|
385
388
|
let additionalProperties;
|
|
386
389
|
if (additional && typeof additional === 'object') {
|
|
387
|
-
if (!additional.type && !additional.anyOf && !additional.allOf && !additional.oneOf) {
|
|
390
|
+
if ((!additional.type || additional.type.length === 0) && !additional.anyOf && !additional.allOf && !additional.oneOf) {
|
|
388
391
|
additionalProperties = true;
|
|
389
392
|
} else {
|
|
390
393
|
additionalProperties = getIdFromSchema(additional, false, ctx);
|
|
@@ -436,12 +439,11 @@ function toSchema(schema, required, ctx) {
|
|
|
436
439
|
items: 'items' in schema && schema.items ? toSchema(schema.items, false, ctx) : toSchema({}, required, ctx),
|
|
437
440
|
isRequired: required
|
|
438
441
|
};
|
|
439
|
-
} else
|
|
440
|
-
items[type] = {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
};
|
|
442
|
+
} else {
|
|
443
|
+
items[type] = toSchema({
|
|
444
|
+
...schema,
|
|
445
|
+
type
|
|
446
|
+
}, true, ctx);
|
|
445
447
|
}
|
|
446
448
|
}
|
|
447
449
|
return {
|
|
@@ -553,7 +555,7 @@ function heading(depth, child, ctx) {
|
|
|
553
555
|
return result;
|
|
554
556
|
}
|
|
555
557
|
|
|
556
|
-
const keys = {
|
|
558
|
+
const keys$1 = {
|
|
557
559
|
default: 'Default',
|
|
558
560
|
minimum: 'Minimum',
|
|
559
561
|
maximum: 'Maximum',
|
|
@@ -617,7 +619,7 @@ function Schema({ name, schema, ctx }) {
|
|
|
617
619
|
text: schema.description
|
|
618
620
|
}, "description"));
|
|
619
621
|
const fields = [];
|
|
620
|
-
for (const [key, value] of Object.entries(keys)){
|
|
622
|
+
for (const [key, value] of Object.entries(keys$1)){
|
|
621
623
|
if (key in schema) {
|
|
622
624
|
fields.push({
|
|
623
625
|
key: value,
|
|
@@ -1193,17 +1195,18 @@ const cache = new Map();
|
|
|
1193
1195
|
*/ async function processDocument(document, disableCache = false) {
|
|
1194
1196
|
const cached = !disableCache && typeof document === 'string' ? cache.get(document) : null;
|
|
1195
1197
|
if (cached) return cached;
|
|
1196
|
-
let bundled = await Parser.bundle(document, {
|
|
1197
|
-
mutateInputSchema: false
|
|
1198
|
-
});
|
|
1199
|
-
bundled = upgrade(bundled).specification;
|
|
1200
1198
|
const dereferenceMap = new Map();
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1199
|
+
const loaded = await load(document, {
|
|
1200
|
+
plugins: [
|
|
1201
|
+
readFiles(),
|
|
1202
|
+
fetchUrls()
|
|
1203
|
+
]
|
|
1204
|
+
});
|
|
1205
|
+
// upgrade
|
|
1206
|
+
loaded.specification = upgrade(loaded.specification).specification;
|
|
1207
|
+
const { schema: dereferenced } = await dereference(loaded.filesystem, {
|
|
1208
|
+
onDereference ({ ref, schema }) {
|
|
1209
|
+
dereferenceMap.set(schema, ref);
|
|
1207
1210
|
}
|
|
1208
1211
|
});
|
|
1209
1212
|
const processed = {
|
|
@@ -1261,6 +1264,7 @@ async function getContext({ document, dereferenceMap }, options = {}) {
|
|
|
1261
1264
|
return {
|
|
1262
1265
|
document: document,
|
|
1263
1266
|
dereferenceMap,
|
|
1267
|
+
proxyUrl: options.proxyUrl,
|
|
1264
1268
|
renderer: {
|
|
1265
1269
|
...createRenders(options.shikiOptions),
|
|
1266
1270
|
...options.renderer
|
|
@@ -1274,8 +1278,69 @@ async function getContext({ document, dereferenceMap }, options = {}) {
|
|
|
1274
1278
|
};
|
|
1275
1279
|
}
|
|
1276
1280
|
|
|
1281
|
+
const keys = [
|
|
1282
|
+
'GET',
|
|
1283
|
+
'POST',
|
|
1284
|
+
'PUT',
|
|
1285
|
+
'DELETE',
|
|
1286
|
+
'PATCH',
|
|
1287
|
+
'HEAD'
|
|
1288
|
+
];
|
|
1289
|
+
function createProxy(allowedUrls) {
|
|
1290
|
+
const handlers = {};
|
|
1291
|
+
async function handler(req) {
|
|
1292
|
+
const url = req.nextUrl.searchParams.get('url');
|
|
1293
|
+
if (!url) {
|
|
1294
|
+
return Response.json('A `url` query parameter is required for proxy url', {
|
|
1295
|
+
status: 400
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
if (allowedUrls && allowedUrls.every((allowedUrl)=>!allowedUrl.startsWith(url))) {
|
|
1299
|
+
return Response.json('The given `url` query parameter is not allowed', {
|
|
1300
|
+
status: 400
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
const clonedReq = new Request(url, {
|
|
1304
|
+
...req,
|
|
1305
|
+
cache: 'no-cache',
|
|
1306
|
+
mode: 'cors'
|
|
1307
|
+
});
|
|
1308
|
+
clonedReq.headers.forEach((_value, originalKey)=>{
|
|
1309
|
+
const key = originalKey.toLowerCase();
|
|
1310
|
+
const notAllowed = key === 'origin';
|
|
1311
|
+
if (notAllowed) {
|
|
1312
|
+
clonedReq.headers.delete(originalKey);
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
const res = await fetch(clonedReq).catch((e)=>new Error(e.toString()));
|
|
1316
|
+
if (res instanceof Error) {
|
|
1317
|
+
return Response.json(`Failed to proxy request: ${res.message}`, {
|
|
1318
|
+
status: 400
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
const headers = new Headers(res.headers);
|
|
1322
|
+
headers.forEach((_value, originalKey)=>{
|
|
1323
|
+
const key = originalKey.toLowerCase();
|
|
1324
|
+
const notAllowed = key.startsWith('access-control-') || key === 'content-encoding';
|
|
1325
|
+
if (notAllowed) {
|
|
1326
|
+
headers.delete(originalKey);
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
headers.set('X-Forwarded-Host', res.url);
|
|
1330
|
+
return new Response(res.body, {
|
|
1331
|
+
...res,
|
|
1332
|
+
headers
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
for (const key of keys){
|
|
1336
|
+
handlers[key] = handler;
|
|
1337
|
+
}
|
|
1338
|
+
return handlers;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1277
1341
|
function createOpenAPI(options = {}) {
|
|
1278
1342
|
return {
|
|
1343
|
+
createProxy,
|
|
1279
1344
|
APIPage (props) {
|
|
1280
1345
|
return /*#__PURE__*/ jsx(APIPage, {
|
|
1281
1346
|
...options,
|
|
@@ -253,7 +253,7 @@ function useSchemaContext() {
|
|
|
253
253
|
return ctx;
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
const APIPlayground = dynamic(()=>import('./
|
|
256
|
+
const APIPlayground = dynamic(()=>import('./index-client-Br05jF3h.js').then(function (n) { return n.i; }).then((mod)=>mod.APIPlayground));
|
|
257
257
|
function Root({ children, baseUrl, className, shikiOptions, ...props }) {
|
|
258
258
|
return /*#__PURE__*/ jsx("div", {
|
|
259
259
|
className: cn('flex flex-col gap-24 text-sm text-fd-muted-foreground', className),
|
|
@@ -309,4 +309,4 @@ function BaseUrlSelect({ baseUrls }) {
|
|
|
309
309
|
});
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
export { APIPlayground as A, BaseUrlSelect as B,
|
|
312
|
+
export { APIPlayground as A, BaseUrlSelect as B, ChevronDown as C, Plus as P, Root as R, SchemaContext as S, Trash2 as T, ChevronUp as a, Check as b, useApiContext as c, CircleCheck as d, CircleX as e, CopyRouteButton as f, useSchemaContext as u };
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { r as resolve } from './index-client-Br05jF3h.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param bodySchema - schema of body
|
|
5
|
+
* @param references - defined references of schemas, needed for resolve cyclic references
|
|
6
|
+
*/ function createBrowserFetcher(bodySchema, references) {
|
|
7
|
+
return {
|
|
8
|
+
async fetch (input) {
|
|
9
|
+
const headers = new Headers();
|
|
10
|
+
if (input.type !== 'form-data') headers.append('Content-Type', 'application/json');
|
|
11
|
+
for (const key of Object.keys(input.header)){
|
|
12
|
+
const paramValue = input.header[key];
|
|
13
|
+
if (typeof paramValue === 'string' && paramValue.length > 0) headers.append(key, paramValue.toString());
|
|
14
|
+
}
|
|
15
|
+
return fetch(input.url, {
|
|
16
|
+
method: input.method,
|
|
17
|
+
cache: 'no-cache',
|
|
18
|
+
headers,
|
|
19
|
+
body: bodySchema ? createBodyFromValue(input.type, input.body, bodySchema, references, input.dynamicFields ?? new Map()) : undefined,
|
|
20
|
+
signal: AbortSignal.timeout(10 * 1000)
|
|
21
|
+
}).then(async (res)=>{
|
|
22
|
+
const contentType = res.headers.get('Content-Type') ?? '';
|
|
23
|
+
let type;
|
|
24
|
+
let data;
|
|
25
|
+
if (contentType.startsWith('application/json')) {
|
|
26
|
+
type = 'json';
|
|
27
|
+
data = await res.json();
|
|
28
|
+
} else {
|
|
29
|
+
type = contentType.startsWith('text/html') ? 'html' : 'text';
|
|
30
|
+
data = await res.text();
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
status: res.status,
|
|
34
|
+
type,
|
|
35
|
+
data
|
|
36
|
+
};
|
|
37
|
+
}).catch((e)=>{
|
|
38
|
+
const message = e instanceof Error ? `[${e.name}] ${e.message}` : e.toString();
|
|
39
|
+
return {
|
|
40
|
+
status: 400,
|
|
41
|
+
type: 'text',
|
|
42
|
+
data: `Client side error: ${message}`
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create request body from value
|
|
50
|
+
*/ function createBodyFromValue(type, value, schema, references, dynamicFields) {
|
|
51
|
+
const result = convertValue('body', value, schema, references, dynamicFields);
|
|
52
|
+
if (type === 'json') {
|
|
53
|
+
return JSON.stringify(result);
|
|
54
|
+
}
|
|
55
|
+
const formData = new FormData();
|
|
56
|
+
if (typeof result !== 'object' || !result) {
|
|
57
|
+
throw new Error(`Unsupported body type: ${typeof result}, expected: object`);
|
|
58
|
+
}
|
|
59
|
+
for (const key of Object.keys(result)){
|
|
60
|
+
const prop = result[key];
|
|
61
|
+
if (typeof prop === 'object' && prop instanceof File) {
|
|
62
|
+
formData.set(key, prop);
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(prop) && prop.every((item)=>item instanceof File)) {
|
|
65
|
+
for (const item of prop){
|
|
66
|
+
formData.append(key, item);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (prop && !(prop instanceof File)) {
|
|
70
|
+
formData.set(key, JSON.stringify(prop));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return formData;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Convert a value (object or string) to the corresponding type of schema
|
|
77
|
+
*
|
|
78
|
+
* @param fieldName - field name of value
|
|
79
|
+
* @param value - the original value
|
|
80
|
+
* @param schema - the schema of field
|
|
81
|
+
* @param references - schema references
|
|
82
|
+
* @param dynamicFields - Dynamic references
|
|
83
|
+
*/ function convertValue(fieldName, value, schema, references, dynamicFields) {
|
|
84
|
+
const isEmpty = value === '' || value === undefined || value === null;
|
|
85
|
+
if (isEmpty && schema.isRequired) return schema.type === 'boolean' ? false : '';
|
|
86
|
+
else if (isEmpty) return undefined;
|
|
87
|
+
if (Array.isArray(value) && schema.type === 'array') {
|
|
88
|
+
return value.map((item, index)=>convertValue(`${fieldName}.${String(index)}`, item, resolve(schema.items, references), references, dynamicFields));
|
|
89
|
+
}
|
|
90
|
+
if (schema.type === 'switcher') {
|
|
91
|
+
const schema = resolve(getDynamicFieldSchema(fieldName, dynamicFields), references);
|
|
92
|
+
return convertValue(fieldName, value, schema, references, dynamicFields);
|
|
93
|
+
}
|
|
94
|
+
if (typeof value === 'object' && schema.type === 'object') {
|
|
95
|
+
const entries = Object.keys(value).map((key)=>{
|
|
96
|
+
const prop = value[key];
|
|
97
|
+
const propFieldName = `${fieldName}.${key}`;
|
|
98
|
+
if (key in schema.properties) {
|
|
99
|
+
return [
|
|
100
|
+
key,
|
|
101
|
+
convertValue(propFieldName, prop, resolve(schema.properties[key], references), references, dynamicFields)
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
if (schema.additionalProperties) {
|
|
105
|
+
const schema = resolve(getDynamicFieldSchema(propFieldName, dynamicFields), references);
|
|
106
|
+
return [
|
|
107
|
+
key,
|
|
108
|
+
convertValue(propFieldName, prop, schema, references, dynamicFields)
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
console.warn('Could not resolve field', propFieldName, dynamicFields);
|
|
112
|
+
return [
|
|
113
|
+
key,
|
|
114
|
+
prop
|
|
115
|
+
];
|
|
116
|
+
});
|
|
117
|
+
return Object.fromEntries(entries);
|
|
118
|
+
}
|
|
119
|
+
switch(schema.type){
|
|
120
|
+
case 'number':
|
|
121
|
+
return Number(value);
|
|
122
|
+
case 'boolean':
|
|
123
|
+
return value === 'null' ? undefined : value === 'true';
|
|
124
|
+
case 'file':
|
|
125
|
+
return value; // file
|
|
126
|
+
default:
|
|
127
|
+
return String(value);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function getDynamicFieldSchema(name, dynamicFields) {
|
|
131
|
+
const field = dynamicFields.get(name);
|
|
132
|
+
return field?.type === 'field' ? field.schema : {
|
|
133
|
+
type: 'null',
|
|
134
|
+
isRequired: false
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export { createBodyFromValue, createBrowserFetcher };
|
|
@@ -5,13 +5,12 @@ import { forwardRef, useId, createContext, useContext, useState, useCallback, us
|
|
|
5
5
|
import { FormProvider, Controller, useFormContext, useFieldArray, useForm, useWatch } from 'react-hook-form';
|
|
6
6
|
import { Accordions, Accordion } from 'fumadocs-ui/components/accordion';
|
|
7
7
|
import { cn, buttonVariants } from 'fumadocs-ui/components/api';
|
|
8
|
-
import { C as
|
|
8
|
+
import { C as ChevronDown, a as ChevronUp, b as Check, u as useSchemaContext, T as Trash2, P as Plus, c as useApiContext, d as CircleCheck, e as CircleX, S as SchemaContext } from './client-client-DTw64k7r.js';
|
|
9
9
|
import { Slot } from '@radix-ui/react-slot';
|
|
10
10
|
import { cva } from 'class-variance-authority';
|
|
11
11
|
import { useOnChange } from 'fumadocs-core/utils/use-on-change';
|
|
12
12
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
13
|
-
import
|
|
14
|
-
import { useShiki } from 'fumadocs-core/utils/use-shiki';
|
|
13
|
+
import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
|
|
15
14
|
|
|
16
15
|
const Form = FormProvider;
|
|
17
16
|
const FormFieldContext = /*#__PURE__*/ createContext({
|
|
@@ -102,145 +101,6 @@ FormDescription.displayName = 'FormDescription';
|
|
|
102
101
|
};
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
/**
|
|
106
|
-
* Create request body from value
|
|
107
|
-
*/ function createBodyFromValue(type, value, schema, references, dynamic) {
|
|
108
|
-
const result = convertValue('body', value, schema, references, dynamic);
|
|
109
|
-
if (type === 'json') {
|
|
110
|
-
return JSON.stringify(result);
|
|
111
|
-
}
|
|
112
|
-
const formData = new FormData();
|
|
113
|
-
if (typeof result !== 'object' || !result) {
|
|
114
|
-
throw new Error(`Unsupported body type: ${typeof result}, expected: object`);
|
|
115
|
-
}
|
|
116
|
-
for (const key of Object.keys(result)){
|
|
117
|
-
const prop = result[key];
|
|
118
|
-
if (typeof prop === 'object' && prop instanceof File) {
|
|
119
|
-
formData.set(key, prop);
|
|
120
|
-
}
|
|
121
|
-
if (Array.isArray(prop) && prop.every((item)=>item instanceof File)) {
|
|
122
|
-
for (const item of prop){
|
|
123
|
-
formData.append(key, item);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (prop && !(prop instanceof File)) {
|
|
127
|
-
formData.set(key, JSON.stringify(prop));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return formData;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Convert a value (object or string) to the corresponding type of schema
|
|
134
|
-
*
|
|
135
|
-
* @param fieldName - field name of value
|
|
136
|
-
* @param value - the original value
|
|
137
|
-
* @param schema - the schema of field
|
|
138
|
-
* @param references - schema references
|
|
139
|
-
* @param dynamic - Dynamic references
|
|
140
|
-
*/ function convertValue(fieldName, value, schema, references, dynamic) {
|
|
141
|
-
const isEmpty = value === '' || value === undefined || value === null;
|
|
142
|
-
if (isEmpty && schema.isRequired) return schema.type === 'boolean' ? false : '';
|
|
143
|
-
else if (isEmpty) return undefined;
|
|
144
|
-
if (Array.isArray(value) && schema.type === 'array') {
|
|
145
|
-
return value.map((item, index)=>convertValue(`${fieldName}.${String(index)}`, item, resolve(schema.items, references), references, dynamic));
|
|
146
|
-
}
|
|
147
|
-
if (schema.type === 'switcher') {
|
|
148
|
-
return convertDynamicValue(fieldName, value, references, dynamic);
|
|
149
|
-
}
|
|
150
|
-
if (typeof value === 'object' && schema.type === 'object') {
|
|
151
|
-
const entries = Object.keys(value).map((key)=>{
|
|
152
|
-
const prop = value[key];
|
|
153
|
-
const propFieldName = `${fieldName}.${key}`;
|
|
154
|
-
if (key in schema.properties) {
|
|
155
|
-
return [
|
|
156
|
-
key,
|
|
157
|
-
convertValue(propFieldName, prop, resolve(schema.properties[key], references), references, dynamic)
|
|
158
|
-
];
|
|
159
|
-
}
|
|
160
|
-
if (schema.additionalProperties) {
|
|
161
|
-
return [
|
|
162
|
-
key,
|
|
163
|
-
convertDynamicValue(propFieldName, prop, references, dynamic)
|
|
164
|
-
];
|
|
165
|
-
}
|
|
166
|
-
console.warn('Could not resolve field', propFieldName, dynamic);
|
|
167
|
-
return [
|
|
168
|
-
key,
|
|
169
|
-
prop
|
|
170
|
-
];
|
|
171
|
-
});
|
|
172
|
-
return Object.fromEntries(entries);
|
|
173
|
-
}
|
|
174
|
-
switch(schema.type){
|
|
175
|
-
case 'number':
|
|
176
|
-
return Number(value);
|
|
177
|
-
case 'boolean':
|
|
178
|
-
return value === 'null' ? undefined : value === 'true';
|
|
179
|
-
case 'file':
|
|
180
|
-
return value; // file
|
|
181
|
-
default:
|
|
182
|
-
return String(value);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function convertDynamicValue(fieldName, value, references, dynamic) {
|
|
186
|
-
const fieldDynamic = dynamic.get(fieldName);
|
|
187
|
-
return convertValue(fieldName, value, fieldDynamic?.type === 'field' ? resolve(fieldDynamic.schema, references) : {
|
|
188
|
-
type: 'null',
|
|
189
|
-
isRequired: false
|
|
190
|
-
}, references, dynamic);
|
|
191
|
-
}
|
|
192
|
-
const statusMap = {
|
|
193
|
-
400: {
|
|
194
|
-
description: 'Bad Request',
|
|
195
|
-
color: 'text-red-500',
|
|
196
|
-
icon: CircleX
|
|
197
|
-
},
|
|
198
|
-
401: {
|
|
199
|
-
description: 'Unauthorized',
|
|
200
|
-
color: 'text-red-500',
|
|
201
|
-
icon: CircleX
|
|
202
|
-
},
|
|
203
|
-
403: {
|
|
204
|
-
description: 'Forbidden',
|
|
205
|
-
color: 'text-red-500',
|
|
206
|
-
icon: CircleX
|
|
207
|
-
},
|
|
208
|
-
404: {
|
|
209
|
-
description: 'Not Found',
|
|
210
|
-
color: 'text-fd-muted-foreground',
|
|
211
|
-
icon: CircleX
|
|
212
|
-
},
|
|
213
|
-
500: {
|
|
214
|
-
description: 'Internal Server Error',
|
|
215
|
-
color: 'text-red-500',
|
|
216
|
-
icon: CircleX
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
function getStatusInfo(status) {
|
|
220
|
-
if (status in statusMap) {
|
|
221
|
-
return statusMap[status];
|
|
222
|
-
}
|
|
223
|
-
if (status >= 200 && status < 300) {
|
|
224
|
-
return {
|
|
225
|
-
description: 'Successful',
|
|
226
|
-
color: 'text-green-500',
|
|
227
|
-
icon: CircleCheck
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
if (status >= 400) {
|
|
231
|
-
return {
|
|
232
|
-
description: 'Error',
|
|
233
|
-
color: 'text-red-500',
|
|
234
|
-
icon: CircleX
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
description: 'No Description',
|
|
239
|
-
color: 'text-fd-muted-foreground',
|
|
240
|
-
icon: CircleX
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
104
|
function getDefaultValue(item, references) {
|
|
245
105
|
if (item.type === 'object') return Object.fromEntries(Object.entries(item.properties).map(([key, prop])=>[
|
|
246
106
|
key,
|
|
@@ -248,7 +108,11 @@ function getDefaultValue(item, references) {
|
|
|
248
108
|
]));
|
|
249
109
|
if (item.type === 'array') return [];
|
|
250
110
|
if (item.type === 'null') return null;
|
|
251
|
-
if (item.type === 'switcher')
|
|
111
|
+
if (item.type === 'switcher') {
|
|
112
|
+
const first = Object.values(item.items).at(0);
|
|
113
|
+
if (!first) return '';
|
|
114
|
+
return getDefaultValue(resolve(first, references), references);
|
|
115
|
+
}
|
|
252
116
|
if (item.type === 'file') return undefined;
|
|
253
117
|
return String(item.defaultValue);
|
|
254
118
|
}
|
|
@@ -812,24 +676,66 @@ function ArrayInput({ fieldName, field, ...props }) {
|
|
|
812
676
|
|
|
813
677
|
function CodeBlock({ code, lang = 'json' }) {
|
|
814
678
|
const { shikiOptions } = useApiContext();
|
|
815
|
-
|
|
816
|
-
lang,
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
pre: (props)=>/*#__PURE__*/ jsx(Base.Pre, {
|
|
820
|
-
className: "max-h-[288px]",
|
|
821
|
-
...props,
|
|
822
|
-
children: props.children
|
|
823
|
-
})
|
|
824
|
-
}
|
|
825
|
-
});
|
|
826
|
-
return /*#__PURE__*/ jsx(Base.CodeBlock, {
|
|
827
|
-
className: "my-0",
|
|
828
|
-
children: rendered
|
|
679
|
+
return /*#__PURE__*/ jsx(DynamicCodeBlock, {
|
|
680
|
+
lang: lang,
|
|
681
|
+
code: code,
|
|
682
|
+
options: shikiOptions
|
|
829
683
|
});
|
|
830
684
|
}
|
|
831
685
|
|
|
832
|
-
|
|
686
|
+
const statusMap = {
|
|
687
|
+
400: {
|
|
688
|
+
description: 'Bad Request',
|
|
689
|
+
color: 'text-red-500',
|
|
690
|
+
icon: CircleX
|
|
691
|
+
},
|
|
692
|
+
401: {
|
|
693
|
+
description: 'Unauthorized',
|
|
694
|
+
color: 'text-red-500',
|
|
695
|
+
icon: CircleX
|
|
696
|
+
},
|
|
697
|
+
403: {
|
|
698
|
+
description: 'Forbidden',
|
|
699
|
+
color: 'text-red-500',
|
|
700
|
+
icon: CircleX
|
|
701
|
+
},
|
|
702
|
+
404: {
|
|
703
|
+
description: 'Not Found',
|
|
704
|
+
color: 'text-fd-muted-foreground',
|
|
705
|
+
icon: CircleX
|
|
706
|
+
},
|
|
707
|
+
500: {
|
|
708
|
+
description: 'Internal Server Error',
|
|
709
|
+
color: 'text-red-500',
|
|
710
|
+
icon: CircleX
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
function getStatusInfo(status) {
|
|
714
|
+
if (status in statusMap) {
|
|
715
|
+
return statusMap[status];
|
|
716
|
+
}
|
|
717
|
+
if (status >= 200 && status < 300) {
|
|
718
|
+
return {
|
|
719
|
+
description: 'Successful',
|
|
720
|
+
color: 'text-green-500',
|
|
721
|
+
icon: CircleCheck
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
if (status >= 400) {
|
|
725
|
+
return {
|
|
726
|
+
description: 'Error',
|
|
727
|
+
color: 'text-red-500',
|
|
728
|
+
icon: CircleX
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
description: 'No Description',
|
|
733
|
+
color: 'text-fd-muted-foreground',
|
|
734
|
+
icon: CircleX
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
function APIPlayground({ route, method = 'GET', bodyType, authorization, path = [], header = [], query = [], body, fields = {}, schemas, proxyUrl }) {
|
|
833
739
|
const { baseUrl } = useApiContext();
|
|
834
740
|
const dynamicRef = useRef(new Map());
|
|
835
741
|
const form = useForm({
|
|
@@ -842,27 +748,29 @@ function APIPlayground({ route, method = 'GET', bodyType, authorization, path =
|
|
|
842
748
|
}
|
|
843
749
|
});
|
|
844
750
|
const testQuery = useQuery(async (input)=>{
|
|
845
|
-
const
|
|
846
|
-
const
|
|
847
|
-
|
|
751
|
+
const fetcher = await import('./fetcher-BuBL-ccr.js').then((mod)=>mod.createBrowserFetcher(body, schemas));
|
|
752
|
+
const targetUrl = `${baseUrl ?? window.location.origin}${createPathnameFromInput(route, input.path, input.query)}`;
|
|
753
|
+
let url;
|
|
754
|
+
if (proxyUrl) {
|
|
755
|
+
url = new URL(proxyUrl, window.location.origin);
|
|
756
|
+
url.searchParams.append('url', targetUrl);
|
|
757
|
+
} else {
|
|
758
|
+
url = new URL(targetUrl);
|
|
759
|
+
}
|
|
760
|
+
const header = {
|
|
761
|
+
...input.header
|
|
762
|
+
};
|
|
848
763
|
if (input.authorization && authorization) {
|
|
849
|
-
|
|
764
|
+
header[authorization.name] = input.authorization;
|
|
850
765
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
766
|
+
return fetcher.fetch({
|
|
767
|
+
type: bodyType,
|
|
768
|
+
url: url.toString(),
|
|
769
|
+
header,
|
|
770
|
+
body: input.body,
|
|
771
|
+
dynamicFields: dynamicRef.current,
|
|
772
|
+
method
|
|
854
773
|
});
|
|
855
|
-
const bodyValue = body && input.body && Object.keys(input.body).length > 0 ? createBodyFromValue(bodyType, input.body, body, schemas, dynamicRef.current) : undefined;
|
|
856
|
-
const response = await fetch(url, {
|
|
857
|
-
method,
|
|
858
|
-
headers,
|
|
859
|
-
body: bodyValue
|
|
860
|
-
});
|
|
861
|
-
const data = await response.json().catch(()=>undefined);
|
|
862
|
-
return {
|
|
863
|
-
status: response.status,
|
|
864
|
-
data
|
|
865
|
-
};
|
|
866
774
|
});
|
|
867
775
|
useEffect(()=>{
|
|
868
776
|
if (!authorization) return;
|
|
@@ -898,6 +806,7 @@ function APIPlayground({ route, method = 'GET', bodyType, authorization, path =
|
|
|
898
806
|
field: info
|
|
899
807
|
}, key);
|
|
900
808
|
}
|
|
809
|
+
const isParamEmpty = path.length === 0 && query.length === 0 && header.length === 0 && body === undefined;
|
|
901
810
|
return /*#__PURE__*/ jsx(Form, {
|
|
902
811
|
...form,
|
|
903
812
|
children: /*#__PURE__*/ jsx(SchemaContext.Provider, {
|
|
@@ -928,9 +837,9 @@ function APIPlayground({ route, method = 'GET', bodyType, authorization, path =
|
|
|
928
837
|
]
|
|
929
838
|
}),
|
|
930
839
|
authorization ? renderCustomField('authorization', authorization, fields.auth) : null,
|
|
931
|
-
/*#__PURE__*/ jsxs(Accordions, {
|
|
840
|
+
!isParamEmpty ? /*#__PURE__*/ jsxs(Accordions, {
|
|
932
841
|
type: "multiple",
|
|
933
|
-
className:
|
|
842
|
+
className: "-m-3 border-0 bg-transparent text-sm",
|
|
934
843
|
children: [
|
|
935
844
|
path.length > 0 ? /*#__PURE__*/ jsx(Accordion, {
|
|
936
845
|
title: "Path",
|
|
@@ -961,7 +870,7 @@ function APIPlayground({ route, method = 'GET', bodyType, authorization, path =
|
|
|
961
870
|
}) : renderCustomField('body', body, fields.body)
|
|
962
871
|
}) : null
|
|
963
872
|
]
|
|
964
|
-
}),
|
|
873
|
+
}) : null,
|
|
965
874
|
testQuery.data ? /*#__PURE__*/ jsx(ResultDisplay, {
|
|
966
875
|
data: testQuery.data
|
|
967
876
|
}) : null
|
|
@@ -970,17 +879,17 @@ function APIPlayground({ route, method = 'GET', bodyType, authorization, path =
|
|
|
970
879
|
})
|
|
971
880
|
});
|
|
972
881
|
}
|
|
973
|
-
function
|
|
882
|
+
function createPathnameFromInput(route, path, query) {
|
|
974
883
|
let pathname = route;
|
|
975
|
-
Object.keys(path)
|
|
884
|
+
for (const key of Object.keys(path)){
|
|
976
885
|
const paramValue = path[key];
|
|
977
886
|
if (typeof paramValue === 'string' && paramValue.length > 0) pathname = pathname.replace(`{${key}}`, paramValue);
|
|
978
|
-
}
|
|
887
|
+
}
|
|
979
888
|
const searchParams = new URLSearchParams();
|
|
980
|
-
Object.keys(query)
|
|
889
|
+
for (const key of Object.keys(query)){
|
|
981
890
|
const paramValue = query[key];
|
|
982
891
|
if (typeof paramValue === 'string' && paramValue.length > 0) searchParams.append(key, paramValue);
|
|
983
|
-
}
|
|
892
|
+
}
|
|
984
893
|
return searchParams.size > 0 ? `${pathname}?${searchParams.toString()}` : pathname;
|
|
985
894
|
}
|
|
986
895
|
function RouteDisplay({ route }) {
|
|
@@ -990,7 +899,7 @@ function RouteDisplay({ route }) {
|
|
|
990
899
|
'query'
|
|
991
900
|
]
|
|
992
901
|
});
|
|
993
|
-
const pathname = useMemo(()=>
|
|
902
|
+
const pathname = useMemo(()=>createPathnameFromInput(route, path, query), [
|
|
994
903
|
route,
|
|
995
904
|
path,
|
|
996
905
|
query
|
|
@@ -1021,7 +930,8 @@ function ResultDisplay({ data }) {
|
|
|
1021
930
|
children: data.status
|
|
1022
931
|
}),
|
|
1023
932
|
data.data ? /*#__PURE__*/ jsx(CodeBlock, {
|
|
1024
|
-
|
|
933
|
+
lang: typeof data.data === 'string' && data.data.length > 50000 ? 'text' : data.type,
|
|
934
|
+
code: typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)
|
|
1025
935
|
}) : null
|
|
1026
936
|
]
|
|
1027
937
|
});
|
|
@@ -1049,4 +959,9 @@ function useQuery(fn) {
|
|
|
1049
959
|
]);
|
|
1050
960
|
}
|
|
1051
961
|
|
|
1052
|
-
|
|
962
|
+
var index = {
|
|
963
|
+
__proto__: null,
|
|
964
|
+
APIPlayground: APIPlayground
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
export { index as i, resolve as r };
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
|
-
import { ReactNode, ComponentType, ReactElement,
|
|
3
|
+
import { ReactNode, ComponentType, ReactElement, RefObject, HTMLAttributes } from 'react';
|
|
4
4
|
import { FieldPath, ControllerRenderProps, ControllerFieldState, UseFormStateReturn } from 'react-hook-form';
|
|
5
5
|
import { OpenAPIV3_1 } from 'openapi-types';
|
|
6
6
|
import Slugger from 'github-slugger';
|
|
@@ -54,6 +54,10 @@ type Awaitable<T> = T | Promise<T>;
|
|
|
54
54
|
*/
|
|
55
55
|
type DereferenceMap = Map<unknown, string>;
|
|
56
56
|
interface RenderContext {
|
|
57
|
+
/**
|
|
58
|
+
* The url of proxy to avoid CORS issues
|
|
59
|
+
*/
|
|
60
|
+
proxyUrl?: string;
|
|
57
61
|
renderer: Renderer;
|
|
58
62
|
/**
|
|
59
63
|
* dereferenced schema
|
|
@@ -134,6 +138,7 @@ interface APIPlaygroundProps {
|
|
|
134
138
|
header?: PrimitiveRequestField[];
|
|
135
139
|
body?: RequestSchema;
|
|
136
140
|
schemas: Record<string, RequestSchema>;
|
|
141
|
+
proxyUrl?: string;
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
interface ResponsesProps {
|
|
@@ -225,7 +230,7 @@ interface CustomField<TName extends FieldPath<FormValues>, Info> {
|
|
|
225
230
|
|
|
226
231
|
interface SchemaContextType {
|
|
227
232
|
references: Record<string, RequestSchema>;
|
|
228
|
-
dynamic:
|
|
233
|
+
dynamic: RefObject<Map<string, DynamicField>>;
|
|
229
234
|
}
|
|
230
235
|
type DynamicField = {
|
|
231
236
|
type: 'object';
|
package/dist/ui/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { cn } from 'fumadocs-ui/components/api';
|
|
|
3
3
|
import { Fragment } from 'react';
|
|
4
4
|
import { Accordions, Accordion } from 'fumadocs-ui/components/accordion';
|
|
5
5
|
import { cva } from 'class-variance-authority';
|
|
6
|
-
import { f as CopyRouteButton, B as BaseUrlSelect } from './client-client-
|
|
7
|
-
export { A as APIPlayground, R as Root, u as useSchemaContext } from './client-client-
|
|
6
|
+
import { f as CopyRouteButton, B as BaseUrlSelect } from './client-client-DTw64k7r.js';
|
|
7
|
+
export { A as APIPlayground, R as Root, u as useSchemaContext } from './client-client-DTw64k7r.js';
|
|
8
8
|
|
|
9
9
|
const badgeVariants = cva('rounded-xl border px-1.5 py-1 text-xs font-medium leading-[12px]', {
|
|
10
10
|
variants: {
|
|
@@ -95,9 +95,9 @@ function APIInfo({ className, route, badgeClassname, baseUrls, method = 'GET', h
|
|
|
95
95
|
function API({ children, ...props }) {
|
|
96
96
|
return /*#__PURE__*/ jsx("div", {
|
|
97
97
|
...props,
|
|
98
|
-
className: cn('flex flex-col gap-x-6 gap-y-4
|
|
98
|
+
className: cn('flex flex-col gap-x-6 gap-y-4 xl:flex-row xl:items-start', props.className),
|
|
99
99
|
style: {
|
|
100
|
-
'--fd-api-info-top': 'calc(var(--fd-nav-height) + var(--fd-banner-height) + var(--fd-
|
|
100
|
+
'--fd-api-info-top': 'calc(var(--fd-nav-height) + var(--fd-banner-height) + var(--fd-tocnav-height, 0px))',
|
|
101
101
|
...props.style
|
|
102
102
|
},
|
|
103
103
|
children: children
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fumadocs-openapi",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0",
|
|
4
4
|
"description": "Generate MDX docs for your OpenAPI spec",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -31,32 +31,32 @@
|
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@apidevtools/json-schema-ref-parser": "^11.7.3",
|
|
35
34
|
"@fumari/json-schema-to-typescript": "^1.1.2",
|
|
36
|
-
"@radix-ui/react-select": "^2.1.
|
|
37
|
-
"@radix-ui/react-slot": "^1.1.
|
|
38
|
-
"@scalar/openapi-parser": "
|
|
35
|
+
"@radix-ui/react-select": "^2.1.4",
|
|
36
|
+
"@radix-ui/react-slot": "^1.1.1",
|
|
37
|
+
"@scalar/openapi-parser": "0.10.2",
|
|
38
|
+
"ajv-draft-04": "^1.0.0",
|
|
39
39
|
"class-variance-authority": "^0.7.1",
|
|
40
40
|
"fast-glob": "^3.3.1",
|
|
41
41
|
"github-slugger": "^2.0.0",
|
|
42
42
|
"hast-util-to-jsx-runtime": "^2.3.2",
|
|
43
43
|
"js-yaml": "^4.1.0",
|
|
44
44
|
"openapi-sampler": "^1.6.1",
|
|
45
|
-
"react-hook-form": "^7.54.
|
|
45
|
+
"react-hook-form": "^7.54.1",
|
|
46
46
|
"remark": "^15.0.1",
|
|
47
47
|
"remark-rehype": "^11.1.1",
|
|
48
48
|
"shiki": "^1.24.2",
|
|
49
|
-
"fumadocs-core": "14.6.
|
|
50
|
-
"fumadocs-ui": "14.6.
|
|
49
|
+
"fumadocs-core": "14.6.2",
|
|
50
|
+
"fumadocs-ui": "14.6.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/js-yaml": "^4.0.9",
|
|
54
|
-
"@types/node": "22.10.
|
|
54
|
+
"@types/node": "22.10.2",
|
|
55
55
|
"@types/openapi-sampler": "^1.0.3",
|
|
56
56
|
"@types/react": "^19.0.1",
|
|
57
57
|
"bunchee": "^6.0.3",
|
|
58
58
|
"lucide-react": "^0.468.0",
|
|
59
|
-
"next": "15.
|
|
59
|
+
"next": "15.1.1",
|
|
60
60
|
"openapi-types": "^12.1.3",
|
|
61
61
|
"eslint-config-custom": "0.0.0",
|
|
62
62
|
"tsconfig": "0.0.0"
|