@universal-middleware/compress
Version:
Universal compress middleware
176 lines (172 loc) • 6.08 kB
JavaScript
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 };