UNPKG

@universal-middleware/compress

Version:
176 lines (172 loc) 6.08 kB
import { nodeHeadersToWeb } from './chunk-A5W3PKM7.js'; // ../node/dist/chunk-Q2IKOWAS.js var requestSymbol = /* @__PURE__ */ Symbol.for("unRequest"); var env = typeof globalThis.process?.env !== "undefined" ? globalThis.process.env : typeof import.meta?.env !== "undefined" ? import.meta.env : {}; var deno = typeof Deno !== "undefined"; var bun = typeof Bun !== "undefined"; function createRequestAdapter(options = {}) { const { origin = env.ORIGIN, trustProxy = env.TRUST_PROXY === "1" } = options; let { protocol: protocolOverride, host: hostOverride } = origin ? new URL(origin) : {}; if (protocolOverride) { protocolOverride = protocolOverride.slice(0, -1); } let warned = false; return function requestAdapter(req, res) { if (req[requestSymbol]) { return req[requestSymbol]; } function parseForwardedHeader(name) { return (headers[`x-forwarded-${name}`] || "").split(",", 1)[0].trim(); } let headers = req.headers; if (headers[":method"]) { headers = Object.fromEntries(Object.entries(headers).filter(([key]) => !key.startsWith(":"))); } const protocol = protocolOverride || trustProxy && parseForwardedHeader("proto") || req.protocol || // biome-ignore lint/suspicious/noExplicitAny: encrypted can exist in some express versions req.socket?.encrypted && "https" || "http"; let host = hostOverride || trustProxy && parseForwardedHeader("host") || headers.host; if (!host && !warned) { console.warn( "Could not automatically determine the origin host, using 'localhost'. Use the 'origin' option or the 'ORIGIN' environment variable to set the origin explicitly." ); warned = true; host = "localhost"; } const abortController = new AbortController(); res.once("close", () => { if (!res.writableEnded) abortController.abort(); }); const request = new Request(`${protocol}://${host}${req.originalUrl ?? req.url}`, { method: req.method, headers, body: convertBody(req), signal: abortController.signal, // @ts-expect-error duplex: "half" }); req[requestSymbol] = request; return request; }; } function convertBody(req) { if (req.method === "GET" || req.method === "HEAD") { return; } if (req.rawBody !== void 0) { return req.rawBody; } if (!bun && !deno) { return req; } return new ReadableStream({ start(controller) { req.on("data", (chunk) => { controller.enqueue(chunk); if ((controller.desiredSize ?? 1) <= 0) req.pause(); }); req.on("end", () => controller.close()); req.on("error", (err) => controller.error(err)); }, pull() { req.resume(); }, cancel(reason) { req.destroy(reason instanceof Error ? reason : void 0); } }); } // ../node/dist/chunk-TQRO4M5X.js async function sendResponse(fetchResponse, nodeResponse) { const fetchBody = fetchResponse.body; let body = null; if (!fetchBody) { body = null; } else if (typeof fetchBody.pipe === "function") { body = fetchBody; } else if (typeof fetchBody.pipeTo === "function") { const { Readable } = await import('node:stream'); if (Readable.fromWeb) { body = Readable.fromWeb(fetchBody); } else { const reader = fetchBody.getReader(); body = new Readable({ async read() { try { const { done, value } = await reader.read(); if (done) { this.push(null); } else { const canContinue = this.push(value); if (!canContinue) { reader.releaseLock(); } } } catch (e) { this.destroy(e); } }, destroy(err, callback) { reader.cancel().finally(() => callback(err)); } }); } } else if (fetchBody) { const { Readable } = await import('node:stream'); body = Readable.from(fetchBody); } setResponseHeaders(fetchResponse, nodeResponse); if (body) { const { pipeline } = await import('node:stream/promises'); await pipeline(body, nodeResponse).catch(() => { }); } else { nodeResponse.setHeader("content-length", "0"); nodeResponse.end(); } } function getFullUrl(pathnameOrFull, req) { try { return new URL(pathnameOrFull).href; } catch { const protocol = req.socket?.encrypted || req.headers["x-forwarded-proto"] === "https" ? "https" : "http"; const host = req.headers["x-forwarded-host"] || req.headers.host || "localhost"; const baseUrl = `${protocol}://${host}`; return new URL(pathnameOrFull, baseUrl).href; } } function responseAdapter(nodeResponse, bodyInit) { if ([301, 302, 303, 307, 308].includes(nodeResponse.statusCode) && nodeResponse.req) { const location = nodeResponse.getHeader("location"); if (location) { const fullUrl = getFullUrl(location, nodeResponse.req); return Response.redirect(fullUrl, nodeResponse.statusCode); } } return new Response([204, 304].includes(nodeResponse.statusCode) ? null : bodyInit, { status: nodeResponse.statusCode, statusText: nodeResponse.statusMessage, headers: nodeHeadersToWeb(nodeResponse.getHeaders()) }); } function setResponseHeaders(fetchResponse, nodeResponse, mirror = false) { nodeResponse.statusCode = fetchResponse.status; if (fetchResponse.statusText) { nodeResponse.statusMessage = fetchResponse.statusText; } const nodeResponseHeaders = new Set(Object.keys(nodeResponse.getHeaders())); const setCookie = fetchResponse.headers.getSetCookie(); for (const cookie of setCookie) { nodeResponse.appendHeader("set-cookie", cookie); } fetchResponse.headers.forEach((value, key) => { nodeResponseHeaders.delete(key); if (key === "set-cookie") return; nodeResponse.setHeader(key, value); }); if (mirror) { nodeResponseHeaders.forEach((key) => { nodeResponse.removeHeader(key); }); } } export { createRequestAdapter, responseAdapter, sendResponse, setResponseHeaders };