fumadocs-openapi 10.3.4 → 10.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MediaAdapter } from "./requests/media/adapter.js";
2
2
  import { OperationOutput, OutputEntry, OutputGroup, PagesBuilder, PagesBuilderConfig, TagOutput, WebhookOutput, fromSchema, fromServer } from "./utils/pages/builder.js";
3
3
  import { SchemaToPagesOptions, createAutoPreset } from "./utils/pages/preset-auto.js";
4
- import { Awaitable, CallbackObject, DistributiveOmit, Document, MethodInformation, OperationObject, ParameterObject, PathItemObject, ReferenceObject, RenderContext, ResponseObject, SecuritySchemeObject, ServerObject, ServerVariableObject, TagObject } from "./types.js";
4
+ import { Awaitable, CallbackObject, DistributiveOmit, Document, ExampleObject, HttpMethods, MediaTypeObject, MethodInformation, OAuth2SecurityScheme, OperationObject, ParameterObject, PathItemObject, ReferenceObject, RenderContext, RequestBodyObject, ResponseObject, SecuritySchemeObject, ServerObject, ServerVariableObject, TagObject } from "./types.js";
5
5
  import { Config, OutputFile, generateFiles, generateFilesOnly } from "./generate-file.js";
6
- export { Awaitable, CallbackObject, Config, DistributiveOmit, Document, type MediaAdapter, MethodInformation, OperationObject, OperationOutput, OutputEntry, OutputFile, OutputGroup, PagesBuilder, PagesBuilderConfig, ParameterObject, PathItemObject, ReferenceObject, RenderContext, ResponseObject, SchemaToPagesOptions, SecuritySchemeObject, ServerObject, ServerVariableObject, TagObject, TagOutput, WebhookOutput, createAutoPreset, fromSchema, fromServer, generateFiles, generateFilesOnly };
6
+ export { Awaitable, CallbackObject, Config, DistributiveOmit, Document, ExampleObject, HttpMethods, type MediaAdapter, MediaTypeObject, MethodInformation, OAuth2SecurityScheme, OperationObject, OperationOutput, OutputEntry, OutputFile, OutputGroup, PagesBuilder, PagesBuilderConfig, ParameterObject, PathItemObject, ReferenceObject, RenderContext, RequestBodyObject, ResponseObject, SchemaToPagesOptions, SecuritySchemeObject, ServerObject, ServerVariableObject, TagObject, TagOutput, WebhookOutput, createAutoPreset, fromSchema, fromServer, generateFiles, generateFilesOnly };
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../utils/url.js";
4
4
  import { useStorageKey } from "../ui/client/storage-key.js";
5
- import { useApiContext } from "../ui/contexts/api.js";
5
+ import { useApiContext, useServerContext } from "../ui/contexts/api.js";
6
6
  import { getStatusInfo } from "./status-info.js";
7
7
  import { cn } from "../utils/cn.js";
8
8
  import { MethodLabel } from "../ui/components/method-label.js";
