/** * Shared HTTP server utilities for route handlers. * Owner: T-1.5 */ import type { IncomingMessage, ServerResponse } from "node:http"; /** Read the full request body as a string. */ export function readBody(req: IncomingMessage): Promise { return new Promise((resolve, reject) => { const chunks: Buffer[] = []; req.on("data", (chunk: Buffer) => chunks.push(chunk)); req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); req.on("error", reject); }); } /** Send a JSON response. */ export function sendJson( res: ServerResponse, status: number, body: unknown, ): void { const payload = JSON.stringify(body); res.writeHead(status, { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload), }); res.end(payload); } /** Extract a path segment by index (0-based, after splitting on '/'). */ export function pathSegment(url: string, index: number): string | undefined { return url.split("?")[0].split("/").filter(Boolean)[index]; } /** * Parse bearer token from Authorization header or ?token= query param. * Returns the raw token string or null. */ export function extractBearer(req: IncomingMessage): string | null { const auth = req.headers["authorization"]; if (auth?.startsWith("Bearer ")) return auth.slice(7).trim(); if (auth?.startsWith("bearer ")) return auth.slice(7).trim(); const url = new URL(req.url ?? "/", "http://localhost"); return url.searchParams.get("token"); }