@universal-middleware/compress
Version:
Universal compress middleware
202 lines (198 loc) • 6.08 kB
JavaScript
import { createRequestAdapter, sendResponse, responseAdapter, setResponseHeaders } from './chunk-DZTR7BGC.js';
import { bindUniversal, contextSymbol, universalSymbol, getAdapterRuntime } from './chunk-A5W3PKM7.js';
import { middleware_default } from './chunk-OE4YTAMF.js';
import 'node:http';
import 'node:stream';
var pendingMiddlewaresSymbol = /* @__PURE__ */ Symbol.for("unPendingMiddlewares");
var wrappedResponseSymbol = /* @__PURE__ */ Symbol.for("unWrappedResponse");
function createTransformStream() {
const textEncoder = new TextEncoder();
return new TransformStream({
transform(chunk, ctrl) {
if (typeof chunk === "string") {
ctrl.enqueue(textEncoder.encode(chunk));
} else if (chunk instanceof Uint8Array) {
ctrl.enqueue(chunk);
} else {
ctrl.enqueue(new Uint8Array(chunk));
}
}
});
}
function override(nodeResponse, key, forwardTo) {
const original = nodeResponse[key];
nodeResponse[key] = (...args) => {
if (!nodeResponse.headersSent) {
nodeResponse.writeHead(nodeResponse.statusCode);
}
if (args[0] && args[0].length > 0) {
forwardTo.write(args[0]).catch(console.error);
}
if (key === "end") {
forwardTo.close().catch(() => {
});
}
return true;
};
return {
original(...args) {
original.apply(nodeResponse, args);
},
restore() {
nodeResponse[key] = original;
}
};
}
function overrideWriteHead(nodeResponse, callback) {
const original = nodeResponse.writeHead;
let alreadyCalled = false;
nodeResponse.writeHead = () => {
if (!alreadyCalled) {
callback().catch(console.error);
alreadyCalled = true;
}
return nodeResponse;
};
return {
original(...args) {
original.apply(nodeResponse, args);
},
restore() {
nodeResponse.writeHead = original;
}
};
}
function wrapResponse(nodeResponse, next) {
if (nodeResponse[wrappedResponseSymbol]) return;
nodeResponse[wrappedResponseSymbol] = true;
const body = createTransformStream();
const writer = body.writable.getWriter();
const [reader1, reader2] = body.readable.tee();
const original = {
write: override(nodeResponse, "write", writer),
end: override(nodeResponse, "end", writer),
writeHead: overrideWriteHead(nodeResponse, triggerPendingMiddlewares)
};
async function triggerPendingMiddlewares() {
if (!nodeResponse[pendingMiddlewaresSymbol]) {
return;
}
const middlewares = nodeResponse[pendingMiddlewaresSymbol];
delete nodeResponse[pendingMiddlewaresSymbol];
let response;
try {
response = responseAdapter(nodeResponse, reader1);
for (const middleware of middlewares) {
const tmp = await middleware(response);
if (tmp) response = tmp;
}
} catch (e) {
response = void 0;
await writer.abort();
original.writeHead.restore();
original.write.restore();
original.end.restore();
if (next) {
next(e);
} else {
throw e;
}
}
if (!response) return;
const readableToOriginal = response.body ?? reader2;
setResponseHeaders(response, nodeResponse, true);
original.writeHead.restore();
nodeResponse.flushHeaders();
const wait = readableToOriginal.pipeTo(
new WritableStream({
write(chunk) {
original.write.original(chunk);
},
close() {
original.end.original();
},
abort() {
original.end.original();
}
})
);
await wait;
original.write.restore();
original.end.restore();
}
}
function nextOr404(res, next) {
if (next) {
next();
} else {
res.statusCode = 404;
res.end();
}
}
function createMiddleware(middlewareFactory, options = {}) {
const requestAdapter = createRequestAdapter(options);
return (...args) => {
const middleware = middlewareFactory(...args);
return bindUniversal(middleware, async function universalMiddlewareExpress(req, res, next) {
try {
req[contextSymbol] ??= {};
const request = requestAdapter(req, res);
const response = await this[universalSymbol](request, getContext(req), getRuntime(req, res));
if (!response) {
return nextOr404(res, next);
}
if (typeof response === "function") {
if (res.headersSent) {
throw new Error(
"Universal Middleware called after headers have been sent. Please open an issue at https://github.com/magne4000/universal-middleware"
);
}
if (req.complete === void 0) req.complete = req._readableState?.ended ?? true;
wrapResponse(res, next);
res[pendingMiddlewaresSymbol] ??= [];
res[pendingMiddlewaresSymbol].push(response);
return nextOr404(res, next);
}
if (response instanceof Response) {
await sendResponse(response, res);
} else {
req[contextSymbol] = response;
return nextOr404(res, next);
}
} catch (error) {
if (next) {
next(error);
} else {
console.error(error);
if (!res.headersSent) {
res.statusCode = 500;
}
if (!res.writableEnded) {
res.end();
}
}
}
});
};
}
function getContext(req) {
return req[contextSymbol];
}
function getRuntime(request, response) {
return getAdapterRuntime("express", {
params: request.params,
// biome-ignore lint/suspicious/noExplicitAny: cast
req: request,
// biome-ignore lint/suspicious/noExplicitAny: cast
res: response,
express: Object.freeze({
// biome-ignore lint/suspicious/noExplicitAny: cast
req: request,
// biome-ignore lint/suspicious/noExplicitAny: cast
res: response
})
});
}
// virtual:universal-middleware:virtual:universal-middleware:express:middleware:src/middleware.ts
var middleware_default2 = createMiddleware(middleware_default);
export { middleware_default2 as default };