Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

34 linesCodeBlameRaw
1import { renderToReadableStream } from "react-dom/server";
2import { type EntryContext, ServerRouter } from "react-router";
3
4import { makeNonce, pagePolicy } from "./lib/guard";
5
6/**
7 * Renders the whole page before sending it, then the browser hydrates it.
8 * The page runs only sudo's own scripts: React Router writes its inline
9 * scripts and preloads with this page's nonce (ServerRouter hands it to
10 * <Links>, <Scripts> and <ScrollRestoration>), and the page's policy
11 * names that nonce and nothing else (lib/guard.ts). workers/app.ts keeps
12 * the policy set here.
13 */
14export default async function handleRequest(
15 request: Request,
16 responseStatusCode: number,
17 responseHeaders: Headers,
18 routerContext: EntryContext,
19) {
20 let status = responseStatusCode;
21 const nonce = makeNonce();
22 const body = await renderToReadableStream(<ServerRouter context={routerContext} url={request.url} nonce={nonce} />, {
23 nonce,
24 signal: request.signal,
25 onError(error: unknown) {
26 status = 500;
27 console.error(error);
28 },
29 });
30 await body.allReady;
31 responseHeaders.set("content-type", "text/html; charset=utf-8");
32 responseHeaders.set("content-security-policy", pagePolicy(nonce));
33 return new Response(body, { headers: responseHeaders, status });
34}