@farming-labs/next 0.1.108 → 0.1.111

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/config.mjs CHANGED
@@ -258,6 +258,15 @@ function readDocsContentDir(root) {
258
258
  } catch {}
259
259
  }
260
260
  }
261
+ function readDocsPath(root) {
262
+ for (const ext of FILE_EXTS) {
263
+ const configPath = join(root, `docs.config.${ext}`);
264
+ if (!existsSync(configPath)) continue;
265
+ try {
266
+ return readTopLevelStringProperty(readFileSync(configPath, "utf-8"), "docsPath");
267
+ } catch {}
268
+ }
269
+ }
261
270
  function readDocsConfigPath(root) {
262
271
  for (const ext of FILE_EXTS) {
263
272
  const relativePath = `docs.config.${ext}`;
@@ -910,8 +919,74 @@ function readAgentFeedbackConfig(root) {
910
919
  }
911
920
  return enabled;
912
921
  }
913
- function buildDocsMarkdownRewrites(entry) {
914
- const normalizedEntry = entry.replace(/^\/+|\/+$/g, "") || "docs";
922
+ function normalizeRouteSegment(value, fallback = "docs") {
923
+ return (value ?? fallback).replace(/^\/+|\/+$/g, "") || fallback;
924
+ }
925
+ function normalizeDocsPath(value, entry) {
926
+ if (typeof value !== "string") return `/${normalizeRouteSegment(entry)}`;
927
+ const cleaned = value.trim();
928
+ if (cleaned === "" || cleaned === "/") return "";
929
+ return `/${cleaned.replace(/^\/+|\/+$/g, "")}`;
930
+ }
931
+ function docsRootSource(entry) {
932
+ return [
933
+ "/:slug((?!",
934
+ "_next/",
935
+ "|api/",
936
+ `|${normalizeRouteSegment(entry)}(?:/|$)`,
937
+ "|favicon\\.ico",
938
+ "|robots\\.txt",
939
+ "|sitemap\\.xml",
940
+ "|sitemap\\.md",
941
+ "|docs\\.md",
942
+ "|llms\\.txt",
943
+ "|llms-full\\.txt",
944
+ "|mcp(?:/|$)",
945
+ "|AGENTS\\.md",
946
+ "|AGENT\\.md",
947
+ "|skill\\.md",
948
+ "|\\.well-known/",
949
+ "|.*\\..*",
950
+ ").*)"
951
+ ].join("");
952
+ }
953
+ function docsRootMarkdownSource(entry) {
954
+ return [
955
+ "/:slug((?!",
956
+ "_next/",
957
+ "|api/",
958
+ `|${normalizeRouteSegment(entry)}/`,
959
+ "|docs\\.md",
960
+ "|sitemap\\.md",
961
+ "|AGENTS\\.md",
962
+ "|AGENT\\.md",
963
+ "|skill\\.md",
964
+ "|\\.well-known/",
965
+ ").*)\\.md"
966
+ ].join("");
967
+ }
968
+ function buildDocsPathRewrites(entry, docsPath) {
969
+ const normalizedEntry = normalizeRouteSegment(entry);
970
+ const internalBase = `/${normalizedEntry}`;
971
+ if (docsPath === internalBase) return [];
972
+ if (docsPath === "") return [{
973
+ source: "/",
974
+ destination: `${internalBase}/`
975
+ }, {
976
+ source: docsRootSource(normalizedEntry),
977
+ destination: `${internalBase}/:slug`
978
+ }];
979
+ return [{
980
+ source: docsPath,
981
+ destination: internalBase
982
+ }, {
983
+ source: `${docsPath}/:slug*`,
984
+ destination: `${internalBase}/:slug*`
985
+ }];
986
+ }
987
+ function buildDocsMarkdownRewrites(entry, docsPath) {
988
+ const normalizedEntry = normalizeRouteSegment(entry);
989
+ const publicBase = docsPath || "";
915
990
  const markdownAcceptHeader = {
916
991
  type: "header",
917
992
  key: "accept",
@@ -922,32 +997,65 @@ function buildDocsMarkdownRewrites(entry) {
922
997
  key: "signature-agent",
923
998
  value: ".+"
924
999
  };
1000
+ if (publicBase === "") {
1001
+ const rootPageSource = docsRootSource(normalizedEntry);
1002
+ return [
1003
+ {
1004
+ source: `/${normalizedEntry}.md`,
1005
+ destination: "/api/docs?format=markdown"
1006
+ },
1007
+ {
1008
+ source: docsRootMarkdownSource(normalizedEntry),
1009
+ destination: "/api/docs?format=markdown&path=:slug"
1010
+ },
1011
+ {
1012
+ source: "/",
1013
+ has: [markdownAcceptHeader],
1014
+ destination: "/api/docs?format=markdown"
1015
+ },
1016
+ {
1017
+ source: rootPageSource,
1018
+ has: [markdownAcceptHeader],
1019
+ destination: "/api/docs?format=markdown&path=:slug"
1020
+ },
1021
+ {
1022
+ source: "/",
1023
+ has: [markdownSignatureAgentHeader],
1024
+ destination: "/api/docs?format=markdown"
1025
+ },
1026
+ {
1027
+ source: rootPageSource,
1028
+ has: [markdownSignatureAgentHeader],
1029
+ destination: "/api/docs?format=markdown&path=:slug"
1030
+ }
1031
+ ];
1032
+ }
925
1033
  return [
926
1034
  {
927
- source: `/${normalizedEntry}.md`,
1035
+ source: `${publicBase}.md`,
928
1036
  destination: "/api/docs?format=markdown"
929
1037
  },
930
1038
  {
931
- source: `/${normalizedEntry}/:slug*.md`,
1039
+ source: `${publicBase}/:slug*.md`,
932
1040
  destination: "/api/docs?format=markdown&path=:slug*"
933
1041
  },
934
1042
  {
935
- source: `/${normalizedEntry}`,
1043
+ source: publicBase,
936
1044
  has: [markdownAcceptHeader],
937
1045
  destination: "/api/docs?format=markdown"
938
1046
  },
939
1047
  {
940
- source: `/${normalizedEntry}/:slug*`,
1048
+ source: `${publicBase}/:slug*`,
941
1049
  has: [markdownAcceptHeader],
942
1050
  destination: "/api/docs?format=markdown&path=:slug*"
943
1051
  },
944
1052
  {
945
- source: `/${normalizedEntry}`,
1053
+ source: publicBase,
946
1054
  has: [markdownSignatureAgentHeader],
947
1055
  destination: "/api/docs?format=markdown"
948
1056
  },
949
1057
  {
950
- source: `/${normalizedEntry}/:slug*`,
1058
+ source: `${publicBase}/:slug*`,
951
1059
  has: [markdownSignatureAgentHeader],
952
1060
  destination: "/api/docs?format=markdown&path=:slug*"
953
1061
  }
@@ -970,7 +1078,7 @@ function buildAgentSpecRewrites() {
970
1078
  ];
971
1079
  }
972
1080
  function buildLlmsTxtRewrites(entry) {
973
- const normalizedEntry = entry.replace(/^\/+|\/+$/g, "") || "docs";
1081
+ const normalizedEntry = normalizeRouteSegment(entry);
974
1082
  return [
975
1083
  {
976
1084
  source: DEFAULT_LLMS_TXT_ROUTE,
@@ -1161,7 +1269,12 @@ function findFirstVisibleDocsChildSlug(dir, slugParts) {
1161
1269
  return childSlugParts;
1162
1270
  }
1163
1271
  }
1164
- function buildHiddenFolderRedirects(docsDir, entry) {
1272
+ function publicDocsRoute(docsPath, slugParts = []) {
1273
+ const slug = slugParts.join("/");
1274
+ if (!slug) return docsPath || "/";
1275
+ return docsPath ? `${docsPath}/${slug}` : `/${slug}`;
1276
+ }
1277
+ function buildHiddenFolderRedirects(docsDir, docsPath) {
1165
1278
  const redirects = [];
1166
1279
  function scan(dir, slugParts) {
1167
1280
  if (!existsSync(dir)) return;
@@ -1170,8 +1283,8 @@ function buildHiddenFolderRedirects(docsDir, entry) {
1170
1283
  if (resolveDocsPageFolderIndexBehavior(readDocsPageFrontmatter(pageSource)) === "hidden") {
1171
1284
  const destinationSlug = findFirstVisibleDocsChildSlug(dir, slugParts);
1172
1285
  if (destinationSlug && destinationSlug.join("/") !== slugParts.join("/")) {
1173
- const source = slugParts.length > 0 ? `/${entry}/${slugParts.join("/")}` : `/${entry}`;
1174
- const destination = destinationSlug.length > 0 ? `/${entry}/${destinationSlug.join("/")}` : `/${entry}`;
1286
+ const source = publicDocsRoute(docsPath, slugParts);
1287
+ const destination = publicDocsRoute(docsPath, destinationSlug);
1175
1288
  redirects.push({
1176
1289
  source,
1177
1290
  destination,
@@ -1185,7 +1298,7 @@ function buildHiddenFolderRedirects(docsDir, entry) {
1185
1298
  scan(docsDir, []);
1186
1299
  return dedupeRedirects(redirects);
1187
1300
  }
1188
- function mergeDocsMarkdownRewrites(entry, mcp, sitemap, agentFeedback, robots, result) {
1301
+ function mergeDocsMarkdownRewrites(entry, docsPath, mcp, sitemap, agentFeedback, robots, result) {
1189
1302
  const autoBeforeFilesRewrites = [
1190
1303
  ...buildAgentSpecRewrites(),
1191
1304
  ...buildMcpRewrites(mcp),
@@ -1193,7 +1306,8 @@ function mergeDocsMarkdownRewrites(entry, mcp, sitemap, agentFeedback, robots, r
1193
1306
  ...buildSkillMdRewrites(),
1194
1307
  ...buildSitemapRewrites(sitemap),
1195
1308
  ...buildRobotsRewrites(robots),
1196
- ...buildDocsMarkdownRewrites(entry),
1309
+ ...buildDocsMarkdownRewrites(entry, docsPath),
1310
+ ...buildDocsPathRewrites(entry, docsPath),
1197
1311
  ...buildAgentFeedbackRewrites(agentFeedback)
1198
1312
  ];
1199
1313
  const autoAfterFilesRewrites = buildLlmsTxtRewrites(entry);
@@ -1223,6 +1337,7 @@ function withDocs(nextConfig = {}) {
1223
1337
  const docsConfigRelativeAlias = docsConfigPath.startsWith("./") || docsConfigPath.startsWith("../") ? docsConfigPath : `./${docsConfigPath}`;
1224
1338
  if (!hasFile(root, "mdx-components")) writeFileSync(join(root, "mdx-components.tsx"), MDX_COMPONENTS_TEMPLATE);
1225
1339
  const entry = readDocsEntry(root);
1340
+ const docsPath = normalizeDocsPath(readDocsPath(root), entry);
1226
1341
  const configuredContentDir = readDocsContentDir(root);
1227
1342
  const appDir = getNextAppDir(root);
1228
1343
  const docsContentDir = configuredContentDir ?? join(appDir, entry);
@@ -1317,6 +1432,7 @@ function withDocs(nextConfig = {}) {
1317
1432
  entry,
1318
1433
  appDir,
1319
1434
  contentDir: docsContentDir,
1435
+ docsPath,
1320
1436
  enabled: !isStaticExport
1321
1437
  }]);
1322
1438
  remarkPlugins.push(["remark-mdx-frontmatter", { name: "metadata" }], "@farming-labs/next/mdx-plugins/remark-heading");
@@ -1403,9 +1519,9 @@ function withDocs(nextConfig = {}) {
1403
1519
  if (!isStaticExport) {
1404
1520
  const existingRewrites = nextConfig.rewrites;
1405
1521
  nextConfig.rewrites = async () => {
1406
- return mergeDocsMarkdownRewrites(entry, mcp, sitemap, agentFeedback, robots, typeof existingRewrites === "function" ? await existingRewrites() : existingRewrites);
1522
+ return mergeDocsMarkdownRewrites(entry, docsPath, mcp, sitemap, agentFeedback, robots, typeof existingRewrites === "function" ? await existingRewrites() : existingRewrites);
1407
1523
  };
1408
- const autoRedirects = buildHiddenFolderRedirects(docsContentRoot, entry);
1524
+ const autoRedirects = buildHiddenFolderRedirects(docsContentRoot, docsPath);
1409
1525
  if (autoRedirects.length > 0) {
1410
1526
  const existingRedirects = nextConfig.redirects;
1411
1527
  nextConfig.redirects = async () => {
@@ -3,6 +3,7 @@ interface RemarkMarkdownAlternateOptions {
3
3
  entry?: string;
4
4
  appDir?: string;
5
5
  contentDir?: string;
6
+ docsPath?: string;
6
7
  enabled?: boolean;
7
8
  }
8
9
  interface MarkdownNode {
@@ -7,6 +7,16 @@ function normalizePath(value) {
7
7
  function normalizeSegment(value, fallback) {
8
8
  return (value ?? fallback).replace(/^\/+|\/+$/g, "") || fallback;
9
9
  }
10
+ function normalizeDocsPath(value, entry) {
11
+ if (typeof value !== "string") return `/${entry}`;
12
+ const cleaned = value.trim();
13
+ if (cleaned === "" || cleaned === "/") return "";
14
+ return `/${cleaned.replace(/^\/+|\/+$/g, "")}`;
15
+ }
16
+ function joinDocsPath(docsPath, slug) {
17
+ if (!slug) return docsPath || "/";
18
+ return docsPath ? `${docsPath}/${slug}` : `/${slug}`;
19
+ }
10
20
  function escapeYamlString(value) {
11
21
  return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
12
22
  }
@@ -27,7 +37,7 @@ function routeFromSourcePath(filePath, options) {
27
37
  const relativePath = normalized.slice(markerIndex + marker.length);
28
38
  if (!relativePath.endsWith("page.mdx") && !relativePath.endsWith("page.md")) continue;
29
39
  const slug = relativePath.replace(/\/?page\.mdx?$/, "").replace(/^\/+|\/+$/g, "");
30
- return slug ? `/${entry}/${slug}` : `/${entry}`;
40
+ return joinDocsPath(normalizeDocsPath(options.docsPath, entry), slug);
31
41
  }
32
42
  return null;
33
43
  }
@@ -41,7 +51,7 @@ function alternateYaml(url) {
41
51
  return [
42
52
  "alternates:",
43
53
  " types:",
44
- ` text/markdown: "${escapeYamlString(toDocsMarkdownUrl(url))}"`
54
+ ` text/markdown: "${escapeYamlString(url === "/" ? "/docs.md" : toDocsMarkdownUrl(url))}"`
45
55
  ].join("\n");
46
56
  }
47
57
  function remarkMarkdownAlternate(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/next",
3
- "version": "0.1.108",
3
+ "version": "0.1.111",
4
4
  "description": "Next.js adapter for @farming-labs/docs — MDX config wrapper",
5
5
  "keywords": [
6
6
  "docs",
@@ -100,8 +100,8 @@
100
100
  "tsdown": "^0.20.3",
101
101
  "typescript": "^5.9.3",
102
102
  "vitest": "^3.2.4",
103
- "@farming-labs/docs": "0.1.108",
104
- "@farming-labs/theme": "0.1.108"
103
+ "@farming-labs/docs": "0.1.111",
104
+ "@farming-labs/theme": "0.1.111"
105
105
  },
106
106
  "peerDependencies": {
107
107
  "@farming-labs/docs": ">=0.0.1",