@farming-labs/next 0.1.9 → 0.1.11

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,9 +1,39 @@
1
1
  import { resolveApiReferenceConfig } from "@farming-labs/docs/server";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
3
  import { DocsConfig } from "@farming-labs/docs";
3
4
 
4
5
  //#region src/api-reference.d.ts
6
+ interface NextApiReferenceSourceState {
7
+ apiReference: ReturnType<typeof resolveApiReferenceConfig>;
8
+ document: Record<string, unknown>;
9
+ info: {
10
+ title: string;
11
+ description?: string;
12
+ };
13
+ pages: Array<{
14
+ url: string;
15
+ } & Record<string, any>>;
16
+ server: any;
17
+ source: {
18
+ getPage: (slug?: string[]) => any;
19
+ getPages: () => Array<any>;
20
+ getPageTree: () => any;
21
+ };
22
+ }
5
23
  declare function buildNextOpenApiDocument(config: DocsConfig): Record<string, unknown>;
6
24
  declare function withNextApiReferenceBanner(config: DocsConfig): DocsConfig;
7
- declare function createNextApiReference(config: DocsConfig): () => Promise<Response>;
25
+ declare function createNextApiReference(config: DocsConfig): (request?: Request) => Promise<Response>;
26
+ declare function createNextApiReferencePage(config: DocsConfig): (props?: {
27
+ params?: Promise<{
28
+ slug?: string[];
29
+ }> | {
30
+ slug?: string[];
31
+ };
32
+ }) => Promise<react_jsx_runtime0.JSX.Element>;
33
+ declare function createNextApiReferenceLayout(config: DocsConfig): (props: {
34
+ children: React.ReactNode;
35
+ }) => Promise<react_jsx_runtime0.JSX.Element>;
36
+ declare function getNextApiReferenceSourceState(config: DocsConfig): Promise<NextApiReferenceSourceState>;
37
+ declare function getNextApiReferenceMode(config: DocsConfig): "fumadocs" | "scalar";
8
38
  //#endregion
9
- export { buildNextOpenApiDocument, createNextApiReference, resolveApiReferenceConfig, withNextApiReferenceBanner };
39
+ export { NextApiReferenceSourceState, buildNextOpenApiDocument, createNextApiReference, createNextApiReferenceLayout, createNextApiReferencePage, getNextApiReferenceMode, getNextApiReferenceSourceState, resolveApiReferenceConfig, withNextApiReferenceBanner };
@@ -1,8 +1,11 @@
1
+ import DocsClientCallbacks from "./client-callbacks.mjs";
1
2
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
3
  import { join, relative } from "node:path";
3
4
  import { ApiReference } from "@scalar/nextjs-api-reference";
4
- import { buildApiReferenceOpenApiDocumentAsync, buildApiReferencePageTitle, buildApiReferenceScalarCss, resolveApiReferenceConfig } from "@farming-labs/docs/server";
5
- import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { buildApiReferenceOpenApiDocumentAsync, buildApiReferencePageTitle, buildApiReferenceScalarCss, resolveApiReferenceConfig, resolveApiReferenceRenderer } from "@farming-labs/docs/server";
6
+ import Link from "next/link";
7
+ import { notFound } from "next/navigation";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
9
 
7
10
  //#region src/api-reference.tsx
8
11
  const ROUTE_FILE_RE = /^route\.(ts|tsx|js|jsx)$/;
