Skip to content

chore(release): release v0.3.0 - #199

Merged
derodero24 merged 103 commits into
mainfrom
develop
Mar 24, 2026
Merged

derodero24 merged 103 commits into
mainfrom
develop

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Release v0.3.0

Merging this PR will:

  1. Build native binaries for all 9 platforms
  2. Publish to npm with provenance

Changelog

# comprs

## 0.3.0

### Minor Changes

- c23b4e6: Add brotli compression/decompression support via `brotliCompress()` and `brotliDecompress()` functions. Includes streaming API with `createBrotliCompressStream()` and `createBrotliDecompressStream()`. Quality levels 0-11 (default: 6).
- 98e64a9: Add gzip and raw deflate compression/decompression support via `gzipCompress()`, `gzipDecompress()`, `deflateCompress()`, `deflateDecompress()` functions. Includes streaming API with `createGzipCompressStream()`, `createGzipDecompressStream()`, `createDeflateCompressStream()`, and `createDeflateDecompressStream()`.
- 356319f: Add LZ4 frame compression/decompression support via `lz4Compress()` and `lz4Decompress()` functions. Includes streaming API with `createLz4CompressStream()` and `createLz4DecompressStream()`, and Node.js Transform streams via `createLz4CompressTransform()` and `createLz4DecompressTransform()`. Auto-detect (`decompress()`, `detectFormat()`) now recognizes LZ4 frames.

### Patch Changes

- 49b5c2d: Rename package from `zflate` to `comprs` to avoid npm typosquat protection.

## 0.2.0

### Minor Changes

- fb7c15f: Add streaming compression/decompression API using Web Streams API (`TransformStream`). New functions `createZstdCompressStream()` and `createZstdDecompressStream()` enable chunked processing of large data with bounded memory usage. Streaming output is fully interoperable with one-shot `zstdCompress()`/`zstdDecompress()`.
- 9ceb306: Add zstd compression and decompression support via `zstdCompress()`, `zstdDecompress()`, and `zstdDecompressWithCapacity()` functions. Supports compression levels 1-22 (default: 3) and negative levels for fast mode.

derodero24 and others added 30 commits March 20, 2026 12:58
* chore(core): add Rust crate skeleton with napi-rs bindings

Minimal `zflate` crate with a single `version()` export to verify the
napi-rs build pipeline works end-to-end.

- crates/core/Cargo.toml: cdylib crate with napi-rs v3
- crates/core/build.rs: napi_build setup
- crates/core/src/lib.rs: version() function

* chore: add package.json with napi-rs configuration

Configure the npm package with 9 build targets (macOS, Linux, Windows,
WASM), dev dependencies for tooling (Biome, Vitest, TypeScript,
Changesets, CodSpeed), and build/test/lint scripts.

* chore: add build scripts and module entry points

- scripts/optimize-wasm.js: post-process WASM with wasm-opt
- index.mjs / index.d.mts: ESM entry points
- index.js / index.d.ts / browser.js: napi-rs generated files (force-tracked)
* test: add initial test suite and ESM smoke test

- __test__/index.spec.ts: Vitest spec verifying version() export
- __test__/esm-import.mjs: ESM import smoke test for CI

* chore: update biome and tsconfig for test files

- biome.json: allow console in ESM smoke test
- tsconfig.json: format with Biome

* ci: add CI workflow

Full CI pipeline adapted from rapid-fuzzy:
- Lint (Biome, TypeScript, publint, generated file verification)
- Dependency audit (npm + cargo-deny)
- Rust lint (fmt + clippy) and test
- Cross-platform build (9 targets: macOS, Linux, Windows, WASM)
- Node.js test matrix (3 versions × 3 OSes)
- Coverage (Rust via cargo-llvm-cov + JS via Vitest, uploaded to Codecov)
* ci: add release workflow with Cargo.toml version sync

Changesets-driven release flow:
- On develop push: create version PR, then release PR (develop → main)
- On main push: build all 9 targets and publish to npm with provenance
- scripts/sync-cargo-version.js: keep Cargo.toml version in sync with
  package.json after changeset version bumps

* ci: add CodeQL security analysis

Analyze JavaScript/TypeScript and Rust code for security vulnerabilities.
Runs on PRs, develop pushes, and weekly schedule (Monday 6 AM UTC).

* ci: add CodSpeed benchmark workflow

Continuous performance tracking via CodSpeed. Runs JS benchmarks on
develop pushes and PRs when crate or bench files change.
Rust benchmarks will be added when the bench crate is introduced.

