@farming-labs/theme 0.1.85 → 0.1.88

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.
@@ -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
+ /** llms.txt configuration. Enabled by default; set false to opt out. */
58
+ llmsTxt?: boolean | LlmsTxtOptions;
57
59
  /** Sitemap configuration used for sitemap.xml and sitemap.md. */
58
60
  sitemap?: boolean | DocsSitemapConfig;
59
61
  /** Robots.txt generation policy used for the agent discovery spec. */
@@ -72,6 +74,12 @@ interface DocsMCPAPIOptions {
72
74
  analytics?: boolean | DocsAnalyticsConfig;
73
75
  observability?: boolean | DocsObservabilityConfig;
74
76
  }
77
+ interface LlmsTxtOptions {
78
+ enabled?: boolean;
79
+ siteTitle?: string;
80
+ siteDescription?: string;
81
+ baseUrl?: string;
82
+ }
75
83
  /**
76
84
  * Create a unified docs API route handler.
77
85
  *
package/dist/docs-api.mjs CHANGED
@@ -3,7 +3,7 @@ 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, createDocsSitemapResponse, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, formatDocsAskAIPackageHints, getDocsMarkdownVaryHeader, hasDocsMarkdownSignatureAgent, normalizeDocsRelated, performDocsSearch, renderDocsMarkdownNotFound, renderDocsRelatedMarkdownLines, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsI18n, resolveDocsLocale, resolveDocsSitemapConfig, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig } from "@farming-labs/docs";
6
+ import { buildDocsAskAIContext, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsSitemapResponse, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, formatDocsAskAIPackageHints, getDocsMarkdownVaryHeader, hasDocsMarkdownSignatureAgent, normalizeDocsRelated, performDocsSearch, renderDocsMarkdownNotFound, renderDocsRelatedMarkdownLines, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsI18n, resolveDocsLocale, resolveDocsSitemapConfig, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, toDocsMarkdownUrl } from "@farming-labs/docs";
7
7
  import { createDocsMcpHttpHandler, createFilesystemDocsMcpSource, readDocsSitemapManifest, resolveDocsMcpConfig } from "@farming-labs/docs/server";
8
8
 
9
9
  //#region src/docs-api.ts
@@ -1495,14 +1495,21 @@ function readLlmsTxtConfig(root) {
1495
1495
  const configPath = path.join(root, `docs.config.${ext}`);
1496
1496
  if (fs.existsSync(configPath)) try {
1497
1497
  const content = fs.readFileSync(configPath, "utf-8");
1498
- if (!content.includes("llmsTxt")) return { enabled: false };
1499
- if (/llmsTxt\s*:\s*true/.test(content)) return { enabled: true };
1498
+ const navTitleMatch = content.match(/nav\s*:\s*\{[^}]*title\s*:\s*["']([^"']+)["']/s);
1499
+ if (!content.includes("llmsTxt")) return {
1500
+ enabled: true,
1501
+ siteTitle: navTitleMatch?.[1]
1502
+ };
1503
+ if (/llmsTxt\s*:\s*true/.test(content)) return {
1504
+ enabled: true,
1505
+ siteTitle: navTitleMatch?.[1]
1506
+ };
1507
+ if (/llmsTxt\s*:\s*false/.test(content)) return { enabled: false };
1500
1508
  const enabledMatch = content.match(/llmsTxt\s*:\s*\{[^}]*enabled\s*:\s*(true|false)/s);
1501
1509
  if (enabledMatch && enabledMatch[1] === "false") return { enabled: false };
1502
1510
  const baseUrlMatch = content.match(/llmsTxt\s*:\s*\{[^}]*baseUrl\s*:\s*["']([^"']+)["']/s);
1503
1511
  const siteTitleMatch = content.match(/llmsTxt\s*:\s*\{[^}]*siteTitle\s*:\s*["']([^"']+)["']/s);
1504
1512
  const siteDescMatch = content.match(/llmsTxt\s*:\s*\{[^}]*siteDescription\s*:\s*["']([^"']+)["']/s);
1505
- const navTitleMatch = content.match(/nav\s*:\s*\{[^}]*title\s*:\s*["']([^"']+)["']/s);
1506
1513
  return {
1507
1514
  enabled: true,
1508
1515
  baseUrl: baseUrlMatch?.[1],
@@ -1511,7 +1518,19 @@ function readLlmsTxtConfig(root) {
1511
1518
  };
1512
1519
  } catch {}
1513
1520
  }
1514
- return { enabled: false };
1521
+ return { enabled: true };
1522
+ }
1523
+ function resolveLlmsTxtConfig(input, fallback) {
1524
+ if (input === void 0) return fallback;
1525
+ if (typeof input === "boolean") return input ? {
1526
+ ...fallback,
1527
+ enabled: true
1528
+ } : { enabled: false };
1529
+ return {
1530
+ ...fallback,
1531
+ ...input,
1532
+ enabled: input.enabled ?? true
1533
+ };
1515
1534
  }
1516
1535
  function readSitemapConfig(root) {
1517
1536
  for (const ext of FILE_EXTS) {
@@ -1569,7 +1588,7 @@ function generateLlmsTxt(indexes, options) {
1569
1588
  if (siteDescription) llmsTxt += `> ${siteDescription}\n\n`;
1570
1589
  llmsTxt += `## Pages\n\n`;
1571
1590
  for (const page of indexes) {
1572
- llmsTxt += `- [${page.title}](${baseUrl}${page.url})`;
1591
+ llmsTxt += `- [${page.title}](${baseUrl}${toDocsMarkdownUrl(page.url)})`;
1573
1592
  if (page.description) llmsTxt += `: ${page.description}`;
1574
1593
  llmsTxt += `\n`;
1575
1594
  }
@@ -1622,7 +1641,7 @@ function createDocsAPI(options) {
1622
1641
  const i18n = resolveDocsI18n(options?.i18n ?? readI18nConfig(root));
1623
1642
  const aiConfig = options?.ai ?? readAIConfig(root);
1624
1643
  const searchConfig = options?.search;
1625
- const llmsConfig = readLlmsTxtConfig(root);
1644
+ const llmsConfig = resolveLlmsTxtConfig(options?.llmsTxt, readLlmsTxtConfig(root));
1626
1645
  const sitemapConfig = options?.sitemap ?? readSitemapConfig(root);
1627
1646
  const robotsConfig = options?.robots ?? readRobotsConfig(root);
1628
1647
  const mcpConfig = resolveDocsMcpConfig(options?.mcp ?? readMcpConfig(root), { defaultName: llmsConfig.siteTitle ?? "Documentation" });
@@ -1903,6 +1922,15 @@ function createDocsAPI(options) {
1903
1922
  } });
1904
1923
  }
1905
1924
  const llmsFormat = resolveLlmsTxtFormat(url);
1925
+ if (llmsFormat === "llms" || llmsFormat === "llms-full") {
1926
+ if (!llmsConfig.enabled) return new Response("Not Found", {
1927
+ status: 404,
1928
+ headers: {
1929
+ "Content-Type": "text/plain; charset=utf-8",
1930
+ "X-Robots-Tag": "noindex"
1931
+ }
1932
+ });
1933
+ }
1906
1934
  if (llmsFormat === "llms") {
1907
1935
  await emitDocsAnalyticsEvent(analytics, {
1908
1936
  type: "llms_request",
@@ -636,7 +636,7 @@ function createDocsLayout(config, options) {
636
636
  const readingTimeOptions = resolveReadingTimeOptions(config.readingTime);
637
637
  const readingTimeEnabledByDefault = readingTimeOptions.enabled;
638
638
  const readingTimeWordsPerMinute = readingTimeOptions.wordsPerMinute ?? 220;
639
- const llmsTxtEnabled = resolveBool(config.llmsTxt);
639
+ const llmsTxtEnabled = resolveEnabledByDefault(config.llmsTxt);
640
640
  const feedbackConfig = resolveFeedbackConfig(config.feedback);
641
641
  const openDocsProviders = (pageActions?.openDocs && typeof pageActions.openDocs === "object" && pageActions.openDocs.providers ? pageActions.openDocs.providers : void 0)?.map((p) => ({
642
642
  name: p.name,
@@ -795,6 +795,11 @@ function resolveBool(v) {
795
795
  if (typeof v === "boolean") return v;
796
796
  return v.enabled !== false;
797
797
  }
798
+ function resolveEnabledByDefault(v) {
799
+ if (v === void 0) return true;
800
+ if (typeof v === "boolean") return v;
801
+ return v.enabled !== false;
802
+ }
798
803
  function resolveFeedbackConfig(feedback) {
799
804
  const defaults = {
800
805
  enabled: false,
@@ -181,6 +181,11 @@ function resolveBool(value) {
181
181
  if (typeof value === "boolean") return value;
182
182
  return value.enabled !== false;
183
183
  }
184
+ function resolveEnabledByDefault(value) {
185
+ if (value === void 0) return true;
186
+ if (typeof value === "boolean") return value;
187
+ return value.enabled !== false;
188
+ }
184
189
  function resolveFeedbackConfig(feedback) {
185
190
  const defaults = {
186
191
  enabled: false,
@@ -237,7 +242,7 @@ function TanstackDocsLayout({ config, tree, locale, description, readingTime, la
237
242
  const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
238
243
  const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
239
244
  const readingTimeEnabled = resolveReadingTimeOptions(config.readingTime).enabled;
240
- const llmsTxtEnabled = resolveBool(config.llmsTxt);
245
+ const llmsTxtEnabled = resolveEnabledByDefault(config.llmsTxt);
241
246
  const feedbackConfig = resolveFeedbackConfig(config.feedback);
242
247
  const staticExport = !!config.staticExport;
243
248
  const openDocsProviders = (pageActions?.openDocs && typeof pageActions.openDocs === "object" && pageActions.openDocs.providers ? pageActions.openDocs.providers : void 0)?.map((provider) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.1.85",
3
+ "version": "0.1.88",
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.85"
142
+ "@farming-labs/docs": "0.1.88"
143
143
  },
144
144
  "peerDependencies": {
145
145
  "@farming-labs/docs": ">=0.0.1",