fumadocs-openapi 9.7.3 → 10.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.
Files changed (151) hide show
  1. package/dist/generate-file.d.ts +3 -4
  2. package/dist/generate-file.d.ts.map +1 -1
  3. package/dist/generate-file.js +4 -34
  4. package/dist/playground/client.d.ts +43 -22
  5. package/dist/playground/client.d.ts.map +1 -1
  6. package/dist/playground/client.js +68 -63
  7. package/dist/playground/{inputs.d.ts → components/inputs.d.ts} +1 -1
  8. package/dist/playground/components/inputs.d.ts.map +1 -0
  9. package/dist/playground/{inputs.js → components/inputs.js} +7 -7
  10. package/dist/playground/components/oauth-dialog.d.ts.map +1 -0
  11. package/dist/playground/components/server-select.d.ts.map +1 -0
  12. package/dist/{ui → playground/components}/server-select.js +6 -7
  13. package/dist/playground/index.d.ts +1 -4
  14. package/dist/playground/index.d.ts.map +1 -1
  15. package/dist/playground/index.js +5 -3
  16. package/dist/playground/lazy.d.ts +2 -0
  17. package/dist/playground/lazy.d.ts.map +1 -0
  18. package/dist/playground/lazy.js +3 -0
  19. package/dist/requests/generators/index.d.ts +2 -2
  20. package/dist/requests/generators/index.d.ts.map +1 -1
  21. package/dist/requests/generators/index.js +6 -0
  22. package/dist/requests/media/adapter.d.ts +0 -6
  23. package/dist/requests/media/adapter.d.ts.map +1 -1
  24. package/dist/scalar/client.d.ts +1 -0
  25. package/dist/scalar/client.d.ts.map +1 -1
  26. package/dist/scalar/client.js +2 -3
  27. package/dist/scalar/index.d.ts +7 -6
  28. package/dist/scalar/index.d.ts.map +1 -1
  29. package/dist/scalar/index.js +17 -1
  30. package/dist/server/create.d.ts +11 -59
  31. package/dist/server/create.d.ts.map +1 -1
  32. package/dist/server/create.js +5 -14
  33. package/dist/server/source-api.d.ts +1 -1
  34. package/dist/server/source-api.d.ts.map +1 -1
  35. package/dist/server/source-api.js +1 -1
  36. package/dist/types.d.ts +12 -4
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/ui/api-page.d.ts +145 -0
  39. package/dist/ui/api-page.d.ts.map +1 -0
  40. package/dist/ui/api-page.js +120 -0
  41. package/dist/ui/client/index.d.ts +29 -0
  42. package/dist/ui/client/index.d.ts.map +1 -0
  43. package/dist/ui/client/index.js +4 -0
  44. package/dist/ui/client/storage-key.d.ts +9 -0
  45. package/dist/ui/client/storage-key.d.ts.map +1 -0
  46. package/dist/ui/client/storage-key.js +12 -0
  47. package/dist/ui/components/method-label.d.ts +1 -1
  48. package/dist/ui/contexts/api.d.ts +12 -10
  49. package/dist/ui/contexts/api.d.ts.map +1 -1
  50. package/dist/ui/contexts/api.js +53 -37
  51. package/dist/ui/contexts/api.lazy.d.ts +2 -0
  52. package/dist/ui/contexts/api.lazy.d.ts.map +1 -0
  53. package/dist/ui/contexts/api.lazy.js +3 -0
  54. package/dist/ui/contexts/operation.d.ts +20 -0
  55. package/dist/ui/contexts/operation.d.ts.map +1 -0
  56. package/dist/ui/contexts/operation.js +48 -0
  57. package/dist/ui/contexts/operation.lazy.d.ts +2 -0
  58. package/dist/ui/contexts/operation.lazy.d.ts.map +1 -0
  59. package/dist/ui/contexts/operation.lazy.js +3 -0
  60. package/dist/ui/index.d.ts +1 -8
  61. package/dist/ui/index.d.ts.map +1 -1
  62. package/dist/ui/index.js +1 -26
  63. package/dist/ui/{select-tabs.d.ts → operation/client.d.ts} +5 -2
  64. package/dist/ui/operation/client.d.ts.map +1 -0
  65. package/dist/ui/{client.js → operation/client.js} +18 -1
  66. package/dist/ui/operation/example-panel/client.d.ts +4 -0
  67. package/dist/ui/operation/example-panel/client.d.ts.map +1 -0
  68. package/dist/ui/operation/example-panel/client.js +50 -0
  69. package/dist/ui/operation/example-panel/index.d.ts +58 -0
  70. package/dist/ui/operation/example-panel/index.d.ts.map +1 -0
  71. package/dist/ui/operation/example-panel/index.js +140 -0
  72. package/dist/ui/operation/example-panel/lazy.d.ts +3 -0
  73. package/dist/ui/operation/example-panel/lazy.d.ts.map +1 -0
  74. package/dist/ui/operation/example-panel/lazy.js +4 -0
  75. package/dist/ui/operation/get-request-data.d.ts.map +1 -0
  76. package/dist/ui/operation/index.d.ts +11 -0
  77. package/dist/ui/operation/index.d.ts.map +1 -0
  78. package/dist/{render → ui}/operation/index.js +50 -24
  79. package/dist/ui/schema/client.d.ts +11 -0
  80. package/dist/ui/schema/client.d.ts.map +1 -0
  81. package/dist/{render → ui}/schema/client.js +22 -12
  82. package/dist/{render/schema/server.d.ts → ui/schema/index.d.ts} +5 -4
  83. package/dist/ui/schema/index.d.ts.map +1 -0
  84. package/dist/{render/schema/server.js → ui/schema/index.js} +11 -5
  85. package/dist/ui/schema/lazy.d.ts +2 -0
  86. package/dist/ui/schema/lazy.d.ts.map +1 -0
  87. package/dist/ui/schema/lazy.js +3 -0
  88. package/dist/utils/get-typescript-schema.d.ts +3 -2
  89. package/dist/utils/get-typescript-schema.d.ts.map +1 -1
  90. package/dist/utils/get-typescript-schema.js +12 -7
  91. package/dist/utils/lazy.d.ts +5 -0
  92. package/dist/utils/lazy.d.ts.map +1 -0
  93. package/dist/utils/lazy.js +12 -0
  94. package/dist/utils/pages/builder.d.ts +1 -1
  95. package/dist/utils/pages/builder.d.ts.map +1 -1
  96. package/dist/utils/pages/to-body.d.ts +2 -3
  97. package/dist/utils/pages/to-body.d.ts.map +1 -1
  98. package/dist/utils/pages/to-body.js +7 -7
  99. package/dist/utils/pages/to-text.d.ts.map +1 -1
  100. package/dist/utils/process-document.d.ts +1 -0
  101. package/dist/utils/process-document.d.ts.map +1 -1
  102. package/dist/utils/process-document.js +7 -2
  103. package/package.json +20 -16
  104. package/dist/playground/auth/oauth-dialog.d.ts.map +0 -1
  105. package/dist/playground/inputs.d.ts.map +0 -1
  106. package/dist/render/api-page.d.ts +0 -33
  107. package/dist/render/api-page.d.ts.map +0 -1
  108. package/dist/render/api-page.js +0 -59
  109. package/dist/render/codeblock.d.ts +0 -9
  110. package/dist/render/codeblock.d.ts.map +0 -1
  111. package/dist/render/codeblock.js +0 -14
  112. package/dist/render/heading.d.ts +0 -4
  113. package/dist/render/heading.d.ts.map +0 -1
  114. package/dist/render/heading.js +0 -6
  115. package/dist/render/markdown.d.ts +0 -5
  116. package/dist/render/markdown.d.ts.map +0 -1
  117. package/dist/render/markdown.js +0 -31
  118. package/dist/render/operation/api-example.d.ts +0 -30
  119. package/dist/render/operation/api-example.d.ts.map +0 -1
  120. package/dist/render/operation/api-example.js +0 -103
  121. package/dist/render/operation/get-request-data.d.ts.map +0 -1
  122. package/dist/render/operation/index.d.ts +0 -27
  123. package/dist/render/operation/index.d.ts.map +0 -1
  124. package/dist/render/renderer.d.ts +0 -79
  125. package/dist/render/renderer.d.ts.map +0 -1
  126. package/dist/render/renderer.js +0 -25
  127. package/dist/render/schema/client.d.ts +0 -18
  128. package/dist/render/schema/client.d.ts.map +0 -1
  129. package/dist/render/schema/index.d.ts +0 -7
  130. package/dist/render/schema/index.d.ts.map +0 -1
  131. package/dist/render/schema/index.js +0 -11
  132. package/dist/render/schema/server.d.ts.map +0 -1
  133. package/dist/render/schema/ui.d.ts +0 -16
  134. package/dist/render/schema/ui.d.ts.map +0 -1
  135. package/dist/render/schema/ui.js +0 -14
  136. package/dist/ui/client.d.ts +0 -4
  137. package/dist/ui/client.d.ts.map +0 -1
  138. package/dist/ui/contexts/code-example.d.ts +0 -24
  139. package/dist/ui/contexts/code-example.d.ts.map +0 -1
  140. package/dist/ui/contexts/code-example.js +0 -97
  141. package/dist/ui/lazy.d.ts +0 -16
  142. package/dist/ui/lazy.d.ts.map +0 -1
  143. package/dist/ui/lazy.js +0 -22
  144. package/dist/ui/select-tabs.d.ts.map +0 -1
  145. package/dist/ui/select-tabs.js +0 -20
  146. package/dist/ui/server-select.d.ts.map +0 -1
  147. /package/dist/playground/{auth → components}/oauth-dialog.d.ts +0 -0
  148. /package/dist/playground/{auth → components}/oauth-dialog.js +0 -0
  149. /package/dist/{ui → playground/components}/server-select.d.ts +0 -0
  150. /package/dist/{render → ui}/operation/get-request-data.d.ts +0 -0
  151. /package/dist/{render → ui}/operation/get-request-data.js +0 -0
