fumadocs-openapi 11.4.3 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/css/preset.css +0 -1
  3. package/dist/_virtual/_rolldown/runtime.js +10 -1
  4. package/dist/generate-file.d.ts +2 -2
  5. package/dist/generate-file.js +1 -1
  6. package/dist/i18n.d.ts +6 -8
  7. package/dist/i18n.js +2 -17
  8. package/dist/index.browser.d.ts +13 -0
  9. package/dist/index.browser.js +11 -0
  10. package/dist/index.d.ts +5 -2
  11. package/dist/index.js +3 -1
  12. package/dist/operation.d.ts +133 -0
  13. package/dist/operation.js +296 -0
  14. package/dist/packages/shared-api/dist/.translations/index.d.ts +29 -0
  15. package/dist/packages/shared-api/dist/.translations/keys.js +28 -0
  16. package/dist/packages/shared-api/dist/auto-anchor/client.js +20 -0
  17. package/dist/packages/shared-api/dist/auto-anchor/index.js +17 -0
  18. package/dist/packages/shared-api/dist/codegen.d.ts +42 -0
  19. package/dist/packages/shared-api/dist/codegen.js +35 -0
  20. package/dist/packages/shared-api/dist/components/accordion.js +71 -0
  21. package/dist/packages/shared-api/dist/components/badge.js +21 -0
  22. package/dist/packages/shared-api/dist/components/collapsible.d.ts +7 -0
  23. package/dist/packages/shared-api/dist/components/collapsible.js +16 -0
  24. package/dist/packages/shared-api/dist/components/defaults.d.ts +20 -0
  25. package/dist/packages/shared-api/dist/components/defaults.js +70 -0
  26. package/dist/packages/shared-api/dist/components/dialog.js +55 -0
  27. package/dist/packages/shared-api/dist/components/input.js +14 -0
  28. package/dist/packages/shared-api/dist/components/label.js +11 -0
  29. package/dist/packages/shared-api/dist/components/playground/inputs.js +439 -0
  30. package/dist/packages/shared-api/dist/components/playground/schema.js +112 -0
  31. package/dist/packages/shared-api/dist/components/popover.js +23 -0
  32. package/dist/packages/shared-api/dist/components/schema/client.d.ts +12 -0
  33. package/dist/packages/shared-api/dist/components/schema/client.js +508 -0
  34. package/dist/packages/shared-api/dist/components/schema/index.d.ts +9 -0
  35. package/dist/packages/shared-api/dist/components/schema/index.js +28 -0
  36. package/dist/packages/shared-api/dist/components/select-tab.js +54 -0
  37. package/dist/packages/shared-api/dist/components/select.js +70 -0
  38. package/dist/packages/shared-api/dist/components/spinner.js +14 -0
  39. package/dist/packages/shared-api/dist/i18n.d.ts +3 -0
  40. package/dist/packages/shared-api/dist/i18n.js +7 -0
  41. package/dist/packages/shared-api/dist/utils/cn.js +2 -0
  42. package/dist/packages/shared-api/dist/utils/id-to-title.js +12 -0
  43. package/dist/packages/shared-api/dist/utils/is-plain-object.js +8 -0
  44. package/dist/packages/shared-api/dist/utils/merge-refs.js +11 -0
  45. package/dist/packages/shared-api/dist/utils/url.js +13 -0
  46. package/dist/{utils → packages/shared-api/dist/utils}/use-query.js +2 -1
  47. package/dist/packages/shared-api/dist/utils/use-server-store.js +56 -0
  48. package/dist/playground/auth.d.ts +37 -0
  49. package/dist/playground/auth.js +216 -21
  50. package/dist/playground/fetcher.d.ts +11 -1
  51. package/dist/playground/index.d.ts +3 -0
  52. package/dist/playground/index.js +3 -0
  53. package/dist/requests/generators/index.d.ts +4 -4
  54. package/dist/requests/generators/index.js +2 -2
  55. package/dist/requests/index.d.ts +4 -0
  56. package/dist/requests/index.js +3 -0
  57. package/dist/requests/media/adapter.d.ts +1 -0
  58. package/dist/requests/media/encode.d.ts +7 -2
  59. package/dist/requests/media/resolve-adapter.d.ts +20 -0
  60. package/dist/server/index.d.ts +4 -7
  61. package/dist/server/index.js +1 -7
  62. package/dist/types.d.ts +0 -14
  63. package/dist/ui/base.d.ts +3 -2
  64. package/dist/ui/base.js +15 -166
  65. package/dist/ui/components/codeblock.js +3 -10
  66. package/dist/ui/components/heading.js +10 -19
  67. package/dist/ui/components/markdown.js +4 -6
  68. package/dist/ui/components/method-label.js +2 -17
  69. package/dist/ui/components/schema.js +28 -0
  70. package/dist/ui/index.d.ts +7 -198
  71. package/dist/ui/index.js +1 -3
  72. package/dist/ui/operation/index.js +142 -229
  73. package/dist/ui/operation/request-tabs.js +15 -23
  74. package/dist/ui/operation/response-tabs.js +9 -53
  75. package/dist/ui/operation/usage-tabs.js +35 -93
  76. package/dist/{playground → ui/playground}/client.d.ts +10 -21
  77. package/dist/ui/playground/client.js +432 -0
  78. package/dist/{playground → ui/playground}/components/oauth-dialog.js +26 -91
  79. package/dist/{playground → ui/playground}/components/result-display.d.ts +2 -2
  80. package/dist/{playground → ui/playground}/components/result-display.js +7 -7
  81. package/dist/{playground → ui/playground}/components/server-select.js +12 -13
  82. package/dist/{playground → ui/playground}/status-info.js +2 -2
  83. package/dist/{scalar → ui/scalar}/client.js +7 -5
  84. package/dist/{scalar → ui/scalar}/index.d.ts +2 -2
  85. package/dist/{scalar → ui/scalar}/index.js +3 -7
  86. package/dist/utils/create-page.d.ts +216 -0
  87. package/dist/utils/create-page.js +221 -0
  88. package/dist/utils/document/dereference.d.ts +2 -2
  89. package/dist/utils/document/dereference.js +8 -3
  90. package/dist/utils/document/load.js +2 -2
  91. package/dist/utils/get-example-requests.js +11 -13
  92. package/dist/utils/pages/builder.d.ts +15 -2
  93. package/dist/utils/pages/builder.js +6 -6
  94. package/dist/utils/pages/preset-auto.d.ts +1 -1
  95. package/dist/utils/pages/preset-auto.js +3 -3
  96. package/dist/utils/pages/to-static-data.js +4 -4
  97. package/dist/utils/pages/to-text.d.ts +1 -1
  98. package/dist/utils/pages/to-text.js +3 -5
  99. package/dist/utils/schema.js +5 -5
  100. package/dist/utils/use-server.d.ts +24 -0
  101. package/dist/utils/use-server.js +57 -0
  102. package/package.json +28 -20
  103. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js +0 -508
  104. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js +0 -152
  105. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js +0 -61
  106. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +0 -25
  107. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +0 -15
  108. package/dist/playground/client.js +0 -574
  109. package/dist/ui/contexts/api.d.ts +0 -17
  110. package/dist/ui/contexts/api.js +0 -84
  111. package/dist/ui/create-client.d.ts +0 -9
  112. package/dist/ui/create-client.js +0 -7
  113. package/dist/ui/operation/context.d.ts +0 -15
  114. package/dist/ui/operation/context.js +0 -48
  115. package/dist/ui/operation/request-tabs.d.ts +0 -12
  116. package/dist/ui/operation/response-tabs.d.ts +0 -30
  117. package/dist/utils/get-example-requests.d.ts +0 -11
  118. package/dist/utils/schema.d.ts +0 -3
  119. package/dist/utils/storage-key.js +0 -15
