Skip to content
File

Blob: src/worker/lib/http-entry.ts

typescript70 lines
1import { matchSiteHost } from "@/worker/lib/host-match";
2 
3type Awaitable<T> = T | Promise<T>;
4 
5export interface HttpEntryDeps<TEnv> {
6 handlePartyRequest: (request: Request, env: TEnv) => Awaitable<Response | null>;
7 handleAppRequest: (request: Request, env: TEnv, ctx: ExecutionContext) => Awaitable<Response>;
8 handleAssetRequest: (request: Request, env: TEnv) => Awaitable<Response>;
9 handleShellRequest: (request: Request, env: TEnv) => Awaitable<Response>;
10 handleSiteRequest: (request: Request, env: TEnv, ctx: ExecutionContext) => Awaitable<Response>;
11}
12 
13export function isDirectAssetRequest(pathname: string): boolean {
14 return /\.\w+$/.test(pathname) && !pathname.endsWith(".html");
15}
16 
17export function isViteDevRuntimeAssetRequest(request: Request): boolean {
18 if (request.method !== "GET" && request.method !== "HEAD") return false;
19 
20 const { pathname } = new URL(request.url);
21 return pathname.startsWith("/@") || pathname.startsWith("/src/") || pathname.startsWith("/node_modules/");
22}
23 
24export async function handleHttpRequest<TEnv extends Pick<Env, "PUBLISHED_SITE_DOMAIN">>(
25 request: Request,
26 env: TEnv,
27 ctx: ExecutionContext,
28 deps: HttpEntryDeps<TEnv>,
29): Promise<Response> {
30 const url = new URL(request.url);
31 
32 if (import.meta.env.DEV && isViteDevRuntimeAssetRequest(request)) {
33 return deps.handleAssetRequest(request, env);
34 }
35 
36 // Site host dispatch runs BEFORE any path-prefix branch so a published
37 // subdomain or apex request never falls through to /api, /uploads, the
38 // SPA shell, or the static asset binding. The Sites surface owns every
39 // path under its host (Class A page/asset OR Class B robots/apex).
40 const siteMatch = matchSiteHost(url, env);
41 if (siteMatch.kind !== "none") {
42 return deps.handleSiteRequest(request, env, ctx);
43 }
44 
45 const { pathname } = url;
46 const isReadRequest = request.method === "GET" || request.method === "HEAD";
47 
48 if (pathname.startsWith("/parties/")) {
49 return (await deps.handlePartyRequest(request, env)) ?? deps.handleAppRequest(request, env, ctx);
50 }
51 
52 if (pathname.startsWith("/api/") || pathname.startsWith("/uploads/")) {
53 return deps.handleAppRequest(request, env, ctx);
54 }
55 
56 if (isReadRequest && isDirectAssetRequest(pathname)) {
57 return deps.handleAssetRequest(request, env);
58 }
59 
60 if (request.method === "GET") {
61 return deps.handleShellRequest(request, env);
62 }
63 
64 if (request.method === "HEAD") {
65 return deps.handleAssetRequest(request, env);
66 }
67 
68 return deps.handleAppRequest(request, env, ctx);
69}