fumadocs-openapi 4.3.1 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -51,13 +51,20 @@ interface Renderer {
51
51
 
52
52
  declare const defaultRenderer: Renderer;
53
53
 
54
+ /**
55
+ * Sample info of endpoint
56
+ */
54
57
  interface Endpoint {
55
58
  /**
56
- * URL, including path and query parameters
59
+ * Request URL, including path and query parameters
57
60
  */
58
61
  url: string;
59
62
  method: string;
60
- body?: unknown;
63
+ body?: {
64
+ schema: OpenAPIV3.SchemaObject;
65
+ mediaType: string;
66
+ sample: unknown;
67
+ };
61
68
  responses: Record<string, Response>;
62
69
  parameters: Parameter[];
63
70
  }
@@ -68,6 +75,7 @@ interface Parameter {
68
75
  name: string;
69
76
  in: string;
70
77
  schema: OpenAPIV3.SchemaObject;
78
+ sample: unknown;
71
79
  }
72
80
 
73
81
  interface CodeSample {
package/dist/index.js CHANGED
@@ -143,6 +143,9 @@ function idToTitle(id) {
143
143
  return result.join("");
144
144
  }
145
145
 
146
+ // src/endpoint.ts
147
+ import { sample as sample2 } from "openapi-sampler";
148
+
146
149
  // src/utils/schema.ts
147
150
  function noRef(v) {
148
151
  return v;
@@ -173,18 +176,41 @@ function createEndpoint(path, method, baseUrl) {
173
176
  const params = [];
174
177
  const responses = {};
175
178
  for (const param of method.parameters) {
176
- const schema = noRef(
177
- param.schema ?? getPreferredMedia(param.content ?? {})?.schema
178
- );
179
- if (!schema) continue;
180
- params.push({
181
- name: param.name,
182
- in: param.in,
183
- schema
184
- });
179
+ if (param.schema) {
180
+ params.push({
181
+ name: param.name,
182
+ in: param.in,
183
+ schema: noRef(param.schema),
184
+ sample: param.example ?? sample2(param.schema)
185
+ });
186
+ } else if (param.content) {
187
+ const key = getPreferredType(param.content);
188
+ const content = key ? param.content[key] : void 0;
189
+ if (!key || !content?.schema)
190
+ throw new Error(
191
+ `Cannot find parameter schema for ${param.name} in ${path} ${method.method}`
192
+ );
193
+ params.push({
194
+ name: param.name,
195
+ in: param.in,
196
+ schema: noRef(content.schema),
197
+ sample: content.example ?? param.example ?? sample2(content.schema)
198
+ });
199
+ }
200
+ }
201
+ let bodyOutput;
202
+ if (method.requestBody) {
203
+ const body = noRef(method.requestBody).content;
204
+ const type = getPreferredType(body);
205
+ const schema = type ? noRef(body[type].schema) : void 0;
206
+ if (!type || !schema)
207
+ throw new Error(`Cannot find body schema for ${path} ${method.method}`);
208
+ bodyOutput = {
209
+ schema,
210
+ mediaType: type,
211
+ sample: body[type].example ?? generateInput(method.method, schema)
212
+ };
185
213
  }
186
- const body = noRef(method.requestBody)?.content ?? {};
187
- const bodySchema = noRef(getPreferredMedia(body)?.schema);
188
214
  for (const [code, value] of Object.entries(method.responses)) {
189
215
  const mediaTypes = noRef(value).content ?? {};
190
216
  const responseSchema = noRef(getPreferredMedia(mediaTypes)?.schema);
@@ -209,7 +235,7 @@ function createEndpoint(path, method, baseUrl) {
209
235
  pathWithParameters = `${pathWithParameters}?${queryParams.toString()}`;
210
236
  return {
211
237
  url: new URL(`${baseUrl}${pathWithParameters}`).toString(),
212
- body: bodySchema ? generateInput(method.method, bodySchema) : void 0,
238
+ body: bodyOutput,
213
239
  responses,
214
240
  method: method.method,
215
241
  parameters: params
@@ -233,15 +259,13 @@ function getSampleRequest(endpoint) {
233
259
  s.push(`curl -X ${endpoint.method} "${endpoint.url}"`);
234
260
  for (const param of endpoint.parameters) {
235
261
  if (param.in === "header") {
236
- const value = generateInput(endpoint.method, param.schema);
237
- const header = `${param.name}: ${toSampleInput(value)}`;
262
+ const header = `${param.name}: ${toSampleInput(param.sample)}`;
238
263
  s.push(`-H "${header}"`);
239
264
  }
240
- if (param.in === "formData") {
241
- console.log("Request example for form data is not supported");
242
- }
243
265
  }
244
- if (endpoint.body) s.push(`-d '${toSampleInput(endpoint.body)}'`);
266
+ if (endpoint.body?.mediaType === "multipart/form-data")
267
+ console.warn("Curl sample with form data body isn't supported.");
268
+ if (endpoint.body) s.push(`-d '${toSampleInput(endpoint.body.sample)}'`);
245
269
  return s.join(" \\\n ");
246
270
  }
247
271
 
@@ -250,24 +274,25 @@ function getSampleRequest2(endpoint) {
250
274
  const s = [];
251
275
  const options = /* @__PURE__ */ new Map();
252
276
  const headers = {};
253
- const formData = {};
254
277
  for (const param of endpoint.parameters) {
255
278
  if (param.in === "header") {
256
279
  headers[param.name] = generateInput(endpoint.method, param.schema);
257
280
  }
258
- if (param.in === "formData") {
259
- formData[param.name] = generateInput(endpoint.method, param.schema);
260
- }
261
281
  }
262
282
  options.set("method", JSON.stringify(endpoint.method));
263
283
  if (Object.keys(headers).length > 0) {
264
284
  options.set("headers", JSON.stringify(headers, void 0, 2));
265
285
  }
266
- if (Object.keys(formData).length > 0) {
286
+ if (endpoint.body?.mediaType === "multipart/form-data" && typeof endpoint.body.sample === "object" && endpoint.body.sample) {
267
287
  s.push(`const formData = new FormData();`);
268
- for (const [key, value] of Object.entries(formData))
269
- s.push(`formData.set(${key}, ${JSON.stringify(value)}`);
288
+ for (const [key, value] of Object.entries(endpoint.body.sample))
289
+ s.push(`formData.set(${key}, ${JSON.stringify(value)})`);
270
290
  options.set("body", "formData");
291
+ } else if (endpoint.body) {
292
+ options.set(
293
+ "body",
294
+ `JSON.stringify(${JSON.stringify(endpoint.body.sample, null, 2).split("\n").map((v, i) => i > 0 ? ` ${v}` : v).join("\n")})`
295
+ );
271
296
  }
272
297
  const optionsStr = Array.from(options.entries()).map(([k, v]) => ` ${k}: ${v}`).join(",\n");
273
298
  s.push(`fetch(${JSON.stringify(endpoint.url)}, {
package/dist/ui/index.js CHANGED
@@ -71,12 +71,12 @@ function APIInfo({
71
71
  method = "GET",
72
72
  ...props
73
73
  }) {
74
- return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0 flex-1 prose-no-margin", className), ...props, children: [
74
+ return /* @__PURE__ */ jsxs("div", { className: cn("min-w-0 flex-1", className), ...props, children: [
75
75
  /* @__PURE__ */ jsxs(
76
76
  "div",
77
77
  {
78
78
  className: cn(
79
- "sticky top-24 z-[2] flex flex-row items-center gap-2 rounded-lg border bg-fd-card p-3 md:top-10"
79
+ "sticky top-24 z-[2] mb-4 flex flex-row items-center gap-2 rounded-lg border bg-fd-card p-3 md:top-10"
80
80
  ),
81
81
  children: [
82
82
  /* @__PURE__ */ jsx(
@@ -94,7 +94,7 @@ function APIInfo({
94
94
  ]
95
95
  }
96
96
  ),
97
- children
97
+ /* @__PURE__ */ jsx("div", { className: "prose-no-margin", children })
98
98
  ] });
99
99
  }
100
100
  function Property({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-openapi",
3
- "version": "4.3.1",
3
+ "version": "4.4.1",
4
4
  "description": "Generate MDX docs for your OpenAPI spec",
5
5
  "keywords": [
6
6
  "NextJs",
@@ -56,8 +56,8 @@
56
56
  "react-hook-form": "^7.52.1",
57
57
  "shiki": "^1.11.1",
58
58
  "swr": "^2.2.5",
59
- "fumadocs-core": "13.0.4",
60
- "fumadocs-ui": "13.0.4"
59
+ "fumadocs-core": "13.0.6",
60
+ "fumadocs-ui": "13.0.6"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/js-yaml": "^4.0.9",