@@ -29,7 +29,8 @@ const OauthDialogTrigger = lazy(() => import("./components/oauth-dialog.js").the
29
29
  function PlaygroundClient({ route, method = "GET", securities, parameters = [], body, references, proxyUrl, writeOnly, readOnly, ...rest }) {
30
30
  const { example: exampleId, examples, setExampleData } = useExampleRequests();
31
31
  const storageKeys = useStorageKey();
32
- const { mediaAdapters, serverRef, client: { playground: { components: { ResultDisplay = DefaultResultDisplay } = {}, requestTimeout = 10, transformAuthInputs } = {} } } = useApiContext();
32
+ const { mediaAdapters, client: { playground: { components: { ResultDisplay = DefaultResultDisplay } = {}, requestTimeout = 10, transformAuthInputs } = {} } } = useApiContext();
33
+ const { serverRef } = useServerContext();
33
34
  const [securityId, setSecurityId] = useState(0);
34
35
  const { inputs, mapInputs, initAuthValues } = useAuthInputs(securities[securityId], transformAuthInputs);
35
36
  const defaultValues = useMemo(() => {
@@ -97,7 +98,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
97
98
  e.preventDefault();
98
99
  },
99
100
  children: [
100
- /* @__PURE__ */ jsx(ServerSelect, {}),
101
+ /* @__PURE__ */ jsx(ServerSelect, { className: "border-b" }),
101
102
  /* @__PURE__ */ jsxs("div", {
102
103
  className: "flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0",
103
104
  children: [
@@ -12,25 +12,35 @@ import { useForm } from "react-hook-form";
12
12
  const FlowTypes = {
13
13
  password: {
14
14
  name: "Resource Owner Password Flow",
15
- description: "Authenticate using username and password."
15
+ description: "Authenticate using username and password.",
16
+ supported: true
16
17
  },
17
18
  clientCredentials: {
18
19
  name: "Client Credentials",
19
- description: "Intended for the server-to-server authentication."
20
+ description: "Intended for the server-to-server authentication.",
21
+ supported: true
20
22
  },
21
23
  authorizationCode: {
22
24
  name: "Authorization code",
23
- description: "Authenticate with 3rd party services"
25
+ description: "Authenticate with 3rd party services",
26
+ supported: true
24
27
  },
25
28
  implicit: {
26
29
  name: "Implicit",
27
- description: "Retrieve the access token directly."
30
+ description: "Retrieve the access token directly.",
31
+ supported: true
32
+ },
33
+ deviceAuthorization: {
34
+ name: "Device Authorization",
35
+ description: "Authenticate with device.",
36
+ supported: false
28
37
  }
29
38
  };
30
39
  function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
31
40
  const [type, setType] = useState(() => {
32
41
  return Object.keys(scheme.flows)[0];
33
42
  });
43
+ const { supported } = FlowTypes[type];
34
44
  const form = useForm({ defaultValues: {
35
45
  clientId: "",
36
46
  clientSecret: "",
@@ -252,15 +262,17 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
252
262
  ...form.register("password", { required: true })
253
263
  })]
254
264
  })] }),
255
- error ? /* @__PURE__ */ jsx("p", {
265
+ supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
256
266
  className: "text-red-400 font-medium text-sm",
257
267
  children: String(error)
258
- }) : null,
259
- /* @__PURE__ */ jsx("button", {
268
+ }) : null, /* @__PURE__ */ jsx("button", {
260
269
  type: "submit",
261
270
  disabled: isLoading,
262
271
  className: cn(buttonVariants({ color: "primary" })),
263
272
  children: authCodeCallback.isLoading ? "Fetching token..." : "Submit"
273
+ })] }) : /* @__PURE__ */ jsx("p", {
274
+ className: "text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border",
275
+ children: "Unsupported"
264
276
  })
265
277
  ]
266
278
  })] })]
@@ -1,18 +1,19 @@
1
1
  'use client';
2
2
 
3
3
  import { resolveServerUrl, withBase } from "../../utils/url.js";
4
- import { useApiContext, useServerSelectContext } from "../../ui/contexts/api.js";
4
+ import { useServerContext, useServerSelectContext } from "../../ui/contexts/api.js";
5
5
  import { cn } from "../../utils/cn.js";
6
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
7
7
  import { Input, labelVariants } from "../../ui/components/input.js";
8
8
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
9
9
  import { useEffect, useRef, useState } from "react";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { EditIcon } from "lucide-react";
11
12
  import { StfProvider, useFieldValue, useListener, useStf } from "@fumari/stf";
12
13
 
13
14
  //#region src/playground/components/server-select.tsx
