Skip to content

Commit 2acef7b

Browse files
devin-ai-integration[bot]dannysheridandsinghvivercel[bot]davidkonigsberg
authored
test(docs): add comprehensive tests and monitoring for llms.txt endpoints (#4676)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: [email protected] <[email protected]> Co-authored-by: Deep Singhvi <[email protected]> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: David Konigsberg <[email protected]>
1 parent df9b4c7 commit 2acef7b

File tree

5 files changed

+623
-2
lines changed

5 files changed

+623
-2
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Monitor LLM-friendly Docs Endpoints
2+
3+
on:
4+
schedule:
5+
# Run every 5 minutes
6+
- cron: '*/5 * * * *'
7+
workflow_dispatch: # Allow manual triggering
8+
9+
jobs:
10+
monitor:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 10
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: '20'
22+
23+
- name: Install dependencies
24+
run: |
25+
npm install -g tsx
26+
27+
- name: Run monitoring script
28+
env:
29+
SLACK_WEBHOOK_URL_DOCS_INCIDENTS: ${{ secrets.SLACK_WEBHOOK_URL_DOCS_INCIDENTS }}
30+
INCIDENT_API_KEY: ${{ secrets.INCIDENT_API_KEY }}
31+
DRY_RUN: ${{ github.event_name == 'push' && '1' || '0' }}
32+
continue-on-error: ${{ github.event_name == 'push' }}
33+
run: |
34+
tsx scripts/monitor/check-llms-md-endpoints.ts

biome.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,8 @@
381381
"packages/workers/proxy/src/websocket.ts",
382382
"packages/generator-cli/src/**/*.ts",
383383
"packages/commons/visual-editor-server/src/mongodb-client.ts",
384-
"servers/fdr-lambda/src/index.ts"
384+
"servers/fdr-lambda/src/index.ts",
385+
"scripts/monitor/**/*.ts"
385386
],
386387
"linter": {
387388
"rules": {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { NextRequest } from "next/server";
2+
import { describe, expect, it, vi } from "vitest";
3+
4+
describe("markdown route slug handling", () => {
5+
const createMockRequest = (pathname: string, searchParams: Record<string, string> = {}) => {
6+
const url = new URL(`https://example.com${pathname}`);
7+
Object.entries(searchParams).forEach(([key, value]) => {
8+
url.searchParams.set(key, value);
9+
});
10+
return new NextRequest(url);
11+
};
12+
13+
it("should prefer slug from search params over pathname", () => {
14+
const request = createMockRequest("/api/fern-docs/markdown", { slug: "docs/quickstart" });
15+
16+
const slugParam = request.nextUrl.searchParams.get("slug");
17+
const slug = slugParam ?? request.nextUrl.pathname.replace(/\.(md|mdx)$/, "");
18+
19+
expect(slug).toBe("docs/quickstart");
20+
});
21+
22+
it("should fallback to pathname parsing when slug param is not present", () => {
23+
const request = createMockRequest("/docs/quickstart.md");
24+
25+
const slugParam = request.nextUrl.searchParams.get("slug");
26+
const slug = slugParam ?? request.nextUrl.pathname.replace(/\.(md|mdx)$/, "");
27+
28+
expect(slug).toBe("/docs/quickstart");
29+
});
30+
31+
it("should handle .mdx extension in pathname fallback", () => {
32+
const request = createMockRequest("/docs/quickstart.mdx");
33+
34+
const slugParam = request.nextUrl.searchParams.get("slug");
35+
const slug = slugParam ?? request.nextUrl.pathname.replace(/\.(md|mdx)$/, "");
36+
37+
expect(slug).toBe("/docs/quickstart");
38+
});
39+
40+
it("should handle nested paths in slug param", () => {
41+
const request = createMockRequest("/api/fern-docs/markdown", {
42+
slug: "learn/sdks/overview/quickstart"
43+
});
44+
45+
const slugParam = request.nextUrl.searchParams.get("slug");
46+
const slug = slugParam ?? request.nextUrl.pathname.replace(/\.(md|mdx)$/, "");
47+
48+
expect(slug).toBe("learn/sdks/overview/quickstart");
49+
});
50+
51+
it("should handle empty slug param", () => {
52+
const request = createMockRequest("/api/fern-docs/markdown", { slug: "" });
53+
54+
const slugParam = request.nextUrl.searchParams.get("slug");
55+
const slug = slugParam ?? request.nextUrl.pathname.replace(/\.(md|mdx)$/, "");
56+
57+
expect(slug).toBe("");
58+
});
59+
});

packages/fern-docs/bundle/src/app/[host]/[domain]/api/fern-docs/markdown/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export async function GET(
3030
const fernToken = req.headers.get("FERN_TOKEN") ?? (await cookies()).get(COOKIE_FERN_TOKEN)?.value;
3131

3232
const path = req.nextUrl.pathname;
33-
const slug = path.replace(MARKDOWN_PATTERN, "");
33+
const slugParam = req.nextUrl.searchParams.get("slug");
34+
const slug = slugParam ?? path.replace(MARKDOWN_PATTERN, "");
3435
const cleanSlug = removeLeadingSlash(slug);
3536

3637
const loader = await createCachedDocsLoader(host, domain, fernToken);

0 commit comments

Comments
 (0)