fumadocs-openapi 10.3.12 → 10.3.13

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.
Files changed (34) hide show
  1. package/css/generated/shared.css +24 -4
  2. package/dist/requests/generators/all.d.ts +6 -0
  3. package/dist/requests/generators/all.js +19 -0
  4. package/dist/requests/generators/csharp.d.ts +6 -0
  5. package/dist/requests/generators/csharp.js +34 -32
  6. package/dist/requests/generators/curl.d.ts +6 -0
  7. package/dist/requests/generators/curl.js +24 -22
  8. package/dist/requests/generators/go.d.ts +6 -0
  9. package/dist/requests/generators/go.js +29 -27
  10. package/dist/requests/generators/index.d.ts +55 -0
  11. package/dist/requests/generators/index.js +37 -46
  12. package/dist/requests/generators/java.d.ts +6 -0
  13. package/dist/requests/generators/java.js +49 -47
  14. package/dist/requests/generators/javascript.d.ts +6 -0
  15. package/dist/requests/generators/javascript.js +31 -29
  16. package/dist/requests/generators/python.d.ts +6 -0
  17. package/dist/requests/generators/python.js +26 -24
  18. package/dist/requests/types.d.ts +1 -6
  19. package/dist/server/create.d.ts +5 -2
  20. package/dist/server/create.js +4 -6
  21. package/dist/types.d.ts +4 -4
  22. package/dist/ui/base.d.ts +22 -4
  23. package/dist/ui/base.js +8 -0
  24. package/dist/ui/client/index.d.ts +5 -0
  25. package/dist/ui/contexts/api.js +18 -7
  26. package/dist/ui/full.js +2 -3
  27. package/dist/ui/operation/client.js +9 -5
  28. package/dist/ui/operation/index.js +25 -8
  29. package/dist/ui/operation/usage-tabs/client.js +24 -12
  30. package/dist/ui/operation/usage-tabs/index.js +25 -32
  31. package/dist/ui/schema/client.js +81 -32
  32. package/dist/utils/process-document.js +0 -1
  33. package/package.json +31 -45
  34. package/dist/ui/operation/usage-tabs/index.d.ts +0 -26
@@ -1,57 +1,59 @@
1
- 'use client';
2
-
3
1
  import { ident } from "../string-utils.js";
4
2
  import { resolveMediaAdapter } from "../media/resolve-adapter.js";
5
3
  import "../media/adapter.js";
6
4
 
7
5
  //#region src/requests/generators/java.ts