* ci: add self-hosted Renovate workflow

Automated dependency updates via self-hosted Renovate bot.
Runs weekly on Sunday 19:00 UTC (Monday 4:00 JST).

* test(bench): add initial benchmark file

Minimal benchmark to satisfy CodSpeed workflow. Real compression
benchmarks will be added alongside algorithm implementations.
* feat(zstd): implement zstd compression and decompression

Add zstdCompress() and zstdDecompress() functions powered by the zstd
C library via the zstd Rust crate.

- Compression levels 1-22 (default: 3)
- Auto-detection of frame content size for efficient decompression
- zstdDecompressWithCapacity() for data exceeding 256 MB default limit
- Rust unit tests for round-trip, empty data, large data, and levels

* test(zstd): add JS tests and benchmarks for zstd

- __test__/zstd.spec.ts: 11 tests covering round-trip, levels, errors
- __test__/esm-import.mjs: updated with zstd round-trip smoke test
- __test__/index.bench.ts: compress/decompress benchmarks at 150B/10KB/1MB
- index.mjs: export zstd functions

* chore: update napi-rs generated files and add changeset

- Regenerate index.js, index.d.ts, browser.js with zstd exports
- Add changeset for minor version bump

* ci: add WASI SDK setup for zstd WASM builds

The zstd crate compiles C code via zstd-sys, which requires a proper
WASI sysroot when targeting wasm32-wasip1-threads. Without it, clang
picks up system glibc headers and fails with missing
'bits/libc-header-start.h'.

Use bytecodealliance/actions/wasi-sdk/setup to install WASI SDK and
set CC, AR, CFLAGS, and WASI_SYSROOT environment variables for the
WASM build step in both CI and release workflows.
* fix(zstd): validate capacity parameter in zstdDecompressWithCapacity

Reject negative, NaN, and Infinity values before casting f64 to usize.
Without validation, a negative f64 wraps to a very large usize, which
could cause memory exhaustion.

Closes #17

* fix(ci): use RUNNER_TEMP for WASI SDK installation

Replace /opt with $RUNNER_TEMP for WASI SDK extraction. /opt may not
be writable on all GitHub Actions runner configurations.
Also switch curl from -sL to -fsSL to fail on HTTP errors.

Closes #18
* docs: add SECURITY.md

* docs: address review feedback on SECURITY.md

- Replace vague "extremely large size" with "massive size" for clarity
- Unify SLA day units by removing "business" qualifier from initial
  assessment timeline for consistency
* test(zstd): expand test coverage and benchmarks

Add comprehensive JS tests covering compression level boundaries (0,
negative, 22), decompressWithCapacity edge cases (insufficient, oversized,
invalid inputs), and round-trip verification with random data.

Expand benchmarks with random (incompressible) and realistic (JSON, text)
data variants alongside existing patterned data.

Update Rust doc comments to document negative compression levels and
level 0 behavior. Add Rust tests for boundary levels. Update changeset
to include all public API functions.

Closes #19

* chore: update napi-rs generated type definitions

Regenerate index.d.ts to reflect updated doc comments for
zstd_compress documenting negative levels and level 0 behavior.
Implement streaming zstd compression and decompression using the Web
Streams API (TransformStream). The Rust layer exposes ZstdCompressContext
and ZstdDecompressContext classes with transform/flush/finish methods
using zstd::stream::raw for stateful chunked processing.

The JS layer wraps these in TransformStream via createZstdCompressStream()
and createZstdDecompressStream(), available from both ESM and CJS entry
points. Streaming output is fully interoperable with one-shot APIs.

Add comprehensive tests covering chunked round-trips, various chunk
sizes, large data (1MB), random data, and one-shot/streaming interop.

Closes #5
* docs: add README and verify npm package readiness

Add comprehensive README with project description, installation guide,
quick-start examples (one-shot and streaming), full API reference,
supported algorithms table, platform compatibility matrix, and
benchmark results.

Verify npm package with publint (no errors). Package includes all
required files: index.js, index.mjs, index.d.ts, index.d.mts,
streams.js, streams.d.ts, browser.js, LICENSE, and README.md.

Closes #8

* docs(readme): address review feedback

- Add bun installation instructions
- Replace streaming example with self-contained runnable snippet
* fix(ci): resolve release workflow failures

- Generate npm platform package directories for all 9 targets
- Add optionalDependencies to root package.json for platform binaries
- Fix changeset version command argument parsing in release workflow
  by using a dedicated npm script instead of inline shell command

Closes #27

* fix(ci): remove optionalDependencies from committed package.json