14
15
  function ServerSelect(props) {
15
- const { servers } = useApiContext();
16
+ const { servers } = useServerContext();
16
17
  const { server, setServer, setServerVariables } = useServerSelectContext();
17
18
  const [open, setOpen] = useState(false);
18
19
  const [isMounted, setIsMounted] = useState(false);
@@ -24,34 +25,42 @@ function ServerSelect(props) {
24
25
  return /* @__PURE__ */ jsxs(Dialog, {
25
26
  open,
26
27
  onOpenChange: setOpen,
27
- children: [/* @__PURE__ */ jsx(DialogTrigger, {
28
- className: "text-xs p-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors truncate hover:bg-fd-accent hover:text-fd-accent-foreground focus-visible:outline-none",
29
- children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) : "loading..."
30
- }), /* @__PURE__ */ jsxs(DialogContent, {
28
+ children: [/* @__PURE__ */ jsxs(DialogTrigger, {
31
29
  ...props,
30
+ className: cn("flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground", props.className),
32
31
  children: [
33
- /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Server URL" }), /* @__PURE__ */ jsx(DialogDescription, { children: "The base URL of your API endpoint." })] }),
34
- /* @__PURE__ */ jsxs(Select, {
35
- value: server?.url,
36
- onValueChange: setServer,
37
- children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: servers.map((item) => /* @__PURE__ */ jsxs(SelectItem, {
38
- value: item.url,
39
- children: [/* @__PURE__ */ jsx("code", {
40
- className: "text-[0.8125rem]",
41
- children: item.url
42
- }), /* @__PURE__ */ jsx("p", {
43
- className: "text-fd-muted-foreground",
44
- children: item.description
45
- })]
46
- }, item.url)) })]
32
+ /* @__PURE__ */ jsx("span", {
33
+ className: "px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm",
34
+ children: server?.name ?? "Server URL"
47
35
  }),
48
- server?.variables && serverSchema?.variables && /* @__PURE__ */ jsx(ServerSelectContent, {
49
- defaultValues: server.variables,
50
- schema: serverSchema.variables,
51
- onChange: setServerVariables
52
- }, server.url)
36
+ /* @__PURE__ */ jsx("code", {
37
+ className: "truncate min-w-0 flex-1",
38
+ children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) : "loading..."
39
+ }),
40
+ /* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
53
41
  ]
54
- })]
42
+ }), /* @__PURE__ */ jsxs(DialogContent, { children: [
43
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Server URL" }), /* @__PURE__ */ jsx(DialogDescription, { children: "The base URL of your API endpoint." })] }),
44
+ /* @__PURE__ */ jsxs(Select, {
45
+ value: server?.url,
46
+ onValueChange: setServer,
47
+ children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: servers.map((item) => /* @__PURE__ */ jsxs(SelectItem, {
48
+ value: item.url,
49
+ children: [/* @__PURE__ */ jsx("code", {
50
+ className: "text-[0.8125rem]",
51
+ children: item.url
52
+ }), /* @__PURE__ */ jsx("p", {
53
+ className: "text-fd-muted-foreground",
54
+ children: item.description
55
+ })]
56
+ }, item.url)) })]
57
+ }),
58
+ server?.variables && serverSchema?.variables && /* @__PURE__ */ jsx(ServerSelectContent, {
59
+ defaultValues: server.variables,
60
+ schema: serverSchema.variables,
61
+ onChange: setServerVariables
62
+ }, server.url)
63
+ ] })]
55
64
  });
56
65
  }
57
66
  function ServerSelectContent({ defaultValues, onChange, schema }) {
@@ -102,7 +111,7 @@ function Field({ fieldName, variable }) {
102
111
  id: fieldName,
103
112
  children: /* @__PURE__ */ jsx(SelectValue, {})
104
113
  }), /* @__PURE__ */ jsx(SelectContent, { children: variable.enum.map((value) => /* @__PURE__ */ jsx(SelectItem, {
105
- value,
114
+ value: String(value),
106
115
  children: value
107
116
  }, value)) })]
108
117
  });
@@ -5,7 +5,7 @@ import "./adapter.js";
5
5
  /**
6
6
  * serialize parameters, see https://swagger.io/docs/specification/v3_0/serialization.
7
7
  */
