Commit b6a88ad
authored
feat(node): add batch response compression plugin (#1882)
Batch responses were never compressed. Their body frames several
subresponses of mixed content types, so the envelope has no single
content type for the runtime-agnostic Response Compression Plugin to
judge, and a batch of JSON went out uncompressed even though it shrinks
about tenfold. Compressing it with the web `CompressionStream` is not an
option either: it cannot flush, so every early subresponse would sit in
the compressor until the slowest one resolved, trading streaming for
compression.
`BatchResponseCompressionHandlerPlugin` in `@orpc/node` compresses them
with `node:zlib` instead, ending every write with a sync flush. Each
message reaches the client as soon as its procedure resolves, keep-alive
frames included, so a streaming batch stays streaming while compressed.
Registering the plugin is the explicit statement that your batches are
mostly compressible, which is why it ships as an opt-in in the Node.js
package rather than as default behaviour.
Resolves #1645, which reached for the same goal by probing Node builtins
from the shared fetch plugin via `process.getBuiltinModule`.
## Behaviour
- Covers every successful batch response: the length-prefixed framing of
a streaming batch or a buffered batch carrying binary, and the plain
JSON array a buffered batch of JSON-only subresponses produces.
- Leaves everything else alone: non-batch responses, whole-batch
failures (`status >= 400`), bodies already content-encoded, partial
`206` responses whose `Content-Range` would stop describing the body,
and `Cache-Control: no-transform`.
- Negotiates gzip, deflate, or deflate-raw from `Accept-Encoding`, keys
shared caches with `Vary: accept-encoding`, and applies a size threshold
where the size is known.
- Composes with the Response Compression Plugin in either registration
order, neither compressing what the other already did.
- Nothing changes on the client: fetch implementations decompress as the
stream arrives, so each message is decoded the moment it lands.
## Testing
- A batch response measured 8.2 KB uncompressed against under 600 bytes
on the wire.
- The batch end-to-end suite gained a compressed variant over real HTTP
with a real client, so its existing per-subresponse timing assertions
now prove the compressor flushes rather than buffers.
- A raw-socket test reads gzip bytes off the wire, and confirms
keep-alive frames keep flowing while the batch is idle.
- Every guard is covered by a test that fails when the guard is removed.
## Also
`varyByAcceptEncoding` and `isNoTransformCacheControl` moved from the
server plugin into `@orpc/shared`, with tests, so both compression
plugins share one implementation. Two stale source links on the batch
docs page now point at files that exist.1 parent 81dec7f commit b6a88ad
14 files changed
Lines changed: 938 additions & 42 deletions
File tree
- apps/content/docs
- plugins
- packages
- node/src
- server/src/plugins
- tests
- batch
- plugins
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
51 | | - | |
| 51 | + | |
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
109 | 124 | | |
110 | 125 | | |
111 | 126 | | |
| |||
173 | 188 | | |
174 | 189 | | |
175 | 190 | | |
176 | | - | |
| 191 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
45 | 49 | | |
46 | 50 | | |
47 | 51 | | |
| |||
0 commit comments