@farming-labs/theme 0.2.58 → 0.2.60
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/bounded-route-cache.mjs +40 -0
- package/dist/docs-api.d.mts +7 -2
- package/dist/docs-api.mjs +239 -75
- package/dist/search.d.mts +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/bounded-route-cache.ts
|
|
2
|
+
/**
|
|
3
|
+
* A small per-locale LRU cache for request-derived route variants.
|
|
4
|
+
*
|
|
5
|
+
* Locales come from the configured i18n locale list, while routes can be
|
|
6
|
+
* inferred from request URLs. Bounding each locale prevents arbitrary request
|
|
7
|
+
* paths from growing the cache indefinitely.
|
|
8
|
+
*/
|
|
9
|
+
var BoundedRouteCache = class {
|
|
10
|
+
entries = /* @__PURE__ */ new Map();
|
|
11
|
+
constructor(maxRoutesPerLocale) {
|
|
12
|
+
this.maxRoutesPerLocale = maxRoutesPerLocale;
|
|
13
|
+
if (!Number.isInteger(maxRoutesPerLocale) || maxRoutesPerLocale < 1) throw new RangeError("maxRoutesPerLocale must be a positive integer");
|
|
14
|
+
}
|
|
15
|
+
get(locale, route) {
|
|
16
|
+
const routes = this.entries.get(locale);
|
|
17
|
+
if (!routes?.has(route)) return void 0;
|
|
18
|
+
const value = routes.get(route);
|
|
19
|
+
routes.delete(route);
|
|
20
|
+
routes.set(route, value);
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
set(locale, route, value) {
|
|
24
|
+
let routes = this.entries.get(locale);
|
|
25
|
+
if (!routes) {
|
|
26
|
+
routes = /* @__PURE__ */ new Map();
|
|
27
|
+
this.entries.set(locale, routes);
|
|
28
|
+
}
|
|
29
|
+
routes.delete(route);
|
|
30
|
+
routes.set(route, value);
|
|
31
|
+
while (routes.size > this.maxRoutesPerLocale) {
|
|
32
|
+
const oldestRoute = routes.keys().next().value;
|
|
33
|
+
if (oldestRoute === void 0) break;
|
|
34
|
+
routes.delete(oldestRoute);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { BoundedRouteCache };
|
package/dist/docs-api.d.mts
CHANGED
|
@@ -34,6 +34,8 @@ interface AIOptions {
|
|
|
34
34
|
}
|
|
35
35
|
interface DocsAPIOptions {
|
|
36
36
|
rootDir?: string;
|
|
37
|
+
/** Internal docs API route used by query-form discovery endpoints. */
|
|
38
|
+
apiRoute?: string;
|
|
37
39
|
/** Docs entry folder (default: read from docs.config) */
|
|
38
40
|
entry?: string;
|
|
39
41
|
/** Public docs route prefix. Defaults to the docs entry path. */
|
|
@@ -66,6 +68,8 @@ interface DocsAPIOptions {
|
|
|
66
68
|
mcp?: boolean | DocsMcpConfig;
|
|
67
69
|
/** llms.txt configuration. Enabled by default; set false to opt out. */
|
|
68
70
|
llmsTxt?: boolean | LlmsTxtOptions;
|
|
71
|
+
/** Override RFC 9727 API catalog discovery without disabling Agent Skills discovery. */
|
|
72
|
+
apiCatalog?: boolean;
|
|
69
73
|
/** Sitemap configuration used for sitemap.xml, sitemap.md, and docs/sitemap.md. */
|
|
70
74
|
sitemap?: boolean | DocsSitemapConfig;
|
|
71
75
|
/** Robots.txt generation policy used for the agent discovery spec. */
|
|
@@ -93,7 +97,7 @@ type LlmsTxtOptions = LlmsTxtConfig;
|
|
|
93
97
|
/**
|
|
94
98
|
* Create a unified docs API route handler.
|
|
95
99
|
*
|
|
96
|
-
* Returns `{ GET, POST }` for use in a Next.js route handler:
|
|
100
|
+
* Returns `{ GET, HEAD, POST }` for use in a Next.js route handler:
|
|
97
101
|
* - **GET ?query=…** → full-text search
|
|
98
102
|
* - **GET ?format=llms** → llms.txt (concise page listing)
|
|
99
103
|
* - **GET ?format=llms-full** → llms-full.txt (full page content)
|
|
@@ -104,7 +108,7 @@ type LlmsTxtOptions = LlmsTxtConfig;
|
|
|
104
108
|
* ```ts
|
|
105
109
|
* // app/api/docs/route.ts (auto-generated by withDocs)
|
|
106
110
|
* import { createDocsAPI } from "@farming-labs/next/api";
|
|
107
|
-
* export const { GET, POST } = createDocsAPI();
|
|
111
|
+
* export const { GET, HEAD, POST } = createDocsAPI();
|
|
108
112
|
* export const revalidate = false;
|
|
109
113
|
* ```
|
|
110
114
|
*
|
|
@@ -115,6 +119,7 @@ type LlmsTxtOptions = LlmsTxtConfig;
|
|
|
115
119
|
* The `@farming-labs/theme/api` path is kept for compatibility and will be phased out.
|
|
116
120
|
*/
|
|
117
121
|
declare function createDocsAPI(options?: DocsAPIOptions): {
|
|
122
|
+
HEAD(request: Request): Promise<Response>;
|
|
118
123
|
/**
|
|
119
124
|
* GET handler — search, markdown, llms.txt, llms-full.txt, or skill.md.
|
|
120
125
|
*/
|
package/dist/docs-api.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { withLangInUrl } from "./i18n.mjs";
|
|
2
2
|
import { getNextAppDir } from "./get-app-dir.mjs";
|
|
3
|
+
import { BoundedRouteCache } from "./bounded-route-cache.mjs";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import matter from "gray-matter";
|
|
6
|
-
import { DEFAULT_SITEMAP_MD_DOCS_ROUTE, acceptsDocsMarkdown, buildDocsAskAIContext, buildDocsConfigMap, buildDocsDiagnostics, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsMarkdownResponse, createDocsRobotsResponse, createDocsSitemapResponse, detectDocsMarkdownAgentRequest, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, emitDocsTelemetryAgentSurfaceEvent, emitDocsTelemetryProjectEvent, formatDocsAskAIPackageHints, getDocsLlmsTxtMaxCharsIssue, hasDocsMarkdownSignatureAgent, inferDocsTelemetryAgentSurface, isDocsConfigRequest, isDocsDiagnosticsRequest, normalizeDocsRelated, normalizePageAgentFrontmatter, performDocsSearch, renderDocsLlmsTxt, renderDocsMarkdownDocument, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsAgentContractMcpTools, resolveDocsAudienceMdxContent, resolveDocsI18n, resolveDocsLlmsTxtRequest, resolveDocsLlmsTxtSections, resolveDocsLocale, resolveDocsMetadataBaseUrl, resolveDocsSitemapConfig, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, selectDocsLlmsTxtContent, stripGeneratedAgentProvenance } from "@farming-labs/docs";
|
|
7
|
+
import { DEFAULT_AGENT_SKILLS_INDEX_ROUTE, DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, DEFAULT_API_CATALOG_ROUTE, DEFAULT_SITEMAP_MD_DOCS_ROUTE, acceptsDocsMarkdown, buildDocsAskAIContext, buildDocsConfigMap, buildDocsDiagnostics, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsMarkdownResponse, createDocsRobotsResponse, createDocsSitemapResponse, createDocsStandardsDiscoveryResponse, detectDocsMarkdownAgentRequest, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, emitDocsTelemetryAgentSurfaceEvent, emitDocsTelemetryProjectEvent, formatDocsAskAIPackageHints, getDocsDiscoveryLinkHeader, getDocsLlmsTxtMaxCharsIssue, hasDocsMarkdownSignatureAgent, inferDocsTelemetryAgentSurface, isDocsConfigRequest, isDocsDiagnosticsRequest, normalizeDocsRelated, normalizePageAgentFrontmatter, performDocsSearch, renderDocsLlmsTxt, renderDocsMarkdownDocument, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsAgentContractMcpTools, resolveDocsAudienceMdxContent, resolveDocsI18n, resolveDocsLlmsTxtRequest, resolveDocsLlmsTxtSections, resolveDocsLocale, resolveDocsMetadataBaseUrl, resolveDocsRequestApiRoute, resolveDocsSitemapConfig, resolveDocsStandardsDiscoveryRequest, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, selectDocsLlmsTxtContent, stripGeneratedAgentProvenance } from "@farming-labs/docs";
|
|
7
8
|
import { buildApiReferenceOpenApiDocumentAsync, createDocsMcpHttpHandler, createFilesystemDocsMcpSource, readDocsSitemapManifest, resolveApiReferenceConfig, resolveDocsMcpConfig } from "@farming-labs/docs/server";
|
|
8
9
|
|
|
9
10
|
//#region src/docs-api.ts
|
|
@@ -24,7 +25,7 @@ import { buildApiReferenceOpenApiDocumentAsync, createDocsMcpHttpHandler, create
|
|
|
24
25
|
* ```ts
|
|
25
26
|
* // app/api/docs/route.ts (auto-generated by withDocs)
|
|
26
27
|
* import { createDocsAPI } from "@farming-labs/next/api";
|
|
27
|
-
* export const { GET, POST } = createDocsAPI();
|
|
28
|
+
* export const { GET, HEAD, POST } = createDocsAPI();
|
|
28
29
|
* export const revalidate = false;
|
|
29
30
|
* ```
|
|
30
31
|
*/
|
|
@@ -35,6 +36,7 @@ const FILE_EXTS = [
|
|
|
35
36
|
"js"
|
|
36
37
|
];
|
|
37
38
|
const DEFAULT_DOCS_API_ROUTE = "/api/docs";
|
|
39
|
+
const MAX_LLMS_CACHE_ROUTES_PER_LOCALE = 8;
|
|
38
40
|
const DEFAULT_DOCS_CLOUD_API_BASE_URL = "https://api.farming-labs.dev";
|
|
39
41
|
const DEFAULT_DOCS_CLOUD_API_KEY_ENV = "DOCS_CLOUD_API_KEY";
|
|
40
42
|
const DEFAULT_AGENT_SPEC_ROUTE = "/api/docs/agent/spec";
|
|
@@ -202,12 +204,13 @@ function resolveApiReferenceOpenApiDiscovery(value) {
|
|
|
202
204
|
return {
|
|
203
205
|
enabled: true,
|
|
204
206
|
url: `${DEFAULT_DOCS_API_ROUTE}?format=openapi`,
|
|
207
|
+
urlSource: "default",
|
|
205
208
|
source: apiReference.specUrl ? "configured" : "generated",
|
|
206
209
|
specUrl: apiReference.specUrl,
|
|
207
210
|
apiReferencePath: `/${apiReference.path}`
|
|
208
211
|
};
|
|
209
212
|
}
|
|
210
|
-
function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, sitemap, robots, openapi }) {
|
|
213
|
+
function buildAgentSpec({ origin, entry, apiRoute, apiCatalog, i18n, search, mcp, feedback, llms, sitemap, robots, openapi }) {
|
|
211
214
|
const normalizedEntry = normalizePathSegment(entry) || "docs";
|
|
212
215
|
const localesEnabled = i18n !== null;
|
|
213
216
|
const searchEnabled = isSearchEnabled(search);
|
|
@@ -215,6 +218,7 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
215
218
|
const robotsEnabled = isRobotsDiscoveryEnabled(robots);
|
|
216
219
|
const llmsSections = resolveDocsLlmsTxtSections(llms);
|
|
217
220
|
const agentContractMcpTools = resolveDocsAgentContractMcpTools(mcp);
|
|
221
|
+
const agentSpecRoute = apiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : `${apiRoute}?agent=spec`;
|
|
218
222
|
return {
|
|
219
223
|
version: "1",
|
|
220
224
|
name: "@farming-labs/docs",
|
|
@@ -247,32 +251,46 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
247
251
|
structuredData: true,
|
|
248
252
|
apiReference: openapi.enabled,
|
|
249
253
|
openapi: openapi.enabled,
|
|
254
|
+
apiCatalog,
|
|
255
|
+
agentSkillsDiscovery: true,
|
|
250
256
|
agentFeedback: feedback.enabled,
|
|
251
257
|
locales: localesEnabled
|
|
252
258
|
},
|
|
253
259
|
api: {
|
|
254
|
-
docs:
|
|
255
|
-
config: `${
|
|
256
|
-
diagnostics: `${
|
|
257
|
-
agentSpec:
|
|
260
|
+
docs: apiRoute,
|
|
261
|
+
config: `${apiRoute}?format=config`,
|
|
262
|
+
diagnostics: `${apiRoute}?format=diagnostics`,
|
|
263
|
+
agentSpec: agentSpecRoute,
|
|
258
264
|
agentSpecDefault: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
|
|
259
265
|
agentSpecFallback: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
|
|
260
266
|
agentSpecWellKnown: DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE,
|
|
261
267
|
agentSpecWellKnownJson: DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE,
|
|
262
|
-
agentSpecQuery: `${
|
|
263
|
-
agents: `${
|
|
264
|
-
openapi: `${
|
|
268
|
+
agentSpecQuery: `${apiRoute}?agent=spec`,
|
|
269
|
+
agents: `${apiRoute}?format=agents`,
|
|
270
|
+
openapi: `${apiRoute}?format=openapi`,
|
|
271
|
+
...apiCatalog ? {
|
|
272
|
+
apiCatalog: DEFAULT_API_CATALOG_ROUTE,
|
|
273
|
+
apiCatalogQuery: `${apiRoute}?format=api-catalog`
|
|
274
|
+
} : {},
|
|
275
|
+
agentSkillsIndex: DEFAULT_AGENT_SKILLS_INDEX_ROUTE
|
|
276
|
+
},
|
|
277
|
+
apiCatalog: {
|
|
278
|
+
enabled: apiCatalog,
|
|
279
|
+
route: apiCatalog ? DEFAULT_API_CATALOG_ROUTE : null,
|
|
280
|
+
api: apiCatalog ? `${apiRoute}?format=api-catalog` : null,
|
|
281
|
+
mediaType: "application/linkset+json",
|
|
282
|
+
profile: "https://www.rfc-editor.org/info/rfc9727"
|
|
265
283
|
},
|
|
266
284
|
config: {
|
|
267
285
|
format: "docs-config-map.v1",
|
|
268
|
-
endpoint: `${
|
|
286
|
+
endpoint: `${apiRoute}?format=config`
|
|
269
287
|
},
|
|
270
288
|
markdown: {
|
|
271
289
|
enabled: true,
|
|
272
290
|
acceptHeader: "text/markdown",
|
|
273
291
|
pagePattern: `/${normalizedEntry}/{slug}.md`,
|
|
274
292
|
rootPage: `/${normalizedEntry}.md`,
|
|
275
|
-
apiPattern: `${
|
|
293
|
+
apiPattern: `${apiRoute}?format=markdown&path={slug}`,
|
|
276
294
|
resolutionOrder: [
|
|
277
295
|
"agent.md",
|
|
278
296
|
"agent audience projection",
|
|
@@ -310,8 +328,8 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
310
328
|
enabled: llms.enabled,
|
|
311
329
|
defaultTxt: DEFAULT_LLMS_TXT_ROUTE,
|
|
312
330
|
defaultFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
|
|
313
|
-
txt: `${
|
|
314
|
-
full: `${
|
|
331
|
+
txt: `${apiRoute}?format=llms`,
|
|
332
|
+
full: `${apiRoute}?format=llms-full`,
|
|
315
333
|
publicTxt: DEFAULT_LLMS_TXT_ROUTE,
|
|
316
334
|
publicFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
|
|
317
335
|
wellKnownTxt: DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
|
|
@@ -329,14 +347,14 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
329
347
|
xml: {
|
|
330
348
|
enabled: sitemapConfig.xml.enabled,
|
|
331
349
|
route: sitemapConfig.xml.route,
|
|
332
|
-
api: `${
|
|
350
|
+
api: `${apiRoute}?format=sitemap-xml`
|
|
333
351
|
},
|
|
334
352
|
markdown: {
|
|
335
353
|
enabled: sitemapConfig.markdown.enabled,
|
|
336
354
|
route: sitemapConfig.markdown.route,
|
|
337
355
|
docsRoute: sitemapConfig.markdown.docsRoute,
|
|
338
356
|
wellKnownRoute: sitemapConfig.markdown.wellKnownRoute,
|
|
339
|
-
api: `${
|
|
357
|
+
api: `${apiRoute}?format=sitemap-md`,
|
|
340
358
|
defaultDocsRoute: DEFAULT_SITEMAP_MD_DOCS_ROUTE
|
|
341
359
|
}
|
|
342
360
|
},
|
|
@@ -363,7 +381,7 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
363
381
|
},
|
|
364
382
|
openapi: {
|
|
365
383
|
enabled: openapi.enabled,
|
|
366
|
-
url: openapi.
|
|
384
|
+
url: openapi.enabled ? `${apiRoute}?format=openapi` : null,
|
|
367
385
|
source: openapi.source ?? null,
|
|
368
386
|
specUrl: openapi.specUrl ?? null,
|
|
369
387
|
apiReferencePath: openapi.apiReferencePath ?? null,
|
|
@@ -371,7 +389,7 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
371
389
|
},
|
|
372
390
|
search: {
|
|
373
391
|
enabled: searchEnabled,
|
|
374
|
-
endpoint: `${
|
|
392
|
+
endpoint: `${apiRoute}?query={query}`,
|
|
375
393
|
method: "GET",
|
|
376
394
|
queryParam: "query",
|
|
377
395
|
localeParam: "lang"
|
|
@@ -381,7 +399,7 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
381
399
|
file: "AGENTS.md",
|
|
382
400
|
route: DEFAULT_AGENTS_MD_ROUTE,
|
|
383
401
|
wellKnown: DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE,
|
|
384
|
-
api: `${
|
|
402
|
+
api: `${apiRoute}?format=agents`,
|
|
385
403
|
generatedFallback: true,
|
|
386
404
|
aliases: [DEFAULT_AGENT_MD_ROUTE, DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE]
|
|
387
405
|
},
|
|
@@ -390,8 +408,16 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
390
408
|
file: "skill.md",
|
|
391
409
|
route: DEFAULT_SKILL_MD_ROUTE,
|
|
392
410
|
wellKnown: DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE,
|
|
393
|
-
api: `${
|
|
411
|
+
api: `${apiRoute}?format=skill`,
|
|
394
412
|
generatedFallback: true,
|
|
413
|
+
discovery: {
|
|
414
|
+
schema: "https://schemas.agentskills.io/discovery/0.2.0/schema.json",
|
|
415
|
+
index: DEFAULT_AGENT_SKILLS_INDEX_ROUTE,
|
|
416
|
+
artifact: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/{name}/SKILL.md`,
|
|
417
|
+
apiIndex: `${apiRoute}?format=agent-skills`,
|
|
418
|
+
apiArtifact: `${apiRoute}?format=agent-skill&name={name}`,
|
|
419
|
+
digest: "sha256"
|
|
420
|
+
},
|
|
395
421
|
registry: "skills.sh",
|
|
396
422
|
install: "npx skills add farming-labs/docs",
|
|
397
423
|
recommended: [{
|
|
@@ -415,8 +441,8 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
|
|
|
415
441
|
enabled: feedback.enabled,
|
|
416
442
|
schema: feedback.schemaRoute,
|
|
417
443
|
submit: feedback.route,
|
|
418
|
-
schemaQuery: `${
|
|
419
|
-
submitQuery: `${
|
|
444
|
+
schemaQuery: `${apiRoute}?feedback=agent&schema=1`,
|
|
445
|
+
submitQuery: `${apiRoute}?feedback=agent`
|
|
420
446
|
},
|
|
421
447
|
instructions: {
|
|
422
448
|
preferMarkdownRoutes: true,
|
|
@@ -618,9 +644,14 @@ function readCloudConfig(root) {
|
|
|
618
644
|
const configObject = extractRootConfigObject(content, sanitized);
|
|
619
645
|
const cloudBlock = extractObjectLiteral(configObject?.content ?? content, configObject?.sanitized ?? sanitized, "cloud");
|
|
620
646
|
if (!cloudBlock) continue;
|
|
621
|
-
const
|
|
647
|
+
const cloudBlockSanitized = stripCommentsAndStrings(cloudBlock);
|
|
648
|
+
const apiKeyBlock = extractObjectLiteral(cloudBlock, cloudBlockSanitized, "apiKey");
|
|
622
649
|
const apiKeyEnv = apiKeyBlock ? readStringFromBlock(apiKeyBlock, "env") : void 0;
|
|
623
|
-
|
|
650
|
+
const apiRoute = readTopLevelString(cloudBlock, cloudBlockSanitized, "apiRoute");
|
|
651
|
+
return {
|
|
652
|
+
...apiKeyEnv ? { apiKey: { env: apiKeyEnv } } : {},
|
|
653
|
+
...apiRoute ? { apiRoute } : {}
|
|
654
|
+
};
|
|
624
655
|
} catch {}
|
|
625
656
|
}
|
|
626
657
|
}
|
|
@@ -702,6 +733,14 @@ function readTopLevelBoolean(content, key) {
|
|
|
702
733
|
if (!match) return void 0;
|
|
703
734
|
return match[1] === "true";
|
|
704
735
|
}
|
|
736
|
+
function readTopLevelString(content, sanitized, key) {
|
|
737
|
+
const keyIndex = findTopLevelPropertyIndex(sanitized, key);
|
|
738
|
+
if (keyIndex === -1) return void 0;
|
|
739
|
+
const colonIndex = sanitized.indexOf(":", keyIndex + key.length);
|
|
740
|
+
if (colonIndex === -1) return void 0;
|
|
741
|
+
const match = content.slice(colonIndex + 1).match(/^\s*(?:"([^"]*)"|'([^']*)')/s);
|
|
742
|
+
return match?.[1] ?? match?.[2];
|
|
743
|
+
}
|
|
705
744
|
function findTopLevelPropertyIndex(content, key) {
|
|
706
745
|
let depth = 0;
|
|
707
746
|
for (let index = 0; index < content.length; index += 1) {
|
|
@@ -726,11 +765,11 @@ function findTopLevelPropertyIndex(content, key) {
|
|
|
726
765
|
return -1;
|
|
727
766
|
}
|
|
728
767
|
function extractRootConfigObject(content, sanitized) {
|
|
729
|
-
const defineDocsIndex = sanitized.
|
|
768
|
+
const defineDocsIndex = sanitized.match(/\bdefineDocs\s*\(/)?.index ?? -1;
|
|
730
769
|
const exportDefaultIndex = sanitized.indexOf("export default");
|
|
731
770
|
let braceStart = -1;
|
|
732
771
|
if (defineDocsIndex !== -1) {
|
|
733
|
-
const parenIndex = sanitized.indexOf("(", defineDocsIndex);
|
|
772
|
+
const parenIndex = sanitized.indexOf("(", defineDocsIndex + 10);
|
|
734
773
|
if (parenIndex !== -1) braceStart = sanitized.indexOf("{", parenIndex);
|
|
735
774
|
}
|
|
736
775
|
if (braceStart === -1 && exportDefaultIndex !== -1) braceStart = sanitized.indexOf("{", exportDefaultIndex);
|
|
@@ -1005,6 +1044,10 @@ function normalizeUrlPath(value) {
|
|
|
1005
1044
|
if (normalized === "/") return normalized;
|
|
1006
1045
|
return normalized.replace(/\/+$/, "");
|
|
1007
1046
|
}
|
|
1047
|
+
function normalizeDocsApiRoute(value) {
|
|
1048
|
+
const route = value?.trim().split(/[?#]/, 1)[0] || DEFAULT_DOCS_API_ROUTE;
|
|
1049
|
+
return normalizeUrlPath(route.startsWith("/") ? route : `/${route}`);
|
|
1050
|
+
}
|
|
1008
1051
|
function normalizeRequestedMarkdownPath(entry, requestedPath) {
|
|
1009
1052
|
const trimmed = requestedPath.trim().replace(/\.md$/i, "");
|
|
1010
1053
|
if (!trimmed) return `/${entry}`;
|
|
@@ -1186,13 +1229,15 @@ function renderMarkdownDocument(page, options = {}) {
|
|
|
1186
1229
|
sitemap: options.sitemap
|
|
1187
1230
|
});
|
|
1188
1231
|
}
|
|
1189
|
-
function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitemap, robots, openapi }) {
|
|
1232
|
+
function renderSkillDocument({ origin, entry, apiRoute, apiCatalog, search, mcp, feedback, llms, sitemap, robots, openapi }) {
|
|
1190
1233
|
const normalizedEntry = normalizePathSegment(entry) || "docs";
|
|
1191
1234
|
const siteTitle = compactSkillText(llms.siteTitle ?? "Documentation");
|
|
1192
1235
|
const siteDescription = llms.siteDescription ? compactSkillText(llms.siteDescription) : void 0;
|
|
1193
1236
|
const searchEnabled = isSearchEnabled(search);
|
|
1194
1237
|
const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
|
|
1195
1238
|
const robotsEnabled = isRobotsDiscoveryEnabled(robots);
|
|
1239
|
+
const agentSpecRoute = apiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : `${apiRoute}?agent=spec`;
|
|
1240
|
+
const openapiUrl = openapi.urlSource === "default" && openapi.url === `${DEFAULT_DOCS_API_ROUTE}?format=openapi` ? `${apiRoute}?format=openapi` : openapi.url;
|
|
1196
1241
|
const llmsSections = resolveDocsLlmsTxtSections(llms);
|
|
1197
1242
|
const lines = [
|
|
1198
1243
|
"---",
|
|
@@ -1205,9 +1250,11 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
|
|
|
1205
1250
|
`Base URL: ${origin}`
|
|
1206
1251
|
];
|
|
1207
1252
|
if (siteDescription) lines.push(`Description: ${siteDescription}`);
|
|
1208
|
-
lines.push("", "## When To Use", "Use this skill when you need to read or implement against this documentation site.", "", "## Start Here", `- Fetch ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${
|
|
1209
|
-
if (
|
|
1210
|
-
|
|
1253
|
+
lines.push("", "## When To Use", "Use this skill when you need to read or implement against this documentation site.", "", "## Start Here", `- Fetch ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${agentSpecRoute}.`);
|
|
1254
|
+
if (apiCatalog) lines.push(`- Fetch ${DEFAULT_API_CATALOG_ROUTE} for the standards-based API catalog.`);
|
|
1255
|
+
lines.push(`- Fetch ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE} to discover the published site skill and verify its SHA-256 digest.`, `- Fetch /${normalizedEntry}.md for the root docs page.`, `- Fetch /${normalizedEntry}/{slug}.md for page-specific context.`, "- You can also request text/markdown from normal page URLs.");
|
|
1256
|
+
if (searchEnabled) lines.push(`- Search with ${apiRoute}?query={query} when you do not know the page.`);
|
|
1257
|
+
if (openapi.enabled && openapiUrl) lines.push(`- Fetch ${openapiUrl} for the machine-readable OpenAPI schema before scraping API reference pages.`);
|
|
1211
1258
|
if (llms.enabled) {
|
|
1212
1259
|
lines.push(`- Use ${DEFAULT_LLMS_TXT_ROUTE} for a compact docs index.`, `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} for full markdown context.`);
|
|
1213
1260
|
for (const section of llmsSections) lines.push(`- Use ${section.route} for the ${section.title} llms.txt section.`);
|
|
@@ -1219,7 +1266,9 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
|
|
|
1219
1266
|
if (robotsEnabled) lines.push(`- Check ${DEFAULT_ROBOTS_TXT_ROUTE} for crawler and AI-agent access policy.`);
|
|
1220
1267
|
if (mcp.enabled) lines.push(`- Use ${DEFAULT_MCP_WELL_KNOWN_ROUTE} or ${DEFAULT_MCP_PUBLIC_ROUTE} for MCP tools when your environment supports MCP.`);
|
|
1221
1268
|
if (feedback.enabled) lines.push(`- Read ${feedback.schemaRoute} before posting agent feedback to ${feedback.route}.`);
|
|
1222
|
-
lines.push("", "## Routes", `- Agent instructions: ${DEFAULT_AGENTS_MD_ROUTE}`, `- Agent instructions well-known alias: ${DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE}`, `- Agent instructions API format: ${
|
|
1269
|
+
lines.push("", "## Routes", `- Agent instructions: ${DEFAULT_AGENTS_MD_ROUTE}`, `- Agent instructions well-known alias: ${DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE}`, `- Agent instructions API format: ${apiRoute}?format=agents`, `- Skill document: ${DEFAULT_SKILL_MD_ROUTE}`, `- Skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Skill API format: ${apiRoute}?format=skill`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`);
|
|
1270
|
+
if (apiCatalog) lines.push(`- API catalog: ${DEFAULT_API_CATALOG_ROUTE}`);
|
|
1271
|
+
lines.push(`- Agent Skills index: ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE}`, `- Agent Skills artifacts: ${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/{name}/SKILL.md`, `- Markdown root: /${normalizedEntry}.md`, `- Markdown pages: /${normalizedEntry}/{slug}.md`);
|
|
1223
1272
|
if (robotsEnabled) lines.push(`- Robots policy: ${DEFAULT_ROBOTS_TXT_ROUTE}`);
|
|
1224
1273
|
if (llms.enabled) {
|
|
1225
1274
|
lines.push(`- llms.txt: ${DEFAULT_LLMS_TXT_ROUTE}`, `- llms-full.txt: ${DEFAULT_LLMS_FULL_TXT_ROUTE}`, `- llms well-known aliases: ${DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE}, ${DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE}`);
|
|
@@ -1228,8 +1277,8 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
|
|
|
1228
1277
|
lines.push(`- ${section.title} llms-full.txt: ${section.fullRoute}`);
|
|
1229
1278
|
}
|
|
1230
1279
|
}
|
|
1231
|
-
if (openapi.enabled &&
|
|
1232
|
-
lines.push(`- OpenAPI schema: ${
|
|
1280
|
+
if (openapi.enabled && openapiUrl) {
|
|
1281
|
+
lines.push(`- OpenAPI schema: ${openapiUrl}`);
|
|
1233
1282
|
if (openapi.apiReferencePath) lines.push(`- API reference: ${openapi.apiReferencePath}`);
|
|
1234
1283
|
}
|
|
1235
1284
|
if (sitemapConfig.enabled) {
|
|
@@ -1240,13 +1289,15 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
|
|
|
1240
1289
|
lines.push("", "## Reusable Framework Skills", "For framework setup, CLI, page actions, Ask AI, or configuration work, install the reusable Farming Labs skills:", "", "```sh", "npx skills add farming-labs/docs", "```");
|
|
1241
1290
|
return lines.join("\n");
|
|
1242
1291
|
}
|
|
1243
|
-
function renderAgentsDocument({ origin, entry, search, mcp, feedback, llms, sitemap, robots, openapi }) {
|
|
1292
|
+
function renderAgentsDocument({ origin, entry, apiRoute, apiCatalog, search, mcp, feedback, llms, sitemap, robots, openapi }) {
|
|
1244
1293
|
const normalizedEntry = normalizePathSegment(entry) || "docs";
|
|
1245
1294
|
const siteTitle = compactSkillText(llms.siteTitle ?? "Documentation");
|
|
1246
1295
|
const siteDescription = llms.siteDescription ? compactSkillText(llms.siteDescription) : void 0;
|
|
1247
1296
|
const searchEnabled = isSearchEnabled(search);
|
|
1248
1297
|
const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
|
|
1249
1298
|
const robotsEnabled = isRobotsDiscoveryEnabled(robots);
|
|
1299
|
+
const agentSpecRoute = apiRoute === DEFAULT_DOCS_API_ROUTE ? DEFAULT_AGENT_SPEC_ROUTE : `${apiRoute}?agent=spec`;
|
|
1300
|
+
const openapiUrl = openapi.urlSource === "default" && openapi.url === `${DEFAULT_DOCS_API_ROUTE}?format=openapi` ? `${apiRoute}?format=openapi` : openapi.url;
|
|
1250
1301
|
const llmsSections = resolveDocsLlmsTxtSections(llms);
|
|
1251
1302
|
const lines = [
|
|
1252
1303
|
"# Agent Instructions",
|
|
@@ -1255,7 +1306,9 @@ function renderAgentsDocument({ origin, entry, search, mcp, feedback, llms, site
|
|
|
1255
1306
|
`Base URL: ${origin}`
|
|
1256
1307
|
];
|
|
1257
1308
|
if (siteDescription) lines.push(`Description: ${siteDescription}`);
|
|
1258
|
-
lines.push("", "## Start Here", `- Read ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE} first; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${
|
|
1309
|
+
lines.push("", "## Start Here", `- Read ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE} first; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${agentSpecRoute}.`);
|
|
1310
|
+
if (apiCatalog) lines.push(`- Read ${DEFAULT_API_CATALOG_ROUTE} for the standards-based API catalog.`);
|
|
1311
|
+
lines.push(`- Read ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE} to discover the published site skill and verify its SHA-256 digest.`, `- Read /${normalizedEntry}.md for the root docs page.`, `- Read /${normalizedEntry}/{slug}.md for page-specific context.`);
|
|
1259
1312
|
if (llms.enabled) {
|
|
1260
1313
|
lines.push(`- Use ${DEFAULT_LLMS_TXT_ROUTE} as the compact docs map.`, `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} when you need the full markdown bundle.`);
|
|
1261
1314
|
for (const section of llmsSections) lines.push(`- Use ${section.route} for the ${section.title} section map.`);
|
|
@@ -1265,11 +1318,13 @@ function renderAgentsDocument({ origin, entry, search, mcp, feedback, llms, site
|
|
|
1265
1318
|
if (sitemapConfig.xml.enabled) lines.push(`- Use ${sitemapConfig.xml.route} for canonical URLs and freshness metadata.`);
|
|
1266
1319
|
}
|
|
1267
1320
|
if (robotsEnabled) lines.push(`- Check ${DEFAULT_ROBOTS_TXT_ROUTE} before crawling broadly.`);
|
|
1268
|
-
if (searchEnabled) lines.push(`- Search with ${
|
|
1269
|
-
if (openapi.enabled &&
|
|
1321
|
+
if (searchEnabled) lines.push(`- Search with ${apiRoute}?query={query} when the route is unknown.`);
|
|
1322
|
+
if (openapi.enabled && openapiUrl) lines.push(`- Fetch ${openapiUrl} before scraping API reference pages; prefer schemas over prose.`);
|
|
1270
1323
|
if (mcp.enabled) lines.push(`- Use MCP at ${DEFAULT_MCP_PUBLIC_ROUTE} or ${DEFAULT_MCP_WELL_KNOWN_ROUTE} when your environment supports MCP tools.`);
|
|
1271
1324
|
if (feedback.enabled) lines.push(`- Read ${feedback.schemaRoute} before posting feedback to ${feedback.route}.`);
|
|
1272
|
-
lines.push("", "## Working Rules", "- Prefer markdown routes, llms.txt, sitemap.md, OpenAPI schemas, and MCP tools over scraping rendered HTML.", "- Treat generated context files as discovery aids, then fetch the smallest page or section that answers the task.", "- Preserve canonical docs URLs when citing pages back to humans.", "- If a route returns a markdown 404, use the sitemap and discovery spec before guessing a slug.", "", "## Public Routes", `- Agent instructions: ${DEFAULT_AGENTS_MD_ROUTE}`, `- Agent instructions well-known alias: ${DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE}`, `- Agent instructions API format: ${
|
|
1325
|
+
lines.push("", "## Working Rules", "- Prefer markdown routes, llms.txt, sitemap.md, OpenAPI schemas, and MCP tools over scraping rendered HTML.", "- Treat generated context files as discovery aids, then fetch the smallest page or section that answers the task.", "- Preserve canonical docs URLs when citing pages back to humans.", "- If a route returns a markdown 404, use the sitemap and discovery spec before guessing a slug.", "", "## Public Routes", `- Agent instructions: ${DEFAULT_AGENTS_MD_ROUTE}`, `- Agent instructions well-known alias: ${DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE}`, `- Agent instructions API format: ${apiRoute}?format=agents`, `- Agent instructions aliases: ${DEFAULT_AGENT_MD_ROUTE}, ${DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE}`, `- Site skill: ${DEFAULT_SKILL_MD_ROUTE}`, `- Site skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Site skill API format: ${apiRoute}?format=skill`, `- Markdown root: /${normalizedEntry}.md`, `- Markdown pages: /${normalizedEntry}/{slug}.md`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`);
|
|
1326
|
+
if (apiCatalog) lines.push(`- API catalog: ${DEFAULT_API_CATALOG_ROUTE}`);
|
|
1327
|
+
lines.push(`- Agent Skills index: ${DEFAULT_AGENT_SKILLS_INDEX_ROUTE}`, `- Agent Skills artifacts: ${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/{name}/SKILL.md`);
|
|
1273
1328
|
if (llms.enabled) {
|
|
1274
1329
|
lines.push(`- llms.txt: ${DEFAULT_LLMS_TXT_ROUTE}`, `- llms-full.txt: ${DEFAULT_LLMS_FULL_TXT_ROUTE}`, `- llms well-known aliases: ${DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE}, ${DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE}`);
|
|
1275
1330
|
for (const section of llmsSections) {
|
|
@@ -1282,8 +1337,8 @@ function renderAgentsDocument({ origin, entry, search, mcp, feedback, llms, site
|
|
|
1282
1337
|
if (sitemapConfig.xml.enabled) lines.push(`- Sitemap XML: ${sitemapConfig.xml.route}`);
|
|
1283
1338
|
if (sitemapConfig.markdown.enabled) lines.push(`- Sitemap Markdown: ${sitemapConfig.markdown.route}`, ...sitemapConfig.markdown.docsRoute ? [`- Sitemap docs alias: ${sitemapConfig.markdown.docsRoute}`] : [], `- Sitemap well-known alias: ${sitemapConfig.markdown.wellKnownRoute}`);
|
|
1284
1339
|
}
|
|
1285
|
-
if (openapi.enabled &&
|
|
1286
|
-
lines.push(`- OpenAPI schema: ${
|
|
1340
|
+
if (openapi.enabled && openapiUrl) {
|
|
1341
|
+
lines.push(`- OpenAPI schema: ${openapiUrl}`);
|
|
1287
1342
|
if (openapi.apiReferencePath) lines.push(`- API reference: ${openapi.apiReferencePath}`);
|
|
1288
1343
|
}
|
|
1289
1344
|
if (mcp.enabled) lines.push(`- MCP: ${DEFAULT_MCP_PUBLIC_ROUTE}, ${DEFAULT_MCP_WELL_KNOWN_ROUTE}`);
|
|
@@ -2223,26 +2278,35 @@ function readLlmsTxtConfig(root) {
|
|
|
2223
2278
|
const configPath = path.join(root, `docs.config.${ext}`);
|
|
2224
2279
|
if (fs.existsSync(configPath)) try {
|
|
2225
2280
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
2226
|
-
const
|
|
2227
|
-
|
|
2281
|
+
const sanitized = stripCommentsAndStrings(content);
|
|
2282
|
+
const configObject = extractRootConfigObject(content, sanitized);
|
|
2283
|
+
const scopedContent = configObject?.content ?? content;
|
|
2284
|
+
const scopedSanitized = configObject?.sanitized ?? sanitized;
|
|
2285
|
+
const navBlock = extractObjectLiteral(scopedContent, scopedSanitized, "nav");
|
|
2286
|
+
const navTitle = navBlock ? readTopLevelString(navBlock, stripCommentsAndStrings(navBlock), "title") : void 0;
|
|
2287
|
+
const llmsTxtBoolean = readTopLevelBoolean(scopedSanitized, "llmsTxt");
|
|
2288
|
+
if (llmsTxtBoolean === true) return {
|
|
2228
2289
|
enabled: true,
|
|
2229
|
-
siteTitle:
|
|
2290
|
+
siteTitle: navTitle
|
|
2230
2291
|
};
|
|
2231
|
-
if (
|
|
2292
|
+
if (llmsTxtBoolean === false) return { enabled: false };
|
|
2293
|
+
const llmsTxtBlock = extractObjectLiteral(scopedContent, scopedSanitized, "llmsTxt");
|
|
2294
|
+
if (!llmsTxtBlock) return {
|
|
2232
2295
|
enabled: true,
|
|
2233
|
-
siteTitle:
|
|
2296
|
+
siteTitle: navTitle
|
|
2234
2297
|
};
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
const
|
|
2239
|
-
const
|
|
2240
|
-
const
|
|
2298
|
+
const llmsTxtSanitized = stripCommentsAndStrings(llmsTxtBlock);
|
|
2299
|
+
if (readTopLevelBoolean(llmsTxtSanitized, "enabled") === false) return { enabled: false };
|
|
2300
|
+
const apiCatalog = readTopLevelBoolean(llmsTxtSanitized, "apiCatalog");
|
|
2301
|
+
const baseUrl = readTopLevelString(llmsTxtBlock, llmsTxtSanitized, "baseUrl");
|
|
2302
|
+
const siteTitle = readTopLevelString(llmsTxtBlock, llmsTxtSanitized, "siteTitle");
|
|
2303
|
+
const siteDescription = readTopLevelString(llmsTxtBlock, llmsTxtSanitized, "siteDescription");
|
|
2241
2304
|
return {
|
|
2242
2305
|
enabled: true,
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2306
|
+
apiCatalog,
|
|
2307
|
+
baseUrl,
|
|
2308
|
+
siteTitle: siteTitle ?? navTitle,
|
|
2309
|
+
siteDescription
|
|
2246
2310
|
};
|
|
2247
2311
|
} catch {}
|
|
2248
2312
|
}
|
|
@@ -2347,7 +2411,7 @@ function generateLlmsTxt(indexes, options) {
|
|
|
2347
2411
|
/**
|
|
2348
2412
|
* Create a unified docs API route handler.
|
|
2349
2413
|
*
|
|
2350
|
-
* Returns `{ GET, POST }` for use in a Next.js route handler:
|
|
2414
|
+
* Returns `{ GET, HEAD, POST }` for use in a Next.js route handler:
|
|
2351
2415
|
* - **GET ?query=…** → full-text search
|
|
2352
2416
|
* - **GET ?format=llms** → llms.txt (concise page listing)
|
|
2353
2417
|
* - **GET ?format=llms-full** → llms-full.txt (full page content)
|
|
@@ -2358,7 +2422,7 @@ function generateLlmsTxt(indexes, options) {
|
|
|
2358
2422
|
* ```ts
|
|
2359
2423
|
* // app/api/docs/route.ts (auto-generated by withDocs)
|
|
2360
2424
|
* import { createDocsAPI } from "@farming-labs/next/api";
|
|
2361
|
-
* export const { GET, POST } = createDocsAPI();
|
|
2425
|
+
* export const { GET, HEAD, POST } = createDocsAPI();
|
|
2362
2426
|
* export const revalidate = false;
|
|
2363
2427
|
* ```
|
|
2364
2428
|
*
|
|
@@ -2382,8 +2446,15 @@ function createDocsAPI(options) {
|
|
|
2382
2446
|
const i18n = resolveDocsI18n(i18nConfig);
|
|
2383
2447
|
const aiConfig = options?.ai ?? readAIConfig(root);
|
|
2384
2448
|
const cloudConfig = options?.cloud ?? readCloudConfig(root);
|
|
2449
|
+
const configuredApiRouteInput = options?.apiRoute ?? cloudConfig?.apiRoute;
|
|
2450
|
+
const configuredApiRoute = normalizeDocsApiRoute(configuredApiRouteInput);
|
|
2451
|
+
const effectiveCloudConfig = options?.apiRoute !== void 0 || cloudConfig?.apiRoute !== void 0 ? {
|
|
2452
|
+
...cloudConfig,
|
|
2453
|
+
apiRoute: configuredApiRoute
|
|
2454
|
+
} : cloudConfig;
|
|
2385
2455
|
const searchConfig = options?.search;
|
|
2386
2456
|
const llmsConfig = resolveLlmsTxtConfig(options?.llmsTxt, readLlmsTxtConfig(root));
|
|
2457
|
+
const apiCatalogEnabled = options?.apiCatalog ?? llmsConfig.apiCatalog ?? true;
|
|
2387
2458
|
const sitemapConfig = options?.sitemap ?? readSitemapConfig(root);
|
|
2388
2459
|
const robotsConfig = options?.robots ?? readRobotsConfig(root);
|
|
2389
2460
|
const markdownMetadataBaseUrl = resolveDocsMetadataBaseUrl({
|
|
@@ -2403,6 +2474,7 @@ function createDocsAPI(options) {
|
|
|
2403
2474
|
const openapiDiscovery = resolveApiReferenceOpenApiDiscovery(apiReferenceConfig);
|
|
2404
2475
|
const rawMcpConfig = options?.mcp ?? readMcpConfig(root);
|
|
2405
2476
|
const mcpConfig = resolveDocsMcpConfig(rawMcpConfig, { defaultName: llmsConfig.siteTitle ?? "Documentation" });
|
|
2477
|
+
const discoveryLinkHeader = getDocsDiscoveryLinkHeader({ includeApiCatalog: apiCatalogEnabled });
|
|
2406
2478
|
const telemetryConfig = {
|
|
2407
2479
|
entry,
|
|
2408
2480
|
docsPath,
|
|
@@ -2410,7 +2482,7 @@ function createDocsAPI(options) {
|
|
|
2410
2482
|
telemetry: options?.telemetry,
|
|
2411
2483
|
search: searchConfig,
|
|
2412
2484
|
ai: aiConfig,
|
|
2413
|
-
cloud:
|
|
2485
|
+
cloud: effectiveCloudConfig,
|
|
2414
2486
|
i18n: i18nConfig ?? void 0,
|
|
2415
2487
|
feedback: options?.feedback,
|
|
2416
2488
|
mcp: rawMcpConfig,
|
|
@@ -2420,15 +2492,15 @@ function createDocsAPI(options) {
|
|
|
2420
2492
|
apiReference: apiReferenceConfig,
|
|
2421
2493
|
metadata: options?.metadata
|
|
2422
2494
|
};
|
|
2423
|
-
const { rootDir: _rootDir, language: _language, ...docsConfigMapOptions } = options ?? {};
|
|
2495
|
+
const { rootDir: _rootDir, language: _language, apiRoute: _apiRoute, ...docsConfigMapOptions } = options ?? {};
|
|
2424
2496
|
const docsConfigMapInput = { ...docsConfigMapOptions };
|
|
2497
|
+
if (effectiveCloudConfig !== void 0) docsConfigMapInput.cloud = effectiveCloudConfig;
|
|
2425
2498
|
const setConfigMapFallback = (key, value) => {
|
|
2426
2499
|
if (Object.prototype.hasOwnProperty.call(docsConfigMapInput, key) || value === void 0) return;
|
|
2427
2500
|
docsConfigMapInput[key] = value;
|
|
2428
2501
|
};
|
|
2429
2502
|
setConfigMapFallback("entry", entry);
|
|
2430
2503
|
setConfigMapFallback("ai", Object.keys(aiConfig).length > 0 ? aiConfig : void 0);
|
|
2431
|
-
setConfigMapFallback("cloud", cloudConfig);
|
|
2432
2504
|
setConfigMapFallback("search", searchConfig);
|
|
2433
2505
|
setConfigMapFallback("i18n", i18nConfig ?? void 0);
|
|
2434
2506
|
setConfigMapFallback("mcp", rawMcpConfig);
|
|
@@ -2437,8 +2509,12 @@ function createDocsAPI(options) {
|
|
|
2437
2509
|
...docsConfigMapInput,
|
|
2438
2510
|
docsPath: docsConfigMapInput.docsPath ?? docsPath,
|
|
2439
2511
|
contentDir: docsConfigMapInput.contentDir ?? contentDir,
|
|
2512
|
+
cloud: effectiveCloudConfig,
|
|
2440
2513
|
feedback: docsConfigMapInput.feedback ?? options?.feedback,
|
|
2441
|
-
llmsTxt:
|
|
2514
|
+
llmsTxt: {
|
|
2515
|
+
...llmsConfig,
|
|
2516
|
+
apiCatalog: apiCatalogEnabled
|
|
2517
|
+
},
|
|
2442
2518
|
sitemap: docsConfigMapInput.sitemap ?? sitemapConfig,
|
|
2443
2519
|
robots: docsConfigMapInput.robots ?? robotsConfig,
|
|
2444
2520
|
staticExport: docsConfigMapInput.staticExport ?? options?.staticExport
|
|
@@ -2521,7 +2597,7 @@ function createDocsAPI(options) {
|
|
|
2521
2597
|
};
|
|
2522
2598
|
}
|
|
2523
2599
|
const indexesByLocale = /* @__PURE__ */ new Map();
|
|
2524
|
-
const
|
|
2600
|
+
const llmsCache = new BoundedRouteCache(MAX_LLMS_CACHE_ROUTES_PER_LOCALE);
|
|
2525
2601
|
const markdownSourcesByLocale = /* @__PURE__ */ new Map();
|
|
2526
2602
|
function getIndexes(ctx) {
|
|
2527
2603
|
const key = ctx.locale ?? "__default__";
|
|
@@ -2594,26 +2670,73 @@ function createDocsAPI(options) {
|
|
|
2594
2670
|
};
|
|
2595
2671
|
return null;
|
|
2596
2672
|
}
|
|
2597
|
-
function getLlmsContent(ctx) {
|
|
2598
|
-
const
|
|
2599
|
-
const cached = llmsCacheByLocale.get(key);
|
|
2673
|
+
function getLlmsContent(ctx, apiRoute) {
|
|
2674
|
+
const cached = llmsCache.get(ctx.locale, apiRoute);
|
|
2600
2675
|
if (cached) return cached;
|
|
2601
2676
|
const next = generateLlmsTxt(getIndexes(ctx), {
|
|
2602
2677
|
siteTitle: llmsConfig.siteTitle ?? "Documentation",
|
|
2603
2678
|
siteDescription: llmsConfig.siteDescription,
|
|
2604
2679
|
baseUrl: llmsConfig.baseUrl ?? "",
|
|
2680
|
+
apiRoute,
|
|
2605
2681
|
maxChars: llmsConfig.maxChars,
|
|
2606
2682
|
sections: llmsConfig.sections,
|
|
2683
|
+
apiCatalog: apiCatalogEnabled,
|
|
2607
2684
|
openapi: openapiDiscovery
|
|
2608
2685
|
});
|
|
2609
|
-
|
|
2686
|
+
llmsCache.set(ctx.locale, apiRoute, next);
|
|
2610
2687
|
return next;
|
|
2611
2688
|
}
|
|
2612
|
-
|
|
2689
|
+
async function resolveStandardsResponse(request, url) {
|
|
2690
|
+
const apiRoute = resolveDocsRequestApiRoute(url, configuredApiRouteInput);
|
|
2691
|
+
const resolved = resolveDocsStandardsDiscoveryRequest(url, { apiRoute });
|
|
2692
|
+
if (!resolved) return null;
|
|
2693
|
+
const method = request.method.toUpperCase();
|
|
2694
|
+
const needsSkill = (method === "GET" || method === "HEAD") && resolved.kind !== "api-catalog";
|
|
2695
|
+
const fallbackSkillDocument = needsSkill ? renderSkillDocument({
|
|
2696
|
+
origin: url.origin,
|
|
2697
|
+
entry,
|
|
2698
|
+
apiRoute,
|
|
2699
|
+
apiCatalog: apiCatalogEnabled,
|
|
2700
|
+
i18n,
|
|
2701
|
+
search: searchConfig,
|
|
2702
|
+
mcp: mcpConfig,
|
|
2703
|
+
feedback: agentFeedbackConfig,
|
|
2704
|
+
llms: llmsConfig,
|
|
2705
|
+
sitemap: sitemapConfig,
|
|
2706
|
+
robots: robotsConfig,
|
|
2707
|
+
openapi: openapiDiscovery
|
|
2708
|
+
}) : "";
|
|
2709
|
+
return createDocsStandardsDiscoveryResponse({
|
|
2710
|
+
request,
|
|
2711
|
+
preferredSkillDocument: needsSkill ? readRootSkillDocument(root) : null,
|
|
2712
|
+
fallbackSkillDocument,
|
|
2713
|
+
origin: url.origin,
|
|
2714
|
+
entry,
|
|
2715
|
+
docsPath,
|
|
2716
|
+
apiCatalog: apiCatalogEnabled,
|
|
2717
|
+
apiRoute,
|
|
2718
|
+
i18n,
|
|
2719
|
+
search: searchConfig,
|
|
2720
|
+
mcp: mcpConfig,
|
|
2721
|
+
feedback: agentFeedbackConfig,
|
|
2722
|
+
llms: llmsConfig,
|
|
2723
|
+
sitemap: sitemapConfig,
|
|
2724
|
+
robots: robotsConfig,
|
|
2725
|
+
openapi: openapiDiscovery,
|
|
2726
|
+
markdown: {
|
|
2727
|
+
acceptHeader: true,
|
|
2728
|
+
signatureAgentHeader: true
|
|
2729
|
+
}
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
const handlers = {
|
|
2613
2733
|
async GET(request) {
|
|
2614
2734
|
trackTelemetryRequest(request);
|
|
2615
2735
|
const ctx = resolveContextFromRequest(request);
|
|
2616
2736
|
const url = new URL(request.url);
|
|
2737
|
+
const requestMethod = request.method.toUpperCase();
|
|
2738
|
+
const isHeadRequest = requestMethod === "HEAD";
|
|
2739
|
+
const requestApiRoute = resolveDocsRequestApiRoute(url, configuredApiRouteInput);
|
|
2617
2740
|
const requestAnalyticsProperties = getRequestAnalyticsProperties(request);
|
|
2618
2741
|
if (isDocsConfigRequest(url)) return Response.json(buildDocsConfigMap(docsConfigMapInput), { headers: {
|
|
2619
2742
|
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
@@ -2621,7 +2744,9 @@ function createDocsAPI(options) {
|
|
|
2621
2744
|
} });
|
|
2622
2745
|
if (isDocsDiagnosticsRequest(url)) return Response.json(buildDocsDiagnostics(docsDiagnosticsInput, {
|
|
2623
2746
|
adapter: "next",
|
|
2747
|
+
apiCatalog: apiCatalogEnabled,
|
|
2624
2748
|
entry,
|
|
2749
|
+
apiRoute: requestApiRoute,
|
|
2625
2750
|
i18n,
|
|
2626
2751
|
mcp: mcpConfig,
|
|
2627
2752
|
feedback: agentFeedbackConfig,
|
|
@@ -2630,6 +2755,8 @@ function createDocsAPI(options) {
|
|
|
2630
2755
|
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2631
2756
|
"X-Robots-Tag": "noindex"
|
|
2632
2757
|
} });
|
|
2758
|
+
const standardsResponse = await resolveStandardsResponse(request, url);
|
|
2759
|
+
if (standardsResponse) return standardsResponse;
|
|
2633
2760
|
if (resolveAgentSpecRequest(url)) {
|
|
2634
2761
|
await emitDocsAnalyticsEvent(analytics, {
|
|
2635
2762
|
type: "agent_spec_request",
|
|
@@ -2639,12 +2766,20 @@ function createDocsAPI(options) {
|
|
|
2639
2766
|
locale: ctx.locale,
|
|
2640
2767
|
properties: {
|
|
2641
2768
|
...requestAnalyticsProperties,
|
|
2642
|
-
method:
|
|
2769
|
+
method: requestMethod
|
|
2643
2770
|
}
|
|
2644
2771
|
});
|
|
2772
|
+
if (isHeadRequest) return new Response(null, { headers: {
|
|
2773
|
+
"Content-Type": "application/json",
|
|
2774
|
+
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2775
|
+
Link: discoveryLinkHeader,
|
|
2776
|
+
"X-Robots-Tag": "noindex"
|
|
2777
|
+
} });
|
|
2645
2778
|
return Response.json(buildAgentSpec({
|
|
2646
2779
|
origin: url.origin,
|
|
2647
2780
|
entry,
|
|
2781
|
+
apiRoute: requestApiRoute,
|
|
2782
|
+
apiCatalog: apiCatalogEnabled,
|
|
2648
2783
|
i18n,
|
|
2649
2784
|
search: searchConfig,
|
|
2650
2785
|
mcp: mcpConfig,
|
|
@@ -2655,6 +2790,7 @@ function createDocsAPI(options) {
|
|
|
2655
2790
|
openapi: openapiDiscovery
|
|
2656
2791
|
}), { headers: {
|
|
2657
2792
|
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2793
|
+
Link: discoveryLinkHeader,
|
|
2658
2794
|
"X-Robots-Tag": "noindex"
|
|
2659
2795
|
} });
|
|
2660
2796
|
}
|
|
@@ -2666,6 +2802,11 @@ function createDocsAPI(options) {
|
|
|
2666
2802
|
"X-Robots-Tag": "noindex"
|
|
2667
2803
|
}
|
|
2668
2804
|
});
|
|
2805
|
+
if (isHeadRequest) return new Response(null, { headers: {
|
|
2806
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
2807
|
+
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2808
|
+
"X-Robots-Tag": "noindex"
|
|
2809
|
+
} });
|
|
2669
2810
|
const document = await buildApiReferenceOpenApiDocumentAsync(apiReferenceDocsConfig, {
|
|
2670
2811
|
framework: "next",
|
|
2671
2812
|
rootDir: root,
|
|
@@ -2691,10 +2832,10 @@ function createDocsAPI(options) {
|
|
|
2691
2832
|
locale: ctx.locale,
|
|
2692
2833
|
properties: {
|
|
2693
2834
|
...requestAnalyticsProperties,
|
|
2694
|
-
method:
|
|
2835
|
+
method: requestMethod
|
|
2695
2836
|
}
|
|
2696
2837
|
});
|
|
2697
|
-
return new Response(JSON.stringify(agentFeedbackConfig.schema, null, 2), { headers: {
|
|
2838
|
+
return new Response(isHeadRequest ? null : JSON.stringify(agentFeedbackConfig.schema, null, 2), { headers: {
|
|
2698
2839
|
"Content-Type": "application/schema+json; charset=utf-8",
|
|
2699
2840
|
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2700
2841
|
"X-Robots-Tag": "noindex"
|
|
@@ -2709,12 +2850,14 @@ function createDocsAPI(options) {
|
|
|
2709
2850
|
locale: ctx.locale,
|
|
2710
2851
|
properties: {
|
|
2711
2852
|
...requestAnalyticsProperties,
|
|
2712
|
-
method:
|
|
2853
|
+
method: requestMethod
|
|
2713
2854
|
}
|
|
2714
2855
|
});
|
|
2715
|
-
return new Response(readRootAgentsDocument(root) ?? renderAgentsDocument({
|
|
2856
|
+
return new Response(isHeadRequest ? null : readRootAgentsDocument(root) ?? renderAgentsDocument({
|
|
2716
2857
|
origin: url.origin,
|
|
2717
2858
|
entry,
|
|
2859
|
+
apiRoute: requestApiRoute,
|
|
2860
|
+
apiCatalog: apiCatalogEnabled,
|
|
2718
2861
|
search: searchConfig,
|
|
2719
2862
|
mcp: mcpConfig,
|
|
2720
2863
|
feedback: agentFeedbackConfig,
|
|
@@ -2725,6 +2868,7 @@ function createDocsAPI(options) {
|
|
|
2725
2868
|
}), { headers: {
|
|
2726
2869
|
"Content-Type": "text/markdown; charset=utf-8",
|
|
2727
2870
|
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2871
|
+
Link: discoveryLinkHeader,
|
|
2728
2872
|
"X-Robots-Tag": "noindex"
|
|
2729
2873
|
} });
|
|
2730
2874
|
}
|
|
@@ -2737,12 +2881,14 @@ function createDocsAPI(options) {
|
|
|
2737
2881
|
locale: ctx.locale,
|
|
2738
2882
|
properties: {
|
|
2739
2883
|
...requestAnalyticsProperties,
|
|
2740
|
-
method:
|
|
2884
|
+
method: requestMethod
|
|
2741
2885
|
}
|
|
2742
2886
|
});
|
|
2743
|
-
return new Response(readRootSkillDocument(root) ?? renderSkillDocument({
|
|
2887
|
+
return new Response(isHeadRequest ? null : readRootSkillDocument(root) ?? renderSkillDocument({
|
|
2744
2888
|
origin: url.origin,
|
|
2745
2889
|
entry,
|
|
2890
|
+
apiRoute: requestApiRoute,
|
|
2891
|
+
apiCatalog: apiCatalogEnabled,
|
|
2746
2892
|
i18n,
|
|
2747
2893
|
search: searchConfig,
|
|
2748
2894
|
mcp: mcpConfig,
|
|
@@ -2754,12 +2900,14 @@ function createDocsAPI(options) {
|
|
|
2754
2900
|
}), { headers: {
|
|
2755
2901
|
"Content-Type": "text/markdown; charset=utf-8",
|
|
2756
2902
|
"Cache-Control": "public, max-age=0, s-maxage=3600",
|
|
2903
|
+
Link: discoveryLinkHeader,
|
|
2757
2904
|
"X-Robots-Tag": "noindex"
|
|
2758
2905
|
} });
|
|
2759
2906
|
}
|
|
2760
2907
|
const robotsResponse = createDocsRobotsResponse({
|
|
2761
2908
|
request,
|
|
2762
2909
|
entry,
|
|
2910
|
+
apiCatalog: apiCatalogEnabled,
|
|
2763
2911
|
sitemap: sitemapConfig,
|
|
2764
2912
|
baseUrl: llmsConfig.baseUrl ?? url.origin,
|
|
2765
2913
|
robots: robotsConfig
|
|
@@ -2767,6 +2915,7 @@ function createDocsAPI(options) {
|
|
|
2767
2915
|
if (robotsResponse) return robotsResponse;
|
|
2768
2916
|
const sitemapResponse = createDocsSitemapResponse({
|
|
2769
2917
|
request,
|
|
2918
|
+
apiRoute: requestApiRoute,
|
|
2770
2919
|
sitemap: sitemapConfig,
|
|
2771
2920
|
entry,
|
|
2772
2921
|
siteTitle: llmsConfig.siteTitle ?? "Documentation",
|
|
@@ -2815,6 +2964,7 @@ function createDocsAPI(options) {
|
|
|
2815
2964
|
});
|
|
2816
2965
|
return createDocsMarkdownResponse({
|
|
2817
2966
|
request,
|
|
2967
|
+
apiRoute: requestApiRoute,
|
|
2818
2968
|
document: null,
|
|
2819
2969
|
entry,
|
|
2820
2970
|
requestedPath: markdownRequest.requestedPath,
|
|
@@ -2855,6 +3005,7 @@ function createDocsAPI(options) {
|
|
|
2855
3005
|
});
|
|
2856
3006
|
return createDocsMarkdownResponse({
|
|
2857
3007
|
request,
|
|
3008
|
+
apiRoute: requestApiRoute,
|
|
2858
3009
|
document,
|
|
2859
3010
|
entry,
|
|
2860
3011
|
requestedPath: markdownRequest.requestedPath,
|
|
@@ -2865,7 +3016,7 @@ function createDocsAPI(options) {
|
|
|
2865
3016
|
sitemap: sitemapConfig
|
|
2866
3017
|
});
|
|
2867
3018
|
}
|
|
2868
|
-
const llmsRequest = resolveDocsLlmsTxtRequest(url, llmsConfig, docsPath);
|
|
3019
|
+
const llmsRequest = resolveDocsLlmsTxtRequest(url, llmsConfig, docsPath, { apiRoute: requestApiRoute });
|
|
2869
3020
|
if (llmsRequest) {
|
|
2870
3021
|
if (!llmsConfig.enabled) return new Response("Not Found", {
|
|
2871
3022
|
status: 404,
|
|
@@ -2874,7 +3025,7 @@ function createDocsAPI(options) {
|
|
|
2874
3025
|
"X-Robots-Tag": "noindex"
|
|
2875
3026
|
}
|
|
2876
3027
|
});
|
|
2877
|
-
const selected = selectDocsLlmsTxtContent(getLlmsContent(ctx), llmsRequest);
|
|
3028
|
+
const selected = selectDocsLlmsTxtContent(getLlmsContent(ctx, requestApiRoute), llmsRequest);
|
|
2878
3029
|
if (!selected) return new Response("Not Found", {
|
|
2879
3030
|
status: 404,
|
|
2880
3031
|
headers: {
|
|
@@ -2941,6 +3092,8 @@ function createDocsAPI(options) {
|
|
|
2941
3092
|
trackTelemetryRequest(request);
|
|
2942
3093
|
const url = new URL(request.url);
|
|
2943
3094
|
const requestAnalyticsProperties = getRequestAnalyticsProperties(request);
|
|
3095
|
+
const standardsResponse = await resolveStandardsResponse(request, url);
|
|
3096
|
+
if (standardsResponse) return standardsResponse;
|
|
2944
3097
|
const agentFeedbackRequest = resolveAgentFeedbackRequest(url, agentFeedbackConfig);
|
|
2945
3098
|
if (agentFeedbackRequest) {
|
|
2946
3099
|
if (agentFeedbackRequest.kind === "schema") return Response.json({ error: "Method Not Allowed" }, {
|
|
@@ -3036,6 +3189,17 @@ function createDocsAPI(options) {
|
|
|
3036
3189
|
}), analytics, observability, { locale: ctx.locale });
|
|
3037
3190
|
}
|
|
3038
3191
|
};
|
|
3192
|
+
return {
|
|
3193
|
+
...handlers,
|
|
3194
|
+
async HEAD(request) {
|
|
3195
|
+
const response = await handlers.GET(request);
|
|
3196
|
+
return new Response(null, {
|
|
3197
|
+
status: response.status,
|
|
3198
|
+
statusText: response.statusText,
|
|
3199
|
+
headers: response.headers
|
|
3200
|
+
});
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3039
3203
|
}
|
|
3040
3204
|
/**
|
|
3041
3205
|
* Create MCP route handlers for `/api/docs/mcp`.
|
package/dist/search.d.mts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/theme",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.60",
|
|
4
4
|
"description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"tsdown": "^0.20.3",
|
|
147
147
|
"typescript": "^5.9.3",
|
|
148
148
|
"vitest": "^4.1.8",
|
|
149
|
-
"@farming-labs/docs": "0.2.
|
|
149
|
+
"@farming-labs/docs": "0.2.60"
|
|
150
150
|
},
|
|
151
151
|
"peerDependencies": {
|
|
152
152
|
"@farming-labs/docs": ">=0.0.1",
|