import type { IncomingMessage, ServerResponse } from "node:http"; import type { App } from "../core/app.ts"; import { existsSync } from "node:fs"; import { writeFile } from "node:fs/promises"; import { join, resolve } from "node:path"; export type NodeHandler = ( request: IncomingMessage, response: ServerResponse, ) => Promise; /** Creates a minimal Vercel configuration when the project has none. */ export async function setupVercel(root: string): Promise { const path = join(resolve(root), "vercel.json"); if (existsSync(path)) return path; await writeFile( path, `${JSON.stringify({ cleanUrls: true }, null, 2)}\n`, "utf8", ); return path; } /** Creates the node handler of the application. */ export function createHandler(app: App): NodeHandler { return async (request, response) => { const url = `http://${request.headers.host ?? "localhost"}${request.url ?? "/"}`; const method = (request.method ?? "GET").toUpperCase(); const headers = new Headers(); for (const [name, value] of Object.entries(request.headers)) { if (value === undefined) continue; if (Array.isArray(value)) { for (const entry of value) headers.append(name, entry); continue; } headers.set(name, value); } const body = method === "GET" || method === "HEAD" ? undefined : await readBody(request); const fetchRequest = new Request(url, { method, headers, body, duplex: body ? "half" : undefined, } as RequestInit); const result = await app.fetch(fetchRequest); response.statusCode = result.status; result.headers.forEach((value, name) => { response.setHeader(name, value); }); if (result.body) { const buffer = Buffer.from(await result.arrayBuffer()); response.end(buffer); return; } response.end(); }; } async function readBody(request: IncomingMessage): Promise { const chunks: Buffer[] = []; for await (const chunk of request) { chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); } return Buffer.concat(chunks); }