Summary
zlib deflate-family streams expose stream.params(level, strategy, callback), but Perry currently treats it as a no-op callback shim. Node validates level and strategy, then retunes subsequent compression output for the stream.
Node Behavior
On Node v25.9.0, changing params before writing data produces observably different valid deflate output, and invalid arguments throw synchronously:
const zlib = require("node:zlib");
const input = Buffer.from("a".repeat(32768));
async function encode(level) {
const chunks = [];
const stream = zlib.createDeflate({ level: 6 });
stream.on("data", (chunk) => chunks.push(chunk));
await new Promise((resolve, reject) => {
stream.params(level, zlib.constants.Z_DEFAULT_STRATEGY, (err) => err ? reject(err) : resolve());
});
stream.end(input);
await require("node:events").once(stream, "end");
return Buffer.concat(chunks);
}
const level0 = await encode(0);
const level9 = await encode(9);
console.log(level0.length, level9.length); // 32789 58 on local Node
console.log(zlib.inflateSync(level0).length, zlib.inflateSync(level9).length); // 32768 32768
zlib.createDeflate().params(99, zlib.constants.Z_DEFAULT_STRATEGY, () => {});
// RangeError ERR_OUT_OF_RANGE
zlib.createDeflate().params(1, 999, () => {});
// RangeError ERR_OUT_OF_RANGE
zlib.createDeflate().params("1", zlib.constants.Z_DEFAULT_STRATEGY, () => {});
// TypeError ERR_INVALID_ARG_TYPE
Exact compressed bytes can vary by backend, but option-sensitive output, callback completion, valid round-trip, and validation are observable Node behavior.
Perry Behavior
crates/perry-stdlib/src/zlib.rs documents and implements zlib_stream_params() as a no-op callback dispatch:
/// `stream.params(level, strategy, cb?)` — Perry does not currently retune
/// compression levels, but Node exposes this as a function and invokes the
/// callback asynchronously when parameters are unchanged.
pub fn zlib_stream_params(_handle: i64, cb: i64) {
if cb != 0 {
ZLIB_PENDING_EVENTS.lock().unwrap().push(ZlibEvent::Callback(cb));
perry_runtime::event_pump::js_notify_main_thread();
}
}
The function ignores the stream handle, level, and strategy, so it cannot validate inputs or alter compression behavior.
Suggested PR Cut
Batch this with related issues in:
node:zlib: compression options and stream retuning parity cut
Good batch candidates:
Do not batch with:
Acceptance
- parity/regression test proves
stream.params(0, strategy, cb) and stream.params(9, strategy, cb) produce different valid deflate-family output for a repeated input
- invalid
level and strategy values throw Node-compatible errors for covered cases
- callback completion remains Node-compatible for successful retuning
- implementation matches Node observable behavior without requiring byte-for-byte compression parity
- related known-failure/docs/manifest entries updated if touched
Summary
zlibdeflate-family streams exposestream.params(level, strategy, callback), but Perry currently treats it as a no-op callback shim. Node validateslevelandstrategy, then retunes subsequent compression output for the stream.Node Behavior
On Node v25.9.0, changing params before writing data produces observably different valid deflate output, and invalid arguments throw synchronously:
Exact compressed bytes can vary by backend, but option-sensitive output, callback completion, valid round-trip, and validation are observable Node behavior.
Perry Behavior
crates/perry-stdlib/src/zlib.rsdocuments and implementszlib_stream_params()as a no-op callback dispatch:The function ignores the stream handle, level, and strategy, so it cannot validate inputs or alter compression behavior.
Suggested PR Cut
Batch this with related issues in:
node:zlib: compression options and stream retuning parity cutGood batch candidates:
Do not batch with:
zlib.codesmetadata in node:zlib: expose codes error-code table #2688Acceptance
stream.params(0, strategy, cb)andstream.params(9, strategy, cb)produce different valid deflate-family output for a repeated inputlevelandstrategyvalues throw Node-compatible errors for covered cases