@@ -0,0 +1,140 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { getPreferredType } from '../../../utils/schema.js';
3
+ import { getRequestData } from '../../../ui/operation/get-request-data.js';
4
+ import { sample } from 'openapi-sampler';
5
+ import { defaultSamples } from '../../../requests/generators/index.js';
6
+ import { encodeRequestData } from '../../../requests/media/encode.js';
7
+ import { AccordionContent, AccordionHeader, AccordionItem, Accordions, AccordionTrigger, } from '../../../ui/components/accordion.js';
8
+ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
9
+ import { CodeBlockTab, CodeBlockTabs, CodeBlockTabsList, CodeBlockTabsTrigger, } from 'fumadocs-ui/components/codeblock';
10
+ import { APIExampleSelectorLazy, APIExampleUsageTabLazy } from './lazy.js';
11
+ export function getAPIExamples(path, method, ctx) {
12
+ const media = method.requestBody
13
+ ? getPreferredType(method.requestBody.content)
14
+ : null;
15
+ const bodyOfType = media ? method.requestBody?.content[media] : null;
16
+ if (bodyOfType?.examples) {
17
+ const result = [];
18
+ for (const [key, value] of Object.entries(bodyOfType.examples)) {
19
+ const data = getRequestData(path, method, key, ctx);
20
+ result.push({
21
+ id: key,
22
+ name: value.summary ?? key,
23
+ description: value.description,
24
+ data,
25
+ encoded: encodeRequestData(data, ctx.mediaAdapters, method.parameters ?? []),
26
+ });
27
+ }
28
+ if (result.length > 0)
29
+ return result;
30
+ }
31
+ const data = getRequestData(path, method, null, ctx);
32
+ return [
33
+ {
34
+ id: '_default',
35
+ name: 'Default',
36
+ description: bodyOfType?.schema?.description,
37
+ data,
38
+ encoded: encodeRequestData(data, ctx.mediaAdapters, method.parameters ?? []),
39
+ },
40
+ ];
41
+ }
42
+ export async function APIExample({ method, ctx, }) {
43
+ let { renderAPIExampleUsageTabs, renderAPIExampleLayout } = ctx.content ?? {};
44
+ renderAPIExampleLayout ?? (renderAPIExampleLayout = (slots) => {
45
+ return (_jsxs("div", { className: "prose-no-margin md:sticky md:top-(--fd-api-info-top) xl:w-[400px]", children: [slots.selector, slots.usageTabs, slots.responseTabs] }));
46
+ });
47
+ renderAPIExampleUsageTabs ?? (renderAPIExampleUsageTabs = (generators) => {
48
+ if (generators.length === 0)
49
+ return null;
50
+ return (_jsxs(CodeBlockTabs, { groupId: "fumadocs_openapi_requests", defaultValue: generators[0].id, children: [_jsx(CodeBlockTabsList, { children: generators.map((item) => (_jsx(CodeBlockTabsTrigger, { value: item.id, children: item.label ?? item.lang }, item.id))) }), generators.map((item) => (_jsx(CodeBlockTab, { value: item.id, children: _jsx(APIExampleUsageTabLazy, { ...item }) }, item.id)))] }));
51
+ });
52
+ let generators = [...defaultSamples];
53
+ if (ctx.generateCodeSamples) {
54
+ generators.push(...(await ctx.generateCodeSamples(method)));
55
+ }
56
+ if (method['x-codeSamples']) {
57
+ for (const sample of method['x-codeSamples']) {
58
+ generators.push('id' in sample && typeof sample.id === 'string'
59
+ ? sample
60
+ : {
61
+ id: sample.lang,
62
+ ...sample,
63
+ });
64
+ }
65
+ }
66
+ generators = dedupe(generators);
67
+ return renderAPIExampleLayout({
68
+ selector: method['x-exclusiveCodeSample'] ? null : (_jsx(APIExampleSelectorLazy, {})),
69
+ usageTabs: await renderAPIExampleUsageTabs(generators, ctx),
70
+ responseTabs: _jsx(ResponseTabs, { operation: method, ctx: ctx }),
71
+ }, ctx);
72
+ }
73
+ /**
74
+ * Remove duplicated ids
75
+ */
76
+ function dedupe(samples) {
77
+ const set = new Set();
78
+ const out = [];
79
+ for (let i = samples.length - 1; i >= 0; i--) {
80
+ const item = samples[i];
81
+ if (set.has(item.id))
82
+ continue;
83
+ set.add(item.id);
84
+ if (item.source !== false)
85
+ out.unshift(item);
86
+ }
87
+ return out;
88
+ }
89
+ function ResponseTabs({ operation, ctx, }) {
90
+ if (!operation.responses)
91
+ return null;
92
+ const tabs = [];
93
+ for (const [code, response] of Object.entries(operation.responses)) {
94
+ const media = response.content ? getPreferredType(response.content) : null;
95
+ const responseOfType = media ? response.content?.[media] : null;
96
+ const tab = {
97
+ code,
98
+ response,
99
+ mediaType: media,
100
+ };
101
+ if (responseOfType?.examples) {
102
+ tab.examples ?? (tab.examples = []);
103
+ for (const [key, sample] of Object.entries(responseOfType.examples)) {
104
+ const title = sample?.summary ?? `Example ${key}`;
105
+ tab.examples.push({
106
+ label: title,
107
+ sample: sample.value,
108
+ description: sample?.description,
109
+ });
110
+ }
111
+ }
112
+ else if (responseOfType?.example || responseOfType?.schema) {
113
+ tab.examples ?? (tab.examples = []);
114
+ tab.examples.push({
115
+ label: 'Example',
116
+ sample: responseOfType.example ?? sample(responseOfType.schema),
117
+ });
118
+ }
119
+ tabs.push(tab);
120
+ }
121
+ const { renderResponseTabs = renderResponseTabsDefault } = ctx.content ?? {};
122
+ return renderResponseTabs(tabs, ctx);
123
+ }
124
+ function renderResponseTabsDefault(tabs, ctx) {
125
+ async function renderResponse(tab) {
126
+ const { examples = [] } = tab;
127
+ let slot = 'Empty';
128
+ if (examples.length > 1) {
129
+ slot = (_jsx(Accordions, { type: "single", className: "pt-2", defaultValue: examples[0].label, children: examples.map((example, i) => (_jsxs(AccordionItem, { value: example.label, children: [_jsx(AccordionHeader, { children: _jsx(AccordionTrigger, { children: example.label }) }), _jsxs(AccordionContent, { className: "prose-no-margin", children: [example.description && ctx.renderMarkdown(example.description), ctx.renderCodeBlock('json', JSON.stringify(example.sample, null, 2))] })] }, i))) }));
130
+ }
131
+ else if (examples.length === 1) {
132
+ const example = examples[0];
133
+ slot = (_jsxs(_Fragment, { children: [example.description && ctx.renderMarkdown(example.description), ctx.renderCodeBlock('json', JSON.stringify(example.sample, null, 2))] }));
134
+ }
135
+ return _jsx(Tab, { value: tab.code, children: slot });
136
+ }
137
+ if (tabs.length === 0)
138
+ return null;
139
+ return (_jsx(Tabs, { groupId: "fumadocs_openapi_responses", items: tabs.map((tab) => tab.code), children: tabs.map(renderResponse) }));
140
+ }
@@ -0,0 +1,3 @@
1
+ export declare const APIExampleSelectorLazy: typeof import("./client.js").APIExampleSelector;
2
+ export declare const APIExampleUsageTabLazy: typeof import("./client.js").APIExampleUsageTab;
3
+ //# sourceMappingURL=lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../../../src/ui/operation/example-panel/lazy.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,8CAElC,CAAC;AAEF,eAAO,MAAM,sBAAsB,8CAElC,CAAC"}
@@ -0,0 +1,4 @@
1
+ 'use client';
2
+ import { wrapLazy } from '../../../utils/lazy.js';
3
+ export const APIExampleSelectorLazy = wrapLazy(() => import('./client.js').then((mod) => ({ default: mod.APIExampleSelector })));
4
+ export const APIExampleUsageTabLazy = wrapLazy(() => import('./client.js').then((mod) => ({ default: mod.APIExampleUsageTab })));
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-request-data.d.ts","sourceRoot":"","sources":["../../../src/ui/operation/get-request-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAIhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,iBAAiB,EACzB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,IAAI,EAAE,aAAa,GAClB,cAAc,CAwEhB"}
@@ -0,0 +1,11 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { MethodInformation, RenderContext } from '../../types.js';
3
+ export declare function Operation({ type, path, method, ctx, hasHead, headingLevel, }: {
4
+ type?: 'webhook' | 'operation';
5
+ path: string;
6
+ method: MethodInformation;
7
+ ctx: RenderContext;
8
+ hasHead?: boolean;
9
+ headingLevel?: number;
10
+ }): Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined>;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/operation/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACtE,OAAO,KAAK,EAEV,iBAAiB,EACjB,aAAa,EAEd,MAAM,SAAS,CAAC;AAqCjB,wBAAsB,SAAS,CAAC,EAC9B,IAAkB,EAClB,IAAI,EACJ,MAAM,EACN,GAAG,EACH,OAAO,EACP,YAAgB,GACjB,EAAE;IACD,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;IAEnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,kIAgQA"}
@@ -1,24 +1,24 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Fragment } from 'react';
3
3
  import { createMethod, methodKeys, } from '../../utils/schema.js';
