of the Lord Jesus Christ ☦️
With love for developers
of all backgrounds around the world ❤️
@point0/compress compresses responses at the origin. compress(options)
returns a Point0 middleware: mount it on your root and every
compressible response — HTML, JSON, JS/CSS chunks, SVG — ships brotli- or
gzip-encoded, per the client's Accept-Encoding.
import { Point0 } from '@point0/core'
import { compress } from '@point0/compress'
export const root = Point0.lets
.root()
.middleware(compress()) // ← text responses ship brotli/gzip encoded
// ...
.root()It earns its keep wherever responses leave the server uncompressed — an app
served straight from its host with no CDN edge in front, where the ~100 KB SSR
HTML would otherwise go over the wire as-is. And since that SSR HTML is
private, no-store (see cache-control), no CDN would cache and
compress it for you anyway — the origin is the only place it can happen.
The body is piped through the compressor (node:zlib) with a flush after
every incoming chunk:
Because the compressed size isn't known ahead of the stream, Content-Length is
dropped and the response goes out chunked. Vary: Accept-Encoding is appended
so caches key the variants correctly, and a strong ETag is weakened to W/…
(the compressed bytes are an equivalent, not identical, representation).
Text-like content types: text/*, image/svg+xml, and application/* that is
JSON, XML, JavaScript, or wasm (including suffixed types like manifest+json).
Images, fonts, video, and archives arrive already compressed and are left alone.
The middleware skips by itself:
request.from.server) — they are consumed
programmatically, not sent over the wire;Content-Encoding present);HEAD, bodyless, and 204/205/304 responses;text/event-stream — SSE frames must not be re-chunked;Content-Length under minBytes
(default 1024) isn't worth the encoding overhead. Streams of unknown length
always compress.Accept-Encoding is parsed with honest q-values: br;q=0 is an explicit
refusal, * covers encodings the client didn't list. Among the encodings the
client accepts, the option's preference order decides — the default
['br', 'gzip'] prefers brotli (denser) and falls back to gzip (universal):
compress({ encodings: ['gzip'] }) // gzip only — e.g. to save origin CPU
compress({ brotliQuality: 4 }) // default 5 — the origin sweet spot
compress({ gzipLevel: 9 }) // default: zlib's own (6)tune and tuneCompressCompression has one per-response decision, reachable from two sides. Both yield
the same value — false / true / a settings object / undefined:
false — skip this response;true — compress it even when its content type isn't in the built-in set (you
know the payload is compressible);{ encodings?, brotliQuality?, gzipLevel?, minBytes? } — compress
it with these per-response settings (each falls back to the global option);
this also forces past the content-type check;undefined — the default content-type decision.tune optiontune decides per response from the config. It receives the same detailed
result object the middleware got back from next() (response, request,
variant, scope, error):
compress({
tune: (result) => {
if (result.variant.type === 'endpoint') return false // never compress API responses
if (result.variant.type === 'page') return { brotliQuality: 11 } // max density for the SSR document
return undefined
},
})tuneCompress()tuneCompress(value) sets the same decision imperatively for the current
request, and overrides the config tune (hand-set beats policy). It reads
the current request through point0's getRequest() itself, so you pass only the
value:
import { tuneCompress } from '@point0/compress'
.action(async () => {
tuneCompress(false) // a long-lived LLM stream — nothing may sit between us and the client
return new Response(llmStream, { headers: { 'content-type': 'text/plain' } })
})tuneCompress(false) is the common opt-out (a stream that must not be buffered
or re-chunked); tuneCompress(true) forces a payload whose content type the
sniff doesn't recognize; tuneCompress({ brotliQuality: 11 }) forces + tunes;
tuneCompress(undefined) clears a prior call. It is scoped to the one request
whose handler calls it — kept on that request's per-instance state, under an
internal key (so it never shows up on your typed request.state). That scope is
deliberate: a query running during a page's SSR is its own sub-request, so its
tuneCompress(false) affects only that query's response, never the page
document. A no-op off any request context.
Neither tune nor tuneCompress can un-skip the cases the middleware always
leaves raw: internal server-to-server fetches, already-encoded responses, and
bodyless / HEAD / 204/304 responses. They control the compression policy,
not these correctness invariants.
compress(options)Every option is optional; compress() with no argument is the correct default
for a typical app.
| Option | Type | Default | What |
|---|---|---|---|
encodings | ('br' | 'gzip')[] | ['br', 'gzip'] | preference order; first one the client accepts wins |
minBytes | number | 1024 | skip bodies with a known Content-Length under this |
brotliQuality | number (0..11) | 5 | brotli quality — near-top density at a fraction of the top levels' CPU |
gzipLevel | number (0..9) | zlib default | gzip level |
tune | (result) => boolean | settings | undefined | — | per-response: false skip, true force, settings object to force + tune, undefined default |
| Aspect | Behavior |
|---|---|
| Side | cut from the client bundle — the .middleware(...) argument and its imports are removed, so it never ships to the browser |
| Delivery | streaming with a per-chunk flush — progressive SSR stays progressive, no buffering |
Content-Length | dropped on compressed responses (size unknown ahead of the stream) |
Vary | Accept-Encoding appended for every compressible response, even when negotiation ends with no encoding |
ETag | a strong validator is weakened to W/… |
| Opt-out | tuneCompress(false) from any handler |
| Export | What |
|---|---|
compress(options) | build the middleware |
tuneCompress(value) | set the per-request decision from a handler (false | true | settings object | undefined); overrides the config tune |