fumadocs-openapi 11.2.3 → 11.3.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.
@@ -1 +1 @@
1
- @source inline("--- --fd-docs-row-1 -mode -ms-2 @4xl:flex-row @4xl:items-start @4xl:sticky @4xl:top-[calc(var(--fd-docs-row-1,2rem)+1rem)] @4xl:w-[400px] @container @default @defaultValue @deprecated @fuma-translate/react @fumari/json-schema-ts @fumari/stf @param @private @scalar/api-client-react @see @typescript-eslint/no-explicit-any a access access_token active adapter adapters addListener against all allFlows allow already alt an anchorSegments and animate-spin apiExample apiKey apiPlayground application/javascript application/json application/x-javascript application/x-www-form-urlencoded application/xml apply are array as assume async at auth-specific authCodeQuery authCtx authNode authSchemes authorization authorizationCode authorization_code authorize autoComplete avoid await backward badgeVariants base baseDir basic be because before between bg-fd-card bg-fd-muted bg-fd-primary/10 bg-fd-secondary binary blob blue body bodyMediaType bodyNode boolean border border-b border-current border-fd-border border-s border-t border-y buffer builderOptions built-in bundled but button buttonVariants by byteLength bytes cache cached call callback callbacks callbacksNode can cannot case catch changes charset check children class-variance-authority className client clientCredentials clientId clientSecret client_credentials client_error client_id client_secret cloned cn code codeProps codeUsages codegen codegens collapsible color com compatibility compiler component components conditions configuration const content contentTypes context cookie cookies core could createAutoPreset createClientAPIPage createCodeUsageGeneratorRegistry createContext createOpenAPIPageBase createProxy credentials css csv ctx current currentValue custom customization cva dark dark:text-blue-400 dark:text-green-400 dark:text-orange-400 dark:text-red-400 dark:text-yellow-400 data data-[open]:border-b-0 data-type default defaultAdapters defaultExampleId defaultItem defaultMdxComponents defaultOpen defaultShikiFactory defaultValue defaultValues default_processMarkdown definitions deprecated depth dereferenceBundledDocument dereferenceShallow dereferenced description descriptionNode development deviceAuthorization dialog didn disable disableCache disabled display displayNames div do doc docRoot docs document documents domain downloaded dynamicSource e each else empty:hidden enabled encodeRequestData encoded endpoint enforce engine ensure entire entries entry error eslint-disable eslint-disable-next-line example exampleId exampleRequests examples export exported extends fallback false fast-content-type-parse fd-page-tree-item-name fetch fetcher field fieldName fields file filePath files fine first first:border-t-0 flex flex-1 flex-col flex-col-reverse flex-row flex-wrap flow flows folder folderStyle font-medium font-mono font-semibold for form formData format found from fromSchema fs full fumadocs-core/source fumadocs-core/toc fumadocs-openapi/ui fumadocs-ui/mdx fumadocs:openapi fumadocs_openapi_requests fumadocs_openapi_responses function gap-0.5 gap-1 gap-1.5 gap-2 gap-2.5 gap-24 gap-3 gap-4 gap-6 gap-x-6 gap-y-4 gen generate generateTypeScriptDefinitions generated generated/defined generators get getAPIPageProps getClientAPIPageProps getExampleRequests getOpenAPIPageProps getPreferredType getRaw getSchema getSchemas getWatchPaths github-dark github-light given grant_type green group group-data-[panel-open]:rotate-180 groupId h1 handling hasHead hash hast-util-to-jsx-runtime headNode header headers headingLevel highlighter hook hover:bg-fd-accent hover:text-fd-accent-foreground href html htmlFor http icon id idToTitle idx if ignore img implicit import imports in in-document info initAuthInputs initial inline-flex input inputs instanceof instances instead insteawd interface internal into is isLoading isMediaTypeSupported isRequired issues it item items items-center items-start js json json-schema-typed justify-between kept key keyof label labelVariants lang last:border-b-0 last:mb-0 latest layout lazy length let light line-through list list-disc list-inside listed listener listeners load loadDocument loaderPlugin localStorage lucide-react make map max-age may mb-1 mb-2 md mdxComponents me-auto media mediaAdapters mediaType message meta metaData method methodKeys mime min-w-0 modify mounted ms-auto mt-0! mt-10 mt-2 mt-3 multipart/form-data multiple must my-0! my-1.5 my-4 name name! named necessary need never new newKey no-cache node:fs node:path not not-last:pb-0 not-prose note null number oauth2 obj object of off omit on onChange onClick onCopy onOpenChange onSubmit onValueChange one only open openApiData openIdConnect openapi openapiMeta openid operation operationDescription operationId operations options or orange origin other out outline output overflow-auto overflow-hidden p p-2 p-3 packages page page-level pageData pages panelVariants param paramTypeKeys parameter parameterLabel parameterNode parameters params parent parsed parsedState parts party pass password path pathItem pathnameFromRequest payload pb-2 pe-3 persist persisted persistent place placeholder playground playgrounds please plugins pre prefix preloadOpenAPIPage preloaded prevent primary processed processor prop properties props prose-no-margin provider proxy proxyForwardCookie proxyUrl ps-2 ps-4.5 pt-1 pt-2 pt-2.5 px-1 px-2 px-3 py-0.5 py-1 py-1.5 py-2 query race raw react react-hooks/exhaustive-deps react/jsx-runtime readOnly readonly record red redirect_uri reference refs registerDefault registry rehype-react relativePath remark remark-rehype remarkGfm remarkRehype removeListener render renderAPIExampleLayout renderAPIExampleUsageTabs renderOperationLayout renderPageLayout renderParameterField renderRequestTabs renderRequestTabsDefault renderResponseTabs renderResponseTabsDefault renderWebhookLayout renderer replace request request-body requestData requestInit requestTimeout requestUrl requests required requirement requirementId requirements res reset resolvable resolve resolveMediaAdapter resolveServerUrl resolvedInput resolvedTheme resolves response response-body responseNode responseOfType responseTabs response_type responses rest result return returned returning root rounded-2xl rounded-lg rounded-md rounded-xl route s safeParse same sample satisfies scalar scan schema schemaId schemaMap schemaUI schemaUIShared schemas scheme schemeId schemes scope scopes search secondary seconds secret securities security securityEntries securityId securitySchemes segments segs select selector separator server server-to-server server-url serverSchema servers services set setData setExample setExampleData setIsJson setIsMounted setMounted setObjectUrl setOpen setRequirementId setSecurityId setServer setServerVariables setStore setToken setType setValue shadow-md shadow-sm shiki shikiOptions showDescription showExample showResponseSchema showTitle shrink-0 side signal single size size-3.5 size-4 slot slots sm so source spec specify spread src state staticSource status statusInfo statuses stf stfSync still storageKey storageKeys store stored string stringifyFieldKey structuredData styles submit summary supported sure switch t tab tabs testQuery text text-[0.8125rem] text-blue-600 text-fd-card-foreground text-fd-foreground text-fd-muted-foreground text-fd-primary text-fd-secondary-foreground text-green-500 text-green-600 text-nowrap text-orange-600 text-red-400 text-red-500 text-red-600 text-sm text-start text-xs text-yellow-600 text/css text/csv text/html text/plain the their them themes this throw timeout timerRef tips title to toJsxRuntime toStaticData toc token tokenInfo token_type transform transformAuthInputs transformPageTree transition-colors tree true truncate try ts type typeof types typescript unchanged under unexpected unknown unlisted update updated updatedSchemeId updating url usage usageTabs usages use useAnchorId useApiClient useAuth useCopyButton useMemo useOnChange useOperationContext useQuery useRef useRenderContext useServerContext useState useStatusInfo useStf useStorageKey useTheme useTranslations used username using utf-8 v value values variable variables variant variants via virtual void w-14 w-fit w-full warn we webhook webhookCallbacks webhooks when whitespace-pre-wrap will with without won wrapping writeOnly x-codeSamples x-exclusiveCodeSample x-selectedCodeSample xml yellow you your");
1
+ @source inline("--- --fd-docs-row-1 -mode -ms-2 @4xl:flex-row @4xl:items-start @4xl:sticky @4xl:top-[calc(var(--fd-docs-row-1,2rem)+1rem)] @4xl:w-[400px] @container @default @defaultValue @deprecated @fuma-translate/react @fumari/json-schema-ts @fumari/stf @param @private @scalar/api-client-react @see @typescript-eslint/no-explicit-any a access access_token active adapter adapters addListener against all allFlows allow already alt an anchorSegments and animate-spin apiExample apiKey apiPlayground application/javascript application/json application/x-javascript application/x-www-form-urlencoded application/xml apply are array as assume async at auth-specific authCodeQuery authCtx authNode authSchemes authorization authorizationCode authorization_code authorize autoComplete avoid await backward badgeVariants base baseDir basic be because before between bg-fd-card bg-fd-muted bg-fd-primary/10 bg-fd-secondary binary blob blue body bodyMediaType bodyNode boolean border border-b border-current border-fd-border border-s border-t border-y buffer builderOptions built-in bundled but button buttonVariants by byteLength bytes cache cached cachedDocFiles call callback callbacks callbacksNode can cannot case catch changes charset check children class-variance-authority className client clientCredentials clientId clientSecret client_credentials client_error client_id client_secret cloned cn code codeProps codeUsages codegen codegens collapsible color com compatibility compiler component components conditions configuration const content contentTypes context cookie cookies core could createClientAPIPage createCodeUsageGeneratorRegistry createContext createOpenAPIPageBase createProxy credentials css csv ctx current currentValue custom customization cva dark dark:text-blue-400 dark:text-green-400 dark:text-orange-400 dark:text-red-400 dark:text-yellow-400 data data-[open]:border-b-0 data-type default defaultAdapters defaultExampleId defaultItem defaultMdxComponents defaultOpen defaultShikiFactory defaultValue defaultValues default_processMarkdown definitions deprecated depth dereferenceBundledDocument dereferenceShallow dereferenced description descriptionNode development deviceAuthorization dialog didn disable disableCache disabled display displayNames div do doc docCache docFilesCache docRoot docs document documents domain downloaded dynamicSource e each else empty:hidden enabled encodeRequestData encoded endpoint enforce engine ensure entire entries entry error eslint-disable eslint-disable-next-line example exampleId exampleRequests examples export exported extends fallback false fast-content-type-parse fd-page-tree-item-name fetch fetcher field fieldName fields file filePath files fine first first:border-t-0 flex flex-1 flex-col flex-col-reverse flex-row flex-wrap flow flows folder folderStyle font-medium font-mono font-semibold for form formData format found from fs full fumadocs-core/source fumadocs-core/toc fumadocs-openapi/ui fumadocs-ui/mdx fumadocs:openapi fumadocs_openapi_requests fumadocs_openapi_responses function gap-0.5 gap-1 gap-1.5 gap-2 gap-2.5 gap-24 gap-3 gap-4 gap-6 gap-x-6 gap-y-4 gen generate generateTypeScriptDefinitions generated generated/defined generators get getAPIPageProps getClientAPIPageProps getExampleRequests getOpenAPIPageProps getPreferredType getRaw getSchema getSchemas getWatchPaths github-dark github-light given grant_type green group group-data-[panel-open]:rotate-180 groupId h1 handling hasHead hash hast-util-to-jsx-runtime headNode header headers headingLevel highlighter hook hover:bg-fd-accent hover:text-fd-accent-foreground href html htmlFor http icon id idToTitle idx if ignore img implicit import imports in in-document info initAuthInputs initial inline-flex input inputs instanceof instances instead insteawd interface internal into is isLoading isMediaTypeSupported isRequired issues it item items items-center items-start js json json-schema-typed justify-between kept key keyof label labelVariants lang last:border-b-0 last:mb-0 latest layout lazy length let light line-through list list-disc list-inside listed listener listeners load loadDocument loaderPlugin localStorage lucide-react make map max-age may mb-1 mb-2 md mdxComponents me-auto media mediaAdapters mediaType message meta metaData method methodKeys mime min-w-0 modify mounted ms-auto mt-0! mt-10 mt-2 mt-3 multipart/form-data multiple must my-0! my-1.5 my-4 name name! named necessary need never new newKey no-cache node:fs node:path not not-last:pb-0 not-prose note null number oauth2 obj object of off omit on onChange onClick onCopy onOpenChange onSubmit onValueChange one only open openApiData openIdConnect openapi openapiMeta openid operation operationDescription operationId operations options or orange origin other out outline output overflow-auto overflow-hidden p p-2 p-3 packages page page-level pageData pages panelVariants param paramTypeKeys parameter parameterLabel parameterNode parameters params parent parsed parsedState parts party pass password path pathItem pathnameFromRequest payload pb-2 pe-3 persist persisted persistent place placeholder playground playgrounds please plugins pre prefix preloadOpenAPIPage preloaded prevent primary processed processor prop properties props prose-no-margin provider proxy proxyForwardCookie proxyUrl ps-2 ps-4.5 pt-1 pt-2 pt-2.5 px-1 px-2 px-3 py-0.5 py-1 py-1.5 py-2 query race raw react react-hooks/exhaustive-deps react/jsx-runtime readOnly readonly record red redirect_uri reference refs registerDefault registry rehype-react relativePath remark remark-rehype remarkGfm remarkRehype removeListener render renderAPIExampleLayout renderAPIExampleUsageTabs renderOperationLayout renderPageLayout renderParameterField renderRequestTabs renderRequestTabsDefault renderResponseTabs renderResponseTabsDefault renderWebhookLayout renderer replace request request-body requestData requestInit requestTimeout requestUrl requests required requirement requirementId requirements res reset resolvable resolve resolveMediaAdapter resolveServerUrl resolvedInput resolvedTheme resolves response response-body responseNode responseOfType responseTabs response_type responses rest result return returned returning root rounded-2xl rounded-lg rounded-md rounded-xl route s safeParse same sample satisfies scalar scan schema schemaId schemaUI schemaUIShared scheme schemeId schemes scope scopes search secondary seconds secret securities security securityEntries securityId securitySchemes segments segs select selector separator server server-to-server server-url serverSchema servers services set setData setExample setExampleData setIsJson setIsMounted setMounted setObjectUrl setOpen setRequirementId setSecurityId setServer setServerVariables setStore setToken setType setValue shadow-md shadow-sm shiki shikiOptions showDescription showExample showResponseSchema showTitle shrink-0 side signal single size size-3.5 size-4 slot slots sm so source spec specify spread src state staticSource status statusInfo statuses stf stfSync still storageKey storageKeys store stored string stringifyFieldKey structuredData styles submit summary supported sure switch t tab tabs testQuery text text-[0.8125rem] text-blue-600 text-fd-card-foreground text-fd-foreground text-fd-muted-foreground text-fd-primary text-fd-secondary-foreground text-green-500 text-green-600 text-nowrap text-orange-600 text-red-400 text-red-500 text-red-600 text-sm text-start text-xs text-yellow-600 text/css text/csv text/html text/plain the their them themes this throw timeout timerRef tips title to toJsxRuntime toStaticData toc token tokenInfo token_type transform transformAuthInputs transformPageTree transition-colors tree true truncate try ts type typeof types typescript unchanged under unexpected unknown unlisted update updated updatedSchemeId updating url usage usageTabs usages use useAnchorId useApiClient useAuth useCopyButton useMemo useOnChange useOperationContext useQuery useRef useRenderContext useServerContext useState useStatusInfo useStf useStorageKey useTheme useTranslations used username using utf-8 v value values variable variables variant variants via virtual void w-14 w-fit w-full warn we webhook webhookCallbacks webhooks when whitespace-pre-wrap will with without won wrapping writeOnly x-codeSamples x-exclusiveCodeSample x-selectedCodeSample xml yellow you your");
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
20
20
  value: mod,
