6.6 KiB
Capability Spec Delta: bitpacker-compressed (bitpacker-stub-completion)
Package: @suaveplan/bitpacker-compressed
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time.
ADDED Requirements
Requirement: CompressedBitPacker subclass
The package SHALL export CompressedBitPacker<T extends BitPackerSchema> extends BitPacker<T>. The subclass SHALL run packed bytes through a configured CompressionAdapter before returning them, and SHALL run incoming bytes through decompressData before delegating to BitPacker.unpack. Compression behavior SHALL be configurable via BitPackerConfig.compression (algorithm, options, enabled); accessors compressionAlgorithm, compressionOptions, compressionEnabled SHALL surface and mutate the current settings.
Scenario: pack → decompress round-trip is byte-identical
- WHEN a
CompressedBitPackerpacks{ a: 1, b: "hello" }withalgorithm: "gzip"and the result is decompressed and unpacked - THEN the unpacked value deep-equals the input
Scenario: enabled: false skips compression entirely
- WHEN
compressionEnabledisfalse - THEN
packreturns bytes byte-identical toBitPacker.pack(no compression header, no codec invocation)
Scenario: algorithm: "none" invokes NoCompressionAdapter
- WHEN
algorithmis"none" - THEN
packproduces the same bytes asBitPacker.packAND the OTel counterbitpacker.compress.bytes_inrecords the input length whilebitpacker.compress.bytes_outrecords the same value
Verified by: packages/bitpacker/bitpacker-compressed/src/compressed-bit-packer/compressed-bit-packer.test.ts::"pack-decompress round-trip is byte-identical for gzip" AND packages/bitpacker/bitpacker-compressed/src/compressed-bit-packer/compressed-bit-packer.test.ts::"compressionEnabled false skips codec invocation" AND packages/bitpacker/bitpacker-compressed/src/compressed-bit-packer/compressed-bit-packer.test.ts::"algorithm 'none' yields BitPacker.pack output"
Requirement: CompressionAdapter contract and built-in adapters
The package SHALL expose a CompressionAdapter interface with compress(data, options): Promise<Uint8Array> and decompress(data, options): Promise<Uint8Array>. The package SHALL ship NoCompressionAdapter, GzipCompressionAdapter, and DeflateCompressionAdapter matching upstream behavior (compression.ts L121-L336).
Scenario: gzip adapter round-trip
- WHEN
GzipCompressionAdaptercompresses 1 KiB of zeros, then decompresses - THEN the output is the original 1 KiB AND the compressed length is < 50 bytes
Scenario: deflate adapter round-trip
- WHEN
DeflateCompressionAdaptercompresses random 1 KiB bytes, then decompresses - THEN the decompressed output deep-equals the original
Scenario: NoCompressionAdapter passes bytes through
- WHEN
NoCompressionAdapter.compress(input)is called - THEN the result is byte-identical to the input
Verified by: packages/bitpacker/bitpacker-compressed/src/compression-registry/compression-registry.test.ts::"GzipCompressionAdapter round-trip" AND packages/bitpacker/bitpacker-compressed/src/compression-registry/compression-registry.test.ts::"DeflateCompressionAdapter round-trip" AND packages/bitpacker/bitpacker-compressed/src/compression-registry/compression-registry.test.ts::"NoCompressionAdapter passes bytes through"
Requirement: CompressionRegistry replacement and unknown-algorithm error
The package SHALL expose a CompressionRegistry allowing callers to register(algorithm, adapter) and resolve(algorithm). Resolving an unknown algorithm SHALL throw BitpackerError with code BITPACKER.UNKNOWN_COMPRESSION_ALGORITHM and context.algorithm.
Scenario: registering an adapter overrides the default
- WHEN a custom
BrotliCompressionAdapteris registered under key"brotli"thenresolve("brotli")is called - THEN the registered adapter is returned; subsequent
packcalls withalgorithm: "brotli"route through it
Scenario: resolving an unknown algorithm throws coded error
- WHEN
resolve("zstd")is called and no adapter is registered for that key - THEN the call throws
BitpackerErrorwith codeBITPACKER.UNKNOWN_COMPRESSION_ALGORITHMandcontext.algorithm === "zstd"
Verified by: packages/bitpacker/bitpacker-compressed/src/compression-registry/compression-registry.spec-conformance.test.ts::"register overrides default adapter" AND packages/bitpacker/bitpacker-compressed/src/compression-registry/compression-registry.spec-conformance.test.ts::"resolve throws UNKNOWN_COMPRESSION_ALGORITHM for missing key"
Requirement: Compression failure surfaces coded error
When the underlying codec rejects (e.g. truncated gzip stream), the package SHALL wrap the cause and throw BitpackerError with code BITPACKER.COMPRESSION_FAILED (during compress) or BITPACKER.DECOMPRESSION_FAILED (during decompress); context.algorithm SHALL identify the codec.
Scenario: truncated gzip stream emits DECOMPRESSION_FAILED
- WHEN a half-truncated gzip-compressed buffer is passed to
decompressData(buf, "gzip") - THEN a
BitpackerErrorwith codeBITPACKER.DECOMPRESSION_FAILEDis thrown with the underlying codec error chained ascause
Verified by: packages/bitpacker/bitpacker-compressed/src/compression-registry/compression-registry.spec-conformance.test.ts::"truncated gzip stream emits DECOMPRESSION_FAILED with chained cause"
MODIFIED Requirements
Requirement: RLE pass-through helpers
The package SHALL keep compressRle / decompressRle as exported free functions for the bytes-only fast path; they SHALL be available both at the package root (one-release deprecation) and at the ./rle subpath. Their behavior SHALL match the existing 61-line implementation byte-for-byte (no semantic change).
Scenario: existing RLE call sites still resolve from package root
- WHEN a consumer imports
{ compressRle } from "@suaveplan/bitpacker-compressed" - THEN the import resolves and
compressRleproduces the same bytes as before this change
Scenario: canonical import location is ./rle
- WHEN a consumer imports
{ compressRle } from "@suaveplan/bitpacker-compressed/rle" - THEN the import resolves and the function is the same reference as the root export
Verified by: packages/bitpacker/bitpacker-compressed/src/rle/rle.test.ts::"compressRle output unchanged from pre-rewrite snapshot" AND packages/bitpacker/bitpacker-compressed/src/rle/rle.test.ts::"./rle subpath and root export resolve to the same function"