diff --git a/docs/site/app/[lang]/llms.md/[[...slug]]/route.ts b/docs/site/app/[lang]/llms.md/[[...slug]]/route.ts index 1f955f960b5ac..532b08a6b495e 100644 --- a/docs/site/app/[lang]/llms.md/[[...slug]]/route.ts +++ b/docs/site/app/[lang]/llms.md/[[...slug]]/route.ts @@ -1,10 +1,11 @@ import { notFound } from "next/navigation"; import { getLLMText, source } from "@/lib/geistdocs/source"; +import { trackMdRequest } from "@/lib/md-tracking"; export const revalidate = false; export async function GET( - _req: Request, + req: Request, { params }: RouteContext<"/[lang]/llms.md/[[...slug]]"> ) { const { slug, lang } = await params; @@ -14,6 +15,17 @@ export async function GET( notFound(); } + // Track markdown request (fire-and-forget) + const userAgent = req.headers.get("user-agent"); + const referer = req.headers.get("referer"); + const acceptHeader = req.headers.get("accept"); + void trackMdRequest({ + path: `/llms.md/${slug?.join("/") ?? ""}`, + userAgent, + referer, + acceptHeader + }); + return new Response(await getLLMText(page), { headers: { "Content-Type": "text/markdown" diff --git a/docs/site/app/[lang]/llms.txt/route.ts b/docs/site/app/[lang]/llms.txt/route.ts index 51a86b31c6037..a93c5a5bcc212 100644 --- a/docs/site/app/[lang]/llms.txt/route.ts +++ b/docs/site/app/[lang]/llms.txt/route.ts @@ -1,5 +1,6 @@ import type { NextRequest } from "next/server"; import { source } from "@/lib/geistdocs/source"; +import { trackMdRequest } from "@/lib/md-tracking"; export const revalidate = false; @@ -7,12 +8,23 @@ const TURBO_SLOGAN = "Turborepo is a build system optimized for JavaScript and TypeScript, written in Rust."; export const GET = async ( - _req: NextRequest, + req: NextRequest, { params }: RouteContext<"/[lang]/llms.txt"> ) => { const { lang } = await params; const pages = source.getPages(lang); + // Track markdown request (fire-and-forget) + const userAgent = req.headers.get("user-agent"); + const referer = req.headers.get("referer"); + const acceptHeader = req.headers.get("accept"); + void trackMdRequest({ + path: "/llms.txt", + userAgent, + referer, + acceptHeader + }); + const links = pages .sort((a, b) => a.url.localeCompare(b.url)) .map((page) => { diff --git a/docs/site/lib/md-tracking.ts b/docs/site/lib/md-tracking.ts new file mode 100644 index 0000000000000..3a59c431151b2 --- /dev/null +++ b/docs/site/lib/md-tracking.ts @@ -0,0 +1,53 @@ +const MD_TRACKING_URL = process.env.MD_TRACKING_URL; +const MD_TRACKING_API_KEY = process.env.MD_TRACKING_API_KEY; + +interface TrackMdRequestParams { + path: string; + userAgent: string | null; + referer: string | null; + acceptHeader: string | null; +} + +/** + * Track a markdown page request to the feedback-app analytics. + * Fire-and-forget: errors are logged but don't affect the response. + */ +export async function trackMdRequest({ + path, + userAgent, + referer, + acceptHeader +}: TrackMdRequestParams): Promise { + if (!MD_TRACKING_URL || !MD_TRACKING_API_KEY) { + // Tracking not configured, skip silently + return; + } + + try { + const response = await fetch(MD_TRACKING_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${MD_TRACKING_API_KEY}` + }, + body: JSON.stringify({ + path, + source: "turborepo", + userAgent, + referer, + acceptHeader + }) + }); + + if (!response.ok) { + console.error( + "MD tracking failed:", + response.status, + await response.text() + ); + } + } catch (error) { + // Fire-and-forget: don't let tracking errors affect the response + console.error("MD tracking error:", error); + } +}