@@ -1,18 +1,18 @@
1
1
  "use client";
2
- import { useServerContext } from "../../ui/contexts/api.js";
3
- import { cn } from "../../utils/cn.js";
2
+ import { useServer } from "../../../utils/use-server.js";
3
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../packages/shared-api/dist/components/select.js";
4
+ import { cn } from "../../../utils/cn.js";
5
+ import { Label } from "../../../packages/shared-api/dist/components/label.js";
6
+ import { Input } from "../../../packages/shared-api/dist/components/input.js";
7
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../../packages/shared-api/dist/components/dialog.js";
4
8
  import { useEffect, useRef, useState } from "react";
5
9
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import { EditIcon } from "lucide-react";
7
- import { useTranslations } from "@fuma-translate/react";
8
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@fumadocs/api-docs/components/select";
9
- import { Input, labelVariants } from "@fumadocs/api-docs/components/input";
10
- import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@fumadocs/api-docs/components/dialog";
11
10
  import { StfProvider, useFieldValue, useListener, useStf } from "@fumari/stf";
12
- import { resolveServerUrl } from "@fumadocs/api-docs/utils/url";
13
- //#region src/playground/components/server-select.tsx
11
+ import { useTranslations } from "@fuma-translate/react";
12
+ import { EditIcon } from "lucide-react";
13
+ //#region src/ui/playground/components/server-select.tsx
14
14
  function ServerSelect(props) {
15
- const { servers, server, setServer, setServerVariables } = useServerContext();
15
+ const { servers, server, resolveUrl, setServer, setServerVariables } = useServer();
16
16
  const [open, setOpen] = useState(false);
17
17
  const [isMounted, setIsMounted] = useState(false);
18
18
  const t = useTranslations({ note: "playground server select" });
@@ -34,7 +34,7 @@ function ServerSelect(props) {
34
34
  }),
35
35
  /* @__PURE__ */ jsx("code", {
36
36
  className: "truncate min-w-0 flex-1",
37
- children: isMounted ? new URL(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin).href : t("loading...")
37
+ children: isMounted ? resolveUrl() : t("loading...")
38
38
  }),