8
- function encodeRequestData(from, adapters, parameters) {
8
+ function encodeRequestData(from, adapters, parameters = []) {
9
9
  const result = {
10
10
  method: from.method,
11
11
  body: from.body,
@@ -92,35 +92,32 @@ function serializePathParameter(field, value, output) {
92
92
  }
93
93
  }
94
94
  function serializeQueryParameter(field, value, output) {
95
- const { explode = true } = field;
96
- switch (field.style) {
97
- case "spaceDelimited": if (!explode && Array.isArray(value)) {
98
- output[field.name] = { values: [value.join(" ")] };
99
- break;
100
- }
101
- case "pipeDelimited": if (!explode && Array.isArray(value)) {
102
- output[field.name] = { values: [value.join("|")] };
103
- break;
104
- }
105
- case "deepObject": if (!Array.isArray(value) && typeof value === "object") {
106
- for (const [k, v] of Object.entries(value)) output[`${field.name}[${k}]`] = { values: Array.isArray(v) ? v : [String(v)] };
107
- break;
108
- }
109
- default:
110
- if (Array.isArray(value)) {
111
- output[field.name] = { values: explode ? value : [value.join(",")] };
112
- break;
113
- }
114
- if (typeof value === "object" && explode) {
115
- for (const [k, v] of Object.entries(value)) output[k] = { values: [String(v)] };
116
- break;
117
- }
118
- if (typeof value === "object") {
119
- output[field.name] = { values: [Object.entries(value).flat().join(",")] };
120
- break;
121
- }
122
- output[field.name] = { values: [String(value)] };
95
+ const { style, explode = true } = field;
96
+ if (style === "spaceDelimited" && !explode && Array.isArray(value)) {
97
+ output[field.name] = { values: [value.join(" ")] };
98
+ return;
99
+ }
100
+ if (style === "pipeDelimited" && !explode && Array.isArray(value)) {
101
+ output[field.name] = { values: [value.join("|")] };
102
+ return;
103
+ }
104
+ if (style === "deepObject" && !Array.isArray(value) && typeof value === "object") {
105
+ for (const [k, v] of Object.entries(value)) output[`${field.name}[${k}]`] = { values: Array.isArray(v) ? v : [String(v)] };
106
+ return;
107
+ }
108
+ if (Array.isArray(value)) {
109
+ output[field.name] = { values: explode ? value : [value.join(",")] };
110
+ return;
111
+ }
112
+ if (typeof value === "object" && explode) {
113
+ for (const [k, v] of Object.entries(value)) output[k] = { values: [String(v)] };
114
+ return;
115
+ }
116
+ if (typeof value === "object") {
117
+ output[field.name] = { values: [Object.entries(value).flat().join(",")] };
118
+ return;
123
119
  }
120
+ output[field.name] = { values: [String(value)] };
124
121
  }
125
122
  function serializeCookieParameter(field, value, output) {
126
123
  const { explode = true } = field;
@@ -1,13 +1,13 @@
1
1
  import { createProxy } from "./proxy.js";
2
2
  import { CodeUsageGenerator } from "../ui/operation/usage-tabs/index.js";
3
+ import { Document } from "../types.js";
3
4
  import { ProcessedDocument } from "../utils/process-document.js";
4
- import { OpenAPIV3, OpenAPIV3_1 } from "openapi-types";
5
5
 
6
6
  //#region src/server/create.d.ts
7
7
  /**
8
8
  * schema id -> file path, URL, or downloaded schema object
9
9
  */
10
- type SchemaMap = Record<string, string | OpenAPIV3_1.Document | OpenAPIV3.Document>;
10
+ type SchemaMap = Record<string, string | Document>;
11
11
  type ProcessedSchemaMap = Record<string, ProcessedDocument>;
12
12
  interface OpenAPIOptions {
13
13
  /**
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { OpenAPIV3, OpenAPIV3_2 } from "./_openapi/types.js";
1
2
  import { NoReference } from "./utils/schema.js";
2
3
  import { MediaAdapter } from "./requests/media/adapter.js";
3
4
  import { CodeUsageGenerator } from "./ui/operation/usage-tabs/index.js";
@@ -7,20 +8,24 @@ import { CreateAPIPageOptions } from "./ui/base.js";
7
8
  import { ProcessedDocument } from "./utils/process-document.js";
8
9
  import Slugger from "github-slugger";
9
10
  import { HTMLAttributes, ReactNode } from "react";
10
- import { OpenAPIV3_1 } from "openapi-types";
11
11
 
12
12
  //#region src/types.d.ts
13
- type Document = OpenAPIV3_1.Document;
14
- type OperationObject = OpenAPIV3_1.OperationObject;
15
- type ParameterObject = OpenAPIV3_1.ParameterObject;
16
- type SecuritySchemeObject = OpenAPIV3_1.SecuritySchemeObject;
17
- type ReferenceObject = OpenAPIV3_1.ReferenceObject;
18
- type PathItemObject = OpenAPIV3_1.PathItemObject;
19
- type TagObject = OpenAPIV3_1.TagObject;
20
- type ServerObject = OpenAPIV3_1.ServerObject;
21
- type CallbackObject = OpenAPIV3_1.CallbackObject;
22
- type ServerVariableObject = OpenAPIV3_1.ServerVariableObject;
23
- type ResponseObject = OpenAPIV3_1.ResponseObject;
13
+ type Document = OpenAPIV3_2.Document;
14
+ type OperationObject = OpenAPIV3_2.OperationObject;
15
+ type ParameterObject = OpenAPIV3_2.ParameterObject;
16
+ type SecuritySchemeObject = OpenAPIV3_2.SecuritySchemeObject;
17
+ type ReferenceObject = OpenAPIV3_2.ReferenceObject;
18
+ type PathItemObject = OpenAPIV3_2.PathItemObject;
19
+ type TagObject = OpenAPIV3_2.TagObject;
20
+ type ServerObject = OpenAPIV3_2.ServerObject;
21
+ type CallbackObject = OpenAPIV3_2.CallbackObject;
22
+ type ServerVariableObject = OpenAPIV3.ServerVariableObject;
23
+ type ResponseObject = OpenAPIV3_2.ResponseObject;
24
+ type OAuth2SecurityScheme = OpenAPIV3_2.OAuth2SecurityScheme;
25
+ type HttpMethods = OpenAPIV3_2.HttpMethods;
26
+ type ExampleObject = OpenAPIV3_2.ExampleObject;
27
+ type MediaTypeObject = OpenAPIV3_2.MediaTypeObject;
28
+ type RequestBodyObject = OpenAPIV3_2.RequestBodyObject;
24
29
  type MethodInformation = NoReference<OperationObject> & {
25
30
  method: string;
26
31
  'x-codeSamples'?: Omit<CodeUsageGenerator, 'id'>[];
@@ -28,7 +33,6 @@ type MethodInformation = NoReference<OperationObject> & {
28
33
  'x-exclusiveCodeSample'?: string;
29
34
  };
30
35
  interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<CreateAPIPageOptions, 'renderMarkdown'> {
31
- servers: NoReference<ServerObject>[];
32
36
  slugger: Slugger;
33
37
  /**
34
38
  * dereferenced schema
@@ -42,4 +46,4 @@ interface RenderContext extends Pick<OpenAPIOptions, 'proxyUrl'>, Omit<CreateAPI
42
46
  type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
43
47
  type Awaitable<T> = T | Promise<T>;
44
48
  //#endregion
45
- export { Awaitable, CallbackObject, DistributiveOmit, Document, MethodInformation, OperationObject, ParameterObject, PathItemObject, ReferenceObject, RenderContext, ResponseObject, SecuritySchemeObject, ServerObject, ServerVariableObject, TagObject };
49
+ export { Awaitable, CallbackObject, DistributiveOmit, Document, ExampleObject, HttpMethods, MediaTypeObject, MethodInformation, OAuth2SecurityScheme, OperationObject, ParameterObject, PathItemObject, ReferenceObject, RenderContext, RequestBodyObject, ResponseObject, SecuritySchemeObject, ServerObject, ServerVariableObject, TagObject };
@@ -1,7 +1,6 @@
1
- import "../types.js";
1
+ import { HttpMethods } from "../types.js";
2
2
  import { ProcessedDocument } from "../utils/process-document.js";
3
3
  import "react/jsx-runtime";
4
- import { OpenAPIV3_1 } from "openapi-types";
5
4
 
6
5
  //#region src/ui/api-page.d.ts
7
6
  interface ApiPageProps {
@@ -19,7 +18,7 @@ interface WebhookItem {
19
18
  * webhook name in `webhooks`
20
19
  */
21
20
  name: string;
22
- method: OpenAPIV3_1.HttpMethods;
21
+ method: HttpMethods;
23
22
  }
24
23
  interface OperationItem {
25
24
  /**
@@ -29,7 +28,7 @@ interface OperationItem {
29
28
  /**
30
29
  * the HTTP method of operation
31
30
  */
32
- method: OpenAPIV3_1.HttpMethods;
31
+ method: HttpMethods;
33
32
  }
34
33
  //#endregion
35
34
  export { ApiPageProps, OperationItem, WebhookItem };
@@ -1,6 +1,6 @@
1
1
  import { createMethod } from "../utils/schema.js";
2
+ import { ApiProviderLazy, ServerProviderLazy } from "./contexts/api.lazy.js";
2
3
  import { Operation } from "./operation/index.js";
3
- import { ApiProviderLazy } from "./contexts/api.lazy.js";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
 
6
6
  //#region src/ui/api-page.tsx
@@ -46,11 +46,15 @@ async function APIPage({ showTitle: hasHead = false, showDescription, operations
46
46
  };
47
47
  })
48
48
  }, ctx);
49
+ let servers = ctx.schema.dereferenced.servers;
50
+ if (!servers || servers.length === 0) servers = [{ url: "/" }];
49
51
  return /* @__PURE__ */ jsx(ApiProviderLazy, {
50
- servers: ctx.servers,
51
52
  shikiOptions: ctx.shikiOptions,
52
53
  client: ctx.client ?? {},
53
- children: content
54
+ children: /* @__PURE__ */ jsx(ServerProviderLazy, {
55
+ servers,
56
+ children: content
57
+ })
54
58
  });
55
59
  }
