@farming-labs/farmjs 0.2.98 → 0.2.101
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/browser-css.generated.d.ts +3 -0
- package/dist/browser-css.generated.d.ts.map +1 -0
- package/dist/browser-css.generated.js +4 -0
- package/dist/browser-css.generated.js.map +1 -0
- package/dist/config.d.ts +9 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -1
- package/dist/content.d.ts +1 -0
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +6 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +55 -18
- package/dist/react.js.map +1 -1
- package/dist/server.d.ts +45 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +316 -11
- package/dist/server.js.map +1 -1
- package/dist/vite.d.ts +16 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +66 -6
- package/dist/vite.js.map +1 -1
- package/package.json +12 -8
package/dist/server.js
CHANGED
|
@@ -1,10 +1,45 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { PassThrough } from "node:stream";
|
|
3
4
|
import matter from "gray-matter";
|
|
5
|
+
import { createElement } from "react";
|
|
6
|
+
import * as ReactDOMServer from "react-dom/server";
|
|
4
7
|
import { applySidebarFolderIndexBehavior, buildDocsAskAIContext, buildDocsSearchFacets, buildDocsAgentDiscoverySpec, buildDocsConfigMap, buildDocsDiagnostics, createDocsContentChangeFeed, createDocsContentChangesHttpResponse, createDocsCacheableResponse, createDocsStandardsDiscoveryResponse, createDocsMarkdownResponse, createDocsRobotsResponse, createDocsSitemapResponse, createDocsAgentTraceContext, createDocsAgentTraceId, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, emitDocsTelemetryAgentSurfaceEvent, emitDocsTelemetryProjectEvent, formatDocsAskAIPackageHints, findDocsMarkdownPage, getDocsLlmsTxtMaxCharsIssue, getDocsAgentManifestLinkHeader, getDocsDiscoveryLinkHeader, isDocsAgentDiscoveryRequest, isDocsContentChangesRequest, isDocsAgentsRequest, isDocsConfigRequest, isDocsDiagnosticsRequest, isDocsSkillRequest, normalizeDocsRelated, normalizePageAgentFrontmatter, parseDocsAgentFeedbackData, performDocsSearch, performDocsSearchWithMetadata, renderDocsMarkdownDocument, renderDocsLlmsTxt, renderDocsAgentsDocument, renderDocsSkillDocument, readDocsSitemapManifestFromContentMap, stripGeneratedAgentProvenance, resolveDocsAudienceMdxContent, resolveDocsAgentFeedbackConfig, resolveDocsAgentFeedbackRequest, resolvePageSidebarFolderIndexBehavior, resolveAskAISearchRequestConfig, resolveDocsSearchAudience, resolveDocsSearchError, resolveDocsSearchRequest, resolveSearchRequestConfig, resolveDocsI18n, resolveDocsLlmsTxtRequest, resolveDocsLocale, resolveDocsMarkdownRequest, resolveDocsMetadataBaseUrl, resolveDocsContentChangesConfig, resolveDocsRequestApiRoute, resolveDocsRetrievalLastModified, resolveDocsPublishedAgentSkill, resolveDocsStandardsDiscoveryRequest, resolveDocsPath, resolvePageReadingTime, resolveReadingTimeOptions, resolveDocsSitemapPageLastmod, resolveDocsAgentsFormat, resolveDocsSkillFormat, inferDocsTelemetryAgentSurface, renderDocsPageStructuredDataJson, selectDocsLlmsTxtContent, validateDocsAgentFeedbackPayload, } from "@farming-labs/docs";
|
|
5
8
|
import { buildApiReferenceOpenApiDocumentAsync, createDocsMcpHttpHandler, readDocsSitemapManifest, resolveApiReferenceOpenApiDiscovery, resolveDocsMcpConfig, resolveConfiguredAgentSkills, } from "@farming-labs/docs/server";
|
|
6
9
|
import { loadDocsNavTree, loadDocsContent, flattenNavTree, normalizeDocsFrontmatterLastmod, } from "./content.js";
|
|
10
|
+
import farmDocsBrowserCss from "./browser-css.generated.js";
|
|
7
11
|
export { createFarmjsApiReference } from "./api-reference.js";
|
|
12
|
+
const FARM_DOCS_BROWSER_CSS_PATH = "/__farm_docs/browser.css";
|
|
13
|
+
function loadFarmDocsBrowserCss() {
|
|
14
|
+
return farmDocsBrowserCss;
|
|
15
|
+
}
|
|
16
|
+
async function renderFarmDocsMarkup(element) {
|
|
17
|
+
const server = ReactDOMServer;
|
|
18
|
+
if (server.renderToReadableStream) {
|
|
19
|
+
const stream = await server.renderToReadableStream(element);
|
|
20
|
+
await stream.allReady;
|
|
21
|
+
return new Response(stream).text();
|
|
22
|
+
}
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const destination = new PassThrough();
|
|
25
|
+
const chunks = [];
|
|
26
|
+
destination.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
27
|
+
destination.on("error", reject);
|
|
28
|
+
destination.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
29
|
+
const renderer = server.renderToPipeableStream(element, {
|
|
30
|
+
onAllReady() {
|
|
31
|
+
renderer.pipe(destination);
|
|
32
|
+
},
|
|
33
|
+
onShellError(error) {
|
|
34
|
+
reject(error);
|
|
35
|
+
},
|
|
36
|
+
onError(error) {
|
|
37
|
+
if (!destination.readableEnded)
|
|
38
|
+
destination.destroy(error);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
8
43
|
function isApiReferenceOpenApiRequest(url) {
|
|
9
44
|
return url.searchParams.get("format")?.trim() === "openapi";
|
|
10
45
|
}
|
|
@@ -37,6 +72,64 @@ function safeUrlOrigin(value) {
|
|
|
37
72
|
return value;
|
|
38
73
|
}
|
|
39
74
|
}
|
|
75
|
+
function navigationItemName(item) {
|
|
76
|
+
return item.label?.trim() || item.title?.trim() || item.slug?.trim() || "Documentation";
|
|
77
|
+
}
|
|
78
|
+
function navigationItemUrl(item, entry) {
|
|
79
|
+
if (item.href?.trim())
|
|
80
|
+
return item.href.trim();
|
|
81
|
+
if (typeof item.slug !== "string")
|
|
82
|
+
return undefined;
|
|
83
|
+
const slug = item.slug.replace(/^\/+|\/+$/g, "");
|
|
84
|
+
return slug ? `/${entry}/${slug}` : `/${entry}`;
|
|
85
|
+
}
|
|
86
|
+
function navTreeFromNavigation(config, entry) {
|
|
87
|
+
const configured = config.navigation?.sidebar;
|
|
88
|
+
if (!Array.isArray(configured) || configured.length === 0)
|
|
89
|
+
return null;
|
|
90
|
+
const defaultOpen = config.theme?.name === "fumadocs-pixel-border";
|
|
91
|
+
function toNode(item) {
|
|
92
|
+
const children = item.children ?? item.items ?? [];
|
|
93
|
+
const name = navigationItemName(item);
|
|
94
|
+
const url = navigationItemUrl(item, entry);
|
|
95
|
+
if (children.length > 0) {
|
|
96
|
+
const mappedChildren = children.map(toNode).filter((node) => node !== null);
|
|
97
|
+
return {
|
|
98
|
+
type: "folder",
|
|
99
|
+
name,
|
|
100
|
+
...(defaultOpen ? { defaultOpen: true } : {}),
|
|
101
|
+
...(item.icon ? { icon: item.icon } : {}),
|
|
102
|
+
...(url
|
|
103
|
+
? {
|
|
104
|
+
index: {
|
|
105
|
+
type: "page",
|
|
106
|
+
name,
|
|
107
|
+
url,
|
|
108
|
+
...(item.icon ? { icon: item.icon } : {}),
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
: {}),
|
|
112
|
+
children: mappedChildren,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (!url)
|
|
116
|
+
return null;
|
|
117
|
+
return {
|
|
118
|
+
type: "page",
|
|
119
|
+
name,
|
|
120
|
+
url,
|
|
121
|
+
...(item.icon ? { icon: item.icon } : {}),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
name: typeof config.nav?.title === "string" && config.nav.title.trim()
|
|
126
|
+
? config.nav.title.trim()
|
|
127
|
+
: "Docs",
|
|
128
|
+
children: configured
|
|
129
|
+
.map((item) => toNode(item))
|
|
130
|
+
.filter((node) => node !== null),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
40
133
|
function resolvePreloadedContent(value) {
|
|
41
134
|
if (!value || typeof value !== "object")
|
|
42
135
|
return null;
|
|
@@ -74,6 +167,17 @@ function stripMarkdownText(content) {
|
|
|
74
167
|
.replace(/\n{3,}/g, "\n\n")
|
|
75
168
|
.trim();
|
|
76
169
|
}
|
|
170
|
+
function markdownStartsWithDescription(content, description) {
|
|
171
|
+
if (!description?.trim())
|
|
172
|
+
return false;
|
|
173
|
+
const withoutLeadingTitle = content
|
|
174
|
+
.trimStart()
|
|
175
|
+
.replace(/^#\s+[^\r\n]+(?:\r?\n|$)/, "")
|
|
176
|
+
.trimStart();
|
|
177
|
+
const firstBlock = withoutLeadingTitle.split(/\r?\n\s*\r?\n/, 1)[0] ?? "";
|
|
178
|
+
const normalize = (value) => stripMarkdownText(value).replace(/\s+/g, " ").trim();
|
|
179
|
+
return normalize(firstBlock) === normalize(description);
|
|
180
|
+
}
|
|
77
181
|
function normalizePathSegment(value) {
|
|
78
182
|
return value.replace(/^\/+|\/+$/g, "");
|
|
79
183
|
}
|
|
@@ -400,7 +504,7 @@ export function createDocsServer(config) {
|
|
|
400
504
|
? githubRaw.replace(/\/$/, "")
|
|
401
505
|
: githubRaw?.url.replace(/\/$/, "");
|
|
402
506
|
const githubBranch = typeof githubRaw === "object" ? (githubRaw.branch ?? "main") : "main";
|
|
403
|
-
const
|
|
507
|
+
const githubDirectory = typeof githubRaw === "object" ? githubRaw.directory?.replace(/^\/|\/$/g, "") : undefined;
|
|
404
508
|
const readingTimeOptions = resolveReadingTimeOptions(config.readingTime);
|
|
405
509
|
const aiConfig = { enabled: false, ...config.ai };
|
|
406
510
|
if (config.apiKey && !aiConfig.apiKey) {
|
|
@@ -471,9 +575,11 @@ export function createDocsServer(config) {
|
|
|
471
575
|
async function load({ pathname, locale }) {
|
|
472
576
|
const resolvedLocale = (i18n && locale && i18n.locales.includes(locale) ? locale : undefined) ?? i18n?.defaultLocale;
|
|
473
577
|
const ctx = resolveContextFromPath(pathname, resolvedLocale);
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
578
|
+
const configuredNavigation = navTreeFromNavigation(config, entry);
|
|
579
|
+
const tree = applySidebarFolderIndexBehavior(configuredNavigation ??
|
|
580
|
+
(preloaded
|
|
581
|
+
? navTreeFromMap(preloaded, ctx.dirPrefix, entry, ordering)
|
|
582
|
+
: loadDocsNavTree(ctx.contentDirAbs, entry, ordering)), {
|
|
477
583
|
sidebar: config.sidebar,
|
|
478
584
|
defaultBehavior: "link",
|
|
479
585
|
});
|
|
@@ -560,16 +666,24 @@ export function createDocsServer(config) {
|
|
|
560
666
|
const previousPage = currentIndex > 0 ? flatPages[currentIndex - 1] : null;
|
|
561
667
|
const nextPage = currentIndex < flatPages.length - 1 ? flatPages[currentIndex + 1] : null;
|
|
562
668
|
let editOnGithub;
|
|
563
|
-
if (githubRepo
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
|
|
669
|
+
if (githubRepo) {
|
|
670
|
+
const contentPath = normalizePathSegment(path.isAbsolute(ctx.contentDirRel)
|
|
671
|
+
? toPosixPath(path.relative(rootDir, ctx.contentDirRel))
|
|
672
|
+
: toPosixPath(ctx.contentDirRel));
|
|
673
|
+
const configuredDirectory = normalizePathSegment(githubDirectory ?? "");
|
|
674
|
+
const sourceDirectory = configuredDirectory &&
|
|
675
|
+
(contentPath === configuredDirectory || contentPath.startsWith(`${configuredDirectory}/`))
|
|
676
|
+
? contentPath
|
|
677
|
+
: joinPathParts(configuredDirectory, contentPath);
|
|
678
|
+
const sourcePath = joinPathParts(sourceDirectory, toPosixPath(relPath));
|
|
679
|
+
editOnGithub = `${githubRepo}/edit/${githubBranch}/${sourcePath}`;
|
|
567
680
|
}
|
|
568
681
|
const fallbackTitle = isIndex
|
|
569
682
|
? "Documentation"
|
|
570
683
|
: (slug.split("/").pop()?.replace(/-/g, " ") ?? "Documentation");
|
|
571
684
|
const title = data.title ?? fallbackTitle;
|
|
572
685
|
const description = data.description;
|
|
686
|
+
const descriptionInBody = markdownStartsWithDescription(humanRawContent, description);
|
|
573
687
|
const structuredData = renderDocsPageStructuredDataJson({
|
|
574
688
|
title,
|
|
575
689
|
description,
|
|
@@ -585,6 +699,7 @@ export function createDocsServer(config) {
|
|
|
585
699
|
url: currentUrl,
|
|
586
700
|
title,
|
|
587
701
|
description,
|
|
702
|
+
descriptionInBody,
|
|
588
703
|
rawContent: humanRawContent,
|
|
589
704
|
readingTime,
|
|
590
705
|
readingTimeFormat: readingTimeOptions.format,
|
|
@@ -1598,9 +1713,10 @@ export function createDocsServer(config) {
|
|
|
1598
1713
|
},
|
|
1599
1714
|
getNavigation(locale) {
|
|
1600
1715
|
const ctx = resolveContextFromPath(`/${entry}`, resolveLocaleForMcp(locale));
|
|
1601
|
-
return applySidebarFolderIndexBehavior(
|
|
1602
|
-
|
|
1603
|
-
|
|
1716
|
+
return applySidebarFolderIndexBehavior(navTreeFromNavigation(config, entry) ??
|
|
1717
|
+
(preloaded
|
|
1718
|
+
? navTreeFromMap(preloaded, ctx.dirPrefix, entry, ordering)
|
|
1719
|
+
: loadDocsNavTree(ctx.contentDirAbs, entry, ordering)), {
|
|
1604
1720
|
sidebar: config.sidebar,
|
|
1605
1721
|
defaultBehavior: "link",
|
|
1606
1722
|
});
|
|
@@ -1722,4 +1838,193 @@ export function createDocsServer(config) {
|
|
|
1722
1838
|
}
|
|
1723
1839
|
return { load, GET, HEAD, POST, MCP, handle };
|
|
1724
1840
|
}
|
|
1841
|
+
function escapeDocumentText(value) {
|
|
1842
|
+
return String(value ?? "")
|
|
1843
|
+
.replace(/&/g, "&")
|
|
1844
|
+
.replace(/</g, "<")
|
|
1845
|
+
.replace(/>/g, ">")
|
|
1846
|
+
.replace(/"/g, """);
|
|
1847
|
+
}
|
|
1848
|
+
function serializeInlineJson(value) {
|
|
1849
|
+
return JSON.stringify(value)
|
|
1850
|
+
.replace(/</g, "\\u003c")
|
|
1851
|
+
.replace(/>/g, "\\u003e")
|
|
1852
|
+
.replace(/\u2028/g, "\\u2028")
|
|
1853
|
+
.replace(/\u2029/g, "\\u2029");
|
|
1854
|
+
}
|
|
1855
|
+
function createClientDocsConfig(config) {
|
|
1856
|
+
const { apiKey: _apiKey, rootDir: _rootDir, contentDir: _contentDir, _preloadedContent, _preloadedAgentSkills, socialImage, ...clientConfig } = config;
|
|
1857
|
+
const ai = clientConfig.ai && typeof clientConfig.ai === "object"
|
|
1858
|
+
? {
|
|
1859
|
+
...clientConfig.ai,
|
|
1860
|
+
apiKey: undefined,
|
|
1861
|
+
providers: clientConfig.ai.providers && typeof clientConfig.ai.providers === "object"
|
|
1862
|
+
? Object.fromEntries(Object.entries(clientConfig.ai.providers).map(([name, provider]) => [
|
|
1863
|
+
name,
|
|
1864
|
+
provider && typeof provider === "object"
|
|
1865
|
+
? { ...provider, apiKey: undefined }
|
|
1866
|
+
: provider,
|
|
1867
|
+
]))
|
|
1868
|
+
: clientConfig.ai.providers,
|
|
1869
|
+
}
|
|
1870
|
+
: clientConfig.ai;
|
|
1871
|
+
return {
|
|
1872
|
+
...clientConfig,
|
|
1873
|
+
...(ai ? { ai } : {}),
|
|
1874
|
+
...(socialImage === false ? { socialImage: false } : {}),
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
function normalizedPublicRoute(value, fallback) {
|
|
1878
|
+
const normalized = typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
1879
|
+
if (normalized === "/")
|
|
1880
|
+
return "/";
|
|
1881
|
+
return `/${normalized.replace(/^\/+|\/+$/g, "")}`;
|
|
1882
|
+
}
|
|
1883
|
+
function isHtmlDocsPageRequest(config, request) {
|
|
1884
|
+
const method = request.method.toUpperCase();
|
|
1885
|
+
if (method !== "GET" && method !== "HEAD")
|
|
1886
|
+
return false;
|
|
1887
|
+
const url = new URL(request.url);
|
|
1888
|
+
const pathname = url.pathname === "/" ? "/" : url.pathname.replace(/\/+$/, "");
|
|
1889
|
+
const docsPath = normalizedPublicRoute(config.docsPath, `/${config.entry ?? "docs"}`);
|
|
1890
|
+
const isPagePath = docsPath === "/"
|
|
1891
|
+
? !pathname.endsWith(".md")
|
|
1892
|
+
: pathname === docsPath || pathname.startsWith(`${docsPath}/`);
|
|
1893
|
+
if (!isPagePath || pathname.endsWith(".md"))
|
|
1894
|
+
return false;
|
|
1895
|
+
const accept = request.headers.get("accept")?.toLowerCase() ?? "";
|
|
1896
|
+
return !accept.includes("text/markdown");
|
|
1897
|
+
}
|
|
1898
|
+
function runtimeFontClasses(fonts) {
|
|
1899
|
+
return Array.from(new Set([fonts?.body?.className, fonts?.body?.variable, fonts?.code?.variable].filter((value) => typeof value === "string" && value.length > 0))).join(" ");
|
|
1900
|
+
}
|
|
1901
|
+
function runtimeFontStyle(fonts) {
|
|
1902
|
+
const declarations = [];
|
|
1903
|
+
const bodyFontFamily = fonts?.body?.style?.fontFamily?.trim();
|
|
1904
|
+
const codeFontFamily = fonts?.code?.style?.fontFamily?.trim();
|
|
1905
|
+
if (bodyFontFamily) {
|
|
1906
|
+
declarations.push(`--font-sans:${bodyFontFamily}`, `--fd-font-sans:${bodyFontFamily}`);
|
|
1907
|
+
}
|
|
1908
|
+
if (codeFontFamily) {
|
|
1909
|
+
declarations.push(`--font-mono:${codeFontFamily}`, `--fd-font-mono:${codeFontFamily}`);
|
|
1910
|
+
}
|
|
1911
|
+
return declarations.join(";");
|
|
1912
|
+
}
|
|
1913
|
+
function runtimeFontPreloads(fonts) {
|
|
1914
|
+
const seen = new Set();
|
|
1915
|
+
const values = [fonts?.body, fonts?.code].flatMap((font) => font?.preloads ?? []);
|
|
1916
|
+
const unique = values.filter(({ href }) => {
|
|
1917
|
+
if (seen.has(href))
|
|
1918
|
+
return false;
|
|
1919
|
+
seen.add(href);
|
|
1920
|
+
return true;
|
|
1921
|
+
});
|
|
1922
|
+
return {
|
|
1923
|
+
markup: unique
|
|
1924
|
+
.map(({ href, type }) => `<link rel="preload" href="${escapeDocumentText(href)}" as="font" type="${escapeDocumentText(type)}" crossorigin>`)
|
|
1925
|
+
.join("\n "),
|
|
1926
|
+
header: unique
|
|
1927
|
+
.map(({ href, type }) => `<${href}>; rel=preload; as=font; type=${type}; crossorigin`)
|
|
1928
|
+
.join(", "),
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
function renderFarmDocsDocument(input) {
|
|
1932
|
+
const { config, data } = input;
|
|
1933
|
+
const description = data.description ?? config.metadata?.description;
|
|
1934
|
+
const themeName = config.theme?.name ?? "default";
|
|
1935
|
+
const favicon = typeof config.favicon === "string" ? config.favicon : undefined;
|
|
1936
|
+
const rootClasses = runtimeFontClasses(input.fonts);
|
|
1937
|
+
const rootStyle = runtimeFontStyle(input.fonts);
|
|
1938
|
+
const fontPreloads = runtimeFontPreloads(input.fonts).markup;
|
|
1939
|
+
return `<!doctype html>
|
|
1940
|
+
<html class="dark" lang="${escapeDocumentText(data.locale ?? "en")}" data-docs-theme="${escapeDocumentText(themeName)}" data-farm-docs-runtime="true">
|
|
1941
|
+
<head>
|
|
1942
|
+
<meta charset="utf-8">
|
|
1943
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1944
|
+
<meta name="generator" content="@farming-labs/farmjs">
|
|
1945
|
+
<title>${escapeDocumentText(data.title)}</title>
|
|
1946
|
+
${description ? `<meta name="description" content="${escapeDocumentText(description)}">` : ""}
|
|
1947
|
+
${favicon ? `<link rel="icon" href="${escapeDocumentText(favicon)}">` : ""}
|
|
1948
|
+
${fontPreloads}
|
|
1949
|
+
<link rel="stylesheet" href="${FARM_DOCS_BROWSER_CSS_PATH}">
|
|
1950
|
+
${input.stylesheets
|
|
1951
|
+
.map((href) => `<link rel="stylesheet" href="${escapeDocumentText(href)}">`)
|
|
1952
|
+
.join("\n ")}
|
|
1953
|
+
</head>
|
|
1954
|
+
<body>
|
|
1955
|
+
<div id="root"><div id="farm-docs-root"${rootClasses ? ` class="${escapeDocumentText(rootClasses)}"` : ""}${rootStyle ? ` style="${escapeDocumentText(rootStyle)}"` : ""}>${input.markup}</div></div>
|
|
1956
|
+
<script>window.__FARM_DOCS_ADAPTER__={config:${serializeInlineJson(createClientDocsConfig(config))},data:${serializeInlineJson(data)}};</script>
|
|
1957
|
+
<script type="module" src="${escapeDocumentText(input.clientEntry)}"></script>
|
|
1958
|
+
</body>
|
|
1959
|
+
</html>`;
|
|
1960
|
+
}
|
|
1961
|
+
/**
|
|
1962
|
+
* Create the complete Farm docs runtime owned by this adapter.
|
|
1963
|
+
*
|
|
1964
|
+
* Farm core supplies host assets and module loading; this adapter owns route
|
|
1965
|
+
* classification, docs APIs, content loading, React rendering, and hydration
|
|
1966
|
+
* state for every documentation request.
|
|
1967
|
+
*/
|
|
1968
|
+
export function createFarmDocsRuntimeHandler(config, options = {}) {
|
|
1969
|
+
const runtimeConfig = {
|
|
1970
|
+
...config,
|
|
1971
|
+
rootDir: options.rootDir ?? config.rootDir ?? process.cwd(),
|
|
1972
|
+
};
|
|
1973
|
+
const docsServer = createDocsServer(runtimeConfig);
|
|
1974
|
+
return async function handleFarmDocsRuntimeRequest(request) {
|
|
1975
|
+
const url = new URL(request.url);
|
|
1976
|
+
if (url.pathname === FARM_DOCS_BROWSER_CSS_PATH) {
|
|
1977
|
+
return new Response(request.method.toUpperCase() === "HEAD" ? null : loadFarmDocsBrowserCss(), {
|
|
1978
|
+
status: 200,
|
|
1979
|
+
headers: {
|
|
1980
|
+
"Content-Type": "text/css; charset=utf-8",
|
|
1981
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
1982
|
+
},
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
if (!isHtmlDocsPageRequest(runtimeConfig, request)) {
|
|
1986
|
+
return docsServer.handle(request);
|
|
1987
|
+
}
|
|
1988
|
+
let data;
|
|
1989
|
+
try {
|
|
1990
|
+
data = await docsServer.load({ pathname: url.pathname });
|
|
1991
|
+
}
|
|
1992
|
+
catch (error) {
|
|
1993
|
+
const status = error &&
|
|
1994
|
+
typeof error === "object" &&
|
|
1995
|
+
typeof error.status === "number"
|
|
1996
|
+
? error.status
|
|
1997
|
+
: 500;
|
|
1998
|
+
if (status === 404)
|
|
1999
|
+
return null;
|
|
2000
|
+
throw error;
|
|
2001
|
+
}
|
|
2002
|
+
const reactModule = options.loadReactModule
|
|
2003
|
+
? await options.loadReactModule()
|
|
2004
|
+
: (await import("./react.js"));
|
|
2005
|
+
const markup = await renderFarmDocsMarkup(createElement(reactModule.FarmDocsPage, {
|
|
2006
|
+
config: runtimeConfig,
|
|
2007
|
+
data,
|
|
2008
|
+
}));
|
|
2009
|
+
const fonts = await options.resolveLayoutFonts?.(url.pathname);
|
|
2010
|
+
const fontPreloadHeader = runtimeFontPreloads(fonts).header;
|
|
2011
|
+
const html = renderFarmDocsDocument({
|
|
2012
|
+
config: runtimeConfig,
|
|
2013
|
+
data,
|
|
2014
|
+
markup,
|
|
2015
|
+
clientEntry: options.clientEntry ?? "/farm-client.js",
|
|
2016
|
+
stylesheets: options.stylesheets ?? [],
|
|
2017
|
+
fonts,
|
|
2018
|
+
});
|
|
2019
|
+
return new Response(request.method.toUpperCase() === "HEAD" ? null : html, {
|
|
2020
|
+
status: 200,
|
|
2021
|
+
headers: {
|
|
2022
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
2023
|
+
"Cache-Control": "public, s-maxage=60, stale-while-revalidate=300",
|
|
2024
|
+
"X-Farm-Docs-Adapter": "@farming-labs/farmjs",
|
|
2025
|
+
...(fontPreloadHeader ? { Link: fontPreloadHeader } : {}),
|
|
2026
|
+
},
|
|
2027
|
+
});
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
1725
2030
|
//# sourceMappingURL=server.js.map
|