The optionalDependencies for platform-specific packages are added
at publish time by the prepublishOnly hook (napi prepublish -t npm),
not in the committed source. Having them in package.json breaks
pnpm install --frozen-lockfile since the packages are not yet on npm.
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…#34)

- Regenerate index.js with v0.2.0 version strings
- Update npm platform package versions to 0.2.0
- Add Rust toolchain to version job for napi build during version bump
- Add napi version, build, and format to changeset:version script
- Fix version test to read from package.json dynamically
Add gzip and raw deflate compression/decompression with one-shot and
streaming APIs. Includes interoperability tests with Node.js built-in
zlib module.

Closes #6
* feat(brotli): add brotli compression support

Add brotli compression/decompression with one-shot and streaming APIs.
Quality levels 0-11 (default: 6). Includes interoperability tests with
Node.js built-in zlib brotli module.

Closes #7

* test(brotli): add brotli compression benchmarks

Add brotli compress/decompress benchmarks matching the zstd benchmark
structure for patterned, random, and realistic data at various sizes.

* test(gzip): increase timeout for 1MB round-trip tests

Extend timeout from 5s to 30s for gzip and deflate 1MB data tests
to prevent CI failures on slower runners.

* test: increase timeout for all 1MB tests

Set 30s timeout on all 1MB data round-trip and streaming tests to
prevent failures on slower CI runners (Windows).
Add gzip, deflate, and brotli to the API reference tables. Update
supported algorithms table to reflect all three algorithms are now
available with both one-shot and streaming APIs.
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Add a `./streams` subpath export so users can import streaming APIs
directly via `import { ... } from 'zflate/streams'`.

Closes #48
Validate that the compression level parameter is within the valid range
(0-9) for gzip_compress, deflate_compress, GzipCompressContext, and
DeflateCompressContext. Return InvalidArg error if out of range, matching
the existing validation pattern in brotli_compress.

Closes #38
* fix(gzip): add decompression size limits to gzip and deflate

Add MAX_DECOMPRESSED_SIZE (256 MB) to gzip_decompress and
deflate_decompress to prevent zip bomb attacks. Both functions now use
chunked reading with size checking instead of unbounded read_to_end().

Add gzipDecompressWithCapacity and deflateDecompressWithCapacity for
explicit control over the maximum decompressed size, matching the
existing zstd and brotli patterns.

Closes #37

* chore(napi): regenerate bindings for new WithCapacity functions
Change all input parameters from Buffer to Either<Buffer, Uint8Array>
across all one-shot and streaming functions. This generates
Buffer | Uint8Array TypeScript types, enabling browser/Deno/Bun users
to pass Uint8Array directly without type errors.

Return types remain Buffer. No runtime behavior changes for existing
Buffer usage.

Closes #42
Add decompress() function that auto-detects compression format from
magic bytes (zstd: 0xFD2FB528, gzip: 0x1F8B) and falls back to brotli
heuristic detection. Add detectFormat() for format identification
without decompression.

Supported formats: zstd, gzip, brotli. Raw deflate cannot be
auto-detected due to lack of magic bytes.

Closes #16
derodero24 and others added 27 commits March 21, 2026 14:08
#158)

Replace native streaming contexts with JS-side adapters in the browser
entry point to work around WebAssembly.Memory growth invalidating
ArrayBuffer views. Adapters accumulate chunks and delegate to one-shot
APIs, maintaining the same transform()/flush()/finish() API surface.

- browser-streaming.js: adapter classes for all 10 streaming contexts
- browser-entry.js: re-exports WASM APIs with adapter overrides
- package.json: browser condition points to browser-entry.js
- e2e: streaming tests enabled for browser WASM
* chore(renovate): run daily and remove PR concurrent limit

Closes #163

* chore(renovate): disable lock file maintenance
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
* fix(bench): exclude third-party benchmarks from CodSpeed tracking

Split benchmark files into zflate-only (*.bench.ts) and comparison
(*.compare.bench.ts) variants. CodSpeed now only tracks zflate's own
benchmarks, eliminating false regressions from pako/fflate/node:zlib
that are caused by GitHub Actions CPU heterogeneity affecting Callgrind
instruction counting.

Closes #167

* fix(bench): use deterministic random data in CodSpeed benchmarks