56
60
 
package/dist/ui/base.js CHANGED
@@ -36,14 +36,11 @@ function createAPIPage(server, options) {
36
36
  let processed;
37
37
  if (typeof document === "string") processed = await server.getSchema(document);
38
38
  else processed = await document;
39
- const { dereferenced } = processed;
40
- const servers = dereferenced.servers && dereferenced.servers.length > 0 ? dereferenced.servers : [{ url: "/" }];
41
39
  const slugger = new Slugger();
42
40
  const ctx = {
43
41
  schema: processed,
44
42
  proxyUrl: server.options.proxyUrl,
45
43
  ...options,
46
- servers,
47
44
  mediaAdapters: {
48
45
  ...defaultAdapters,
49
46
  ...options.mediaAdapters
@@ -6,6 +6,7 @@ import { createContext, use, useEffect, useMemo, useRef, useState } from "react"
6
6
  import { jsx } from "react/jsx-runtime";
7
7
 
8
8
  //#region src/ui/contexts/api.tsx
9
+ const ServerContext = createContext(null);
9
10
  const ApiContext = createContext(null);
10
11
  const ServerSelectContext = createContext(null);
11
12
  function useApiContext() {
@@ -13,28 +14,34 @@ function useApiContext() {
13
14
  if (!ctx) throw new Error("Component must be used under <ApiProvider />");
14
15
  return ctx;
15
16
  }
17
+ function useServerContext() {
18
+ return use(ServerContext);
19
+ }
16
20
  function useServerSelectContext() {
17
21
  const ctx = use(ServerSelectContext);
18
22
  if (!ctx) throw new Error("Component must be used under <ApiProvider />");
19
23
  return ctx;
20
24
  }
21
- function ApiProvider({ defaultBaseUrl, children, servers, shikiOptions, client }) {
22
- const serverRef = useRef(null);
25
+ function ApiProvider({ children, shikiOptions, client }) {
23
26
  return /* @__PURE__ */ jsx(ApiContext, {
24
27
  value: useMemo(() => ({
25
- serverRef,
26
28
  shikiOptions,
27
29
  client,
28
30
  mediaAdapters: {
29
31
  ...defaultAdapters,
30
32
  ...client.mediaAdapters
31
- },
32
- servers
33
- }), [
33
+ }
34
+ }), [client, shikiOptions]),
35
+ children
36
+ });
37
+ }
38
+ function ServerProvider({ servers, defaultBaseUrl, children }) {
39
+ const serverRef = useRef(null);
40
+ return /* @__PURE__ */ jsx(ServerContext, {
41
+ value: useMemo(() => ({
34
42
  servers,
35
- client,
36
- shikiOptions
37
- ]),
43
+ serverRef
44
+ }), [servers]),
38
45
  children: /* @__PURE__ */ jsx(ServerSelectProvider, {
39
46
  defaultBaseUrl,
40
47
  children
@@ -42,11 +49,12 @@ function ApiProvider({ defaultBaseUrl, children, servers, shikiOptions, client }
42
49
  });
43
50
  }
44
51
  function ServerSelectProvider({ defaultBaseUrl, children }) {
45
- const { servers, serverRef } = useApiContext();
52
+ const { servers, serverRef } = use(ServerContext);
46
53
  const storageKeys = useStorageKey();
47
54
  const [server, setServer] = useState(() => {
48
55
  const defaultItem = defaultBaseUrl ? servers.find((item) => item.url === defaultBaseUrl) : servers[0];
49
56
  return defaultItem ? {
57
+ name: defaultItem.name,
50
58
  url: defaultItem.url,
51
59
  variables: getDefaultValues(defaultItem)
52
60
  } : null;
@@ -57,8 +65,7 @@ function ServerSelectProvider({ defaultBaseUrl, children }) {
57
65
  if (!cached) return;
58
66
  try {
59
67
  const obj = JSON.parse(cached);
60
- if (!obj || typeof obj !== "object") return;
61
- setServer(obj);
68
+ if (typeof obj === "object" && obj !== null && "url" in obj && typeof obj.url === "string" && "variables" in obj && typeof obj.variables === "object" && obj.variables !== null) setServer(obj);
62
69
  } catch {}
63
70
  }, [storageKeys]);
64
71
  return /* @__PURE__ */ jsx(ServerSelectContext, {
@@ -79,6 +86,7 @@ function ServerSelectProvider({ defaultBaseUrl, children }) {
79
86
  const obj = servers.find((item) => item.url === value);
80
87
  if (!obj) return;
81
88
  const result = {
89
+ name: obj.name,
82
90
  url: value,
83
91
  variables: getDefaultValues(obj)
84
92
  };
@@ -96,9 +104,9 @@ function ServerSelectProvider({ defaultBaseUrl, children }) {
96
104
  function getDefaultValues(server) {
97
105
  const out = {};
98
106
  if (!server.variables) return out;
99
- for (const [k, v] of Object.entries(server.variables)) out[k] = v.default;
107
+ for (const [k, v] of Object.entries(server.variables)) if (v.default !== void 0) out[k] = String(v.default);
100
108
  return out;
101
109
  }
102
110
 
103
111
  //#endregion
104
- export { ApiProvider, useApiContext, useServerSelectContext };
112
+ export { ApiProvider, ServerProvider, useApiContext, useServerContext, useServerSelectContext };
@@ -4,6 +4,7 @@ import { wrapLazy } from "../../utils/lazy.js";
4
4
 
5
5
  //#region src/ui/contexts/api.lazy.ts
6
6
  const ApiProviderLazy = wrapLazy(() => import("./api.js").then((mod) => ({ default: mod.ApiProvider })));
7
+ const ServerProviderLazy = wrapLazy(() => import("./api.js").then((mod) => ({ default: mod.ServerProvider })));
7
8
 
8
9
  //#endregion
9
- export { ApiProviderLazy };
10
+ export { ApiProviderLazy, ServerProviderLazy };
@@ -11,6 +11,7 @@ import { AccordionContent, AccordionHeader, AccordionItem, AccordionTrigger, Acc
11
11
  import { UsageTabs } from "./usage-tabs/index.js";
12
12
  import { CopyResponseTypeScript, SelectTab, SelectTabTrigger, SelectTabs } from "./client.js";
13
13
  import { RequestTabs, getExampleRequests } from "./request-tabs.js";
14
+ import { ServerProviderLazy } from "../contexts/api.lazy.js";
14
15
  import { Fragment } from "react";
15
16
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
17
 
@@ -35,7 +36,7 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
35
36
  headNode = ctx.renderHeading(headingLevel, title);
36
37
  headingLevel++;
37
38
  }
38
- const contentTypes = body ? Object.entries(body.content) : null;
39
+ const contentTypes = body?.content ? Object.entries(body.content) : null;
39
40
  if (body && contentTypes && contentTypes.length > 0) {
40
41
  const items = contentTypes.map(([key]) => ({
41
42
  label: /* @__PURE__ */ jsx("code", {
@@ -99,11 +100,11 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
99
100
  name: param.name,
100
101
  required: param.required
101
102
  },
102
- root: {
103
+ root: typeof param.schema === "object" ? {
103
104
  ...param.schema,
104
105
  description: param.description ?? param.schema?.description,
105
106
  deprecated: (param.deprecated ?? false) || (param.schema?.deprecated ?? false)
106
- },
107
+ } : param.schema,
107
108
  readOnly: method.method === "GET",
108
109
  writeOnly: method.method !== "GET",
109
110
  ctx
@@ -211,7 +212,7 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
211
212
  });
212
213
  };
213
214
  const playgroundEnabled = ctx.playground?.enabled ?? true;
214
- const content = await renderOperationLayout({
215
+ let content = await renderOperationLayout({
215
216
  header: headNode,
216
217
  description: descriptionNode,
217
218
  authSchemes: authNode,
@@ -238,12 +239,17 @@ async function Operation({ type = "operation", path, method, ctx, showTitle, sho
238
239
  ctx
239
240
  })
240
241
  }, ctx, method);
241
- return /* @__PURE__ */ jsx(UsageTabsProviderLazy, {
242
+ content = /* @__PURE__ */ jsx(UsageTabsProviderLazy, {
242
243
  defaultExampleId: method["x-exclusiveCodeSample"] ?? method["x-selectedCodeSample"],
243
244
  route: path,
244
245
  examples: getExampleRequests(path, method, ctx),
245
246
  children: content
246
247
  });
248
+ if (method.servers) content = /* @__PURE__ */ jsx(ServerProviderLazy, {
249
+ servers: method.servers,
250
+ children: content
251
+ });
252
+ return content;
247
253
  } else {
248
254
  renderWebhookLayout ??= (slots) => /* @__PURE__ */ jsxs("div", {
249
255
  className: "flex flex-col-reverse gap-x-6 gap-y-4 @4xl:flex-row @4xl:items-start",
@@ -9,8 +9,9 @@ import { sample } from "openapi-sampler";
9
9
 
10
10
  //#region src/ui/operation/request-tabs.tsx
11
11
  function getExampleRequests(path, operation, ctx) {
12
- const media = operation.requestBody ? getPreferredType(operation.requestBody.content) : null;
13
- const bodyOfType = media ? operation.requestBody?.content[media] : null;
12
+ const requestBody = operation.requestBody;
13
+ const media = requestBody?.content ? getPreferredType(requestBody.content) : null;
14
+ const bodyOfType = media ? requestBody.content[media] : null;
14
15
  if (bodyOfType?.examples) {
15
16
  const result = [];
16
17
  for (const [key, value] of Object.entries(bodyOfType.examples)) {
@@ -29,7 +30,7 @@ function getExampleRequests(path, operation, ctx) {
29
30
  return [{
30
31
  id: "_default",
31
32
  name: "Default",
32
- description: bodyOfType?.schema?.description,
33
+ description: typeof bodyOfType?.schema === "object" ? bodyOfType.schema.description : void 0,
33
34
  data,
34
35
  encoded: encodeRequestData(data, ctx.mediaAdapters, operation.parameters ?? [])
35
36
  }];
@@ -66,7 +67,7 @@ function getRequestData(path, method, sampleKey, _ctx) {
66
67
  default: result.path[param.name] = value;
67
68
  }
68
69
  }
69
- if (method.requestBody) {
70
+ if (method.requestBody?.content) {
70
71
  const body = method.requestBody.content;
71
72
  const type = getPreferredType(body);
72
73
  if (!type) throw new Error(`Cannot find body schema for ${path} ${method.method}: missing media type`);
@@ -52,8 +52,8 @@ function createAutoPreset(options) {
52
52
  schemaId: builder.id,
53
53
  path: "",
54
54
  info: {
55
- title: dereferenced.info.title,
56
- description: dereferenced.info.description
55
+ title: dereferenced.info?.title ?? "Unknown",
56
+ description: dereferenced.info?.description
57
57
  },
58
58
  ...items
59
59
  };
@@ -1,9 +1,8 @@
1
1
  import { NoReference } from "./schema.js";
2
2
  import { Document } from "../types.js";
3
- import { OpenAPIV3, OpenAPIV3_1 } from "openapi-types";
4
3
 
5
4
  //#region src/utils/process-document.d.ts
6
- type ProcessedDocument = {
5
+ interface ProcessedDocument {
7
6
  /**
8
7
  * dereferenced document
9
8
  */
@@ -14,6 +13,6 @@ type ProcessedDocument = {
14
13
  */
15
14
  getRawRef: (obj: object) => string | undefined;
16
15
  bundled: Document;
17
- };
16
+ }
18
17
  //#endregion
19
18
  export { ProcessedDocument };