Summary
node:zlib exposes callback-form one-shot codecs beyond gzip/gunzip, but current Perry source only routes the async/promise-returning dispatch for gzip, gunzip, brotliCompress, and brotliDecompress. The exported deflate, inflate, deflateRaw, inflateRaw, and unzip functions should actually run the corresponding codec and invoke the callback / work through util.promisify() like Node.
No local Perry binary was available in this issue-creator workspace, so this report is based on current origin/main source inspection plus the Node oracle below.
Node oracle
Node v25.9.0 exposes all five functions and they complete callback and promisified round trips:
const zlib = require('node:zlib');
const { promisify } = require('node:util');
const input = Buffer.from('perry zlib callback coverage');
console.log(process.version);
console.log('types:', ['deflate','inflate','deflateRaw','inflateRaw','unzip']
.map((name) => name + ':' + typeof zlib[name]).join(','));
zlib.deflate(input, (err, compressed) => {
console.log('deflate cb:', err && err.name, Buffer.isBuffer(compressed), compressed.length > 0);
zlib.inflate(compressed, (err2, plain) => console.log('inflate cb:', err2 && err2.name, plain.toString()));
});
zlib.deflateRaw(input, (err, compressed) => {
console.log('deflateRaw cb:', err && err.name, Buffer.isBuffer(compressed), compressed.length > 0);
zlib.inflateRaw(compressed, (err2, plain) => console.log('inflateRaw cb:', err2 && err2.name, plain.toString()));
});
zlib.gzip(input, (err, compressed) => {
zlib.unzip(compressed, (err2, plain) => console.log('unzip gzip cb:', err2 && err2.name, plain.toString()));
});
Promise.all([
promisify(zlib.deflate)(input).then((buf) => ['pdeflate', Buffer.isBuffer(buf), buf.length > 0]),
promisify(zlib.unzip)(zlib.gzipSync(input)).then((buf) => ['punzip', buf.toString()]),
]).then((rows) => rows.forEach((row) => console.log(...row)));
Output:
v25.9.0
types: deflate:function,inflate:function,deflateRaw:function,inflateRaw:function,unzip:function
deflate cb: null true true
deflateRaw cb: null true true
pdeflate true true
punzip perry zlib callback coverage
inflate cb: null perry zlib callback coverage
inflateRaw cb: null perry zlib callback coverage
unzip gzip cb: null perry zlib callback coverage
Perry evidence
Current origin/main source shows the functions are surfaced but not wired end to end:
crates/perry-api-manifest/src/entries.rs registers zlib.deflate, deflateRaw, inflate, inflateRaw, and unzip, with a comment saying these callback-form variants were stubbed so typeof zlib.deflate === "function" resolves true and should piggy-back on existing native-table sync routes when used with util.promisify().
crates/perry-runtime/src/util_promisify.rs treats all zlib callback-form codecs, including these five names, as already Promise-returning and returns the bound function unchanged.
crates/perry-codegen/src/lower_call/native_table/media.rs has native call entries for gzip, gunzip, Brotli async methods, and the sync raw/unzip methods, but no direct async entries for deflate, inflate, deflateRaw, inflateRaw, or unzip.
crates/perry-stdlib/src/zlib.rs::js_zlib_native_dispatch() dispatches sync forms plus gzip, gunzip, brotliCompress, and brotliDecompress; the five non-gzip callback-form names fall through to undefined.
That leaves these Node functions in a feature-detection shape without the actual callback/promisify behavior Node provides.
Suggested parity coverage
Add granular node-suite/zlib cases for:
import { deflate, inflate, deflateRaw, inflateRaw, unzip, gzipSync } from 'node:zlib';
import { promisify } from 'node:util';
const input = Buffer.from('perry zlib callback coverage');
deflate(input, (err, compressed) => {
console.log('deflate callback:', err && err.name, Buffer.isBuffer(compressed), compressed.length > 0);
inflate(compressed, (err2, plain) => console.log('inflate callback:', err2 && err2.name, plain.toString()));
});
deflateRaw(input, (err, compressed) => {
console.log('deflateRaw callback:', err && err.name, Buffer.isBuffer(compressed), compressed.length > 0);
inflateRaw(compressed, (err2, plain) => console.log('inflateRaw callback:', err2 && err2.name, plain.toString()));
});
unzip(gzipSync(input), (err, plain) => console.log('unzip callback:', err && err.name, plain.toString()));
console.log('promisified deflate:', Buffer.isBuffer(await promisify(deflate)(input)));
console.log('promisified unzip:', (await promisify(unzip)(gzipSync(input))).toString());
Scope / non-goals
This is narrower than #2557 option-object parity and #2510 Zstd codec support. It is also not about the already-wired gzip/gunzip/Brotli callback forms or stream Transform factories. The requested fix is routing the five exposed one-shot callback-form codecs to their existing sync/raw/unzip implementations with Node-compatible callback and util.promisify() behavior.
Duplicate searches performed before filing:
zlib deflate inflate unzip callback
zlib native dispatch deflate inflate async
zlib callback-form variants
- PR search for
zlib deflate inflate unzip callback native dispatch async
Summary
node:zlibexposes callback-form one-shot codecs beyondgzip/gunzip, but current Perry source only routes the async/promise-returning dispatch forgzip,gunzip,brotliCompress, andbrotliDecompress. The exporteddeflate,inflate,deflateRaw,inflateRaw, andunzipfunctions should actually run the corresponding codec and invoke the callback / work throughutil.promisify()like Node.No local Perry binary was available in this issue-creator workspace, so this report is based on current
origin/mainsource inspection plus the Node oracle below.Node oracle
Node v25.9.0 exposes all five functions and they complete callback and promisified round trips:
Output:
Perry evidence
Current
origin/mainsource shows the functions are surfaced but not wired end to end:crates/perry-api-manifest/src/entries.rsregisterszlib.deflate,deflateRaw,inflate,inflateRaw, andunzip, with a comment saying these callback-form variants were stubbed sotypeof zlib.deflate === "function"resolves true and should piggy-back on existing native-table sync routes when used withutil.promisify().crates/perry-runtime/src/util_promisify.rstreats all zlib callback-form codecs, including these five names, as already Promise-returning and returns the bound function unchanged.crates/perry-codegen/src/lower_call/native_table/media.rshas native call entries forgzip,gunzip, Brotli async methods, and the sync raw/unzip methods, but no direct async entries fordeflate,inflate,deflateRaw,inflateRaw, orunzip.crates/perry-stdlib/src/zlib.rs::js_zlib_native_dispatch()dispatches sync forms plusgzip,gunzip,brotliCompress, andbrotliDecompress; the five non-gzip callback-form names fall through toundefined.That leaves these Node functions in a feature-detection shape without the actual callback/promisify behavior Node provides.
Suggested parity coverage
Add granular
node-suite/zlibcases for:Scope / non-goals
This is narrower than #2557 option-object parity and #2510 Zstd codec support. It is also not about the already-wired
gzip/gunzip/Brotli callback forms or stream Transform factories. The requested fix is routing the five exposed one-shot callback-form codecs to their existing sync/raw/unzip implementations with Node-compatible callback andutil.promisify()behavior.Duplicate searches performed before filing:
zlib deflate inflate unzip callbackzlib native dispatch deflate inflate asynczlib callback-form variantszlib deflate inflate unzip callback native dispatch async