Document that server.publish() compresses by default; pin the compress defaults
Closed
RO
1mo ago+240+240+012345678901234567890123456789-12-12-01234567890123456789
Problem
server.publish(topic, data)with thecompressargument omitted deflates the message for every subscriber that negotiated permessage-deflate.ws.send(),ws.publish()and their text/binary variants send uncompressed unlesscompressistrue.- The
truedefault comes fromcompress_value.unwrap_or(JSValue::TRUE)insrc/runtime/server/server_body.rs:1680; theServerWebSocketmethods go throughparse_compress_arginsrc/runtime/server/ServerWebSocket.rs:298, which yieldsfalsewhen the argument is missing.server.publish()has behaved this way since it was added (8753c483ff, 2022). - Neither default is stated anywhere. The
.d.tsand the docs describe compression as something you passtrueto get, so code callingserver.publish()on small messages compresses without the author knowing: a 23 byte payload goes out as 29 bytes with RSV1 set, and uWS deflates it once per subscriber (packages/bun-uws/src/App.h:244and:470callws->send(..., compress)per subscriber).
Fix
- This PR documents the existing behavior rather than changing it. Flipping the default would silently stop compressing for existing callers; #24593, for example, is a user relying on
server.publish()compressing ~109 KB broadcasts with no third argument. If the default should change instead, it is the one line inserver_body.rsabove plus inverting the new test. packages/bun-types/serve.d.ts:Server.publishJSDoc sayscompressdefaults totrueand points at theServerWebSocketmethods that default tofalse; its explicit-trueexample becomes an explicit-falseone. The sixServerWebSocketsend/publish methods saycompressdefaults tofalse.docs/runtime/http/websockets.mdx,docs/guides/websocket/compression.mdx,docs/runtime/http/server.mdx: the compression sections state both defaults and showserver.publish(topic, data, false). The reference block inwebsockets.mdxalso gains thecompressparameter andnumberreturn type thatws.publish()already has.test/js/bun/websocket/websocket-server.test.ts,describe("compress argument defaults"): a raw TCP client negotiates permessage-deflate and records the RSV1 bit of each text frame the server writes (inflating the compressed ones). It checksserver.publish()with the argument omitted /false/true,ws.publish()omitted /true, andws.send()omitted /true, plus a second subscriber without the extension and a second test withperMessageDeflateoff, where every frame is plain regardless of the argument.- Verified: the new tests pass with
bun bd testand with the released 1.4.0; changing theserver.publish()expectation tocompressed: falsemakes the test fail, so it pins the default.bun test test/integration/bun-types/bun-types.test.tspasses.
Background
- permessage-deflate (RFC 7692) is a WebSocket extension negotiated during the upgrade. Bun's server offers it when
websocket.perMessageDeflateis set; whether a given message is actually deflated is decided persend/publishcall via thecompressargument, and a compressed message is marked by the RSV1 bit in the first byte of its frame. The argument has no effect on a connection that did not negotiate the extension. server.publish()andws.publish()both fan out through the uWS topic tree, which calls the per-socketsend()once per subscriber with the samecompressflag, so a compressed publish costs one deflate per subscriber rather than one per message.