From 873b350ac30a22af930308bc81abbc49d86c15ce Mon Sep 17 00:00:00 2001 From: Jose Montes de Oca Date: Sat, 6 Jun 2026 11:45:03 -0700 Subject: [PATCH] feat: adopt docs.prose.md as the canonical docs domain --- __tests__/canonical.test.ts | 12 ++++++------ __tests__/proxy.test.ts | 20 ++++++++++++++++++++ __tests__/robots.test.ts | 2 +- lib/canonical.ts | 2 +- lib/site.ts | 2 +- package.json | 2 +- proxy.ts | 20 ++++++++++++++++++++ 7 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 __tests__/proxy.test.ts diff --git a/__tests__/canonical.test.ts b/__tests__/canonical.test.ts index c36a616..1f9e925 100644 --- a/__tests__/canonical.test.ts +++ b/__tests__/canonical.test.ts @@ -7,19 +7,19 @@ import { describe("canonicalUrl", () => { it("returns the absolute URL for the root path", () => { - expect(canonicalUrl("/")).toBe("https://docs.openprose.ai/"); + expect(canonicalUrl("/")).toBe("https://docs.prose.md/"); }); it("returns the absolute URL for a nested path", () => { expect(canonicalUrl("/get-started/install")).toBe( - "https://docs.openprose.ai/get-started/install", + "https://docs.prose.md/get-started/install", ); }); - it("ignores the runtime hostname (always pins to docs.openprose.ai)", () => { + it("ignores the runtime hostname (always pins to docs.prose.md)", () => { // Regression: even when running on openprose-docs.fly.dev during preview, - // canonical must point to docs.openprose.ai per spec Section 6. - expect(canonicalUrl("/foo")).toContain("docs.openprose.ai"); + // canonical must point to docs.prose.md per spec Section 6. + expect(canonicalUrl("/foo")).toContain("docs.prose.md"); expect(canonicalUrl("/foo")).not.toContain("fly.dev"); }); }); @@ -40,7 +40,7 @@ describe("buildPageMetadata", () => { it("emits absolute canonical URL for a nested docs path", () => { const md = buildPageMetadata("/docs/get-started/install"); expect(md.alternates?.canonical).toBe( - "https://docs.openprose.ai/docs/get-started/install", + "https://docs.prose.md/docs/get-started/install", ); }); diff --git a/__tests__/proxy.test.ts b/__tests__/proxy.test.ts new file mode 100644 index 0000000..501c21c --- /dev/null +++ b/__tests__/proxy.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { resolveDocsHostRedirect } from '../proxy'; + +describe('resolveDocsHostRedirect', () => { + it('redirects the legacy docs host to docs.prose.md', () => { + expect(resolveDocsHostRedirect('docs.openprose.ai', '/foo?x=1')).toBe( + 'https://docs.prose.md/foo?x=1', + ); + }); + + it('ignores the canonical docs host', () => { + expect(resolveDocsHostRedirect('docs.prose.md', '/foo?x=1')).toBeNull(); + }); + + it('ignores the Fly preview host', () => { + expect( + resolveDocsHostRedirect('openprose-docs.fly.dev', '/foo?x=1'), + ).toBeNull(); + }); +}); diff --git a/__tests__/robots.test.ts b/__tests__/robots.test.ts index 896fb3f..1a65136 100644 --- a/__tests__/robots.test.ts +++ b/__tests__/robots.test.ts @@ -28,6 +28,6 @@ describe("app/robots.ts", () => { allow: "/", }); expect(config.rules).toContainEqual({ userAgent: "CCBot", allow: "/" }); - expect(config.sitemap).toBe("https://docs.openprose.ai/sitemap.xml"); + expect(config.sitemap).toBe("https://docs.prose.md/sitemap.xml"); }); }); diff --git a/lib/canonical.ts b/lib/canonical.ts index ceec088..37ab1fe 100644 --- a/lib/canonical.ts +++ b/lib/canonical.ts @@ -4,7 +4,7 @@ import { isPreviewMode } from "./preview-mode"; /** * Returns the absolute canonical URL for a docs path. The path argument - * MUST start with '/'. We pin the host to docs.openprose.ai regardless of + * MUST start with '/'. We pin the host to docs.prose.md regardless of * the actual runtime hostname, so preview deploys at openprose-docs.fly.dev * still emit the production canonical (preventing split-indexing on cutover). */ diff --git a/lib/site.ts b/lib/site.ts index e2bda67..dd86967 100644 --- a/lib/site.ts +++ b/lib/site.ts @@ -1,3 +1,3 @@ export const SITE = { - canonicalBaseUrl: "https://docs.openprose.ai", + canonicalBaseUrl: "https://docs.prose.md", } as const; diff --git a/package.json b/package.json index b3b2720..11d1fe8 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "type": "git", "url": "https://github.com/openprose/docs.git" }, - "homepage": "https://docs.openprose.ai", + "homepage": "https://docs.prose.md", "packageManager": "pnpm@10.11.0", "scripts": { "postinstall": "fumadocs-mdx", diff --git a/proxy.ts b/proxy.ts index dabe3a6..72c986d 100644 --- a/proxy.ts +++ b/proxy.ts @@ -11,7 +11,27 @@ const { rewrite: rewriteSuffix } = rewritePath( `${docsContentRoute}{/*path}/content.md`, ); +export function resolveDocsHostRedirect( + host: string, + pathWithSearch: string, +): string | null { + const hostname = host.split(':')[0]; + + if (hostname !== 'docs.openprose.ai') return null; + + return `https://docs.prose.md${pathWithSearch}`; +} + export default function proxy(request: NextRequest) { + const hostRedirect = resolveDocsHostRedirect( + request.headers.get('host') ?? '', + `${request.nextUrl.pathname}${request.nextUrl.search}`, + ); + + if (hostRedirect) { + return NextResponse.redirect(hostRedirect, 301); + } + const result = rewriteSuffix(request.nextUrl.pathname); if (result) { return NextResponse.rewrite(new URL(result, request.nextUrl));