/** * Deployed-app (Nitro) half of the platform PWA chrome. Auto-registered as * global h3 middleware because vite.config.ts sets `serverDir: "./server"` — * without that option Nitro v3 never scans this directory. * * - `?install=1&platform=ios` on a document path → the Home Screen tutorial, * bundled into the server build via `?raw` (the public/ directory is CDN * static output on Vercel and not readable from the function). * - `/__grok/manifest.webmanifest` → per-app-named manifest (kept out of * public/ so this dynamic response is the only one). * - Other HTML documents → stream-inject PWA + OG head tags at ``. * OG identity is baked via `virtual:grok-og-identity` at `vite build` * (this function cannot read `src/lib/og/site.json` or `public/og.jpg`). * This must be a middleware transforming `next()`: h3 discards the `response` * runtime hook's return value, and `render:html` does not exist in Nitro v3. */ import installPageTemplate from "../../scripts/install-page.html?raw"; import { grokOgIdentity } from "virtual:grok-og-identity"; import { acceptsHtml, createHeadInjector, isDocumentPath, isInstallQuery, renderInstallPageHtml, renderWebManifest, } from "../../scripts/grok-pwa-shared.mjs"; interface GrokPwaEvent { url: URL; req: { method: string; headers: Headers }; } function requestHost(event: GrokPwaEvent): string { return ( event.req.headers.get("x-forwarded-host") ?? event.req.headers.get("host") ?? event.url.host ); } function injectHeadStreaming(response: Response, host: string): Response { const injector = createHeadInjector({ host, site: grokOgIdentity.site, }); const transformed = response.body!.pipeThrough( new TransformStream({ transform(chunk, controller) { for (const out of injector.push(chunk)) controller.enqueue(out); }, flush(controller) { for (const out of injector.flush()) controller.enqueue(out); }, }), ); const headers = new Headers(response.headers); headers.delete("content-length"); return new Response(transformed, { status: response.status, statusText: response.statusText, headers, }); } export default async function grokPwaMiddleware( event: GrokPwaEvent, next: () => unknown | Promise, ): Promise { const method = (event.req.method ?? "GET").toUpperCase(); if (method !== "GET") return next(); const path = event.url.pathname; const urlWithQuery = path + event.url.search; if (path === "/__grok/manifest.webmanifest" || path === "/__grok/manifest.json") { return new Response(renderWebManifest(requestHost(event)), { headers: { "content-type": "application/manifest+json; charset=utf-8", "cache-control": "no-cache", }, }); } if ( isInstallQuery(urlWithQuery) && isDocumentPath(path) && acceptsHtml(event.req.headers.get("accept")) ) { const html = renderInstallPageHtml(installPageTemplate, { host: requestHost(event), url: urlWithQuery, }); return new Response(html, { headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-cache", }, }); } if (!isDocumentPath(path)) return next(); const result = await next(); if ( result instanceof Response && result.body && String(result.headers.get("content-type") ?? "").includes("text/html") && !result.headers.get("content-encoding") ) { return injectHeadStreaming(result, requestHost(event)); } return result; }