import http from 'node:http'; import https from 'node:https'; type RequestHeaders = Record; export type TestRequestInit = { method?: string; headers?: RequestHeaders; body?: string; }; type TestHeaders = { get(name: string): string | null; }; export type TestResponse = { status: number; headers: TestHeaders; text(): Promise; json(): Promise; }; function createHeadersMap(headers: http.IncomingHttpHeaders): TestHeaders { const values = new Map(); for (const [key, value] of Object.entries(headers)) { if (typeof value === 'string') { values.set(key.toLowerCase(), value); continue; } if (Array.isArray(value)) { values.set(key.toLowerCase(), value.join(', ')); } } return { get(name: string) { return values.get(name.toLowerCase()) ?? null; }, }; } export async function httpRequest( urlText: string, init: TestRequestInit = {}, ): Promise { const url = new URL(urlText); const transport = url.protocol === 'https:' ? https : http; return new Promise((resolve, reject) => { const request = transport.request( { protocol: url.protocol, hostname: url.hostname, port: url.port, path: `${url.pathname}${url.search}`, method: init.method ?? 'GET', headers: init.headers, }, (response) => { const chunks: Buffer[] = []; response.on('data', (chunk) => { chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); }); response.on('end', () => { const body = Buffer.concat(chunks).toString('utf8'); resolve({ status: response.statusCode ?? 0, headers: createHeadersMap(response.headers), async text() { return body; }, async json() { return JSON.parse(body) as T; }, }); }); }, ); request.on('error', reject); if (typeof init.body === 'string' && init.body.length > 0) { request.write(init.body); } request.end(); }); }