4
4
  import { idToTitle } from '../../utils/id-to-title.js';
5
- import { Markdown } from '../markdown.js';
6
- import { heading } from '../heading.js';
7
5
  import { Schema } from '../schema/index.js';
8
- import { APIExample, APIExampleProvider, getAPIExamples, } from '../../render/operation/api-example.js';
6
+ import { APIExample, getAPIExamples } from '../../ui/operation/example-panel/index.js';
9
7
  import { MethodLabel } from '../../ui/components/method-label.js';
10
8
  import { getTypescriptSchema } from '../../utils/get-typescript-schema.js';
11
- import { CopyResponseTypeScript } from '../../ui/client.js';
12
- import { SelectTab, SelectTabs, SelectTabTrigger } from '../../ui/select-tabs.js';
9
+ import { CopyResponseTypeScript, SelectTab, SelectTabs, SelectTabTrigger, } from './client.js';
13
10
  import { AccordionContent, AccordionHeader, AccordionItem, Accordions, AccordionTrigger, } from '../../ui/components/accordion.js';
14
11
  import { isMediaTypeSupported } from '../../requests/media/adapter.js';
12
+ import { cn } from 'fumadocs-ui/utils/cn';
13
+ import { APIPlayground } from '../../playground/index.js';
14
+ import { OperationProviderLazy } from '../contexts/operation.lazy.js';
15
15
  const ParamTypes = {
16
16
  path: 'Path Parameters',
17
17
  query: 'Query Parameters',
18
18
  header: 'Header Parameters',
19
19
  cookie: 'Cookie Parameters',
20
20
  };
