import type { HostApiResult } from '@src/types/runtime'; import type { IncomingMessage, ServerResponse } from 'node:http'; export interface HostApiRequest { path: string; method?: string; headers?: Record; body?: unknown; } export interface NormalizedHostApiRequest { path: string; pathname: string; method: string; headers: Record; body: unknown; url: URL; } export async function parseRawJsonBody(req: IncomingMessage): Promise { const chunks: Buffer[] = []; for await (const chunk of req) { chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); } const raw = Buffer.concat(chunks).toString('utf8').trim(); if (!raw) { return {} as T; } return JSON.parse(raw) as T; } export function normalizeRequest(request: HostApiRequest): NormalizedHostApiRequest { const path = String(request.path || '/').trim() || '/'; return { path, pathname: new URL(path, 'http://127.0.0.1').pathname, method: String(request.method || 'GET').trim().toUpperCase(), headers: request.headers || {}, body: request.body ?? null, url: new URL(path, 'http://127.0.0.1'), }; } export function parseJsonBody(body: unknown): T { if (body == null || body === '') { return {} as T; } if (typeof body === 'string') { return JSON.parse(body) as T; } return body as T; } export function ok(data: T, status = 200): HostApiResult { return { success: true, ok: true, status, json: data, data, }; } export function fail(status: number, error: string, data?: T): HostApiResult { return { success: false, ok: false, status, error, text: error, data, }; } export function setCorsHeaders(res: ServerResponse, origin?: string): void { if (origin) { res.setHeader('Access-Control-Allow-Origin', origin); res.setHeader('Vary', 'Origin'); } else { res.setHeader('Access-Control-Allow-Origin', '*'); } res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Host-Api-Token'); } export function requireJsonContentType(req: IncomingMessage): boolean { if (req.method === 'GET' || req.method === 'OPTIONS' || req.method === 'HEAD') { return true; } const contentLength = req.headers['content-length']; if (contentLength === '0' || contentLength === undefined) { return true; } const contentType = req.headers['content-type'] || ''; return contentType.includes('application/json'); } export function sendJsonResponse(res: ServerResponse, statusCode: number, payload: unknown): void { res.statusCode = statusCode; res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.end(JSON.stringify(payload)); }