8
- const generator = (url, data, { mediaAdapters }) => {
9
- const s = [];
10
- const headers = { ...data.header };
11
- const imports = new Set([
12
- "java.net.URI",
13
- "java.net.http.HttpClient",
14
- "java.net.http.HttpRequest",
15
- "java.net.http.HttpResponse",
16
- "java.net.http.HttpResponse.BodyHandlers",
17
- "java.time.Duration"
18
- ]);
19
- let body;
20
- if (data.body && data.bodyMediaType) body = resolveMediaAdapter(data.bodyMediaType, mediaAdapters)?.generateExample(data, {
21
- lang: "java",
22
- addImport(specifier) {
23
- imports.add(specifier);
6
+ const java = {
7
+ label: "Java",
8
+ lang: "java",
9
+ generate(url, data, { mediaAdapters }) {
10
+ const s = [];
11
+ const headers = { ...data.header };
12
+ const imports = new Set([
13
+ "java.net.URI",
14
+ "java.net.http.HttpClient",
15
+ "java.net.http.HttpRequest",
16
+ "java.net.http.HttpResponse",
17
+ "java.net.http.HttpResponse.BodyHandlers",
18
+ "java.time.Duration"
19
+ ]);
20
+ let body;
21
+ if (data.body && data.bodyMediaType) body = resolveMediaAdapter(data.bodyMediaType, mediaAdapters)?.generateExample(data, {
22
+ lang: "java",
23
+ addImport(specifier) {
24
+ imports.add(specifier);
25
+ }
26
+ });
27
+ for (const value of imports.values()) s.push(`import ${value};`);
28
+ s.push("");
29
+ if (body) s.push(body);
30
+ s.push("HttpClient client = HttpClient.newBuilder()");
31
+ s.push(ident(".connectTimeout(Duration.ofSeconds(10))"));
32
+ s.push(ident(".build();"));
33
+ s.push("");
34
+ s.push("HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()");
35
+ s.push(ident(`.uri(URI.create(${JSON.stringify(url)}))`));
36
+ for (const [key, param] of Object.entries(headers)) s.push(ident(`.header(${JSON.stringify(key)}, ${JSON.stringify(param.value)})`));
37
+ if (data.bodyMediaType) s.push(ident(`.header("Content-Type", "${data.bodyMediaType}")`));
38
+ const cookies = Object.entries(data.cookie);
39
+ if (cookies.length > 0) {
40
+ const cookieString = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
41
+ s.push(ident(`.header("Cookie", ${JSON.stringify(cookieString)})`));
24
42
  }
25
- });
26
- for (const value of imports.values()) s.push(`import ${value};`);
27
- s.push("");
28
- if (body) s.push(body);
29
- s.push("HttpClient client = HttpClient.newBuilder()");
30
- s.push(ident(".connectTimeout(Duration.ofSeconds(10))"));
31
- s.push(ident(".build();"));
32
- s.push("");
33
- s.push("HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()");
34
- s.push(ident(`.uri(URI.create(${JSON.stringify(url)}))`));
35
- for (const [key, param] of Object.entries(headers)) s.push(ident(`.header(${JSON.stringify(key)}, ${JSON.stringify(param.value)})`));
36
- if (data.bodyMediaType) s.push(ident(`.header("Content-Type", "${data.bodyMediaType}")`));
37
- const cookies = Object.entries(data.cookie);
38
- if (cookies.length > 0) {
39
- const cookieString = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
40
- s.push(ident(`.header("Cookie", ${JSON.stringify(cookieString)})`));
43
+ const arg = body ? "body" : "";
44
+ s.push(ident(`.${data.method.toUpperCase()}(${arg})`));
45
+ s.push(ident(".build();"));
46
+ s.push("");
47
+ s.push("try {");
48
+ s.push(ident("HttpResponse<String> response = client.send(requestBuilder.build(), BodyHandlers.ofString());"));
49
+ s.push(ident("System.out.println(\"Status code: \" + response.statusCode());"));
50
+ s.push(ident("System.out.println(\"Response body: \" + response.body());"));
51
+ s.push("} catch (Exception e) {");
52
+ s.push(ident("e.printStackTrace();"));
53
+ s.push("}");
54
+ return s.join("\n");
41
55
  }
42
- const arg = body ? "body" : "";
43
- s.push(ident(`.${data.method.toUpperCase()}(${arg})`));
44
- s.push(ident(".build();"));
45
- s.push("");
46
- s.push("try {");
47
- s.push(ident("HttpResponse<String> response = client.send(requestBuilder.build(), BodyHandlers.ofString());"));
48
- s.push(ident("System.out.println(\"Status code: \" + response.statusCode());"));
49
- s.push(ident("System.out.println(\"Response body: \" + response.body());"));
50
- s.push("} catch (Exception e) {");
51
- s.push(ident("e.printStackTrace();"));
52
- s.push("}");
53
- return s.join("\n");
54
56
  };
55
57
 
56
58
  //#endregion
57
- export { generator };
59
+ export { java };
@@ -0,0 +1,6 @@
1
+ import { CodeUsageGenerator } from "./index.js";
2
+
3
+ //#region src/requests/generators/javascript.d.ts
4
+ declare const javascript: CodeUsageGenerator;
5
+ //#endregion
6
+ export { javascript };
@@ -1,39 +1,41 @@
1
- 'use client';
2
-
3
1
  import { ident } from "../string-utils.js";
4
2
  import { resolveMediaAdapter } from "../media/resolve-adapter.js";
5
3
  import "../media/adapter.js";
6
4
 
7
5
  //#region src/requests/generators/javascript.ts
8
- const generator = (url, data, { mediaAdapters }) => {
9
- const s = [];
10
- const options = /* @__PURE__ */ new Map();
11
- const headers = {};
12
- options.set("method", JSON.stringify(data.method));
13
- if (data.bodyMediaType) headers["Content-Type"] = data.bodyMediaType;
14
- for (const [k, v] of Object.entries(data.header)) headers[k] = v.value;
15
- const cookies = Object.entries(data.cookie);
16
- if (cookies.length > 0) headers["cookie"] = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
17
- if (Object.keys(headers).length > 0) options.set("headers", JSON.stringify(headers, null, 2));
18
- let body;
19
- if (data.body && data.bodyMediaType) body = resolveMediaAdapter(data.bodyMediaType, mediaAdapters)?.generateExample(data, {
20
- lang: "js",
21
- addImport(from, name) {
22
- s.unshift(`import { ${name} } from "${from}"`);
6
+ const javascript = {
7
+ label: "JavaScript",
8
+ lang: "js",
9
+ generate(url, data, { mediaAdapters }) {
10
+ const s = [];
11
+ const options = /* @__PURE__ */ new Map();
12
+ const headers = {};
13
+ options.set("method", JSON.stringify(data.method));
14
+ if (data.bodyMediaType) headers["Content-Type"] = data.bodyMediaType;
15
+ for (const [k, v] of Object.entries(data.header)) headers[k] = v.value;
16
+ const cookies = Object.entries(data.cookie);
17
+ if (cookies.length > 0) headers["cookie"] = cookies.map(([key, param]) => `${key}=${param.value}`).join("; ");
18
+ if (Object.keys(headers).length > 0) options.set("headers", JSON.stringify(headers, null, 2));
19
+ let body;
20
+ if (data.body && data.bodyMediaType) body = resolveMediaAdapter(data.bodyMediaType, mediaAdapters)?.generateExample(data, {
21
+ lang: "js",
22
+ addImport(from, name) {
23
+ s.unshift(`import { ${name} } from "${from}"`);
24
+ }
25
+ });
26
+ if (body) {
27
+ s.push(body);
28
+ options.set("body", "body");
23
29
  }
24
- });
25
- if (body) {
26
- s.push(body);
27
- options.set("body", "body");
28
- }
29
- const params = [JSON.stringify(url)];
30
- if (options.size > 0) {
31
- const str = Array.from(options.entries()).map(([k, v]) => ident(k === v ? k : `${k}: ${v}`)).join(",\n");
32
- params.push(`{\n${str}\n}`);
30
+ const params = [JSON.stringify(url)];
31
+ if (options.size > 0) {
32
+ const str = Array.from(options.entries()).map(([k, v]) => ident(k === v ? k : `${k}: ${v}`)).join(",\n");
33
+ params.push(`{\n${str}\n}`);
34
+ }
35
+ s.push(`fetch(${params.join(", ")})`);
36
+ return s.join("\n\n");
33
37
  }
34
- s.push(`fetch(${params.join(", ")})`);
35
- return s.join("\n\n");
36
38
  };
37
39
 
38
40
  //#endregion
39
- export { generator };
41
+ export { javascript };
@@ -0,0 +1,6 @@
1
+ import { CodeUsageGenerator } from "./index.js";
2
+
3
+ //#region src/requests/generators/python.d.ts
4
+ declare const python: CodeUsageGenerator;
5
+ //#endregion
6
+ export { python };
@@ -1,38 +1,40 @@
1
- 'use client';
2
-
3
1
  import { resolveMediaAdapter } from "../media/resolve-adapter.js";
4
2
  import "../media/adapter.js";
5
3
  import { generatePythonObject } from "../to-python-object.js";
6
4
 
7
5
  //#region src/requests/generators/python.ts
8
- const generator = (url, data, { mediaAdapters }) => {
9
- const headers = {};
10
- const imports = /* @__PURE__ */ new Set();
11
- const params = [`"${data.method}"`, "url"];
12
- let body;
13
- imports.add("requests");
14
- if (data.body && data.bodyMediaType) {
15
- const adapter = resolveMediaAdapter(data.bodyMediaType, mediaAdapters);
16
- headers["Content-Type"] = data.bodyMediaType;
17
- body = adapter?.generateExample(data, { lang: "python" });
18
- if (body) params.push("data = body");
19
- }
20
- for (const [k, v] of Object.entries(data.header)) headers[k] = v.value;
21
- if (Object.keys(headers).length > 0) params.push(`headers = ${generatePythonObject(headers, imports)}`);
22
- const inputCookies = Object.entries(data.cookie);
23
- if (inputCookies.length > 0) {
24
- const cookies = {};
25
- for (const [k, v] of inputCookies) cookies[k] = v.value;
26
- params.push(`cookies = ${generatePythonObject(cookies, imports)}`);
27
- }
28
- return `${Array.from(imports).map((name) => "import " + name).join("\n")}
6
+ const python = {
7
+ label: "Python",
8
+ lang: "python",
9
+ generate(url, data, { mediaAdapters }) {
10
+ const headers = {};
11
+ const imports = /* @__PURE__ */ new Set();
12
+ const params = [`"${data.method}"`, "url"];
13
+ let body;
14
+ imports.add("requests");
15
+ if (data.body && data.bodyMediaType) {
16
+ const adapter = resolveMediaAdapter(data.bodyMediaType, mediaAdapters);
17
+ headers["Content-Type"] = data.bodyMediaType;
18
+ body = adapter?.generateExample(data, { lang: "python" });
19
+ if (body) params.push("data = body");
20
+ }
21
+ for (const [k, v] of Object.entries(data.header)) headers[k] = v.value;
22
+ if (Object.keys(headers).length > 0) params.push(`headers = ${generatePythonObject(headers, imports)}`);
23
+ const inputCookies = Object.entries(data.cookie);
24
+ if (inputCookies.length > 0) {
25
+ const cookies = {};
26
+ for (const [k, v] of inputCookies) cookies[k] = v.value;
27
+ params.push(`cookies = ${generatePythonObject(cookies, imports)}`);
28
+ }
29
+ return `${Array.from(imports).map((name) => "import " + name).join("\n")}
29
30
 
30
31
  url = ${JSON.stringify(url)}
31
32
  ${body ?? ""}
32
33
  response = requests.request(${params.join(", ")})
33
34
 
34
35
  print(response.text)`;
36
+ }
35
37
  };
36
38
 
37
39
  //#endregion
38
- export { generator };
40
+ export { python };
@@ -1,11 +1,6 @@
1
- import { MediaAdapter } from "./media/adapter.js";
2
1
  import { EncodedParameter, EncodedParameterMultiple } from "./media/encode.js";
3
2
 
4
3
  //#region src/requests/types.d.ts
5
- type SampleGenerator<ServerContext = unknown> = (url: string, data: RequestData, context: {
6
- mediaAdapters: Record<string, MediaAdapter>;
7
- server: ServerContext;
8
- }) => string;
9
4
  interface RawRequestData {
10
5
  method: string;
11
6
  path: Record<string, unknown>;
@@ -25,4 +20,4 @@ interface RequestData {
25
20
  bodyMediaType?: string;
26
21
  }
27
22
  //#endregion
28
- export { RawRequestData, RequestData, SampleGenerator };
23
+ export { RawRequestData, RequestData };
@@ -1,5 +1,5 @@
1
1
  import { createProxy } from "./proxy.js";
2
- import { CodeUsageGenerator } from "../ui/operation/usage-tabs/index.js";
2
+ import { InlineCodeUsageGenerator } from "../requests/generators/index.js";
3
3
  import { Document } from "../types.js";
4
4
  import { ProcessedDocument } from "../utils/process-document.js";
5
5
 
@@ -30,6 +30,9 @@ interface OpenAPIServer {
30
30
  readonly options: OpenAPIOptions;
31
31
  }
32
32
  declare function createOpenAPI(options?: OpenAPIOptions): OpenAPIServer;
33
- declare function createCodeSample<T>(options: Partial<CodeUsageGenerator<T>>): CodeUsageGenerator;
33
+ /**
34
+ * @deprecated
35
+ */
36
+ declare function createCodeSample<T>(options: InlineCodeUsageGenerator<T>): InlineCodeUsageGenerator<T>;
34
37
  //#endregion
35
38
  export { OpenAPIOptions, OpenAPIServer, createCodeSample, createOpenAPI };
@@ -30,13 +30,11 @@ function createOpenAPI(options = {}) {
30
30
  }
31
31
  };
32
32
  }
33
+ /**
34
+ * @deprecated
35
+ */
33
36
  function createCodeSample(options) {
34
- const { lang = "unknown", id = lang, ...rest } = options;
35
- return {
36
- id,
37
- lang,
38
- ...rest
39
- };
37
+ return options;
40
38
  }
41
39
 
42
40
  //#endregion
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { OpenAPIV3, OpenAPIV3_2 } from "./_openapi/types.js";
2
2
  import { NoReference } from "./utils/schema.js";
3
3
  import { MediaAdapter } from "./requests/media/adapter.js";
4
- import { CodeUsageGenerator } from "./ui/operation/usage-tabs/index.js";
4
+ import { InlineCodeUsageGenerator } from "./requests/generators/index.js";
5
5
  import { OpenAPIOptions } from "./server/create.js";
6
6
  import "./server/index.js";
7
7
  import { CreateAPIPageOptions } from "./ui/base.js";
@@ -28,11 +28,12 @@ type MediaTypeObject = OpenAPIV3_2.MediaTypeObject;
28
28
  type RequestBodyObject = OpenAPIV3_2.RequestBodyObject;
29
29
  type MethodInformation = NoReference<OperationObject> & {
30
30
  method: string;
31
- 'x-codeSamples'?: Omit<CodeUsageGenerator, 'id'>[];
31
+ 'x-codeSamples'?: InlineCodeUsageGenerator[];
32
32
  'x-selectedCodeSample'?: string;
33
33
  'x-exclusiveCodeSample'?: string;
34
34
  };
35
- interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<CreateAPIPageOptions, 'renderMarkdown'> {
35
+ type RequireKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
36
+ interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, RequireKeys<CreateAPIPageOptions, 'generateTypeScriptDefinitions' | 'renderMarkdown'> {
36
37
  slugger: Slugger;
37
38
  /**
38
39
  * dereferenced schema
@@ -40,7 +41,6 @@ interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<CreateAPI
40
41
  schema: ProcessedDocument;
41
42
  mediaAdapters: Record<string, MediaAdapter>;
42
43
  renderHeading: (depth: number, text: string, props?: HTMLAttributes<HTMLHeadingElement>) => ReactNode;
43
- renderMarkdown: (text: string) => ReactNode;
44
44
  renderCodeBlock: (lang: string, code: string) => ReactNode;
45
45
  }
46
46
  type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
package/dist/ui/base.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { NoReference } from "../utils/schema.js";
2
2
  import { MediaAdapter } from "../requests/media/adapter.js";
3
- import { CodeUsageGenerator } from "./operation/usage-tabs/index.js";
3
+ import { CodeUsageGeneratorRegistry, InlineCodeUsageGenerator } from "../requests/generators/index.js";
4
4
  import { OpenAPIServer } from "../server/create.js";
5
5
  import { ApiPageProps, OperationItem, WebhookItem } from "./api-page.js";
6
6
  import "../server/index.js";
@@ -12,6 +12,7 @@ import { Awaitable, DistributiveOmit, MethodInformation, RenderContext } from ".
12
12
  import { FC, ReactNode } from "react";
13
13
  import { CoreHighlightOptions } from "fumadocs-core/highlight/core";
14
14
  import { ResolvedShikiConfig } from "fumadocs-core/highlight/config";
15
+ import { JSONSchema } from "json-schema-typed";
15
16
 
16
17
  //#region src/ui/base.d.ts
17
18
  interface CreateAPIPageOptions {
@@ -22,14 +23,31 @@ interface CreateAPIPageOptions {
22
23
  *
23
24
  * @param method - the operation object
24
25
  * @param statusCode - status code
26
+ * @deprecated use `generateTypeScriptDefinitions` instead.
25
27
  */
26
28
  generateTypeScriptSchema?: ((method: NoReference<MethodInformation>, statusCode: string, contentType: string, ctx: RenderContext) => Awaitable<string | undefined>) | false;
29
+ /**
30
+ * Generate TypeScript definitions from JSON schema.
31
+ *
32
+ * Pass `false` to disable it.
33
+ */
34
+ generateTypeScriptDefinitions?: (schema: JSONSchema, ctx: RenderContext & {
35
+ operation: NoReference<MethodInformation>; /** @deprecated */
36
+ _internal_legacy?: {
37
+ statusCode: string;
38
+ contentType: string;
39
+ };
40
+ }) => Awaitable<string | undefined>;
41
+ /**
42
+ * Generate example code usage for endpoints.
43
+ */
44
+ codeUsages?: CodeUsageGeneratorRegistry;
27
45
  /**
28
46
  * Generate example code usage for endpoints.
29
47
  */
30
- generateCodeSamples?: (method: MethodInformation) => Awaitable<CodeUsageGenerator[]>;
48
+ generateCodeSamples?: (method: MethodInformation) => Awaitable<InlineCodeUsageGenerator[]>;
31
49
  shiki: ResolvedShikiConfig;
32
- renderMarkdown?: (md: string) => Awaitable<ReactNode>;
50
+ renderMarkdown?: (md: string) => ReactNode;
33
51
  shikiOptions?: DistributiveOmit<CoreHighlightOptions, 'config' | 'lang' | 'components'>;
34
52
  /**
35
53
  * Show full response schema instead of only example response & Typescript definitions.
@@ -58,7 +76,7 @@ interface CreateAPIPageOptions {
58
76
  /**
59
77
  * @param generators - codegens for API example usages
60
78
  */
61
- renderAPIExampleUsageTabs?: (generators: CodeUsageGenerator[], ctx: RenderContext) => Awaitable<ReactNode>;
79
+ renderAPIExampleUsageTabs?: (generators: CodeUsageGeneratorRegistry, ctx: RenderContext) => Awaitable<ReactNode>;
62
80
  /**
63
81
  * renderer of the entire page's layout (containing all operations & webhooks UI)
64
82
  */
package/dist/ui/base.js CHANGED
@@ -55,6 +55,14 @@ function createAPIPage(server, options) {
55
55
  children: text
56
56
  }, id);
57
57
  },
58
+ generateTypeScriptDefinitions(schema, ctx) {
59
+ const { generateTypeScriptSchema, generateTypeScriptDefinitions } = options;
60
+ if (generateTypeScriptSchema && ctx._internal_legacy) {
61
+ const { statusCode, contentType } = ctx._internal_legacy;
62
+ return generateTypeScriptSchema(ctx.operation, statusCode, contentType, ctx);
63
+ }
64
+ return generateTypeScriptDefinitions?.(schema, ctx);
65
+ },
58
66
  async renderMarkdown(text) {
59
67
  if (options.renderMarkdown) return options.renderMarkdown(text);
60
68
  processor ??= createMarkdownProcessor();
@@ -1,4 +1,5 @@
1
1
  import { MediaAdapter } from "../../requests/media/adapter.js";
2
+ import { CodeUsageGeneratorRegistry } from "../../requests/generators/index.js";
2
3
  import { PlaygroundClientOptions } from "../../playground/client.js";
3
4
  import { ExampleRequestItem } from "../operation/request-tabs.js";
4
5
  import { FC } from "react";
@@ -19,6 +20,10 @@ interface APIPageClientOptions {
19
20
  * Support other media types (for client-side serialization)
20
21
  */
21
22
  mediaAdapters?: Record<string, MediaAdapter>;
23
+ /**
24
+ * generate code usage examples
25
+ */
26
+ codeUsages?: CodeUsageGeneratorRegistry;
22
27
  }
23
28
  interface OperationClientOptions {
24
29
  APIExampleSelector?: FC<{
@@ -2,6 +2,8 @@
2
2
 
3
3
  import { defaultAdapters } from "../../requests/media/adapter.js";
4
4
  import { useStorageKey } from "../client/storage-key.js";
5
+ import { createCodeUsageGeneratorRegistry } from "../../requests/generators/index.js";
6
+ import { registerDefault } from "../../requests/generators/all.js";
5
7
  import { createContext, use, useEffect, useMemo, useRef, useState } from "react";
6
8
  import { jsx } from "react/jsx-runtime";
7
9
 
@@ -24,14 +26,23 @@ function useServerSelectContext() {
24
26
  }
25
27
  function ApiProvider({ children, shikiOptions, client }) {
26
28
  return /* @__PURE__ */ jsx(ApiContext, {
27
- value: useMemo(() => ({
28
- shikiOptions,
29
- client,
30
- mediaAdapters: {
31
- ...defaultAdapters,
32
- ...client.mediaAdapters
29
+ value: useMemo(() => {
30
+ let codeUsages;
31
+ if (client.codeUsages) codeUsages = createCodeUsageGeneratorRegistry(client.codeUsages);
32
+ else {
33
+ codeUsages = createCodeUsageGeneratorRegistry();
34
+ registerDefault(codeUsages);
33
35
  }
34
- }), [client, shikiOptions]),
36
+ return {
37
+ shikiOptions,
38
+ client,
39
+ codeUsages,
40
+ mediaAdapters: {
41
+ ...defaultAdapters,
42
+ ...client.mediaAdapters
43
+ }
44
+ };
45
+ }, [client, shikiOptions]),
35
46
  children
36
47
  });
37
48
  }
package/dist/ui/full.js CHANGED
@@ -9,9 +9,8 @@ function createAPIPage(server, options = {}) {
9
9
  const APIPage = createAPIPage$1(server, {
10
10
  ...options,
11
11
  shiki: configDefault,
12
- generateTypeScriptSchema(method, statusCode, contentType, ctx) {
13
- const schema = method.responses?.[statusCode]?.content?.[contentType].schema;
14
- if (!schema || typeof schema !== "object") return;
12
+ generateTypeScriptDefinitions(schema, ctx) {
13
+ if (typeof schema !== "object") return;
15
14
  return getTypescriptSchema(schema, ctx);
16
15
  }
17
16
  });
@@ -9,18 +9,22 @@ import { buttonVariants } from "fumadocs-ui/components/ui/button";
9
9
  import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
10
10
 
11
11
  //#region src/ui/operation/client.tsx
12
- function CopyResponseTypeScript({ code }) {
12
+ function CopyTypeScriptPanel({ name, code, className }) {
13
13
  const [isChecked, onCopy] = useCopyButton(() => {
14
14
  navigator.clipboard.writeText(code);
15
15
  });
16
16
  return /* @__PURE__ */ jsxs("div", {
17
- className: "flex items-start justify-between gap-2 bg-fd-card text-fd-card-foreground border rounded-xl p-3 not-prose mb-4 last:mb-0",
17
+ className: cn("flex items-start justify-between gap-2 bg-fd-card text-fd-card-foreground border rounded-xl p-3 not-prose mb-4 last:mb-0", className),
18
18
  children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
19
19
  className: "font-medium text-sm mb-2",
20
20
  children: "TypeScript Definitions"
21
- }), /* @__PURE__ */ jsx("p", {
21
+ }), /* @__PURE__ */ jsxs("p", {
22
22
  className: "text-xs text-fd-muted-foreground",
23
- children: "Use the response body type in TypeScript."
23
+ children: [
24
+ "Use the ",
25
+ name,
26
+ " type in TypeScript."
27
+ ]
24
28
  })] }), /* @__PURE__ */ jsxs("button", {
25
29
  onClick: onCopy,
26
30
  className: cn(buttonVariants({
@@ -67,4 +71,4 @@ function SelectTabTrigger({ items, className, ...props }) {
67
71
  }
68
72
 
69
73
  //#endregion
70
- export { CopyResponseTypeScript, SelectTab, SelectTabTrigger, SelectTabs };
74
+ export { CopyTypeScriptPanel, SelectTab, SelectTabTrigger, SelectTabs };
@@ -9,7 +9,7 @@ import { Schema } from "../schema/index.js";
9
9
  import { UsageTabsProviderLazy } from "./usage-tabs/lazy.js";
10
10
  import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Accordions } from "../components/accordion.js";
11
11
  import { UsageTabs } from "./usage-tabs/index.js";
12
- import { CopyResponseTypeScript, SelectTab, SelectTabTrigger, SelectTabs } from "./client.js";
12
+ import { CopyTypeScriptPanel, SelectTab, SelectTabTrigger, SelectTabs } from "./client.js";
13
13
  import { RequestTabs, getExampleRequests } from "./request-tabs.js";
14
14
  import { ServerProviderLazy } from "../contexts/api.lazy.js";
15
15
  import { Fragment } from "react";
@@ -59,11 +59,19 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
59
59
  })]
60
60
  }),
61
61
  body.description && ctx.renderMarkdown(body.description),
62
- contentTypes.map(([type, content]) => {
62
+ contentTypes.map(async ([type, content]) => {
63
63
  if (!isMediaTypeSupported(type, ctx.mediaAdapters)) throw new Error(`Media type ${type} is not supported (in ${path})`);
64
- return /* @__PURE__ */ jsx(SelectTab, {
64
+ const ts = content.schema ? await ctx.generateTypeScriptDefinitions(content.schema, {
65
+ operation: method,
66
+ ...ctx
67
+ }) : void 0;
68
+ return /* @__PURE__ */ jsxs(SelectTab, {
65
69
  value: type,
66
- children: /* @__PURE__ */ jsx(Schema, {
70
+ children: [ts && /* @__PURE__ */ jsx(CopyTypeScriptPanel, {
71
+ name: "request body",
72
+ code: ts,
73
+ className: "mt-4"
74
+ }), /* @__PURE__ */ jsx(Schema, {
67
75
  client: {
68
76
  name: "body",
69
77
  as: "body",
@@ -73,7 +81,7 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
73
81
  readOnly: method.method === "GET",
74
82
  writeOnly: method.method !== "GET",
75
83
  ctx
76
- })
84
+ })]
77
85
  }, type);
78
86
  })
79
87
  ]
@@ -319,12 +327,21 @@ async function ResponseAccordion({ status, operation, ctx }) {
319
327
  children: ctx.renderMarkdown(response.description)
320
328
  }), contentTypes.map(async ([type, resType]) => {
321
329
  const schema = resType.schema;
322
- let ts;
323
- if (ctx.generateTypeScriptSchema) ts = await ctx.generateTypeScriptSchema(operation, status, type, ctx);
330
+ const ts = schema ? await ctx.generateTypeScriptDefinitions(schema, {
331
+ operation,
332
+ _internal_legacy: {
333
+ statusCode: status,
334
+ contentType: type
335
+ },
336
+ ...ctx
337
+ }) : void 0;
324
338
  return /* @__PURE__ */ jsxs(SelectTab, {
325
339
  value: type,
326
340
  className: "mb-2",
327
- children: [ts && /* @__PURE__ */ jsx(CopyResponseTypeScript, { code: ts }), schema && /* @__PURE__ */ jsx("div", {
341
+ children: [ts && /* @__PURE__ */ jsx(CopyTypeScriptPanel, {
342
+ name: "response body",
343
+ code: ts
344
+ }), schema && /* @__PURE__ */ jsx("div", {
328
345
  className: "border px-3 py-2 rounded-lg",
329
346
  children: /* @__PURE__ */ jsx(Schema, {
330
347
  client: {