@farming-labs/next 0.1.3 → 0.1.5

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/api.d.mts CHANGED
@@ -1,2 +1,23 @@
1
- import { createDocsAPI, createDocsMCPAPI } from "@farming-labs/theme/api";
2
- export { createDocsAPI, createDocsMCPAPI };
1
+ import { createDocsAPI as createDocsAPI$1, createDocsMCPAPI as createDocsMCPAPI$1 } from "@farming-labs/theme/api";
2
+
3
+ //#region src/api.d.ts
4
+ type DocsAPIOptions = NonNullable<Parameters<typeof createDocsAPI$1>[0]>;
5
+ type DocsMCPAPIOptions = NonNullable<Parameters<typeof createDocsMCPAPI$1>[0]>;
6
+ /**
7
+ * Resolve the app project root for a Next route module.
8
+ *
9
+ * This handles source routes (`app/...` or `src/app/...`) and built production
10
+ * output (`.next/server/app/...` or custom-dist-dir `/server/app/...`).
11
+ */
12
+ declare function resolveNextProjectRoot(metaUrl: string): string;
13
+ declare function createDocsAPI(options?: DocsAPIOptions): {
14
+ GET(request: Request): Promise<Response>;
15
+ POST(request: Request): Promise<Response>;
16
+ };
17
+ declare function createDocsMCPAPI(options?: DocsMCPAPIOptions): {
18
+ GET(request: Request): Promise<Response>;
19
+ POST(request: Request): Promise<Response>;
20
+ DELETE(request: Request): Promise<Response>;
21
+ };
22
+ //#endregion
23
+ export { createDocsAPI, createDocsMCPAPI, resolveNextProjectRoot };
package/dist/api.mjs CHANGED
@@ -1,3 +1,66 @@
1
- import { createDocsAPI, createDocsMCPAPI } from "@farming-labs/theme/api";
1
+ import path from "node:path";
2
+ import { fileURLToPath, pathToFileURL } from "node:url";
3
+ import { createDocsAPI as createDocsAPI$1, createDocsMCPAPI as createDocsMCPAPI$1 } from "@farming-labs/theme/api";
2
4
 
3
- export { createDocsAPI, createDocsMCPAPI };
5
+ //#region src/api.ts
6
+ /**
7
+ * Resolve the app project root for a Next route module.
8
+ *
9
+ * This handles source routes (`app/...` or `src/app/...`) and built production
10
+ * output (`.next/server/app/...` or custom-dist-dir `/server/app/...`).
11
+ */
12
+ function resolveNextProjectRoot(metaUrl) {
13
+ const filePath = fileURLToPath(metaUrl);
14
+ let current = path.dirname(filePath);
15
+ while (true) {
16
+ const parent = path.dirname(current);
17
+ if (path.basename(current) === "app") {
18
+ if (path.basename(parent) === "src") return path.dirname(parent);
19
+ if (path.basename(parent) === "server") {
20
+ const serverParent = path.dirname(parent);
21
+ if (path.basename(serverParent) === "dev") return path.dirname(path.dirname(serverParent));
22
+ return path.dirname(serverParent);
23
+ }
24
+ return parent;
25
+ }
26
+ if (parent === current) return process.cwd();
27
+ current = parent;
28
+ }
29
+ }
30
+ function isNextRouteFile(filePath) {
31
+ const normalized = filePath.replaceAll("\\", "/");
32
+ return /\/(?:src\/)?app\/api\/.+\/route\.[cm]?[jt]sx?$/.test(normalized);
33
+ }
34
+ function inferNextProjectRootFromCaller() {
35
+ const previousPrepareStackTrace = Error.prepareStackTrace;
36
+ try {
37
+ Error.prepareStackTrace = (_error, stack) => stack;
38
+ const error = /* @__PURE__ */ new Error();
39
+ Error.captureStackTrace?.(error, inferNextProjectRootFromCaller);
40
+ const stack = error.stack;
41
+ for (const frame of stack ?? []) {
42
+ const fileName = frame.getFileName?.();
43
+ if (!fileName || !isNextRouteFile(fileName)) continue;
44
+ return resolveNextProjectRoot(pathToFileURL(fileName).href);
45
+ }
46
+ } catch {} finally {
47
+ Error.prepareStackTrace = previousPrepareStackTrace;
48
+ }
49
+ }
50
+ function createDocsAPI(options = {}) {
51
+ const rootDir = options.rootDir ?? inferNextProjectRootFromCaller();
52
+ return createDocsAPI$1(rootDir ? {
53
+ ...options,
54
+ rootDir
55
+ } : options);
56
+ }
57
+ function createDocsMCPAPI(options = {}) {
58
+ const rootDir = options.rootDir ?? inferNextProjectRootFromCaller();
59
+ return createDocsMCPAPI$1(rootDir ? {
60
+ ...options,
61
+ rootDir
62
+ } : options);
63
+ }
64
+
65
+ //#endregion
66
+ export { createDocsAPI, createDocsMCPAPI, resolveNextProjectRoot };
package/dist/config.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
3
  import createMDX from "@next/mdx";