@@ -43,6 +46,9 @@ function shouldExcludeRoute(excludes, routePath, relativeFile, relativeDir) {
43
46
  function humanizeSegment(value) {
44
47
  return value.replace(/^\[\[?\.{3}/, "").replace(/^\[/, "").replace(/\]\]?$/, "").replace(/^\$/, "").replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
45
48
  }
49
+ function slugifyApiReferencePageName(value) {
50
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
51
+ }
46
52
  function endpointSegmentFromFsSegment(value) {
47
53
  if (value.startsWith("[[...") && value.endsWith("]]")) return `{${value.slice(5, -2)}}`;
48
54
  if (value.startsWith("[...") && value.endsWith("]")) return `{${value.slice(4, -1)}}`;
@@ -97,6 +103,25 @@ function isThemeToggleHidden(config) {
97
103
  if (config.themeToggle && typeof config.themeToggle === "object") return config.themeToggle.enabled === false;
98
104
  return false;
99
105
  }
106
+ function getOriginFromRequest(request) {
107
+ if (!request) return void 0;
108
+ try {
109
+ return new URL(request.url).origin;
110
+ } catch {
111
+ return;
112
+ }
113
+ }
114
+ function getForwardedHeaderValue(value) {
115
+ if (!value) return void 0;
116
+ return value.split(",").map((entry) => entry.trim()).find(Boolean) || void 0;
117
+ }
118
+ async function getOriginFromNextHeaders() {
119
+ const { headers } = await import("next/headers");
120
+ const headerList = await headers();
121
+ const host = getForwardedHeaderValue(headerList.get("x-forwarded-host")) ?? getForwardedHeaderValue(headerList.get("host"));
122
+ if (!host) return void 0;
123
+ return `${getForwardedHeaderValue(headerList.get("x-forwarded-proto")) ?? "https"}://${host}`;
124
+ }
100
125
  function buildPathParameters(fsSegments) {
101
126
  const parameters = [];
102
127
  for (const segment of fsSegments) {
@@ -203,7 +228,7 @@ function buildNextOpenApiDocument(config) {
203
228
  openapi: "3.1.0",
204
229
  info: {
205
230
  title: "API Reference",
206
- description: "Remote OpenAPI specs are resolved at request time through createNextApiReference().",
231
+ description: "Remote OpenAPI specs are resolved at request time through the Next.js API reference renderer.",
207
232
  version: "0.0.0"
208
233
  },
209
234
  servers: [{ url: "/" }],
@@ -227,25 +252,80 @@ function buildNextOpenApiDocument(config) {
227
252
  paths: buildOpenApiPaths(routes)
228
253
  };
229
254
  }
230
- function DropdownIcon({ current, radius }) {
231
- const label = current === "api" ? "</>" : "▣";
255
+ function SwitcherGlyph({ kind, radius, active }) {
256
+ const isApi = kind === "api";
232
257
  return /* @__PURE__ */ jsx("span", {
233
258
  "aria-hidden": "true",
234
259
  style: {
235
260
  display: "inline-flex",
236
- width: 20,
237
- height: 20,
261
+ width: 22,
262
+ height: 22,
238
263
  alignItems: "center",
239
264
  justifyContent: "center",
240
265
  borderRadius: radius,
241
266
  border: "1px solid color-mix(in srgb, var(--color-fd-border, #2a2a2a) 100%, transparent)",
242
267
  background: "color-mix(in srgb, var(--color-fd-card, #161616) 92%, transparent)",
243
- color: "var(--color-fd-primary, currentColor)",
244
- boxShadow: "0 0 0 1px color-mix(in srgb, var(--color-fd-border, #2a2a2a) 32%, transparent)",
245
- fontSize: 9,
246
- fontWeight: 700
268
+ color: active ? "var(--color-fd-primary, currentColor)" : "var(--color-fd-muted-foreground, rgba(255,255,255,0.72))",
269
+ boxShadow: "0 0 0 1px color-mix(in srgb, var(--color-fd-border, #2a2a2a) 32%, transparent)"
247
270
  },
248
- children: label
271
+ children: isApi ? /* @__PURE__ */ jsx("svg", {
272
+ width: "13",
273
+ height: "13",
274
+ viewBox: "0 0 24 24",
275
+ fill: "none",
276
+ children: /* @__PURE__ */ jsx("path", {
277
+ d: "M8 8L4 12L8 16M16 8L20 12L16 16M13.5 6L10.5 18",
278
+ stroke: "currentColor",
279
+ strokeWidth: "1.8",
280
+ strokeLinecap: "round",
281
+ strokeLinejoin: "round"
282
+ })
283
+ }) : /* @__PURE__ */ jsx("svg", {
284
+ width: "13",
285
+ height: "13",
286
+ viewBox: "0 0 24 24",
287
+ fill: "none",
288
+ children: /* @__PURE__ */ jsx("path", {
289
+ d: "M4.75 6.75C4.75 5.64543 5.64543 4.75 6.75 4.75H11.25V19.25H6.75C5.64543 19.25 4.75 18.3546 4.75 17.25V6.75ZM12.75 4.75H17.25C18.3546 4.75 19.25 5.64543 19.25 6.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H12.75V4.75Z",
290
+ stroke: "currentColor",
291
+ strokeWidth: "1.8",
292
+ strokeLinejoin: "round"
293
+ })
294
+ })
295
+ });
296
+ }
297
+ function ChevronStack() {
298
+ return /* @__PURE__ */ jsxs("span", {
299
+ "aria-hidden": "true",
300
+ style: {
301
+ display: "inline-flex",
302
+ flexDirection: "column",
303
+ gap: 2,
304
+ color: "var(--color-fd-muted-foreground, rgba(255,255,255,0.65))"
305
+ },
306
+ children: [/* @__PURE__ */ jsx("svg", {
307
+ width: "11",
308
+ height: "7",
309
+ viewBox: "0 0 10 6",
310
+ fill: "none",
311
+ children: /* @__PURE__ */ jsx("path", {
312
+ d: "M1 5L5 1L9 5",
313
+ stroke: "currentColor",
314
+ strokeWidth: "1.5",
315
+ strokeLinecap: "round"
316
+ })
317
+ }), /* @__PURE__ */ jsx("svg", {
318
+ width: "11",
319
+ height: "7",
320
+ viewBox: "0 0 10 6",
321
+ fill: "none",
322
+ children: /* @__PURE__ */ jsx("path", {
323
+ d: "M1 1L5 5L9 1",
324
+ stroke: "currentColor",
325
+ strokeWidth: "1.5",
326
+ strokeLinecap: "round"
327
+ })
328
+ })]
249
329
  });
250
330
  }
251
331
  function getApiReferenceSwitcherTheme(config) {
@@ -260,87 +340,191 @@ function getApiReferenceSwitcherTheme(config) {
260
340
  backgroundImage: isPixelBorder ? "repeating-linear-gradient(-45deg, color-mix(in srgb, var(--color-fd-border) 10%, transparent), color-mix(in srgb, var(--color-fd-border) 10%, transparent) 1px, transparent 1px, transparent 6px)" : void 0,
261
341
  boxShadow: isPixelBorder || isDarksharp ? "none" : isShiny ? "0 14px 40px color-mix(in srgb, var(--color-fd-border, #2a2a2a) 18%, transparent)" : "0 0 0 1px color-mix(in srgb, var(--color-fd-border, #2a2a2a) 32%, transparent)",
262
342
  titleStyle: {
263
- fontFamily: isPixelBorder ? "var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace))" : void 0,
343
+ fontFamily: isPixelBorder ? "var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace))" : "var(--fd-font-sans, var(--font-geist-sans, system-ui, sans-serif))",
264
344
  textTransform: isPixelBorder ? "uppercase" : void 0,
265
345
  letterSpacing: isPixelBorder ? "0.08em" : void 0,
266
- fontSize: isPixelBorder ? 12 : 14
346
+ fontSize: isPixelBorder ? 12 : 13
267
347
  },
268
348
  descriptionStyle: {
269
- fontFamily: isPixelBorder ? "var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace))" : void 0,
349
+ fontFamily: isPixelBorder ? "var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace))" : "var(--fd-font-sans, var(--font-geist-sans, system-ui, sans-serif))",
270
350
  textTransform: isPixelBorder ? "uppercase" : void 0,
271
351
  letterSpacing: isPixelBorder ? "0.04em" : void 0,
272
- fontSize: isPixelBorder ? 11 : 12,
273
- opacity: isPixelBorder ? .74 : .62
352
+ fontSize: isPixelBorder ? 11 : 11,
353
+ opacity: isPixelBorder ? .74 : .72
274
354
  }
275
355
  };
276
356
  }
277
- function SwitcherOption({ href, title, description, current, config }) {
357
+ const API_REFERENCE_COLOR_MAP = {
358
+ primary: "--color-fd-primary",
359
+ primaryForeground: "--color-fd-primary-foreground",
360
+ background: "--color-fd-background",
361
+ foreground: "--color-fd-foreground",
362
+ muted: "--color-fd-muted",
363
+ mutedForeground: "--color-fd-muted-foreground",
364
+ border: "--color-fd-border",
365
+ card: "--color-fd-card",
366
+ cardForeground: "--color-fd-card-foreground",
367
+ accent: "--color-fd-accent",
368
+ accentForeground: "--color-fd-accent-foreground",
369
+ popover: "--color-fd-popover",
370
+ popoverForeground: "--color-fd-popover-foreground",
371
+ secondary: "--color-fd-secondary",
372
+ secondaryForeground: "--color-fd-secondary-foreground",
373
+ ring: "--color-fd-ring"
374
+ };
375
+ function buildApiReferenceColorsCSS(colors) {
376
+ if (!colors) return "";
377
+ const vars = [];
378
+ for (const [key, value] of Object.entries(colors)) {
379
+ if (!value || !API_REFERENCE_COLOR_MAP[key]) continue;
380
+ vars.push(`${API_REFERENCE_COLOR_MAP[key]}: ${value};`);
381
+ }
382
+ if (vars.length === 0) return "";
383
+ const block = vars.join("\n ");
384
+ return `:root {\n ${block}\n}\n.dark {\n ${block}\n}`;
385
+ }
386
+ function ApiReferenceColorStyle({ colors }) {
387
+ const css = buildApiReferenceColorsCSS(colors);
388
+ if (!css) return null;
389
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } });
390
+ }
391
+ function buildApiReferenceFontStyleVars(prefix, style) {
392
+ if (!style) return "";
393
+ const parts = [];
394
+ if (style.size) parts.push(`${prefix}-size: ${style.size};`);
395
+ if (style.weight != null) parts.push(`${prefix}-weight: ${style.weight};`);
396
+ if (style.lineHeight) parts.push(`${prefix}-line-height: ${style.lineHeight};`);
397
+ if (style.letterSpacing) parts.push(`${prefix}-letter-spacing: ${style.letterSpacing};`);
398
+ return parts.join("\n ");
399
+ }
400
+ function buildApiReferenceTypographyCSS(typography) {
401
+ if (!typography?.font) return "";
402
+ const vars = [];
403
+ const fontStyle = typography.font.style;
404
+ if (fontStyle?.sans) vars.push(`--fd-font-sans: ${fontStyle.sans};`);
405
+ if (fontStyle?.mono) vars.push(`--fd-font-mono: ${fontStyle.mono};`);
406
+ for (const element of [
407
+ "h1",
408
+ "h2",
409
+ "h3",
410
+ "h4",
411
+ "body",
412
+ "small"
413
+ ]) {
414
+ const style = typography.font[element];
415
+ if (!style) continue;
416
+ const cssVars = buildApiReferenceFontStyleVars(`--fd-${element}`, style);
417
+ if (cssVars) vars.push(cssVars);
418
+ }
419
+ if (vars.length === 0) return "";
420
+ return `:root {\n ${vars.join("\n ")}\n}`;
421
+ }
422
+ function ApiReferenceTypographyStyle({ typography }) {
423
+ const css = buildApiReferenceTypographyCSS(typography);
424
+ if (!css) return null;
425
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } });
426
+ }
427
+ function ApiReferenceLayoutStyle({ layout }) {
428
+ if (!layout) return null;
429
+ const rootVars = [];
430
+ const desktopRootVars = [];
431
+ const desktopGridVars = [];
432
+ if (layout.sidebarWidth) {
433
+ const value = `--fd-sidebar-width: ${layout.sidebarWidth}px`;
434
+ desktopRootVars.push(`${value};`);
435
+ desktopGridVars.push(`${value} !important;`);
436
+ }
437
+ if (layout.contentWidth) rootVars.push(`--fd-content-width: ${layout.contentWidth}px;`);
438
+ if (layout.tocWidth) {
439
+ const value = `--fd-toc-width: ${layout.tocWidth}px`;
440
+ desktopRootVars.push(`${value};`);
441
+ desktopGridVars.push(`${value} !important;`);
442
+ }
443
+ if (rootVars.length === 0 && desktopRootVars.length === 0) return null;
444
+ const parts = [];
445
+ if (rootVars.length > 0) parts.push(`:root {\n ${rootVars.join("\n ")}\n}`);
446
+ if (desktopRootVars.length > 0) {
447
+ const inner = [`:root {\n ${desktopRootVars.join("\n ")}\n }`];
448
+ if (desktopGridVars.length > 0) inner.push(`[style*="fd-sidebar-col"] {\n ${desktopGridVars.join("\n ")}\n }`);
449
+ parts.push(`@media (min-width: 1024px) {\n ${inner.join("\n ")}\n}`);
450
+ }
451
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: parts.join("\n") } });
452
+ }
453
+ function resolveApiReferenceThemeSwitch(toggle) {
454
+ if (toggle === void 0 || toggle === true) return { enabled: true };
455
+ if (toggle === false) return { enabled: false };
456
+ return {
457
+ enabled: toggle.enabled !== false,
458
+ mode: toggle.mode
459
+ };
460
+ }
461
+ function ApiReferenceForcedThemeScript({ theme }) {
462
+ return /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: `document.documentElement.classList.remove('light','dark');document.documentElement.classList.add('${theme}');` } });
463
+ }
464
+ function ApiReferenceThemeBridge({ config }) {
465
+ const colors = config.theme?._userColorOverrides;
466
+ const typography = config.theme?.ui?.typography;
467
+ const layout = config.theme?.ui?.layout;
468
+ const themeSwitch = resolveApiReferenceThemeSwitch(config.themeToggle);
469
+ const toggleConfig = typeof config.themeToggle === "object" ? config.themeToggle : void 0;
470
+ const forcedTheme = themeSwitch.enabled === false && toggleConfig?.default && toggleConfig.default !== "system" ? toggleConfig.default : void 0;
471
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
472
+ /* @__PURE__ */ jsx(ApiReferenceColorStyle, { colors }),
473
+ /* @__PURE__ */ jsx(ApiReferenceTypographyStyle, { typography }),
474
+ /* @__PURE__ */ jsx(ApiReferenceLayoutStyle, { layout }),
475
+ forcedTheme ? /* @__PURE__ */ jsx(ApiReferenceForcedThemeScript, { theme: forcedTheme }) : null
476
+ ] });
477
+ }
478
+ function SwitcherOption({ href, kind, title, description, current, config }) {
278
479
  const theme = getApiReferenceSwitcherTheme(config);
279
- return /* @__PURE__ */ jsxs("a", {
480
+ return /* @__PURE__ */ jsxs(Link, {
280
481
  href,
482
+ prefetch: true,
281
483
  style: {
282
484
  display: "grid",
283
- gridTemplateColumns: "20px 1fr 14px",
485
+ gridTemplateColumns: "22px minmax(0, 1fr)",
284
486
  gap: 12,
285
487
  alignItems: "start",
286
488
  padding: "11px 12px",
287
- borderRadius: theme.cardRadius,
489
+ borderRadius: "0.625rem",
288
490
  textDecoration: "none",
289
491
  color: "inherit",
290
- background: current ? "color-mix(in srgb, var(--color-fd-primary, #3a7) 10%, transparent)" : "transparent",
291
- backgroundImage: !current ? theme.backgroundImage : void 0
492
+ background: current ? "linear-gradient(90deg, color-mix(in srgb, var(--color-fd-primary, #facc15) 20%, transparent), color-mix(in srgb, var(--color-fd-primary, #facc15) 14%, transparent))" : "transparent",
493
+ backgroundImage: current ? theme.backgroundImage : void 0
292
494
  },
293
- children: [
294
- /* @__PURE__ */ jsx("span", {
295
- "aria-hidden": "true",
296
- style: {
297
- display: "inline-flex",
298
- width: 20,
299
- height: 20,
300
- alignItems: "center",
301
- justifyContent: "center",
302
- borderRadius: theme.iconRadius,
303
- border: "1px solid color-mix(in srgb, var(--color-fd-border, #2a2a2a) 100%, transparent)",
304
- color: current ? "var(--color-fd-primary, currentColor)" : "var(--color-fd-muted-foreground, rgba(255,255,255,0.62))",
305
- background: "color-mix(in srgb, var(--color-fd-card, #161616) 92%, transparent)",
306
- boxShadow: "0 0 0 1px color-mix(in srgb, var(--color-fd-border, #2a2a2a) 32%, transparent)",
307
- fontSize: 9,
308
- fontWeight: 700
309
- },
310
- children: title === "API Reference" ? "</>" : "▣"
311
- }),
312
- /* @__PURE__ */ jsxs("span", {
495
+ children: [/* @__PURE__ */ jsx("span", {
496
+ style: {
497
+ display: "inline-flex",
498
+ alignSelf: "start",
499
+ paddingTop: 1
500
+ },
501
+ children: /* @__PURE__ */ jsx(SwitcherGlyph, {
502
+ kind,
503
+ radius: theme.iconRadius,
504
+ active: current
505
+ })
506
+ }), /* @__PURE__ */ jsxs("span", {
507
+ style: {
508
+ display: "flex",
509
+ minWidth: 0,
510
+ flexDirection: "column",
511
+ gap: 3
512
+ },
513
+ children: [/* @__PURE__ */ jsx("span", {
313
514
  style: {
314
- display: "flex",
315
- flexDirection: "column",
316
- gap: 4
515
+ fontWeight: 600,
516
+ lineHeight: 1.2,
517
+ ...theme.titleStyle
317
518
  },
318
- children: [/* @__PURE__ */ jsx("span", {
319
- style: {
320
- fontWeight: 600,
321
- lineHeight: 1.25,
322
- ...theme.titleStyle
323
- },
324
- children: title
325
- }), /* @__PURE__ */ jsx("span", {
326
- style: {
327
- lineHeight: 1.4,
328
- ...theme.descriptionStyle
329
- },
330
- children: description
331
- })]
332
- }),
333
- /* @__PURE__ */ jsx("span", {
334
- "aria-hidden": "true",
519
+ children: title
520
+ }), /* @__PURE__ */ jsx("span", {
335
521
  style: {
336
- fontSize: 12,
337
- opacity: current ? 1 : 0,
338
- color: "var(--color-fd-primary, currentColor)",
339
- paddingTop: 2
522
+ lineHeight: 1.4,
523
+ ...theme.descriptionStyle
340
524
  },
341
- children: "✓"
342
- })
343
- ]
525
+ children: description
526
+ })]
527
+ })]
344
528
  });
345
529
  }
346
530
  function ApiReferenceSwitcher({ docsUrl, apiUrl, current, config }) {
@@ -365,59 +549,59 @@ function ApiReferenceSwitcher({ docsUrl, apiUrl, current, config }) {
365
549
  justifyContent: "space-between",
366
550
  gap: 10,
367
551
  cursor: "pointer",
368
- padding: "11px 13px",
369
- background: "color-mix(in srgb, var(--color-fd-card, #202020) 96%, transparent)",
370
- borderBottom: "1px solid color-mix(in srgb, var(--color-fd-border, #2a2a2a) 100%, transparent)"
552
+ padding: "10px 13px",
553
+ background: "color-mix(in srgb, var(--color-fd-card, #202020) 96%, transparent)"
371
554
  },
372
555
  children: [/* @__PURE__ */ jsxs("span", {
373
556
  style: {
374
557
  display: "flex",
558
+ minWidth: 0,
375
559
  alignItems: "center",
376
560
  gap: 10
377
561
  },
378
- children: [/* @__PURE__ */ jsx(DropdownIcon, {
379
- current,
380
- radius: theme.iconRadius
562
+ children: [/* @__PURE__ */ jsx(SwitcherGlyph, {
563
+ kind: current,
564
+ radius: theme.iconRadius,
565
+ active: true
381
566
  }), /* @__PURE__ */ jsx("span", {
382
567
  style: {
383
568
  fontWeight: 600,
569
+ lineHeight: 1.2,
384
570
  ...theme.titleStyle
385
571
  },
386
572
  children: currentLabel
387
573
  })]
388
- }), /* @__PURE__ */ jsx("span", {
389
- "aria-hidden": "true",
390
- style: {
391
- fontSize: 11,
392
- opacity: .56,
393
- transform: "translateY(1px)"
394
- },
395
- children: "▿"
396
- })]
574
+ }), /* @__PURE__ */ jsx(ChevronStack, {})]
397
575
  }), /* @__PURE__ */ jsxs("div", {
398
576
  style: {
399
577
  display: "flex",
400
578
  flexDirection: "column",
401
579
  gap: 2,
402
- padding: 8,
580
+ padding: "8px 8px 9px",
403
581
  background: "color-mix(in srgb, var(--color-fd-card, #151515) 96%, transparent)"
404
582
  },
405
583
  children: [/* @__PURE__ */ jsx(SwitcherOption, {
406
584
  href: docsUrl,
585
+ kind: "docs",
407
586
  title: "Documentation",
408
- description: "Markdown pages, guides, and concepts",
587
+ description: "Guides & concepts",
409
588
  current: current === "docs",
410
589
  config
411
590
  }), /* @__PURE__ */ jsx(SwitcherOption, {
412
591
  href: apiUrl,
592
+ kind: "api",
413
593
  title: "API Reference",
414
- description: "Scalar-powered route handler reference",
594
+ description: "Endpoints & examples",
415
595
  current: current === "api",
416
596
  config
417
597
  })]
418
598
  })]
