@farming-labs/next 0.2.120 → 0.2.122
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/README.md +30 -1
- package/dist/api-reference-CTAOPJih.d.mts +49 -0
- package/dist/api-reference-banner-q98BnSRL.mjs +94 -0
- package/dist/api-reference.d.mts +2 -46
- package/dist/api-reference.mjs +2 -88
- package/dist/config-woF1rXS1.mjs +2345 -0
- package/dist/config-yzp9kyZ0.d.mts +21 -0
- package/dist/config.d.mts +2 -7
- package/dist/config.mjs +1 -2256
- package/dist/core-DRyvBL8l.mjs +16 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -2
- package/dist/layout.mjs +1 -1
- package/dist/mdx-plugins/remark-code-group.d.mts +7 -2
- package/dist/mdx-plugins/remark-code-group.mjs +2 -2
- package/dist/mdx-plugins/remark-heading.mjs +1 -1
- package/dist/mdx-plugins/remark-markdown-alternate.mjs +1 -1
- package/package.json +4 -4
- package/dist/code-block-themes-CCE5ViGj.mjs +0 -25
|
@@ -0,0 +1,2345 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, extname, isAbsolute, join, relative } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { DEFAULT_A2A_AGENT_CARD_ROUTE, DEFAULT_AGENT_SKILLS_INDEX_ROUTE, DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, DEFAULT_AGENT_SKILL_ARCHIVE_FORMAT, DEFAULT_API_CATALOG_ROUTE, DEFAULT_LEGACY_SKILLS_INDEX_ROUTE, DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX, DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN, DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN, DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN, ensureDocsReviewWorkflow, renderDocsAgentSkillsBundle, resolveConfiguredAgentSkillsSync } from "@farming-labs/docs/build";
|
|
5
|
+
import matter from "gray-matter";
|
|
6
|
+
import { parse } from "@babel/parser";
|
|
7
|
+
import createMDX from "@next/mdx";
|
|
8
|
+
|
|
9
|
+
//#region src/package-resolution.ts
|
|
10
|
+
/** Pin shared packages without replacing exported subpaths with filesystem paths. */
|
|
11
|
+
var DocsPackageResolutionPlugin = class {
|
|
12
|
+
roots;
|
|
13
|
+
constructor(packages) {
|
|
14
|
+
this.roots = new Map(Object.entries(packages).filter(([, directory]) => isAbsolute(directory)).map(([name, directory]) => [name, dirname(dirname(directory))]));
|
|
15
|
+
}
|
|
16
|
+
apply(resolver) {
|
|
17
|
+
resolver.getHook("described-resolve").tapAsync("DocsPackageResolutionPlugin", (request, context, done) => {
|
|
18
|
+
const name = request.request;
|
|
19
|
+
if (!name) return done();
|
|
20
|
+
const entry = [...this.roots].find(([pkg]) => name === pkg || name.startsWith(`${pkg}/`));
|
|
21
|
+
if (!entry || request.path === entry[1]) return done();
|
|
22
|
+
resolver.doResolve(resolver.ensureHook("resolve"), {
|
|
23
|
+
...request,
|
|
24
|
+
path: entry[1],
|
|
25
|
+
descriptionFilePath: void 0,
|
|
26
|
+
descriptionFileRoot: void 0,
|
|
27
|
+
descriptionFileData: void 0,
|
|
28
|
+
relativePath: void 0
|
|
29
|
+
}, `resolve shared docs package ${name}`, context, done);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/code-block-themes.ts
|
|
36
|
+
const DEFAULT_CODE_BLOCK_THEMES = {
|
|
37
|
+
light: "github-light",
|
|
38
|
+
dark: "github-dark"
|
|
39
|
+
};
|
|
40
|
+
const SHADCN_CODE_BLOCK_THEMES = {
|
|
41
|
+
light: "github-light-default",
|
|
42
|
+
dark: "vesper"
|
|
43
|
+
};
|
|
44
|
+
const SHADCN_THEME_IMPORT = /(?:from\s*|import\s*)["']@farming-labs\/theme\/shadcn["']/;
|
|
45
|
+
function resolveCodeBlockThemes({ root, configPath, theme, readSource = (path) => readFileSync(path, "utf8") }) {
|
|
46
|
+
const configFile = join(root, configPath);
|
|
47
|
+
const fallback = existsSync(configFile) && SHADCN_THEME_IMPORT.test(readSource(configFile)) ? SHADCN_CODE_BLOCK_THEMES : DEFAULT_CODE_BLOCK_THEMES;
|
|
48
|
+
const codeBlock = theme?.ui?.codeBlock;
|
|
49
|
+
return {
|
|
50
|
+
light: codeBlock?.theme ?? fallback.light,
|
|
51
|
+
dark: codeBlock?.darkTheme ?? fallback.dark
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/mdx-options.ts
|
|
57
|
+
function isJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
58
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
59
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
60
|
+
if (typeof value !== "object" || seen.has(value)) return false;
|
|
61
|
+
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return false;
|
|
62
|
+
seen.add(value);
|
|
63
|
+
const valid = Object.values(value).every((item) => isJsonValue(item, seen));
|
|
64
|
+
seen.delete(value);
|
|
65
|
+
return valid;
|
|
66
|
+
}
|
|
67
|
+
function copyPlugin(plugin) {
|
|
68
|
+
const module = Array.isArray(plugin) ? plugin[0] : plugin;
|
|
69
|
+
if (typeof module !== "string" || !module.trim() || Array.isArray(plugin) && plugin.length > 2) throw new TypeError("withDocs MDX plugins must be module names/paths or [module, JSON options] tuples.");
|
|
70
|
+
if (!Array.isArray(plugin)) return plugin;
|
|
71
|
+
if (plugin[1] === void 0) return [module];
|
|
72
|
+
if (!isJsonValue(plugin[1])) throw new TypeError(`withDocs MDX plugin ${module} requires JSON-serializable options for Turbopack. Put callbacks in the plugin module instead.`);
|
|
73
|
+
return [module, JSON.parse(JSON.stringify(plugin[1]))];
|
|
74
|
+
}
|
|
75
|
+
function resolveMdxExtensions(options) {
|
|
76
|
+
return {
|
|
77
|
+
remarkPlugins: (options?.remarkPlugins ?? []).map(copyPlugin),
|
|
78
|
+
rehypePlugins: (options?.rehypePlugins ?? []).map(copyPlugin),
|
|
79
|
+
codeHighlighter: options?.codeHighlighter === void 0 ? void 0 : copyPlugin(options.codeHighlighter)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/config.ts
|
|
85
|
+
/**
|
|
86
|
+
* Next.js config wrapper for @farming-labs/docs.
|
|
87
|
+
* Handles MDX compilation, frontmatter, syntax highlighting, TOC extraction,
|
|
88
|
+
* and auto-generates mdx-components.tsx + docs layout when missing.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* // next.config.ts — this is all you need:
|
|
92
|
+
* import { withDocs } from "@farming-labs/next/config";
|
|
93
|
+
* export default withDocs();
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* // With existing Next.js config
|
|
97
|
+
* import { withDocs } from "@farming-labs/next/config";
|
|
98
|
+
* export default withDocs({
|
|
99
|
+
* images: { remotePatterns: [{ hostname: "example.com" }] },
|
|
100
|
+
* });
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Full static export (Cloudflare Pages, etc.) — no server; API route is skipped.
|
|
104
|
+
* // In docs.config set ai.enabled: false and staticExport: true.
|
|
105
|
+
* export default withDocs({ output: "export" });
|
|
106
|
+
*/
|
|
107
|
+
/** Resolve Next.js App Router directory: prefer src/app when present, else app. */
|
|
108
|
+
function getNextAppDir(root) {
|
|
109
|
+
if (existsSync(join(root, "src", "app"))) return "src/app";
|
|
110
|
+
return "app";
|
|
111
|
+
}
|
|
112
|
+
const GENERATED_BANNER = "// Auto-generated by @farming-labs/next — do not edit manually.\n";
|
|
113
|
+
const MDX_COMPONENTS_TEMPLATE = `\
|
|
114
|
+
${GENERATED_BANNER}
|
|
115
|
+
import { getMDXComponents, type GetMDXComponentsOptions } from "@farming-labs/theme/mdx";
|
|
116
|
+
import type { MDXComponents } from "mdx/types";
|
|
117
|
+
import docsConfig from "@/docs.config";
|
|
118
|
+
|
|
119
|
+
export function useMDXComponents(components?: MDXComponents): MDXComponents {
|
|
120
|
+
const promptIconRegistry = docsConfig.icons as GetMDXComponentsOptions["icons"];
|
|
121
|
+
const promptOpenDocsProviders =
|
|
122
|
+
docsConfig.pageActions?.openDocs && typeof docsConfig.pageActions.openDocs === "object"
|
|
123
|
+
? (docsConfig.pageActions.openDocs.providers as GetMDXComponentsOptions["openDocsProviders"])
|
|
124
|
+
: undefined;
|
|
125
|
+
|
|
126
|
+
return getMDXComponents(
|
|
127
|
+
{
|
|
128
|
+
...(docsConfig.components as MDXComponents),
|
|
129
|
+
...components,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
onCopyClick: docsConfig.onCopyClick,
|
|
133
|
+
theme: docsConfig.theme,
|
|
134
|
+
icons: promptIconRegistry,
|
|
135
|
+
openDocsProviders: promptOpenDocsProviders,
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
const DOCS_LAYOUT_TEMPLATE = `\
|
|
141
|
+
${GENERATED_BANNER}
|
|
142
|
+
import docsConfig from "@/docs.config";
|
|
143
|
+
import { createNextDocsLayout, createNextDocsMetadata } from "@farming-labs/next/layout";
|
|
144
|
+
|
|
145
|
+
export const metadata = createNextDocsMetadata(docsConfig);
|
|
146
|
+
|
|
147
|
+
const DocsLayout = createNextDocsLayout(docsConfig);
|
|
148
|
+
|
|
149
|
+
export default function Layout({ children }: { children: React.ReactNode }) {
|
|
150
|
+
return <DocsLayout>{children}</DocsLayout>;
|
|
151
|
+
}
|
|
152
|
+
`;
|
|
153
|
+
const DOCS_API_ROUTE_TEMPLATE = `\
|
|
154
|
+
${GENERATED_BANNER}
|
|
155
|
+
import docsConfig from "@/docs.config";
|
|
156
|
+
import { createDocsAPI } from "@farming-labs/next/api";
|
|
157
|
+
import { createDocsCloudServer } from "@farming-labs/docs/cloud/server";
|
|
158
|
+
|
|
159
|
+
const docsCloud = createDocsCloudServer({
|
|
160
|
+
config: docsConfig,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export const { GET, HEAD, POST } = createDocsAPI(docsConfig, docsCloud);
|
|
164
|
+
|
|
165
|
+
export const revalidate = false;
|
|
166
|
+
`;
|
|
167
|
+
const DOCS_MCP_ROUTE_TEMPLATE = `\
|
|
168
|
+
${GENERATED_BANNER}
|
|
169
|
+
import docsConfig from "@/docs.config";
|
|
170
|
+
import { createDocsMCPAPI } from "@farming-labs/next/api";
|
|
171
|
+
|
|
172
|
+
export const { GET, POST, DELETE, OPTIONS } = createDocsMCPAPI(docsConfig);
|
|
173
|
+
|
|
174
|
+
export const revalidate = false;
|
|
175
|
+
`;
|
|
176
|
+
const API_REFERENCE_ROUTE_TEMPLATE = `\
|
|
177
|
+
${GENERATED_BANNER}
|
|
178
|
+
import docsConfig from "@/docs.config";
|
|
179
|
+
import { createNextApiReference } from "@farming-labs/next/api-reference";
|
|
180
|
+
|
|
181
|
+
export const GET = createNextApiReference(docsConfig);
|
|
182
|
+
|
|
183
|
+
export const revalidate = false;
|
|
184
|
+
`;
|
|
185
|
+
const API_REFERENCE_PAGE_TEMPLATE = `\
|
|
186
|
+
${GENERATED_BANNER}
|
|
187
|
+
import "@farming-labs/next/api-reference.css";
|
|
188
|
+
import docsConfig from "@/docs.config";
|
|
189
|
+
import { createNextApiReferencePage } from "@farming-labs/next/api-reference";
|
|
190
|
+
|
|
191
|
+
const ApiReferencePage = createNextApiReferencePage(docsConfig);
|
|
192
|
+
|
|
193
|
+
export const dynamic = "force-dynamic";
|
|
194
|
+
export const revalidate = 0;
|
|
195
|
+
|
|
196
|
+
export default ApiReferencePage;
|
|
197
|
+
`;
|
|
198
|
+
const API_REFERENCE_LAYOUT_TEMPLATE = `\
|
|
199
|
+
${GENERATED_BANNER}
|
|
200
|
+
import docsConfig from "@/docs.config";
|
|
201
|
+
import { createNextApiReferenceLayout } from "@farming-labs/next/api-reference";
|
|
202
|
+
|
|
203
|
+
const ApiReferenceLayout = createNextApiReferenceLayout(docsConfig);
|
|
204
|
+
|
|
205
|
+
export default ApiReferenceLayout;
|
|
206
|
+
`;
|
|
207
|
+
const CHANGELOG_SOURCE_LAYOUT_TEMPLATE = `\
|
|
208
|
+
${GENERATED_BANNER}
|
|
209
|
+
import { notFound } from "next/navigation";
|
|
210
|
+
|
|
211
|
+
export default function HiddenChangelogSourceLayout() {
|
|
212
|
+
notFound();
|
|
213
|
+
}
|
|
214
|
+
`;
|
|
215
|
+
const FILE_EXTS = [
|
|
216
|
+
"tsx",
|
|
217
|
+
"ts",
|
|
218
|
+
"jsx",
|
|
219
|
+
"js"
|
|
220
|
+
];
|
|
221
|
+
const INTERNAL_DOCS_CONFIG_ALIAS = "@farming-labs/next-internal-docs-config";
|
|
222
|
+
const AGENT_SKILLS_BUNDLE_ALIAS = "@farming-labs/docs/agent-skills-bundle";
|
|
223
|
+
const AGENT_SKILLS_BUNDLE_PATH = ".docs/agent-skills-bundle.mjs";
|
|
224
|
+
const NEXT_PACKAGE_ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
225
|
+
const DEFAULT_AGENT_SPEC_ROUTE = "/api/docs/agent/spec";
|
|
226
|
+
const DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE = "/.well-known/agent";
|
|
227
|
+
const DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE = "/.well-known/agent.json";
|
|
228
|
+
const DEFAULT_AGENT_FEEDBACK_ROUTE = "/api/docs/agent/feedback";
|
|
229
|
+
const DEFAULT_MCP_ROUTE = "/api/docs/mcp";
|
|
230
|
+
const DEFAULT_MCP_PUBLIC_ROUTE = "/mcp";
|
|
231
|
+
const DEFAULT_MCP_WELL_KNOWN_ROUTE = "/.well-known/mcp";
|
|
232
|
+
const DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE = "/.well-known/oauth-protected-resource";
|
|
233
|
+
const DEFAULT_LLMS_TXT_ROUTE = "/llms.txt";
|
|
234
|
+
const DEFAULT_LLMS_FULL_TXT_ROUTE = "/llms-full.txt";
|
|
235
|
+
const DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms.txt";
|
|
236
|
+
const DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms-full.txt";
|
|
237
|
+
const DEFAULT_SKILL_MD_ROUTE = "/skill.md";
|
|
238
|
+
const DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE = "/.well-known/skill.md";
|
|
239
|
+
const DEFAULT_AGENTS_MD_ROUTE = "/AGENTS.md";
|
|
240
|
+
const DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE = "/.well-known/AGENTS.md";
|
|
241
|
+
const DEFAULT_AGENT_MD_ROUTE = "/AGENT.md";
|
|
242
|
+
const DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE = "/.well-known/AGENT.md";
|
|
243
|
+
const DEFAULT_ROBOTS_TXT_ROUTE = "/robots.txt";
|
|
244
|
+
const DEFAULT_SITEMAP_XML_ROUTE = "/sitemap.xml";
|
|
245
|
+
const DEFAULT_SITEMAP_MD_ROUTE = "/sitemap.md";
|
|
246
|
+
const DEFAULT_SITEMAP_MD_DOCS_ROUTE = "/docs/sitemap.md";
|
|
247
|
+
const DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE = "/.well-known/sitemap.md";
|
|
248
|
+
const DEFAULT_SITEMAP_MANIFEST_PATH = ".farming-labs/sitemap-manifest.json";
|
|
249
|
+
const MARKDOWN_ACCEPT_HEADER_VALUE = [
|
|
250
|
+
"^",
|
|
251
|
+
"(?!.*(?:^|,)\\s*(?:[Tt][Ee][Xx][Tt]/[Hh][Tt][Mm][Ll]|[Tt][Ee][Xx][Tt]/\\*|\\*/\\*)(?:\\s*;[^,]*)?\\s*(?:,|$))",
|
|
252
|
+
"(?=.*(?:^|,)\\s*[Tt][Ee][Xx][Tt]/[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn]",
|
|
253
|
+
"(?:\\s*;",
|
|
254
|
+
"(?!\\s*(?:[^,;]*;\\s*)*[Qq]\\s*=\\s*(?:0+(?:\\.0*)?|\\.0+)\\s*(?:;|,|$))",
|
|
255
|
+
"[^,]*)?",
|
|
256
|
+
"\\s*(?:,|$))",
|
|
257
|
+
".*$"
|
|
258
|
+
].join("");
|
|
259
|
+
function resolvePackageAlias(packageName, fallbacks = []) {
|
|
260
|
+
return [join(NEXT_PACKAGE_ROOT, "node_modules", packageName), ...fallbacks.map((value) => join(NEXT_PACKAGE_ROOT, value))].find((value) => existsSync(value));
|
|
261
|
+
}
|
|
262
|
+
function resolvePackageSubpath(packageDir, relativePath) {
|
|
263
|
+
if (!isAbsolute(packageDir)) return `${packageDir}/${relativePath.replace(/^dist\//, "").replace(/\/index\.js$/, "")}`;
|
|
264
|
+
return join(packageDir, relativePath);
|
|
265
|
+
}
|
|
266
|
+
function toTurbopackAliasPath(root, value) {
|
|
267
|
+
if (!isAbsolute(value)) return value;
|
|
268
|
+
const relativePath = relative(root, value).replaceAll("\\", "/");
|
|
269
|
+
return relativePath === ".." || relativePath.startsWith("../") ? relativePath : relativePath.startsWith("./") ? relativePath : `./${relativePath}`;
|
|
270
|
+
}
|
|
271
|
+
const FUMADOCS_OPENAPI_PACKAGE_ALIAS = resolvePackageAlias("fumadocs-openapi") ?? "fumadocs-openapi";
|
|
272
|
+
const FUMADOCS_CORE_PACKAGE_ALIAS = resolvePackageAlias("fumadocs-core") ?? "fumadocs-core";
|
|
273
|
+
const FUMADOCS_UI_PACKAGE_ALIAS = resolvePackageAlias("fumadocs-ui", ["node_modules/fumadocs-openapi/node_modules/fumadocs-ui", "../node_modules/fumadocs-ui"]) ?? "fumadocs-ui";
|
|
274
|
+
const FUMADOCS_OPENAPI_UI_ALIAS = resolvePackageSubpath(FUMADOCS_OPENAPI_PACKAGE_ALIAS, "dist/ui/index.js");
|
|
275
|
+
const FUMADOCS_OPENAPI_SERVER_ALIAS = resolvePackageSubpath(FUMADOCS_OPENAPI_PACKAGE_ALIAS, "dist/server/index.js");
|
|
276
|
+
const FUMADOCS_CORE_FRAMEWORK_ALIAS = resolvePackageSubpath(FUMADOCS_CORE_PACKAGE_ALIAS, "dist/framework/index.js");
|
|
277
|
+
const FUMADOCS_CORE_FRAMEWORK_NEXT_ALIAS = resolvePackageSubpath(FUMADOCS_CORE_PACKAGE_ALIAS, "dist/framework/next.js");
|
|
278
|
+
const FUMADOCS_UI_NOTEBOOK_ALIAS = resolvePackageSubpath(FUMADOCS_UI_PACKAGE_ALIAS, "dist/layouts/notebook/index.js");
|
|
279
|
+
const FUMADOCS_UI_NOTEBOOK_PAGE_ALIAS = resolvePackageSubpath(FUMADOCS_UI_PACKAGE_ALIAS, "dist/layouts/notebook/page/index.js");
|
|
280
|
+
const FUMADOCS_UI_PROVIDER_NEXT_ALIAS = resolvePackageSubpath(FUMADOCS_UI_PACKAGE_ALIAS, "dist/provider/next.js");
|
|
281
|
+
function isDocsWorkspaceRoot(root) {
|
|
282
|
+
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"));
|
|
283
|
+
}
|
|
284
|
+
function findDocsWorkspaceRoot(start) {
|
|
285
|
+
let current = start;
|
|
286
|
+
while (true) {
|
|
287
|
+
if (isDocsWorkspaceRoot(current)) return current;
|
|
288
|
+
const parent = dirname(current);
|
|
289
|
+
if (parent === current) return void 0;
|
|
290
|
+
current = parent;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function normalizeEnvValue(value) {
|
|
294
|
+
const normalized = value?.trim();
|
|
295
|
+
return normalized ? normalized : void 0;
|
|
296
|
+
}
|
|
297
|
+
function createPublicDocsCloudAnalyticsEnv() {
|
|
298
|
+
const projectId = normalizeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_PROJECT_ID) ?? normalizeEnvValue(process.env.PUBLIC_DOCS_CLOUD_PROJECT_ID) ?? normalizeEnvValue(process.env.DOCS_CLOUD_PROJECT_ID);
|
|
299
|
+
const configuredEndpoint = normalizeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT) ?? normalizeEnvValue(process.env.PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT) ?? normalizeEnvValue(process.env.DOCS_CLOUD_ANALYTICS_ENDPOINT);
|
|
300
|
+
const enabled = normalizeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED) ?? normalizeEnvValue(process.env.PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED) ?? normalizeEnvValue(process.env.DOCS_CLOUD_ANALYTICS_ENABLED);
|
|
301
|
+
const env = {};
|
|
302
|
+
if (projectId) env.NEXT_PUBLIC_DOCS_CLOUD_PROJECT_ID = projectId;
|
|
303
|
+
if (configuredEndpoint) env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT = configuredEndpoint;
|
|
304
|
+
if (enabled) env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED = enabled;
|
|
305
|
+
return env;
|
|
306
|
+
}
|
|
307
|
+
function createDocsWorkspaceAliases(root, workspaceRoot) {
|
|
308
|
+
const workspaceAlias = (...parts) => toTurbopackAliasPath(root, join(workspaceRoot, ...parts));
|
|
309
|
+
const workspaceEntrypoint = (distParts, sourceParts) => {
|
|
310
|
+
const distPath = join(workspaceRoot, ...distParts);
|
|
311
|
+
const sourcePath = join(workspaceRoot, ...sourceParts);
|
|
312
|
+
return workspaceAlias(...existsSync(distPath) || !existsSync(sourcePath) ? distParts : sourceParts);
|
|
313
|
+
};
|
|
314
|
+
return {
|
|
315
|
+
"@farming-labs/docs": workspaceEntrypoint([
|
|
316
|
+
"packages",
|
|
317
|
+
"docs",
|
|
318
|
+
"dist",
|
|
319
|
+
"index.mjs"
|
|
320
|
+
], [
|
|
321
|
+
"packages",
|
|
322
|
+
"docs",
|
|
323
|
+
"src",
|
|
324
|
+
"index.ts"
|
|
325
|
+
]),
|
|
326
|
+
"@farming-labs/docs/server": workspaceEntrypoint([
|
|
327
|
+
"packages",
|
|
328
|
+
"docs",
|
|
329
|
+
"dist",
|
|
330
|
+
"server.mjs"
|
|
331
|
+
], [
|
|
332
|
+
"packages",
|
|
333
|
+
"docs",
|
|
334
|
+
"src",
|
|
335
|
+
"server.ts"
|
|
336
|
+
]),
|
|
337
|
+
"@farming-labs/docs/cloud/server": workspaceEntrypoint([
|
|
338
|
+
"packages",
|
|
339
|
+
"docs",
|
|
340
|
+
"dist",
|
|
341
|
+
"docs-cloud-server.mjs"
|
|
342
|
+
], [
|
|
343
|
+
"packages",
|
|
344
|
+
"docs",
|
|
345
|
+
"src",
|
|
346
|
+
"docs-cloud-server.ts"
|
|
347
|
+
]),
|
|
348
|
+
"@farming-labs/next": workspaceEntrypoint([
|
|
349
|
+
"packages",
|
|
350
|
+
"next",
|
|
351
|
+
"dist",
|
|
352
|
+
"index.mjs"
|
|
353
|
+
], [
|
|
354
|
+
"packages",
|
|
355
|
+
"next",
|
|
356
|
+
"src",
|
|
357
|
+
"index.ts"
|
|
358
|
+
]),
|
|
359
|
+
"@farming-labs/next/api": workspaceEntrypoint([
|
|
360
|
+
"packages",
|
|
361
|
+
"next",
|
|
362
|
+
"dist",
|
|
363
|
+
"api.mjs"
|
|
364
|
+
], [
|
|
365
|
+
"packages",
|
|
366
|
+
"next",
|
|
367
|
+
"src",
|
|
368
|
+
"api.ts"
|
|
369
|
+
]),
|
|
370
|
+
"@farming-labs/next/changelog": workspaceEntrypoint([
|
|
371
|
+
"packages",
|
|
372
|
+
"next",
|
|
373
|
+
"dist",
|
|
374
|
+
"changelog.mjs"
|
|
375
|
+
], [
|
|
376
|
+
"packages",
|
|
377
|
+
"next",
|
|
378
|
+
"src",
|
|
379
|
+
"changelog.tsx"
|
|
380
|
+
]),
|
|
381
|
+
"@farming-labs/next/client-callbacks": workspaceEntrypoint([
|
|
382
|
+
"packages",
|
|
383
|
+
"next",
|
|
384
|
+
"dist",
|
|
385
|
+
"client-callbacks.mjs"
|
|
386
|
+
], [
|
|
387
|
+
"packages",
|
|
388
|
+
"next",
|
|
389
|
+
"src",
|
|
390
|
+
"client-callbacks.tsx"
|
|
391
|
+
]),
|
|
392
|
+
"@farming-labs/next/layout": workspaceEntrypoint([
|
|
393
|
+
"packages",
|
|
394
|
+
"next",
|
|
395
|
+
"dist",
|
|
396
|
+
"layout.mjs"
|
|
397
|
+
], [
|
|
398
|
+
"packages",
|
|
399
|
+
"next",
|
|
400
|
+
"src",
|
|
401
|
+
"layout.tsx"
|
|
402
|
+
]),
|
|
403
|
+
"@farming-labs/next/mdx-plugins/rehype-code": workspaceEntrypoint([
|
|
404
|
+
"packages",
|
|
405
|
+
"next",
|
|
406
|
+
"dist",
|
|
407
|
+
"mdx-plugins",
|
|
408
|
+
"rehype-code.mjs"
|
|
409
|
+
], [
|
|
410
|
+
"packages",
|
|
411
|
+
"next",
|
|
412
|
+
"src",
|
|
413
|
+
"mdx-plugins",
|
|
414
|
+
"rehype-code.ts"
|
|
415
|
+
]),
|
|
416
|
+
"@farming-labs/next/mdx-plugins/rehype-toc": workspaceEntrypoint([
|
|
417
|
+
"packages",
|
|
418
|
+
"next",
|
|
419
|
+
"dist",
|
|
420
|
+
"mdx-plugins",
|
|
421
|
+
"rehype-toc.mjs"
|
|
422
|
+
], [
|
|
423
|
+
"packages",
|
|
424
|
+
"next",
|
|
425
|
+
"src",
|
|
426
|
+
"mdx-plugins",
|
|
427
|
+
"rehype-toc.ts"
|
|
428
|
+
]),
|
|
429
|
+
"@farming-labs/next/mdx-plugins/remark-code-group": workspaceEntrypoint([
|
|
430
|
+
"packages",
|
|
431
|
+
"next",
|
|
432
|
+
"dist",
|
|
433
|
+
"mdx-plugins",
|
|
434
|
+
"remark-code-group.mjs"
|
|
435
|
+
], [
|
|
436
|
+
"packages",
|
|
437
|
+
"next",
|
|
438
|
+
"src",
|
|
439
|
+
"mdx-plugins",
|
|
440
|
+
"remark-code-group.ts"
|
|
441
|
+
]),
|
|
442
|
+
"@farming-labs/next/mdx-plugins/remark-heading": workspaceEntrypoint([
|
|
443
|
+
"packages",
|
|
444
|
+
"next",
|
|
445
|
+
"dist",
|
|
446
|
+
"mdx-plugins",
|
|
447
|
+
"remark-heading.mjs"
|
|
448
|
+
], [
|
|
449
|
+
"packages",
|
|
450
|
+
"next",
|
|
451
|
+
"src",
|
|
452
|
+
"mdx-plugins",
|
|
453
|
+
"remark-heading.ts"
|
|
454
|
+
]),
|
|
455
|
+
"@farming-labs/next/mdx-plugins/remark-og": workspaceEntrypoint([
|
|
456
|
+
"packages",
|
|
457
|
+
"next",
|
|
458
|
+
"dist",
|
|
459
|
+
"mdx-plugins",
|
|
460
|
+
"remark-og.mjs"
|
|
461
|
+
], [
|
|
462
|
+
"packages",
|
|
463
|
+
"next",
|
|
464
|
+
"src",
|
|
465
|
+
"mdx-plugins",
|
|
466
|
+
"remark-og.ts"
|
|
467
|
+
]),
|
|
468
|
+
"@farming-labs/next/mdx-plugins/remark-markdown-alternate": workspaceEntrypoint([
|
|
469
|
+
"packages",
|
|
470
|
+
"next",
|
|
471
|
+
"dist",
|
|
472
|
+
"mdx-plugins",
|
|
473
|
+
"remark-markdown-alternate.mjs"
|
|
474
|
+
], [
|
|
475
|
+
"packages",
|
|
476
|
+
"next",
|
|
477
|
+
"src",
|
|
478
|
+
"mdx-plugins",
|
|
479
|
+
"remark-markdown-alternate.ts"
|
|
480
|
+
]),
|
|
481
|
+
"@farming-labs/theme": workspaceEntrypoint([
|
|
482
|
+
"packages",
|
|
483
|
+
"fumadocs",
|
|
484
|
+
"dist",
|
|
485
|
+
"index.mjs"
|
|
486
|
+
], [
|
|
487
|
+
"packages",
|
|
488
|
+
"fumadocs",
|
|
489
|
+
"src",
|
|
490
|
+
"index.ts"
|
|
491
|
+
]),
|
|
492
|
+
"@farming-labs/theme/api": workspaceEntrypoint([
|
|
493
|
+
"packages",
|
|
494
|
+
"fumadocs",
|
|
495
|
+
"dist",
|
|
496
|
+
"docs-api.mjs"
|
|
497
|
+
], [
|
|
498
|
+
"packages",
|
|
499
|
+
"fumadocs",
|
|
500
|
+
"src",
|
|
501
|
+
"docs-api.ts"
|
|
502
|
+
]),
|
|
503
|
+
"@farming-labs/theme/client-hooks": workspaceEntrypoint([
|
|
504
|
+
"packages",
|
|
505
|
+
"fumadocs",
|
|
506
|
+
"dist",
|
|
507
|
+
"docs-client-hooks.mjs"
|
|
508
|
+
], [
|
|
509
|
+
"packages",
|
|
510
|
+
"fumadocs",
|
|
511
|
+
"src",
|
|
512
|
+
"docs-client-hooks.tsx"
|
|
513
|
+
]),
|
|
514
|
+
"@farming-labs/theme/concrete": workspaceEntrypoint([
|
|
515
|
+
"packages",
|
|
516
|
+
"fumadocs",
|
|
517
|
+
"dist",
|
|
518
|
+
"concrete",
|
|
519
|
+
"index.mjs"
|
|
520
|
+
], [
|
|
521
|
+
"packages",
|
|
522
|
+
"fumadocs",
|
|
523
|
+
"src",
|
|
524
|
+
"concrete",
|
|
525
|
+
"index.ts"
|
|
526
|
+
]),
|
|
527
|
+
"@farming-labs/theme/hardline": workspaceEntrypoint([
|
|
528
|
+
"packages",
|
|
529
|
+
"fumadocs",
|
|
530
|
+
"dist",
|
|
531
|
+
"hardline",
|
|
532
|
+
"index.mjs"
|
|
533
|
+
], [
|
|
534
|
+
"packages",
|
|
535
|
+
"fumadocs",
|
|
536
|
+
"src",
|
|
537
|
+
"hardline",
|
|
538
|
+
"index.ts"
|
|
539
|
+
]),
|
|
540
|
+
"@farming-labs/theme/ledger": workspaceEntrypoint([
|
|
541
|
+
"packages",
|
|
542
|
+
"fumadocs",
|
|
543
|
+
"dist",
|
|
544
|
+
"ledger",
|
|
545
|
+
"index.mjs"
|
|
546
|
+
], [
|
|
547
|
+
"packages",
|
|
548
|
+
"fumadocs",
|
|
549
|
+
"src",
|
|
550
|
+
"ledger",
|
|
551
|
+
"index.ts"
|
|
552
|
+
]),
|
|
553
|
+
"@farming-labs/theme/shadcn": workspaceEntrypoint([
|
|
554
|
+
"packages",
|
|
555
|
+
"fumadocs",
|
|
556
|
+
"dist",
|
|
557
|
+
"shadcn",
|
|
558
|
+
"index.mjs"
|
|
559
|
+
], [
|
|
560
|
+
"packages",
|
|
561
|
+
"fumadocs",
|
|
562
|
+
"src",
|
|
563
|
+
"shadcn",
|
|
564
|
+
"index.ts"
|
|
565
|
+
]),
|
|
566
|
+
"@farming-labs/theme/mdx": workspaceEntrypoint([
|
|
567
|
+
"packages",
|
|
568
|
+
"fumadocs",
|
|
569
|
+
"dist",
|
|
570
|
+
"mdx.mjs"
|
|
571
|
+
], [
|
|
572
|
+
"packages",
|
|
573
|
+
"fumadocs",
|
|
574
|
+
"src",
|
|
575
|
+
"mdx.ts"
|
|
576
|
+
]),
|
|
577
|
+
"@farming-labs/theme/search": workspaceEntrypoint([
|
|
578
|
+
"packages",
|
|
579
|
+
"fumadocs",
|
|
580
|
+
"dist",
|
|
581
|
+
"search.mjs"
|
|
582
|
+
], [
|
|
583
|
+
"packages",
|
|
584
|
+
"fumadocs",
|
|
585
|
+
"src",
|
|
586
|
+
"search.ts"
|
|
587
|
+
])
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function hasFile(root, baseName) {
|
|
591
|
+
return FILE_EXTS.some((ext) => existsSync(join(root, `${baseName}.${ext}`)));
|
|
592
|
+
}
|
|
593
|
+
function isManagedGeneratedFile(filePath) {
|
|
594
|
+
if (!existsSync(filePath)) return false;
|
|
595
|
+
try {
|
|
596
|
+
return readFileSync(filePath, "utf-8").startsWith(GENERATED_BANNER);
|
|
597
|
+
} catch {
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
/** Scope file contents to one configuration pass so later calls see edits. */
|
|
602
|
+
function createConfigSourceReader() {
|
|
603
|
+
const sources = /* @__PURE__ */ new Map();
|
|
604
|
+
return (path) => {
|
|
605
|
+
let content = sources.get(path);
|
|
606
|
+
if (content === void 0) {
|
|
607
|
+
content = readFileSync(path, "utf-8");
|
|
608
|
+
sources.set(path, content);
|
|
609
|
+
}
|
|
610
|
+
return content;
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
/** Read the docs entry path from docs.config.ts[x] (defaults to "docs"). */
|
|
614
|
+
function readDocsEntry(root, readSource) {
|
|
615
|
+
for (const ext of FILE_EXTS) {
|
|
616
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
617
|
+
if (existsSync(configPath)) try {
|
|
618
|
+
const match = readSource(configPath).match(/entry\s*:\s*["']([^"']+)["']/);
|
|
619
|
+
if (match) return match[1];
|
|
620
|
+
} catch {}
|
|
621
|
+
}
|
|
622
|
+
return "docs";
|
|
623
|
+
}
|
|
624
|
+
function readDocsContentDir(root, readSource) {
|
|
625
|
+
for (const ext of FILE_EXTS) {
|
|
626
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
627
|
+
if (!existsSync(configPath)) continue;
|
|
628
|
+
try {
|
|
629
|
+
const contentDir = readTopLevelStringProperty(readSource(configPath), "contentDir");
|
|
630
|
+
if (contentDir) return contentDir;
|
|
631
|
+
} catch {}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function readDocsPath(root, readSource) {
|
|
635
|
+
for (const ext of FILE_EXTS) {
|
|
636
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
637
|
+
if (!existsSync(configPath)) continue;
|
|
638
|
+
try {
|
|
639
|
+
return readTopLevelStringProperty(readSource(configPath), "docsPath");
|
|
640
|
+
} catch {}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function readDocsConfigPath(root) {
|
|
644
|
+
for (const ext of FILE_EXTS) {
|
|
645
|
+
const relativePath = `docs.config.${ext}`;
|
|
646
|
+
if (existsSync(join(root, relativePath))) return relativePath;
|
|
647
|
+
}
|
|
648
|
+
return "docs.config.ts";
|
|
649
|
+
}
|
|
650
|
+
function unwrapStaticExpression(expression) {
|
|
651
|
+
let current = expression;
|
|
652
|
+
while (current.type === "ParenthesizedExpression" || current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression" || current.type === "TSInstantiationExpression") current = current.expression;
|
|
653
|
+
return current;
|
|
654
|
+
}
|
|
655
|
+
function readStaticPropertyName(property) {
|
|
656
|
+
const key = unwrapStaticExpression(property.key);
|
|
657
|
+
if (property.computed) return void 0;
|
|
658
|
+
if (key.type === "Identifier") return key.name;
|
|
659
|
+
if (key.type === "StringLiteral") return key.value;
|
|
660
|
+
if (key.type === "NumericLiteral") return String(key.value);
|
|
661
|
+
if (key.type === "BigIntLiteral") return key.value;
|
|
662
|
+
if (key.type === "TemplateLiteral" && key.expressions.length === 0) return key.quasis[0]?.value.cooked ?? void 0;
|
|
663
|
+
}
|
|
664
|
+
function resolveStaticObjectProperty(object, key) {
|
|
665
|
+
let resolution = { status: "absent" };
|
|
666
|
+
for (const entry of object.properties) {
|
|
667
|
+
if (entry.type === "SpreadElement") {
|
|
668
|
+
resolution = { status: "unknown" };
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
const name = readStaticPropertyName(entry);
|
|
672
|
+
if (name === void 0) {
|
|
673
|
+
if (entry.computed) resolution = { status: "unknown" };
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
if (name === "__proto__" && !entry.computed && entry.type === "ObjectProperty" && !entry.shorthand) {
|
|
677
|
+
if (resolution.status !== "value") resolution = { status: "unknown" };
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
if (name !== key) continue;
|
|
681
|
+
if (entry.type !== "ObjectProperty" || entry.shorthand) {
|
|
682
|
+
resolution = { status: "unknown" };
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
resolution = {
|
|
686
|
+
status: "value",
|
|
687
|
+
value: entry.value
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
return resolution;
|
|
691
|
+
}
|
|
692
|
+
function hasDefineDocsImport(program, localName) {
|
|
693
|
+
return program.body.some((statement) => statement.type === "ImportDeclaration" && statement.importKind !== "type" && statement.source.value === "@farming-labs/docs" && statement.specifiers.some((specifier) => specifier.type === "ImportSpecifier" && specifier.importKind !== "type" && specifier.local.name === localName && specifier.imported.type === "Identifier" && specifier.imported.name === "defineDocs"));
|
|
694
|
+
}
|
|
695
|
+
function readDocsConfigRootObject(configPath, content) {
|
|
696
|
+
let program;
|
|
697
|
+
try {
|
|
698
|
+
const extension = extname(configPath).toLowerCase();
|
|
699
|
+
program = parse(content, {
|
|
700
|
+
sourceType: "module",
|
|
701
|
+
sourceFilename: configPath,
|
|
702
|
+
plugins: extension === ".tsx" ? [
|
|
703
|
+
"typescript",
|
|
704
|
+
"jsx",
|
|
705
|
+
"decorators-legacy"
|
|
706
|
+
] : extension === ".ts" ? ["typescript", "decorators-legacy"] : extension === ".jsx" ? ["jsx", "decorators-legacy"] : ["decorators-legacy"],
|
|
707
|
+
createParenthesizedExpressions: true
|
|
708
|
+
}).program;
|
|
709
|
+
} catch (error) {
|
|
710
|
+
throw new Error(`withDocs could not parse ${configPath} while bundling Agent Skills: ${error instanceof Error ? error.message : String(error)}`);
|
|
711
|
+
}
|
|
712
|
+
const defaults = program.body.filter((statement) => statement.type === "ExportDefaultDeclaration");
|
|
713
|
+
if (defaults.length !== 1) throw new Error("withDocs could not statically determine agent.skills. Pass the live docs config as the second withDocs argument or use a literal agent object.");
|
|
714
|
+
let expression = unwrapStaticExpression(defaults[0].declaration);
|
|
715
|
+
if (expression.type === "CallExpression") {
|
|
716
|
+
const callee = expression.callee.type === "V8IntrinsicIdentifier" ? void 0 : unwrapStaticExpression(expression.callee);
|
|
717
|
+
const argument = expression.arguments[0];
|
|
718
|
+
if (!callee || callee.type !== "Identifier" || !hasDefineDocsImport(program, callee.name) || !argument || argument.type === "SpreadElement" || argument.type === "ArgumentPlaceholder") throw new Error("withDocs could not statically determine agent.skills. Pass the live docs config as the second withDocs argument or use a literal agent object.");
|
|
719
|
+
expression = unwrapStaticExpression(argument);
|
|
720
|
+
}
|
|
721
|
+
if (expression.type !== "ObjectExpression") throw new Error("withDocs could not statically determine agent.skills. Pass the live docs config as the second withDocs argument or use a literal agent object.");
|
|
722
|
+
return expression;
|
|
723
|
+
}
|
|
724
|
+
function readStaticStringPaths(expression) {
|
|
725
|
+
const value = unwrapStaticExpression(expression);
|
|
726
|
+
if (value.type === "StringLiteral") return [value.value];
|
|
727
|
+
if (value.type !== "ArrayExpression") return null;
|
|
728
|
+
const paths = [];
|
|
729
|
+
for (const entry of value.elements) {
|
|
730
|
+
if (!entry || entry.type === "SpreadElement") return null;
|
|
731
|
+
const item = unwrapStaticExpression(entry);
|
|
732
|
+
if (item.type !== "StringLiteral") return null;
|
|
733
|
+
paths.push(item.value);
|
|
734
|
+
}
|
|
735
|
+
return paths;
|
|
736
|
+
}
|
|
737
|
+
function readAgentSkillPaths(root, configPath, readSource) {
|
|
738
|
+
const absoluteConfigPath = join(root, configPath);
|
|
739
|
+
if (!existsSync(absoluteConfigPath)) return [];
|
|
740
|
+
const agent = resolveStaticObjectProperty(readDocsConfigRootObject(absoluteConfigPath, readSource(absoluteConfigPath)), "agent");
|
|
741
|
+
if (agent.status === "absent") return [];
|
|
742
|
+
if (agent.status === "unknown") throw new Error("withDocs could not statically determine agent.skills from a composed agent config. Pass the live docs config as the second withDocs argument.");
|
|
743
|
+
const agentValue = unwrapStaticExpression(agent.value);
|
|
744
|
+
if (agentValue.type !== "ObjectExpression") throw new Error("withDocs could not statically determine agent.skills from a composed agent config. Pass the live docs config as the second withDocs argument.");
|
|
745
|
+
const skills = resolveStaticObjectProperty(agentValue, "skills");
|
|
746
|
+
if (skills.status === "absent") return [];
|
|
747
|
+
if (skills.status === "unknown") throw new Error("withDocs could not statically determine agent.skills from a composed agent config. Pass the live docs config as the second withDocs argument.");
|
|
748
|
+
const skillsValue = unwrapStaticExpression(skills.value);
|
|
749
|
+
let configured;
|
|
750
|
+
if (skillsValue.type === "ObjectExpression") {
|
|
751
|
+
const paths = resolveStaticObjectProperty(skillsValue, "paths");
|
|
752
|
+
configured = paths.status === "value" ? readStaticStringPaths(paths.value) : null;
|
|
753
|
+
} else configured = readStaticStringPaths(skillsValue);
|
|
754
|
+
if (!configured) throw new Error("withDocs could not statically bundle agent.skills. Use a literal path, a literal path array, or { paths: [...] } so configured skills are included in production.");
|
|
755
|
+
return configured;
|
|
756
|
+
}
|
|
757
|
+
const ROOT_DOCUMENT_FILES = [
|
|
758
|
+
"skill.md",
|
|
759
|
+
"AGENTS.md",
|
|
760
|
+
"AGENT.md"
|
|
761
|
+
];
|
|
762
|
+
/**
|
|
763
|
+
* Snapshot the project-root agent documents into the skills bundle. Tracing
|
|
764
|
+
* them by bare filename is not an option: Turbopack matches such globs at any
|
|
765
|
+
* depth, which drags `node_modules/next/AGENTS.md` into the trace through the
|
|
766
|
+
* pnpm workspace symlink and breaks Vercel output materialization.
|
|
767
|
+
*/
|
|
768
|
+
function readRootDocumentsSnapshot(root) {
|
|
769
|
+
const documents = {};
|
|
770
|
+
for (const fileName of ROOT_DOCUMENT_FILES) {
|
|
771
|
+
const filePath = join(root, fileName);
|
|
772
|
+
if (!existsSync(filePath)) continue;
|
|
773
|
+
try {
|
|
774
|
+
documents[fileName] = readFileSync(filePath, "utf8");
|
|
775
|
+
} catch {}
|
|
776
|
+
}
|
|
777
|
+
return Object.keys(documents).length > 0 ? documents : void 0;
|
|
778
|
+
}
|
|
779
|
+
function writeAgentSkillsBundle(root, configuredSkills) {
|
|
780
|
+
const bundlePath = join(root, AGENT_SKILLS_BUNDLE_PATH);
|
|
781
|
+
const source = `${GENERATED_BANNER}${renderDocsAgentSkillsBundle(resolveConfiguredAgentSkillsSync(configuredSkills, { rootDir: root }), readRootDocumentsSnapshot(root))}`;
|
|
782
|
+
makeGeneratedDir(dirname(bundlePath));
|
|
783
|
+
if (!existsSync(bundlePath) || readFileSync(bundlePath, "utf8") !== source) writeGeneratedFile(bundlePath, source);
|
|
784
|
+
return bundlePath;
|
|
785
|
+
}
|
|
786
|
+
/** Read the OG endpoint from docs.config.ts[x] (returns undefined if not set). */
|
|
787
|
+
function readOgEndpoint(root, readSource) {
|
|
788
|
+
for (const ext of FILE_EXTS) {
|
|
789
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
790
|
+
if (existsSync(configPath)) try {
|
|
791
|
+
const match = readSource(configPath).match(/endpoint\s*:\s*["']([^"']+)["']/);
|
|
792
|
+
if (match && match[1]) return match[1];
|
|
793
|
+
} catch {}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
function readApiReferenceConfig(root, readSource) {
|
|
797
|
+
for (const ext of FILE_EXTS) {
|
|
798
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
799
|
+
if (!existsSync(configPath)) continue;
|
|
800
|
+
try {
|
|
801
|
+
const content = readSource(configPath);
|
|
802
|
+
if (content.match(/apiReference\s*:\s*false/)) return {
|
|
803
|
+
enabled: false,
|
|
804
|
+
path: "api-reference",
|
|
805
|
+
renderer: "farming-labs",
|
|
806
|
+
routeRoot: "api"
|
|
807
|
+
};
|
|
808
|
+
if (content.match(/apiReference\s*:\s*true/)) return {
|
|
809
|
+
enabled: true,
|
|
810
|
+
path: "api-reference",
|
|
811
|
+
renderer: "farming-labs",
|
|
812
|
+
routeRoot: "api"
|
|
813
|
+
};
|
|
814
|
+
const block = extractObjectLiteral(content, "apiReference");
|
|
815
|
+
if (!block) continue;
|
|
816
|
+
const enabledMatch = block.match(/enabled\s*:\s*(true|false)/);
|
|
817
|
+
const pathMatch = block.match(/path\s*:\s*["']([^"']+)["']/);
|
|
818
|
+
const rendererMatch = block.match(/renderer\s*:\s*["'](farming-labs|fumadocs|scalar)["']/);
|
|
819
|
+
const rendererConfigNameMatch = extractObjectLiteral(block, "renderer")?.match(/name\s*:\s*["'](farming-labs|fumadocs|scalar)["']/);
|
|
820
|
+
const usesFumadocsRendererHelper = /renderer\s*:\s*fumadocsRenderer\s*\(/.test(block);
|
|
821
|
+
const routeRootMatch = block.match(/routeRoot\s*:\s*["']([^"']+)["']/);
|
|
822
|
+
return {
|
|
823
|
+
enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
|
|
824
|
+
path: pathMatch?.[1]?.replace(/^\/+|\/+$/g, "") || "api-reference",
|
|
825
|
+
renderer: rendererMatch?.[1] ?? rendererConfigNameMatch?.[1] ?? (usesFumadocsRendererHelper ? "fumadocs" : void 0) ?? "farming-labs",
|
|
826
|
+
routeRoot: routeRootMatch?.[1]?.replace(/^\/+|\/+$/g, "") || "api"
|
|
827
|
+
};
|
|
828
|
+
} catch {
|
|
829
|
+
return {
|
|
830
|
+
enabled: false,
|
|
831
|
+
path: "api-reference",
|
|
832
|
+
renderer: "farming-labs",
|
|
833
|
+
routeRoot: "api"
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return {
|
|
838
|
+
enabled: false,
|
|
839
|
+
path: "api-reference",
|
|
840
|
+
renderer: "farming-labs",
|
|
841
|
+
routeRoot: "api"
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
function readChangelogConfig(root, readSource) {
|
|
845
|
+
for (const ext of FILE_EXTS) {
|
|
846
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
847
|
+
if (!existsSync(configPath)) continue;
|
|
848
|
+
try {
|
|
849
|
+
const content = readSource(configPath);
|
|
850
|
+
if (content.match(/changelog\s*:\s*false/)) return {
|
|
851
|
+
enabled: false,
|
|
852
|
+
path: "changelog",
|
|
853
|
+
contentDir: "changelog"
|
|
854
|
+
};
|
|
855
|
+
if (content.match(/changelog\s*:\s*true/)) return {
|
|
856
|
+
enabled: true,
|
|
857
|
+
path: "changelog",
|
|
858
|
+
contentDir: "changelog"
|
|
859
|
+
};
|
|
860
|
+
const block = extractObjectLiteral(content, "changelog");
|
|
861
|
+
if (!block) continue;
|
|
862
|
+
const enabledMatch = block.match(/enabled\s*:\s*(true|false)/);
|
|
863
|
+
const pathMatch = block.match(/path\s*:\s*["']([^"']+)["']/);
|
|
864
|
+
const contentDirMatch = block.match(/contentDir\s*:\s*["']([^"']+)["']/);
|
|
865
|
+
return {
|
|
866
|
+
enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
|
|
867
|
+
path: pathMatch?.[1]?.replace(/^\/+|\/+$/g, "") || "changelog",
|
|
868
|
+
contentDir: contentDirMatch?.[1]?.replace(/\/+$/, "") || "changelog"
|
|
869
|
+
};
|
|
870
|
+
} catch {
|
|
871
|
+
return {
|
|
872
|
+
enabled: false,
|
|
873
|
+
path: "changelog",
|
|
874
|
+
contentDir: "changelog"
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return {
|
|
879
|
+
enabled: false,
|
|
880
|
+
path: "changelog",
|
|
881
|
+
contentDir: "changelog"
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function resolveDocsContentDir(root, appDir, entry, readSource) {
|
|
885
|
+
const configuredContentDir = readDocsContentDir(root, readSource);
|
|
886
|
+
if (!configuredContentDir) return join(root, appDir, entry);
|
|
887
|
+
return isAbsolute(configuredContentDir) ? configuredContentDir : join(root, configuredContentDir);
|
|
888
|
+
}
|
|
889
|
+
function resolveChangelogContentDir(root, appDir, entry, changelogContentDir, readSource) {
|
|
890
|
+
if (isAbsolute(changelogContentDir)) return changelogContentDir;
|
|
891
|
+
return join(resolveDocsContentDir(root, appDir, entry, readSource), changelogContentDir);
|
|
892
|
+
}
|
|
893
|
+
function findChangelogSourceEntries(changelogDir) {
|
|
894
|
+
if (!existsSync(changelogDir)) return [];
|
|
895
|
+
const entries = [];
|
|
896
|
+
for (const name of readdirSync(changelogDir).sort()) {
|
|
897
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(name)) continue;
|
|
898
|
+
const entryDir = join(changelogDir, name);
|
|
899
|
+
try {
|
|
900
|
+
if (!statSync(entryDir).isDirectory()) continue;
|
|
901
|
+
} catch {
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
const sourceFile = ["page.mdx", "page.md"].map((fileName) => join(entryDir, fileName)).find((value) => existsSync(value));
|
|
905
|
+
if (!sourceFile) continue;
|
|
906
|
+
let metadata = {};
|
|
907
|
+
try {
|
|
908
|
+
metadata = matter(readFileSync(sourceFile, "utf-8")).data;
|
|
909
|
+
} catch {
|
|
910
|
+
metadata = {};
|
|
911
|
+
}
|
|
912
|
+
entries.push({
|
|
913
|
+
slug: name,
|
|
914
|
+
date: name,
|
|
915
|
+
sourceFile,
|
|
916
|
+
metadata
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
return entries.sort((left, right) => right.date.localeCompare(left.date));
|
|
920
|
+
}
|
|
921
|
+
function extractRootObjectLiteral(content) {
|
|
922
|
+
const candidateIndexes = [content.search(/\bdefineDocs\s*\(/), content.search(/\bexport\s+default\b/)].filter((value) => value !== -1);
|
|
923
|
+
for (const startIndex of candidateIndexes) {
|
|
924
|
+
const braceStart = content.indexOf("{", startIndex);
|
|
925
|
+
if (braceStart === -1) continue;
|
|
926
|
+
let depth = 0;
|
|
927
|
+
let inString = null;
|
|
928
|
+
let escaped = false;
|
|
929
|
+
for (let index = braceStart; index < content.length; index += 1) {
|
|
930
|
+
const char = content[index];
|
|
931
|
+
if (inString) {
|
|
932
|
+
if (escaped) {
|
|
933
|
+
escaped = false;
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (char === "\\") {
|
|
937
|
+
escaped = true;
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
if (char === inString) inString = null;
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
943
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
944
|
+
inString = char;
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
if (char === "{") {
|
|
948
|
+
depth += 1;
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
951
|
+
if (char !== "}") continue;
|
|
952
|
+
depth -= 1;
|
|
953
|
+
if (depth === 0) return content.slice(braceStart + 1, index);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function findTopLevelPropertyValueIndex(block, key) {
|
|
958
|
+
let objectDepth = 0;
|
|
959
|
+
let arrayDepth = 0;
|
|
960
|
+
let parenDepth = 0;
|
|
961
|
+
let inString = null;
|
|
962
|
+
let inLineComment = false;
|
|
963
|
+
let inBlockComment = false;
|
|
964
|
+
let escaped = false;
|
|
965
|
+
for (let index = 0; index < block.length; index += 1) {
|
|
966
|
+
const char = block[index];
|
|
967
|
+
const next = block[index + 1];
|
|
968
|
+
if (inLineComment) {
|
|
969
|
+
if (char === "\n") inLineComment = false;
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (inBlockComment) {
|
|
973
|
+
if (char === "*" && next === "/") {
|
|
974
|
+
inBlockComment = false;
|
|
975
|
+
index += 1;
|
|
976
|
+
}
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
if (inString) {
|
|
980
|
+
if (escaped) {
|
|
981
|
+
escaped = false;
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (char === "\\") {
|
|
985
|
+
escaped = true;
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
if (char === inString) inString = null;
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
991
|
+
if (char === "/" && next === "/") {
|
|
992
|
+
inLineComment = true;
|
|
993
|
+
index += 1;
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
if (char === "/" && next === "*") {
|
|
997
|
+
inBlockComment = true;
|
|
998
|
+
index += 1;
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
1002
|
+
inString = char;
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
if (char === "{") {
|
|
1006
|
+
objectDepth += 1;
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
if (char === "}") {
|
|
1010
|
+
objectDepth = Math.max(0, objectDepth - 1);
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (char === "[") {
|
|
1014
|
+
arrayDepth += 1;
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (char === "]") {
|
|
1018
|
+
arrayDepth = Math.max(0, arrayDepth - 1);
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
if (char === "(") {
|
|
1022
|
+
parenDepth += 1;
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
if (char === ")") {
|
|
1026
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
if (objectDepth !== 0 || arrayDepth !== 0 || parenDepth !== 0) continue;
|
|
1030
|
+
if (!block.startsWith(key, index)) continue;
|
|
1031
|
+
const before = block[index - 1] ?? "";
|
|
1032
|
+
const after = block[index + key.length] ?? "";
|
|
1033
|
+
if (/[A-Za-z0-9_$]/.test(before) || /[A-Za-z0-9_$]/.test(after)) continue;
|
|
1034
|
+
let cursor = index + key.length;
|
|
1035
|
+
while (/\s/.test(block[cursor] ?? "")) cursor += 1;
|
|
1036
|
+
if (block[cursor] !== ":") continue;
|
|
1037
|
+
cursor += 1;
|
|
1038
|
+
while (/\s/.test(block[cursor] ?? "")) cursor += 1;
|
|
1039
|
+
return cursor;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
function findMatchingObjectEnd(block, start) {
|
|
1043
|
+
let depth = 0;
|
|
1044
|
+
let inString = null;
|
|
1045
|
+
let inLineComment = false;
|
|
1046
|
+
let inBlockComment = false;
|
|
1047
|
+
let escaped = false;
|
|
1048
|
+
for (let index = start; index < block.length; index += 1) {
|
|
1049
|
+
const char = block[index];
|
|
1050
|
+
const next = block[index + 1];
|
|
1051
|
+
if (inLineComment) {
|
|
1052
|
+
if (char === "\n") inLineComment = false;
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
if (inBlockComment) {
|
|
1056
|
+
if (char === "*" && next === "/") {
|
|
1057
|
+
inBlockComment = false;
|
|
1058
|
+
index += 1;
|
|
1059
|
+
}
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
if (inString) {
|
|
1063
|
+
if (escaped) {
|
|
1064
|
+
escaped = false;
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
if (char === "\\") {
|
|
1068
|
+
escaped = true;
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
if (char === inString) inString = null;
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
1074
|
+
if (char === "/" && next === "/") {
|
|
1075
|
+
inLineComment = true;
|
|
1076
|
+
index += 1;
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
if (char === "/" && next === "*") {
|
|
1080
|
+
inBlockComment = true;
|
|
1081
|
+
index += 1;
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
1085
|
+
inString = char;
|
|
1086
|
+
continue;
|
|
1087
|
+
}
|
|
1088
|
+
if (char === "{") {
|
|
1089
|
+
depth += 1;
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
if (char !== "}") continue;
|
|
1093
|
+
depth -= 1;
|
|
1094
|
+
if (depth === 0) return index;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
function readTopLevelStringProperty(content, key) {
|
|
1098
|
+
const block = extractRootObjectLiteral(content);
|
|
1099
|
+
if (!block) return void 0;
|
|
1100
|
+
const cursor = findTopLevelPropertyValueIndex(block, key);
|
|
1101
|
+
if (cursor === void 0) return void 0;
|
|
1102
|
+
const quote = block[cursor];
|
|
1103
|
+
if (quote !== "\"" && quote !== "'") return void 0;
|
|
1104
|
+
let value = "";
|
|
1105
|
+
for (let index = cursor + 1; index < block.length; index += 1) {
|
|
1106
|
+
const valueChar = block[index];
|
|
1107
|
+
if (valueChar === "\\") {
|
|
1108
|
+
const escapedChar = block[index + 1];
|
|
1109
|
+
if (escapedChar) {
|
|
1110
|
+
value += escapedChar;
|
|
1111
|
+
index += 1;
|
|
1112
|
+
}
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
if (valueChar === quote) return value;
|
|
1116
|
+
value += valueChar;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
function readTopLevelBooleanProperty(content, key) {
|
|
1120
|
+
const block = extractRootObjectLiteral(content);
|
|
1121
|
+
if (!block) return void 0;
|
|
1122
|
+
const cursor = findTopLevelPropertyValueIndex(block, key);
|
|
1123
|
+
if (cursor === void 0) return void 0;
|
|
1124
|
+
if (block.startsWith("true", cursor)) return true;
|
|
1125
|
+
if (block.startsWith("false", cursor)) return false;
|
|
1126
|
+
}
|
|
1127
|
+
function extractTopLevelObjectLiteral(content, key) {
|
|
1128
|
+
const block = extractRootObjectLiteral(content);
|
|
1129
|
+
if (!block) return void 0;
|
|
1130
|
+
const cursor = findTopLevelPropertyValueIndex(block, key);
|
|
1131
|
+
if (cursor === void 0 || block[cursor] !== "{") return void 0;
|
|
1132
|
+
const end = findMatchingObjectEnd(block, cursor);
|
|
1133
|
+
return end === void 0 ? void 0 : block.slice(cursor + 1, end);
|
|
1134
|
+
}
|
|
1135
|
+
function extractObjectLiteral(content, key) {
|
|
1136
|
+
const keyIndex = content.search(new RegExp(`${key}\\s*:\\s*\\{`));
|
|
1137
|
+
if (keyIndex === -1) return void 0;
|
|
1138
|
+
const braceStart = content.indexOf("{", keyIndex);
|
|
1139
|
+
if (braceStart === -1) return void 0;
|
|
1140
|
+
let depth = 0;
|
|
1141
|
+
for (let index = braceStart; index < content.length; index += 1) {
|
|
1142
|
+
const char = content[index];
|
|
1143
|
+
if (char === "{") {
|
|
1144
|
+
depth += 1;
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
if (char !== "}") continue;
|
|
1148
|
+
depth -= 1;
|
|
1149
|
+
if (depth === 0) return content.slice(braceStart + 1, index);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function toImportPath(fromFile, toFile) {
|
|
1153
|
+
const relativePath = relative(dirname(fromFile), toFile).replaceAll("\\", "/");
|
|
1154
|
+
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
1155
|
+
}
|
|
1156
|
+
function toObjectKeySource(key) {
|
|
1157
|
+
return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
1158
|
+
}
|
|
1159
|
+
function toInlineValueSource(value) {
|
|
1160
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
1161
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
1162
|
+
if (typeof value === "boolean") return String(value);
|
|
1163
|
+
if (value === null) return "null";
|
|
1164
|
+
return JSON.stringify(value) ?? "undefined";
|
|
1165
|
+
}
|
|
1166
|
+
function toObjectPropertySource(key, value, depth) {
|
|
1167
|
+
const childIndent = " ".repeat(depth + 2);
|
|
1168
|
+
const wrappedValueIndent = " ".repeat(depth + 4);
|
|
1169
|
+
const valueSource = toChangelogMetadataSource(value, depth + 2);
|
|
1170
|
+
const inlineSource = `${childIndent}${toObjectKeySource(key)}: ${valueSource},`;
|
|
1171
|
+
if (!valueSource.includes("\n") && inlineSource.length > 100) return `${childIndent}${toObjectKeySource(key)}:\n${wrappedValueIndent}${valueSource},`;
|
|
1172
|
+
return inlineSource;
|
|
1173
|
+
}
|
|
1174
|
+
function toChangelogMetadataSource(value, depth = 0) {
|
|
1175
|
+
const indent = " ".repeat(depth);
|
|
1176
|
+
const childIndent = " ".repeat(depth + 2);
|
|
1177
|
+
if (Array.isArray(value)) {
|
|
1178
|
+
if (value.length === 0) return "[]";
|
|
1179
|
+
if (value.every((item) => item === null || typeof item === "string" || typeof item === "number" || typeof item === "boolean")) return `[${value.map(toInlineValueSource).join(", ")}]`;
|
|
1180
|
+
return `[
|
|
1181
|
+
${value.map((item) => `${childIndent}${toChangelogMetadataSource(item, depth + 2)},`).join("\n")}
|
|
1182
|
+
${indent}]`;
|
|
1183
|
+
}
|
|
1184
|
+
if (value && typeof value === "object") {
|
|
1185
|
+
const entries = Object.entries(value).filter((entry) => entry[1] !== void 0);
|
|
1186
|
+
if (entries.length === 0) return "{}";
|
|
1187
|
+
return `{
|
|
1188
|
+
${entries.map(([key, item]) => toObjectPropertySource(key, item, depth)).join("\n")}
|
|
1189
|
+
${indent}}`;
|
|
1190
|
+
}
|
|
1191
|
+
return toInlineValueSource(value);
|
|
1192
|
+
}
|
|
1193
|
+
function buildInlineChangelogEntriesSource(root, pagePath, entryPath, routePath, entries) {
|
|
1194
|
+
const imports = [];
|
|
1195
|
+
const records = [];
|
|
1196
|
+
entries.forEach((entry, index) => {
|
|
1197
|
+
const importName = `ChangelogEntry${index + 1}`;
|
|
1198
|
+
imports.push(`import ${importName} from "${toImportPath(pagePath, entry.sourceFile)}";`);
|
|
1199
|
+
records.push(` {
|
|
1200
|
+
slug: ${JSON.stringify(entry.slug)},
|
|
1201
|
+
date: ${JSON.stringify(entry.date)},
|
|
1202
|
+
url: ${JSON.stringify(`/${entryPath}/${routePath}/${entry.slug}`)},
|
|
1203
|
+
sourcePath: ${JSON.stringify(relative(root, entry.sourceFile).replaceAll("\\", "/"))},
|
|
1204
|
+
Component: ${importName},
|
|
1205
|
+
metadata: ${toChangelogMetadataSource(entry.metadata, 4)},
|
|
1206
|
+
}`);
|
|
1207
|
+
});
|
|
1208
|
+
return {
|
|
1209
|
+
importsSource: `import type { GeneratedChangelogEntry } from "@farming-labs/next/changelog";
|
|
1210
|
+
${imports.join("\n")}`.trimEnd(),
|
|
1211
|
+
entriesSource: `export const changelogEntries: GeneratedChangelogEntry[] = [
|
|
1212
|
+
${records.length > 0 ? `${records.join(",\n")},` : ""}
|
|
1213
|
+
];`
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
function buildChangelogIndexPageSource(root, pagePath, entryPath, routePath, entries) {
|
|
1217
|
+
const { importsSource, entriesSource } = buildInlineChangelogEntriesSource(root, pagePath, entryPath, routePath, entries);
|
|
1218
|
+
return `\
|
|
1219
|
+
${GENERATED_BANNER}
|
|
1220
|
+
import docsConfig from "@/docs.config";
|
|
1221
|
+
${importsSource}
|
|
1222
|
+
import {
|
|
1223
|
+
createNextChangelogIndexMetadata,
|
|
1224
|
+
createNextChangelogIndexPage,
|
|
1225
|
+
} from "@farming-labs/next/changelog";
|
|
1226
|
+
|
|
1227
|
+
${entriesSource}
|
|
1228
|
+
|
|
1229
|
+
export const metadata = createNextChangelogIndexMetadata(docsConfig);
|
|
1230
|
+
|
|
1231
|
+
const ChangelogPage = createNextChangelogIndexPage(docsConfig, changelogEntries);
|
|
1232
|
+
|
|
1233
|
+
export default ChangelogPage;
|
|
1234
|
+
`;
|
|
1235
|
+
}
|
|
1236
|
+
function buildChangelogEntryPageSource(root, pagePath, entryPath, routePath, entries) {
|
|
1237
|
+
const { importsSource, entriesSource } = buildInlineChangelogEntriesSource(root, pagePath, entryPath, routePath, entries);
|
|
1238
|
+
return `\
|
|
1239
|
+
${GENERATED_BANNER}
|
|
1240
|
+
import docsConfig from "@/docs.config";
|
|
1241
|
+
${importsSource}
|
|
1242
|
+
import {
|
|
1243
|
+
createNextChangelogEntryMetadata,
|
|
1244
|
+
createNextChangelogEntryPage,
|
|
1245
|
+
createNextChangelogStaticParams,
|
|
1246
|
+
} from "@farming-labs/next/changelog";
|
|
1247
|
+
|
|
1248
|
+
${entriesSource}
|
|
1249
|
+
|
|
1250
|
+
export const generateStaticParams = createNextChangelogStaticParams(changelogEntries);
|
|
1251
|
+
export const generateMetadata = createNextChangelogEntryMetadata(docsConfig, changelogEntries);
|
|
1252
|
+
|
|
1253
|
+
const ChangelogEntryPage = createNextChangelogEntryPage(docsConfig, changelogEntries);
|
|
1254
|
+
|
|
1255
|
+
export default ChangelogEntryPage;
|
|
1256
|
+
`;
|
|
1257
|
+
}
|
|
1258
|
+
function resolveManagedChangelogSourceLayoutPath(root, appDir, entry, changelogContentDir, readSource) {
|
|
1259
|
+
if (isAbsolute(changelogContentDir)) return void 0;
|
|
1260
|
+
const appRoot = join(root, appDir);
|
|
1261
|
+
const contentRoot = resolveChangelogContentDir(root, appDir, entry, changelogContentDir, readSource);
|
|
1262
|
+
const relativePath = relative(appRoot, contentRoot);
|
|
1263
|
+
if (relativePath.startsWith("..") || isAbsolute(relativePath)) return void 0;
|
|
1264
|
+
return join(contentRoot, "layout.tsx");
|
|
1265
|
+
}
|
|
1266
|
+
function removeManagedFile(filePath) {
|
|
1267
|
+
if (isManagedGeneratedFile(filePath)) withReadOnlyFsGuard(filePath, () => rmSync(filePath, { force: true }));
|
|
1268
|
+
}
|
|
1269
|
+
const READ_ONLY_FS_CODES = new Set([
|
|
1270
|
+
"EROFS",
|
|
1271
|
+
"EACCES",
|
|
1272
|
+
"EPERM"
|
|
1273
|
+
]);
|
|
1274
|
+
/** Generation must not take down config evaluation on read-only filesystems; the build already shipped these files. */
|
|
1275
|
+
function withReadOnlyFsGuard(target, mutate) {
|
|
1276
|
+
try {
|
|
1277
|
+
return mutate();
|
|
1278
|
+
} catch (error) {
|
|
1279
|
+
const code = error?.code;
|
|
1280
|
+
if (!code || !READ_ONLY_FS_CODES.has(code)) throw error;
|
|
1281
|
+
console.warn(`[docs] Skipped generating ${target} (${code}): filesystem is read-only; using existing files.`);
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
function makeGeneratedDir(dirPath) {
|
|
1286
|
+
withReadOnlyFsGuard(dirPath, () => mkdirSync(dirPath, { recursive: true }));
|
|
1287
|
+
}
|
|
1288
|
+
function writeGeneratedFile(filePath, content) {
|
|
1289
|
+
withReadOnlyFsGuard(filePath, () => {
|
|
1290
|
+
if (existsSync(filePath) && readFileSync(filePath, "utf8") === content) return;
|
|
1291
|
+
writeFileSync(filePath, content, "utf8");
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
function resolveMcpConfig(mcp) {
|
|
1295
|
+
if (mcp === false) return {
|
|
1296
|
+
enabled: false,
|
|
1297
|
+
route: DEFAULT_MCP_ROUTE,
|
|
1298
|
+
protectedResource: false
|
|
1299
|
+
};
|
|
1300
|
+
if (!mcp || mcp === true) return {
|
|
1301
|
+
enabled: true,
|
|
1302
|
+
route: DEFAULT_MCP_ROUTE,
|
|
1303
|
+
protectedResource: false
|
|
1304
|
+
};
|
|
1305
|
+
return {
|
|
1306
|
+
enabled: mcp.enabled ?? true,
|
|
1307
|
+
route: normalizeRoutePath(mcp.route ?? DEFAULT_MCP_ROUTE),
|
|
1308
|
+
protectedResource: Boolean(mcp.security?.authenticate && mcp.security.protectedResource)
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
function readMcpConfig(root, readSource) {
|
|
1312
|
+
for (const ext of FILE_EXTS) {
|
|
1313
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
1314
|
+
if (!existsSync(configPath)) continue;
|
|
1315
|
+
try {
|
|
1316
|
+
const content = readSource(configPath);
|
|
1317
|
+
if (content.match(/mcp\s*:\s*false/)) return {
|
|
1318
|
+
enabled: false,
|
|
1319
|
+
route: DEFAULT_MCP_ROUTE,
|
|
1320
|
+
protectedResource: false
|
|
1321
|
+
};
|
|
1322
|
+
if (content.match(/mcp\s*:\s*true/)) return {
|
|
1323
|
+
enabled: true,
|
|
1324
|
+
route: DEFAULT_MCP_ROUTE,
|
|
1325
|
+
protectedResource: false
|
|
1326
|
+
};
|
|
1327
|
+
const block = extractObjectLiteral(content, "mcp");
|
|
1328
|
+
if (!block) continue;
|
|
1329
|
+
const enabledMatch = block.match(/enabled\s*:\s*(true|false)/);
|
|
1330
|
+
const routeMatch = block.match(/route\s*:\s*["']([^"']+)["']/);
|
|
1331
|
+
const securityBlock = extractObjectLiteral(block, "security");
|
|
1332
|
+
const protectedResource = Boolean(securityBlock && /\bauthenticate\b/u.test(securityBlock) && extractObjectLiteral(securityBlock, "protectedResource"));
|
|
1333
|
+
return {
|
|
1334
|
+
enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
|
|
1335
|
+
route: normalizeRoutePath(routeMatch?.[1] ?? DEFAULT_MCP_ROUTE),
|
|
1336
|
+
protectedResource
|
|
1337
|
+
};
|
|
1338
|
+
} catch {
|
|
1339
|
+
return {
|
|
1340
|
+
enabled: true,
|
|
1341
|
+
route: DEFAULT_MCP_ROUTE,
|
|
1342
|
+
protectedResource: false
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
return {
|
|
1347
|
+
enabled: true,
|
|
1348
|
+
route: DEFAULT_MCP_ROUTE,
|
|
1349
|
+
protectedResource: false
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
function normalizeRoutePath(route) {
|
|
1353
|
+
const normalized = `/${route}`.replace(/\/+/g, "/");
|
|
1354
|
+
return normalized !== "/" ? normalized.replace(/\/+$/, "") : DEFAULT_MCP_ROUTE;
|
|
1355
|
+
}
|
|
1356
|
+
function normalizeMcpResourcePath(route) {
|
|
1357
|
+
return route.trim() === "/" ? "/" : normalizeRoutePath(route);
|
|
1358
|
+
}
|
|
1359
|
+
function buildMcpProtectedResourceMetadataRoute(resourcePath) {
|
|
1360
|
+
const normalized = normalizeMcpResourcePath(resourcePath);
|
|
1361
|
+
return normalized === "/" ? DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE : `${DEFAULT_MCP_PROTECTED_RESOURCE_METADATA_ROUTE}${normalized}`;
|
|
1362
|
+
}
|
|
1363
|
+
function normalizeRoutePrefix(prefix) {
|
|
1364
|
+
if (!prefix) return "";
|
|
1365
|
+
const normalized = `/${prefix.replace(/^\/+|\/+$/g, "")}`.replace(/\/+/g, "/");
|
|
1366
|
+
return normalized === "/" ? "" : normalized;
|
|
1367
|
+
}
|
|
1368
|
+
function joinPublicRoute(prefix, route) {
|
|
1369
|
+
return `${prefix}/${route.replace(/^\/+/, "")}`.replace(/\/+/g, "/");
|
|
1370
|
+
}
|
|
1371
|
+
function readSitemapConfig(root, readSource) {
|
|
1372
|
+
for (const ext of FILE_EXTS) {
|
|
1373
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
1374
|
+
if (!existsSync(configPath)) continue;
|
|
1375
|
+
try {
|
|
1376
|
+
const content = readSource(configPath);
|
|
1377
|
+
if (content.match(/sitemap\s*:\s*false/)) return {
|
|
1378
|
+
enabled: false,
|
|
1379
|
+
routePrefix: ""
|
|
1380
|
+
};
|
|
1381
|
+
if (content.match(/sitemap\s*:\s*true/)) return {
|
|
1382
|
+
enabled: true,
|
|
1383
|
+
routePrefix: ""
|
|
1384
|
+
};
|
|
1385
|
+
const block = extractObjectLiteral(content, "sitemap");
|
|
1386
|
+
if (!block) continue;
|
|
1387
|
+
const enabledMatch = block.match(/enabled\s*:\s*(true|false)/);
|
|
1388
|
+
const routePrefixMatch = block.match(/routePrefix\s*:\s*["']([^"']+)["']/);
|
|
1389
|
+
return {
|
|
1390
|
+
enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
|
|
1391
|
+
routePrefix: normalizeRoutePrefix(routePrefixMatch?.[1])
|
|
1392
|
+
};
|
|
1393
|
+
} catch {
|
|
1394
|
+
return {
|
|
1395
|
+
enabled: true,
|
|
1396
|
+
routePrefix: ""
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return {
|
|
1401
|
+
enabled: true,
|
|
1402
|
+
routePrefix: ""
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
function readRobotsConfig(root, readSource) {
|
|
1406
|
+
const publicStaticPath = join(root, "public", "robots.txt");
|
|
1407
|
+
const appDir = getNextAppDir(root);
|
|
1408
|
+
const appStaticPath = join(root, appDir, "robots.txt");
|
|
1409
|
+
const appRouteExists = FILE_EXTS.some((ext) => existsSync(join(root, appDir, `robots.${ext}`)));
|
|
1410
|
+
const hasStaticFile = existsSync(publicStaticPath) || existsSync(appStaticPath) || appRouteExists;
|
|
1411
|
+
for (const ext of FILE_EXTS) {
|
|
1412
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
1413
|
+
if (!existsSync(configPath)) continue;
|
|
1414
|
+
try {
|
|
1415
|
+
const content = readSource(configPath);
|
|
1416
|
+
if (content.match(/robots\s*:\s*false/)) return {
|
|
1417
|
+
enabled: false,
|
|
1418
|
+
hasStaticFile
|
|
1419
|
+
};
|
|
1420
|
+
if (content.match(/robots\s*:\s*true/)) return {
|
|
1421
|
+
enabled: true,
|
|
1422
|
+
hasStaticFile
|
|
1423
|
+
};
|
|
1424
|
+
const block = extractObjectLiteral(content, "robots");
|
|
1425
|
+
if (!block) continue;
|
|
1426
|
+
const enabledMatch = block.match(/enabled\s*:\s*(true|false)/);
|
|
1427
|
+
return {
|
|
1428
|
+
enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
|
|
1429
|
+
hasStaticFile
|
|
1430
|
+
};
|
|
1431
|
+
} catch {
|
|
1432
|
+
return {
|
|
1433
|
+
enabled: true,
|
|
1434
|
+
hasStaticFile
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return {
|
|
1439
|
+
enabled: true,
|
|
1440
|
+
hasStaticFile
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1443
|
+
function normalizeAgentFeedbackRoute(route, fallback = DEFAULT_AGENT_FEEDBACK_ROUTE) {
|
|
1444
|
+
if (!route || route.trim().length === 0) return fallback;
|
|
1445
|
+
const normalized = `/${route}`.replace(/\/+/g, "/");
|
|
1446
|
+
return normalized !== "/" ? normalized.replace(/\/+$/, "") : fallback;
|
|
1447
|
+
}
|
|
1448
|
+
function readAgentFeedbackConfig(root, readSource) {
|
|
1449
|
+
const defaultRoute = normalizeAgentFeedbackRoute();
|
|
1450
|
+
const enabled = {
|
|
1451
|
+
enabled: true,
|
|
1452
|
+
route: defaultRoute,
|
|
1453
|
+
schemaRoute: `${defaultRoute}/schema`
|
|
1454
|
+
};
|
|
1455
|
+
const disabled = {
|
|
1456
|
+
enabled: false,
|
|
1457
|
+
route: defaultRoute,
|
|
1458
|
+
schemaRoute: `${defaultRoute}/schema`
|
|
1459
|
+
};
|
|
1460
|
+
for (const ext of FILE_EXTS) {
|
|
1461
|
+
const configPath = join(root, `docs.config.${ext}`);
|
|
1462
|
+
if (!existsSync(configPath)) continue;
|
|
1463
|
+
try {
|
|
1464
|
+
const content = readSource(configPath);
|
|
1465
|
+
const feedbackBoolean = readTopLevelBooleanProperty(content, "feedback");
|
|
1466
|
+
if (feedbackBoolean === false) return disabled;
|
|
1467
|
+
if (feedbackBoolean === true) return enabled;
|
|
1468
|
+
const feedbackBlock = extractTopLevelObjectLiteral(content, "feedback");
|
|
1469
|
+
if (!feedbackBlock) return enabled;
|
|
1470
|
+
if (feedbackBlock.match(/agent\s*:\s*false/)) return disabled;
|
|
1471
|
+
if (feedbackBlock.match(/agent\s*:\s*true/)) return enabled;
|
|
1472
|
+
const agentBlock = extractObjectLiteral(feedbackBlock, "agent");
|
|
1473
|
+
if (!agentBlock) return enabled;
|
|
1474
|
+
const enabledMatch = agentBlock.match(/enabled\s*:\s*(true|false)/);
|
|
1475
|
+
const routeMatch = agentBlock.match(/route\s*:\s*["']([^"']+)["']/);
|
|
1476
|
+
const schemaRouteMatch = agentBlock.match(/schemaRoute\s*:\s*["']([^"']+)["']/);
|
|
1477
|
+
const route = normalizeAgentFeedbackRoute(routeMatch?.[1], defaultRoute);
|
|
1478
|
+
return {
|
|
1479
|
+
enabled: enabledMatch ? enabledMatch[1] !== "false" : true,
|
|
1480
|
+
route,
|
|
1481
|
+
schemaRoute: normalizeAgentFeedbackRoute(schemaRouteMatch?.[1], `${route}/schema`)
|
|
1482
|
+
};
|
|
1483
|
+
} catch {
|
|
1484
|
+
return disabled;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
return enabled;
|
|
1488
|
+
}
|
|
1489
|
+
function normalizeRouteSegment(value, fallback = "docs") {
|
|
1490
|
+
return (value ?? fallback).replace(/^\/+|\/+$/g, "") || fallback;
|
|
1491
|
+
}
|
|
1492
|
+
function normalizeDocsPath(value, entry) {
|
|
1493
|
+
if (typeof value !== "string") return `/${normalizeRouteSegment(entry)}`;
|
|
1494
|
+
const cleaned = value.trim().replace(/^\/+|\/+$/g, "").replace(/\/+/g, "/");
|
|
1495
|
+
if (cleaned === "") return "";
|
|
1496
|
+
return `/${cleaned}`;
|
|
1497
|
+
}
|
|
1498
|
+
function docsRootSource(entry) {
|
|
1499
|
+
return [
|
|
1500
|
+
"/:slug((?!",
|
|
1501
|
+
"_next/",
|
|
1502
|
+
"|api/",
|
|
1503
|
+
`|${normalizeRouteSegment(entry)}(?:/|$)`,
|
|
1504
|
+
"|favicon\\.ico",
|
|
1505
|
+
"|robots\\.txt",
|
|
1506
|
+
"|sitemap\\.xml",
|
|
1507
|
+
"|sitemap\\.md",
|
|
1508
|
+
"|docs\\.md",
|
|
1509
|
+
"|llms\\.txt",
|
|
1510
|
+
"|llms-full\\.txt",
|
|
1511
|
+
"|mcp(?:/|$)",
|
|
1512
|
+
"|AGENTS\\.md",
|
|
1513
|
+
"|AGENT\\.md",
|
|
1514
|
+
"|skill\\.md",
|
|
1515
|
+
"|\\.well-known/",
|
|
1516
|
+
"|.*\\..*",
|
|
1517
|
+
").*)"
|
|
1518
|
+
].join("");
|
|
1519
|
+
}
|
|
1520
|
+
function docsRootMarkdownSource(entry) {
|
|
1521
|
+
return [
|
|
1522
|
+
"/:slug((?!",
|
|
1523
|
+
"_next/",
|
|
1524
|
+
"|api/",
|
|
1525
|
+
`|${normalizeRouteSegment(entry)}/`,
|
|
1526
|
+
"|docs\\.md",
|
|
1527
|
+
"|sitemap\\.md",
|
|
1528
|
+
"|AGENTS\\.md",
|
|
1529
|
+
"|AGENT\\.md",
|
|
1530
|
+
"|skill\\.md",
|
|
1531
|
+
"|\\.well-known/",
|
|
1532
|
+
").*)\\.md"
|
|
1533
|
+
].join("");
|
|
1534
|
+
}
|
|
1535
|
+
function buildDocsPathRewrites(entry, docsPath) {
|
|
1536
|
+
const normalizedEntry = normalizeRouteSegment(entry);
|
|
1537
|
+
const internalBase = `/${normalizedEntry}`;
|
|
1538
|
+
if (docsPath === internalBase) return [];
|
|
1539
|
+
if (docsPath === "") return [{
|
|
1540
|
+
source: "/",
|
|
1541
|
+
destination: `${internalBase}/`
|
|
1542
|
+
}, {
|
|
1543
|
+
source: docsRootSource(normalizedEntry),
|
|
1544
|
+
destination: `${internalBase}/:slug`
|
|
1545
|
+
}];
|
|
1546
|
+
return [{
|
|
1547
|
+
source: docsPath,
|
|
1548
|
+
destination: internalBase
|
|
1549
|
+
}, {
|
|
1550
|
+
source: `${docsPath}/:slug*`,
|
|
1551
|
+
destination: `${internalBase}/:slug*`
|
|
1552
|
+
}];
|
|
1553
|
+
}
|
|
1554
|
+
function buildDocsMarkdownRewrites(entry, docsPath) {
|
|
1555
|
+
const normalizedEntry = normalizeRouteSegment(entry);
|
|
1556
|
+
const publicBase = docsPath || "";
|
|
1557
|
+
const markdownAcceptHeader = {
|
|
1558
|
+
type: "header",
|
|
1559
|
+
key: "accept",
|
|
1560
|
+
value: MARKDOWN_ACCEPT_HEADER_VALUE
|
|
1561
|
+
};
|
|
1562
|
+
const markdownSignatureAgentHeader = {
|
|
1563
|
+
type: "header",
|
|
1564
|
+
key: "signature-agent",
|
|
1565
|
+
value: ".+"
|
|
1566
|
+
};
|
|
1567
|
+
const markdownAgentUserAgentHeader = {
|
|
1568
|
+
type: "header",
|
|
1569
|
+
key: "user-agent",
|
|
1570
|
+
value: DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN
|
|
1571
|
+
};
|
|
1572
|
+
const markdownBotLikeUserAgentHeader = {
|
|
1573
|
+
type: "header",
|
|
1574
|
+
key: "user-agent",
|
|
1575
|
+
value: DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN
|
|
1576
|
+
};
|
|
1577
|
+
const markdownTraditionalBotUserAgentHeader = {
|
|
1578
|
+
type: "header",
|
|
1579
|
+
key: "user-agent",
|
|
1580
|
+
value: DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN
|
|
1581
|
+
};
|
|
1582
|
+
const markdownSecFetchModeHeader = {
|
|
1583
|
+
type: "header",
|
|
1584
|
+
key: "sec-fetch-mode"
|
|
1585
|
+
};
|
|
1586
|
+
if (publicBase === "") {
|
|
1587
|
+
const rootPageSource = docsRootSource(normalizedEntry);
|
|
1588
|
+
return [
|
|
1589
|
+
{
|
|
1590
|
+
source: `/${normalizedEntry}.md`,
|
|
1591
|
+
destination: "/api/docs?format=markdown"
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
source: docsRootMarkdownSource(normalizedEntry),
|
|
1595
|
+
destination: "/api/docs?format=markdown&path=:slug"
|
|
1596
|
+
},
|
|
1597
|
+
{
|
|
1598
|
+
source: "/",
|
|
1599
|
+
has: [markdownAcceptHeader],
|
|
1600
|
+
destination: "/api/docs?format=markdown"
|
|
1601
|
+
},
|
|
1602
|
+
{
|
|
1603
|
+
source: rootPageSource,
|
|
1604
|
+
has: [markdownAcceptHeader],
|
|
1605
|
+
destination: "/api/docs?format=markdown&path=:slug"
|
|
1606
|
+
},
|
|
1607
|
+
{
|
|
1608
|
+
source: "/",
|
|
1609
|
+
has: [markdownSignatureAgentHeader],
|
|
1610
|
+
destination: "/api/docs?format=markdown"
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
source: rootPageSource,
|
|
1614
|
+
has: [markdownSignatureAgentHeader],
|
|
1615
|
+
destination: "/api/docs?format=markdown&path=:slug"
|
|
1616
|
+
},
|
|
1617
|
+
{
|
|
1618
|
+
source: "/",
|
|
1619
|
+
has: [markdownAgentUserAgentHeader],
|
|
1620
|
+
destination: "/api/docs?format=markdown"
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
source: rootPageSource,
|
|
1624
|
+
has: [markdownAgentUserAgentHeader],
|
|
1625
|
+
destination: "/api/docs?format=markdown&path=:slug"
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
source: "/",
|
|
1629
|
+
has: [markdownBotLikeUserAgentHeader],
|
|
1630
|
+
missing: [markdownTraditionalBotUserAgentHeader, markdownSecFetchModeHeader],
|
|
1631
|
+
destination: "/api/docs?format=markdown"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
source: rootPageSource,
|
|
1635
|
+
has: [markdownBotLikeUserAgentHeader],
|
|
1636
|
+
missing: [markdownTraditionalBotUserAgentHeader, markdownSecFetchModeHeader],
|
|
1637
|
+
destination: "/api/docs?format=markdown&path=:slug"
|
|
1638
|
+
}
|
|
1639
|
+
];
|
|
1640
|
+
}
|
|
1641
|
+
return [
|
|
1642
|
+
{
|
|
1643
|
+
source: `${publicBase}.md`,
|
|
1644
|
+
destination: "/api/docs?format=markdown"
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
source: `${publicBase}/:slug*.md`,
|
|
1648
|
+
destination: "/api/docs?format=markdown&path=:slug*"
|
|
1649
|
+
},
|
|
1650
|
+
{
|
|
1651
|
+
source: publicBase,
|
|
1652
|
+
has: [markdownAcceptHeader],
|
|
1653
|
+
destination: "/api/docs?format=markdown"
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
source: `${publicBase}/:slug*`,
|
|
1657
|
+
has: [markdownAcceptHeader],
|
|
1658
|
+
destination: "/api/docs?format=markdown&path=:slug*"
|
|
1659
|
+
},
|
|
1660
|
+
{
|
|
1661
|
+
source: publicBase,
|
|
1662
|
+
has: [markdownSignatureAgentHeader],
|
|
1663
|
+
destination: "/api/docs?format=markdown"
|
|
1664
|
+
},
|
|
1665
|
+
{
|
|
1666
|
+
source: `${publicBase}/:slug*`,
|
|
1667
|
+
has: [markdownSignatureAgentHeader],
|
|
1668
|
+
destination: "/api/docs?format=markdown&path=:slug*"
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
source: publicBase,
|
|
1672
|
+
has: [markdownAgentUserAgentHeader],
|
|
1673
|
+
destination: "/api/docs?format=markdown"
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
source: `${publicBase}/:slug*`,
|
|
1677
|
+
has: [markdownAgentUserAgentHeader],
|
|
1678
|
+
destination: "/api/docs?format=markdown&path=:slug*"
|
|
1679
|
+
},
|
|
1680
|
+
{
|
|
1681
|
+
source: publicBase,
|
|
1682
|
+
has: [markdownBotLikeUserAgentHeader],
|
|
1683
|
+
missing: [markdownTraditionalBotUserAgentHeader, markdownSecFetchModeHeader],
|
|
1684
|
+
destination: "/api/docs?format=markdown"
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
source: `${publicBase}/:slug*`,
|
|
1688
|
+
has: [markdownBotLikeUserAgentHeader],
|
|
1689
|
+
missing: [markdownTraditionalBotUserAgentHeader, markdownSecFetchModeHeader],
|
|
1690
|
+
destination: "/api/docs?format=markdown&path=:slug*"
|
|
1691
|
+
}
|
|
1692
|
+
];
|
|
1693
|
+
}
|
|
1694
|
+
function buildApiReferenceMarkdownRewrites(apiReference) {
|
|
1695
|
+
if (!apiReference.enabled) return [];
|
|
1696
|
+
const basePath = `/${apiReference.path}`;
|
|
1697
|
+
const markdownAcceptHeader = {
|
|
1698
|
+
type: "header",
|
|
1699
|
+
key: "accept",
|
|
1700
|
+
value: MARKDOWN_ACCEPT_HEADER_VALUE
|
|
1701
|
+
};
|
|
1702
|
+
const markdownSignatureAgentHeader = {
|
|
1703
|
+
type: "header",
|
|
1704
|
+
key: "signature-agent",
|
|
1705
|
+
value: ".+"
|
|
1706
|
+
};
|
|
1707
|
+
const markdownAgentUserAgentHeader = {
|
|
1708
|
+
type: "header",
|
|
1709
|
+
key: "user-agent",
|
|
1710
|
+
value: DOCS_AI_AGENT_USER_AGENT_HEADER_PATTERN
|
|
1711
|
+
};
|
|
1712
|
+
const markdownBotLikeUserAgentHeader = {
|
|
1713
|
+
type: "header",
|
|
1714
|
+
key: "user-agent",
|
|
1715
|
+
value: DOCS_BOT_LIKE_USER_AGENT_HEADER_PATTERN
|
|
1716
|
+
};
|
|
1717
|
+
const markdownTraditionalBotUserAgentHeader = {
|
|
1718
|
+
type: "header",
|
|
1719
|
+
key: "user-agent",
|
|
1720
|
+
value: DOCS_TRADITIONAL_BOT_USER_AGENT_HEADER_PATTERN
|
|
1721
|
+
};
|
|
1722
|
+
const markdownSecFetchModeHeader = {
|
|
1723
|
+
type: "header",
|
|
1724
|
+
key: "sec-fetch-mode"
|
|
1725
|
+
};
|
|
1726
|
+
return [{
|
|
1727
|
+
source: `${basePath}/operations/:operation`,
|
|
1728
|
+
path: `${apiReference.path}/operations/:operation`
|
|
1729
|
+
}, {
|
|
1730
|
+
source: `${basePath}/:version/operations/:operation`,
|
|
1731
|
+
path: `${apiReference.path}/:version/operations/:operation`
|
|
1732
|
+
}].flatMap((route) => [
|
|
1733
|
+
{
|
|
1734
|
+
source: `${route.source}.md`,
|
|
1735
|
+
destination: `/api/docs?format=markdown&path=${route.path}`
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
source: route.source,
|
|
1739
|
+
has: [markdownAcceptHeader],
|
|
1740
|
+
destination: `/api/docs?format=markdown&path=${route.path}`
|
|
1741
|
+
},
|
|
1742
|
+
{
|
|
1743
|
+
source: route.source,
|
|
1744
|
+
has: [markdownSignatureAgentHeader],
|
|
1745
|
+
destination: `/api/docs?format=markdown&path=${route.path}`
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
source: route.source,
|
|
1749
|
+
has: [markdownAgentUserAgentHeader],
|
|
1750
|
+
destination: `/api/docs?format=markdown&path=${route.path}`
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
source: route.source,
|
|
1754
|
+
has: [markdownBotLikeUserAgentHeader],
|
|
1755
|
+
missing: [markdownTraditionalBotUserAgentHeader, markdownSecFetchModeHeader],
|
|
1756
|
+
destination: `/api/docs?format=markdown&path=${route.path}`
|
|
1757
|
+
}
|
|
1758
|
+
]);
|
|
1759
|
+
}
|
|
1760
|
+
function buildAgentSpecRewrites() {
|
|
1761
|
+
return [
|
|
1762
|
+
{
|
|
1763
|
+
source: DEFAULT_AGENT_SPEC_ROUTE,
|
|
1764
|
+
destination: "/api/docs?agent=spec"
|
|
1765
|
+
},
|
|
1766
|
+
{
|
|
1767
|
+
source: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
|
|
1768
|
+
destination: "/api/docs?agent=spec"
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
source: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
|
|
1772
|
+
destination: "/api/docs?agent=spec"
|
|
1773
|
+
}
|
|
1774
|
+
];
|
|
1775
|
+
}
|
|
1776
|
+
function buildStandardsDiscoveryRewrites() {
|
|
1777
|
+
return [
|
|
1778
|
+
{
|
|
1779
|
+
source: DEFAULT_API_CATALOG_ROUTE,
|
|
1780
|
+
destination: "/api/docs?format=api-catalog"
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
source: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
|
|
1784
|
+
destination: "/api/docs?format=agent-skills"
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
source: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/:name/SKILL.md`,
|
|
1788
|
+
destination: "/api/docs?format=agent-skill-file&name=:name&path=SKILL.md"
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
source: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/:name/skill.md`,
|
|
1792
|
+
destination: "/api/docs?format=agent-skill-file&name=:name&path=SKILL.md"
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
source: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/:name.tar.gz`,
|
|
1796
|
+
destination: `/api/docs?format=${DEFAULT_AGENT_SKILL_ARCHIVE_FORMAT}&name=:name`
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
source: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/:name/:path*`,
|
|
1800
|
+
destination: "/api/docs?format=agent-skill-file&name=:name&path=:path*"
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
source: DEFAULT_LEGACY_SKILLS_INDEX_ROUTE,
|
|
1804
|
+
destination: "/api/docs?format=legacy-skills"
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
source: `${DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX}/:name/skill.md`,
|
|
1808
|
+
destination: "/api/docs?format=agent-skill-file&name=:name&path=SKILL.md"
|
|
1809
|
+
},
|
|
1810
|
+
{
|
|
1811
|
+
source: `${DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX}/:name/:path*`,
|
|
1812
|
+
destination: "/api/docs?format=agent-skill-file&name=:name&path=:path*"
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
source: DEFAULT_A2A_AGENT_CARD_ROUTE,
|
|
1816
|
+
destination: "/api/docs?format=agent-card"
|
|
1817
|
+
}
|
|
1818
|
+
];
|
|
1819
|
+
}
|
|
1820
|
+
function buildLlmsTxtRewrites(entry, docsPath) {
|
|
1821
|
+
const internalBase = `/${normalizeRouteSegment(entry)}`;
|
|
1822
|
+
const publicBase = docsPath;
|
|
1823
|
+
const baseRoutes = Array.from(new Set([internalBase, publicBase].filter(Boolean)));
|
|
1824
|
+
return [
|
|
1825
|
+
{
|
|
1826
|
+
source: DEFAULT_LLMS_TXT_ROUTE,
|
|
1827
|
+
destination: "/api/docs?format=llms"
|
|
1828
|
+
},
|
|
1829
|
+
{
|
|
1830
|
+
source: DEFAULT_LLMS_FULL_TXT_ROUTE,
|
|
1831
|
+
destination: "/api/docs?format=llms-full"
|
|
1832
|
+
},
|
|
1833
|
+
{
|
|
1834
|
+
source: DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
|
|
1835
|
+
destination: "/api/docs?format=llms"
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
source: DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE,
|
|
1839
|
+
destination: "/api/docs?format=llms-full"
|
|
1840
|
+
},
|
|
1841
|
+
...baseRoutes.flatMap((baseRoute) => [
|
|
1842
|
+
{
|
|
1843
|
+
source: `${baseRoute}/llms.txt`,
|
|
1844
|
+
destination: "/api/docs?format=llms"
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
source: `${baseRoute}/llms-full.txt`,
|
|
1848
|
+
destination: "/api/docs?format=llms-full"
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
source: `${baseRoute}/:section*/llms.txt`,
|
|
1852
|
+
destination: `/api/docs?format=llms§ion=${baseRoute}/:section*/llms.txt`
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
source: `${baseRoute}/:section*/llms-full.txt`,
|
|
1856
|
+
destination: `/api/docs?format=llms-full§ion=${baseRoute}/:section*/llms-full.txt`
|
|
1857
|
+
}
|
|
1858
|
+
])
|
|
1859
|
+
];
|
|
1860
|
+
}
|
|
1861
|
+
function buildSkillMdRewrites() {
|
|
1862
|
+
return [{
|
|
1863
|
+
source: DEFAULT_SKILL_MD_ROUTE,
|
|
1864
|
+
destination: "/api/docs?format=skill"
|
|
1865
|
+
}, {
|
|
1866
|
+
source: DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE,
|
|
1867
|
+
destination: "/api/docs?format=skill"
|
|
1868
|
+
}];
|
|
1869
|
+
}
|
|
1870
|
+
function buildAgentsMdRewrites() {
|
|
1871
|
+
return [
|
|
1872
|
+
{
|
|
1873
|
+
source: DEFAULT_AGENTS_MD_ROUTE,
|
|
1874
|
+
destination: "/api/docs?format=agents"
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
source: DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE,
|
|
1878
|
+
destination: "/api/docs?format=agents"
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
source: DEFAULT_AGENT_MD_ROUTE,
|
|
1882
|
+
destination: "/api/docs?format=agents"
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
source: DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE,
|
|
1886
|
+
destination: "/api/docs?format=agents"
|
|
1887
|
+
}
|
|
1888
|
+
];
|
|
1889
|
+
}
|
|
1890
|
+
function buildSitemapRewrites(config) {
|
|
1891
|
+
if (!config.enabled) return [];
|
|
1892
|
+
const prefix = config.routePrefix;
|
|
1893
|
+
return [
|
|
1894
|
+
{
|
|
1895
|
+
source: joinPublicRoute(prefix, DEFAULT_SITEMAP_XML_ROUTE),
|
|
1896
|
+
destination: "/api/docs?format=sitemap-xml"
|
|
1897
|
+
},
|
|
1898
|
+
{
|
|
1899
|
+
source: joinPublicRoute(prefix, DEFAULT_SITEMAP_MD_ROUTE),
|
|
1900
|
+
destination: "/api/docs?format=sitemap-md"
|
|
1901
|
+
},
|
|
1902
|
+
...prefix ? [] : [{
|
|
1903
|
+
source: DEFAULT_SITEMAP_MD_DOCS_ROUTE,
|
|
1904
|
+
destination: "/api/docs?format=sitemap-md"
|
|
1905
|
+
}],
|
|
1906
|
+
{
|
|
1907
|
+
source: joinPublicRoute(prefix, DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE),
|
|
1908
|
+
destination: "/api/docs?format=sitemap-md"
|
|
1909
|
+
}
|
|
1910
|
+
];
|
|
1911
|
+
}
|
|
1912
|
+
function buildRobotsRewrites(config) {
|
|
1913
|
+
if (!config.enabled || config.hasStaticFile) return [];
|
|
1914
|
+
return [{
|
|
1915
|
+
source: DEFAULT_ROBOTS_TXT_ROUTE,
|
|
1916
|
+
destination: "/api/docs?format=robots"
|
|
1917
|
+
}];
|
|
1918
|
+
}
|
|
1919
|
+
function buildMcpRewrites(config) {
|
|
1920
|
+
if (!config.enabled) return [];
|
|
1921
|
+
const endpointRewrites = [DEFAULT_MCP_PUBLIC_ROUTE, DEFAULT_MCP_WELL_KNOWN_ROUTE].filter((source) => source !== config.route).map((source) => ({
|
|
1922
|
+
source,
|
|
1923
|
+
destination: config.route
|
|
1924
|
+
}));
|
|
1925
|
+
const metadataRewrites = config.protectedResource ? Array.from(new Set([
|
|
1926
|
+
config.route,
|
|
1927
|
+
DEFAULT_MCP_PUBLIC_ROUTE,
|
|
1928
|
+
DEFAULT_MCP_WELL_KNOWN_ROUTE
|
|
1929
|
+
])).map(buildMcpProtectedResourceMetadataRoute).map((source) => ({
|
|
1930
|
+
source,
|
|
1931
|
+
destination: config.route
|
|
1932
|
+
})) : [];
|
|
1933
|
+
return [...endpointRewrites, ...metadataRewrites];
|
|
1934
|
+
}
|
|
1935
|
+
function buildAgentFeedbackRewrites(config) {
|
|
1936
|
+
if (!config.enabled) return [];
|
|
1937
|
+
return [{
|
|
1938
|
+
source: config.route,
|
|
1939
|
+
destination: "/api/docs?feedback=agent"
|
|
1940
|
+
}, {
|
|
1941
|
+
source: config.schemaRoute,
|
|
1942
|
+
destination: "/api/docs?feedback=agent&schema=1"
|
|
1943
|
+
}];
|
|
1944
|
+
}
|
|
1945
|
+
function dedupeRewrites(rewrites) {
|
|
1946
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1947
|
+
const result = [];
|
|
1948
|
+
for (const rewrite of rewrites) {
|
|
1949
|
+
const key = JSON.stringify({
|
|
1950
|
+
source: rewrite.source,
|
|
1951
|
+
destination: rewrite.destination,
|
|
1952
|
+
has: rewrite.has ?? [],
|
|
1953
|
+
missing: rewrite.missing ?? []
|
|
1954
|
+
});
|
|
1955
|
+
if (seen.has(key)) continue;
|
|
1956
|
+
seen.add(key);
|
|
1957
|
+
result.push(rewrite);
|
|
1958
|
+
}
|
|
1959
|
+
return result;
|
|
1960
|
+
}
|
|
1961
|
+
function dedupeRedirects(redirects) {
|
|
1962
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1963
|
+
const result = [];
|
|
1964
|
+
for (const redirect of redirects) {
|
|
1965
|
+
const key = redirect.source;
|
|
1966
|
+
if (seen.has(key)) continue;
|
|
1967
|
+
seen.add(key);
|
|
1968
|
+
result.push(redirect);
|
|
1969
|
+
}
|
|
1970
|
+
return result;
|
|
1971
|
+
}
|
|
1972
|
+
function resolveDocsPageSourceFile(dir) {
|
|
1973
|
+
return ["page.mdx", "page.md"].map((fileName) => join(dir, fileName)).find((candidate) => existsSync(candidate));
|
|
1974
|
+
}
|
|
1975
|
+
function readDocsPageFrontmatter(filePath) {
|
|
1976
|
+
try {
|
|
1977
|
+
return matter(readFileSync(filePath, "utf-8")).data;
|
|
1978
|
+
} catch {
|
|
1979
|
+
return {};
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
function resolveDocsPageFolderIndexBehavior(data) {
|
|
1983
|
+
const sidebar = data.sidebar;
|
|
1984
|
+
if (!sidebar || typeof sidebar !== "object") return void 0;
|
|
1985
|
+
const value = sidebar.folderIndexBehavior;
|
|
1986
|
+
return value === "link" || value === "toggle" || value === "hidden" ? value : void 0;
|
|
1987
|
+
}
|
|
1988
|
+
function publicDocsRoute(docsPath, slugParts = []) {
|
|
1989
|
+
const slug = slugParts.join("/");
|
|
1990
|
+
if (!slug) return docsPath || "/";
|
|
1991
|
+
return docsPath ? `${docsPath}/${slug}` : `/${slug}`;
|
|
1992
|
+
}
|
|
1993
|
+
function buildHiddenFolderRedirects(docsDir, docsPath) {
|
|
1994
|
+
const redirects = [];
|
|
1995
|
+
const frontmatterByDir = /* @__PURE__ */ new Map();
|
|
1996
|
+
const childrenByDir = /* @__PURE__ */ new Map();
|
|
1997
|
+
const firstVisibleByDir = /* @__PURE__ */ new Map();
|
|
1998
|
+
function frontmatter(dir) {
|
|
1999
|
+
if (!frontmatterByDir.has(dir)) {
|
|
2000
|
+
const source = resolveDocsPageSourceFile(dir);
|
|
2001
|
+
frontmatterByDir.set(dir, source ? readDocsPageFrontmatter(source) : void 0);
|
|
2002
|
+
}
|
|
2003
|
+
return frontmatterByDir.get(dir);
|
|
2004
|
+
}
|
|
2005
|
+
function childDirectories(dir) {
|
|
2006
|
+
const cached = childrenByDir.get(dir);
|
|
2007
|
+
if (cached) return cached;
|
|
2008
|
+
const children = [];
|
|
2009
|
+
try {
|
|
2010
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
2011
|
+
const fullPath = join(dir, entry.name);
|
|
2012
|
+
try {
|
|
2013
|
+
if (entry.isSymbolicLink() ? !statSync(fullPath).isDirectory() : !entry.isDirectory()) continue;
|
|
2014
|
+
} catch {
|
|
2015
|
+
continue;
|
|
2016
|
+
}
|
|
2017
|
+
const order = frontmatter(fullPath)?.order;
|
|
2018
|
+
children.push({
|
|
2019
|
+
name: entry.name,
|
|
2020
|
+
order: typeof order === "number" ? order : Number.POSITIVE_INFINITY
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
} catch {}
|
|
2024
|
+
const names = children.sort((left, right) => {
|
|
2025
|
+
if (left.order !== right.order) return left.order - right.order;
|
|
2026
|
+
return left.name.localeCompare(right.name);
|
|
2027
|
+
}).map(({ name }) => name);
|
|
2028
|
+
childrenByDir.set(dir, names);
|
|
2029
|
+
return names;
|
|
2030
|
+
}
|
|
2031
|
+
function firstVisibleChild(dir, slugParts) {
|
|
2032
|
+
if (firstVisibleByDir.has(dir)) return firstVisibleByDir.get(dir);
|
|
2033
|
+
let destination;
|
|
2034
|
+
for (const name of childDirectories(dir)) {
|
|
2035
|
+
const childDir = join(dir, name);
|
|
2036
|
+
const childSlugParts = [...slugParts, name];
|
|
2037
|
+
const data = frontmatter(childDir);
|
|
2038
|
+
if (!data || data.hidden === true || resolveDocsPageFolderIndexBehavior(data) === "hidden") {
|
|
2039
|
+
destination = firstVisibleChild(childDir, childSlugParts);
|
|
2040
|
+
if (!destination) continue;
|
|
2041
|
+
} else destination = childSlugParts;
|
|
2042
|
+
break;
|
|
2043
|
+
}
|
|
2044
|
+
firstVisibleByDir.set(dir, destination);
|
|
2045
|
+
return destination;
|
|
2046
|
+
}
|
|
2047
|
+
function scan(dir, slugParts) {
|
|
2048
|
+
const data = frontmatter(dir);
|
|
2049
|
+
if (data && resolveDocsPageFolderIndexBehavior(data) === "hidden") {
|
|
2050
|
+
const destinationSlug = firstVisibleChild(dir, slugParts);
|
|
2051
|
+
if (destinationSlug && destinationSlug.join("/") !== slugParts.join("/")) redirects.push({
|
|
2052
|
+
source: publicDocsRoute(docsPath, slugParts),
|
|
2053
|
+
destination: publicDocsRoute(docsPath, destinationSlug),
|
|
2054
|
+
permanent: false
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
for (const name of childDirectories(dir)) scan(join(dir, name), [...slugParts, name]);
|
|
2058
|
+
}
|
|
2059
|
+
scan(docsDir, []);
|
|
2060
|
+
return dedupeRedirects(redirects);
|
|
2061
|
+
}
|
|
2062
|
+
function mergeDocsMarkdownRewrites(entry, docsPath, apiReference, mcp, sitemap, agentFeedback, robots, result) {
|
|
2063
|
+
const autoBeforeFilesRewrites = [
|
|
2064
|
+
...buildAgentSpecRewrites(),
|
|
2065
|
+
...buildStandardsDiscoveryRewrites(),
|
|
2066
|
+
...buildMcpRewrites(mcp),
|
|
2067
|
+
...buildAgentsMdRewrites(),
|
|
2068
|
+
...buildSkillMdRewrites(),
|
|
2069
|
+
...buildSitemapRewrites(sitemap),
|
|
2070
|
+
...buildRobotsRewrites(robots),
|
|
2071
|
+
...buildDocsMarkdownRewrites(entry, docsPath),
|
|
2072
|
+
...buildApiReferenceMarkdownRewrites(apiReference),
|
|
2073
|
+
...buildDocsPathRewrites(entry, docsPath),
|
|
2074
|
+
...buildAgentFeedbackRewrites(agentFeedback)
|
|
2075
|
+
];
|
|
2076
|
+
const autoAfterFilesRewrites = buildLlmsTxtRewrites(entry, docsPath);
|
|
2077
|
+
if (!result) return {
|
|
2078
|
+
beforeFiles: dedupeRewrites(autoBeforeFilesRewrites),
|
|
2079
|
+
afterFiles: dedupeRewrites(autoAfterFilesRewrites)
|
|
2080
|
+
};
|
|
2081
|
+
if (Array.isArray(result)) return {
|
|
2082
|
+
beforeFiles: dedupeRewrites(autoBeforeFilesRewrites),
|
|
2083
|
+
afterFiles: dedupeRewrites([...result, ...autoAfterFilesRewrites])
|
|
2084
|
+
};
|
|
2085
|
+
return {
|
|
2086
|
+
beforeFiles: dedupeRewrites([...result.beforeFiles ?? [], ...autoBeforeFilesRewrites]),
|
|
2087
|
+
afterFiles: dedupeRewrites([...result.afterFiles ?? [], ...autoAfterFilesRewrites]),
|
|
2088
|
+
fallback: result.fallback ?? []
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
function mergeDocsRedirects(autoRedirects, redirects) {
|
|
2092
|
+
return dedupeRedirects([...redirects ?? [], ...autoRedirects]);
|
|
2093
|
+
}
|
|
2094
|
+
function withDocs(nextConfig = {}, docsConfig, options = {}) {
|
|
2095
|
+
const mdx = resolveMdxExtensions(options.mdx);
|
|
2096
|
+
const root = process.cwd();
|
|
2097
|
+
const readSource = createConfigSourceReader();
|
|
2098
|
+
const workspaceRoot = findDocsWorkspaceRoot(root);
|
|
2099
|
+
const docsConfigPath = readDocsConfigPath(root);
|
|
2100
|
+
const docsConfigAbsolutePath = join(root, docsConfigPath);
|
|
2101
|
+
const codeBlockThemes = resolveCodeBlockThemes({
|
|
2102
|
+
root,
|
|
2103
|
+
configPath: docsConfigPath,
|
|
2104
|
+
readSource,
|
|
2105
|
+
theme: docsConfig?.theme
|
|
2106
|
+
});
|
|
2107
|
+
const mcp = docsConfig ? resolveMcpConfig(docsConfig.mcp) : readMcpConfig(root, readSource);
|
|
2108
|
+
const nextBasePath = normalizeRoutePrefix(nextConfig.basePath);
|
|
2109
|
+
if (mcp.enabled && mcp.protectedResource && nextBasePath) throw new Error(`@farming-labs/next: mcp.security.protectedResource cannot be combined with Next.js basePath ${JSON.stringify(nextBasePath)} because RFC 9728 metadata must be hosted at origin-root well-known URLs. Host the protected docs app at the origin root or publish the metadata and MCP proxy at the edge.`);
|
|
2110
|
+
const agentSkillsBundlePath = writeAgentSkillsBundle(root, docsConfig === void 0 || !Object.hasOwn(docsConfig, "agent") ? readAgentSkillPaths(root, docsConfigPath, readSource) : docsConfig.agent?.skills);
|
|
2111
|
+
const agentFeedback = readAgentFeedbackConfig(root, readSource);
|
|
2112
|
+
const docsConfigRelativeAlias = docsConfigPath.startsWith("./") || docsConfigPath.startsWith("../") ? docsConfigPath : `./${docsConfigPath}`;
|
|
2113
|
+
withReadOnlyFsGuard(".github/workflows/docs-review.yml", () => ensureDocsReviewWorkflow({
|
|
2114
|
+
rootDir: root,
|
|
2115
|
+
configPath: docsConfigPath,
|
|
2116
|
+
configContent: existsSync(docsConfigAbsolutePath) ? readSource(docsConfigAbsolutePath) : void 0,
|
|
2117
|
+
log: process.env.NODE_ENV === "test" ? void 0 : (message) => console.log(message)
|
|
2118
|
+
}));
|
|
2119
|
+
if (!hasFile(root, "mdx-components")) writeGeneratedFile(join(root, "mdx-components.tsx"), MDX_COMPONENTS_TEMPLATE);
|
|
2120
|
+
const entry = readDocsEntry(root, readSource);
|
|
2121
|
+
const docsPath = normalizeDocsPath(readDocsPath(root, readSource), entry);
|
|
2122
|
+
const configuredContentDir = readDocsContentDir(root, readSource);
|
|
2123
|
+
const appDir = getNextAppDir(root);
|
|
2124
|
+
const docsContentDir = configuredContentDir ?? join(appDir, entry);
|
|
2125
|
+
const layoutDir = join(root, appDir, entry);
|
|
2126
|
+
if (!existsSync(layoutDir)) makeGeneratedDir(layoutDir);
|
|
2127
|
+
const docsLayoutPath = join(layoutDir, "layout.tsx");
|
|
2128
|
+
if (!hasFile(layoutDir, "layout") || isManagedGeneratedFile(docsLayoutPath)) writeGeneratedFile(join(layoutDir, "layout.tsx"), DOCS_LAYOUT_TEMPLATE);
|
|
2129
|
+
const isStaticExport = nextConfig.output === "export";
|
|
2130
|
+
const docsApiRouteDir = join(root, appDir, "api", "docs");
|
|
2131
|
+
const existingDocsApiRoutePath = FILE_EXTS.map((ext) => join(docsApiRouteDir, `route.${ext}`)).find((filePath) => existsSync(filePath));
|
|
2132
|
+
const docsApiRoutePath = existingDocsApiRoutePath ?? join(docsApiRouteDir, "route.ts");
|
|
2133
|
+
if (!isStaticExport && (!existingDocsApiRoutePath || isManagedGeneratedFile(existingDocsApiRoutePath))) {
|
|
2134
|
+
makeGeneratedDir(docsApiRouteDir);
|
|
2135
|
+
writeGeneratedFile(docsApiRoutePath, DOCS_API_ROUTE_TEMPLATE);
|
|
2136
|
+
}
|
|
2137
|
+
const sitemap = readSitemapConfig(root, readSource);
|
|
2138
|
+
const robots = readRobotsConfig(root, readSource);
|
|
2139
|
+
const docsMcpRouteDir = join(root, appDir, "api", "docs", "mcp");
|
|
2140
|
+
if (mcp.enabled && mcp.route === DEFAULT_MCP_ROUTE && !isStaticExport && !hasFile(docsMcpRouteDir, "route")) {
|
|
2141
|
+
makeGeneratedDir(docsMcpRouteDir);
|
|
2142
|
+
writeGeneratedFile(join(docsMcpRouteDir, "route.ts"), DOCS_MCP_ROUTE_TEMPLATE);
|
|
2143
|
+
}
|
|
2144
|
+
const apiReference = readApiReferenceConfig(root, readSource);
|
|
2145
|
+
if (apiReference.enabled && !isStaticExport) {
|
|
2146
|
+
const apiReferenceBaseDir = join(root, appDir, ...apiReference.path.split("/"));
|
|
2147
|
+
const apiReferencePageDir = join(apiReferenceBaseDir, "[[...slug]]");
|
|
2148
|
+
const apiReferencePagePath = join(apiReferencePageDir, "page.tsx");
|
|
2149
|
+
const apiReferenceLayoutPath = join(apiReferenceBaseDir, "layout.tsx");
|
|
2150
|
+
const apiReferenceRouteDir = join(apiReferenceBaseDir, "[[...slug]]");
|
|
2151
|
+
const apiReferenceRoutePath = join(apiReferenceRouteDir, "route.ts");
|
|
2152
|
+
const legacyApiReferencePagePath = join(apiReferenceBaseDir, "page.tsx");
|
|
2153
|
+
if (apiReference.renderer === "fumadocs") {
|
|
2154
|
+
removeManagedFile(apiReferenceRoutePath);
|
|
2155
|
+
removeManagedFile(legacyApiReferencePagePath);
|
|
2156
|
+
if (!hasFile(apiReferenceBaseDir, "layout") || isManagedGeneratedFile(apiReferenceLayoutPath)) {
|
|
2157
|
+
makeGeneratedDir(apiReferenceBaseDir);
|
|
2158
|
+
writeGeneratedFile(apiReferenceLayoutPath, API_REFERENCE_LAYOUT_TEMPLATE);
|
|
2159
|
+
}
|
|
2160
|
+
if (!hasFile(apiReferencePageDir, "page") || isManagedGeneratedFile(apiReferencePagePath)) {
|
|
2161
|
+
makeGeneratedDir(apiReferencePageDir);
|
|
2162
|
+
writeGeneratedFile(apiReferencePagePath, API_REFERENCE_PAGE_TEMPLATE);
|
|
2163
|
+
}
|
|
2164
|
+
} else {
|
|
2165
|
+
removeManagedFile(apiReferenceLayoutPath);
|
|
2166
|
+
removeManagedFile(apiReferencePagePath);
|
|
2167
|
+
if (!hasFile(apiReferenceRouteDir, "route") || isManagedGeneratedFile(apiReferenceRoutePath)) {
|
|
2168
|
+
makeGeneratedDir(apiReferenceRouteDir);
|
|
2169
|
+
writeGeneratedFile(apiReferenceRoutePath, API_REFERENCE_ROUTE_TEMPLATE);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
const changelog = readChangelogConfig(root, readSource);
|
|
2174
|
+
if (changelog.enabled) {
|
|
2175
|
+
const changelogBaseDir = join(root, appDir, entry, ...changelog.path.split("/"));
|
|
2176
|
+
const changelogEntryDir = join(changelogBaseDir, "[slug]");
|
|
2177
|
+
const changelogIndexPath = join(changelogBaseDir, "page.tsx");
|
|
2178
|
+
const changelogEntryPath = join(changelogEntryDir, "page.tsx");
|
|
2179
|
+
const changelogSourceDir = resolveChangelogContentDir(root, appDir, entry, changelog.contentDir, readSource);
|
|
2180
|
+
const changelogUsesSourcePagesAsDetails = !isAbsolute(changelog.contentDir) && changelog.contentDir === changelog.path;
|
|
2181
|
+
const changelogEntries = findChangelogSourceEntries(changelogSourceDir);
|
|
2182
|
+
const changelogSourceLayoutPath = resolveManagedChangelogSourceLayoutPath(root, appDir, entry, changelog.contentDir, readSource);
|
|
2183
|
+
const legacyChangelogBaseDirs = new Set([join(root, appDir, ...changelog.path.split("/")), ...isAbsolute(changelog.contentDir) ? [] : [join(root, appDir, ...changelog.contentDir.split("/"))]]);
|
|
2184
|
+
for (const legacyChangelogBaseDir of legacyChangelogBaseDirs) {
|
|
2185
|
+
if (legacyChangelogBaseDir === changelogBaseDir) continue;
|
|
2186
|
+
removeManagedFile(join(legacyChangelogBaseDir, "[slug]", "page.tsx"));
|
|
2187
|
+
removeManagedFile(join(legacyChangelogBaseDir, "page.tsx"));
|
|
2188
|
+
removeManagedFile(join(legacyChangelogBaseDir, "__changelog.generated.tsx"));
|
|
2189
|
+
}
|
|
2190
|
+
makeGeneratedDir(changelogBaseDir);
|
|
2191
|
+
removeManagedFile(join(changelogBaseDir, "__changelog.generated.tsx"));
|
|
2192
|
+
if (!hasFile(changelogBaseDir, "page") || isManagedGeneratedFile(changelogIndexPath)) writeGeneratedFile(changelogIndexPath, buildChangelogIndexPageSource(root, changelogIndexPath, entry, changelog.path, changelogEntries));
|
|
2193
|
+
if (changelogUsesSourcePagesAsDetails) {
|
|
2194
|
+
removeManagedFile(changelogEntryPath);
|
|
2195
|
+
if (changelogSourceLayoutPath) removeManagedFile(changelogSourceLayoutPath);
|
|
2196
|
+
} else {
|
|
2197
|
+
if (!hasFile(changelogEntryDir, "page") || isManagedGeneratedFile(changelogEntryPath)) {
|
|
2198
|
+
makeGeneratedDir(changelogEntryDir);
|
|
2199
|
+
writeGeneratedFile(changelogEntryPath, buildChangelogEntryPageSource(root, changelogEntryPath, entry, changelog.path, changelogEntries));
|
|
2200
|
+
}
|
|
2201
|
+
if (changelogSourceLayoutPath) {
|
|
2202
|
+
const changelogSourceLayoutDir = dirname(changelogSourceLayoutPath);
|
|
2203
|
+
if (!hasFile(changelogSourceLayoutDir, "layout") || isManagedGeneratedFile(changelogSourceLayoutPath)) {
|
|
2204
|
+
makeGeneratedDir(changelogSourceLayoutDir);
|
|
2205
|
+
writeGeneratedFile(changelogSourceLayoutPath, CHANGELOG_SOURCE_LAYOUT_TEMPLATE);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
const ogEndpoint = readOgEndpoint(root, readSource);
|
|
2211
|
+
const remarkPlugins = ["remark-gfm", "remark-frontmatter"];
|
|
2212
|
+
if (ogEndpoint) remarkPlugins.push(["@farming-labs/next/mdx-plugins/remark-og", { endpoint: ogEndpoint }]);
|
|
2213
|
+
remarkPlugins.push(["@farming-labs/next/mdx-plugins/remark-markdown-alternate", {
|
|
2214
|
+
entry,
|
|
2215
|
+
appDir,
|
|
2216
|
+
contentDir: docsContentDir,
|
|
2217
|
+
docsPath,
|
|
2218
|
+
enabled: !isStaticExport
|
|
2219
|
+
}]);
|
|
2220
|
+
remarkPlugins.push(["remark-mdx-frontmatter", { name: "metadata" }], "@farming-labs/next/mdx-plugins/remark-code-group", "@farming-labs/next/mdx-plugins/remark-heading", ...mdx.remarkPlugins);
|
|
2221
|
+
const withMDX = createMDX({
|
|
2222
|
+
extension: /\.mdx?$/,
|
|
2223
|
+
options: {
|
|
2224
|
+
remarkPlugins,
|
|
2225
|
+
rehypePlugins: [
|
|
2226
|
+
"@farming-labs/next/mdx-plugins/rehype-toc",
|
|
2227
|
+
mdx.codeHighlighter ?? ["@farming-labs/next/mdx-plugins/rehype-code", { themes: codeBlockThemes }],
|
|
2228
|
+
...mdx.rehypePlugins
|
|
2229
|
+
]
|
|
2230
|
+
}
|
|
2231
|
+
});
|
|
2232
|
+
const defaultExts = [
|
|
2233
|
+
"js",
|
|
2234
|
+
"jsx",
|
|
2235
|
+
"md",
|
|
2236
|
+
"mdx",
|
|
2237
|
+
"ts",
|
|
2238
|
+
"tsx"
|
|
2239
|
+
];
|
|
2240
|
+
const userExts = nextConfig.pageExtensions;
|
|
2241
|
+
if (userExts) {
|
|
2242
|
+
for (const ext of ["md", "mdx"]) if (!userExts.includes(ext)) userExts.push(ext);
|
|
2243
|
+
} else nextConfig.pageExtensions = defaultExts;
|
|
2244
|
+
const publicDocsCloudAnalyticsEnv = createPublicDocsCloudAnalyticsEnv();
|
|
2245
|
+
if (Object.keys(publicDocsCloudAnalyticsEnv).length > 0) nextConfig.env = {
|
|
2246
|
+
...publicDocsCloudAnalyticsEnv,
|
|
2247
|
+
...nextConfig.env
|
|
2248
|
+
};
|
|
2249
|
+
const existingTurbopack = nextConfig.turbopack ?? {};
|
|
2250
|
+
const existingResolveAlias = existingTurbopack.resolveAlias ?? {};
|
|
2251
|
+
nextConfig.turbopack = {
|
|
2252
|
+
...existingTurbopack,
|
|
2253
|
+
...workspaceRoot && !existingTurbopack.root ? { root: workspaceRoot } : {},
|
|
2254
|
+
resolveAlias: {
|
|
2255
|
+
...workspaceRoot ? createDocsWorkspaceAliases(root, workspaceRoot) : {},
|
|
2256
|
+
...existingResolveAlias,
|
|
2257
|
+
[INTERNAL_DOCS_CONFIG_ALIAS]: docsConfigRelativeAlias,
|
|
2258
|
+
[AGENT_SKILLS_BUNDLE_ALIAS]: toTurbopackAliasPath(root, agentSkillsBundlePath),
|
|
2259
|
+
"fumadocs-openapi": toTurbopackAliasPath(root, FUMADOCS_OPENAPI_PACKAGE_ALIAS),
|
|
2260
|
+
"fumadocs-openapi/ui": toTurbopackAliasPath(root, FUMADOCS_OPENAPI_UI_ALIAS),
|
|
2261
|
+
"fumadocs-openapi/server": toTurbopackAliasPath(root, FUMADOCS_OPENAPI_SERVER_ALIAS),
|
|
2262
|
+
"fumadocs-core": toTurbopackAliasPath(root, FUMADOCS_CORE_PACKAGE_ALIAS),
|
|
2263
|
+
"fumadocs-core/framework": toTurbopackAliasPath(root, FUMADOCS_CORE_FRAMEWORK_ALIAS),
|
|
2264
|
+
"fumadocs-core/framework/next": toTurbopackAliasPath(root, FUMADOCS_CORE_FRAMEWORK_NEXT_ALIAS),
|
|
2265
|
+
"fumadocs-ui": toTurbopackAliasPath(root, FUMADOCS_UI_PACKAGE_ALIAS),
|
|
2266
|
+
"fumadocs-ui/layouts/notebook": toTurbopackAliasPath(root, FUMADOCS_UI_NOTEBOOK_ALIAS),
|
|
2267
|
+
"fumadocs-ui/layouts/notebook/page": toTurbopackAliasPath(root, FUMADOCS_UI_NOTEBOOK_PAGE_ALIAS),
|
|
2268
|
+
"fumadocs-ui/provider/next": toTurbopackAliasPath(root, FUMADOCS_UI_PROVIDER_NEXT_ALIAS)
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
const userWebpack = nextConfig.webpack;
|
|
2272
|
+
nextConfig.webpack = (config, options) => {
|
|
2273
|
+
const resolvedConfig = userWebpack ? userWebpack(config, options) : config;
|
|
2274
|
+
resolvedConfig.resolve ??= {};
|
|
2275
|
+
resolvedConfig.resolve.alias ??= {};
|
|
2276
|
+
if (workspaceRoot) Object.assign(resolvedConfig.resolve.alias, {
|
|
2277
|
+
"@farming-labs/docs$": join(workspaceRoot, "packages", "docs", "dist", "index.mjs"),
|
|
2278
|
+
"@farming-labs/docs/server": join(workspaceRoot, "packages", "docs", "dist", "server.mjs"),
|
|
2279
|
+
"@farming-labs/docs/cloud/server": join(workspaceRoot, "packages", "docs", "dist", "docs-cloud-server.mjs"),
|
|
2280
|
+
"@farming-labs/next$": join(workspaceRoot, "packages", "next", "dist", "index.mjs"),
|
|
2281
|
+
"@farming-labs/next/api": join(workspaceRoot, "packages", "next", "dist", "api.mjs"),
|
|
2282
|
+
"@farming-labs/next/changelog": join(workspaceRoot, "packages", "next", "dist", "changelog.mjs"),
|
|
2283
|
+
"@farming-labs/next/client-callbacks": join(workspaceRoot, "packages", "next", "dist", "client-callbacks.mjs"),
|
|
2284
|
+
"@farming-labs/next/layout": join(workspaceRoot, "packages", "next", "dist", "layout.mjs"),
|
|
2285
|
+
"@farming-labs/next/mdx-plugins/remark-markdown-alternate": join(workspaceRoot, "packages", "next", "dist", "mdx-plugins", "remark-markdown-alternate.mjs"),
|
|
2286
|
+
"@farming-labs/theme$": join(workspaceRoot, "packages", "fumadocs", "dist", "index.mjs"),
|
|
2287
|
+
"@farming-labs/theme/api": join(workspaceRoot, "packages", "fumadocs", "dist", "docs-api.mjs")
|
|
2288
|
+
});
|
|
2289
|
+
resolvedConfig.resolve.alias[INTERNAL_DOCS_CONFIG_ALIAS] = docsConfigAbsolutePath;
|
|
2290
|
+
resolvedConfig.resolve.alias[AGENT_SKILLS_BUNDLE_ALIAS] = agentSkillsBundlePath;
|
|
2291
|
+
resolvedConfig.resolve.plugins ??= [];
|
|
2292
|
+
resolvedConfig.resolve.plugins.push(new DocsPackageResolutionPlugin({
|
|
2293
|
+
"fumadocs-core": FUMADOCS_CORE_PACKAGE_ALIAS,
|
|
2294
|
+
"fumadocs-ui": FUMADOCS_UI_PACKAGE_ALIAS,
|
|
2295
|
+
"fumadocs-openapi": FUMADOCS_OPENAPI_PACKAGE_ALIAS
|
|
2296
|
+
}));
|
|
2297
|
+
return resolvedConfig;
|
|
2298
|
+
};
|
|
2299
|
+
const existingTracingIncludes = nextConfig.outputFileTracingIncludes ?? {};
|
|
2300
|
+
const existingTracingExcludes = nextConfig.outputFileTracingExcludes ?? {};
|
|
2301
|
+
const docsTraceGlob = docsContentDir.replace(/\\/g, "/").replace(/^\.?\//, "") + "/**/*";
|
|
2302
|
+
const sitemapManifestTraceFile = DEFAULT_SITEMAP_MANIFEST_PATH;
|
|
2303
|
+
const docsContentRoot = isAbsolute(docsContentDir) ? docsContentDir : join(root, docsContentDir);
|
|
2304
|
+
if (!isStaticExport) {
|
|
2305
|
+
const existingRewrites = nextConfig.rewrites;
|
|
2306
|
+
nextConfig.rewrites = async () => {
|
|
2307
|
+
return mergeDocsMarkdownRewrites(entry, docsPath, apiReference, mcp, sitemap, agentFeedback, robots, typeof existingRewrites === "function" ? await existingRewrites() : existingRewrites);
|
|
2308
|
+
};
|
|
2309
|
+
const autoRedirects = buildHiddenFolderRedirects(docsContentRoot, docsPath);
|
|
2310
|
+
if (autoRedirects.length > 0) {
|
|
2311
|
+
const existingRedirects = nextConfig.redirects;
|
|
2312
|
+
nextConfig.redirects = async () => {
|
|
2313
|
+
return mergeDocsRedirects(autoRedirects, typeof existingRedirects === "function" ? await existingRedirects() : existingRedirects);
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
nextConfig.outputFileTracingIncludes = {
|
|
2318
|
+
...existingTracingIncludes,
|
|
2319
|
+
"/api/docs": [...new Set([
|
|
2320
|
+
...existingTracingIncludes["/api/docs"] ?? [],
|
|
2321
|
+
docsTraceGlob,
|
|
2322
|
+
sitemapManifestTraceFile
|
|
2323
|
+
])],
|
|
2324
|
+
[DEFAULT_MCP_ROUTE]: [...new Set([...existingTracingIncludes[DEFAULT_MCP_ROUTE] ?? [], docsTraceGlob])]
|
|
2325
|
+
};
|
|
2326
|
+
nextConfig.outputFileTracingExcludes = {
|
|
2327
|
+
...existingTracingExcludes,
|
|
2328
|
+
"/api/docs": [...new Set([
|
|
2329
|
+
...existingTracingExcludes["/api/docs"] ?? [],
|
|
2330
|
+
"next.config.js",
|
|
2331
|
+
"next.config.mjs",
|
|
2332
|
+
"next.config.ts"
|
|
2333
|
+
])],
|
|
2334
|
+
[DEFAULT_MCP_ROUTE]: [...new Set([
|
|
2335
|
+
...existingTracingExcludes[DEFAULT_MCP_ROUTE] ?? [],
|
|
2336
|
+
"next.config.js",
|
|
2337
|
+
"next.config.mjs",
|
|
2338
|
+
"next.config.ts"
|
|
2339
|
+
])]
|
|
2340
|
+
};
|
|
2341
|
+
return withMDX(nextConfig);
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
//#endregion
|
|
2345
|
+
export { withDocs as t };
|