39
39
  /* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
40
40
  ]
@@ -87,8 +87,7 @@ function ServerSelectContent({ defaultValues, onChange, schema }) {
87
87
  return /* @__PURE__ */ jsxs("fieldset", {
88
88
  className: "flex flex-col gap-1",
89
89
  children: [
90
- /* @__PURE__ */ jsx("label", {
91
- className: cn(labelVariants()),
90
+ /* @__PURE__ */ jsx(Label, {
92
91
  htmlFor: key,
93
92
  children: key
94
93
  }),
@@ -1,7 +1,7 @@
1
1
  import { useMemo } from "react";
2
- import { CircleCheck, CircleX } from "lucide-react";
3
2
  import { useTranslations } from "@fuma-translate/react";
4
- //#region src/playground/status-info.tsx
3
+ import { CircleCheck, CircleX } from "lucide-react";
4
+ //#region src/ui/playground/status-info.tsx
5
5
  function useStatusInfo(status) {
6
6
  const t = useTranslations({ note: "playground status info" });
7
7
  return useMemo(() => {
@@ -1,6 +1,7 @@
1
1
  "use client";
2
- import { cn } from "../utils/cn.js";
3
- import { MethodLabel } from "../ui/components/method-label.js";
2
+ import { useOpenAPI } from "../../utils/create-page.js";
3
+ import { MethodLabel } from "../components/method-label.js";
4
+ import { cn } from "../../utils/cn.js";
4
5
  import { useEffect, useState } from "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { useTranslations } from "@fuma-translate/react";
@@ -8,12 +9,13 @@ import { buttonVariants } from "fumadocs-ui/components/ui/button";
8
9
  import { useApiClient } from "@scalar/api-client-react";
9
10
  import { useTheme } from "fumadocs-ui/provider/base";
10
11
  import "@scalar/api-client-react/style.css";
11
- //#region src/scalar/client.tsx
12
- function ScalarPlayground({ path, method, spec }) {
12
+ //#region src/ui/scalar/client.tsx
13
+ function ScalarPlayground({ path, method }) {
13
14
  const { resolvedTheme } = useTheme();
15
+ const { bundled } = useOpenAPI().doc;
14
16
  const t = useTranslations({ note: "scalar API client" });
15
17
  const [mounted, setMounted] = useState(false);
16
- const client = useApiClient({ configuration: { content: spec } });
18
+ const client = useApiClient({ configuration: { content: bundled } });
17
19
  useEffect(() => {
18
20
  setMounted(true);
19
21
  }, []);
@@ -1,5 +1,5 @@
1
- import { CreateOpenAPIPageOptions } from "../ui/index.js";
2
- //#region src/scalar/index.d.ts
1
+ import { CreateOpenAPIPageOptions } from "../index.js";
2
+ //#region src/ui/scalar/index.d.ts
3
3
  /**
4
4
  * Enable Scalar for API playgrounds by wrapping your options inside.
5
5
  *
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { lazy } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
- //#region src/scalar/index.tsx
4
+ //#region src/ui/scalar/index.tsx
5
5
  const Client = lazy(() => import("./client.js"));
6
6
  /**
7
7
  * Enable Scalar for API playgrounds by wrapping your options inside.
@@ -13,14 +13,10 @@ function withScalar(options = {}) {
13
13
  ...options,
14
14
  playground: {
15
15
  ...options.playground,
16
- provider(props) {
17
- return props.children;
18
- },
19
- render({ method, path, ctx }) {
16
+ render({ method, path }) {
20
17
  return /* @__PURE__ */ jsx(Client, {
21
18
  method,
22
- path,
23
- spec: ctx.schema.bundled
19
+ path
24
20
  });
25
21
  }
26
22
  }
@@ -0,0 +1,216 @@
1
+ import { MediaAdapter } from "../requests/media/adapter.js";
2
+ import { CodeUsageGeneratorRegistry, InlineCodeUsageGenerator } from "../requests/generators/index.js";
3
+ import { Awaitable, HttpMethods, OperationObject, PathItemObject } from "../types.js";
4
+ import { ExampleRequest, PageOperationProps, ResponseTab } from "../operation.js";
5
+ import { OpenAPIPageProps, OperationItem, WebhookItem } from "./pages/builder.js";
6
+ import { DereferencedDocument } from "./document/dereference.js";
7
+ import { SchemaUIOptions } from "../packages/shared-api/dist/components/schema/index.js";
8
+ import { PlaygroundClientOptions } from "../ui/playground/client.js";
9
+ import { PageComponents, ShikiOptions } from "../packages/shared-api/dist/components/defaults.js";
10
+ import { FC, ReactNode } from "react";
11
+ import { JsonSchema } from "@fumadocs/json-schema";
12
+ import { ShikiFactory } from "fumadocs-core/highlight/shiki";
13
+ //#region src/utils/create-page.d.ts
14
+ /** components the UI renders through, so a page can replace them */
15
+ export interface OpenAPIComponents extends PageComponents {
16
+ SchemaUI: FC<SchemaUIOptions>;
17
+ }
18
+ export interface GenerateTypeScriptDefinitionsContext {
19
+ name: string;
20
+ readOnly: boolean;
21
+ writeOnly: boolean;
22
+ doc: DereferencedDocument;
23
+ }
24
+ export interface OpenAPIRuntimeOptions {
25
+ /**
26
+ * Support other media types.
27
+ */
28
+ mediaAdapters?: Record<string, MediaAdapter>;
29
+ /**
30
+ * Set a prefix for `localStorage` keys.
31
+ *
32
+ * Useful when using multiple OpenAPI instances to prevent state conflicts.
33
+ *
34
+ * @defaultValue `fumadocs-openapi-`
35
+ */
36
+ storageKeyPrefix?: string;
37
+ /**
38
+ * Generate example code usage for all endpoints.
39
+ */
40
+ codeUsages?: CodeUsageGeneratorRegistry;
41
+ /**
42
+ * Generate example code usage for each endpoint.
43
+ */
44
+ generateCodeSamples?: (options: {
45
+ path: string;
46
+ operation: OperationObject;
47
+ method: HttpMethods;
48
+ pathItem: PathItemObject;
49
+ }) => InlineCodeUsageGenerator[];
50
+ /**
51
+ * Generate TypeScript definitions from JSON schema.
52
+ *
53
+ * Pass `false` to disable it.
54
+ */
55
+ generateTypeScriptDefinitions?: ((schema: JsonSchema, ctx: GenerateTypeScriptDefinitionsContext) => Awaitable<string | undefined>) | false;
56
+ }
57
+ /**
58
+ * The document and request options of the page, read from `useOpenAPI()`.
59
+ */
60
+ export interface OpenAPIRuntime extends OpenAPIRuntimeOptions {
61
+ doc: DereferencedDocument;
62
+ proxyUrl?: string;
63
+ mediaAdapters: Record<string, MediaAdapter>;
64
+ storageKeyPrefix: string;
65
+ }
66
+ export interface APIPlaygroundProps {
67
+ path: string;
68
+ method: HttpMethods;
69
+ operation: OperationObject;
70
+ pathItem: PathItemObject;
71
+ }
72
+ export interface OperationPlaygroundOptions extends PlaygroundClientOptions {
73
+ /**
74
+ * @defaultValue true
75
+ */
76
+ enabled?: boolean;
77
+ /**
78
+ * Replace the renderer, e.g. the playground installed with Fumadocs CLI.
79
+ */
80
+ render?: (props: APIPlaygroundProps) => ReactNode;
81
+ }
82
+ export interface PageLayoutProps {
83
+ operations?: {
84
+ item: OperationItem;
85
+ children: ReactNode;
86
+ }[];
87
+ webhooks?: {
88
+ item: WebhookItem;
89
+ children: ReactNode;
90
+ }[];
91
+ }
92
+ /**
93
+ * The options the UI renders with, read from `useRenderContext()`.
94
+ */
95
+ export interface OpenAPIRenderOptions {
96
+ /** the Shiki highlighter of code blocks */
97
+ shiki?: ShikiFactory;
98
+ shikiOptions?: ShikiOptions;
99
+ /**
100
+ * Show full response schema instead of only example response & Typescript definitions.
101
+ *
102
+ * @default true
103
+ */
104
+ showResponseSchema?: boolean;
105
+ /**
106
+ * Customize page content.
107
+ */
108
+ content?: {
109
+ renderResponseTabs?: (options: {
110
+ tabs: ResponseTab[];
111
+ }, ctx: RenderContext) => ReactNode;
112
+ renderRequestTabs?: (options: {
113
+ route: string;
114
+ items: ExampleRequest[];
115
+ method: HttpMethods;
116
+ pathItem: PathItemObject;
117
+ operation: OperationObject;
118
+ }, ctx: RenderContext) => ReactNode;
119
+ renderAPIExampleLayout?: (slots: {
120
+ selector: ReactNode;
121
+ usageTabs: ReactNode;
122
+ responseTabs: ReactNode;
123
+ }, ctx: RenderContext) => ReactNode;
124
+ /**
125
+ * @param generators - codegens for API example usages
126
+ */
127
+ renderAPIExampleUsageTabs?: (generators: CodeUsageGeneratorRegistry, ctx: RenderContext) => ReactNode;
128
+ /**
129
+ * renderer of the entire page's layout (containing all operations & webhooks UI)
130
+ */
131
+ renderPageLayout?: (slots: PageLayoutProps, ctx: RenderContext) => ReactNode;
132
+ renderOperationLayout?: (slots: {
133
+ header: ReactNode;
134
+ description: ReactNode;
135
+ apiExample: ReactNode;
136
+ apiPlayground: ReactNode;
137
+ authSchemes: ReactNode;
138
+ parameters: ReactNode;
139
+ body: ReactNode;
140
+ responses: ReactNode;
141
+ callbacks: ReactNode;
142
+ }, context: {
143
+ path: string;
144
+ operation: OperationObject;
145
+ method: HttpMethods;
146
+ pathItem: PathItemObject;
147
+ ctx: RenderContext;
148
+ }) => ReactNode;
149
+ renderWebhookLayout?: (slots: {
150
+ header: ReactNode;
151
+ description: ReactNode;
152
+ authSchemes: ReactNode;
153
+ parameters: ReactNode;
154
+ body: ReactNode;
155
+ requests: ReactNode;
156
+ responses: ReactNode;
157
+ callbacks: ReactNode;
158
+ }) => ReactNode;
159
+ };
160
+ /**
161
+ * Info UI for JSON schemas.
162
+ */
163
+ schemaUI?: {
164
+ /**
165
+ * Show examples under the generated content of JSON schemas.
166
+ *
167
+ * @defaultValue false
168
+ */
169
+ showExample?: boolean;
170
+ };
171
+ /**
172
+ * Customize API playground.
173
+ */
174
+ playground?: OperationPlaygroundOptions;
175
+ }
176
+ /**
177
+ * The render options of the page with their defaults applied, read from `useRenderContext()`.
178
+ */
179
+ export interface RenderContext extends OpenAPIRenderOptions {
180
+ shiki: ShikiFactory;
181
+ shikiOptions: ShikiOptions;
182
+ }
183
+ export interface CreateOpenAPIRendererOptions extends OpenAPIRuntimeOptions, OpenAPIRenderOptions {
184
+ components: Partial<PageComponents> & {
185
+ SchemaUI: FC<SchemaUIOptions>;
186
+ /** renders an operation or webhook of the page */
187
+ Operation: FC<PageOperationProps>;
188
+ /** wraps the rendered operations and webhooks */
189
+ Layout?: FC<PageLayoutProps>;
190
+ };
191
+ }
192
+ /**
193
+ * The runtime of the API page: the document and request options.
194
+ */
195
+ export declare function useOpenAPI(): OpenAPIRuntime;
196
+ export declare function useComponents(): OpenAPIComponents;
197
+ /**
198
+ * The render options of the page, available under a page created with `createOpenAPIRenderer()`.
199
+ */
200
+ export declare function useRenderContext(): RenderContext;
201
+ /**
202
+ * Generate TypeScript definitions of a JSON schema, `undefined` when disabled.
203
+ */
204
+ export declare function useTypeScriptDefinitions(schema: JsonSchema | undefined, options: Pick<GenerateTypeScriptDefinitionsContext, 'name' | 'readOnly' | 'writeOnly'>): string | undefined;
205
+ /**
206
+ * Create `<OpenAPIPage />` from your own UI, it takes the props of generated pages.
207
+ */
208
+ export declare function createOpenAPIRenderer(options: CreateOpenAPIRendererOptions): FC<OpenAPIPageProps>;
209
+ /**
210
+ * `createOpenAPIRenderer()` with nothing built in: it highlights through the `shiki` you pass, and
211
+ * generates code usages and TypeScript definitions only when you pass them.
212
+ */
213
+ export declare function createOpenAPIBaseRenderer({ components, ...options }: CreateOpenAPIRendererOptions & {
214
+ shiki: ShikiFactory;
215
+ }): FC<OpenAPIPageProps>;
216
+ //#endregion
@@ -0,0 +1,221 @@
1
+ "use client";
2
+ import { dereferenceBundledDocument } from "./document/dereference.js";
3
+ import { defaultAdapters } from "../requests/media/adapter.js";
4
+ import { createCodeUsageGeneratorRegistry } from "../requests/generators/index.js";
5
+ import { registerDefault } from "../requests/generators/all.js";
6
+ import { createPageComponents, defaultShikiOptions } from "../packages/shared-api/dist/components/defaults.js";
7
+ import { AuthProvider } from "../playground/auth.js";
8
+ import { ServerProvider } from "./use-server.js";
9
+ import { createContext, use, useMemo } from "react";
10
+ import { getRaw } from "@scalar/json-magic/magic-proxy";
11
+ import { generate } from "@fumari/json-schema-ts";
12
+ import { defaultShikiFactory } from "fumadocs-core/highlight/shiki/full";
13
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
14
+ //#region src/utils/create-page.tsx
15
+ const OpenAPIContext = createContext(null);
16
+ const ComponentsContext = createContext(null);
17
+ const OptionsContext = createContext(null);
18
+ /**
19
+ * The runtime of the API page: the document and request options.
20
+ */
21
+ function useOpenAPI() {
22
+ const ctx = use(OpenAPIContext);
23
+ if (!ctx) throw new Error("Component must be used under <OpenAPIProvider />");
24
+ return ctx;
25
+ }
26
+ function useComponents() {
27
+ const components = use(ComponentsContext);
28
+ if (!components) throw new Error("Component must be used under <OpenAPIProvider />");
29
+ return components;
30
+ }
31
+ /**
32
+ * The render options of the page, available under a page created with `createOpenAPIRenderer()`.
33
+ */
34
+ function useRenderContext() {
35
+ const ctx = use(OptionsContext);
36
+ if (!ctx) throw new Error("Component must be used under <OpenAPIProvider />");
37
+ return ctx;
38
+ }
39
+ /**
40
+ * Generate TypeScript definitions of a JSON schema, `undefined` when disabled.
41
+ */
42
+ function useTypeScriptDefinitions(schema, options) {
43
+ const runtime = useOpenAPI();
44
+ const { name, readOnly, writeOnly } = options;
45
+ const result = useMemo(() => {
46
+ if (!schema || !runtime.generateTypeScriptDefinitions) return;
47
+ return runtime.generateTypeScriptDefinitions(schema, {
48
+ name,
49
+ readOnly,
50
+ writeOnly,
51
+ doc: runtime.doc
52
+ });
53
+ }, [
54
+ runtime,
55
+ schema,
56
+ name,
57
+ readOnly,
58
+ writeOnly
59
+ ]);
60
+ return result instanceof Promise ? use(result) : result;
61
+ }
62
+ function OpenAPIProvider({ document, mediaAdapters, codeUsages, generateCodeSamples, generateTypeScriptDefinitions, proxyUrl, storageKeyPrefix = "fumadocs-openapi-", shiki, shikiOptions = defaultShikiOptions, showResponseSchema, content, schemaUI, playground, components, children }) {
63
+ const runtime = useMemo(() => ({
64
+ doc: dereferenceBundledDocument(document),
65
+ mediaAdapters: {
66
+ ...defaultAdapters,
67
+ ...mediaAdapters
68
+ },
69
+ codeUsages,
70
+ generateCodeSamples,
71
+ generateTypeScriptDefinitions,
72
+ proxyUrl,
73
+ storageKeyPrefix
74
+ }), [
75
+ document,
76
+ mediaAdapters,
77
+ codeUsages,
78
+ generateCodeSamples,
79
+ generateTypeScriptDefinitions,
80
+ proxyUrl,
81
+ storageKeyPrefix
82
+ ]);
83
+ const render = useMemo(() => ({
84
+ shiki,
85
+ shikiOptions,
86
+ showResponseSchema,
87
+ content,
88
+ schemaUI,
89
+ playground
90
+ }), [
91
+ shiki,
92
+ shikiOptions,
93
+ showResponseSchema,
94
+ content,
95
+ schemaUI,
96
+ playground
97
+ ]);
98
+ return /* @__PURE__ */ jsx(OpenAPIContext, {
99
+ value: runtime,
100
+ children: /* @__PURE__ */ jsx(ComponentsContext, {
101
+ value: components,
102
+ children: /* @__PURE__ */ jsx(OptionsContext, {
103
+ value: render,
104
+ children: /* @__PURE__ */ jsx(ServerProvider, {
105
+ servers: runtime.doc.dereferenced.servers,
106
+ storageKeyPrefix: runtime.storageKeyPrefix,
107
+ children: /* @__PURE__ */ jsx(AuthProvider, { children })
108
+ })
109
+ })
110
+ })
111
+ });
112
+ }
113
+ let defaultCodeUsages;
114
+ const defaultTypeScriptDefinitions = (schema, ctx) => {
115
+ if (typeof schema !== "object") return;
116
+ try {
117
+ return generate({
118
+ ...ctx.doc.bundled,
119
+ ...getRaw(schema)
120
+ }, {
121
+ name: ctx.name,
122
+ readOnly: ctx.readOnly,
123
+ writeOnly: ctx.writeOnly
124
+ });
125
+ } catch (e) {
126
+ console.warn("Failed to generate typescript schema:", e);
127
+ }
128
+ };
129
+ /**
130
+ * Create `<OpenAPIPage />` from your own UI, it takes the props of generated pages.
131
+ */
132
+ function createOpenAPIRenderer(options) {
133
+ return createOpenAPIBaseRenderer({
134
+ ...options,
135
+ shiki: options.shiki ?? defaultShikiFactory,
136
+ codeUsages: options.codeUsages ?? (defaultCodeUsages ??= registerDefault(createCodeUsageGeneratorRegistry())),
137
+ generateTypeScriptDefinitions: options.generateTypeScriptDefinitions ?? defaultTypeScriptDefinitions
138
+ });
139
+ }
140
+ /**
141
+ * `createOpenAPIRenderer()` with nothing built in: it highlights through the `shiki` you pass, and
142
+ * generates code usages and TypeScript definitions only when you pass them.
143
+ */
144
+ function createOpenAPIBaseRenderer({ components, ...options }) {
145
+ const { Operation, Layout = DefaultLayout } = components;
146
+ const slots = {
147
+ SchemaUI: components.SchemaUI,
148
+ ...createPageComponents({
149
+ ...options,
150
+ components
151
+ })
152
+ };
153
+ function Content({ showTitle, showDescription, operations, webhooks }) {
154
+ const { dereferenced, resolve } = useOpenAPI().doc;
155
+ const ctx = useRenderContext();
156
+ const layout = {
157
+ operations: operations?.map((item) => {
158
+ const pathItem = resolve(dereferenced.paths?.[item.path]);
159
+ if (!pathItem) throw new Error(`[Fumadocs OpenAPI] Path not found in OpenAPI schema: ${item.path}`);
160
+ const operation = pathItem[item.method];
161
+ if (!operation) throw new Error(`[Fumadocs OpenAPI] Method ${item.method} not found in operation: ${item.path}`);
162
+ return {
163
+ item,
164
+ children: /* @__PURE__ */ jsx(Operation, {
165
+ type: "operation",
166
+ path: item.path,
167
+ method: item.method,
168
+ operation,
169
+ pathItem,
170
+ showTitle,
171
+ showDescription
172
+ }, `${item.path}:${item.method}`)
173
+ };
174
+ }),
175
+ webhooks: webhooks?.map((item) => {
176
+ const pathItem = resolve(dereferenced.webhooks?.[item.name]);
177
+ if (!pathItem) throw new Error(`[Fumadocs OpenAPI] Webhook not found in OpenAPI schema: ${item.name}`);
178
+ const operation = pathItem[item.method];
179
+ if (!operation) throw new Error(`[Fumadocs OpenAPI] Method ${item.method} not found in webhook: ${item.name}`);
180
+ return {
181
+ item,
182
+ children: /* @__PURE__ */ jsx(Operation, {
183
+ type: "webhook",
184
+ path: `/${item.name}`,
185
+ method: item.method,
186
+ operation,
187
+ pathItem,
188
+ showTitle,
189
+ showDescription
190
+ }, `${item.name}:${item.method}`)
191
+ };
192
+ })
193
+ };
194
+ if (ctx.content?.renderPageLayout) return ctx.content.renderPageLayout(layout, ctx);
195
+ return /* @__PURE__ */ jsx(Layout, { ...layout });
196
+ }
197
+ return function OpenAPIPage(props) {
198
+ let document;
199
+ let proxyUrl;
200
+ if ("preloaded" in props) {
201
+ document = props.preloaded.docs[props.document];
202
+ if (!document) throw new Error(`[Fumadocs OpenAPI] the document ${props.document} is not preloaded, make sure to pass the "preloaded" prop to <OpenAPIPage />`);
203
+ proxyUrl = props.preloaded.proxyUrl;
204
+ } else {
205
+ document = props.payload.bundled;
206
+ proxyUrl = props.payload.proxyUrl;
207
+ }
208
+ return /* @__PURE__ */ jsx(OpenAPIProvider, {
209
+ ...options,
210
+ document,
211
+ proxyUrl,
212
+ components: slots,
213
+ children: /* @__PURE__ */ jsx(Content, { ...props })
214
+ });
215
+ };
216
+ }
217
+ function DefaultLayout({ operations, webhooks }) {
218
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [operations?.map((item) => item.children), webhooks?.map((item) => item.children)] });
219
+ }
220
+ //#endregion
221
+ export { createOpenAPIBaseRenderer, createOpenAPIRenderer, useComponents, useOpenAPI, useRenderContext, useTypeScriptDefinitions };
@@ -1,5 +1,5 @@
1
1
  import { Document } from "../../types.js";
2
- import { NoReferenceSwallow } from "@fumadocs/api-docs/schema";
2
+ import { DereferencedShallow } from "@fumadocs/json-schema";
3
3
  //#region src/utils/document/dereference.d.ts
4
4
  export interface DereferencedDocument {
5
5
  /**
@@ -13,7 +13,7 @@ export interface DereferencedDocument {
13
13
  *
14
14
  * Non-reference values are returned as-is.
15
15
  */
16
- resolve: <T>(node: T) => NoReferenceSwallow<T>;
16
+ resolve: <T>(node: T) => DereferencedShallow<T>;
17
17
  bundled: Document;
18
18
  }
19
19
  //#endregion
@@ -1,14 +1,19 @@
1
- import { dereferenceShallow } from "@fumadocs/api-docs/schema/dereference";
2
1
  import { createMagicProxy } from "@scalar/json-magic/magic-proxy";
2
+ import { dereference } from "@fumadocs/json-schema";
3
3
  //#region src/utils/document/dereference.ts
4
+ const cache = /* @__PURE__ */ new WeakMap();
4
5
  function dereferenceBundledDocument(bundled) {
5
- return {
6
+ const cached = cache.get(bundled);
7
+ if (cached) return cached;
8
+ const doc = {
6
9
  bundled,
7
10
  dereferenced: createMagicProxy(bundled),
8
11
  resolve(node) {
9
- return dereferenceShallow(node);
12
+ return dereference(node);
10
13
  }
11
14
  };
15
+ cache.set(bundled, doc);
16
+ return doc;
12
17
  }
13
18
  //#endregion
14
19
  export { dereferenceBundledDocument };
@@ -1,5 +1,5 @@
1
- import { upgrade } from "../../node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js";
2
- import { bundle } from "@fumadocs/api-docs/schema/bundle";
1
+ import { upgrade } from "@scalar/openapi-upgrader";
2
+ import { bundle } from "@fumadocs/json-schema/bundle";
3
3
  //#region src/utils/document/load.ts
4
4
  /**
5
5
  * Process input document to a Fumadocs OpenAPI compatible format
@@ -1,18 +1,16 @@
1
1
  import { getPreferredType, pickExample } from "./schema.js";
2
2
  import { encodeRequestData } from "../requests/media/encode.js";
3
- import { dereferenceShallow } from "@fumadocs/api-docs/schema/dereference";
4
3
  import { getRaw } from "@scalar/json-magic/magic-proxy";
5
- import { sample } from "@fumadocs/api-docs/schema/sample";
4
+ import { dereference, sample } from "@fumadocs/json-schema";
6
5
  //#region src/utils/get-example-requests.ts
7
- function getExampleRequests({ path, method, ctx, operation, pathItem }) {
8
- const requestBody = dereferenceShallow(operation.requestBody);
6
+ function getExampleRequests({ path, method, mediaAdapters, operation, parameters }) {
7
+ const requestBody = dereference(operation.requestBody);
9
8
  const media = requestBody?.content ? getPreferredType(requestBody.content) : null;
10
- const bodyOfType = media ? dereferenceShallow(requestBody.content[media]) : null;
11
- const parameters = [...operation.parameters ?? [], ...pathItem.parameters ?? []].map(dereferenceShallow);
9
+ const bodyOfType = media ? dereference(requestBody.content[media]) : null;
12
10
  if (bodyOfType?.examples) {
13
11
  const result = [];
14
12
  for (const [key, item] of Object.entries(bodyOfType.examples)) {
15
- const { summary, description } = dereferenceShallow(item);
13
+ const { summary, description } = dereference(item);
16
14
  const data = getRequestData({
17
15
  path,
18
16
  body: requestBody,
@@ -25,7 +23,7 @@ function getExampleRequests({ path, method, ctx, operation, pathItem }) {
25
23
  name: summary || key,
26
24
  description,
27
25
  data,
28
- encoded: encodeRequestData(data, ctx.mediaAdapters, parameters)
26
+ encoded: encodeRequestData(data, mediaAdapters, parameters)
29
27
  });
30
28
  }
31
29
  if (result.length > 0) return result;
@@ -36,13 +34,13 @@ function getExampleRequests({ path, method, ctx, operation, pathItem }) {
36
34
  method,
37
35
  parameters
38
36
  });
39
- const schema = dereferenceShallow(bodyOfType?.schema);
37
+ const schema = dereference(bodyOfType?.schema);
40
38
  return [{
41
39
  id: "_default",
42
40
  name: "Default",
43
41
  description: typeof schema === "object" ? schema.description : void 0,
44
42
  data,
45
- encoded: encodeRequestData(data, ctx.mediaAdapters, parameters)
43
+ encoded: encodeRequestData(data, mediaAdapters, parameters)
46
44
  }];
47
45
  }
48
46
  function getRequestData({ method, path, parameters, sampleKey, body }) {
@@ -59,7 +57,7 @@ function getRequestData({ method, path, parameters, sampleKey, body }) {
59
57
  if (param.schema) value = sample(param.schema);
60
58
  else if (param.content) {
61
59
  const type = getPreferredType(param.content);
62
- const content = type ? dereferenceShallow(param.content[type]) : void 0;
60
+ const content = type ? dereference(param.content[type]) : void 0;
63
61
  if (!content || !content.schema) throw new Error(`Cannot find "${param.name}" parameter info for media type "${type}" in ${path} ${method}`);
64
62
  value = sample(content.schema);
65
63
  }
@@ -81,8 +79,8 @@ function getRequestData({ method, path, parameters, sampleKey, body }) {
81
79
  const type = getPreferredType(body.content);
82
80
  if (!type) throw new Error(`Cannot find body schema for ${path} ${method}: missing media type`);
83
81
  result.bodyMediaType = type;
84
- const bodyOfType = dereferenceShallow(body.content[type]);
85
- if (bodyOfType.examples && sampleKey) result.body = getRaw(dereferenceShallow(bodyOfType.examples[sampleKey]).value);
82
+ const bodyOfType = dereference(body.content[type]);
83
+ if (bodyOfType.examples && sampleKey) result.body = getRaw(dereference(bodyOfType.examples[sampleKey]).value);
86
84
  else if (bodyOfType.example) result.body = getRaw(bodyOfType.example);
87
85
  else result.body = sample(bodyOfType?.schema ?? {}, {
88
86
  skipReadOnly: method !== "get",