diff --git a/apps/server/src/http/app.test.ts b/apps/server/src/http/app.test.ts index c41690342..902644e24 100644 --- a/apps/server/src/http/app.test.ts +++ b/apps/server/src/http/app.test.ts @@ -192,4 +192,16 @@ describe("createApp", () => { expect(mocks.serveWebDistStatic).not.toHaveBeenCalled(); expect(mocks.handleWebApp).not.toHaveBeenCalled(); }); + + it.each(["GET", "HEAD"])("routes %s / to the web app handler so SEO markup is injected", async (method) => { + const { createApp } = await import("./app"); + const app = createApp(); + const request = new Request("http://localhost:3001/", { method }); + + const response = await app.fetch(request); + + expect(response.status).toBe(200); + expect(mocks.handleWebApp).toHaveBeenCalledWith(request); + expect(mocks.serveWebDistStatic).not.toHaveBeenCalled(); + }); }); diff --git a/apps/server/src/http/app.ts b/apps/server/src/http/app.ts index bf8cba197..677f92d5a 100644 --- a/apps/server/src/http/app.ts +++ b/apps/server/src/http/app.ts @@ -65,6 +65,9 @@ export function createApp() { app.on(["GET", "HEAD"], "/sitemap.xml", (c) => handleSitemap({ head: c.req.method === "HEAD" })); app.on(["GET", "HEAD"], "/llms.txt", (c) => handleLlms({ head: c.req.method === "HEAD" })); + // Must precede the static middleware: serveStatic resolves "/" to dist/index.html and would + // return it verbatim, skipping the OpenGraph/Twitter/canonical/JSON-LD injection in handleWebApp. + app.on(["GET", "HEAD"], "/", (c) => handleWebApp(c.req.raw)); app.use("/*", serveWebDistStatic); app.on(["GET", "HEAD"], "/*", (c) => handleWebApp(c.req.raw));