-
Notifications
You must be signed in to change notification settings - Fork 0
encoders
Request-side body compression: compress: 'gzip' (or true) compresses the outgoing body and sets Content-Encoding. The response side needs nothing — fetch decompresses gzip/br/zstd responses natively on every platform, and the browser owns Accept-Encoding.
import io from 'double-meh';
await io.post('/bulk', bigPayload, {compress: 'gzip'}); // Content-Encoding: gzip
await io.put('/doc/42', doc, {compress: true}); // true = gzipio.encoders maps an encoder name to a function (source: ReadableStream, options) => ReadableStream (async allowed). Out of the box it holds gzip and deflate, built on the standard CompressionStream — available everywhere, browsers included. Add your own by assignment:
io.encoders.identity = source => source; // a (pointless) custom encoder
await io.post('/x', data, {compress: 'identity'});An unknown name throws a TypeError naming the encoder.
Brotli and zstandard compressors live in node:zlib, so they ship as an opt-in module — keeping node: references out of browser bundles (the same pattern as the SQLite storage backend):
import io from 'double-meh';
import {installZlibEncoders} from 'double-meh/encoders/zlib.js';
await installZlibEncoders(io); // registers br; zstd where the runtime ships it
await io.post('/bulk', bigPayload, {compress: 'br'});Works on Node, Bun, and Deno. br always registers (brotli quality defaults to 5 — the on-the-fly convention; the zlib default of 11 is for static assets). zstd is feature-detected (zlib.createZstdCompress) and simply absent where the runtime lacks it.
Compression parameters are set at registration, not per request — pick a policy once, name it, and select it by name at call sites. Two mechanisms, both riding node:zlib options verbatim:
// 1. configure the default registrations
await installZlibEncoders(io, {br: {quality: 7}, zstd: {level: 10}});
// 2. factories — register named variants for distinct policies
import {brotliEncoder, gzipEncoder} from 'double-meh/encoders/zlib.js';
io.encoders.brMax = await brotliEncoder({quality: 11}); // static-asset grade
io.encoders.gzipFast = await gzipEncoder({level: 1}); // cheap telemetry uploads
await io.post('/telemetry', batch, {compress: 'gzipFast'});Factories: gzipEncoder(options), deflateEncoder(options) (standard ZlibOptions — level, memLevel, strategy, …), brotliEncoder(options) (quality is sugar for params[BROTLI_PARAM_QUALITY]; explicit params win), zstdEncoder(options) (level is sugar for params[ZSTD_c_compressionLevel]; throws where the runtime ships no zstd).
Honoring is best-effort by construction: the platform CompressionStream pair has no knobs at all (the web standard takes only the format name), so the out-of-the-box gzip/deflate ignore nothing — they simply can't be parameterized. Passing gzip/deflate options to installZlibEncoders replaces them with parameterized node:zlib versions (CLI runtimes only).
compress also accepts an encoder function directly — (source, options) => stream — mirroring decode: fn. It runs one-off, without touching the registry, and since there is no name, no Content-Encoding is set automatically: the caller owns the header.
await io.post('/bulk', bigPayload, {
compress: source => source.pipeThrough(new CompressionStream('gzip')),
headers: {'Content-Encoding': 'gzip'}
});Prefer named registry variants for anything used twice — configure at setup, select at call site.
- A buffered body (a string, bytes, a
Blob, a JSON-encoded object) is compressed to completion and sent as bytes —Content-Lengthstays known, and it works over HTTP/1.1 everywhere. - A stream body (
{readable}chains, io.stream duplexes) is compressed streaming — bytes flow through the encoder as they are produced. - A bodyless request (
GETet al.) ignorescompressentirely. -
FormData/URLSearchParamsbodies throw: their wire encoding (multipart boundaries, form encoding) belongs to the transport, and pre-consuming them would corrupt it.
Compression runs before user-registered request inspectors, so a body-signing inspector (say SigV4) sees the final compressed bytes.
The server must accept compressed requests — Content-Encoding on a request is a contract with your API, not something HTTP negotiates automatically.
Guides
Concepts
Services
Modules
- fetch transport
- keys & URLs
- helpers
- records
- sse
- storage backends
- compression encoders
- Service Worker integration
Cookbook