Replace non-deterministic randomBytes() with a seeded LCG to ensure
reproducible benchmark inputs across runs, reducing CodSpeed instruction
count variance.
…ction (#170)

Replace CodSpeed simulation mode (Callgrind instruction counting) with
Bencher.dev (statistical wall-clock analysis). CodSpeed's instruction
counting was fundamentally incompatible with this napi-rs project due to
GitHub Actions CPU heterogeneity and glibc's CPU-adaptive malloc.

Changes:
- Add Bencher workflow with t-test threshold for regression detection
- Add vitest-to-bmf.js conversion script for vitest bench output
- Remove CodSpeed workflow and @codspeed/vitest-plugin dependency
- Remove CodSpeed plugin from vitest config

Closes #168
…#172)

Replace Bencher.dev with CodSpeed Walltime mode (Macro Runners) which
runs benchmarks on dedicated bare-metal hardware, eliminating GitHub
Actions CPU variance. CodSpeed also provides native vitest integration
via @codspeed/vitest-plugin, removing the need for conversion scripts.

Key change: `mode: walltime` instead of the previous `mode: simulation`
which used Callgrind instruction counting.

Closes #171
…Speed reporting (#174)

Split index.bench.ts (mixed zstd+brotli) into separate zstd.bench.ts
and brotli.bench.ts so CodSpeed PR reports only show benchmarks relevant
to the changed algorithm. Extract shared test fixtures into
bench-fixtures.ts and add realistic data benchmarks (JSON, text) to
gzip and deflate for consistent coverage across all four algorithms.

Closes #173
* perf(core): eliminate double-copy buffer pattern in decompression

Replace the manual 4 KiB read loop (stack buffer → Vec copy) with
read_to_end + Take, which writes directly into Vec spare capacity.
This eliminates one full copy of every decompressed byte and uses
adaptive buffer sizing instead of fixed 4 KiB chunks.

Affected: gzip, deflate, brotli (sync + async, default + with-capacity)

Closes #175

* fix(core): use saturating_mul for init capacity and update size limit tests

Address CodeRabbit review feedback:
- Replace len() * 4 with len().saturating_mul(4) across all call sites
  to prevent overflow on 32-bit targets (wasm32-wasip1-threads)
- Replace old chunk-loop size limit tests with Take+read_to_end tests
  that exercise the actual decompression pattern (avoiding napi::Error
  symbol resolution issues in standalone test binaries)
* chore(bench): add bench:ci script and Rust CodSpeed benchmarks

- Add bench:ci script that excludes comparison benchmarks
- Simplify CodSpeed workflow to use bench:ci instead of explicit file list
- Use glob pattern for bench file path triggers
- Add crates/bench workspace member with Criterion benchmarks
  (gzip, deflate, brotli, zstd) using codspeed-criterion-compat
- Add rust-benchmarks job to CodSpeed workflow (simulation mode)

Closes #177

* fix(ci): add Cargo.toml, Cargo.lock, package.json to CodSpeed path triggers

Ensures CodSpeed benchmarks run when workspace config or dependency
lockfiles change, which could affect benchmark behavior.
* feat(core): add LZ4 frame compression support

Add LZ4 as a fourth compression algorithm using lz4_flex (pure Rust):

- Bulk API: lz4Compress, lz4Decompress, lz4DecompressWithCapacity
- Async API: lz4CompressAsync, lz4DecompressAsync, lz4DecompressWithCapacityAsync
- Streaming: Lz4CompressContext, Lz4DecompressContext
- Web Streams: createLz4CompressStream, createLz4DecompressStream
- Format detection: detectFormat returns "lz4" for LZ4 frame magic bytes
- Auto-decompress: decompress/decompressAsync and createDecompressStream
  now handle LZ4 data automatically

Closes #176

* fix(core): add Read import to LZ4 test modules

Tests use read_to_end which requires the Read trait in scope.
* refactor(core): validate capacity as non-negative integer across all algorithms

Extract shared validate_capacity() that rejects NaN, Infinity, negative,
fractional values, and values exceeding usize::MAX. Applied to all 10
DecompressWithCapacity functions (sync + async × 5 algorithms).

Closes #181

* test: add regression tests for fractional and oversized capacity
* perf(lz4): implement incremental streaming for LZ4 compression

Replace full-input buffering with cursor-based incremental output in
Lz4CompressContext. The FrameEncoder now persists across transform()
calls, emitting compressed blocks as they become available instead of
buffering all input until finish().

Decompression remains buffered due to lz4_flex FrameDecoder requiring
full input (documented in #182).

Closes #182

* perf(lz4): implement incremental streaming for LZ4 compression

Replace full-input buffering with FrameEncoder-based incremental output
in Lz4CompressContext. Compressed blocks are emitted as internal buffers
fill, and old bytes are drained to bound memory usage.

Decompression remains buffered due to lz4_flex FrameDecoder requiring
full input (documented in #182).

Closes #182
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
* chore: rename package from zflate to comprs

Rename npm package, Rust crates, napi binary name, platform packages,
and all references from "zflate" to "comprs". The name "comprs" conveys
"compress" with a Rust flavor, is available on npm, and avoids the
typosquat protection that blocks "zflate".

Changes across 70 files:
- npm: comprs, comprs-darwin-arm64, comprs-wasm32-wasi, etc.
- Rust: comprs (core), comprs-bench
- napi binaryName: comprs (→ comprs.*.node, comprs.*.wasm)
- README, workflows, changesets, tests, benchmarks

GitHub repository URL (derodero24/zflate) is preserved.

Closes #189

* chore: update GitHub repo URLs to derodero24/comprs

Update all repository references to match the planned GitHub repo
rename from derodero24/zflate to derodero24/comprs.
…192)

Rename internal Rust error type `ZflateError` → `ComprsError` across
all source files and update benchmark variable names `*_ZFLATE` →
`*_COMPRS` for consistency with the package rename in #190.

Closes #191
…ublish files (#194)

- Add LZ4 one-shot and streaming context exports to browser-entry.js
- Add Lz4CompressContext/Lz4DecompressContext adapters to browser-streaming.js
- Add createLz4CompressTransform/createLz4DecompressTransform to node.js
- Add LZ4 type declarations to node.d.ts
- Add 'lz4' case to createDecompressContext in node.js
- Add browser-entry.js and browser-streaming.js to package.json files array
- Document LZ4 API in README.md (one-shot, async, streaming, comparison)
- Fix streaming import path in README.md (comprs → comprs/streams)
- Update auto-detect descriptions to include LZ4
- Add "lz4" to package.json keywords and description
- Add LZ4 changeset for upcoming release

Closes #193
…#196)

- Add LZ4 one-shot APIs, Context classes, and streaming functions to
  index.mjs (ESM users could not access LZ4 at all)
- Add createLz4CompressStream/createLz4DecompressStream to index.mjs
- Add gzipCompressWithHeader and gzipReadHeader to browser-entry.js
- Document gzipCompressWithHeader, gzipReadHeader in README
- Document crc32 and version() utilities in README
- Document createDecompressStream and createDecompressTransform in README

Closes #195
…ection (#198)

The decompressAsync Rust doc comment listed only zstd, gzip, brotli as
supported formats, but the implementation also handles lz4. The README
async section claimed "all one-shot functions" have async variants, which
is inaccurate for utility functions like crc32, version, gzipReadHeader.

Closes #197
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@github-actions
github-actions Bot requested a review from derodero24 as a code owner March 24, 2026 12:21
# Conflicts:
#	.github/workflows/ci.yml
#	.github/workflows/codeql.yml
#	.github/workflows/codspeed.yml
#	.github/workflows/release.yml
#	CHANGELOG.md
#	CONTRIBUTING.md
#	Cargo.lock
#	Cargo.toml
#	README.md
#	SECURITY.md
#	__test__/esm-import.mjs
#	__test__/index.spec.ts
#	__test__/streaming.spec.ts
#	__test__/zstd.spec.ts
#	browser.js
#	crates/core/Cargo.toml
#	crates/core/src/lib.rs
#	crates/core/src/zstd.rs
#	crates/core/src/zstd_stream.rs
#	index.d.ts
#	index.js
#	index.mjs
#	npm/darwin-arm64/README.md
#	npm/darwin-arm64/package.json
#	npm/darwin-x64/README.md
#	npm/darwin-x64/package.json
#	npm/linux-arm64-gnu/README.md
#	npm/linux-arm64-gnu/package.json
#	npm/linux-arm64-musl/README.md
#	npm/linux-arm64-musl/package.json
#	npm/linux-x64-gnu/README.md
#	npm/linux-x64-gnu/package.json
#	npm/linux-x64-musl/README.md
#	npm/linux-x64-musl/package.json
#	npm/wasm32-wasi/README.md
#	npm/wasm32-wasi/package.json
#	npm/win32-arm64-msvc/README.md
#	npm/win32-arm64-msvc/package.json
#	npm/win32-x64-msvc/README.md
#	npm/win32-x64-msvc/package.json
#	package.json
#	pnpm-lock.yaml
#	scripts/optimize-wasm.js
#	streams.d.ts
#	streams.js
@derodero24
derodero24 merged commit 033714b into main Mar 24, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant