@farming-labs/docs 0.1.35 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.mjs +2 -2
- package/dist/index.d.mts +183 -3
- package/dist/index.mjs +260 -2
- package/dist/{init-DwUjo2Kv.mjs → init-i5ySLGa2.mjs} +278 -65
- package/dist/mcp.d.mts +2 -1
- package/dist/mcp.mjs +16 -3
- package/dist/{search-zClNrbqL.d.mts → search-BWqFW9rt.d.mts} +1 -1
- package/dist/{search-CLaNOUrd.mjs → search-CNesqs89.mjs} +1 -1
- package/dist/{search-BS6C5N1i.mjs → search-CfnJVeh-.mjs} +50 -1
- package/dist/server.d.mts +2 -2
- package/dist/server.mjs +1 -1
- package/dist/{types-CP8OcVgL.d.mts → types-CP2NmW5c.d.mts} +12 -5
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -69,13 +69,13 @@ async function main() {
|
|
|
69
69
|
searchApiKey: typeof flags["search-api-key"] === "string" ? flags["search-api-key"] : void 0
|
|
70
70
|
};
|
|
71
71
|
if (!parsedCommand.command || parsedCommand.command === "init") {
|
|
72
|
-
const { init } = await import("../init-
|
|
72
|
+
const { init } = await import("../init-i5ySLGa2.mjs");
|
|
73
73
|
await init(initOptions);
|
|
74
74
|
} else if (parsedCommand.command === "mcp") {
|
|
75
75
|
const { runMcp } = await import("../mcp-DLP94P1H.mjs");
|
|
76
76
|
await runMcp(mcpOptions);
|
|
77
77
|
} else if (parsedCommand.command === "search" && subcommand === "sync") {
|
|
78
|
-
const { syncSearch } = await import("../search-
|
|
78
|
+
const { syncSearch } = await import("../search-CNesqs89.mjs");
|
|
79
79
|
await syncSearch(searchSyncOptions);
|
|
80
80
|
} else if (parsedCommand.command === "search") {
|
|
81
81
|
console.error(pc.red(`Unknown search subcommand: ${subcommand ?? "(missing)"}`));
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import {
|
|
1
|
+
import { $ as SidebarFolderNode, A as DocsSearchQuery, B as McpDocsSearchConfig, C as DocsSearchAdapter, D as DocsSearchConfig, E as DocsSearchChunkingConfig, F as FeedbackConfig, G as OrderingItem, H as OpenDocsConfig, I as FontStyle, J as PageOpenGraph, K as PageActionsConfig, L as GithubConfig, M as DocsSearchResultType, N as DocsSearchSourcePage, O as DocsSearchDocument, P as DocsTheme, Q as SidebarConfig, R as LastUpdatedConfig, S as DocsRelatedItem, T as DocsSearchAdapterFactory, U as OpenDocsProvider, V as OGConfig, W as OpenGraphImage, X as ResolvedDocsRelatedLink, Y as PageTwitter, Z as SidebarComponentProps, _ as DocsI18nConfig, a as ApiReferenceRenderer, at as TypesenseDocsSearchConfig, b as DocsMetadata, c as ChangelogFrontmatter, d as CustomDocsSearchConfig, et as SidebarNode, f as DocsAgentFeedbackContext, g as DocsFeedbackValue, h as DocsFeedbackData, i as ApiReferenceConfig, it as ThemeToggleConfig, j as DocsSearchResult, k as DocsSearchEmbeddingsConfig, l as CodeBlockCopyData, m as DocsConfig, n as AgentFeedbackConfig, nt as SidebarTree, o as BreadcrumbConfig, ot as TypographyConfig, p as DocsAgentFeedbackData, q as PageFrontmatter, r as AlgoliaDocsSearchConfig, rt as SimpleDocsSearchConfig, s as ChangelogConfig, st as UIConfig, t as AIConfig, tt as SidebarPageNode, u as CopyMarkdownConfig, v as DocsMcpConfig, w as DocsSearchAdapterContext, x as DocsNav, y as DocsMcpToolsConfig, z as LlmsTxtConfig } from "./types-CP2NmW5c.mjs";
|
|
2
|
+
import { DocsMcpPage, DocsMcpResolvedConfig } from "./mcp.mjs";
|
|
3
|
+
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments } from "./search-BWqFW9rt.mjs";
|
|
3
4
|
|
|
4
5
|
//#region src/define-docs.d.ts
|
|
5
6
|
/**
|
|
@@ -115,4 +116,183 @@ declare function buildPageOpenGraph(page: Pick<PageFrontmatter, "title" | "descr
|
|
|
115
116
|
*/
|
|
116
117
|
declare function buildPageTwitter(page: Pick<PageFrontmatter, "title" | "description" | "ogImage" | "openGraph" | "twitter">, ogConfig?: OGConfig, baseUrl?: string): PageTwitter | undefined;
|
|
117
118
|
//#endregion
|
|
118
|
-
|
|
119
|
+
//#region src/related.d.ts
|
|
120
|
+
declare function normalizeDocsRelated(value: unknown): ResolvedDocsRelatedLink[];
|
|
121
|
+
declare function renderDocsRelatedMarkdownLines(related: ResolvedDocsRelatedLink[] | undefined): string[];
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/agent.d.ts
|
|
124
|
+
declare const DEFAULT_DOCS_API_ROUTE = "/api/docs";
|
|
125
|
+
declare const DEFAULT_AGENT_SPEC_ROUTE = "/api/docs/agent/spec";
|
|
126
|
+
declare const DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE = "/.well-known/agent";
|
|
127
|
+
declare const DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE = "/.well-known/agent.json";
|
|
128
|
+
declare const DEFAULT_MCP_ROUTE = "/api/docs/mcp";
|
|
129
|
+
declare const DEFAULT_MCP_PUBLIC_ROUTE = "/mcp";
|
|
130
|
+
declare const DEFAULT_MCP_WELL_KNOWN_ROUTE = "/.well-known/mcp";
|
|
131
|
+
declare const DEFAULT_LLMS_TXT_ROUTE = "/llms.txt";
|
|
132
|
+
declare const DEFAULT_LLMS_FULL_TXT_ROUTE = "/llms-full.txt";
|
|
133
|
+
declare const DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms.txt";
|
|
134
|
+
declare const DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms-full.txt";
|
|
135
|
+
declare const DEFAULT_AGENT_FEEDBACK_ROUTE = "/api/docs/agent/feedback";
|
|
136
|
+
interface DocsAgentFeedbackDiscoveryConfig {
|
|
137
|
+
enabled?: boolean;
|
|
138
|
+
route?: string;
|
|
139
|
+
schemaRoute?: string;
|
|
140
|
+
}
|
|
141
|
+
interface DocsLlmsDiscoveryConfig {
|
|
142
|
+
enabled?: boolean;
|
|
143
|
+
baseUrl?: string;
|
|
144
|
+
siteTitle?: string;
|
|
145
|
+
siteDescription?: string;
|
|
146
|
+
}
|
|
147
|
+
interface DocsAgentDiscoverySpecOptions {
|
|
148
|
+
origin: string;
|
|
149
|
+
entry?: string;
|
|
150
|
+
i18n?: ResolvedDocsI18n | null;
|
|
151
|
+
search?: boolean | DocsSearchConfig;
|
|
152
|
+
mcp: DocsMcpResolvedConfig;
|
|
153
|
+
feedback?: DocsAgentFeedbackDiscoveryConfig;
|
|
154
|
+
llms?: DocsLlmsDiscoveryConfig;
|
|
155
|
+
markdown?: {
|
|
156
|
+
acceptHeader?: boolean;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
interface DocsMarkdownPage {
|
|
160
|
+
slug?: string;
|
|
161
|
+
url: string;
|
|
162
|
+
title: string;
|
|
163
|
+
description?: string;
|
|
164
|
+
related?: ResolvedDocsRelatedLink[];
|
|
165
|
+
content: string;
|
|
166
|
+
rawContent?: string;
|
|
167
|
+
agentContent?: string;
|
|
168
|
+
agentRawContent?: string;
|
|
169
|
+
agentFallbackContent?: string;
|
|
170
|
+
agentFallbackRawContent?: string;
|
|
171
|
+
}
|
|
172
|
+
declare function normalizeDocsPathSegment(value: string): string;
|
|
173
|
+
declare function normalizeDocsUrlPath(value: string): string;
|
|
174
|
+
declare function isDocsAgentDiscoveryRequest(url: URL): boolean;
|
|
175
|
+
declare function isDocsMcpRequest(url: URL): boolean;
|
|
176
|
+
declare function isDocsPublicGetRequest(entry: string, url: URL, request: Request): boolean;
|
|
177
|
+
declare function resolveDocsLlmsTxtFormat(url: URL): "llms" | "llms-full" | null;
|
|
178
|
+
declare function resolveDocsMarkdownRequest(entry: string, url: URL, request: Request): {
|
|
179
|
+
requestedPath: string;
|
|
180
|
+
} | null;
|
|
181
|
+
declare function findDocsMarkdownPage<T extends DocsMarkdownPage>(entry: string, pages: T[], requestedPath: string): T | null;
|
|
182
|
+
declare function renderDocsMarkdownDocument(page: DocsMcpPage | DocsSearchSourcePage): string;
|
|
183
|
+
declare function renderDocsMarkdownDocument(page: DocsMarkdownPage): string;
|
|
184
|
+
declare function resolveDocsAgentMdxContent(content: string, audience: "human" | "agent"): string;
|
|
185
|
+
declare function buildDocsAgentDiscoverySpec({
|
|
186
|
+
origin,
|
|
187
|
+
entry,
|
|
188
|
+
i18n,
|
|
189
|
+
search,
|
|
190
|
+
mcp,
|
|
191
|
+
feedback,
|
|
192
|
+
llms,
|
|
193
|
+
markdown
|
|
194
|
+
}: DocsAgentDiscoverySpecOptions): {
|
|
195
|
+
version: string;
|
|
196
|
+
name: string;
|
|
197
|
+
baseUrl: string;
|
|
198
|
+
site: {
|
|
199
|
+
title: string;
|
|
200
|
+
description: string | undefined;
|
|
201
|
+
entry: string;
|
|
202
|
+
baseUrl: string;
|
|
203
|
+
};
|
|
204
|
+
locales: {
|
|
205
|
+
enabled: boolean;
|
|
206
|
+
available: string[];
|
|
207
|
+
default: string | null;
|
|
208
|
+
queryParam: string;
|
|
209
|
+
fallbackQueryParam: string;
|
|
210
|
+
};
|
|
211
|
+
capabilities: {
|
|
212
|
+
markdownRoutes: boolean;
|
|
213
|
+
agentMdOverrides: boolean;
|
|
214
|
+
agentBlocks: boolean;
|
|
215
|
+
llms: boolean;
|
|
216
|
+
skills: boolean;
|
|
217
|
+
mcp: boolean;
|
|
218
|
+
search: boolean;
|
|
219
|
+
agentFeedback: boolean;
|
|
220
|
+
locales: boolean;
|
|
221
|
+
};
|
|
222
|
+
api: {
|
|
223
|
+
docs: string;
|
|
224
|
+
agentSpec: string;
|
|
225
|
+
agentSpecDefault: string;
|
|
226
|
+
agentSpecFallback: string;
|
|
227
|
+
agentSpecWellKnown: string;
|
|
228
|
+
agentSpecWellKnownJson: string;
|
|
229
|
+
agentSpecQuery: string;
|
|
230
|
+
};
|
|
231
|
+
markdown: {
|
|
232
|
+
enabled: boolean;
|
|
233
|
+
acceptHeader: string | null;
|
|
234
|
+
pagePattern: string;
|
|
235
|
+
rootPage: string;
|
|
236
|
+
apiPattern: string;
|
|
237
|
+
resolutionOrder: string[];
|
|
238
|
+
};
|
|
239
|
+
llms: {
|
|
240
|
+
enabled: boolean;
|
|
241
|
+
defaultTxt: string;
|
|
242
|
+
defaultFull: string;
|
|
243
|
+
txt: string;
|
|
244
|
+
full: string;
|
|
245
|
+
publicTxt: string;
|
|
246
|
+
publicFull: string;
|
|
247
|
+
wellKnownTxt: string;
|
|
248
|
+
wellKnownFull: string;
|
|
249
|
+
};
|
|
250
|
+
search: {
|
|
251
|
+
enabled: boolean;
|
|
252
|
+
endpoint: string;
|
|
253
|
+
method: string;
|
|
254
|
+
queryParam: string;
|
|
255
|
+
localeParam: string;
|
|
256
|
+
};
|
|
257
|
+
skills: {
|
|
258
|
+
enabled: boolean;
|
|
259
|
+
registry: string;
|
|
260
|
+
install: string;
|
|
261
|
+
recommended: {
|
|
262
|
+
name: string;
|
|
263
|
+
description: string;
|
|
264
|
+
}[];
|
|
265
|
+
};
|
|
266
|
+
mcp: {
|
|
267
|
+
enabled: boolean;
|
|
268
|
+
endpoint: string;
|
|
269
|
+
defaultEndpoint: string;
|
|
270
|
+
publicEndpoint: string;
|
|
271
|
+
wellKnownEndpoint: string;
|
|
272
|
+
publicEndpoints: string[];
|
|
273
|
+
canonicalEndpoint: string;
|
|
274
|
+
name: string;
|
|
275
|
+
version: string;
|
|
276
|
+
tools: {
|
|
277
|
+
listPages: boolean;
|
|
278
|
+
readPage: boolean;
|
|
279
|
+
searchDocs: boolean;
|
|
280
|
+
getNavigation: boolean;
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
feedback: {
|
|
284
|
+
enabled: boolean;
|
|
285
|
+
schema: string;
|
|
286
|
+
submit: string;
|
|
287
|
+
schemaQuery: string;
|
|
288
|
+
submitQuery: string;
|
|
289
|
+
};
|
|
290
|
+
instructions: {
|
|
291
|
+
preferMarkdownRoutes: boolean;
|
|
292
|
+
useMcpWhenAvailable: boolean;
|
|
293
|
+
readFeedbackSchemaBeforeSubmitting: boolean;
|
|
294
|
+
doNotAssumeFeedbackPayloadShape: boolean;
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
//#endregion
|
|
298
|
+
export { type AIConfig, type AgentFeedbackConfig, type AlgoliaDocsSearchConfig, type ApiReferenceConfig, type ApiReferenceRenderer, type BreadcrumbConfig, type ChangelogConfig, type ChangelogEntrySummary, type ChangelogFrontmatter, type CodeBlockCopyData, type CopyMarkdownConfig, type CustomDocsSearchConfig, DEFAULT_AGENT_FEEDBACK_ROUTE, DEFAULT_AGENT_SPEC_ROUTE, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, DEFAULT_DOCS_API_ROUTE, DEFAULT_LLMS_FULL_TXT_ROUTE, DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE, DEFAULT_LLMS_TXT_ROUTE, DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE, DEFAULT_MCP_PUBLIC_ROUTE, DEFAULT_MCP_ROUTE, DEFAULT_MCP_WELL_KNOWN_ROUTE, type DocsAgentDiscoverySpecOptions, type DocsAgentFeedbackContext, type DocsAgentFeedbackData, type DocsAgentFeedbackDiscoveryConfig, type DocsConfig, type DocsFeedbackData, type DocsFeedbackValue, type DocsI18nConfig, type DocsLlmsDiscoveryConfig, type DocsMarkdownPage, type DocsMcpConfig, type DocsMcpToolsConfig, type DocsMetadata, type DocsNav, type DocsPathMatch, type DocsRelatedItem, type DocsSearchAdapter, type DocsSearchAdapterContext, type DocsSearchAdapterFactory, type DocsSearchChunkingConfig, type DocsSearchConfig, type DocsSearchDocument, type DocsSearchEmbeddingsConfig, type DocsSearchQuery, type DocsSearchResult, type DocsSearchResultType, type DocsSearchSourcePage, type DocsTheme, type FeedbackConfig, type FontStyle, type GithubConfig, type LastUpdatedConfig, type LlmsTxtConfig, type McpDocsSearchConfig, type OGConfig, type OpenDocsConfig, type OpenDocsProvider, type OpenGraphImage, type OrderingItem, type PageActionsConfig, type PageFrontmatter, type PageOpenGraph, type PageTwitter, type ResolvedChangelogConfig, type ResolvedDocsI18n, type ResolvedDocsRelatedLink, type SidebarComponentProps, type SidebarConfig, type SidebarFolderNode, type SidebarNode, type SidebarPageNode, type SidebarTree, type SimpleDocsSearchConfig, type ThemeToggleConfig, type TypesenseDocsSearchConfig, type TypographyConfig, type UIConfig, buildDocsAgentDiscoverySpec, buildDocsSearchDocuments, buildPageOpenGraph, buildPageTwitter, createAlgoliaSearchAdapter, createCustomSearchAdapter, createMcpSearchAdapter, createSimpleSearchAdapter, createTheme, createTypesenseSearchAdapter, deepMerge, defineDocs, extendTheme, findDocsMarkdownPage, isDocsAgentDiscoveryRequest, isDocsMcpRequest, isDocsPublicGetRequest, normalizeDocsPathSegment, normalizeDocsRelated, normalizeDocsUrlPath, performDocsSearch, renderDocsMarkdownDocument, renderDocsRelatedMarkdownLines, resolveChangelogConfig, resolveDocsAgentMdxContent, resolveDocsI18n, resolveDocsLlmsTxtFormat, resolveDocsLocale, resolveDocsMarkdownRequest, resolveDocsPath, resolveOGImage, resolveSearchRequestConfig, resolveTitle };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments } from "./search-
|
|
1
|
+
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, l as normalizeDocsRelated, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments, u as renderDocsRelatedMarkdownLines } from "./search-CfnJVeh-.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/define-docs.ts
|
|
4
4
|
/**
|
|
@@ -266,4 +266,262 @@ function buildPageTwitter(page, ogConfig, baseUrl) {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
//#endregion
|
|
269
|
-
|
|
269
|
+
//#region src/agent.ts
|
|
270
|
+
const DEFAULT_DOCS_API_ROUTE = "/api/docs";
|
|
271
|
+
const DEFAULT_AGENT_SPEC_ROUTE = "/api/docs/agent/spec";
|
|
272
|
+
const DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE = "/.well-known/agent";
|
|
273
|
+
const DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE = "/.well-known/agent.json";
|
|
274
|
+
const DEFAULT_MCP_ROUTE = "/api/docs/mcp";
|
|
275
|
+
const DEFAULT_MCP_PUBLIC_ROUTE = "/mcp";
|
|
276
|
+
const DEFAULT_MCP_WELL_KNOWN_ROUTE = "/.well-known/mcp";
|
|
277
|
+
const DEFAULT_LLMS_TXT_ROUTE = "/llms.txt";
|
|
278
|
+
const DEFAULT_LLMS_FULL_TXT_ROUTE = "/llms-full.txt";
|
|
279
|
+
const DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms.txt";
|
|
280
|
+
const DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE = "/.well-known/llms-full.txt";
|
|
281
|
+
const DEFAULT_AGENT_FEEDBACK_ROUTE = "/api/docs/agent/feedback";
|
|
282
|
+
function normalizeDocsPathSegment(value) {
|
|
283
|
+
return value.replace(/^\/+|\/+$/g, "");
|
|
284
|
+
}
|
|
285
|
+
function normalizeDocsUrlPath(value) {
|
|
286
|
+
const normalized = value.replace(/\/+/g, "/");
|
|
287
|
+
if (normalized === "/") return normalized;
|
|
288
|
+
return normalized.replace(/\/+$/, "");
|
|
289
|
+
}
|
|
290
|
+
function isDocsAgentDiscoveryRequest(url) {
|
|
291
|
+
const pathname = normalizeDocsUrlPath(url.pathname);
|
|
292
|
+
if (pathname === DEFAULT_DOCS_API_ROUTE && url.searchParams.get("agent")?.trim() === "spec") return true;
|
|
293
|
+
return pathname === DEFAULT_AGENT_SPEC_ROUTE || pathname === DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE || pathname === DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE;
|
|
294
|
+
}
|
|
295
|
+
function isDocsMcpRequest(url) {
|
|
296
|
+
const pathname = normalizeDocsUrlPath(url.pathname);
|
|
297
|
+
return pathname === DEFAULT_MCP_ROUTE || pathname === DEFAULT_MCP_PUBLIC_ROUTE || pathname === DEFAULT_MCP_WELL_KNOWN_ROUTE;
|
|
298
|
+
}
|
|
299
|
+
function isDocsPublicGetRequest(entry, url, request) {
|
|
300
|
+
const pathname = normalizeDocsUrlPath(url.pathname);
|
|
301
|
+
if (pathname === DEFAULT_DOCS_API_ROUTE || pathname === DEFAULT_MCP_ROUTE) return false;
|
|
302
|
+
return isDocsAgentDiscoveryRequest(url) || resolveDocsLlmsTxtFormat(url) !== null || resolveDocsMarkdownRequest(entry, url, request) !== null;
|
|
303
|
+
}
|
|
304
|
+
function resolveDocsLlmsTxtFormat(url) {
|
|
305
|
+
const pathname = normalizeDocsUrlPath(url.pathname);
|
|
306
|
+
if (pathname === DEFAULT_LLMS_TXT_ROUTE || pathname === DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE) return "llms";
|
|
307
|
+
if (pathname === DEFAULT_LLMS_FULL_TXT_ROUTE || pathname === DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE) return "llms-full";
|
|
308
|
+
const format = url.searchParams.get("format");
|
|
309
|
+
return pathname === DEFAULT_DOCS_API_ROUTE && (format === "llms" || format === "llms-full") ? format : null;
|
|
310
|
+
}
|
|
311
|
+
function resolveDocsMarkdownRequest(entry, url, request) {
|
|
312
|
+
const pathname = normalizeDocsUrlPath(url.pathname);
|
|
313
|
+
const format = url.searchParams.get("format")?.trim();
|
|
314
|
+
if (pathname === DEFAULT_DOCS_API_ROUTE && format === "markdown") return { requestedPath: url.searchParams.get("path")?.trim() ?? "" };
|
|
315
|
+
const normalizedEntry = `/${normalizeDocsPathSegment(entry) || "docs"}`;
|
|
316
|
+
if (pathname === `${normalizedEntry}.md`) return { requestedPath: "" };
|
|
317
|
+
const slugPrefix = `${normalizedEntry}/`;
|
|
318
|
+
if (pathname.startsWith(slugPrefix) && pathname.endsWith(".md")) return { requestedPath: pathname.slice(slugPrefix.length, -3) };
|
|
319
|
+
if (acceptsMarkdown(request)) {
|
|
320
|
+
if (pathname === normalizedEntry) return { requestedPath: "" };
|
|
321
|
+
if (pathname.startsWith(slugPrefix)) return { requestedPath: pathname.slice(slugPrefix.length) };
|
|
322
|
+
}
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
function findDocsMarkdownPage(entry, pages, requestedPath) {
|
|
326
|
+
const normalizedRequest = normalizeRequestedMarkdownPath(entry, requestedPath);
|
|
327
|
+
for (const page of pages) if (normalizeDocsUrlPath(page.url) === normalizedRequest) return page;
|
|
328
|
+
const normalizedSlug = normalizeDocsPathSegment(requestedPath.replace(/^\//, "").replace(/\.md$/i, ""));
|
|
329
|
+
for (const page of pages) if (page.slug !== void 0 && normalizeDocsPathSegment(page.slug) === normalizedSlug) return page;
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
function renderDocsMarkdownDocument(page) {
|
|
333
|
+
if (page.agentRawContent !== void 0) return page.agentRawContent;
|
|
334
|
+
const relatedLines = renderDocsRelatedMarkdownLines(page.related);
|
|
335
|
+
const lines = [`# ${page.title}`, `URL: ${page.url}`];
|
|
336
|
+
if (page.description) lines.push(`Description: ${page.description}`);
|
|
337
|
+
lines.push(...relatedLines);
|
|
338
|
+
lines.push("", page.agentFallbackRawContent ?? page.rawContent ?? page.content);
|
|
339
|
+
return lines.join("\n");
|
|
340
|
+
}
|
|
341
|
+
function resolveDocsAgentMdxContent(content, audience) {
|
|
342
|
+
const lines = content.split("\n");
|
|
343
|
+
const output = [];
|
|
344
|
+
let fenceMarker = null;
|
|
345
|
+
let agentDepth = 0;
|
|
346
|
+
for (const line of lines) {
|
|
347
|
+
const trimmed = line.trim();
|
|
348
|
+
const fenceMatch = trimmed.match(/^(`{3,}|~{3,})/);
|
|
349
|
+
if (fenceMatch) {
|
|
350
|
+
if (!fenceMarker) fenceMarker = fenceMatch[1];
|
|
351
|
+
else if (trimmed.startsWith(fenceMarker)) fenceMarker = null;
|
|
352
|
+
if (audience === "agent" || agentDepth === 0) output.push(line);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (!fenceMarker) {
|
|
356
|
+
if (/^<Agent(?:\s[^>]*)?\/>$/.test(trimmed)) continue;
|
|
357
|
+
const singleLineMatch = line.match(/^(\s*)<Agent(?:\s[^>]*)?>([\s\S]*?)<\/Agent>\s*$/);
|
|
358
|
+
if (singleLineMatch) {
|
|
359
|
+
if (audience === "agent" && singleLineMatch[2]) output.push(`${singleLineMatch[1]}${singleLineMatch[2]}`);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (line.match(/^(\s*)<Agent(?:\s[^>]*)?>\s*$/)) {
|
|
363
|
+
agentDepth += 1;
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const openWithContentMatch = line.match(/^(\s*)<Agent(?:\s[^>]*)?>(.*)$/);
|
|
367
|
+
if (openWithContentMatch) {
|
|
368
|
+
agentDepth += 1;
|
|
369
|
+
if (audience === "agent" && openWithContentMatch[2]) output.push(`${openWithContentMatch[1]}${openWithContentMatch[2]}`);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const closeWithContentMatch = line.match(/^(.*)<\/Agent>\s*$/);
|
|
373
|
+
if (closeWithContentMatch && agentDepth > 0) {
|
|
374
|
+
if (audience === "agent" && closeWithContentMatch[1].trim()) output.push(closeWithContentMatch[1]);
|
|
375
|
+
agentDepth = Math.max(0, agentDepth - 1);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (/^<\/Agent>\s*$/.test(trimmed) && agentDepth > 0) {
|
|
379
|
+
agentDepth = Math.max(0, agentDepth - 1);
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (agentDepth > 0 && audience === "human") continue;
|
|
384
|
+
output.push(line);
|
|
385
|
+
}
|
|
386
|
+
return output.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
387
|
+
}
|
|
388
|
+
function buildDocsAgentDiscoverySpec({ origin, entry = "docs", i18n = null, search, mcp, feedback, llms, markdown }) {
|
|
389
|
+
const normalizedEntry = normalizeDocsPathSegment(entry) || "docs";
|
|
390
|
+
const localesEnabled = i18n !== null;
|
|
391
|
+
const searchEnabled = isSearchEnabled(search);
|
|
392
|
+
const feedbackRoute = feedback?.route ?? DEFAULT_AGENT_FEEDBACK_ROUTE;
|
|
393
|
+
const feedbackSchemaRoute = feedback?.schemaRoute ?? `${feedbackRoute}/schema`;
|
|
394
|
+
const llmsEnabled = llms?.enabled ?? true;
|
|
395
|
+
return {
|
|
396
|
+
version: "1",
|
|
397
|
+
name: "@farming-labs/docs",
|
|
398
|
+
baseUrl: origin,
|
|
399
|
+
site: {
|
|
400
|
+
title: llms?.siteTitle ?? "Documentation",
|
|
401
|
+
description: llms?.siteDescription,
|
|
402
|
+
entry: normalizedEntry,
|
|
403
|
+
baseUrl: llms?.baseUrl ?? origin
|
|
404
|
+
},
|
|
405
|
+
locales: {
|
|
406
|
+
enabled: localesEnabled,
|
|
407
|
+
available: i18n?.locales ?? [],
|
|
408
|
+
default: i18n?.defaultLocale ?? null,
|
|
409
|
+
queryParam: "lang",
|
|
410
|
+
fallbackQueryParam: "locale"
|
|
411
|
+
},
|
|
412
|
+
capabilities: {
|
|
413
|
+
markdownRoutes: true,
|
|
414
|
+
agentMdOverrides: true,
|
|
415
|
+
agentBlocks: true,
|
|
416
|
+
llms: llmsEnabled,
|
|
417
|
+
skills: true,
|
|
418
|
+
mcp: mcp.enabled,
|
|
419
|
+
search: searchEnabled,
|
|
420
|
+
agentFeedback: feedback?.enabled ?? false,
|
|
421
|
+
locales: localesEnabled
|
|
422
|
+
},
|
|
423
|
+
api: {
|
|
424
|
+
docs: DEFAULT_DOCS_API_ROUTE,
|
|
425
|
+
agentSpec: DEFAULT_AGENT_SPEC_ROUTE,
|
|
426
|
+
agentSpecDefault: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
|
|
427
|
+
agentSpecFallback: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
|
|
428
|
+
agentSpecWellKnown: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
|
|
429
|
+
agentSpecWellKnownJson: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
|
|
430
|
+
agentSpecQuery: `${DEFAULT_DOCS_API_ROUTE}?agent=spec`
|
|
431
|
+
},
|
|
432
|
+
markdown: {
|
|
433
|
+
enabled: true,
|
|
434
|
+
acceptHeader: markdown?.acceptHeader === false ? null : "text/markdown",
|
|
435
|
+
pagePattern: `/${normalizedEntry}/{slug}.md`,
|
|
436
|
+
rootPage: `/${normalizedEntry}.md`,
|
|
437
|
+
apiPattern: `${DEFAULT_DOCS_API_ROUTE}?format=markdown&path={slug}`,
|
|
438
|
+
resolutionOrder: [
|
|
439
|
+
"agent.md",
|
|
440
|
+
"Agent blocks",
|
|
441
|
+
"page markdown"
|
|
442
|
+
]
|
|
443
|
+
},
|
|
444
|
+
llms: {
|
|
445
|
+
enabled: llmsEnabled,
|
|
446
|
+
defaultTxt: DEFAULT_LLMS_TXT_ROUTE,
|
|
447
|
+
defaultFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
|
|
448
|
+
txt: `${DEFAULT_DOCS_API_ROUTE}?format=llms`,
|
|
449
|
+
full: `${DEFAULT_DOCS_API_ROUTE}?format=llms-full`,
|
|
450
|
+
publicTxt: DEFAULT_LLMS_TXT_ROUTE,
|
|
451
|
+
publicFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
|
|
452
|
+
wellKnownTxt: DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
|
|
453
|
+
wellKnownFull: DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE
|
|
454
|
+
},
|
|
455
|
+
search: {
|
|
456
|
+
enabled: searchEnabled,
|
|
457
|
+
endpoint: `${DEFAULT_DOCS_API_ROUTE}?query={query}`,
|
|
458
|
+
method: "GET",
|
|
459
|
+
queryParam: "query",
|
|
460
|
+
localeParam: "lang"
|
|
461
|
+
},
|
|
462
|
+
skills: {
|
|
463
|
+
enabled: true,
|
|
464
|
+
registry: "skills.sh",
|
|
465
|
+
install: "npx skills add farming-labs/docs",
|
|
466
|
+
recommended: [{
|
|
467
|
+
name: "getting-started",
|
|
468
|
+
description: "Use for installation, init, framework setup, theme CSS, and first docs.config wiring."
|
|
469
|
+
}]
|
|
470
|
+
},
|
|
471
|
+
mcp: {
|
|
472
|
+
enabled: mcp.enabled,
|
|
473
|
+
endpoint: mcp.route,
|
|
474
|
+
defaultEndpoint: DEFAULT_MCP_PUBLIC_ROUTE,
|
|
475
|
+
publicEndpoint: DEFAULT_MCP_PUBLIC_ROUTE,
|
|
476
|
+
wellKnownEndpoint: DEFAULT_MCP_WELL_KNOWN_ROUTE,
|
|
477
|
+
publicEndpoints: [DEFAULT_MCP_PUBLIC_ROUTE, DEFAULT_MCP_WELL_KNOWN_ROUTE],
|
|
478
|
+
canonicalEndpoint: DEFAULT_MCP_ROUTE,
|
|
479
|
+
name: mcp.name,
|
|
480
|
+
version: mcp.version,
|
|
481
|
+
tools: mcp.tools
|
|
482
|
+
},
|
|
483
|
+
feedback: {
|
|
484
|
+
enabled: feedback?.enabled ?? false,
|
|
485
|
+
schema: feedbackSchemaRoute,
|
|
486
|
+
submit: feedbackRoute,
|
|
487
|
+
schemaQuery: `${DEFAULT_DOCS_API_ROUTE}?feedback=agent&schema=1`,
|
|
488
|
+
submitQuery: `${DEFAULT_DOCS_API_ROUTE}?feedback=agent`
|
|
489
|
+
},
|
|
490
|
+
instructions: {
|
|
491
|
+
preferMarkdownRoutes: true,
|
|
492
|
+
useMcpWhenAvailable: true,
|
|
493
|
+
readFeedbackSchemaBeforeSubmitting: true,
|
|
494
|
+
doNotAssumeFeedbackPayloadShape: true
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
function acceptsMarkdown(request) {
|
|
499
|
+
const accept = request.headers.get("accept");
|
|
500
|
+
if (!accept) return false;
|
|
501
|
+
return accept.split(",").map((value) => value.trim()).some((value) => {
|
|
502
|
+
const [mediaType, ...params] = value.split(";").map((part) => part.trim().toLowerCase());
|
|
503
|
+
if (mediaType !== "text/markdown") return false;
|
|
504
|
+
const qualityParam = params.find((param) => param.split("=", 1)[0]?.trim() === "q");
|
|
505
|
+
if (!qualityParam) return true;
|
|
506
|
+
const qualityValue = qualityParam.slice(qualityParam.indexOf("=") + 1).trim();
|
|
507
|
+
const quality = Number.parseFloat(qualityValue);
|
|
508
|
+
return Number.isFinite(quality) ? quality > 0 : true;
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
function normalizeRequestedMarkdownPath(entry, requestedPath) {
|
|
512
|
+
const normalizedEntry = `/${normalizeDocsPathSegment(entry) || "docs"}`;
|
|
513
|
+
const trimmed = requestedPath.trim().replace(/\.md$/i, "");
|
|
514
|
+
if (!trimmed) return normalizedEntry;
|
|
515
|
+
const normalized = normalizeDocsUrlPath(trimmed.startsWith("/") ? trimmed : `/${trimmed}`);
|
|
516
|
+
if (normalized === normalizedEntry || normalized.startsWith(`${normalizedEntry}/`)) return normalized;
|
|
517
|
+
const slug = normalizeDocsPathSegment(trimmed);
|
|
518
|
+
return slug ? normalizeDocsUrlPath(`${normalizedEntry}/${slug}`) : normalizedEntry;
|
|
519
|
+
}
|
|
520
|
+
function isSearchEnabled(search) {
|
|
521
|
+
if (search === false) return false;
|
|
522
|
+
if (search && typeof search === "object" && search.enabled === false) return false;
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
//#endregion
|
|
527
|
+
export { DEFAULT_AGENT_FEEDBACK_ROUTE, DEFAULT_AGENT_SPEC_ROUTE, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, DEFAULT_DOCS_API_ROUTE, DEFAULT_LLMS_FULL_TXT_ROUTE, DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE, DEFAULT_LLMS_TXT_ROUTE, DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE, DEFAULT_MCP_PUBLIC_ROUTE, DEFAULT_MCP_ROUTE, DEFAULT_MCP_WELL_KNOWN_ROUTE, buildDocsAgentDiscoverySpec, buildDocsSearchDocuments, buildPageOpenGraph, buildPageTwitter, createAlgoliaSearchAdapter, createCustomSearchAdapter, createMcpSearchAdapter, createSimpleSearchAdapter, createTheme, createTypesenseSearchAdapter, deepMerge, defineDocs, extendTheme, findDocsMarkdownPage, isDocsAgentDiscoveryRequest, isDocsMcpRequest, isDocsPublicGetRequest, normalizeDocsPathSegment, normalizeDocsRelated, normalizeDocsUrlPath, performDocsSearch, renderDocsMarkdownDocument, renderDocsRelatedMarkdownLines, resolveChangelogConfig, resolveDocsAgentMdxContent, resolveDocsI18n, resolveDocsLlmsTxtFormat, resolveDocsLocale, resolveDocsMarkdownRequest, resolveDocsPath, resolveOGImage, resolveSearchRequestConfig, resolveTitle };
|
|
@@ -247,6 +247,14 @@ function sveltePageConfigImport(useAlias) {
|
|
|
247
247
|
function svelteLayoutServerImport(useAlias) {
|
|
248
248
|
return useAlias ? "$lib/docs.server" : "../../lib/docs.server";
|
|
249
249
|
}
|
|
250
|
+
function svelteRouteServerImport(filePath, useAlias) {
|
|
251
|
+
if (useAlias) return "$lib/docs.server";
|
|
252
|
+
return relativeImport(filePath, "src/lib/docs.server.ts");
|
|
253
|
+
}
|
|
254
|
+
function svelteRouteConfigImport(filePath, useAlias) {
|
|
255
|
+
if (useAlias) return "$lib/docs.config";
|
|
256
|
+
return relativeImport(filePath, "src/lib/docs.config.ts");
|
|
257
|
+
}
|
|
250
258
|
function astroServerConfigImport(useAlias) {
|
|
251
259
|
return useAlias ? "@/lib/docs.config" : "./docs.config";
|
|
252
260
|
}
|
|
@@ -258,6 +266,14 @@ function astroPageServerImport(useAlias, depth) {
|
|
|
258
266
|
if (useAlias) return "@/lib/docs.server";
|
|
259
267
|
return `${"../".repeat(depth)}lib/docs.server`;
|
|
260
268
|
}
|
|
269
|
+
function astroRouteServerImport(filePath, useAlias) {
|
|
270
|
+
if (useAlias) return "@/lib/docs.server";
|
|
271
|
+
return relativeImport(filePath, "src/lib/docs.server.ts");
|
|
272
|
+
}
|
|
273
|
+
function astroRouteConfigImport(filePath, useAlias) {
|
|
274
|
+
if (useAlias) return "@/lib/docs.config";
|
|
275
|
+
return relativeImport(filePath, "src/lib/docs.config.ts");
|
|
276
|
+
}
|
|
261
277
|
function docsConfigTemplate(cfg) {
|
|
262
278
|
if (cfg.theme === "custom" && cfg.customThemeName) {
|
|
263
279
|
const exportName = getThemeExportName(cfg.customThemeName);
|
|
@@ -811,13 +827,27 @@ function DocsIndexPage() {
|
|
|
811
827
|
}
|
|
812
828
|
function tanstackDocsCatchAllRouteTemplate(opts) {
|
|
813
829
|
const entryUrl = `/${opts.entry.replace(/^\/+|\/+$/g, "")}`;
|
|
830
|
+
const serverImport = opts.useAlias ? "@/lib/docs.server" : relativeImport(opts.filePath, "src/lib/docs.server.ts");
|
|
814
831
|
return `\
|
|
815
832
|
import { createFileRoute, notFound } from "@tanstack/react-router";
|
|
833
|
+
import { isDocsPublicGetRequest } from "@farming-labs/docs";
|
|
816
834
|
import { TanstackDocsPage } from "@farming-labs/tanstack-start/react";
|
|
817
835
|
import { loadDocPage } from "${tanstackDocsFunctionsImport(opts)}";
|
|
836
|
+
import { docsServer } from "${serverImport}";
|
|
818
837
|
import docsConfig from "${tanstackDocsConfigImport(opts.filePath)}";
|
|
819
838
|
|
|
820
839
|
export const Route = createFileRoute("${entryUrl}/$")({
|
|
840
|
+
server: {
|
|
841
|
+
handlers: {
|
|
842
|
+
GET: async ({ request }) => {
|
|
843
|
+
const url = new URL(request.url);
|
|
844
|
+
if (isDocsPublicGetRequest(${JSON.stringify(opts.entry)}, url, request)) {
|
|
845
|
+
return docsServer.GET({ request });
|
|
846
|
+
}
|
|
847
|
+
return undefined;
|
|
848
|
+
},
|
|
849
|
+
},
|
|
850
|
+
},
|
|
821
851
|
loader: async ({ location }) => {
|
|
822
852
|
try {
|
|
823
853
|
return await loadDocPage({ data: { pathname: location.pathname } });
|
|
@@ -865,6 +895,46 @@ export const Route = createFileRoute("/api/docs")({
|
|
|
865
895
|
});
|
|
866
896
|
`;
|
|
867
897
|
}
|
|
898
|
+
function tanstackDocsPublicRouteTemplate(useAlias, filePath, entry) {
|
|
899
|
+
return `\
|
|
900
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
901
|
+
import { isDocsMcpRequest, isDocsPublicGetRequest } from "@farming-labs/docs";
|
|
902
|
+
import { docsServer } from "${useAlias ? "@/lib/docs.server" : relativeImport(filePath, "src/lib/docs.server.ts")}";
|
|
903
|
+
|
|
904
|
+
const docsEntry = ${JSON.stringify(entry)};
|
|
905
|
+
|
|
906
|
+
async function handlePublicDocsRequest(request: Request) {
|
|
907
|
+
const url = new URL(request.url);
|
|
908
|
+
const method = request.method.toUpperCase();
|
|
909
|
+
|
|
910
|
+
if (isDocsMcpRequest(url)) {
|
|
911
|
+
if (method === "POST") return docsServer.MCP.POST({ request });
|
|
912
|
+
if (method === "DELETE") return docsServer.MCP.DELETE({ request });
|
|
913
|
+
if (method === "GET" || method === "HEAD") return docsServer.MCP.GET({ request });
|
|
914
|
+
return new Response("Method Not Allowed", {
|
|
915
|
+
status: 405,
|
|
916
|
+
headers: { Allow: "GET, HEAD, POST, DELETE" },
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, url, request)) {
|
|
921
|
+
return docsServer.GET({ request });
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return new Response("Not Found", { status: 404 });
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
export const Route = createFileRoute("/$")({
|
|
928
|
+
server: {
|
|
929
|
+
handlers: {
|
|
930
|
+
GET: async ({ request }) => handlePublicDocsRequest(request),
|
|
931
|
+
POST: async ({ request }) => handlePublicDocsRequest(request),
|
|
932
|
+
DELETE: async ({ request }) => handlePublicDocsRequest(request),
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
});
|
|
936
|
+
`;
|
|
937
|
+
}
|
|
868
938
|
function tanstackApiReferenceRouteTemplate(opts) {
|
|
869
939
|
const routePath = `/${opts.apiReferencePath}${opts.catchAll ? "/$" : "/"}`;
|
|
870
940
|
return `\
|
|
@@ -1038,6 +1108,7 @@ src/lib/docs.functions.ts
|
|
|
1038
1108
|
src/routes/${cfg.entry}/index.tsx
|
|
1039
1109
|
src/routes/${cfg.entry}/$.tsx
|
|
1040
1110
|
src/routes/api/docs.ts
|
|
1111
|
+
src/routes/$.ts
|
|
1041
1112
|
\`\`\`
|
|
1042
1113
|
`;
|
|
1043
1114
|
}
|
|
@@ -1192,7 +1263,7 @@ const contentFiles = import.meta.glob("/${cfg.entry ?? "docs"}/**/*.{md,mdx,svx}
|
|
|
1192
1263
|
eager: true,
|
|
1193
1264
|
}) as Record<string, string>;
|
|
1194
1265
|
|
|
1195
|
-
export const { load, GET, POST } = createDocsServer({
|
|
1266
|
+
export const { load, GET, POST, MCP } = createDocsServer({
|
|
1196
1267
|
...config,
|
|
1197
1268
|
_preloadedContent: contentFiles,
|
|
1198
1269
|
});
|
|
@@ -1237,6 +1308,91 @@ import config from "${useAlias ? "$lib/docs.config" : relativeImport(filePath, "
|
|
|
1237
1308
|
export const GET = createSvelteApiReference(config);
|
|
1238
1309
|
`;
|
|
1239
1310
|
}
|
|
1311
|
+
function svelteDocsApiRouteTemplate(filePath, useAlias) {
|
|
1312
|
+
return `\
|
|
1313
|
+
export { GET, POST } from "${svelteRouteServerImport(filePath, useAlias)}";
|
|
1314
|
+
`;
|
|
1315
|
+
}
|
|
1316
|
+
function svelteDocsPublicHookTemplate(filePath, useAlias) {
|
|
1317
|
+
const serverImport = svelteRouteServerImport(filePath, useAlias);
|
|
1318
|
+
return `\
|
|
1319
|
+
import { isDocsMcpRequest, isDocsPublicGetRequest } from "@farming-labs/docs";
|
|
1320
|
+
import type { Handle } from "@sveltejs/kit";
|
|
1321
|
+
import config from "${svelteRouteConfigImport(filePath, useAlias)}";
|
|
1322
|
+
import { GET, MCP } from "${serverImport}";
|
|
1323
|
+
|
|
1324
|
+
const docsEntry = config.entry ?? "docs";
|
|
1325
|
+
|
|
1326
|
+
export const handle: Handle = async ({ event, resolve }) => {
|
|
1327
|
+
const method = event.request.method.toUpperCase();
|
|
1328
|
+
|
|
1329
|
+
if (isDocsMcpRequest(event.url)) {
|
|
1330
|
+
if (method === "POST") return MCP.POST({ request: event.request });
|
|
1331
|
+
if (method === "DELETE") return MCP.DELETE({ request: event.request });
|
|
1332
|
+
if (method === "GET" || method === "HEAD") return MCP.GET({ request: event.request });
|
|
1333
|
+
return new Response("Method Not Allowed", {
|
|
1334
|
+
status: 405,
|
|
1335
|
+
headers: { Allow: "GET, HEAD, POST, DELETE" },
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, event.url, event.request)) {
|
|
1340
|
+
return GET({ url: event.url, request: event.request });
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
return resolve(event);
|
|
1344
|
+
};
|
|
1345
|
+
`;
|
|
1346
|
+
}
|
|
1347
|
+
function injectSvelteDocsPublicHook(content, filePath, useAlias) {
|
|
1348
|
+
if (content.includes("isDocsPublicGetRequest") || content.includes("docsPublicHandle")) return null;
|
|
1349
|
+
if (/export\s*{\s*handle\b/.test(content)) return null;
|
|
1350
|
+
const serverImport = svelteRouteServerImport(filePath, useAlias);
|
|
1351
|
+
const configImport = svelteRouteConfigImport(filePath, useAlias);
|
|
1352
|
+
let next = content.trimEnd();
|
|
1353
|
+
let hasExistingHandle = false;
|
|
1354
|
+
for (const [pattern, replacement] of [
|
|
1355
|
+
[/\bexport\s+const\s+handle(\s*:\s*[^=]+)?\s*=/, "const existingHandle$1 ="],
|
|
1356
|
+
[/\bexport\s+async\s+function\s+handle\b/, "async function existingHandle"],
|
|
1357
|
+
[/\bexport\s+function\s+handle\b/, "function existingHandle"]
|
|
1358
|
+
]) if (pattern.test(next)) {
|
|
1359
|
+
next = next.replace(pattern, replacement);
|
|
1360
|
+
next = next.replace(/const existingHandle(:[^=\n]*?)\s+=/, "const existingHandle$1 =");
|
|
1361
|
+
hasExistingHandle = true;
|
|
1362
|
+
break;
|
|
1363
|
+
}
|
|
1364
|
+
const imports = [
|
|
1365
|
+
"import { isDocsMcpRequest, isDocsPublicGetRequest } from \"@farming-labs/docs\";",
|
|
1366
|
+
...next.includes("Handle") ? [] : ["import type { Handle } from \"@sveltejs/kit\";"],
|
|
1367
|
+
...hasExistingHandle && !next.includes("sequence") ? ["import { sequence } from \"@sveltejs/kit/hooks\";"] : [],
|
|
1368
|
+
`import docsConfig from "${configImport}";`,
|
|
1369
|
+
`import { GET as docsGET, MCP as docsMCP } from "${serverImport}";`
|
|
1370
|
+
];
|
|
1371
|
+
const docsHandle = `\
|
|
1372
|
+
const docsEntry = docsConfig.entry ?? "docs";
|
|
1373
|
+
|
|
1374
|
+
const docsPublicHandle: Handle = async ({ event, resolve }) => {
|
|
1375
|
+
const method = event.request.method.toUpperCase();
|
|
1376
|
+
|
|
1377
|
+
if (isDocsMcpRequest(event.url)) {
|
|
1378
|
+
if (method === "POST") return docsMCP.POST({ request: event.request });
|
|
1379
|
+
if (method === "DELETE") return docsMCP.DELETE({ request: event.request });
|
|
1380
|
+
if (method === "GET" || method === "HEAD") return docsMCP.GET({ request: event.request });
|
|
1381
|
+
return new Response("Method Not Allowed", {
|
|
1382
|
+
status: 405,
|
|
1383
|
+
headers: { Allow: "GET, HEAD, POST, DELETE" },
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, event.url, event.request)) {
|
|
1388
|
+
return docsGET({ url: event.url, request: event.request });
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
return resolve(event);
|
|
1392
|
+
};`;
|
|
1393
|
+
const exportLine = hasExistingHandle ? "export const handle = sequence(docsPublicHandle, existingHandle);" : "export const handle = docsPublicHandle;";
|
|
1394
|
+
return `${imports.join("\n")}\n${next}\n\n${docsHandle}\n\n${exportLine}\n`;
|
|
1395
|
+
}
|
|
1240
1396
|
function svelteRootLayoutTemplate(globalCssRelPath) {
|
|
1241
1397
|
let cssImport;
|
|
1242
1398
|
if (globalCssRelPath.startsWith("src/")) cssImport = "./" + globalCssRelPath.slice(4);
|
|
@@ -1354,10 +1510,12 @@ ${cfg.entry}/ # Markdown content
|
|
|
1354
1510
|
quickstart/
|
|
1355
1511
|
page.md # /${cfg.entry}/quickstart
|
|
1356
1512
|
src/
|
|
1513
|
+
hooks.server.ts # Public docs aliases
|
|
1357
1514
|
lib/
|
|
1358
1515
|
docs.config.ts # Docs configuration
|
|
1359
1516
|
docs.server.ts # Server-side docs loader
|
|
1360
1517
|
routes/
|
|
1518
|
+
api/docs/+server.ts # Search/AI API route
|
|
1361
1519
|
${cfg.entry}/
|
|
1362
1520
|
+layout.svelte # Docs layout
|
|
1363
1521
|
+layout.server.js # Layout data loader
|
|
@@ -1509,7 +1667,7 @@ const contentFiles = import.meta.glob("/${cfg.entry ?? "docs"}/**/*.{md,mdx}", {
|
|
|
1509
1667
|
eager: true,
|
|
1510
1668
|
}) as Record<string, string>;
|
|
1511
1669
|
|
|
1512
|
-
export const { load, GET, POST } = createDocsServer({
|
|
1670
|
+
export const { load, GET, POST, MCP } = createDocsServer({
|
|
1513
1671
|
...config,
|
|
1514
1672
|
_preloadedContent: contentFiles,
|
|
1515
1673
|
});
|
|
@@ -1619,6 +1777,86 @@ export const POST: APIRoute = async ({ request }) => {
|
|
|
1619
1777
|
};
|
|
1620
1778
|
`;
|
|
1621
1779
|
}
|
|
1780
|
+
function astroDocsMiddlewareTemplate(filePath, useAlias) {
|
|
1781
|
+
const serverImport = astroRouteServerImport(filePath, useAlias);
|
|
1782
|
+
return `\
|
|
1783
|
+
import { isDocsMcpRequest, isDocsPublicGetRequest } from "@farming-labs/docs";
|
|
1784
|
+
import type { MiddlewareHandler } from "astro";
|
|
1785
|
+
import config from "${astroRouteConfigImport(filePath, useAlias)}";
|
|
1786
|
+
import { GET, MCP } from "${serverImport}";
|
|
1787
|
+
|
|
1788
|
+
const docsEntry = config.entry ?? "docs";
|
|
1789
|
+
|
|
1790
|
+
export const onRequest: MiddlewareHandler = async (context, next) => {
|
|
1791
|
+
const method = context.request.method.toUpperCase();
|
|
1792
|
+
|
|
1793
|
+
if (isDocsMcpRequest(context.url)) {
|
|
1794
|
+
if (method === "POST") return MCP.POST({ request: context.request });
|
|
1795
|
+
if (method === "DELETE") return MCP.DELETE({ request: context.request });
|
|
1796
|
+
if (method === "GET" || method === "HEAD") return MCP.GET({ request: context.request });
|
|
1797
|
+
return new Response("Method Not Allowed", {
|
|
1798
|
+
status: 405,
|
|
1799
|
+
headers: { Allow: "GET, HEAD, POST, DELETE" },
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, context.url, context.request)) {
|
|
1804
|
+
return GET({ request: context.request });
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
return next();
|
|
1808
|
+
};
|
|
1809
|
+
`;
|
|
1810
|
+
}
|
|
1811
|
+
function injectAstroDocsMiddleware(content, filePath, useAlias) {
|
|
1812
|
+
if (content.includes("isDocsPublicGetRequest") || content.includes("docsPublicMiddleware")) return null;
|
|
1813
|
+
if (/export\s*{\s*onRequest\b/.test(content)) return null;
|
|
1814
|
+
const serverImport = astroRouteServerImport(filePath, useAlias);
|
|
1815
|
+
const configImport = astroRouteConfigImport(filePath, useAlias);
|
|
1816
|
+
let next = content.trimEnd();
|
|
1817
|
+
let hasExistingMiddleware = false;
|
|
1818
|
+
for (const [pattern, replacement] of [
|
|
1819
|
+
[/\bexport\s+const\s+onRequest(\s*:\s*[^=]+)?\s*=/, "const existingOnRequest$1 ="],
|
|
1820
|
+
[/\bexport\s+async\s+function\s+onRequest\b/, "async function existingOnRequest"],
|
|
1821
|
+
[/\bexport\s+function\s+onRequest\b/, "function existingOnRequest"]
|
|
1822
|
+
]) if (pattern.test(next)) {
|
|
1823
|
+
next = next.replace(pattern, replacement);
|
|
1824
|
+
next = next.replace(/const existingOnRequest(:[^=\n]*?)\s+=/, "const existingOnRequest$1 =");
|
|
1825
|
+
hasExistingMiddleware = true;
|
|
1826
|
+
break;
|
|
1827
|
+
}
|
|
1828
|
+
const imports = [
|
|
1829
|
+
"import { isDocsMcpRequest, isDocsPublicGetRequest } from \"@farming-labs/docs\";",
|
|
1830
|
+
...next.includes("MiddlewareHandler") ? [] : ["import type { MiddlewareHandler } from \"astro\";"],
|
|
1831
|
+
...hasExistingMiddleware && !next.includes("sequence") ? ["import { sequence } from \"astro:middleware\";"] : [],
|
|
1832
|
+
`import docsConfig from "${configImport}";`,
|
|
1833
|
+
`import { GET as docsGET, MCP as docsMCP } from "${serverImport}";`
|
|
1834
|
+
];
|
|
1835
|
+
const docsMiddleware = `\
|
|
1836
|
+
const docsEntry = docsConfig.entry ?? "docs";
|
|
1837
|
+
|
|
1838
|
+
const docsPublicMiddleware: MiddlewareHandler = async (context, next) => {
|
|
1839
|
+
const method = context.request.method.toUpperCase();
|
|
1840
|
+
|
|
1841
|
+
if (isDocsMcpRequest(context.url)) {
|
|
1842
|
+
if (method === "POST") return docsMCP.POST({ request: context.request });
|
|
1843
|
+
if (method === "DELETE") return docsMCP.DELETE({ request: context.request });
|
|
1844
|
+
if (method === "GET" || method === "HEAD") return docsMCP.GET({ request: context.request });
|
|
1845
|
+
return new Response("Method Not Allowed", {
|
|
1846
|
+
status: 405,
|
|
1847
|
+
headers: { Allow: "GET, HEAD, POST, DELETE" },
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, context.url, context.request)) {
|
|
1852
|
+
return docsGET({ request: context.request });
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
return next();
|
|
1856
|
+
};`;
|
|
1857
|
+
const exportLine = hasExistingMiddleware ? "export const onRequest = sequence(docsPublicMiddleware, existingOnRequest);" : "export const onRequest = docsPublicMiddleware;";
|
|
1858
|
+
return `${imports.join("\n")}\n${next}\n\n${docsMiddleware}\n\n${exportLine}\n`;
|
|
1859
|
+
}
|
|
1622
1860
|
function astroApiReferenceRouteTemplate(filePath) {
|
|
1623
1861
|
return `\
|
|
1624
1862
|
import { createAstroApiReference } from "@farming-labs/astro/api-reference";
|
|
@@ -1730,6 +1968,7 @@ ${cfg.entry}/ # Markdown content
|
|
|
1730
1968
|
quickstart/
|
|
1731
1969
|
page.md # /${cfg.entry}/quickstart
|
|
1732
1970
|
src/
|
|
1971
|
+
middleware.ts # Public docs aliases
|
|
1733
1972
|
lib/
|
|
1734
1973
|
docs.config.ts # Docs configuration
|
|
1735
1974
|
docs.server.ts # Server-side docs loader
|
|
@@ -1862,66 +2101,20 @@ export default defineDocs({
|
|
|
1862
2101
|
});
|
|
1863
2102
|
`;
|
|
1864
2103
|
}
|
|
1865
|
-
function
|
|
1866
|
-
const contentDirName = cfg.entry ?? "docs";
|
|
2104
|
+
function nuxtServerApiDocsRouteTemplate(cfg) {
|
|
1867
2105
|
return `\
|
|
1868
|
-
import {
|
|
2106
|
+
import { defineDocsHandler } from "@farming-labs/nuxt/server";
|
|
1869
2107
|
import config from "${cfg.useAlias ? "~/docs.config" : "../../docs.config"}";
|
|
1870
2108
|
|
|
1871
|
-
|
|
1872
|
-
query: "?raw",
|
|
1873
|
-
import: "default",
|
|
1874
|
-
eager: true,
|
|
1875
|
-
}) as Record<string, string>;
|
|
1876
|
-
|
|
1877
|
-
export const docsServer = createDocsServer({
|
|
1878
|
-
...config,
|
|
1879
|
-
_preloadedContent: contentFiles,
|
|
1880
|
-
});
|
|
1881
|
-
`;
|
|
1882
|
-
}
|
|
1883
|
-
function nuxtServerApiDocsGetTemplate() {
|
|
1884
|
-
return `\
|
|
1885
|
-
import { getRequestURL } from "h3";
|
|
1886
|
-
import { docsServer } from "../utils/docs-server";
|
|
1887
|
-
|
|
1888
|
-
export default defineEventHandler((event) => {
|
|
1889
|
-
const url = getRequestURL(event);
|
|
1890
|
-
const request = new Request(url.href, {
|
|
1891
|
-
method: event.method,
|
|
1892
|
-
headers: event.headers,
|
|
1893
|
-
});
|
|
1894
|
-
return docsServer.GET({ request });
|
|
1895
|
-
});
|
|
1896
|
-
`;
|
|
1897
|
-
}
|
|
1898
|
-
function nuxtServerApiDocsPostTemplate() {
|
|
1899
|
-
return `\
|
|
1900
|
-
import { getRequestURL, readRawBody } from "h3";
|
|
1901
|
-
import { docsServer } from "../utils/docs-server";
|
|
1902
|
-
|
|
1903
|
-
export default defineEventHandler(async (event) => {
|
|
1904
|
-
const url = getRequestURL(event);
|
|
1905
|
-
const body = await readRawBody(event);
|
|
1906
|
-
const request = new Request(url.href, {
|
|
1907
|
-
method: "POST",
|
|
1908
|
-
headers: event.headers,
|
|
1909
|
-
body: body ?? undefined,
|
|
1910
|
-
});
|
|
1911
|
-
return docsServer.POST({ request });
|
|
1912
|
-
});
|
|
2109
|
+
export default defineDocsHandler(config, useStorage);
|
|
1913
2110
|
`;
|
|
1914
2111
|
}
|
|
1915
|
-
function
|
|
2112
|
+
function nuxtServerDocsPublicMiddlewareTemplate(cfg) {
|
|
1916
2113
|
return `\
|
|
1917
|
-
import {
|
|
1918
|
-
import {
|
|
2114
|
+
import { defineDocsPublicHandler } from "@farming-labs/nuxt/server";
|
|
2115
|
+
import config from "${cfg.useAlias ? "~/docs.config" : "../../docs.config"}";
|
|
1919
2116
|
|
|
1920
|
-
export default
|
|
1921
|
-
const query = getQuery(event);
|
|
1922
|
-
const pathname = (query.pathname as string) ?? "/docs";
|
|
1923
|
-
return docsServer.load(pathname);
|
|
1924
|
-
});
|
|
2117
|
+
export default defineDocsPublicHandler(config, useStorage);
|
|
1925
2118
|
`;
|
|
1926
2119
|
}
|
|
1927
2120
|
function nuxtServerApiReferenceRouteTemplate(filePath, useAlias) {
|
|
@@ -1942,7 +2135,7 @@ const route = useRoute();
|
|
|
1942
2135
|
const pathname = computed(() => route.path);
|
|
1943
2136
|
|
|
1944
2137
|
const { data, error } = await useAsyncData(\`docs-\${pathname.value}\`, () =>
|
|
1945
|
-
$fetch("/api/docs
|
|
2138
|
+
$fetch("/api/docs", {
|
|
1946
2139
|
query: { pathname: pathname.value },
|
|
1947
2140
|
})
|
|
1948
2141
|
);
|
|
@@ -1979,6 +2172,7 @@ export default defineNuxtConfig({
|
|
|
1979
2172
|
|
|
1980
2173
|
nitro: {
|
|
1981
2174
|
moduleSideEffects: ["@farming-labs/nuxt/server"],
|
|
2175
|
+
serverAssets: [{ baseName: "${cfg.entry}", dir: "${cfg.entry}" }],
|
|
1982
2176
|
},
|
|
1983
2177
|
});
|
|
1984
2178
|
`;
|
|
@@ -2065,11 +2259,8 @@ ${cfg.entry}/ # Markdown content
|
|
|
2065
2259
|
installation/page.md
|
|
2066
2260
|
quickstart/page.md
|
|
2067
2261
|
server/
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
load.get.ts # Page data API
|
|
2071
|
-
docs.get.ts # Search API
|
|
2072
|
-
docs.post.ts # AI chat API
|
|
2262
|
+
api/docs.ts # Page data, search, and AI chat API
|
|
2263
|
+
middleware/docs-public.ts # llms.txt, .well-known, .md, and MCP aliases
|
|
2073
2264
|
pages/
|
|
2074
2265
|
${cfg.entry}/[[...slug]].vue # Docs catch-all page
|
|
2075
2266
|
docs.config.ts
|
|
@@ -3091,6 +3282,7 @@ function scaffoldTanstackStart(cwd, cfg, globalCssRelPath, write, skipped, writt
|
|
|
3091
3282
|
const docsIndexRoute = `${routeDir}/index.tsx`;
|
|
3092
3283
|
const docsCatchAllRoute = `${routeDir}/$.tsx`;
|
|
3093
3284
|
const apiRoute = "src/routes/api/docs.ts";
|
|
3285
|
+
const publicRoute = "src/routes/$.ts";
|
|
3094
3286
|
write(docsIndexRoute, tanstackDocsIndexRouteTemplate({
|
|
3095
3287
|
entry: cfg.entry,
|
|
3096
3288
|
filePath: docsIndexRoute,
|
|
@@ -3104,6 +3296,7 @@ function scaffoldTanstackStart(cwd, cfg, globalCssRelPath, write, skipped, writt
|
|
|
3104
3296
|
projectName: cfg.projectName
|
|
3105
3297
|
}));
|
|
3106
3298
|
write(apiRoute, tanstackApiDocsRouteTemplate(cfg.useAlias, apiRoute));
|
|
3299
|
+
write(publicRoute, tanstackDocsPublicRouteTemplate(cfg.useAlias, publicRoute, cfg.entry));
|
|
3107
3300
|
if (cfg.apiReference) {
|
|
3108
3301
|
const apiReferenceIndexRoute = `src/routes/${cfg.apiReference.path}.index.ts`;
|
|
3109
3302
|
const apiReferenceCatchAllRoute = `src/routes/${cfg.apiReference.path}.$.ts`;
|
|
@@ -3168,6 +3361,18 @@ function scaffoldSvelteKit(cwd, cfg, globalCssRelPath, write, skipped, written)
|
|
|
3168
3361
|
write(`src/routes/${cfg.entry}/+layout.server.js`, svelteDocsLayoutServerTemplate(cfg));
|
|
3169
3362
|
write(`src/routes/${cfg.entry}/[...slug]/+page.svelte`, svelteDocsPageTemplate(cfg));
|
|
3170
3363
|
if (cfg.i18n?.locales.length) write(`src/routes/${cfg.entry}/+page.svelte`, svelteDocsPageTemplate(cfg));
|
|
3364
|
+
const apiDocsRoute = "src/routes/api/docs/+server.ts";
|
|
3365
|
+
const publicHook = "src/hooks.server.ts";
|
|
3366
|
+
write(apiDocsRoute, svelteDocsApiRouteTemplate(apiDocsRoute, cfg.useAlias));
|
|
3367
|
+
const publicHookPath = path.join(cwd, publicHook);
|
|
3368
|
+
const existingPublicHook = readFileSafe(publicHookPath);
|
|
3369
|
+
if (existingPublicHook) {
|
|
3370
|
+
const injected = injectSvelteDocsPublicHook(existingPublicHook, publicHook, cfg.useAlias);
|
|
3371
|
+
if (injected) {
|
|
3372
|
+
writeFileSafe(publicHookPath, injected, true);
|
|
3373
|
+
written.push(`${publicHook} (composed docs public hook)`);
|
|
3374
|
+
} else skipped.push(`${publicHook} (already configured or could not compose docs public hook)`);
|
|
3375
|
+
} else write(publicHook, svelteDocsPublicHookTemplate(publicHook, cfg.useAlias));
|
|
3171
3376
|
if (cfg.apiReference) {
|
|
3172
3377
|
const apiReferenceIndexRoute = `src/routes/${cfg.apiReference.path}/+server.ts`;
|
|
3173
3378
|
const apiReferenceCatchAllRoute = `src/routes/${cfg.apiReference.path}/[...slug]/+server.ts`;
|
|
@@ -3215,6 +3420,16 @@ function scaffoldAstro(cwd, cfg, globalCssRelPath, write, skipped, written) {
|
|
|
3215
3420
|
write(`src/pages/${cfg.entry}/index.astro`, astroDocsIndexTemplate(cfg));
|
|
3216
3421
|
write(`src/pages/${cfg.entry}/[...slug].astro`, astroDocsPageTemplate(cfg));
|
|
3217
3422
|
write(`src/pages/api/${cfg.entry}.ts`, astroApiRouteTemplate(cfg));
|
|
3423
|
+
const middleware = "src/middleware.ts";
|
|
3424
|
+
const middlewarePath = path.join(cwd, middleware);
|
|
3425
|
+
const existingMiddleware = readFileSafe(middlewarePath);
|
|
3426
|
+
if (existingMiddleware) {
|
|
3427
|
+
const injected = injectAstroDocsMiddleware(existingMiddleware, middleware, cfg.useAlias);
|
|
3428
|
+
if (injected) {
|
|
3429
|
+
writeFileSafe(middlewarePath, injected, true);
|
|
3430
|
+
written.push(`${middleware} (composed docs public middleware)`);
|
|
3431
|
+
} else skipped.push(`${middleware} (already configured or could not compose docs public middleware)`);
|
|
3432
|
+
} else write(middleware, astroDocsMiddlewareTemplate(middleware, cfg.useAlias));
|
|
3218
3433
|
if (cfg.apiReference) {
|
|
3219
3434
|
const apiReferenceIndexRoute = `src/pages/${cfg.apiReference.path}/index.ts`;
|
|
3220
3435
|
const apiReferenceCatchAllRoute = `src/pages/${cfg.apiReference.path}/[...slug].ts`;
|
|
@@ -3256,10 +3471,8 @@ function scaffoldNuxt(cwd, cfg, globalCssRelPath, write, skipped, written) {
|
|
|
3256
3471
|
write(`themes/${baseName}.css`, customThemeCssTemplate(baseName));
|
|
3257
3472
|
}
|
|
3258
3473
|
write("docs.config.ts", nuxtDocsConfigTemplate(cfg));
|
|
3259
|
-
write("server/
|
|
3260
|
-
write("server/
|
|
3261
|
-
write("server/api/docs.post.ts", nuxtServerApiDocsPostTemplate());
|
|
3262
|
-
write("server/api/docs/load.get.ts", nuxtServerApiDocsLoadTemplate());
|
|
3474
|
+
write("server/api/docs.ts", nuxtServerApiDocsRouteTemplate(cfg));
|
|
3475
|
+
write("server/middleware/docs-public.ts", nuxtServerDocsPublicMiddlewareTemplate(cfg));
|
|
3263
3476
|
write(`pages/${cfg.entry}/[[...slug]].vue`, nuxtDocsPageTemplate(cfg));
|
|
3264
3477
|
if (cfg.apiReference) {
|
|
3265
3478
|
const apiReferenceIndexRoute = `server/routes/${cfg.apiReference.path}/index.ts`;
|
package/dist/mcp.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as DocsSearchConfig, G as OrderingItem, N as DocsSearchSourcePage, v as DocsMcpConfig } from "./types-CP2NmW5c.mjs";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
|
|
4
4
|
//#region src/mcp.d.ts
|
|
@@ -7,6 +7,7 @@ interface DocsMcpPage {
|
|
|
7
7
|
url: string;
|
|
8
8
|
title: string;
|
|
9
9
|
description?: string;
|
|
10
|
+
related?: DocsSearchSourcePage["related"];
|
|
10
11
|
icon?: string;
|
|
11
12
|
content: string;
|
|
12
13
|
rawContent?: string;
|
package/dist/mcp.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as performDocsSearch } from "./search-
|
|
1
|
+
import { l as normalizeDocsRelated, s as performDocsSearch, u as renderDocsRelatedMarkdownLines } from "./search-CfnJVeh-.mjs";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -330,6 +330,7 @@ function scanFilesystemDocsPages(contentDirAbs, entry) {
|
|
|
330
330
|
url,
|
|
331
331
|
title,
|
|
332
332
|
description: data.description,
|
|
333
|
+
relatedInput: data.related,
|
|
333
334
|
icon: data.icon,
|
|
334
335
|
content: stripMarkdownForMcp(humanRawContent),
|
|
335
336
|
rawContent: humanRawContent,
|
|
@@ -341,7 +342,7 @@ function scanFilesystemDocsPages(contentDirAbs, entry) {
|
|
|
341
342
|
}
|
|
342
343
|
}
|
|
343
344
|
scan(contentDirAbs, []);
|
|
344
|
-
return pages;
|
|
345
|
+
return resolveRelatedForMcpPages(pages);
|
|
345
346
|
}
|
|
346
347
|
function readFilesystemAgentDoc(dir) {
|
|
347
348
|
const agentPath = path.join(dir, "agent.md");
|
|
@@ -352,6 +353,15 @@ function readFilesystemAgentDoc(dir) {
|
|
|
352
353
|
agentRawContent: content
|
|
353
354
|
};
|
|
354
355
|
}
|
|
356
|
+
function resolveRelatedForMcpPages(pages) {
|
|
357
|
+
return pages.map(({ relatedInput, ...page }) => {
|
|
358
|
+
const related = normalizeDocsRelated(relatedInput);
|
|
359
|
+
return related.length > 0 ? {
|
|
360
|
+
...page,
|
|
361
|
+
related
|
|
362
|
+
} : page;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
355
365
|
function buildNavigationTreeFromPages(pages, siteTitle, ordering) {
|
|
356
366
|
const bySlug = new Map(pages.map((page) => [page.slug, page]));
|
|
357
367
|
const rootPage = bySlug.get("");
|
|
@@ -465,7 +475,8 @@ function toSearchSourcePages(pages) {
|
|
|
465
475
|
agentRawContent: page.agentRawContent,
|
|
466
476
|
agentFallbackContent: page.agentFallbackContent,
|
|
467
477
|
agentFallbackRawContent: page.agentFallbackRawContent,
|
|
468
|
-
description: page.description
|
|
478
|
+
description: page.description,
|
|
479
|
+
related: page.related
|
|
469
480
|
}));
|
|
470
481
|
}
|
|
471
482
|
function isSelfMcpSearchEndpoint(search, route) {
|
|
@@ -522,8 +533,10 @@ function normalizeUrlPath(value) {
|
|
|
522
533
|
}
|
|
523
534
|
function renderPageDocument(page) {
|
|
524
535
|
if (page.agentRawContent !== void 0) return page.agentRawContent;
|
|
536
|
+
const relatedLines = renderDocsRelatedMarkdownLines(page.related);
|
|
525
537
|
const lines = [`# ${page.title}`, `URL: ${page.url}`];
|
|
526
538
|
if (page.description) lines.push(`Description: ${page.description}`);
|
|
539
|
+
lines.push(...relatedLines);
|
|
527
540
|
lines.push("", page.agentFallbackRawContent ?? page.rawContent ?? page.content);
|
|
528
541
|
return lines.join("\n");
|
|
529
542
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as McpDocsSearchConfig, C as DocsSearchAdapter, D as DocsSearchConfig, E as DocsSearchChunkingConfig, N as DocsSearchSourcePage, O as DocsSearchDocument, T as DocsSearchAdapterFactory, at as TypesenseDocsSearchConfig, d as CustomDocsSearchConfig, j as DocsSearchResult, r as AlgoliaDocsSearchConfig } from "./types-CP2NmW5c.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/search.d.ts
|
|
4
4
|
declare function buildDocsSearchDocuments(pages: DocsSearchSourcePage[], chunking?: DocsSearchChunkingConfig): DocsSearchDocument[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, t as buildDocsSearchDocuments } from "./search-
|
|
1
|
+
import { n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, t as buildDocsSearchDocuments } from "./search-CfnJVeh-.mjs";
|
|
2
2
|
import "./api-reference-BQ16eRPP.mjs";
|
|
3
3
|
import { createFilesystemDocsMcpSource } from "./mcp.mjs";
|
|
4
4
|
import "./server.mjs";
|
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
//#region src/related.ts
|
|
2
|
+
function normalizeDocsRelated(value) {
|
|
3
|
+
if (!Array.isArray(value)) return [];
|
|
4
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5
|
+
const links = [];
|
|
6
|
+
for (const item of value) {
|
|
7
|
+
const parsed = parseRelatedInput(item);
|
|
8
|
+
if (!parsed) continue;
|
|
9
|
+
const dedupeKey = normalizeRelatedLookupPath(parsed.href) ?? parsed.href;
|
|
10
|
+
if (seen.has(dedupeKey)) continue;
|
|
11
|
+
seen.add(dedupeKey);
|
|
12
|
+
links.push({ href: parsed.href });
|
|
13
|
+
}
|
|
14
|
+
return links;
|
|
15
|
+
}
|
|
16
|
+
function renderDocsRelatedMarkdownLines(related) {
|
|
17
|
+
if (!related?.length) return [];
|
|
18
|
+
return [`Related: ${related.map((link) => normalizeInlineText(link.href)).join(", ")}`];
|
|
19
|
+
}
|
|
20
|
+
function parseRelatedInput(value) {
|
|
21
|
+
if (typeof value === "string") {
|
|
22
|
+
const href = cleanString(value);
|
|
23
|
+
return href ? { href } : null;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function cleanString(value) {
|
|
28
|
+
if (typeof value !== "string") return void 0;
|
|
29
|
+
return value.trim() || void 0;
|
|
30
|
+
}
|
|
31
|
+
function normalizeRelatedLookupPath(value) {
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
if (!trimmed) return null;
|
|
34
|
+
let pathname = trimmed;
|
|
35
|
+
try {
|
|
36
|
+
pathname = new URL(trimmed, "https://docs.local").pathname;
|
|
37
|
+
} catch {
|
|
38
|
+
pathname = trimmed.split(/[?#]/, 1)[0] ?? trimmed;
|
|
39
|
+
}
|
|
40
|
+
pathname = pathname.replace(/\/+/g, "/").replace(/\.md$/i, "");
|
|
41
|
+
if (!pathname.startsWith("/")) pathname = `/${pathname}`;
|
|
42
|
+
if (pathname !== "/") pathname = pathname.replace(/\/+$/, "");
|
|
43
|
+
return pathname;
|
|
44
|
+
}
|
|
45
|
+
function normalizeInlineText(value) {
|
|
46
|
+
return value.replace(/\s+/g, " ").trim();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
1
50
|
//#region src/search.ts
|
|
2
51
|
const DEFAULT_SEARCH_LIMIT = 10;
|
|
3
52
|
const DEFAULT_MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
@@ -668,4 +717,4 @@ function createCustomSearchAdapter(adapter) {
|
|
|
668
717
|
}
|
|
669
718
|
|
|
670
719
|
//#endregion
|
|
671
|
-
export { createSimpleSearchAdapter as a, resolveSearchRequestConfig as c, createMcpSearchAdapter as i, createAlgoliaSearchAdapter as n, createTypesenseSearchAdapter as o, createCustomSearchAdapter as r, performDocsSearch as s, buildDocsSearchDocuments as t };
|
|
720
|
+
export { createSimpleSearchAdapter as a, resolveSearchRequestConfig as c, createMcpSearchAdapter as i, normalizeDocsRelated as l, createAlgoliaSearchAdapter as n, createTypesenseSearchAdapter as o, createCustomSearchAdapter as r, performDocsSearch as s, buildDocsSearchDocuments as t, renderDocsRelatedMarkdownLines as u };
|
package/dist/server.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments } from "./search-zClNrbqL.mjs";
|
|
1
|
+
import { A as DocsSearchQuery, B as McpDocsSearchConfig, C as DocsSearchAdapter, D as DocsSearchConfig, N as DocsSearchSourcePage, O as DocsSearchDocument, T as DocsSearchAdapterFactory, a as ApiReferenceRenderer, j as DocsSearchResult, m as DocsConfig, w as DocsSearchAdapterContext } from "./types-CP2NmW5c.mjs";
|
|
3
2
|
import { DocsMcpHttpHandlers, DocsMcpNavigationNode, DocsMcpNavigationTree, DocsMcpPage, DocsMcpResolvedConfig, DocsMcpSource, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio } from "./mcp.mjs";
|
|
3
|
+
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments } from "./search-BWqFW9rt.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/api-reference.d.ts
|
|
6
6
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS" | "HEAD";
|
package/dist/server.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments } from "./search-
|
|
1
|
+
import { a as createSimpleSearchAdapter, c as resolveSearchRequestConfig, i as createMcpSearchAdapter, n as createAlgoliaSearchAdapter, o as createTypesenseSearchAdapter, r as createCustomSearchAdapter, s as performDocsSearch, t as buildDocsSearchDocuments } from "./search-CfnJVeh-.mjs";
|
|
2
2
|
import { a as buildApiReferencePageTitle, c as resolveApiReferenceRenderer, i as buildApiReferenceOpenApiDocumentAsync, n as buildApiReferenceHtmlDocumentAsync, o as buildApiReferenceScalarCss, r as buildApiReferenceOpenApiDocument, s as resolveApiReferenceConfig, t as buildApiReferenceHtmlDocument } from "./api-reference-BQ16eRPP.mjs";
|
|
3
3
|
import { createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio } from "./mcp.mjs";
|
|
4
4
|
|
|
@@ -242,9 +242,15 @@ interface PageTwitter {
|
|
|
242
242
|
title?: string;
|
|
243
243
|
description?: string;
|
|
244
244
|
}
|
|
245
|
+
type DocsRelatedItem = string;
|
|
246
|
+
interface ResolvedDocsRelatedLink {
|
|
247
|
+
href: string;
|
|
248
|
+
}
|
|
245
249
|
interface PageFrontmatter {
|
|
246
250
|
title: string;
|
|
247
251
|
description?: string;
|
|
252
|
+
/** Related doc URLs rendered into machine-readable markdown routes and MCP page output. */
|
|
253
|
+
related?: DocsRelatedItem[];
|
|
248
254
|
tags?: string[];
|
|
249
255
|
icon?: string;
|
|
250
256
|
/** Path to custom OG image for this page (shorthand). Ignored if `openGraph` is set. */
|
|
@@ -590,7 +596,7 @@ interface DocsMcpToolsConfig {
|
|
|
590
596
|
* Built-in MCP server configuration.
|
|
591
597
|
*
|
|
592
598
|
* When enabled, adapters can expose a Streamable HTTP endpoint for your docs
|
|
593
|
-
* at `/mcp` and `/.well-known/mcp
|
|
599
|
+
* at `/mcp` and `/.well-known/mcp`, backed by the canonical `/api/docs/mcp` route.
|
|
594
600
|
* The same config is also reused by the local `docs mcp` stdio command.
|
|
595
601
|
*/
|
|
596
602
|
interface DocsMcpConfig {
|
|
@@ -598,7 +604,7 @@ interface DocsMcpConfig {
|
|
|
598
604
|
enabled?: boolean;
|
|
599
605
|
/**
|
|
600
606
|
* Streamable HTTP route for the MCP endpoint.
|
|
601
|
-
* Defaults to `/api/docs/mcp`;
|
|
607
|
+
* Defaults to `/api/docs/mcp`; generated projects can also expose it publicly at `/mcp` and `/.well-known/mcp`.
|
|
602
608
|
*/
|
|
603
609
|
route?: string;
|
|
604
610
|
/**
|
|
@@ -620,6 +626,7 @@ interface DocsSearchSourcePage {
|
|
|
620
626
|
url: string;
|
|
621
627
|
content: string;
|
|
622
628
|
description?: string;
|
|
629
|
+
related?: ResolvedDocsRelatedLink[];
|
|
623
630
|
rawContent?: string;
|
|
624
631
|
agentContent?: string;
|
|
625
632
|
agentRawContent?: string;
|
|
@@ -1592,8 +1599,8 @@ interface DocsConfig {
|
|
|
1592
1599
|
/**
|
|
1593
1600
|
* Built-in MCP server for agent/assistant access to your docs content.
|
|
1594
1601
|
*
|
|
1595
|
-
* - omitted → enable the default MCP surface at `/mcp` and `/.well-known/mcp
|
|
1596
|
-
* - `true` → enable the default MCP surface at `/mcp` and `/.well-known/mcp
|
|
1602
|
+
* - omitted → enable the default MCP surface at `/mcp` and `/.well-known/mcp`, backed by `/api/docs/mcp`
|
|
1603
|
+
* - `true` → enable the default MCP surface at `/mcp` and `/.well-known/mcp`, backed by `/api/docs/mcp`
|
|
1597
1604
|
* - `{ route: "/api/docs/mcp" }` → enable with explicit route/config
|
|
1598
1605
|
* - `false` or `{ enabled: false }` → disable MCP explicitly
|
|
1599
1606
|
*/
|
|
@@ -1811,4 +1818,4 @@ interface DocsConfig {
|
|
|
1811
1818
|
og?: OGConfig;
|
|
1812
1819
|
}
|
|
1813
1820
|
//#endregion
|
|
1814
|
-
export {
|
|
1821
|
+
export { SidebarFolderNode as $, DocsSearchQuery as A, McpDocsSearchConfig as B, DocsSearchAdapter as C, DocsSearchConfig as D, DocsSearchChunkingConfig as E, FeedbackConfig as F, OrderingItem as G, OpenDocsConfig as H, FontStyle as I, PageOpenGraph as J, PageActionsConfig as K, GithubConfig as L, DocsSearchResultType as M, DocsSearchSourcePage as N, DocsSearchDocument as O, DocsTheme as P, SidebarConfig as Q, LastUpdatedConfig as R, DocsRelatedItem as S, DocsSearchAdapterFactory as T, OpenDocsProvider as U, OGConfig as V, OpenGraphImage as W, ResolvedDocsRelatedLink as X, PageTwitter as Y, SidebarComponentProps as Z, DocsI18nConfig as _, ApiReferenceRenderer as a, TypesenseDocsSearchConfig as at, DocsMetadata as b, ChangelogFrontmatter as c, CustomDocsSearchConfig as d, SidebarNode as et, DocsAgentFeedbackContext as f, DocsFeedbackValue as g, DocsFeedbackData as h, ApiReferenceConfig as i, ThemeToggleConfig as it, DocsSearchResult as j, DocsSearchEmbeddingsConfig as k, CodeBlockCopyData as l, DocsConfig as m, AgentFeedbackConfig as n, SidebarTree as nt, BreadcrumbConfig as o, TypographyConfig as ot, DocsAgentFeedbackData as p, PageFrontmatter as q, AlgoliaDocsSearchConfig as r, SimpleDocsSearchConfig as rt, ChangelogConfig as s, UIConfig as st, AIConfig as t, SidebarPageNode as tt, CopyMarkdownConfig as u, DocsMcpConfig as v, DocsSearchAdapterContext as w, DocsNav as x, DocsMcpToolsConfig as y, LlmsTxtConfig as z };
|