4
4
 
5
5
  //#region src/config.ts
@@ -70,6 +70,7 @@ import { createDocsAPI } from "@farming-labs/next/api";
70
70
 
71
71
  export const { GET, POST } = createDocsAPI({
72
72
  entry: docsConfig.entry,
73
+ contentDir: docsConfig.contentDir,
73
74
  i18n: docsConfig.i18n,
74
75
  search: docsConfig.search,
75
76
  ai: docsConfig.ai,
@@ -109,6 +110,39 @@ const FILE_EXTS = [
109
110
  "js"
110
111
  ];
111
112
  const INTERNAL_DOCS_CONFIG_ALIAS = "@farming-labs/next-internal-docs-config";
113
+ function isDocsWorkspaceRoot(root) {
114
+ 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
+ }
116
+ function findDocsWorkspaceRoot(start) {
117
+ let current = start;
118
+ while (true) {
119
+ if (isDocsWorkspaceRoot(current)) return current;
120
+ const parent = dirname(current);
121
+ if (parent === current) return void 0;
122
+ current = parent;
123
+ }
124
+ }
125
+ function createDocsWorkspaceAliases() {
126
+ return {
127
+ "@farming-labs/docs": "./packages/docs/src/index.ts",
128
+ "@farming-labs/docs/server": "./packages/docs/src/server.ts",
129
+ "@farming-labs/next": "./packages/next/src/index.ts",
130
+ "@farming-labs/next/api": "./packages/next/src/api.ts",
131
+ "@farming-labs/next/client-callbacks": "./packages/next/src/client-callbacks.tsx",
132
+ "@farming-labs/next/layout": "./packages/next/src/layout.tsx",
133
+ "@farming-labs/next/mdx-plugins/rehype-code": "./packages/next/src/mdx-plugins/rehype-code.ts",
134
+ "@farming-labs/next/mdx-plugins/rehype-toc": "./packages/next/src/mdx-plugins/rehype-toc.ts",
135
+ "@farming-labs/next/mdx-plugins/remark-heading": "./packages/next/src/mdx-plugins/remark-heading.ts",
136
+ "@farming-labs/next/mdx-plugins/remark-og": "./packages/next/src/mdx-plugins/remark-og.ts",
137
+ "@farming-labs/theme": "./packages/fumadocs/src/index.ts",
138
+ "@farming-labs/theme/api": "./packages/fumadocs/src/docs-api.ts",
139
+ "@farming-labs/theme/client-hooks": "./packages/fumadocs/src/docs-client-hooks.tsx",
140
+ "@farming-labs/theme/concrete": "./packages/fumadocs/src/concrete/index.ts",
141
+ "@farming-labs/theme/hardline": "./packages/fumadocs/src/hardline/index.ts",
142
+ "@farming-labs/theme/mdx": "./packages/fumadocs/src/mdx.ts",
143
+ "@farming-labs/theme/search": "./packages/fumadocs/src/search.ts"
144
+ };
145
+ }
112
146
  function hasFile(root, baseName) {
113
147
  return FILE_EXTS.some((ext) => existsSync(join(root, `${baseName}.${ext}`)));
114
148
  }
@@ -131,6 +165,16 @@ function readDocsEntry(root) {
131
165
  }
132
166
  return "docs";
133
167
  }
168
+ function readDocsContentDir(root) {
169
+ for (const ext of FILE_EXTS) {
170
+ const configPath = join(root, `docs.config.${ext}`);
171
+ if (!existsSync(configPath)) continue;
172
+ try {
173
+ const match = readFileSync(configPath, "utf-8").match(/contentDir\s*:\s*["']([^"']+)["']/);
174
+ if (match?.[1]) return match[1];
175
+ } catch {}
176
+ }
177
+ }
134
178
  function readDocsConfigPath(root) {
135
179
  for (const ext of FILE_EXTS) {
136
180
  const relativePath = `docs.config.${ext}`;
@@ -245,12 +289,15 @@ function normalizeRoutePath(route) {
245
289
  }
246
290
  function withDocs(nextConfig = {}) {
247
291
  const root = process.cwd();
292
+ const workspaceRoot = findDocsWorkspaceRoot(root);
248
293
  const docsConfigPath = readDocsConfigPath(root);
249
294
  const docsConfigAbsolutePath = join(root, docsConfigPath);
250
295
  const docsConfigRelativeAlias = docsConfigPath.startsWith("./") || docsConfigPath.startsWith("../") ? docsConfigPath : `./${docsConfigPath}`;
251
296
  if (!hasFile(root, "mdx-components")) writeFileSync(join(root, "mdx-components.tsx"), MDX_COMPONENTS_TEMPLATE);
252
297
  const entry = readDocsEntry(root);
298
+ const configuredContentDir = readDocsContentDir(root);
253
299
  const appDir = getNextAppDir(root);
300
+ const docsContentDir = configuredContentDir ?? join(appDir, entry);
254
301
  const layoutDir = join(root, appDir, entry);
255
302
  if (!existsSync(layoutDir)) mkdirSync(layoutDir, { recursive: true });
256
303
  const docsLayoutPath = join(layoutDir, "layout.tsx");
@@ -305,7 +352,9 @@ function withDocs(nextConfig = {}) {
305
352
  const existingResolveAlias = existingTurbopack.resolveAlias ?? {};
306
353
  nextConfig.turbopack = {
307
354
  ...existingTurbopack,
355
+ ...workspaceRoot && !existingTurbopack.root ? { root: workspaceRoot } : {},
308
356
  resolveAlias: {
357
+ ...workspaceRoot ? createDocsWorkspaceAliases() : {},
309
358
  ...existingResolveAlias,
310
359
  [INTERNAL_DOCS_CONFIG_ALIAS]: docsConfigRelativeAlias
311
360
  }
@@ -318,6 +367,13 @@ function withDocs(nextConfig = {}) {
318
367
  resolvedConfig.resolve.alias[INTERNAL_DOCS_CONFIG_ALIAS] = docsConfigAbsolutePath;
319
368
  return resolvedConfig;
320
369
  };
370
+ const existingTracingIncludes = nextConfig.outputFileTracingIncludes ?? {};
371
+ const docsTraceGlob = docsContentDir.replace(/\\/g, "/").replace(/^\.?\//, "") + "/**/*";
372
+ nextConfig.outputFileTracingIncludes = {
373
+ ...existingTracingIncludes,
374
+ "/api/docs": [...new Set([...existingTracingIncludes["/api/docs"] ?? [], docsTraceGlob])],
375
+ "/api/docs/mcp": [...new Set([...existingTracingIncludes["/api/docs/mcp"] ?? [], docsTraceGlob])]
376
+ };
321
377
  return withMDX(nextConfig);
322
378
  }
323
379
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/next",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Next.js adapter for @farming-labs/docs — MDX config wrapper",
5
5
  "keywords": [
6
6
  "docs",
@@ -84,8 +84,8 @@
84
84
  "tsdown": "^0.20.3",
85
85
  "typescript": "^5.9.3",
86
86
  "vitest": "^3.2.4",
87
- "@farming-labs/docs": "0.1.3",
88
- "@farming-labs/theme": "0.1.3"
87
+ "@farming-labs/theme": "0.1.5",
88
+ "@farming-labs/docs": "0.1.5"
89
89
  },
90
90
  "peerDependencies": {
91
91
  "@farming-labs/docs": ">=0.0.1",