Repository navigation
chore(release): release v0.3.0 - #199
Merged
Merged
Conversation
* 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
#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.
…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>
# 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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.3.0
Merging this PR will:
Changelog