Skip to content

Commit 9389115

Browse files
committed
Add support for deflate/deflate-raw streams
1 parent 3334fae commit 9389115

3 files changed

Lines changed: 126 additions & 2 deletions

File tree

‎README.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,14 @@ Each method accepts a buffer and returns a promise for a buffer.
6161

6262
## Streaming methods
6363

64-
This library also supports streaming decoding, using web de(compression) streams wherever possible.
64+
This library also supports streaming encoding and decoding, returning web-standard `TransformStream` instances. This uses native `CompressionStream`/`DecompressionStream` where available (all modern browsers and Node 18+).
6565

6666
* `createGzipStream`
6767
* `createGunzipStream`
68+
* `createDeflateStream`
69+
* `createInflateStream`
70+
* `createDeflateRawStream`
71+
* `createInflateRawStream`
6872

6973
## Browser usage
7074

‎src/index.ts‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,50 @@ export function createGunzipStream(): TransformStream<BufferSource, Uint8Array>
146146
return getDuplex().toWeb(zlib.createGunzip()) as TransformStream<BufferSource, Uint8Array>;
147147
}
148148

149+
export function createDeflateStream(): TransformStream<BufferSource, Uint8Array> {
150+
// Use native CompressionStream where available:
151+
if (typeof CompressionStream !== 'undefined') {
152+
return new CompressionStream('deflate');
153+
}
154+
// Turn zlib node built-in into a web stream if not:
155+
return getDuplex().toWeb(zlib.createDeflate()) as TransformStream<BufferSource, Uint8Array>;
156+
}
157+
158+
export function createInflateStream(): TransformStream<BufferSource, Uint8Array> {
159+
// Use native DecompressionStream where available:
160+
if (typeof DecompressionStream !== 'undefined') {
161+
return new DecompressionStream('deflate');
162+
}
163+
// Turn zlib node built-in into a web stream if not:
164+
return getDuplex().toWeb(zlib.createInflate()) as TransformStream<BufferSource, Uint8Array>;
165+
}
166+
167+
export function createDeflateRawStream(): TransformStream<BufferSource, Uint8Array> {
168+
// Use native CompressionStream where available:
169+
if (typeof CompressionStream !== 'undefined') {
170+
try {
171+
return new CompressionStream('deflate-raw');
172+
} catch {
173+
// deflate-raw not supported (e.g. Node 18)
174+
}
175+
}
176+
// Turn zlib node built-in into a web stream if not:
177+
return getDuplex().toWeb(zlib.createDeflateRaw()) as TransformStream<BufferSource, Uint8Array>;
178+
}
179+
180+
export function createInflateRawStream(): TransformStream<BufferSource, Uint8Array> {
181+
// Use native DecompressionStream where available:
182+
if (typeof DecompressionStream !== 'undefined') {
183+
try {
184+
return new DecompressionStream('deflate-raw');
185+
} catch {
186+
// deflate-raw not supported (e.g. Node 18)
187+
}
188+
}
189+
// Turn zlib node built-in into a web stream if not:
190+
return getDuplex().toWeb(zlib.createInflateRaw()) as TransformStream<BufferSource, Uint8Array>;
191+
}
192+
149193
// --- Buffer helpers ---
150194

151195
const asBuffer = (input: Buffer | Uint8Array | ArrayBuffer): Buffer => {

‎test/stream.spec.ts‎

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ const expect = chai.expect;
55

66
import {
77
createGzipStream,
8-
createGunzipStream
8+
createGunzipStream,
9+
createDeflateStream,
10+
createInflateStream,
11+
createDeflateRawStream,
12+
createInflateRawStream
913
} from '../src/index';
1014

1115
// Helper to collect all chunks from a ReadableStream into a single Uint8Array
@@ -121,4 +125,76 @@ describe("Streaming", () => {
121125
expect(decompressed.toString()).to.equal(repeated);
122126
});
123127
});
128+
129+
describe("Deflate", () => {
130+
it('should compress data with deflate stream', async () => {
131+
const input = Buffer.from('Hello streaming deflate world!');
132+
const inputStream = createReadableStream(input);
133+
134+
const compressedStream = inputStream.pipeThrough(createDeflateStream());
135+
const compressed = await collectStream(compressedStream);
136+
137+
// Verify the compressed data can be decompressed with zlib
138+
const decompressed = zlib.inflateSync(Buffer.from(compressed));
139+
expect(decompressed.toString()).to.equal('Hello streaming deflate world!');
140+
});
141+
142+
it('should decompress deflate data with stream', async () => {
143+
const original = 'Hello streaming inflate world!';
144+
const compressed = zlib.deflateSync(original);
145+
const inputStream = createReadableStream(compressed);
146+
147+
const decompressedStream = inputStream.pipeThrough(createInflateStream());
148+
const decompressed = await collectStream(decompressedStream);
149+
150+
expect(Buffer.from(decompressed).toString()).to.equal(original);
151+
});
152+
153+
it('should handle round-trip compression and decompression', async () => {
154+
const original = 'Round-trip deflate streaming test with some repeated data data data data';
155+
const inputStream = createReadableStream(Buffer.from(original));
156+
157+
const compressedStream = inputStream.pipeThrough(createDeflateStream());
158+
const decompressedStream = compressedStream.pipeThrough(createInflateStream());
159+
const result = await collectStream(decompressedStream);
160+
161+
expect(Buffer.from(result).toString()).to.equal(original);
162+
});
163+
});
164+
165+
describe("Deflate-Raw", () => {
166+
it('should compress data with deflate-raw stream', async () => {
167+
const input = Buffer.from('Hello streaming deflate-raw world!');
168+
const inputStream = createReadableStream(input);
169+
170+
const compressedStream = inputStream.pipeThrough(createDeflateRawStream());
171+
const compressed = await collectStream(compressedStream);
172+
173+
// Verify the compressed data can be decompressed with zlib
174+
const decompressed = zlib.inflateRawSync(Buffer.from(compressed));
175+
expect(decompressed.toString()).to.equal('Hello streaming deflate-raw world!');
176+
});
177+
178+
it('should decompress deflate-raw data with stream', async () => {
179+
const original = 'Hello streaming inflate-raw world!';
180+
const compressed = zlib.deflateRawSync(original);
181+
const inputStream = createReadableStream(compressed);
182+
183+
const decompressedStream = inputStream.pipeThrough(createInflateRawStream());
184+
const decompressed = await collectStream(decompressedStream);
185+
186+
expect(Buffer.from(decompressed).toString()).to.equal(original);
187+
});
188+
189+
it('should handle round-trip compression and decompression', async () => {
190+
const original = 'Round-trip deflate-raw streaming test with some repeated data data data data';
191+
const inputStream = createReadableStream(Buffer.from(original));
192+
193+
const compressedStream = inputStream.pipeThrough(createDeflateRawStream());
194+
const decompressedStream = compressedStream.pipeThrough(createInflateRawStream());
195+
const result = await collectStream(decompressedStream);
196+
197+
expect(Buffer.from(result).toString()).to.equal(original);
198+
});
199+
});
124200
});

0 commit comments

Comments
 (0)