@unikvs/compression
Explains how to use the Transformer plugin that transparently compresses and decompresses byte sequences with gzip / deflate / deflate-raw.
Overview
@unikvs/compression is a Transformer plugin that transparently compresses and decompresses byte sequences. Transformer It wraps the Web standard CompressionStream and DecompressionStream to fit ITransformer.
Writes compress with encode and reads expand with decode, so you can read and write without thinking about compression.
This transformer is always open. No explicit open or close is needed; isOpen always returns true and name is always "Compression".
Install it as follows.
npm install @unikvs/compressionpnpm add @unikvs/compressionyarn add @unikvs/compressionbun add @unikvs/compressionnub add @unikvs/compressionaube add @unikvs/compressionSupported Formats
The formats you can specify in the constructor are the CompressionFormat type. It is limited to strings accepted by both CompressionStream and DecompressionStream. The three tested values are as follows.
| Format | Value | Characteristics |
|---|---|---|
| gzip | "gzip" |
A versatile format with a header and footer. |
| deflate | "deflate" |
A format with a zlib wrapper. |
| deflate-raw | "deflate-raw" |
A raw format with no wrapper. |
Choose "gzip" for compatibility. If you have an agreement with another system, match that format.
import { Compression } from "@unikvs/compression";
const compression = new Compression("gzip");
Use a single format per KVS. Mixing formats fails to decompress.
If you specify a format the runtime does not support, a TypeError is thrown when constructing the CompressionStream or DecompressionStream.
Usage
The Compression constructor takes exactly one format. There are no options.
import { Compression } from "@unikvs/compression";
const compression = new Compression("gzip");
Its main members are as follows.
| Member | Summary |
|---|---|
new Compression(format) |
Initializes with the compression format. |
name |
Always returns "Compression". |
isOpen |
Always returns true. |
encode({ data }) |
Compresses a Uint8Array<ArrayBuffer>. |
decode({ data }) |
Decompresses a compressed Uint8Array<ArrayBuffer>. |
getEncodable() |
Returns a TransformStream for compression. |
getDecodable() |
Returns a TransformStream for decompression. |
Register it with UniKvs via appendTransformer. It becomes the upstream of subsequently registered storages.
import { Compression } from "@unikvs/compression";
import UniKvs from "unikvs";
const kvs = UniKvs.config()
.appendTransformer(new Compression("gzip"))
.appendStorage(storage)
.create();
await kvs.open();
await kvs.set("data", input);
const output = await kvs.get("data");
set stores compressed data, and get decompresses it automatically.
Streams and Byte Sequences
@unikvs/compression supports both single values and streams.
- Single values are converted with
encodeanddecode. An emptyUint8Arrayor a ~1 MiB sequence round-trips as is. - Stream values are converted with the
TransformStreamfromgetEncodableandgetDecodable. Even uneven chunks restore the original after a round-trip.
The limitations are as follows.
- Passing non-compressed bytes to
decodeis rejected. - If the compression and decompression formats differ, decompression fails. Round-trip with the same format.
- For data with no room for compression, such as random bytes, the size may not shrink. Decompression still restores the original.
Notes
Repetitive text tends to shrink well, while already compressed or random-like data shrinks poorly. Even without shrinking, round-trip accuracy is not impaired.
Examples
A minimal example with Memory storage. Written values are stored compressed and automatically decompressed on reads.
import { Compression } from "@unikvs/compression";
import { Memory } from "@unikvs/memory";
import UniKvs, { type PlainValue } from "unikvs";
const kvs = UniKvs.config<{ data: PlainValue<Uint8Array<ArrayBuffer>> }>()
.appendTransformer(new Compression("gzip"))
.appendStorage(new Memory())
.create();
await kvs.open();
const input = new TextEncoder().encode(
"Repeat this text multiple times to ensure compression efficiency. ".repeat(100),
);
await kvs.set("data", input);
const output = await kvs.get("data");
console.log(output.length === input.length);
await kvs.close();