21
21
  enumerable: true
22
22
  }) : target, mod));
@@ -1,5 +1,5 @@
1
1
  import { traverse } from "../helpers/traverse.js";
2
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.11/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js
2
+ //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.13/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js
3
3
  const DEFAULT_MEDIA_TYPE = "application/json";
4
4
  /** Extracts and removes x-example and x-examples extensions from an object */
5
5
  function extractXExampleExtensions(obj) {
@@ -179,9 +179,11 @@ function upgradeFromTwoToThree(originalSpecification) {
179
179
  const parameters = document.parameters && typeof document.parameters === "object" ? document.parameters : {};
180
180
  for (const [name, param] of Object.entries(parameters)) if (param && typeof param === "object") {
181
181
  if ("$ref" in param) params[name] = transformParameterObject(param);
182
- else if ("in" in param) if (param.in === "body") bodyParams[name] = migrateBodyParameter(param, document.consumes ?? [DEFAULT_MEDIA_TYPE]);
183
- else if (param.in === "formData") bodyParams[name] = migrateFormDataParameter([param], document.consumes);
184
- else params[name] = transformParameterObject(param);
182
+ else if ("in" in param) {
183
+ if (param.in === "body") bodyParams[name] = migrateBodyParameter(param, document.consumes ?? [DEFAULT_MEDIA_TYPE]);
184
+ else if (param.in === "formData") bodyParams[name] = migrateFormDataParameter([param], document.consumes);
185
+ else params[name] = transformParameterObject(param);
186
+ }
185
187
  }
186
188
  if (Object.keys(params).length > 0) document.components.parameters = params;
187
189
  if (Object.keys(bodyParams).length > 0) document.components.requestBodies = bodyParams;
@@ -195,38 +197,40 @@ function upgradeFromTwoToThree(originalSpecification) {
195
197
  document.components ??= {};
196
198
  const migratedResponses = {};
197
199
  const responses = document.responses;
198
- for (const [name, response] of Object.entries(responses)) if (response && typeof response === "object") if ("$ref" in response) migratedResponses[name] = response;
199
- else {
200
- const responseObj = response;
201
- const produces = document.produces ?? [DEFAULT_MEDIA_TYPE];
202
- if (responseObj.schema) {
203
- if (typeof responseObj.content !== "object") responseObj.content = {};
204
- for (const type of produces) responseObj.content[type] = { schema: responseObj.schema };
205
- delete responseObj.schema;
206
- }
207
- if (responseObj.examples && typeof responseObj.examples === "object") {
208
- if (typeof responseObj.content !== "object") responseObj.content = {};
209
- const defaultMediaType = produces[0] ?? DEFAULT_MEDIA_TYPE;
210
- for (const [key, exampleValue] of Object.entries(responseObj.examples)) if (isMediaTypeKey(key)) {
211
- if (typeof responseObj.content[key] !== "object") responseObj.content[key] = {};
212
- responseObj.content[key].example = exampleValue;
213
- } else {
214
- if (typeof responseObj.content[defaultMediaType] !== "object") responseObj.content[defaultMediaType] = {};
215
- const mediaEntry = responseObj.content[defaultMediaType];
216
- if (typeof mediaEntry.examples !== "object") mediaEntry.examples = {};
217
- mediaEntry.examples[key] = wrapAsExampleObject(exampleValue);
200
+ for (const [name, response] of Object.entries(responses)) if (response && typeof response === "object") {
201
+ if ("$ref" in response) migratedResponses[name] = response;
202
+ else {
203
+ const responseObj = response;
204
+ const produces = document.produces ?? [DEFAULT_MEDIA_TYPE];
205
+ if (responseObj.schema) {
206
+ if (typeof responseObj.content !== "object") responseObj.content = {};
207
+ for (const type of produces) responseObj.content[type] = { schema: responseObj.schema };
208
+ delete responseObj.schema;
209
+ }
210
+ if (responseObj.examples && typeof responseObj.examples === "object") {
211
+ if (typeof responseObj.content !== "object") responseObj.content = {};
212
+ const defaultMediaType = produces[0] ?? DEFAULT_MEDIA_TYPE;
213
+ for (const [key, exampleValue] of Object.entries(responseObj.examples)) if (isMediaTypeKey(key)) {
214
+ if (typeof responseObj.content[key] !== "object") responseObj.content[key] = {};
215
+ responseObj.content[key].example = exampleValue;
216
+ } else {
217
+ if (typeof responseObj.content[defaultMediaType] !== "object") responseObj.content[defaultMediaType] = {};
218
+ const mediaEntry = responseObj.content[defaultMediaType];
219
+ if (typeof mediaEntry.examples !== "object") mediaEntry.examples = {};
220
+ mediaEntry.examples[key] = wrapAsExampleObject(exampleValue);
221
+ }
222
+ delete responseObj.examples;
218
223
  }
219
- delete responseObj.examples;
224
+ if (responseObj.content && typeof responseObj.content === "object") removeEmptySchemaOnlyContentEntries(responseObj.content);
225
+ if (responseObj.headers && typeof responseObj.headers === "object") responseObj.headers = Object.entries(responseObj.headers).reduce((acc, [headerName, header]) => {
226
+ if (header && typeof header === "object") return {
227
+ [headerName]: transformResponseHeader(header),
228
+ ...acc
229
+ };
230
+ return acc;
231
+ }, {});
232
+ migratedResponses[name] = responseObj;
220
233
  }
221
- if (responseObj.content && typeof responseObj.content === "object") removeEmptySchemaOnlyContentEntries(responseObj.content);
222
- if (responseObj.headers && typeof responseObj.headers === "object") responseObj.headers = Object.entries(responseObj.headers).reduce((acc, [headerName, header]) => {
223
- if (header && typeof header === "object") return {
224
- [headerName]: transformResponseHeader(header),
225
- ...acc
226
- };
227
- return acc;
228
- }, {});
229
- migratedResponses[name] = responseObj;
230
234
  }
231
235
  if (Object.keys(migratedResponses).length > 0) document.components.responses = migratedResponses;
232
236
  delete document.responses;
@@ -1,5 +1,5 @@
1
1
  import { traverse } from "../helpers/traverse.js";
2
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.11/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js
2
+ //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.13/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js
3
3
  const SCHEMA_SEGMENTS = /* @__PURE__ */ new Set([
4
4
  "properties",
5
5
  "items",
@@ -18,6 +18,46 @@ function isSchemaPath(path) {
18
18
  if (path.length >= 2 && path[0] === "components" && path[1] === "schemas") return true;
19
19
  return false;
20
20
  }
21
+ const NAMED_SCHEMA_MAP_SEGMENTS = /* @__PURE__ */ new Set([
22
+ "properties",
23
+ "patternProperties",
24
+ "$defs",
25
+ "definitions"
26
+ ]);
27
+ /**
28
+ * Determine if the node at `path` is a map of named subschemas rather than a schema object.
29
+ *
30
+ * This matters because the 3.0 to 3.1 upgrade rewrites the `example` keyword into `examples`.
31
+ * A key called `example` (or `examples`) inside one of these maps is a member *name*, not the
32
+ * schema keyword, so it must be left untouched.
33
+ */
34
+ function isNamedSchemaMap(path) {
35
+ const last = path?.[path.length - 1];
36
+ if (last === void 0) return false;
37
+ if (last === "schemas" && path?.[path.length - 2] === "components") return true;
38
+ return NAMED_SCHEMA_MAP_SEGMENTS.has(last);
39
+ }
40
+ const DATA_KEYWORDS = /* @__PURE__ */ new Set([
41
+ "example",
42
+ "default",
43
+ "const",
44
+ "enum"
45
+ ]);
46
+ /**
47
+ * Determine if the node at `path` lives inside a data value rather than a schema.
48
+ *
49
+ * The traversal visits every object node, but a value held by keywords like `example` or
50
+ * `default` is user data, not a schema. Applying the schema transforms to it would mangle it
51
+ * (turning `nullable: true` into a type array, renaming a nested `x-webhooks`, and so on).
52
+ */
53
+ function isInsideDataValue(path) {
54
+ if (!path) return false;
55
+ for (const [index, segment] of path.entries()) {
56
+ if (DATA_KEYWORDS.has(segment) && !isNamedSchemaMap(path.slice(0, index))) return true;
57
+ if (segment === "value" && path[index - 2] === "examples" && !isNamedSchemaMap(path.slice(0, index - 2))) return true;
58
+ }
59
+ return false;
60
+ }
21
61
  /**
22
62
  * Upgrade from OpenAPI 3.0.x to 3.1.1
23
63
  *
@@ -31,9 +71,26 @@ function upgradeFromThreeToThreeOne(originalContent) {
31
71
  return content;
32
72
  }
33
73
  const applyChangesToDocument = (schema, path) => {
74
+ if (isInsideDataValue(path)) return schema;
34
75
  if (schema.type !== void 0 && schema.nullable === true) {
35
76
  schema.type = [schema.type, "null"];
36
77
  delete schema.nullable;
78
+ } else if (schema.nullable === true && schema.type === void 0) {
79
+ if (typeof schema.$ref === "string") {
80
+ const { nullable: _nullable, $ref, ...rest } = schema;
81
+ return {
82
+ ...rest,
83
+ anyOf: [{ $ref }, { type: "null" }]
84
+ };
85
+ }
86
+ if (Array.isArray(schema.allOf)) {
87
+ const { nullable: _nullable, allOf, ...rest } = schema;
88
+ const base = allOf.length === 1 ? allOf[0] : { allOf };
89
+ return {
90
+ ...rest,
91
+ anyOf: [base, { type: "null" }]
92
+ };
93
+ }
37
94
  }
38
95
  if (schema.exclusiveMinimum === true) {
39
96
  schema.exclusiveMinimum = schema.minimum;
@@ -44,10 +101,10 @@ const applyChangesToDocument = (schema, path) => {
44
101
  delete schema.maximum;
45
102
  } else if (schema.exclusiveMaximum === false) delete schema.exclusiveMaximum;
46
103
  const isInsideExamplesMap = path?.some((segment, index) => {
47
- if (segment === "examples" && index > 0) return path[index - 1] !== "properties";
104
+ if (segment === "examples" && index > 0) return !isNamedSchemaMap(path.slice(0, index));
48
105
  return false;
49
106
  });
50
- if (schema.example !== void 0 && !isInsideExamplesMap) {
107
+ if (schema.example !== void 0 && !isInsideExamplesMap && !isNamedSchemaMap(path)) {
51
108
  if (isSchemaPath(path)) schema.examples = [schema.example];
52
109
  else schema.examples = { default: { value: schema.example } };
53
110
  delete schema.example;
@@ -85,7 +142,7 @@ const applyChangesToDocument = (schema, path) => {
85
142
  };
86
143
  }
87
144
  }
88
- if (schema["x-webhooks"] !== void 0) {
145
+ if (schema["x-webhooks"] !== void 0 && (path === void 0 || path.length === 0)) {
89
146
  schema.webhooks = schema["x-webhooks"];
90
147
  delete schema["x-webhooks"];
91
148
  }
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.11/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js
1
+ //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.13/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js
2
2
  /**
3
3
  * Recursively migrate XML object properties from 3.1 to 3.2 format
4
4
  */
@@ -33,10 +33,12 @@ function migrateTagGroups(document) {
33
33
  if (Array.isArray(document.tags)) {
34
34
  for (const tag of document.tags) if (typeof tag === "object" && tag !== null && "name" in tag) {
35
35
  const groupName = tagGroupMap.get(tag.name);
36
- if (groupName) if (groupName.toLowerCase().includes("nav") || groupName.toLowerCase().includes("navigation")) tag.kind = "nav";
37
- else if (groupName.toLowerCase().includes("audience")) tag.kind = "audience";
38
- else if (groupName.toLowerCase().includes("badge")) tag.kind = "badge";
39
- else tag.kind = "nav";
36
+ if (groupName) {
37
+ if (groupName.toLowerCase().includes("nav") || groupName.toLowerCase().includes("navigation")) tag.kind = "nav";
38
+ else if (groupName.toLowerCase().includes("audience")) tag.kind = "audience";
39
+ else if (groupName.toLowerCase().includes("badge")) tag.kind = "badge";
40
+ else tag.kind = "nav";
41
+ }
40
42
  }
41
43
  }
42
44
  delete document["x-tagGroups"];
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.11/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js
1
+ //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.13/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js
2
2
  /**
3
3
  * Recursively traverses the content and applies the transform function to each node.
4
4
  */
@@ -1,7 +1,7 @@
1
1
  import { upgradeFromThreeOneToThreeTwo } from "./3.1-to-3.2/upgrade-from-three-one-to-three-two.js";
2
2
  import { upgradeFromTwoToThree } from "./2.0-to-3.0/upgrade-from-two-to-three.js";
3
3
  import { upgradeFromThreeToThreeOne } from "./3.0-to-3.1/upgrade-from-three-to-three-one.js";
4
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.11/node_modules/@scalar/openapi-upgrader/dist/upgrade.js
4
+ //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.13/node_modules/@scalar/openapi-upgrader/dist/upgrade.js
5
5
  function upgrade(value, targetVersion) {
6
6
  const openapi30 = upgradeFromTwoToThree(value);
7
7
  if (targetVersion === "3.0") return openapi30;
@@ -128,8 +128,10 @@ var require_js2xml = /* @__PURE__ */ __commonJSMin(((exports, module) => {
128
128
  xml.push("<" + elementName);
129
129
  if (element[options.attributesKey]) xml.push(writeAttributes(element[options.attributesKey], options, depth));
130
130
  var withClosingTag = element[options.elementsKey] && element[options.elementsKey].length || element[options.attributesKey] && element[options.attributesKey]["xml:space"] === "preserve";
131
- if (!withClosingTag) if ("fullTagEmptyElementFn" in options) withClosingTag = options.fullTagEmptyElementFn(element.name, element);
132
- else withClosingTag = options.fullTagEmptyElement;
131
+ if (!withClosingTag) {
132
+ if ("fullTagEmptyElementFn" in options) withClosingTag = options.fullTagEmptyElementFn(element.name, element);
133
+ else withClosingTag = options.fullTagEmptyElement;
134
+ }
133
135
  if (withClosingTag) {
134
136
  xml.push(">");
135
137
  if (element[options.elementsKey] && element[options.elementsKey].length) {
@@ -192,8 +194,10 @@ var require_js2xml = /* @__PURE__ */ __commonJSMin(((exports, module) => {
192
194
  }
193
195
  if (element[options.attributesKey]) xml.push(writeAttributes(element[options.attributesKey], options, depth));
194
196
  var withClosingTag = hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]["xml:space"] === "preserve";
195
- if (!withClosingTag) if ("fullTagEmptyElementFn" in options) withClosingTag = options.fullTagEmptyElementFn(name, element);
196
- else withClosingTag = options.fullTagEmptyElement;
197
+ if (!withClosingTag) {
198
+ if ("fullTagEmptyElementFn" in options) withClosingTag = options.fullTagEmptyElementFn(name, element);
199
+ else withClosingTag = options.fullTagEmptyElement;
200
+ }
197
201
  if (withClosingTag) xml.push(">");
198
202
  else {
199
203
  xml.push("/>");
@@ -118,7 +118,10 @@ function str(init, mediaType, ctx) {
118
118
  addImport("java.net.http.HttpRequest.BodyPublishers");
119
119
  return `var body = BodyPublishers.ofString(${tripleDoubleQuote(inputToString(init, mediaType))});`;
120
120
  }
121
- if (ctx.lang === "csharp") return `var body = new StringContent(${tripleDoubleQuote(`\n${inputToString(init, mediaType)}\n`)}, Encoding.UTF8, "${mediaType}");`;
121
+ if (ctx.lang === "csharp") {
122
+ const input = `\n${inputToString(init, mediaType)}\n`;
123
+ return `var body = new StringContent(${tripleDoubleQuote(input)}, Encoding.UTF8, "${mediaType}");`;
124
+ }
122
125
  if (ctx.lang === "rust") return `let body = ${rustRawStringLiteral(inputToString(init, mediaType))};`;
123
126
  }
124
127
  //#endregion
@@ -42,9 +42,7 @@ function encodeRequestData(from, adapters, parameters = []) {
42
42
  case "header":
43
43
  result.header[key] = { value: serializeSimple(value, field.explode ?? false) };
44
44
  break;
45
- case "cookie":
46
- serializeCookieParameter(field, value, result.cookie);
47
- break;
45
+ case "cookie": serializeCookieParameter(field, value, result.cookie);
48
46
  }
49
47
  }
50
48
  return result;
@@ -1,5 +1,6 @@
1
- import { getPageProps } from "../utils/pages/builder.js";
1
+ import { fromSchema, getPageProps } from "../utils/pages/builder.js";
2
2
  import { toStaticData } from "../utils/pages/to-static-data.js";
3
+ import { createAutoPreset } from "../utils/pages/preset-auto.js";
3
4
  import { MethodLabel } from "../ui/components/method-label.js";
4
5
  import { createProxy } from "./proxy.js";
5
6
  import { loadDocument } from "../utils/document/load.js";
@@ -10,7 +11,7 @@ import fs from "node:fs";
10
11
  //#region src/server/index.tsx
11
12
  function createOpenAPI(options = {}) {
12
13
  const { disableCache = false } = options;
13
- const schemaMap = /* @__PURE__ */ new Map();
14
+ const docCache = /* @__PURE__ */ new Map();
14
15
  let resolvedInput = {};
15
16
  if (Array.isArray(options.input)) for (const item of options.input) resolvedInput[item] = item;
16
17
  else if (options.input) resolvedInput = options.input;
@@ -20,30 +21,34 @@ function createOpenAPI(options = {}) {
20
21
  return loadDocument(schemaId);
21
22
  }
22
23
  if (!disableCache) {
23
- const cached = schemaMap.get(schemaId);
24
+ const cached = docCache.get(schemaId);
24
25
  if (cached) return cached;
25
26
  }
26
27
  const raw = resolvedInput[schemaId];
27
28
  const output = Promise.resolve(typeof raw === "function" ? raw() : raw).then(loadDocument);
28
- if (!disableCache) schemaMap.set(schemaId, output);
29
+ if (!disableCache) docCache.set(schemaId, output);
29
30
  return output;
30
31
  }
31
32
  async function getSchemas() {
32
33
  const entries = await Promise.all(Object.keys(resolvedInput).map(async (k) => [k, await getSchema(k)]));
33
34
  return Object.fromEntries(entries);
34
35
  }
35
- async function getVirtualFiles(server, options) {
36
+ async function getVirtualFiles(server, options, docFilesCache) {
36
37
  const { baseDir = "", meta = false } = options;
37
- const { createAutoPreset } = await import("../utils/pages/preset-auto.js");
38
- const { fromSchema } = await import("../utils/pages/builder.js");
39
38
  const files = [];
40
- const schemas = await server.getSchemas();
41
39
  const builderOptions = createAutoPreset(options);
42
- for (const [id, schema] of Object.entries(schemas)) {
43
- onEntries(fromSchema(id, schema.bundled, builderOptions));
40
+ for (const [id, schema] of Object.entries(await server.getSchemas())) {
41
+ const cachedDocFiles = docFilesCache?.get(schema);
42
+ if (cachedDocFiles) {
43
+ files.push(...cachedDocFiles);
44
+ continue;
45
+ }
46
+ const entries = onEntries(fromSchema(id, schema.bundled, builderOptions));
47
+ docFilesCache?.set(schema, entries);
48
+ files.push(...entries);
44
49
  function onEntry(entry) {
45
50
  const props = getPageProps(entry);
46
- files.push({
51
+ return {
47
52
  type: "page",
48
53
  path: `${baseDir}/${entry.path}`,
49
54
  data: {
@@ -76,29 +81,29 @@ function createOpenAPI(options = {}) {
76
81
  deprecated: entry.info.deprecated
77
82
  }
78
83
  }
79
- });
84
+ };
80
85
  }
81
86
  function onEntries(entries, parent) {
87
+ const out = [];
82
88
  if (!meta) {
83
- for (const entry of entries) if (entry.type === "group") onEntries(entry.entries, entry);
84
- else onEntry(entry);
85
- return;
89
+ for (const entry of entries) if (entry.type === "group") out.push(...onEntries(entry.entries, entry));
90
+ else out.push(onEntry(entry));
91
+ return out;
86
92
  }
87
93
  const { folderStyle = "folder" } = meta === true ? {} : meta;
88
94
  const pages = [];
89
95
  for (const entry of entries) {
90
96
  const relativePath = PathUtils.slash(parent ? path.relative(parent.path, entry.path) : entry.path);
91
97
  if (entry.type === "group") {
92
- onEntries(entry.entries, entry);
98
+ out.push(...onEntries(entry.entries, entry));
93
99
  if (folderStyle === "folder") pages.push(relativePath);
94
100
  else pages.push(`---${entry.info.title}---`, `...${relativePath}`);
95
101
  } else {
96
- onEntry(entry);
102
+ out.push(onEntry(entry));
97
103
  pages.push(relativePath.slice(0, -path.extname(entry.path).length));
98
104
  }
99
105
  }
100
- if (pages.length === 0) return;
101
- files.push({
106
+ if (pages.length > 0) out.push({
102
107
  type: "meta",
103
108
  path: path.join(baseDir, parent?.path ?? "", "meta.json"),
104
109
  data: {
@@ -107,6 +112,7 @@ function createOpenAPI(options = {}) {
107
112
  pages
108
113
  }
109
114
  });
115
+ return out;
110
116
  }
111
117
  }
112
118
  return files;
@@ -132,7 +138,14 @@ function createOpenAPI(options = {}) {
132
138
  return { files: await getVirtualFiles(this, options) };
133
139
  },
134
140
  dynamicSource(options = {}) {
135
- return { files: () => getVirtualFiles(this, options) };
141
+ const docFilesCache = /* @__PURE__ */ new WeakMap();
142
+ return {
143
+ cache: "custom",
144
+ files: () => getVirtualFiles(this, options, docFilesCache),
145
+ invalidate() {
146
+ docCache.clear();
147
+ }
148
+ };
136
149
  },
137
150
  loaderPlugin() {
138
151
  return openapiPlugin();
@@ -79,7 +79,6 @@ function createProxy(options = {}) {
79
79
  body = void 0;
80
80
  headers.delete("content-length");
81
81
  headers.delete("content-type");
82
- break;
83
82
  }
84
83
  url = next.href;
85
84
  }
package/dist/ui/base.js CHANGED
@@ -4,10 +4,10 @@ import { ClientCodeBlock } from "./components/codeblock.js";
4
4
  import { createCodeUsageGeneratorRegistry } from "../requests/generators/index.js";
5
5
  import { defaultAdapters } from "../requests/media/adapter.js";
6
6
  import { AuthProvider } from "../playground/auth.js";
7
- import { registerDefault } from "../requests/generators/all.js";
8
7
  import { Markdown } from "./components/markdown.js";
9
8
  import { Operation } from "./operation/index.js";
10
9
  import { dereferenceBundledDocument } from "../utils/document/dereference.js";
10
+ import { registerDefault } from "../requests/generators/all.js";
11
11
  import { getRaw } from "@scalar/json-magic/magic-proxy";
12
12
  import { Children, useMemo } from "react";
13
13
  import * as JsxRuntime from "react/jsx-runtime";
@@ -168,8 +168,9 @@ function MarkdownPre(props) {
168
168
  const codeProps = Children.only(props.children).props;
169
169
  const content = codeProps.children;
170
170
  if (typeof content !== "string") return null;
171
+ const lang = codeProps.className?.split(" ").find((v) => v.startsWith("language-"))?.slice(9) ?? "text";
171
172
  return /* @__PURE__ */ jsx(ClientCodeBlock, {
172
- lang: codeProps.className?.split(" ").find((v) => v.startsWith("language-"))?.slice(9) ?? "text",
173
+ lang,
173
174
  code: content.trimEnd()
174
175
  });
175
176
  }
@@ -1,4 +1,4 @@
1
- import { upgrade } from "../../node_modules/.pnpm/@scalar_openapi-upgrader@0.2.11/node_modules/@scalar/openapi-upgrader/dist/upgrade.js";
1
+ import { upgrade } from "../../node_modules/.pnpm/@scalar_openapi-upgrader@0.2.13/node_modules/@scalar/openapi-upgrader/dist/upgrade.js";
2
2
  import { bundle } from "@fumadocs/api-docs/schema/bundle";
3
3
  //#region src/utils/document/load.ts
4
4
  /**
@@ -3,8 +3,13 @@ import { dereferenceShallow } from "@fumadocs/api-docs/schema/dereference";
3
3
  import { createMagicProxy } from "@scalar/json-magic/magic-proxy";
4
4
  import Slugger from "github-slugger";
5
5
  //#region src/utils/pages/to-static-data.ts
6
+ const proxyCache = /* @__PURE__ */ new WeakMap();
6
7
  function toStaticData(page, doc) {
7
- const proxied = createMagicProxy(doc);
8
+ let proxied = proxyCache.get(doc);
9
+ if (!proxied) {
10
+ proxied = createMagicProxy(doc);
11
+ proxyCache.set(doc, proxied);
12
+ }
8
13
  const slugger = new Slugger();
9
14
  const toc = [];
10
15
  const structuredData = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-openapi",
3
- "version": "11.2.3",
3
+ "version": "11.3.0",
4
4
  "description": "Generate MDX docs for your OpenAPI spec",
5
5
  "keywords": [
6
6
  "Docs",
@@ -45,39 +45,39 @@
45
45
  "dependencies": {
46
46
  "@fuma-translate/react": "^1.0.2",
47
47
  "@fumari/json-schema-ts": "^1.0.2",
48
- "@scalar/json-magic": "^0.12.19",
48
+ "@scalar/json-magic": "^0.12.20",
49
49
  "chokidar": "^5.0.0",
50
50
  "class-variance-authority": "^0.7.1",
51
51
  "cnfast": "^0.1.0",
52
52
  "github-slugger": "^2.0.0",
53
53
  "hast-util-to-jsx-runtime": "^2.3.6",
54
- "lucide-react": "^1.27.0",
54
+ "lucide-react": "^1.31.0",
55
55
  "remark": "^15.0.1",
56
56
  "remark-rehype": "^11.1.2",
57
- "shiki": "^4.3.1",
57
+ "shiki": "^4.4.3",
58
58
  "yaml": "^2.9.0",
59
- "@fumadocs/api-docs": "0.2.2",
59
+ "@fumadocs/api-docs": "0.2.3",
60
60
  "@fumari/stf": "1.1.0"
61
61
  },
62
62
  "devDependencies": {
63
- "@scalar/api-client-react": "^2.0.36",
64
- "@scalar/openapi-upgrader": "^0.2.11",
63
+ "@scalar/api-client-react": "^2.0.38",
64
+ "@scalar/openapi-upgrader": "^0.2.13",
65
65
  "@tailwindcss/oxide": "^4.3.3",
66
- "@types/node": "26.1.2",
67
- "@types/react": "^19.2.17",
66
+ "@types/node": "26.2.0",
67
+ "@types/react": "^19.2.18",
68
68
  "fast-content-type-parse": "^3.0.0",
69
69
  "json-schema-typed": "^8.0.2",
70
70
  "tsdown": "0.22.14",
71
71
  "xml-js": "^1.6.11",
72
- "fumadocs-ui": "npm:@fumadocs/base-ui@16.14.0",
73
- "fumadocs-core": "16.14.0",
72
+ "fumadocs-core": "16.15.0",
73
+ "fumadocs-ui": "npm:@fumadocs/base-ui@16.15.0",
74
74
  "tsconfig": "0.0.0"
75
75
  },
76
76
  "peerDependencies": {
77
77
  "@scalar/api-client-react": "^2.0.20",
78
78
  "@types/react": "*",
79
- "fumadocs-core": "^16.10.0",
80
- "fumadocs-ui": "^16.10.0",
79
+ "fumadocs-core": "^16.15.0",
80
+ "fumadocs-ui": "^16.15.0",
81
81
  "json-schema-typed": "*",
82
82
  "react": "^19.2.0",
83
83
  "react-dom": "^19.2.0"
@@ -94,7 +94,7 @@
94
94
  }
95
95
  },
96
96
  "inlinedDependencies": {
97
- "@scalar/openapi-upgrader": "0.2.11",
97
+ "@scalar/openapi-upgrader": "0.2.13",
98
98
  "fast-content-type-parse": "3.0.0",
99
99
  "xml-js": "1.6.11"
100
100
  },