h3-fast-compression
Version:
Adds compression to h3 request (brotli, gzip, deflate)
86 lines (78 loc) • 3.31 kB
JavaScript
;
const node_util = require('node:util');
const zlib = require('node:zlib');
const h3 = require('h3');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const zlib__default = /*#__PURE__*/_interopDefaultCompat(zlib);
const MINIMUM_COMPRESSION_INPUT_SIZE = 1024;
function getAnyCompression(event) {
const encoding = h3.getRequestHeader(event, "accept-encoding");
if (encoding?.includes("br"))
return "br";
if (encoding?.includes("gzip"))
return "gzip";
if (encoding?.includes("deflate"))
return "deflate";
return void 0;
}
async function compress(event, response, method) {
const acceptEncoding = h3.getRequestHeader(event, "accept-encoding")?.includes(method);
const contentEncoding = h3.getResponseHeader(event, "content-encoding");
const responseBody = response.body;
const shouldCompress = typeof responseBody === "string" && !contentEncoding && responseBody.length >= MINIMUM_COMPRESSION_INPUT_SIZE && acceptEncoding;
if (shouldCompress) {
h3.setResponseHeader(event, "Content-Encoding", method);
const compressed = await (method === "br" ? node_util.promisify(zlib__default.brotliCompress)(responseBody, {
params: {
[zlib__default.constants.BROTLI_PARAM_MODE]: zlib__default.constants.BROTLI_MODE_TEXT,
// 4 is generally more appropriate for dynamic content, faster than gzip and better compression ratio
[zlib__default.constants.BROTLI_PARAM_QUALITY]: 4
}
}) : node_util.promisify(zlib__default[method])(responseBody));
void h3.send(event, compressed);
}
}
async function compressStream(event, response, method) {
const stream = new Response(response.body).body;
const acceptsEncoding = h3.getRequestHeader(event, "accept-encoding")?.includes(
method
);
if (acceptsEncoding) {
h3.setResponseHeader(event, "Content-Encoding", method);
response.body = stream.pipeThrough(new CompressionStream(method));
} else {
response.body = stream;
}
}
async function useGZipCompression(event, response) {
await compress(event, response, "gzip");
}
async function useDeflateCompression(event, response) {
await compress(event, response, "deflate");
}
async function useBrotliCompression(event, response) {
await compress(event, response, "br");
}
async function useCompression(event, response) {
const compression = getAnyCompression(event);
if (compression)
await compress(event, response, compression);
}
async function useGZipCompressionStream(event, response) {
await compressStream(event, response, "gzip");
}
async function useDeflateCompressionStream(event, response) {
await compressStream(event, response, "deflate");
}
async function useCompressionStream(event, response) {
const compression = getAnyCompression(event);
if (compression && compression !== "br")
await compressStream(event, response, compression);
}
exports.useBrotliCompression = useBrotliCompression;
exports.useCompression = useCompression;
exports.useCompressionStream = useCompressionStream;
exports.useDeflateCompression = useDeflateCompression;
exports.useDeflateCompressionStream = useDeflateCompressionStream;
exports.useGZipCompression = useGZipCompression;
exports.useGZipCompressionStream = useGZipCompressionStream;