21
- export function Operation({ type = 'operation', path, method, ctx, hasHead, headingLevel = 2, }) {
21
+ export async function Operation({ type = 'operation', path, method, ctx, hasHead, headingLevel = 2, }) {
22
22
  const { schema: { dereferenced }, } = ctx;
23
23
  const body = method.requestBody;
24
24
  let headNode = null;
@@ -29,12 +29,12 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
29
29
  if (hasHead) {
30
30
  const title = method.summary ??
31
31
  (method.operationId ? idToTitle(method.operationId) : path);
32
- headNode = (_jsxs(_Fragment, { children: [heading(headingLevel, title, ctx), method.description ? _jsx(Markdown, { text: method.description }) : null] }));
32
+ headNode = (_jsxs(_Fragment, { children: [ctx.renderHeading(headingLevel, title), method.description && ctx.renderMarkdown(method.description)] }));
33
33
  headingLevel++;
34
34
  }
35
35
  const contentTypes = body ? Object.entries(body.content) : null;
36
36
  if (body && contentTypes && contentTypes.length > 0) {
37
- bodyNode = (_jsxs(SelectTabs, { defaultValue: contentTypes[0][0], children: [_jsxs("div", { className: "flex gap-2 items-end justify-between", children: [heading(headingLevel, 'Request Body', ctx), _jsx(SelectTabTrigger, { items: contentTypes.map((v) => v[0]), className: "mb-4" })] }), body.description && _jsx(Markdown, { text: body.description }), contentTypes.map(([type, content]) => {
37
+ bodyNode = (_jsxs(SelectTabs, { defaultValue: contentTypes[0][0], children: [_jsxs("div", { className: "flex gap-2 items-end justify-between", children: [ctx.renderHeading(headingLevel, 'Request Body'), _jsx(SelectTabTrigger, { items: contentTypes.map((v) => v[0]), className: "mb-4" })] }), body.description && ctx.renderMarkdown(body.description), contentTypes.map(([type, content]) => {
38
38
  if (!isMediaTypeSupported(type, ctx.mediaAdapters)) {
39
39
  throw new Error(`Media type ${type} is not supported (in ${path})`);
40
40
  }
@@ -43,13 +43,13 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
43
43
  }
44
44
  if (method.responses && ctx.showResponseSchema !== false) {
45
45
  const statuses = Object.keys(method.responses);
46
- responseNode = (_jsxs(_Fragment, { children: [heading(headingLevel, 'Response Body', ctx), _jsx(Accordions, { type: "multiple", children: statuses.map((status) => (_jsx(AccordionItem, { value: status, children: _jsx(ResponseAccordion, { status: status, operation: method, ctx: ctx }) }, status))) })] }));
46
+ responseNode = (_jsxs(_Fragment, { children: [ctx.renderHeading(headingLevel, 'Response Body'), _jsx(Accordions, { type: "multiple", children: statuses.map((status) => (_jsx(AccordionItem, { value: status, children: _jsx(ResponseAccordion, { status: status, operation: method, ctx: ctx }) }, status))) })] }));
47
47
  }
48
48
  const parameterNode = Object.entries(ParamTypes).map(([type, title]) => {
49
49
  const params = method.parameters?.filter((param) => param.in === type);
50
50
  if (!params || params.length === 0)
51
51
  return;
52
- return (_jsxs(Fragment, { children: [heading(headingLevel, title, ctx), _jsx("div", { className: "flex flex-col", children: params.map((param) => (_jsx(Schema, { name: param.name, root: {
52
+ return (_jsxs(Fragment, { children: [ctx.renderHeading(headingLevel, title), _jsx("div", { className: "flex flex-col", children: params.map((param) => (_jsx(Schema, { name: param.name, root: {
53
53
  ...param.schema,
54
54
  description: param.description ?? param.schema?.description,
55
55
  deprecated: (param.deprecated ?? false) ||
@@ -60,7 +60,7 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
60
60
  if (type === 'operation' && securities.length > 0) {
61
61
  const securitySchemes = dereferenced.components?.securitySchemes;
62
62
  const names = securities.map((security) => Object.keys(security).join(' & '));
63
- authNode = (_jsxs(SelectTabs, { defaultValue: names[0], children: [_jsxs("div", { className: "flex items-end justify-between gap-2", children: [heading(headingLevel, 'Authorization', ctx), _jsx(SelectTabTrigger, { items: names, className: "mb-4" })] }), securities.map((security, i) => (_jsx(SelectTab, { value: names[i], children: Object.entries(security).map(([key, scopes]) => {
63
+ authNode = (_jsxs(SelectTabs, { defaultValue: names[0], children: [_jsxs("div", { className: "flex items-end justify-between gap-2", children: [ctx.renderHeading(headingLevel, 'Authorization'), _jsx(SelectTabTrigger, { items: names, className: "mb-4" })] }), securities.map((security, i) => (_jsx(SelectTab, { value: names[i], children: Object.entries(security).map(([key, scopes]) => {
64
64
  const scheme = securitySchemes?.[key];
65
65
  if (!scheme)
66
66
  return;
@@ -69,29 +69,52 @@ export function Operation({ type = 'operation', path, method, ctx, hasHead, head
69
69
  }
70
70
  if (method.callbacks) {
71
71
  const callbacks = Object.entries(method.callbacks);
72
- callbacksNode = (_jsxs(SelectTabs, { defaultValue: callbacks[0][0], children: [_jsxs("div", { className: "flex justify-between gap-2 items-end", children: [heading(headingLevel, 'Callbacks', ctx), _jsx(SelectTabTrigger, { items: callbacks.map((v) => v[0]), className: "mb-4" })] }), callbacks.map(([name, callback]) => (_jsx(SelectTab, { value: name, children: _jsx(WebhookCallback, { callback: callback, ctx: ctx, headingLevel: headingLevel }) }, name)))] }));
72
+ callbacksNode = (_jsxs(SelectTabs, { defaultValue: callbacks[0][0], children: [_jsxs("div", { className: "flex justify-between gap-2 items-end", children: [ctx.renderHeading(headingLevel, 'Callbacks'), _jsx(SelectTabTrigger, { items: callbacks.map((v) => v[0]), className: "mb-4" })] }), callbacks.map(([name, callback]) => (_jsx(SelectTab, { value: name, children: _jsx(WebhookCallback, { callback: callback, ctx: ctx, headingLevel: headingLevel }) }, name)))] }));
73
73
  }
74
- const info = (_jsxs(ctx.renderer.APIInfo, { head: headNode, method: method.method, route: path, children: [type === 'operation' ? (ctx.disablePlayground ? (_jsxs("div", { className: "flex flex-row items-center gap-2.5 p-3 rounded-xl border bg-fd-card text-fd-card-foreground not-prose", children: [_jsx(MethodLabel, { className: "text-xs", children: method.method }), _jsx("code", { className: "flex-1 overflow-auto text-nowrap text-[13px] text-fd-muted-foreground", children: path })] })) : (_jsx(ctx.renderer.APIPlayground, { path: path, method: method, ctx: ctx }))) : null, authNode, parameterNode, bodyNode, responseNode, callbacksNode] }));
74
+ let { renderOperationLayout, renderWebhookLayout } = ctx.content ?? {};
75
75
  if (type === 'operation') {
76
- const examples = getAPIExamples(path, method, ctx);
77
- return (_jsx(ctx.renderer.API, { children: _jsxs(APIExampleProvider, { route: path, examples: examples, method: method, children: [info, _jsx(APIExample, { examples: examples, method: method, ctx: ctx })] }) }));
76
+ renderOperationLayout ?? (renderOperationLayout = (slots) => {
77
+ return (_jsxs("div", { className: "flex flex-col gap-x-6 gap-y-4 xl:flex-row xl:items-start", style: {
78
+ '--fd-api-info-top': 'calc(12px + var(--fd-nav-height) + var(--fd-banner-height) + var(--fd-tocnav-height, 0px))',
79
+ }, children: [_jsxs("div", { className: "min-w-0 flex-1", children: [slots.header, slots.apiPlayground, slots.authSchemes, slots.paremeters, slots.body, slots.responses, slots.callbacks] }), slots.apiExample] }));
80
+ });
81
+ const playgroundEnabled = ctx.playground?.enabled ?? true;
82
+ const content = await renderOperationLayout({
83
+ header: headNode,
84
+ authSchemes: authNode,
85
+ body: bodyNode,
86
+ callbacks: callbacksNode,
87
+ paremeters: parameterNode,
88
+ responses: responseNode,
89
+ apiPlayground: playgroundEnabled ? (_jsx(APIPlayground, { path: path, method: method, ctx: ctx })) : (_jsxs("div", { className: "flex flex-row items-center gap-2.5 p-3 rounded-xl border bg-fd-card text-fd-card-foreground not-prose", children: [_jsx(MethodLabel, { className: "text-xs", children: method.method }), _jsx("code", { className: "flex-1 overflow-auto text-nowrap text-[13px] text-fd-muted-foreground", children: path })] })),
90
+ apiExample: _jsx(APIExample, { method: method, ctx: ctx }),
91
+ }, ctx, method);
92
+ return (_jsx(OperationProviderLazy, { defaultExampleId: method['x-exclusiveCodeSample'] ?? method['x-selectedCodeSample'], route: path, examples: getAPIExamples(path, method, ctx), children: content }));
78
93
  }
79
94
  else {
80
- return info;
95
+ renderWebhookLayout ?? (renderWebhookLayout = (slots) => (_jsxs("div", { children: [slots.header, slots.authSchemes, slots.paremeters, slots.body, slots.responses, slots.callbacks] })));
96
+ return renderWebhookLayout({
97
+ header: headNode,
98
+ authSchemes: authNode,
99
+ body: bodyNode,
100
+ callbacks: callbacksNode,
101
+ paremeters: parameterNode,
102
+ responses: responseNode,
103
+ });
81
104
  }
82
105
  }
83
106
  async function ResponseAccordion({ status, operation, ctx, }) {
84
107
  const response = operation.responses[status];
85
108
  const { generateTypeScriptSchema } = ctx;
86
109
  const contentTypes = response.content ? Object.entries(response.content) : [];
87
- return (_jsxs(SelectTabs, { defaultValue: contentTypes.at(0)?.[0], children: [_jsxs(AccordionHeader, { children: [_jsx(AccordionTrigger, { className: "font-mono", children: status }), contentTypes.length > 1 && (_jsx(SelectTabTrigger, { items: contentTypes.map((v) => v[0]) })), contentTypes.length === 1 && (_jsx("p", { className: "text-[13px] text-fd-muted-foreground", children: contentTypes[0][0] }))] }), _jsxs(AccordionContent, { className: "ps-4.5", children: [response.description && (_jsx("div", { className: "prose-no-margin", children: _jsx(Markdown, { text: response.description }) })), contentTypes?.map(async ([type, resType]) => {
110
+ return (_jsxs(SelectTabs, { defaultValue: contentTypes.at(0)?.[0], children: [_jsxs(AccordionHeader, { children: [_jsx(AccordionTrigger, { className: "font-mono", children: status }), contentTypes.length > 1 && (_jsx(SelectTabTrigger, { items: contentTypes.map((v) => v[0]) })), contentTypes.length === 1 && (_jsx("p", { className: "text-[13px] text-fd-muted-foreground", children: contentTypes[0][0] }))] }), _jsxs(AccordionContent, { className: "ps-4.5", children: [response.description && (_jsx("div", { className: "prose-no-margin", children: ctx.renderMarkdown(response.description) })), contentTypes?.map(async ([type, resType]) => {
88
111
  const schema = resType.schema;
89
112
  let ts;
90
113
  if (generateTypeScriptSchema) {
91
114
  ts = await generateTypeScriptSchema(operation, status);
92
115
  }
93
116
  else if (generateTypeScriptSchema === undefined && schema) {
94
- ts = await getTypescriptSchema(ctx.schema);
117
+ ts = await getTypescriptSchema(schema, ctx);
95
118
  }
96
119
  return (_jsxs(SelectTab, { value: type, className: "my-2", children: [ts && _jsx(CopyResponseTypeScript, { code: ts }), schema && (_jsx("div", { className: "border px-3 py-2 rounded-lg", children: _jsx(Schema, { name: "response", root: schema, as: "body", readOnly: true, ctx: ctx }) }))] }, type));
97
120
  })] })] }));
@@ -108,17 +131,20 @@ function WebhookCallback({ callback, ctx, headingLevel, }) {
108
131
  return (_jsxs(AccordionItem, { value: path, children: [_jsx(AccordionHeader, { children: _jsx(AccordionTrigger, { className: "font-mono", children: path }) }), _jsx(AccordionContent, { children: pathNodes })] }, path));
109
132
  }) }));
110
133
  }
111
- function AuthScheme({ scheme: schema, scopes, ctx: { renderer }, }) {
134
+ function AuthScheme({ scheme: schema, scopes, ctx, }) {
112
135
  const scopeElement = scopes.length > 0 ? (_jsxs("p", { children: ["Scope: ", _jsx("code", { children: scopes.join(', ') })] })) : null;
113
136
  if (schema.type === 'http' || schema.type === 'oauth2') {
114
- return (_jsxs(renderer.Property, { name: "Authorization", type: schema.type === 'http' && schema.scheme === 'basic'
137
+ return (_jsxs(AuthProperty, { name: "Authorization", type: schema.type === 'http' && schema.scheme === 'basic'
115
138
  ? `Basic <token>`
116
- : 'Bearer <token>', required: true, children: [schema.description && _jsx(Markdown, { text: schema.description }), _jsxs("p", { children: ["In: ", _jsx("code", { children: "header" })] }), scopeElement] }));
139
+ : 'Bearer <token>', children: [schema.description && ctx.renderMarkdown(schema.description), _jsxs("p", { children: ["In: ", _jsx("code", { children: "header" })] }), scopeElement] }));
117
140
  }
118
141
  if (schema.type === 'apiKey') {
119
- return (_jsxs(renderer.Property, { name: schema.name, type: "<token>", children: [schema.description && _jsx(Markdown, { text: schema.description }), _jsxs("p", { children: ["In: ", _jsx("code", { children: schema.in }), scopeElement] })] }));
142
+ return (_jsxs(AuthProperty, { name: schema.name, type: "<token>", children: [schema.description && ctx.renderMarkdown(schema.description), _jsxs("p", { children: ["In: ", _jsx("code", { children: schema.in }), scopeElement] })] }));
120
143
  }
121
144
  if (schema.type === 'openIdConnect') {
122
- return (_jsxs(renderer.Property, { name: "OpenID Connect", type: "<token>", required: true, children: [schema.description && _jsx(Markdown, { text: schema.description }), scopeElement] }));
145
+ return (_jsxs(AuthProperty, { name: "OpenID Connect", type: "<token>", children: [schema.description && ctx.renderMarkdown(schema.description), scopeElement] }));
123
146
  }
124
147
  }
148
+ function AuthProperty({ name, type, ...props }) {
149
+ return (_jsxs("div", { className: cn('text-sm border-t py-4 first:border-t-0', props.className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3 not-prose", children: [_jsx("span", { className: "font-medium font-mono text-fd-primary", children: name }), _jsx("span", { className: "text-sm font-mono text-fd-muted-foreground", children: type })] }), _jsx("div", { className: "prose-no-margin pt-2.5 empty:hidden", children: props.children })] }));
150
+ }
@@ -0,0 +1,11 @@
1
+ import type { SchemaUIGeneratedData } from '../../ui/schema/index.js';
2
+ export interface SchemaUIProps {
3
+ name: string;
4
+ required?: boolean;
5
+ as?: 'property' | 'body';
6
+ readOnly?: boolean;
7
+ writeOnly?: boolean;
8
+ generated: SchemaUIGeneratedData;
9
+ }
10
+ export declare function SchemaUI({ name, required, as, generated, readOnly, writeOnly, }: SchemaUIProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/ui/schema/client.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAc,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAuDrE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAEzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,QAAgB,EAChB,EAAe,EACf,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE,aAAa,2CA2Bf"}
@@ -2,7 +2,10 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { createContext, Fragment, use, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
4
4
  import { Tabs, TabsContent, TabsList, TabsTrigger, } from 'fumadocs-ui/components/tabs';
5
- import { ObjectCollapsible, Property } from './ui.js';
5
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from 'fumadocs-ui/components/ui/collapsible';
6
+ import { buttonVariants } from 'fumadocs-ui/components/ui/button';
7
+ import { ChevronDown } from '../../icons.js';
8
+ import { Badge } from '../../ui/components/method-label.js';
6
9
  import { Popover, PopoverContent, PopoverTrigger, } from 'fumadocs-ui/components/ui/popover';
7
10
  import { cn } from 'fumadocs-ui/utils/cn';
8
11
  import { cva } from 'class-variance-authority';
@@ -17,24 +20,23 @@ const PropertyContext = createContext({
17
20
  renderRef: (props) => _jsx(RootRef, { ...props }),
18
21
  });
19
22
  const DataContext = createContext(null);
20
- export function SchemaUIProvider(props) {
21
- return _jsx(DataContext, { value: props.value, children: props.children });
22
- }
23
23
  function useData() {
24
24
  return use(DataContext);
25
25
  }
26
26
  function useProperty() {
27
27
  return use(PropertyContext);
28
28
  }
29
- export function SchemaUI({ name, required = false, as = 'property', }) {
30
- const { $root, refs } = useData();
31
- const schema = refs[$root];
32
- if (as === 'property' || !isExpandable(schema)) {
33
- return (_jsx(SchemaUIProperty, { name: name, "$type": $root, overrides: {
29
+ export function SchemaUI({ name, required = false, as = 'property', generated, readOnly, writeOnly, }) {
30
+ const schema = generated.refs[generated.$root];
31
+ const context = useMemo(() => ({
32
+ ...generated,
33
+ readOnly,
34
+ writeOnly,
35
+ }), [generated, readOnly, writeOnly]);
36
+ const isProperty = as === 'property' || !isExpandable(schema);
37
+ return (_jsx(DataContext, { value: context, children: isProperty ? (_jsx(SchemaUIProperty, { name: name, "$type": generated.$root, overrides: {
34
38
  required,
35
- } }));
36
- }
37
- return _jsx(SchemaUIContent, { "$type": $root });
39
+ } })) : (_jsx(SchemaUIContent, { "$type": generated.$root })) }));
38
40
  }
39
41
  function SchemaUIContent({ $type }) {
40
42
  const { refs, readOnly, writeOnly } = useData();
@@ -134,6 +136,14 @@ function LinkRef({ $ref, pathName, onInsert, text, }) {
134
136
  onInsert(pathName, $ref);
135
137
  }, children: text }));
136
138
  }
139
+ function ObjectCollapsible(props) {
140
+ return (_jsxs(Collapsible, { className: "my-2", ...props, children: [_jsxs(CollapsibleTrigger, { className: cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'group px-3 py-2 data-[state=open]:rounded-b-none'), children: [props.name, _jsx(ChevronDown, { className: "size-4 text-fd-muted-foreground group-data-[state=open]:rotate-180" })] }), _jsx(CollapsibleContent, { className: "-mt-px *:bg-fd-card", children: props.children })] }));
141
+ }
142
+ function Property({ name, type, required, deprecated, nested = false, ...props }) {
143
+ return (_jsxs("div", { className: cn('text-sm border-t', nested
144
+ ? 'p-3 border-x bg-fd-card last:rounded-b-xl first:rounded-tr-xl last:border-b'
145
+ : 'py-4 first:border-t-0', props.className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3 not-prose", children: [_jsxs("span", { className: "font-medium font-mono text-fd-primary", children: [name, required === false && (_jsx("span", { className: "text-fd-muted-foreground", children: "?" }))] }), typeof type === 'string' ? (_jsx("span", { className: "text-sm font-mono text-fd-muted-foreground", children: type })) : (type), deprecated && (_jsx(Badge, { color: "yellow", className: "ms-auto text-xs", children: "Deprecated" }))] }), _jsx("div", { className: "prose-no-margin pt-2.5 empty:hidden", children: props.children })] }));
146
+ }
137
147
  function isExpandable(schema) {
138
148
  return schema.type !== 'primitive';
139
149
  }
@@ -1,6 +1,7 @@
1
- import { type ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
2
  import type { ResolvedSchema } from '../../utils/schema.js';
3
3
  import type { RenderContext } from '../../types.js';
4
+ import type { SchemaUIProps } from '../../ui/schema/client.js';
4
5
  export interface FieldBase {
5
6
  description?: ReactNode;
6
7
  infoTags?: ReactNode[];
@@ -35,9 +36,9 @@ export interface SchemaUIOptions {
35
36
  root: ResolvedSchema;
36
37
  ctx: RenderContext;
37
38
  }
38
- export interface SchemaUIData {
39
+ export interface SchemaUIGeneratedData {
39
40
  $root: string;
40
41
  refs: Record<string, SchemaData>;
41
42
  }
42
- export declare function generateSchemaUI({ ctx, root }: SchemaUIOptions): SchemaUIData;
43
- //# sourceMappingURL=server.d.ts.map
43
+ export declare function Schema({ ctx, root, ...props }: SchemaUIOptions & Omit<SchemaUIProps, 'generated'>): string | number | bigint | boolean | Iterable<ReactNode> | Promise<ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/schema/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,MAAM,WAAW,SAAS;IACxB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IAEvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAChC,CACI;IACE,IAAI,EAAE,WAAW,CAAC;CACnB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,OAAO,CAAC;KACnB,EAAE,CAAC;CACL,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH,GACD;IACE,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL,CACJ,CAAC;AAEJ,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,aAAa,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAClC;AAED,wBAAgB,MAAM,CAAC,EACrB,GAAG,EACH,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,eAAe,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,8IAQpD"}
@@ -1,10 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { FormatFlags, schemaToString } from '../../utils/schema-to-string.js';
3
- import { Markdown } from '../../render/markdown.js';
4
3
  import { combineSchema } from '../../utils/combine-schema.js';
5
- export function generateSchemaUI({ ctx, root }) {
4
+ import { SchemaUILazy } from '../../ui/schema/lazy.js';
5
+ export function Schema({ ctx, root, ...props }) {
6
+ if (ctx.schemaUI?.render) {
7
+ return ctx.schemaUI.render({ root, ...props }, ctx);
8
+ }
9
+ return (_jsx(SchemaUILazy, { ...props, generated: generateSchemaUI({ ctx, root }) }));
10
+ }
11
+ function generateSchemaUI({ ctx, root, }) {
6
12
  const refs = {};
7
- const { content: { showExampleInFields = false } = {} } = ctx;
13
+ const { showExample = false } = ctx.schemaUI ?? {};
8
14
  function generateInfoTags(schema) {
9
15
  const fields = [];
10
16
  function field(key, value) {
@@ -37,7 +43,7 @@ export function generateSchemaUI({ ctx, root }) {
37
43
  if (schema.enum) {
38
44
  fields.push(field('Value in', schema.enum.map((value) => JSON.stringify(value)).join(' | ')));
39
45
  }
40
- if (showExampleInFields && schema.examples) {
46
+ if (showExample && schema.examples) {
41
47
  for (const example of schema.examples) {
42
48
  fields.push(field('Example', JSON.stringify(example, null, 2)));
43
49
  }
@@ -68,7 +74,7 @@ export function generateSchemaUI({ ctx, root }) {
68
74
  };
69
75
  }
70
76
  return {
71
- description: schema.description && _jsx(Markdown, { text: schema.description }),
77
+ description: schema.description && ctx.renderMarkdown(schema.description),
72
78
  infoTags: generateInfoTags(schema),
73
79
  typeName: schemaToString(schema, ctx.schema),
74
80
  aliasName: schemaToString(schema, ctx.schema, FormatFlags.UseAlias),
@@ -0,0 +1,2 @@
1
+ export declare const SchemaUILazy: typeof import("./client.js").SchemaUI;
2
+ //# sourceMappingURL=lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../../src/ui/schema/lazy.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,oCAExB,CAAC"}
@@ -0,0 +1,3 @@
1
+ 'use client';
2
+ import { wrapLazy } from '../../utils/lazy.js';
3
+ export const SchemaUILazy = wrapLazy(() => import('./client.js').then((mod) => ({ default: mod.SchemaUI })));
@@ -1,3 +1,4 @@
1
- import type { ProcessedDocument } from '../utils/process-document.js';
2
- export declare function getTypescriptSchema(processed: ProcessedDocument): Promise<string | undefined>;
1
+ import type { SchemaObject } from 'ajv';
2
+ import type { RenderContext } from '../types.js';
3
+ export declare function getTypescriptSchema(schema: SchemaObject, ctx: RenderContext): Promise<string | undefined>;
3
4
  //# sourceMappingURL=get-typescript-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-typescript-schema.d.ts","sourceRoot":"","sources":["../../src/utils/get-typescript-schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAY7B"}
1
+ {"version":3,"file":"get-typescript-schema.d.ts","sourceRoot":"","sources":["../../src/utils/get-typescript-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAsB7B"}
@@ -1,12 +1,17 @@
1
- import { compile } from '@fumari/json-schema-to-typescript';
2
- export async function getTypescriptSchema(processed) {
1
+ export async function getTypescriptSchema(schema, ctx) {
2
+ const { compile } = await import('@fumari/json-schema-to-typescript');
3
3
  try {
4
- const cloned = structuredClone(processed.bundled);
5
- return await compile(cloned, 'Response', {
6
- $refOptions: false,
7
- bannerComment: '',
8
- additionalProperties: false,
4
+ const input = structuredClone({
5
+ schema,
6
+ idToSchema: ctx.schema._internal_idToSchema(),
7
+ });
8
+ const schemaToId = new WeakMap();
9
+ for (const [k, v] of input.idToSchema) {
10
+ schemaToId.set(v, k);
11
+ }
12
+ return await compile(input.schema, 'Response', {
9
13
  enableConstEnums: false,
14
+ schemaToId,
10
15
  });
11
16
  }
12
17
  catch (e) {
@@ -0,0 +1,5 @@
1
+ import { type ComponentType } from 'react';
2
+ export declare function wrapLazy<T extends ComponentType<any>>(load: () => Promise<{
3
+ default: T;
4
+ }>): T;
5
+ //# sourceMappingURL=lazy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/utils/lazy.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAQ,MAAM,OAAO,CAAC;AAMjD,wBAAgB,QAAQ,CAAC,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EACnD,IAAI,EAAE,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC,GAClC,CAAC,CAMH"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { lazy } from 'react';
3
+ // Waku wraps all export functions of a "use client" file in `React.lazy`, but `lazy(lazy(() => ...))` causes error.
4
+ // we wrap another layer of component such that it is valid
5
+ // TODO: perhaps we can remove it once Waku migrated to vite-rsc
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- type infer
7
+ export function wrapLazy(load) {
8
+ const V = lazy(load);
9
+ return function wrapper(props) {
10
+ return _jsx(V, { ...props });
11
+ };
12
+ }
@@ -1,6 +1,6 @@
1
1
  import type { ProcessedDocument } from '../../utils/process-document.js';
2
2
  import type { OpenAPIServer } from '../../server/index.js';
3
- import type { OperationItem, WebhookItem } from '../../render/api-page.js';
3
+ import type { OperationItem, WebhookItem } from '../../ui/api-page.js';
4
4
  import type { OperationObject, PathItemObject, TagObject } from '../../types.js';
5
5
  import { type NoReference } from '../../utils/schema.js';
6
6
  interface BaseEntry {
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/utils/pages/builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/utils/pages/builder.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,4 @@
1
- import type { ApiPageProps } from '../../render/api-page.js';
2
- import type { OpenAPIServer } from '../../server/index.js';
1
+ import type { ApiPageProps } from '../../ui/api-page.js';
3
2
  import type { OutputEntry } from '../../utils/pages/builder.js';
4
- export declare function toBody(server: OpenAPIServer, entry: OutputEntry): ApiPageProps;
3
+ export declare function toBody(entry: OutputEntry): ApiPageProps;
5
4
  //# sourceMappingURL=to-body.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"to-body.d.ts","sourceRoot":"","sources":["../../../src/utils/pages/to-body.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,wBAAgB,MAAM,CACpB,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,WAAW,GACjB,YAAY,CAoBd"}
1
+ {"version":3,"file":"to-body.d.ts","sourceRoot":"","sources":["../../../src/utils/pages/to-body.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CAoBvD"}