419
599
  });
420
600
  }
601
+ function getExistingSidebarBanner(config) {
602
+ if (!config.sidebar || config.sidebar === true) return void 0;
603
+ return config.sidebar.banner;
604
+ }
421
605
  function mergeBanner(existing, next) {
422
606
  if (!existing) return next;
423
607
  return /* @__PURE__ */ jsxs("div", {
@@ -439,25 +623,27 @@ function withNextApiReferenceBanner(config) {
439
623
  current: "docs",
440
624
  config
441
625
  });
626
+ const banner = mergeBanner(getExistingSidebarBanner(config), switcher);
442
627
  if (!config.sidebar || config.sidebar === true) return {
443
628
  ...config,
444
- sidebar: { banner: switcher }
629
+ sidebar: { banner }
445
630
  };
446
631
  return {
447
632
  ...config,
448
633
  sidebar: {
449
634
  ...config.sidebar,
450
- banner: mergeBanner(config.sidebar.banner, switcher)
635
+ banner
451
636
  }
452
637
  };
453
638
  }
454
639
  function createNextApiReference(config) {
455
640
  const apiReference = resolveApiReferenceConfig(config.apiReference);
456
- return async () => {
641
+ return async (request) => {
457
642
  if (!apiReference.enabled) return new Response("Not Found", { status: 404 });
458
643
  const document = await buildApiReferenceOpenApiDocumentAsync(config, {
459
644
  framework: "next",
460
- rootDir: process.cwd()
645
+ rootDir: process.cwd(),
646
+ baseUrl: getOriginFromRequest(request)
461
647
  });
462
648
  return ApiReference({
463
649
  pageTitle: buildApiReferencePageTitle(config, "API Reference"),
@@ -483,6 +669,161 @@ function createNextApiReference(config) {
483
669
  })();
484
670
  };
485
671
  }
672
+ function getOpenApiInfo(document) {
673
+ const info = document.info && typeof document.info === "object" && !Array.isArray(document.info) ? document.info : {};
674
+ return {
675
+ title: typeof info.title === "string" && info.title.trim() ? info.title : "API Reference",
676
+ description: typeof info.description === "string" && info.description.trim() ? info.description : void 0
677
+ };
678
+ }
679
+ function createNextApiReferencePage(config) {
680
+ return async function NextApiReferencePage(props) {
681
+ const [{ createAPIPage }, { DocsBody, DocsDescription, DocsPage, DocsTitle }] = await Promise.all([import("fumadocs-openapi/ui"), import("fumadocs-ui/layouts/notebook/page")]);
682
+ const { info, pages, server, source } = await getNextApiReferenceSourceState(config);
683
+ const slug = (props?.params ? await props.params : void 0)?.slug ?? [];
684
+ if (pages.length === 0) return /* @__PURE__ */ jsxs(DocsPage, {
685
+ full: true,
686
+ children: [
687
+ /* @__PURE__ */ jsx(DocsTitle, { children: info.title }),
688
+ /* @__PURE__ */ jsx(DocsDescription, { children: info.description }),
689
+ /* @__PURE__ */ jsx(DocsBody, { children: /* @__PURE__ */ jsx("div", {
690
+ className: "rounded-xl border border-fd-border bg-fd-card p-6 text-sm text-fd-muted-foreground",
691
+ children: "No operations were found in the OpenAPI document."
692
+ }) })
693
+ ]
694
+ });
695
+ const page = slug.length === 0 ? pages[0] : source.getPage(slug);
696
+ if (!page || typeof page.data?.getAPIPageProps !== "function") notFound();
697
+ const APIPage = createAPIPage(server);
698
+ const currentPageIndex = slug.length === 0 ? 0 : pages.findIndex((entry) => entry.url === page.url);
699
+ const previousPage = currentPageIndex > 0 ? pages[currentPageIndex - 1] : void 0;
700
+ const nextPage = currentPageIndex >= 0 && currentPageIndex < pages.length - 1 ? pages[currentPageIndex + 1] : void 0;
701
+ return /* @__PURE__ */ jsxs(DocsPage, {
702
+ toc: page.data.toc,
703
+ full: true,
704
+ footer: { enabled: false },
705
+ className: "fd-api-reference-page",
706
+ children: [
707
+ /* @__PURE__ */ jsx(DocsTitle, { children: page.data.title ?? info.title }),
708
+ /* @__PURE__ */ jsx(DocsDescription, { children: typeof page.data.description === "string" && page.data.description.trim() ? page.data.description : info.description }),
709
+ /* @__PURE__ */ jsx(DocsBody, { children: /* @__PURE__ */ jsx(APIPage, { ...page.data.getAPIPageProps() }) }),
710
+ previousPage || nextPage ? /* @__PURE__ */ jsxs("nav", {
711
+ className: "fd-api-reference-pagination",
712
+ "aria-label": "API reference pagination",
713
+ children: [previousPage ? /* @__PURE__ */ jsxs(Link, {
714
+ href: previousPage.url,
715
+ prefetch: true,
716
+ className: "fd-api-reference-pagination-item",
717
+ "data-direction": "previous",
718
+ children: [
719
+ /* @__PURE__ */ jsx("span", {
720
+ className: "fd-api-reference-pagination-label",
721
+ children: "Previous"
722
+ }),
723
+ /* @__PURE__ */ jsx("span", {
724
+ className: "fd-api-reference-pagination-title",
725
+ children: previousPage.data?.title ?? previousPage.url
726
+ }),
727
+ /* @__PURE__ */ jsx("span", {
728
+ className: "fd-api-reference-pagination-description",
729
+ children: previousPage.data?.description ?? "Previous API operation"
730
+ })
731
+ ]
732
+ }) : /* @__PURE__ */ jsx("div", {
733
+ className: "fd-api-reference-pagination-spacer",
734
+ "aria-hidden": "true"
735
+ }), nextPage ? /* @__PURE__ */ jsxs(Link, {
736
+ href: nextPage.url,
737
+ prefetch: true,
738
+ className: "fd-api-reference-pagination-item",
739
+ "data-direction": "next",
740
+ children: [
741
+ /* @__PURE__ */ jsx("span", {
742
+ className: "fd-api-reference-pagination-label",
743
+ children: "Next"
744
+ }),
745
+ /* @__PURE__ */ jsx("span", {
746
+ className: "fd-api-reference-pagination-title",
747
+ children: nextPage.data?.title ?? nextPage.url
748
+ }),
749
+ /* @__PURE__ */ jsx("span", {
750
+ className: "fd-api-reference-pagination-description",
751
+ children: nextPage.data?.description ?? "Next API operation"
752
+ })
753
+ ]
754
+ }) : /* @__PURE__ */ jsx("div", {
755
+ className: "fd-api-reference-pagination-spacer",
756
+ "aria-hidden": "true"
757
+ })]
758
+ }) : null
759
+ ]
760
+ });
761
+ };
762
+ }
763
+ function createNextApiReferenceLayout(config) {
764
+ return async function NextApiReferenceLayout(props) {
765
+ const { DocsLayout } = await import("fumadocs-ui/layouts/notebook");
766
+ const { apiReference, source } = await getNextApiReferenceSourceState(config);
767
+ const docsUrl = getDocsUrl(config);
768
+ const apiUrl = `/${apiReference.path}`;
769
+ const themeSwitch = resolveApiReferenceThemeSwitch(config.themeToggle);
770
+ const banner = mergeBanner(getExistingSidebarBanner(config), /* @__PURE__ */ jsx(ApiReferenceSwitcher, {
771
+ docsUrl,
772
+ apiUrl,
773
+ current: "api",
774
+ config
775
+ }));
776
+ return /* @__PURE__ */ jsxs("div", {
777
+ className: "fd-api-reference-route",
778
+ "data-api-reference": "",
779
+ children: [/* @__PURE__ */ jsx(DocsClientCallbacks, {}), /* @__PURE__ */ jsxs(DocsLayout, {
780
+ tree: source.getPageTree(),
781
+ sidebar: { banner },
782
+ themeSwitch,
783
+ nav: {
784
+ title: config.nav?.title ?? "Docs",
785
+ url: getDocsUrl(config)
786
+ },
787
+ children: [/* @__PURE__ */ jsx(ApiReferenceThemeBridge, { config }), props.children]
788
+ })]
789
+ });
790
+ };
791
+ }
792
+ async function getNextApiReferenceSourceState(config) {
793
+ const apiReference = resolveApiReferenceConfig(config.apiReference);
794
+ const [{ createOpenAPI, openapiPlugin, openapiSource }, { loader }] = await Promise.all([import("fumadocs-openapi/server"), import("fumadocs-core/source")]);
795
+ const baseUrl = await getOriginFromNextHeaders();
796
+ const document = await buildApiReferenceOpenApiDocumentAsync(config, {
797
+ framework: "next",
798
+ rootDir: process.cwd(),
799
+ baseUrl
800
+ });
801
+ const server = createOpenAPI({ input: async () => ({ main: document }) });
802
+ const info = getOpenApiInfo(document);
803
+ const source = loader(await openapiSource(server, {
804
+ per: "operation",
805
+ groupBy: "tag",
806
+ name(output, dereferenced) {
807
+ if (output.type !== "operation") return slugifyApiReferencePageName(output.item.name);
808
+ const operation = (dereferenced.paths?.[output.item.path])?.[output.item.method];
809
+ return slugifyApiReferencePageName(typeof operation?.summary === "string" && operation.summary.trim() ? operation.summary : typeof operation?.operationId === "string" && operation.operationId.trim() ? operation.operationId : `${output.item.method} ${output.item.path}`);
810
+ }
811
+ }), {
812
+ baseUrl: `/${apiReference.path}`,
813
+ plugins: [openapiPlugin()]
814
+ });
815
+ return {
816
+ apiReference,
817
+ document,
818
+ info,
819
+ pages: source.getPages(),
820
+ server,
821
+ source
822
+ };
823
+ }
824
+ function getNextApiReferenceMode(config) {
825
+ return resolveApiReferenceRenderer(config.apiReference, "next");
826
+ }
486
827
 
487
828
  //#endregion
488
- export { buildNextOpenApiDocument, createNextApiReference, resolveApiReferenceConfig, withNextApiReferenceBanner };
829
+ export { buildNextOpenApiDocument, createNextApiReference, createNextApiReferenceLayout, createNextApiReferencePage, getNextApiReferenceMode, getNextApiReferenceSourceState, resolveApiReferenceConfig, withNextApiReferenceBanner };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
 
3
- import { jsx } from "react/jsx-runtime";
4
3
  import docsConfig from "@farming-labs/next-internal-docs-config";
5
4
  import { DocsClientHooks } from "@farming-labs/theme/client-hooks";
5
+ import { jsx } from "react/jsx-runtime";
6
6
 
7
7
  //#region src/client-callbacks.tsx
8
8
  function DocsClientCallbacks() {
package/dist/config.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { dirname, isAbsolute, join, relative } from "node:path";
3
+ import { fileURLToPath } from "node:url";
3
4
  import createMDX from "@next/mdx";
4
5
 
5
6
  //#region src/config.ts
@@ -103,6 +104,28 @@ export const GET = createNextApiReference(docsConfig);
103
104
 
104
105
  export const revalidate = false;
105
106
  `;
107
+ const API_REFERENCE_PAGE_TEMPLATE = `\
108
+ ${GENERATED_BANNER}
109
+ import "@farming-labs/next/api-reference.css";
110
+ import docsConfig from "@/docs.config";
111
+ import { createNextApiReferencePage } from "@farming-labs/next/api-reference";
112
+
113
+ const ApiReferencePage = createNextApiReferencePage(docsConfig);
114
+
115
+ export const dynamic = "force-dynamic";
116
+ export const revalidate = 0;
117
+
118
+ export default ApiReferencePage;
119
+ `;
120
+ const API_REFERENCE_LAYOUT_TEMPLATE = `\
121
+ ${GENERATED_BANNER}
122
+ import docsConfig from "@/docs.config";
123
+ import { createNextApiReferenceLayout } from "@farming-labs/next/api-reference";
124
+
125
+ const ApiReferenceLayout = createNextApiReferenceLayout(docsConfig);
126
+
127
+ export default ApiReferenceLayout;
128
+ `;
106
129
  const FILE_EXTS = [
107
130
  "tsx",
108
131
  "ts",
@@ -110,6 +133,29 @@ const FILE_EXTS = [
110
133
  "js"
111
134
  ];
112
135
  const INTERNAL_DOCS_CONFIG_ALIAS = "@farming-labs/next-internal-docs-config";
136
+ const NEXT_PACKAGE_ROOT = fileURLToPath(new URL("..", import.meta.url));
137
+ function resolvePackageAlias(packageName, fallbacks = []) {
138
+ return [join(NEXT_PACKAGE_ROOT, "node_modules", packageName), ...fallbacks.map((value) => join(NEXT_PACKAGE_ROOT, value))].find((value) => existsSync(value));
139
+ }
140
+ function resolvePackageSubpath(packageDir, relativePath) {
141
+ if (!isAbsolute(packageDir)) return `${packageDir}/${relativePath.replace(/^dist\//, "").replace(/\/index\.js$/, "")}`;
142
+ return join(packageDir, relativePath);
143
+ }
144
+ function toTurbopackAliasPath(root, value) {
145
+ if (!isAbsolute(value)) return value;
146
+ const relativePath = relative(root, value);
147
+ return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
148
+ }
149
+ const FUMADOCS_OPENAPI_PACKAGE_ALIAS = resolvePackageAlias("fumadocs-openapi") ?? "fumadocs-openapi";
150
+ const FUMADOCS_CORE_PACKAGE_ALIAS = resolvePackageAlias("fumadocs-core") ?? "fumadocs-core";
151
+ const FUMADOCS_UI_PACKAGE_ALIAS = resolvePackageAlias("fumadocs-ui", ["node_modules/fumadocs-openapi/node_modules/fumadocs-ui", "../node_modules/fumadocs-ui"]) ?? "fumadocs-ui";
152
+ const FUMADOCS_OPENAPI_UI_ALIAS = resolvePackageSubpath(FUMADOCS_OPENAPI_PACKAGE_ALIAS, "dist/ui/index.js");
153
+ const FUMADOCS_OPENAPI_SERVER_ALIAS = resolvePackageSubpath(FUMADOCS_OPENAPI_PACKAGE_ALIAS, "dist/server/index.js");
154
+ const FUMADOCS_CORE_FRAMEWORK_ALIAS = resolvePackageSubpath(FUMADOCS_CORE_PACKAGE_ALIAS, "dist/framework/index.js");
155
+ const FUMADOCS_CORE_FRAMEWORK_NEXT_ALIAS = resolvePackageSubpath(FUMADOCS_CORE_PACKAGE_ALIAS, "dist/framework/next.js");
156
+ const FUMADOCS_UI_NOTEBOOK_ALIAS = resolvePackageSubpath(FUMADOCS_UI_PACKAGE_ALIAS, "dist/layouts/notebook/index.js");
157
+ const FUMADOCS_UI_NOTEBOOK_PAGE_ALIAS = resolvePackageSubpath(FUMADOCS_UI_PACKAGE_ALIAS, "dist/layouts/notebook/page/index.js");
158
+ const FUMADOCS_UI_PROVIDER_NEXT_ALIAS = resolvePackageSubpath(FUMADOCS_UI_PACKAGE_ALIAS, "dist/provider/next.js");
113
159
  function isDocsWorkspaceRoot(root) {
114
160
  return existsSync(join(root, "packages", "docs", "src", "index.ts")) && existsSync(join(root, "packages", "fumadocs", "src", "index.ts")) && existsSync(join(root, "packages", "next", "src", "config.ts"));
115
161
  }
@@ -201,27 +247,32 @@ function readApiReferenceConfig(root) {
201
247
  if (content.match(/apiReference\s*:\s*false/)) return {
202
248
  enabled: false,
203
249
  path: "api-reference",
250
+ renderer: "fumadocs",
204
251
  routeRoot: "api"
205
252
  };
206
253
  if (content.match(/apiReference\s*:\s*true/)) return {
207
254
  enabled: true,
208
255
  path: "api-reference",
256
+ renderer: "fumadocs",
209
257
  routeRoot: "api"
210
258
  };
211
259
  const block = extractObjectLiteral(content, "apiReference");
212
260
  if (!block) continue;
213
261
  const enabledMatch = block.match(/enabled\s*:\s*(true|false)/);
214
262
  const pathMatch = block.match(/path\s*:\s*["']([^"']+)["']/);
263
+ const rendererMatch = block.match(/renderer\s*:\s*["'](fumadocs|scalar)["']/);
215
264
  const routeRootMatch = block.match(/routeRoot\s*:\s*["']([^"']+)["']/);
216
265
  return {
217
266
  enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
218
267
  path: pathMatch?.[1]?.replace(/^\/+|\/+$/g, "") || "api-reference",
268
+ renderer: rendererMatch?.[1] ?? "fumadocs",
219
269
  routeRoot: routeRootMatch?.[1]?.replace(/^\/+|\/+$/g, "") || "api"
220
270
  };
221
271
  } catch {
222
272
  return {
223
273
  enabled: false,
224
274
  path: "api-reference",
275
+ renderer: "fumadocs",
225
276
  routeRoot: "api"
226
277
  };
227
278
  }
@@ -229,6 +280,7 @@ function readApiReferenceConfig(root) {
229
280
  return {
230
281
  enabled: false,
231
282
  path: "api-reference",
283
+ renderer: "fumadocs",
232
284
  routeRoot: "api"
233
285
  };
234
286
  }
@@ -249,6 +301,9 @@ function extractObjectLiteral(content, key) {
249
301
  if (depth === 0) return content.slice(braceStart + 1, index);
250
302
  }
251
303
  }
304
+ function removeManagedFile(filePath) {
305
+ if (isManagedGeneratedFile(filePath)) rmSync(filePath, { force: true });
306
+ }
252
307
  function readMcpConfig(root) {
253
308
  for (const ext of FILE_EXTS) {
254
309
  const configPath = join(root, `docs.config.${ext}`);
@@ -316,10 +371,31 @@ function withDocs(nextConfig = {}) {
316
371
  }
317
372
  const apiReference = readApiReferenceConfig(root);
318
373
  if (apiReference.enabled && !isStaticExport) {
319
- const apiReferenceRouteDir = join(root, appDir, ...apiReference.path.split("/"), "[[...slug]]");
320
- if (!hasFile(apiReferenceRouteDir, "route")) {
321
- mkdirSync(apiReferenceRouteDir, { recursive: true });
322
- writeFileSync(join(apiReferenceRouteDir, "route.ts"), API_REFERENCE_ROUTE_TEMPLATE);
374
+ const apiReferenceBaseDir = join(root, appDir, ...apiReference.path.split("/"));
375
+ const apiReferencePageDir = join(apiReferenceBaseDir, "[[...slug]]");
376
+ const apiReferencePagePath = join(apiReferencePageDir, "page.tsx");
377
+ const apiReferenceLayoutPath = join(apiReferenceBaseDir, "layout.tsx");
378
+ const apiReferenceRouteDir = join(apiReferenceBaseDir, "[[...slug]]");
379
+ const apiReferenceRoutePath = join(apiReferenceRouteDir, "route.ts");
380
+ const legacyApiReferencePagePath = join(apiReferenceBaseDir, "page.tsx");
381
+ if (apiReference.renderer === "fumadocs") {
382
+ removeManagedFile(apiReferenceRoutePath);
383
+ removeManagedFile(legacyApiReferencePagePath);
384
+ if (!hasFile(apiReferenceBaseDir, "layout") || isManagedGeneratedFile(apiReferenceLayoutPath)) {
385
+ mkdirSync(apiReferenceBaseDir, { recursive: true });
386
+ writeFileSync(apiReferenceLayoutPath, API_REFERENCE_LAYOUT_TEMPLATE);
387
+ }
388
+ if (!hasFile(apiReferencePageDir, "page") || isManagedGeneratedFile(apiReferencePagePath)) {
389
+ mkdirSync(apiReferencePageDir, { recursive: true });
390
+ writeFileSync(apiReferencePagePath, API_REFERENCE_PAGE_TEMPLATE);
391
+ }
392
+ } else {
393
+ removeManagedFile(apiReferenceLayoutPath);
394
+ removeManagedFile(apiReferencePagePath);
395
+ if (!hasFile(apiReferenceRouteDir, "route") || isManagedGeneratedFile(apiReferenceRoutePath)) {
396
+ mkdirSync(apiReferenceRouteDir, { recursive: true });
397
+ writeFileSync(apiReferenceRoutePath, API_REFERENCE_ROUTE_TEMPLATE);
398
+ }
323
399
  }
324
400
  }
325
401
  const ogEndpoint = readOgEndpoint(root);
@@ -356,7 +432,17 @@ function withDocs(nextConfig = {}) {
356
432
  resolveAlias: {
357
433
  ...workspaceRoot ? createDocsWorkspaceAliases() : {},
358
434
  ...existingResolveAlias,
359
- [INTERNAL_DOCS_CONFIG_ALIAS]: docsConfigRelativeAlias
435
+ [INTERNAL_DOCS_CONFIG_ALIAS]: docsConfigRelativeAlias,
436
+ "fumadocs-openapi": toTurbopackAliasPath(root, FUMADOCS_OPENAPI_PACKAGE_ALIAS),
437
+ "fumadocs-openapi/ui": toTurbopackAliasPath(root, FUMADOCS_OPENAPI_UI_ALIAS),
438
+ "fumadocs-openapi/server": toTurbopackAliasPath(root, FUMADOCS_OPENAPI_SERVER_ALIAS),
439
+ "fumadocs-core": toTurbopackAliasPath(root, FUMADOCS_CORE_PACKAGE_ALIAS),
440
+ "fumadocs-core/framework": toTurbopackAliasPath(root, FUMADOCS_CORE_FRAMEWORK_ALIAS),
441
+ "fumadocs-core/framework/next": toTurbopackAliasPath(root, FUMADOCS_CORE_FRAMEWORK_NEXT_ALIAS),
442
+ "fumadocs-ui": toTurbopackAliasPath(root, FUMADOCS_UI_PACKAGE_ALIAS),
443
+ "fumadocs-ui/layouts/notebook": toTurbopackAliasPath(root, FUMADOCS_UI_NOTEBOOK_ALIAS),
444
+ "fumadocs-ui/layouts/notebook/page": toTurbopackAliasPath(root, FUMADOCS_UI_NOTEBOOK_PAGE_ALIAS),
445
+ "fumadocs-ui/provider/next": toTurbopackAliasPath(root, FUMADOCS_UI_PROVIDER_NEXT_ALIAS)
360
446
  }
361
447
  };
362
448
  const userWebpack = nextConfig.webpack;
@@ -365,6 +451,16 @@ function withDocs(nextConfig = {}) {
365
451
  resolvedConfig.resolve ??= {};
366
452
  resolvedConfig.resolve.alias ??= {};
367
453
  resolvedConfig.resolve.alias[INTERNAL_DOCS_CONFIG_ALIAS] = docsConfigAbsolutePath;
454
+ resolvedConfig.resolve.alias["fumadocs-openapi"] = FUMADOCS_OPENAPI_PACKAGE_ALIAS;
455
+ resolvedConfig.resolve.alias["fumadocs-openapi/ui"] = FUMADOCS_OPENAPI_UI_ALIAS;
456
+ resolvedConfig.resolve.alias["fumadocs-openapi/server"] = FUMADOCS_OPENAPI_SERVER_ALIAS;
457
+ resolvedConfig.resolve.alias["fumadocs-core"] = FUMADOCS_CORE_PACKAGE_ALIAS;
458
+ resolvedConfig.resolve.alias["fumadocs-core/framework"] = FUMADOCS_CORE_FRAMEWORK_ALIAS;
459
+ resolvedConfig.resolve.alias["fumadocs-core/framework/next"] = FUMADOCS_CORE_FRAMEWORK_NEXT_ALIAS;
460
+ resolvedConfig.resolve.alias["fumadocs-ui"] = FUMADOCS_UI_PACKAGE_ALIAS;
461
+ resolvedConfig.resolve.alias["fumadocs-ui/layouts/notebook"] = FUMADOCS_UI_NOTEBOOK_ALIAS;
462
+ resolvedConfig.resolve.alias["fumadocs-ui/layouts/notebook/page"] = FUMADOCS_UI_NOTEBOOK_PAGE_ALIAS;
463
+ resolvedConfig.resolve.alias["fumadocs-ui/provider/next"] = FUMADOCS_UI_PROVIDER_NEXT_ALIAS;
368
464
  return resolvedConfig;
369
465
  };
370
466
  const existingTracingIncludes = nextConfig.outputFileTracingIncludes ?? {};
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { buildNextOpenApiDocument, createNextApiReference, resolveApiReferenceConfig, withNextApiReferenceBanner } from "./api-reference.mjs";
1
+ import { buildNextOpenApiDocument, createNextApiReference, createNextApiReferenceLayout, createNextApiReferencePage, getNextApiReferenceMode, getNextApiReferenceSourceState, resolveApiReferenceConfig, withNextApiReferenceBanner } from "./api-reference.mjs";
2
2
  import { createDocsAPI, createDocsMCPAPI } from "./api.mjs";
3
3
  import { withDocs } from "./config.mjs";
4
- export { buildNextOpenApiDocument, createDocsAPI, createDocsMCPAPI, createNextApiReference, resolveApiReferenceConfig, withDocs, withNextApiReferenceBanner };
4
+ export { buildNextOpenApiDocument, createDocsAPI, createDocsMCPAPI, createNextApiReference, createNextApiReferenceLayout, createNextApiReferencePage, getNextApiReferenceMode, getNextApiReferenceSourceState, resolveApiReferenceConfig, withDocs, withNextApiReferenceBanner };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { withDocs } from "./config.mjs";
2
2
  import { createDocsAPI, createDocsMCPAPI } from "./api.mjs";
3
- import { buildNextOpenApiDocument, createNextApiReference, resolveApiReferenceConfig, withNextApiReferenceBanner } from "./api-reference.mjs";
3
+ import { buildNextOpenApiDocument, createNextApiReference, createNextApiReferenceLayout, createNextApiReferencePage, getNextApiReferenceMode, getNextApiReferenceSourceState, resolveApiReferenceConfig, withNextApiReferenceBanner } from "./api-reference.mjs";
4
4
 
5
- export { buildNextOpenApiDocument, createDocsAPI, createDocsMCPAPI, createNextApiReference, resolveApiReferenceConfig, withDocs, withNextApiReferenceBanner };
5
+ export { buildNextOpenApiDocument, createDocsAPI, createDocsMCPAPI, createNextApiReference, createNextApiReferenceLayout, createNextApiReferencePage, getNextApiReferenceMode, getNextApiReferenceSourceState, resolveApiReferenceConfig, withDocs, withNextApiReferenceBanner };
package/dist/layout.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { withNextApiReferenceBanner } from "./api-reference.mjs";
2
1
  import DocsClientCallbacks from "./client-callbacks.mjs";
2
+ import { withNextApiReferenceBanner } from "./api-reference.mjs";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  import { createDocsLayout, createDocsMetadata } from "@farming-labs/theme";
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/next",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Next.js adapter for @farming-labs/docs — MDX config wrapper",
5
5
  "keywords": [
6
6
  "docs",
@@ -11,7 +11,8 @@
11
11
  "license": "MIT",
12
12
  "author": "Farming Labs",
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "styles"
15
16
  ],
16
17
  "type": "module",
17
18
  "main": "./dist/index.mjs",
@@ -27,6 +28,7 @@
27
28
  "import": "./dist/api-reference.mjs",
28
29
  "default": "./dist/api-reference.mjs"
29
30
  },
31
+ "./api-reference.css": "./styles/api-reference.css",
30
32
  "./api": {
31
33
  "types": "./dist/api.d.mts",
32
34
  "import": "./dist/api.mjs",
@@ -73,7 +75,9 @@
73
75
  "@mdx-js/react": "^3.1.0",
74
76
  "@next/mdx": "^16.1.6",
75
77
  "@scalar/nextjs-api-reference": "0.10.3",
78
+ "fumadocs-openapi": "^10.7.0",
76
79
  "fumadocs-core": "^16.6.1",
80
+ "fumadocs-ui": "^16.6.1",
77
81
  "remark-frontmatter": "^5.0.0",
78
82
  "remark-gfm": "^4.0.1",
79
83
  "remark-mdx-frontmatter": "^5.0.0"
@@ -81,11 +85,12 @@
81
85
  "devDependencies": {
82
86
  "@types/node": "^22.10.0",
83
87
  "@types/react": "^19.2.2",
88
+ "@types/react-dom": "^19.2.2",
84
89
  "tsdown": "^0.20.3",
85
90
  "typescript": "^5.9.3",
86
91
  "vitest": "^3.2.4",
87
- "@farming-labs/docs": "0.1.9",
88
- "@farming-labs/theme": "0.1.9"
92
+ "@farming-labs/docs": "0.1.11",
93
+ "@farming-labs/theme": "0.1.11"
89
94
  },
90
95
  "peerDependencies": {
91
96
  "@farming-labs/docs": ">=0.0.1",
@@ -0,0 +1,128 @@
1
+ @import "tailwindcss";
2
+ @import "fumadocs-ui/css/preset.css";
3
+ @import "fumadocs-openapi/css/preset.css";
4
+
5
+ @theme inline {
6
+ --color-fd-background: var(--color-fd-background);
7
+ --color-fd-foreground: var(--color-fd-foreground);
8
+ --color-fd-muted: var(--color-fd-muted);
9
+ --color-fd-muted-foreground: var(--color-fd-muted-foreground);
10
+ --color-fd-popover: var(--color-fd-popover);
11
+ --color-fd-popover-foreground: var(--color-fd-popover-foreground);
12
+ --color-fd-card: var(--color-fd-card);
13
+ --color-fd-card-foreground: var(--color-fd-card-foreground);
14
+ --color-fd-border: var(--color-fd-border);
15
+ --color-fd-primary: var(--color-fd-primary);
16
+ --color-fd-primary-foreground: var(--color-fd-primary-foreground);
17
+ --color-fd-secondary: var(--color-fd-secondary);
18
+ --color-fd-secondary-foreground: var(--color-fd-secondary-foreground);
19
+ --color-fd-accent: var(--color-fd-accent);
20
+ --color-fd-accent-foreground: var(--color-fd-accent-foreground);
21
+ --color-fd-ring: var(--color-fd-ring);
22
+ --color-fd-overlay: var(--color-fd-overlay);
23
+ }
24
+
25
+ @theme static {
26
+ --color-fd-info: oklch(62.3% 0.214 259.815);
27
+ --color-fd-warning: oklch(76.9% 0.188 70.08);
28
+ --color-fd-error: oklch(63.7% 0.237 25.331);
29
+ --color-fd-success: oklch(72.3% 0.219 149.579);
30
+ --color-fd-idea: oklch(70.5% 0.209 60.849);
31
+ --color-fd-diff-remove: rgba(200, 10, 100, 0.12);
32
+ --color-fd-diff-remove-symbol: rgb(230, 10, 100);
33
+ --color-fd-diff-add: rgba(14, 180, 100, 0.1);
34
+ --color-fd-diff-add-symbol: rgb(10, 200, 100);
35
+ }
36
+
37
+ :root,
38
+ .dark {
39
+ --color-fd-overlay: hsla(0, 0%, 0%, 0.2);
40
+ }
41
+
42
+ .fd-api-reference-route #nd-subnav {
43
+ display: none;
44
+ }
45
+
46
+ .fd-api-reference-route #nd-page.fd-api-reference-page > * {
47
+ width: 100%;
48
+ max-width: 1180px;
49
+ }
50
+
51
+ .fd-api-reference-route #nd-page.fd-api-reference-page > .prose {
52
+ max-width: 1180px;
53
+ }
54
+
55
+ .fd-api-reference-pagination {
56
+ display: grid;
57
+ grid-template-columns: repeat(2, minmax(0, 1fr));
58
+ gap: 1rem;
59
+ margin-top: 1rem;
60
+ }
61
+
62
+ .fd-api-reference-pagination-item {
63
+ display: flex;
64
+ min-height: 8.5rem;
65
+ flex-direction: column;
66
+ gap: 0.45rem;
67
+ border: 1px solid var(--color-fd-border);
68
+ border-radius: 1rem;
69
+ background: var(--color-fd-card);
70
+ padding: 1.1rem 1.25rem;
71
+ text-decoration: none;
72
+ color: inherit;
73
+ transition:
74
+ border-color 150ms ease,
75
+ background-color 150ms ease,
76
+ transform 150ms ease;
77
+ }
78
+
79
+ .fd-api-reference-pagination-item:hover {
80
+ border-color: color-mix(in srgb, var(--color-fd-primary) 30%, var(--color-fd-border));
81
+ background: color-mix(in srgb, var(--color-fd-accent) 45%, var(--color-fd-card));
82
+ transform: translateY(-1px);
83
+ }
84
+
85
+ .fd-api-reference-pagination-item[data-direction="next"] {
86
+ text-align: right;
87
+ }
88
+
89
+ .fd-api-reference-pagination-label {
90
+ font-size: 0.72rem;
91
+ font-weight: 600;
92
+ letter-spacing: 0.08em;
93
+ text-transform: uppercase;
94
+ color: var(--color-fd-muted-foreground);
95
+ }
96
+
97
+ .fd-api-reference-pagination-title {
98
+ font-size: 1.05rem;
99
+ font-weight: 600;
100
+ color: var(--color-fd-foreground);
101
+ }
102
+
103
+ .fd-api-reference-pagination-description {
104
+ color: var(--color-fd-muted-foreground);
105
+ font-size: 0.92rem;
106
+ line-height: 1.5;
107
+ }
108
+
109
+ .fd-api-reference-pagination-spacer {
110
+ display: none;
111
+ }
112
+
113
+ @media (min-width: 768px) {
114
+ .fd-api-reference-route #nd-notebook-layout #nd-page {
115
+ padding-inline: 1.5rem;
116
+ padding-top: 2rem;
117
+ }
118
+
119
+ .fd-api-reference-route #nd-notebook-layout #nd-page::before {
120
+ display: none;
121
+ }
122
+ }
123
+
124
+ @media (max-width: 1023px) {
125
+ .fd-api-reference-pagination {
126
+ grid-template-columns: 1fr;
127
+ }
128
+ }