@farming-labs/theme 0.1.74 → 0.1.76

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.
@@ -1,4 +1,4 @@
1
- import { ChangelogConfig, DocsAnalyticsConfig, DocsAskAIMcpConfig, DocsI18nConfig, DocsMcpConfig, DocsObservabilityConfig, DocsSearchConfig, FeedbackConfig, OrderingItem } from "@farming-labs/docs";
1
+ import { ChangelogConfig, DocsAnalyticsConfig, DocsAskAIMcpConfig, DocsI18nConfig, DocsMcpConfig, DocsObservabilityConfig, DocsSearchConfig, DocsSitemapConfig, FeedbackConfig, OrderingItem } from "@farming-labs/docs";
2
2
 
3
3
  //#region src/docs-api.d.ts
4
4
  interface AIProviderConfig {
@@ -54,6 +54,8 @@ interface DocsAPIOptions {
54
54
  feedback?: boolean | FeedbackConfig;
55
55
  /** MCP configuration used for the agent discovery spec. */
56
56
  mcp?: boolean | DocsMcpConfig;
57
+ /** Sitemap configuration used for sitemap.xml and sitemap.md. */
58
+ sitemap?: boolean | DocsSitemapConfig;
57
59
  }
58
60
  interface DocsMCPAPIOptions {
59
61
  rootDir?: string;
package/dist/docs-api.mjs CHANGED
@@ -3,8 +3,8 @@ import { getNextAppDir } from "./get-app-dir.mjs";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import matter from "gray-matter";
6
- import { buildDocsAskAIContext, createDocsAgentTraceContext, createDocsAgentTraceId, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, formatDocsAskAIPackageHints, normalizeDocsRelated, performDocsSearch, renderDocsRelatedMarkdownLines, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsI18n, resolveDocsLocale, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig } from "@farming-labs/docs";
7
- import { createDocsMcpHttpHandler, createFilesystemDocsMcpSource, resolveDocsMcpConfig } from "@farming-labs/docs/server";
6
+ import { buildDocsAskAIContext, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsSitemapResponse, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, formatDocsAskAIPackageHints, normalizeDocsRelated, performDocsSearch, renderDocsRelatedMarkdownLines, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsI18n, resolveDocsLocale, resolveDocsSitemapConfig, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig } from "@farming-labs/docs";
7
+ import { createDocsMcpHttpHandler, createFilesystemDocsMcpSource, readDocsSitemapManifest, resolveDocsMcpConfig } from "@farming-labs/docs/server";
8
8
 
9
9
  //#region src/docs-api.ts
10
10
  /**
@@ -172,10 +172,11 @@ function isSearchEnabled(search) {
172
172
  if (search && typeof search === "object" && search.enabled === false) return false;
173
173
  return true;
174
174
  }
175
- function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms }) {
175
+ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, sitemap }) {
176
176
  const normalizedEntry = normalizePathSegment(entry) || "docs";
177
177
  const localesEnabled = i18n !== null;
178
178
  const searchEnabled = isSearchEnabled(search);
179
+ const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
179
180
  return {
180
181
  version: "1",
181
182
  name: "@farming-labs/docs",
@@ -201,6 +202,7 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms }) {
201
202
  skills: true,
202
203
  mcp: mcp.enabled,
203
204
  search: searchEnabled,
205
+ sitemap: sitemapConfig.enabled,
204
206
  agentFeedback: feedback.enabled,
205
207
  locales: localesEnabled
206
208
  },
@@ -236,6 +238,20 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms }) {
236
238
  wellKnownTxt: DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
237
239
  wellKnownFull: DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE
238
240
  },
241
+ sitemap: {
242
+ enabled: sitemapConfig.enabled,
243
+ xml: {
244
+ enabled: sitemapConfig.xml.enabled,
245
+ route: sitemapConfig.xml.route,
246
+ api: `${DEFAULT_DOCS_API_ROUTE}?format=sitemap-xml`
247
+ },
248
+ markdown: {
249
+ enabled: sitemapConfig.markdown.enabled,
250
+ route: sitemapConfig.markdown.route,
251
+ wellKnownRoute: sitemapConfig.markdown.wellKnownRoute,
252
+ api: `${DEFAULT_DOCS_API_ROUTE}?format=sitemap-md`
253
+ }
254
+ },
239
255
  search: {
240
256
  enabled: searchEnabled,
241
257
  endpoint: `${DEFAULT_DOCS_API_ROUTE}?query={query}`,
@@ -737,6 +753,8 @@ function scanDocsDir(docsDir, entry, locale, excludedDirs = []) {
737
753
  rawContent,
738
754
  agentFallbackRawContent: agentRawContent !== rawContent ? agentRawContent : void 0,
739
755
  url,
756
+ sourcePath: pageSource.replace(/\\/g, "/"),
757
+ lastModified: fs.statSync(pageSource).mtime.toISOString(),
740
758
  locale
741
759
  });
742
760
  }
@@ -895,11 +913,12 @@ function renderMarkdownDocument(page) {
895
913
  lines.push("", page.agentFallbackRawContent ?? page.rawContent ?? page.content);
896
914
  return lines.join("\n");
897
915
  }
898
- function renderSkillDocument({ origin, entry, search, mcp, feedback, llms }) {
916
+ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitemap }) {
899
917
  const normalizedEntry = normalizePathSegment(entry) || "docs";
900
918
  const siteTitle = compactSkillText(llms.siteTitle ?? "Documentation");
901
919
  const siteDescription = llms.siteDescription ? compactSkillText(llms.siteDescription) : void 0;
902
920
  const searchEnabled = isSearchEnabled(search);
921
+ const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
903
922
  const lines = [
904
923
  "---",
905
924
  "name: docs",
@@ -914,10 +933,18 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms }) {
914
933
  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 ${DEFAULT_AGENT_SPEC_ROUTE}.`, `- 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.");
915
934
  if (searchEnabled) lines.push(`- Search with ${DEFAULT_DOCS_API_ROUTE}?query={query} when you do not know the page.`);
916
935
  if (llms.enabled) lines.push(`- Use ${DEFAULT_LLMS_TXT_ROUTE} for a compact docs index.`, `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} for full markdown context.`);
936
+ if (sitemapConfig.enabled) {
937
+ if (sitemapConfig.xml.enabled) lines.push(`- Use ${sitemapConfig.xml.route} to check canonical page freshness.`);
938
+ if (sitemapConfig.markdown.enabled) lines.push(`- Use ${sitemapConfig.markdown.route} for a semantic docs map.`);
939
+ }
917
940
  if (mcp.enabled) lines.push(`- Use ${DEFAULT_MCP_WELL_KNOWN_ROUTE} or ${DEFAULT_MCP_PUBLIC_ROUTE} for MCP tools when your environment supports MCP.`);
918
941
  if (feedback.enabled) lines.push(`- Read ${feedback.schemaRoute} before posting agent feedback to ${feedback.route}.`);
919
942
  lines.push("", "## Routes", `- Skill document: ${DEFAULT_SKILL_MD_ROUTE}`, `- Skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Skill API format: ${DEFAULT_DOCS_API_ROUTE}?format=skill`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`, `- Markdown root: /${normalizedEntry}.md`, `- Markdown pages: /${normalizedEntry}/{slug}.md`);
920
943
  if (llms.enabled) 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}`);
944
+ if (sitemapConfig.enabled) {
945
+ if (sitemapConfig.xml.enabled) lines.push(`- Sitemap XML: ${sitemapConfig.xml.route}`);
946
+ if (sitemapConfig.markdown.enabled) lines.push(`- Sitemap Markdown: ${sitemapConfig.markdown.route}`, `- Sitemap well-known alias: ${sitemapConfig.markdown.wellKnownRoute}`);
947
+ }
921
948
  if (mcp.enabled) lines.push(`- MCP: ${DEFAULT_MCP_PUBLIC_ROUTE}, ${DEFAULT_MCP_WELL_KNOWN_ROUTE}`);
922
949
  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", "```");
923
950
  return lines.join("\n");
@@ -1453,6 +1480,31 @@ function readLlmsTxtConfig(root) {
1453
1480
  }
1454
1481
  return { enabled: false };
1455
1482
  }
1483
+ function readSitemapConfig(root) {
1484
+ for (const ext of FILE_EXTS) {
1485
+ const configPath = path.join(root, `docs.config.${ext}`);
1486
+ if (!fs.existsSync(configPath)) continue;
1487
+ try {
1488
+ const content = fs.readFileSync(configPath, "utf-8");
1489
+ if (!content.includes("sitemap")) return void 0;
1490
+ if (/sitemap\s*:\s*false/.test(content)) return false;
1491
+ if (/sitemap\s*:\s*true/.test(content)) return true;
1492
+ const sitemapBlock = content.match(/sitemap\s*:\s*\{([\s\S]*?)\n\s*\}/)?.[1] ?? "";
1493
+ const routePrefix = sitemapBlock.match(/routePrefix\s*:\s*["']([^"']+)["']/)?.[1];
1494
+ const baseUrl = sitemapBlock.match(/baseUrl\s*:\s*["']([^"']+)["']/)?.[1];
1495
+ const manifestPath = sitemapBlock.match(/manifestPath\s*:\s*["']([^"']+)["']/)?.[1];
1496
+ const enabledMatch = sitemapBlock.match(/enabled\s*:\s*(true|false)/);
1497
+ return {
1498
+ enabled: enabledMatch ? enabledMatch[1] === "true" : true,
1499
+ routePrefix,
1500
+ baseUrl,
1501
+ manifestPath
1502
+ };
1503
+ } catch {
1504
+ return;
1505
+ }
1506
+ }
1507
+ }
1456
1508
  function generateLlmsTxt(indexes, options) {
1457
1509
  const { siteTitle = "Documentation", siteDescription, baseUrl = "" } = options;
1458
1510
  let llmsTxt = `# ${siteTitle}\n\n`;
@@ -1513,6 +1565,7 @@ function createDocsAPI(options) {
1513
1565
  const aiConfig = options?.ai ?? readAIConfig(root);
1514
1566
  const searchConfig = options?.search;
1515
1567
  const llmsConfig = readLlmsTxtConfig(root);
1568
+ const sitemapConfig = options?.sitemap ?? readSitemapConfig(root);
1516
1569
  const mcpConfig = resolveDocsMcpConfig(options?.mcp ?? readMcpConfig(root), { defaultName: llmsConfig.siteTitle ?? "Documentation" });
1517
1570
  function resolveDocsDirCandidates(locale) {
1518
1571
  const relativeCandidates = /* @__PURE__ */ new Set();
@@ -1652,7 +1705,8 @@ function createDocsAPI(options) {
1652
1705
  search: searchConfig,
1653
1706
  mcp: mcpConfig,
1654
1707
  feedback: agentFeedbackConfig,
1655
- llms: llmsConfig
1708
+ llms: llmsConfig,
1709
+ sitemap: sitemapConfig
1656
1710
  }), { headers: {
1657
1711
  "Cache-Control": "public, max-age=0, s-maxage=3600",
1658
1712
  "X-Robots-Tag": "noindex"
@@ -1694,13 +1748,24 @@ function createDocsAPI(options) {
1694
1748
  search: searchConfig,
1695
1749
  mcp: mcpConfig,
1696
1750
  feedback: agentFeedbackConfig,
1697
- llms: llmsConfig
1751
+ llms: llmsConfig,
1752
+ sitemap: sitemapConfig
1698
1753
  }), { headers: {
1699
1754
  "Content-Type": "text/markdown; charset=utf-8",
1700
1755
  "Cache-Control": "public, max-age=0, s-maxage=3600",
1701
1756
  "X-Robots-Tag": "noindex"
1702
1757
  } });
1703
1758
  }
1759
+ const sitemapResponse = createDocsSitemapResponse({
1760
+ request,
1761
+ sitemap: sitemapConfig,
1762
+ entry,
1763
+ siteTitle: llmsConfig.siteTitle ?? "Documentation",
1764
+ baseUrl: llmsConfig.baseUrl ?? url.origin,
1765
+ pages: getIndexes(ctx),
1766
+ manifest: readDocsSitemapManifest(root, sitemapConfig)
1767
+ });
1768
+ if (sitemapResponse) return sitemapResponse;
1704
1769
  const markdownRequest = resolveMarkdownRequest(entry, url, request);
1705
1770
  if (markdownRequest) {
1706
1771
  const document = await getMarkdownDocument(ctx, markdownRequest.requestedPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -139,7 +139,7 @@
139
139
  "tsdown": "^0.20.3",
140
140
  "typescript": "^5.9.3",
141
141
  "vitest": "^3.2.4",
142
- "@farming-labs/docs": "0.1.74"
142
+ "@farming-labs/docs": "0.1.76"
143
143
  },
144
144
  "peerDependencies": {
145
145
  "@farming-labs/docs": ">=0.0.1",