├── .cargo └── config.toml ├── .editorconfig ├── .eslintignore ├── .eslintrc.yml ├── .github ├── CODEOWNERS ├── dependabot.yaml └── workflows │ ├── CI.yaml │ └── lint.yaml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .taplo.toml ├── .yarn └── releases │ └── yarn-4.5.0.cjs ├── .yarnrc.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── __test__ ├── dict.bin └── index.spec.ts ├── benchmark └── bench.ts ├── build.rs ├── index.d.ts ├── index.js ├── npm ├── android-arm-eabi │ ├── README.md │ └── package.json ├── android-arm64 │ ├── README.md │ └── package.json ├── darwin-arm64 │ ├── README.md │ └── package.json ├── darwin-x64 │ ├── README.md │ └── package.json ├── freebsd-x64 │ ├── README.md │ └── package.json ├── linux-arm-gnueabihf │ ├── README.md │ └── package.json ├── linux-arm64-gnu │ ├── README.md │ └── package.json ├── linux-arm64-musl │ ├── README.md │ └── package.json ├── linux-x64-gnu │ ├── README.md │ └── package.json ├── linux-x64-musl │ ├── README.md │ └── package.json ├── win32-arm64-msvc │ ├── README.md │ └── package.json ├── win32-ia32-msvc │ ├── README.md │ └── package.json └── win32-x64-msvc │ ├── README.md │ └── package.json ├── package.json ├── rustfmt.toml ├── simple-test.js ├── src └── lib.rs ├── tsconfig.json ├── util.js └── yarn.lock /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-musl] 2 | rustflags = [ 3 | "-C", 4 | "target-feature=-crt-static", 5 | ] 6 | 7 | [target.aarch64-unknown-linux-musl] 8 | linker = "aarch64-linux-musl-gcc" 9 | rustflags = ["-C", "target-feature=-crt-static"] 10 | 11 | [target.x86_64-pc-windows-msvc] 12 | rustflags = ["-C", "target-feature=+crt-static"] 13 | 14 | [target.i686-pc-windows-msvc] 15 | rustflags = ["-C", "target-feature=+crt-static"] 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors or IDEs 3 | # http://editorconfig.org 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | index.js 2 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | parser: '@typescript-eslint/parser' 2 | 3 | parserOptions: 4 | ecmaFeatures: 5 | jsx: true 6 | ecmaVersion: latest 7 | sourceType: module 8 | project: ./tsconfig.json 9 | extraFileExtensions: ['.mjs'] 10 | 11 | env: 12 | browser: true 13 | es6: true 14 | node: true 15 | jest: true 16 | 17 | plugins: 18 | - import 19 | - '@typescript-eslint' 20 | 21 | extends: 22 | - eslint:recommended 23 | - prettier 24 | 25 | rules: 26 | # 0 = off, 1 = warn, 2 = error 27 | 'space-before-function-paren': 0 28 | 'no-useless-constructor': 0 29 | 'no-undef': 2 30 | 'no-console': [2, { allow: ['error', 'warn', 'info', 'assert'] }] 31 | 'comma-dangle': ['error', 'only-multiline'] 32 | 'no-unused-vars': 0 33 | 'no-var': 2 34 | 'one-var-declaration-per-line': 2 35 | 'prefer-const': 2 36 | 'no-const-assign': 2 37 | 'no-duplicate-imports': 2 38 | 'no-use-before-define': [2, { 'functions': false, 'classes': false }] 39 | 'eqeqeq': [2, 'always', { 'null': 'ignore' }] 40 | 'no-case-declarations': 0 41 | 'no-empty': 0 42 | 'no-restricted-syntax': 43 | [ 44 | 2, 45 | { 46 | 'selector': 'BinaryExpression[operator=/(==|===|!=|!==)/][left.raw=true], BinaryExpression[operator=/(==|===|!=|!==)/][right.raw=true]', 47 | 'message': Don't compare for equality against boolean literals, 48 | }, 49 | ] 50 | 51 | # https://github.com/benmosher/eslint-plugin-import/pull/334 52 | 'import/no-duplicates': 2 53 | 'import/first': 2 54 | 'import/newline-after-import': 2 55 | 'import/order': 56 | [ 57 | 2, 58 | { 59 | 'newlines-between': 'always', 60 | 'alphabetize': { 'order': 'asc' }, 61 | 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], 62 | }, 63 | ] 64 | 65 | overrides: 66 | - files: 67 | - ./**/*{.ts,.tsx,.mjs} 68 | rules: 69 | 'no-undef': 0 70 | # TypeScript declare merge 71 | 'no-redeclare': 0 72 | 'no-useless-constructor': 0 73 | 'no-dupe-class-members': 0 74 | 'no-case-declarations': 0 75 | 'no-duplicate-imports': 0 76 | # TypeScript Interface and Type 77 | 'no-use-before-define': 0 78 | 'no-unused-vars': [2, { varsIgnorePattern: '^_', argsIgnorePattern: '^_', ignoreRestSiblings: true }] 79 | 80 | '@typescript-eslint/adjacent-overload-signatures': 2 81 | '@typescript-eslint/await-thenable': 2 82 | '@typescript-eslint/consistent-type-assertions': 2 83 | '@typescript-eslint/ban-types': 84 | [ 85 | 'error', 86 | { 87 | 'types': 88 | { 89 | 'String': { 'message': 'Use string instead', 'fixWith': 'string' }, 90 | 'Number': { 'message': 'Use number instead', 'fixWith': 'number' }, 91 | 'Boolean': { 'message': 'Use boolean instead', 'fixWith': 'boolean' }, 92 | 'Function': { 'message': 'Use explicit type instead' }, 93 | }, 94 | }, 95 | ] 96 | '@typescript-eslint/explicit-member-accessibility': 97 | [ 98 | 'error', 99 | { 100 | accessibility: 'explicit', 101 | overrides: 102 | { 103 | accessors: 'no-public', 104 | constructors: 'no-public', 105 | methods: 'no-public', 106 | properties: 'no-public', 107 | parameterProperties: 'explicit', 108 | }, 109 | }, 110 | ] 111 | '@typescript-eslint/method-signature-style': 2 112 | '@typescript-eslint/no-floating-promises': 2 113 | '@typescript-eslint/no-implied-eval': 2 114 | '@typescript-eslint/no-for-in-array': 2 115 | '@typescript-eslint/no-inferrable-types': 2 116 | '@typescript-eslint/no-invalid-void-type': 2 117 | '@typescript-eslint/no-misused-new': 2 118 | '@typescript-eslint/no-misused-promises': 2 119 | '@typescript-eslint/no-namespace': 2 120 | '@typescript-eslint/no-non-null-asserted-optional-chain': 2 121 | '@typescript-eslint/no-throw-literal': 2 122 | '@typescript-eslint/no-unnecessary-boolean-literal-compare': 2 123 | '@typescript-eslint/prefer-for-of': 2 124 | '@typescript-eslint/prefer-nullish-coalescing': 2 125 | '@typescript-eslint/switch-exhaustiveness-check': 2 126 | '@typescript-eslint/prefer-optional-chain': 2 127 | '@typescript-eslint/prefer-readonly': 2 128 | '@typescript-eslint/prefer-string-starts-ends-with': 0 129 | '@typescript-eslint/no-array-constructor': 2 130 | '@typescript-eslint/require-await': 2 131 | '@typescript-eslint/return-await': 2 132 | '@typescript-eslint/ban-ts-comment': 133 | [2, { 'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': true, 'ts-check': false }] 134 | '@typescript-eslint/naming-convention': 135 | [ 136 | 2, 137 | { 138 | selector: 'memberLike', 139 | format: ['camelCase', 'PascalCase'], 140 | modifiers: ['private'], 141 | leadingUnderscore: 'forbid', 142 | }, 143 | ] 144 | '@typescript-eslint/no-unused-vars': 145 | [2, { varsIgnorePattern: '^_', argsIgnorePattern: '^_', ignoreRestSiblings: true }] 146 | '@typescript-eslint/member-ordering': 147 | [ 148 | 2, 149 | { 150 | default: 151 | [ 152 | 'public-static-field', 153 | 'protected-static-field', 154 | 'private-static-field', 155 | 'public-static-method', 156 | 'protected-static-method', 157 | 'private-static-method', 158 | 'public-instance-field', 159 | 'protected-instance-field', 160 | 'private-instance-field', 161 | 'public-constructor', 162 | 'protected-constructor', 163 | 'private-constructor', 164 | 'public-instance-method', 165 | 'protected-instance-method', 166 | 'private-instance-method', 167 | ], 168 | }, 169 | ] 170 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @antoniomuso 2 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: 'npm' # See documentation for possible values 9 | directory: '/' # Location of package manifests 10 | schedule: 11 | interval: 'daily' 12 | open-pull-requests-limit: 10 13 | 14 | - package-ecosystem: 'github-actions' 15 | directory: '/' 16 | schedule: 17 | interval: 'daily' 18 | open-pull-requests-limit: 10 19 | 20 | - package-ecosystem: 'cargo' 21 | directory: '/' 22 | schedule: 23 | interval: 'daily' 24 | open-pull-requests-limit: 10 25 | -------------------------------------------------------------------------------- /.github/workflows/CI.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | env: 3 | DEBUG: napi:* 4 | APP_NAME: lz4-napi 5 | MACOSX_DEPLOYMENT_TARGET: '10.13' 6 | permissions: 7 | contents: write 8 | id-token: write 9 | 'on': 10 | push: 11 | branches: 12 | - main 13 | tags-ignore: 14 | - '**' 15 | paths-ignore: 16 | - '**/*.md' 17 | - LICENSE 18 | - '**/*.gitignore' 19 | - .editorconfig 20 | - docs/** 21 | pull_request: null 22 | jobs: 23 | build: 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | settings: 28 | - host: macos-latest 29 | target: x86_64-apple-darwin 30 | build: yarn build --target x86_64-apple-darwin 31 | - host: windows-latest 32 | build: yarn build --target x86_64-pc-windows-msvc 33 | target: x86_64-pc-windows-msvc 34 | - host: windows-latest 35 | build: | 36 | yarn build --target i686-pc-windows-msvc 37 | yarn test 38 | target: i686-pc-windows-msvc 39 | - host: ubuntu-latest 40 | target: x86_64-unknown-linux-gnu 41 | build: CC=clang yarn build --target x86_64-unknown-linux-gnu --use-napi-cross 42 | - host: ubuntu-latest 43 | target: x86_64-unknown-linux-musl 44 | build: yarn build -x --target x86_64-unknown-linux-musl 45 | - host: macos-latest 46 | target: aarch64-apple-darwin 47 | build: yarn build --target aarch64-apple-darwin 48 | - host: ubuntu-latest 49 | target: aarch64-unknown-linux-gnu 50 | build: CC=clang yarn build --target aarch64-unknown-linux-gnu --use-napi-cross 51 | - host: ubuntu-latest 52 | target: armv7-unknown-linux-gnueabihf 53 | setup: | 54 | sudo apt-get update 55 | sudo apt-get install gcc-arm-linux-gnueabihf -y 56 | build: yarn build --target armv7-unknown-linux-gnueabihf --use-napi-cross 57 | - host: ubuntu-latest 58 | target: aarch64-linux-android 59 | build: yarn build --target aarch64-linux-android 60 | - host: ubuntu-latest 61 | target: armv7-linux-androideabi 62 | build: yarn build --target armv7-linux-androideabi 63 | - host: ubuntu-latest 64 | target: aarch64-unknown-linux-musl 65 | build: yarn build --target aarch64-unknown-linux-musl -x 66 | - host: windows-latest 67 | target: aarch64-pc-windows-msvc 68 | build: yarn build --target aarch64-pc-windows-msvc 69 | name: stable - ${{ matrix.settings.target }} - node@20 70 | runs-on: ${{ matrix.settings.host }} 71 | steps: 72 | - uses: actions/checkout@v4 73 | - name: Setup node 74 | uses: actions/setup-node@v4 75 | if: ${{ !matrix.settings.docker }} 76 | with: 77 | node-version: 20 78 | cache: yarn 79 | - name: Install 80 | uses: dtolnay/rust-toolchain@stable 81 | with: 82 | toolchain: stable 83 | targets: ${{ matrix.settings.target }} 84 | - name: Cache cargo 85 | uses: actions/cache@v4 86 | with: 87 | path: | 88 | ~/.cargo/registry 89 | ~/.cargo/git/db/ 90 | .cargo-cache 91 | ~/.napi-rs 92 | target/ 93 | key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }} 94 | - uses: goto-bus-stop/setup-zig@v2 95 | if: ${{ contains(matrix.settings.target, 'musl') }} 96 | with: 97 | version: 0.13.0 98 | - name: Install cargo-zigbuild 99 | uses: taiki-e/install-action@v2 100 | if: ${{ contains(matrix.settings.target, 'musl') }} 101 | env: 102 | GITHUB_TOKEN: ${{ github.token }} 103 | with: 104 | tool: cargo-zigbuild 105 | - name: Setup toolchain 106 | run: ${{ matrix.settings.setup }} 107 | if: ${{ matrix.settings.setup }} 108 | shell: bash 109 | - name: Setup node x86 110 | if: matrix.settings.target == 'i686-pc-windows-msvc' 111 | run: yarn config set supportedArchitectures.cpu "ia32" 112 | shell: bash 113 | - name: Install dependencies 114 | run: yarn install 115 | - name: Setup node x86 116 | uses: actions/setup-node@v4 117 | if: matrix.settings.target == 'i686-pc-windows-msvc' 118 | with: 119 | node-version: 20 120 | cache: yarn 121 | architecture: x86 122 | - name: Build 123 | run: ${{ matrix.settings.build }} 124 | shell: bash 125 | - name: Upload artifact 126 | uses: actions/upload-artifact@v4 127 | with: 128 | name: bindings-${{ matrix.settings.target }} 129 | path: ${{ env.APP_NAME }}.*.node 130 | if-no-files-found: error 131 | build-freebsd: 132 | runs-on: ubuntu-latest 133 | name: Build FreeBSD 134 | steps: 135 | - uses: actions/checkout@v4 136 | - name: Build 137 | id: build 138 | uses: cross-platform-actions/action@v0.25.0 139 | env: 140 | DEBUG: napi:* 141 | RUSTUP_HOME: /usr/local/rustup 142 | CARGO_HOME: /usr/local/cargo 143 | RUSTUP_IO_THREADS: 1 144 | with: 145 | operating_system: freebsd 146 | version: '14.1' 147 | memory: 8G 148 | cpu_count: 3 149 | environment_variables: 'DEBUG RUSTUP_IO_THREADS' 150 | shell: bash 151 | run: | 152 | sudo pkg install -y -f curl node libnghttp2 npm yarn 153 | sudo npm install -g yarn --ignore-scripts 154 | curl https://sh.rustup.rs -sSf --output rustup.sh 155 | sh rustup.sh -y --profile minimal --default-toolchain beta 156 | source "$HOME/.cargo/env" 157 | echo "~~~~ rustc --version ~~~~" 158 | rustc --version 159 | echo "~~~~ node -v ~~~~" 160 | node -v 161 | echo "~~~~ yarn --version ~~~~" 162 | yarn --version 163 | pwd 164 | ls -lah 165 | whoami 166 | env 167 | freebsd-version 168 | yarn install --mode=skip-build 169 | yarn build 170 | rm -rf node_modules 171 | rm -rf target 172 | rm -rf .yarn/cache 173 | - name: Upload artifact 174 | uses: actions/upload-artifact@v4 175 | with: 176 | name: bindings-freebsd 177 | path: ${{ env.APP_NAME }}.*.node 178 | if-no-files-found: error 179 | test-macOS-windows-binding: 180 | name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }} 181 | needs: 182 | - build 183 | strategy: 184 | fail-fast: false 185 | matrix: 186 | settings: 187 | - host: macos-latest 188 | target: x86_64-apple-darwin 189 | architecture: x64 190 | - host: macos-latest 191 | target: aarch64-apple-darwin 192 | architecture: arm64 193 | - host: windows-latest 194 | target: x86_64-pc-windows-msvc 195 | architecture: x64 196 | node: 197 | - '18' 198 | - '20' 199 | runs-on: ${{ matrix.settings.host }} 200 | steps: 201 | - uses: actions/checkout@v4 202 | - name: Setup node 203 | uses: actions/setup-node@v4 204 | with: 205 | node-version: ${{ matrix.node }} 206 | cache: yarn 207 | architecture: ${{ matrix.settings.architecture }} 208 | - name: Install dependencies 209 | run: yarn install --mode=skip-build 210 | - name: Download artifacts 211 | uses: actions/download-artifact@v4 212 | with: 213 | name: bindings-${{ matrix.settings.target }} 214 | path: . 215 | - name: List packages 216 | run: ls -R . 217 | shell: bash 218 | - name: Test bindings 219 | run: yarn test 220 | test-linux-x64-gnu-binding: 221 | name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }} 222 | needs: 223 | - build 224 | strategy: 225 | fail-fast: false 226 | matrix: 227 | node: 228 | - '18' 229 | - '20' 230 | runs-on: ubuntu-latest 231 | steps: 232 | - uses: actions/checkout@v4 233 | - name: Setup node 234 | uses: actions/setup-node@v4 235 | with: 236 | node-version: ${{ matrix.node }} 237 | cache: yarn 238 | - name: Install dependencies 239 | run: yarn install 240 | - name: Download artifacts 241 | uses: actions/download-artifact@v4 242 | with: 243 | name: bindings-x86_64-unknown-linux-gnu 244 | path: . 245 | - name: List packages 246 | run: ls -R . 247 | shell: bash 248 | - name: Test bindings 249 | run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-slim yarn test 250 | test-linux-x64-musl-binding: 251 | name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }} 252 | needs: 253 | - build 254 | strategy: 255 | fail-fast: false 256 | matrix: 257 | node: 258 | - '18' 259 | - '20' 260 | runs-on: ubuntu-latest 261 | steps: 262 | - uses: actions/checkout@v4 263 | - name: Setup node 264 | uses: actions/setup-node@v4 265 | with: 266 | node-version: ${{ matrix.node }} 267 | cache: yarn 268 | - name: Install dependencies 269 | run: | 270 | yarn config set supportedArchitectures.libc "musl" 271 | yarn install --mode=skip-build 272 | - name: Download artifacts 273 | uses: actions/download-artifact@v4 274 | with: 275 | name: bindings-x86_64-unknown-linux-musl 276 | path: . 277 | - name: List packages 278 | run: ls -R . 279 | shell: bash 280 | - name: Test bindings 281 | run: docker run --rm -v $(pwd):/build -w /build node:${{ matrix.node }}-alpine yarn test 282 | test-linux-aarch64-gnu-binding: 283 | name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }} 284 | needs: 285 | - build 286 | strategy: 287 | fail-fast: false 288 | matrix: 289 | node: 290 | - '20' 291 | - '22' 292 | runs-on: ubuntu-latest 293 | steps: 294 | - uses: actions/checkout@v4 295 | - name: Download artifacts 296 | uses: actions/download-artifact@v4 297 | with: 298 | name: bindings-aarch64-unknown-linux-gnu 299 | path: . 300 | - name: List packages 301 | run: ls -R . 302 | shell: bash 303 | - name: Install dependencies 304 | run: | 305 | yarn config set supportedArchitectures.cpu "arm64" 306 | yarn config set supportedArchitectures.libc "glibc" 307 | yarn install --mode=skip-build 308 | - name: Set up QEMU 309 | uses: docker/setup-qemu-action@v3 310 | with: 311 | platforms: arm64 312 | - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes 313 | - name: Setup and run tests 314 | uses: addnab/docker-run-action@v3 315 | with: 316 | image: node:${{ matrix.node }}-slim 317 | options: '--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build' 318 | run: | 319 | set -e 320 | yarn test 321 | ls -la 322 | test-linux-aarch64-musl-binding: 323 | name: Test bindings on aarch64-unknown-linux-musl - node@lts 324 | needs: 325 | - build 326 | runs-on: ubuntu-latest 327 | steps: 328 | - uses: actions/checkout@v4 329 | - name: Download artifacts 330 | uses: actions/download-artifact@v4 331 | with: 332 | name: bindings-aarch64-unknown-linux-musl 333 | path: . 334 | - name: List packages 335 | run: ls -R . 336 | shell: bash 337 | - name: Install dependencies 338 | run: | 339 | yarn config set supportedArchitectures.cpu "arm64" 340 | yarn config set supportedArchitectures.libc "musl" 341 | yarn install --mode=skip-build 342 | - name: Set up QEMU 343 | uses: docker/setup-qemu-action@v3 344 | with: 345 | platforms: arm64 346 | - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes 347 | - name: Setup and run tests 348 | uses: addnab/docker-run-action@v3 349 | with: 350 | image: node:lts-alpine 351 | options: '--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build' 352 | run: | 353 | set -e 354 | yarn test 355 | test-linux-arm-gnueabihf-binding: 356 | name: Test bindings on armv7-unknown-linux-gnueabihf - node@${{ matrix.node }} 357 | needs: 358 | - build 359 | strategy: 360 | fail-fast: false 361 | matrix: 362 | node: 363 | - '18' 364 | - '20' 365 | runs-on: ubuntu-latest 366 | steps: 367 | - uses: actions/checkout@v4 368 | - name: Download artifacts 369 | uses: actions/download-artifact@v4 370 | with: 371 | name: bindings-armv7-unknown-linux-gnueabihf 372 | path: . 373 | - name: List packages 374 | run: ls -R . 375 | shell: bash 376 | - name: Install dependencies 377 | run: | 378 | yarn config set supportedArchitectures.cpu "arm" 379 | yarn install --mode=skip-build 380 | - name: Set up QEMU 381 | uses: docker/setup-qemu-action@v3 382 | with: 383 | platforms: arm 384 | - run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes 385 | - name: Setup and run tests 386 | uses: addnab/docker-run-action@v3 387 | with: 388 | image: node:${{ matrix.node }}-bullseye-slim 389 | options: '--platform linux/arm/v7 -v ${{ github.workspace }}:/build -w /build' 390 | run: | 391 | set -e 392 | yarn test 393 | ls -la 394 | publish: 395 | name: Publish 396 | runs-on: ubuntu-latest 397 | needs: 398 | - build-freebsd 399 | - test-macOS-windows-binding 400 | - test-linux-x64-gnu-binding 401 | - test-linux-x64-musl-binding 402 | - test-linux-aarch64-gnu-binding 403 | - test-linux-aarch64-musl-binding 404 | - test-linux-arm-gnueabihf-binding 405 | steps: 406 | - uses: actions/checkout@v4 407 | - name: Setup node 408 | uses: actions/setup-node@v4 409 | with: 410 | node-version: 20 411 | cache: yarn 412 | - name: Install dependencies 413 | run: yarn install --mode=skip-build 414 | - name: Download all artifacts 415 | uses: actions/download-artifact@v4 416 | with: 417 | path: artifacts 418 | - name: Move artifacts 419 | run: yarn artifacts 420 | - name: List packages 421 | run: ls -R ./npm 422 | shell: bash 423 | - name: Publish 424 | run: | 425 | npm config set provenance true 426 | if git log -1 --pretty=%B | grep "^[0-9]\+\.[0-9]\+\.[0-9]\+$"; 427 | then 428 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc 429 | npm publish --access public 430 | elif git log -1 --pretty=%B | grep "^[0-9]\+\.[0-9]\+\.[0-9]\+"; 431 | then 432 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc 433 | npm publish --tag next --access public 434 | else 435 | echo "Not a release, skipping publish" 436 | fi 437 | env: 438 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 439 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 440 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags-ignore: 8 | - '**' 9 | pull_request: 10 | 11 | jobs: 12 | lint: 13 | name: Lint 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Setup node 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 18 22 | cache: 'yarn' 23 | 24 | - name: Install 25 | uses: dtolnay/rust-toolchain@stable 26 | with: 27 | components: clippy, rustfmt 28 | 29 | - name: 'Install dependencies' 30 | run: yarn install --mode=skip-build 31 | 32 | - name: ESLint 33 | run: yarn lint 34 | 35 | - name: Cargo fmt 36 | run: cargo fmt -- --check 37 | 38 | - name: Clippy 39 | run: cargo clippy 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/node 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Microbundle cache 62 | .rpt2_cache/ 63 | .rts2_cache_cjs/ 64 | .rts2_cache_es/ 65 | .rts2_cache_umd/ 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variables file 77 | .env 78 | .env.test 79 | 80 | # parcel-bundler cache (https://parceljs.org/) 81 | .cache 82 | 83 | # Next.js build output 84 | .next 85 | 86 | # Nuxt.js build / generate output 87 | .nuxt 88 | dist 89 | 90 | # Gatsby files 91 | .cache/ 92 | # Comment in the public line in if your project uses Gatsby and not Next.js 93 | # https://nextjs.org/blog/next-9-1#public-directory-support 94 | # public 95 | 96 | # vuepress build output 97 | .vuepress/dist 98 | 99 | # Serverless directories 100 | .serverless/ 101 | 102 | # FuseBox cache 103 | .fusebox/ 104 | 105 | # DynamoDB Local files 106 | .dynamodb/ 107 | 108 | # TernJS port file 109 | .tern-port 110 | 111 | # Stores VSCode versions used for testing VSCode extensions 112 | .vscode-test 113 | 114 | # End of https://www.toptal.com/developers/gitignore/api/node 115 | 116 | 117 | #Added by cargo 118 | 119 | /target 120 | Cargo.lock 121 | 122 | *.node 123 | .pnp.* 124 | .yarn/* 125 | !.yarn/patches 126 | !.yarn/plugins 127 | !.yarn/releases 128 | !.yarn/sdks 129 | !.yarn/versions 130 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.taplo.toml: -------------------------------------------------------------------------------- 1 | exclude = ["node_modules/**/*.toml"] 2 | 3 | # https://taplo.tamasfe.dev/configuration/formatter-options.html 4 | [formatting] 5 | align_entries = true 6 | indent_tables = true 7 | reorder_keys = true 8 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | 7 | yarnPath: .yarn/releases/yarn-4.5.0.cjs 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [2.4.0](https://github.com/antoniomuso/lz4-napi/compare/v2.3.0...v2.4.0) (2024-10-10) 2 | 3 | 4 | ### Features 5 | 6 | * upgrade deps ([2a07651](https://github.com/antoniomuso/lz4-napi/commit/2a076514141274e9429c5bf6ff466a20a660d0aa)) 7 | 8 | 9 | 10 | ## [2.3.2](https://github.com/antoniomuso/lz4-napi/compare/v2.3.0...v2.3.2) (2024-10-10) 11 | 12 | 13 | ### Features 14 | 15 | * upgrade deps ([2a07651](https://github.com/antoniomuso/lz4-napi/commit/2a076514141274e9429c5bf6ff466a20a660d0aa)) 16 | 17 | 18 | 19 | ## [2.3.1](https://github.com/antoniomuso/lz4-napi/compare/v2.2.0...v2.3.1) (2024-10-10) 20 | 21 | 22 | ### Bug Fixes 23 | 24 | * build ([a0eb566](https://github.com/antoniomuso/lz4-napi/commit/a0eb5668821a6781218bc67c8984346d1660ec3b)) 25 | 26 | 27 | ### Features 28 | 29 | * added frame compression decompression ([ce4b029](https://github.com/antoniomuso/lz4-napi/commit/ce4b0292becbfeea6d902d97d918fc6447b8df83)) 30 | * bump to 2.23.0 ([ef0e01f](https://github.com/antoniomuso/lz4-napi/commit/ef0e01ffba311e1637495e6cb7b51b0ca8b963eb)) 31 | * upgrade deps and CI ([16c8079](https://github.com/antoniomuso/lz4-napi/commit/16c807945c29d6e6385eb344e17f670cf5699d8a)) 32 | 33 | 34 | 35 | # [2.3.0](https://github.com/antoniomuso/lz4-napi/compare/v2.2.0...v2.3.0) (2024-10-10) 36 | 37 | 38 | ### Bug Fixes 39 | 40 | * build ([a0eb566](https://github.com/antoniomuso/lz4-napi/commit/a0eb5668821a6781218bc67c8984346d1660ec3b)) 41 | 42 | 43 | ### Features 44 | 45 | * added frame compression decompression ([ce4b029](https://github.com/antoniomuso/lz4-napi/commit/ce4b0292becbfeea6d902d97d918fc6447b8df83)) 46 | * bump to 2.23.0 ([ef0e01f](https://github.com/antoniomuso/lz4-napi/commit/ef0e01ffba311e1637495e6cb7b51b0ca8b963eb)) 47 | * upgrade deps and CI ([16c8079](https://github.com/antoniomuso/lz4-napi/commit/16c807945c29d6e6385eb344e17f670cf5699d8a)) 48 | 49 | 50 | 51 | # [2.3.0](https://github.com/antoniomuso/lz4-napi/compare/v2.2.0...v2.3.0) (2024-10-10) 52 | 53 | 54 | ### Bug Fixes 55 | 56 | * build ([a0eb566](https://github.com/antoniomuso/lz4-napi/commit/a0eb5668821a6781218bc67c8984346d1660ec3b)) 57 | 58 | 59 | ### Features 60 | 61 | * added frame compression decompression ([ce4b029](https://github.com/antoniomuso/lz4-napi/commit/ce4b0292becbfeea6d902d97d918fc6447b8df83)) 62 | * bump to 2.23.0 ([ef0e01f](https://github.com/antoniomuso/lz4-napi/commit/ef0e01ffba311e1637495e6cb7b51b0ca8b963eb)) 63 | * upgrade deps and CI ([16c8079](https://github.com/antoniomuso/lz4-napi/commit/16c807945c29d6e6385eb344e17f670cf5699d8a)) 64 | 65 | 66 | 67 | # [2.2.0](https://github.com/antoniomuso/lz4-napi/compare/v2.1.0...v2.2.0) (2022-09-24) 68 | 69 | 70 | ### Features 71 | 72 | * added dict support ([640dc96](https://github.com/antoniomuso/lz4-napi/commit/640dc9687d8e635a2457cba48f15d54a0a83532d)) 73 | 74 | 75 | 76 | ## [2.0.3](https://github.com/antoniomuso/lz4-napi/compare/v1.0.1...v2.0.3) (2022-01-30) 77 | 78 | 79 | ### Bug Fixes 80 | 81 | * fix release ([e63b327](https://github.com/antoniomuso/lz4-napi/commit/e63b327786ce0ee87689663e37838bfb35002864)) 82 | * **type:** removed string from uncompress input type ([b7fc2ca](https://github.com/antoniomuso/lz4-napi/commit/b7fc2cacd9b8664006105d4417c04fb6a1103a17)) 83 | 84 | 85 | ### Features 86 | 87 | * napi 2.0.0 ([19845a5](https://github.com/antoniomuso/lz4-napi/commit/19845a54fe0b4897b4fde9ba5796dd061f055422)) 88 | 89 | 90 | 91 | ## [2.0.2](https://github.com/antoniomuso/lz4-napi/compare/v1.0.1...v2.0.2) (2022-01-30) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * **type:** removed string from uncompress input type ([b7fc2ca](https://github.com/antoniomuso/lz4-napi/commit/b7fc2cacd9b8664006105d4417c04fb6a1103a17)) 97 | 98 | 99 | ### Features 100 | 101 | * napi 2.0.0 ([19845a5](https://github.com/antoniomuso/lz4-napi/commit/19845a54fe0b4897b4fde9ba5796dd061f055422)) 102 | 103 | 104 | 105 | ## [2.0.1](https://github.com/antoniomuso/lz4-napi/compare/v1.0.1...v2.0.1) (2022-01-30) 106 | 107 | 108 | ### Bug Fixes 109 | 110 | * **type:** removed string from uncompress input type ([b7fc2ca](https://github.com/antoniomuso/lz4-napi/commit/b7fc2cacd9b8664006105d4417c04fb6a1103a17)) 111 | 112 | 113 | ### Features 114 | 115 | * napi 2.0.0 ([19845a5](https://github.com/antoniomuso/lz4-napi/commit/19845a54fe0b4897b4fde9ba5796dd061f055422)) 116 | 117 | 118 | 119 | # [2.0.0](https://github.com/antoniomuso/lz4-napi/compare/v1.0.1...v2.0.0) (2022-01-30) 120 | 121 | 122 | ### Bug Fixes 123 | 124 | * **type:** removed string from uncompress input type ([b7fc2ca](https://github.com/antoniomuso/lz4-napi/commit/b7fc2cacd9b8664006105d4417c04fb6a1103a17)) 125 | 126 | 127 | ### Features 128 | 129 | * napi 2.0.0 ([19845a5](https://github.com/antoniomuso/lz4-napi/commit/19845a54fe0b4897b4fde9ba5796dd061f055422)) 130 | 131 | 132 | 133 | ## [1.0.2](https://github.com/antoniomuso/lz4-napi/compare/v1.0.1...v1.0.2) (2021-12-04) 134 | 135 | 136 | ### Bug Fixes 137 | 138 | * **type:** removed string from uncompress input type ([b7fc2ca](https://github.com/antoniomuso/lz4-napi/commit/b7fc2cacd9b8664006105d4417c04fb6a1103a17)) 139 | 140 | 141 | 142 | # 1.0.1 (2021-11-27) 143 | 144 | 145 | ### Features 146 | 147 | * added exporting ([4fd604c](https://github.com/antoniomuso/lz4-napi/commit/4fd604c94087fb0f0c6c79bb092a43d43d8c9b6f)) 148 | * changed package name ([c2d229d](https://github.com/antoniomuso/lz4-napi/commit/c2d229dbdb3ce5140a8b95198b546331af7b7b3d)) 149 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["antoniomuso "] 3 | edition = "2021" 4 | name = "lz4-napi" 5 | version = "0.1.0" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | lz4_flex = { version = "0.11.3" } 14 | napi = "2" 15 | napi-derive = "2" 16 | 17 | [target.'cfg(all(any(windows, unix), target_arch = "x86_64", not(target_env = "musl")))'.dependencies] 18 | mimalloc = { version = "0.1" } 19 | 20 | [build-dependencies] 21 | napi-build = "2.0.1" 22 | 23 | [profile.release] 24 | codgen-units = 1 25 | lto = true 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Antonio Musolino 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lz4-napi 2 | 3 | > Node.js NAPI Binding for LZ4 compression algorithm, powered by Rust [napi-rs](https://napi.rs) and [lz4-flex](https://github.com/PSeitz/lz4_flex). 4 | 5 | **Pros:** 6 | 7 | - Fast! ⚡️ 8 | - Memory Safe! 🔒 9 | - Uses libuv's threadpool! 🧵 10 | 11 | ## Table of content 12 | 13 | 14 | 15 | - [Installation](#installation) 16 | - [Usage](#usage) 17 | - [Compress](#compress) 18 | - [Uncompress](#uncompress) 19 | - [APIs](#apis) 20 | - [Promises](#promises) 21 | - [`compress`](#compress) 22 | - [`uncompress`](#uncompress) 23 | - [Sync](#sync) 24 | - [`compressSync`](#compresssync) 25 | - [`uncompressSync`](#uncompresssync) 26 | - [Benchmarks](#benchmarks) 27 | - [Performance](#performance) 28 | - [Hardware](#hardware) 29 | - [Results](#results) 30 | - [Contributing](#contributing) 31 | - [License](#license) 32 | 33 | 34 | 35 | 36 | ## Installation 37 | 38 | ```sh 39 | npm i lz4-napi 40 | # OR 41 | yarn add lz4-napi 42 | ``` 43 | 44 | 45 | 46 | ## Usage 47 | 48 | ### Compress 49 | 50 | ```js 51 | const { readFile } = require('fs/promises'); 52 | const { compress } = require('lz4-napi'); 53 | 54 | // if you support top-level await 55 | const buffer = await readFile("./bigFile.dat"); 56 | const compressedBuffer = await compress(buffer) 57 | // Store compressed buffer somewhere 58 | ``` 59 | 60 | ### Uncompress 61 | 62 | ```js 63 | const { uncompress } = require('lz4-napi'); 64 | 65 | // if you support top-level await 66 | const compressedBuffer = await getFromSomeStorage(); 67 | const uncompressedBuffer = await uncompress(compressedBuffer) 68 | // Do something with compressedBuffer! 69 | ``` 70 | 71 | ## APIs 72 | 73 | ### Promise 74 | 75 | #### `compress` 76 | 77 | ```ts 78 | (data: Buffer | string | ArrayBuffer | Uint8Array, dict?: string | Buffer) => Promise 79 | ``` 80 | 81 | #### `uncompress` 82 | 83 | ```ts 84 | (data: Buffer | string | ArrayBuffer | Uint8Array, dict?: string | Buffer) => Promise 85 | ``` 86 | 87 | #### `compressFrame` 88 | 89 | ```ts 90 | (data: Buffer | string | ArrayBuffer | Uint8Array) => Promise 91 | ``` 92 | 93 | #### `decompressFrame` 94 | 95 | ```ts 96 | (data: Buffer | string | ArrayBuffer | Uint8Array) => Promise 97 | ``` 98 | 99 | ### Sync 100 | 101 | #### `compressSync` 102 | 103 | ```ts 104 | (data: Buffer | string | ArrayBuffer | Uint8Array, dict?: string | Buffer) => Buffer 105 | ``` 106 | 107 | #### `uncompressSync` 108 | 109 | ```ts 110 | (data: Buffer | string | ArrayBuffer | Uint8Array, dict?: string | Buffer) => Buffer 111 | ``` 112 | 113 | ## Performance 114 | 115 | ### Hardware 116 | 117 | Benchmarks runs on the following hardware: 118 | 119 | - Processor Name: i9 9900K 120 | - Total Number of Cores: 8 121 | - Hyper-Threading Technology: Enabled 122 | - Memory: 32 GB 123 | 124 | ### Benchmark 125 | 126 | ```sh 127 | Running "Compress" suite... 128 | Progress: 100% 129 | 130 | lz4: 131 | 911 ops/s, ±18.64% | 54.68% slower 132 | 133 | snappy: 134 | 2 010 ops/s, ±19.23% | fastest 135 | 136 | gzip: 137 | 78 ops/s, ±18.76% | 96.12% slower 138 | 139 | deflate: 140 | 118 ops/s, ±20.42% | 94.13% slower 141 | 142 | brotli: 143 | 6 ops/s, ±0.21% | slowest, 99.7% slower 144 | 145 | Finished 5 cases! 146 | Fastest: snappy 147 | Slowest: brotli 148 | Running "Decompress" suite... 149 | Progress: 100% 150 | 151 | lz4: 152 | 9 425 ops/s, ±12.50% | fastest 153 | 154 | snappy: 155 | 3 900 ops/s, ±13.39% | 58.62% slower 156 | 157 | gzip: 158 | 823 ops/s, ±20.48% | slowest, 91.27% slower 159 | 160 | deflate: 161 | 1 350 ops/s, ±12.52% | 85.68% slower 162 | 163 | brotli: 164 | 979 ops/s, ±11.55% | 89.61% slower 165 | 166 | Finished 5 cases! 167 | Fastest: lz4 168 | Slowest: gzip 169 | Done in 61.20s. 170 | ``` 171 | 172 | 173 | 174 | ## Contributing 175 | 176 | Project is pretty simple and straight forward for what is my needs, but if you have any idea you're welcome. 177 | 178 | > This projects uses [conventional commit](https://commitlint.js.org/#/) so be sure to use standard commit format or PR won't be accepted 179 | 180 | 1. Fork the Project 181 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 182 | 3. Commit your Changes (`git commit -m 'feat(scope): some AmazingFeature'`) 183 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 184 | 5. Open a Pull Request 185 | 186 | 187 | ## Acknowledgments 188 | 189 | - [Brooooooklyn/snappy](https://github.com/Brooooooklyn/snappy) - Inspiration and project structure 190 | 191 | 192 | 193 | ## License 194 | 195 | Distributed under the MIT License. See `LICENSE` for more information. 196 | -------------------------------------------------------------------------------- /__test__/dict.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoniomuso/lz4-napi/3329351cc62f29e8fecfb0ebe13d0dc0919a24b8/__test__/dict.bin -------------------------------------------------------------------------------- /__test__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs' 2 | 3 | import test from 'ava' 4 | 5 | import { compress, uncompress, compressSync, uncompressSync, compressFrame, decompressFrame } from '../index.js' 6 | 7 | const stringToCompress = 'adewqeqweqwewleekqwoekqwoekqwpoekqwpoekqwpoekqwpoekqwpoekqwpokeeqw' 8 | const dict = readFileSync('__test__/dict.bin') 9 | 10 | test('compress should return smaller value', async (t) => { 11 | const before = Buffer.from(stringToCompress) 12 | const compressed = await compress(before) 13 | t.true(before.length > compressed.length) 14 | t.true(compressed.length !== 0) 15 | }) 16 | 17 | test('compressFrame should return smaller value', async (t) => { 18 | const before = Buffer.from(stringToCompress) 19 | const compressed = await compressFrame(before) 20 | t.true(before.length > compressed.length) 21 | t.true(compressed.length !== 0) 22 | }) 23 | 24 | test('compress decompress should work', async (t) => { 25 | const before = Buffer.from(stringToCompress) 26 | const compressed = await compress(before) 27 | t.true(before.length > compressed.length) 28 | const decompressed = await uncompress(compressed) 29 | t.is(before.toString('utf8'), decompressed.toString('utf8')) 30 | }) 31 | 32 | test('compress decompress should work with dict ', async (t) => { 33 | const before = Buffer.from(stringToCompress) 34 | const compressed = await compress(before, dict) 35 | t.true(before.length > compressed.length) 36 | const decompressed = await uncompress(compressed, dict) 37 | t.is(before.toString('utf8'), decompressed.toString('utf8')) 38 | }) 39 | 40 | test('compress decompress sync should work', (t) => { 41 | const before = Buffer.from(stringToCompress) 42 | const compressed = compressSync(before) 43 | t.true(before.length > compressed.length) 44 | const decompressed = uncompressSync(compressed) 45 | t.is(before.toString('utf8'), decompressed.toString('utf8')) 46 | }) 47 | 48 | test('compress should take all input types', async (t) => { 49 | const stringBuffer = Buffer.from(stringToCompress) 50 | await t.notThrowsAsync(compress(stringToCompress)) 51 | await t.notThrowsAsync(compress(stringBuffer)) 52 | await t.notThrowsAsync(compress(new Uint8Array(stringBuffer))) 53 | }) 54 | 55 | test('uncompress should take all input types', async (t) => { 56 | const compressedValue = compressSync(stringToCompress) 57 | await t.notThrowsAsync(uncompress(compressedValue)) 58 | await t.notThrowsAsync(uncompress(new Uint8Array(compressedValue))) 59 | }) 60 | 61 | test('compress and decompress frame should work', async (t) => { 62 | const before = Buffer.from(stringToCompress) 63 | const compressed = await compressFrame(before) 64 | t.true(before.length > compressed.length) 65 | const decompressed = await decompressFrame(compressed) 66 | t.is(before.toString('utf8'), decompressed.toString('utf8')) 67 | }) 68 | -------------------------------------------------------------------------------- /benchmark/bench.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs' 2 | import { join } from 'path' 3 | import { promisify } from 'util' 4 | import { 5 | gzip, 6 | deflate, 7 | brotliCompress, 8 | inflate, 9 | brotliDecompress, 10 | gzipSync, 11 | deflateSync, 12 | brotliCompressSync, 13 | gunzip, 14 | } from 'zlib' 15 | 16 | import b from 'benny' 17 | import snappy from 'snappy' 18 | 19 | import { compress, uncompress, compressSync } from '../index' 20 | 21 | const gzipAsync = promisify(gzip) 22 | const brotliCompressAsync = promisify(brotliCompress) 23 | const deflateAsync = promisify(deflate) 24 | const gunzipAsync = promisify(gunzip) 25 | const inflateAsync = promisify(inflate) 26 | const brotliDecompressAsync = promisify(brotliDecompress) 27 | 28 | const FIXTURE = readFileSync(join(__dirname, '..', 'yarn.lock')) 29 | const FIXTURE_DICT = readFileSync(join(__dirname, '..', '__test__/dict.bin')) 30 | const LZ4_COMPRESSED_FIXTURE = Buffer.from(compressSync(FIXTURE)) 31 | const SNAPPY_COMPRESSED_FIXTURE = Buffer.from(snappy.compressSync(FIXTURE)) 32 | const GZIP_FIXTURE = gzipSync(FIXTURE) 33 | const DEFLATED_FIXTURE = deflateSync(FIXTURE) 34 | const BROTLI_COMPRESSED_FIXTURE = brotliCompressSync(FIXTURE) 35 | 36 | async function run() { 37 | await b.suite( 38 | 'Compress', 39 | 40 | b.add('lz4', () => { 41 | return compress(FIXTURE) 42 | }), 43 | 44 | b.add('lz4 dict', () => { 45 | return compress(FIXTURE, FIXTURE_DICT) 46 | }), 47 | 48 | b.add('snappy', () => { 49 | return snappy.compress(FIXTURE) 50 | }), 51 | 52 | b.add('gzip', () => { 53 | return gzipAsync(FIXTURE) 54 | }), 55 | 56 | b.add('deflate', () => { 57 | return deflateAsync(FIXTURE) 58 | }), 59 | 60 | b.add('brotli', () => { 61 | return brotliCompressAsync(FIXTURE) 62 | }), 63 | 64 | b.cycle(), 65 | b.complete(), 66 | ) 67 | 68 | await b.suite( 69 | 'Decompress', 70 | 71 | b.add('lz4', () => { 72 | return uncompress(LZ4_COMPRESSED_FIXTURE) 73 | }), 74 | 75 | b.add('lz4 dict', () => { 76 | return uncompress(LZ4_COMPRESSED_FIXTURE, FIXTURE_DICT) 77 | }), 78 | 79 | b.add('snappy', () => { 80 | return snappy.uncompress(SNAPPY_COMPRESSED_FIXTURE) 81 | }), 82 | 83 | b.add('gzip', () => { 84 | return gunzipAsync(GZIP_FIXTURE) 85 | }), 86 | 87 | b.add('deflate', () => { 88 | return inflateAsync(DEFLATED_FIXTURE) 89 | }), 90 | 91 | b.add('brotli', () => { 92 | return brotliDecompressAsync(BROTLI_COMPRESSED_FIXTURE) 93 | }), 94 | 95 | b.cycle(), 96 | b.complete(), 97 | ) 98 | } 99 | 100 | run().catch((e) => { 101 | console.error(e) 102 | }) 103 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate napi_build; 2 | 3 | fn main() { 4 | napi_build::setup(); 5 | } 6 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | /* auto-generated by NAPI-RS */ 2 | /* eslint-disable */ 3 | export declare function compress( 4 | data: string | Buffer, 5 | dict?: string | Buffer | undefined | null, 6 | ): Promise | Promise 7 | export declare function compressFrame(data: string | Buffer): Promise 8 | export declare function compressSync(data: string | Buffer, dict?: string | Buffer | undefined | null): Buffer 9 | export declare function decompressFrame(data: string | Buffer): Promise 10 | export declare function uncompress( 11 | data: string | Buffer, 12 | dict?: string | Buffer | undefined | null, 13 | ): Promise | Promise 14 | export declare function uncompressSync(data: string | Buffer, dict?: string | Buffer | undefined | null): Buffer 15 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // prettier-ignore 2 | /* eslint-disable */ 3 | /* auto-generated by NAPI-RS */ 4 | 5 | const { readFileSync } = require('fs') 6 | 7 | let nativeBinding = null 8 | const loadErrors = [] 9 | 10 | const isMusl = () => { 11 | let musl = false 12 | if (process.platform === 'linux') { 13 | musl = isMuslFromFilesystem() 14 | if (musl === null) { 15 | musl = isMuslFromReport() 16 | } 17 | if (musl === null) { 18 | musl = isMuslFromChildProcess() 19 | } 20 | } 21 | return musl 22 | } 23 | 24 | const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') 25 | 26 | const isMuslFromFilesystem = () => { 27 | try { 28 | return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') 29 | } catch { 30 | return null 31 | } 32 | } 33 | 34 | const isMuslFromReport = () => { 35 | const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null 36 | if (!report) { 37 | return null 38 | } 39 | if (report.header && report.header.glibcVersionRuntime) { 40 | return false 41 | } 42 | if (Array.isArray(report.sharedObjects)) { 43 | if (report.sharedObjects.some(isFileMusl)) { 44 | return true 45 | } 46 | } 47 | return false 48 | } 49 | 50 | const isMuslFromChildProcess = () => { 51 | try { 52 | return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') 53 | } catch (e) { 54 | // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false 55 | return false 56 | } 57 | } 58 | 59 | function requireNative() { 60 | if (process.platform === 'android') { 61 | if (process.arch === 'arm64') { 62 | try { 63 | return require('./lz4-napi.android-arm64.node') 64 | } catch (e) { 65 | loadErrors.push(e) 66 | } 67 | try { 68 | return require('@antoniomuso/lz4-napi-android-arm64') 69 | } catch (e) { 70 | loadErrors.push(e) 71 | } 72 | 73 | } else if (process.arch === 'arm') { 74 | try { 75 | return require('./lz4-napi.android-arm-eabi.node') 76 | } catch (e) { 77 | loadErrors.push(e) 78 | } 79 | try { 80 | return require('@antoniomuso/lz4-napi-android-arm-eabi') 81 | } catch (e) { 82 | loadErrors.push(e) 83 | } 84 | 85 | } else { 86 | loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)) 87 | } 88 | } else if (process.platform === 'win32') { 89 | if (process.arch === 'x64') { 90 | try { 91 | return require('./lz4-napi.win32-x64-msvc.node') 92 | } catch (e) { 93 | loadErrors.push(e) 94 | } 95 | try { 96 | return require('@antoniomuso/lz4-napi-win32-x64-msvc') 97 | } catch (e) { 98 | loadErrors.push(e) 99 | } 100 | 101 | } else if (process.arch === 'ia32') { 102 | try { 103 | return require('./lz4-napi.win32-ia32-msvc.node') 104 | } catch (e) { 105 | loadErrors.push(e) 106 | } 107 | try { 108 | return require('@antoniomuso/lz4-napi-win32-ia32-msvc') 109 | } catch (e) { 110 | loadErrors.push(e) 111 | } 112 | 113 | } else if (process.arch === 'arm64') { 114 | try { 115 | return require('./lz4-napi.win32-arm64-msvc.node') 116 | } catch (e) { 117 | loadErrors.push(e) 118 | } 119 | try { 120 | return require('@antoniomuso/lz4-napi-win32-arm64-msvc') 121 | } catch (e) { 122 | loadErrors.push(e) 123 | } 124 | 125 | } else { 126 | loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)) 127 | } 128 | } else if (process.platform === 'darwin') { 129 | try { 130 | return require('./lz4-napi.darwin-universal.node') 131 | } catch (e) { 132 | loadErrors.push(e) 133 | } 134 | try { 135 | return require('@antoniomuso/lz4-napi-darwin-universal') 136 | } catch (e) { 137 | loadErrors.push(e) 138 | } 139 | 140 | if (process.arch === 'x64') { 141 | try { 142 | return require('./lz4-napi.darwin-x64.node') 143 | } catch (e) { 144 | loadErrors.push(e) 145 | } 146 | try { 147 | return require('@antoniomuso/lz4-napi-darwin-x64') 148 | } catch (e) { 149 | loadErrors.push(e) 150 | } 151 | 152 | } else if (process.arch === 'arm64') { 153 | try { 154 | return require('./lz4-napi.darwin-arm64.node') 155 | } catch (e) { 156 | loadErrors.push(e) 157 | } 158 | try { 159 | return require('@antoniomuso/lz4-napi-darwin-arm64') 160 | } catch (e) { 161 | loadErrors.push(e) 162 | } 163 | 164 | } else { 165 | loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)) 166 | } 167 | } else if (process.platform === 'freebsd') { 168 | if (process.arch === 'x64') { 169 | try { 170 | return require('./lz4-napi.freebsd-x64.node') 171 | } catch (e) { 172 | loadErrors.push(e) 173 | } 174 | try { 175 | return require('@antoniomuso/lz4-napi-freebsd-x64') 176 | } catch (e) { 177 | loadErrors.push(e) 178 | } 179 | 180 | } else if (process.arch === 'arm64') { 181 | try { 182 | return require('./lz4-napi.freebsd-arm64.node') 183 | } catch (e) { 184 | loadErrors.push(e) 185 | } 186 | try { 187 | return require('@antoniomuso/lz4-napi-freebsd-arm64') 188 | } catch (e) { 189 | loadErrors.push(e) 190 | } 191 | 192 | } else { 193 | loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)) 194 | } 195 | } else if (process.platform === 'linux') { 196 | if (process.arch === 'x64') { 197 | if (isMusl()) { 198 | try { 199 | return require('./lz4-napi.linux-x64-musl.node') 200 | } catch (e) { 201 | loadErrors.push(e) 202 | } 203 | try { 204 | return require('@antoniomuso/lz4-napi-linux-x64-musl') 205 | } catch (e) { 206 | loadErrors.push(e) 207 | } 208 | 209 | } else { 210 | try { 211 | return require('./lz4-napi.linux-x64-gnu.node') 212 | } catch (e) { 213 | loadErrors.push(e) 214 | } 215 | try { 216 | return require('@antoniomuso/lz4-napi-linux-x64-gnu') 217 | } catch (e) { 218 | loadErrors.push(e) 219 | } 220 | 221 | } 222 | } else if (process.arch === 'arm64') { 223 | if (isMusl()) { 224 | try { 225 | return require('./lz4-napi.linux-arm64-musl.node') 226 | } catch (e) { 227 | loadErrors.push(e) 228 | } 229 | try { 230 | return require('@antoniomuso/lz4-napi-linux-arm64-musl') 231 | } catch (e) { 232 | loadErrors.push(e) 233 | } 234 | 235 | } else { 236 | try { 237 | return require('./lz4-napi.linux-arm64-gnu.node') 238 | } catch (e) { 239 | loadErrors.push(e) 240 | } 241 | try { 242 | return require('@antoniomuso/lz4-napi-linux-arm64-gnu') 243 | } catch (e) { 244 | loadErrors.push(e) 245 | } 246 | 247 | } 248 | } else if (process.arch === 'arm') { 249 | if (isMusl()) { 250 | try { 251 | return require('./lz4-napi.linux-arm-musleabihf.node') 252 | } catch (e) { 253 | loadErrors.push(e) 254 | } 255 | try { 256 | return require('@antoniomuso/lz4-napi-linux-arm-musleabihf') 257 | } catch (e) { 258 | loadErrors.push(e) 259 | } 260 | 261 | } else { 262 | try { 263 | return require('./lz4-napi.linux-arm-gnueabihf.node') 264 | } catch (e) { 265 | loadErrors.push(e) 266 | } 267 | try { 268 | return require('@antoniomuso/lz4-napi-linux-arm-gnueabihf') 269 | } catch (e) { 270 | loadErrors.push(e) 271 | } 272 | 273 | } 274 | } else if (process.arch === 'riscv64') { 275 | if (isMusl()) { 276 | try { 277 | return require('./lz4-napi.linux-riscv64-musl.node') 278 | } catch (e) { 279 | loadErrors.push(e) 280 | } 281 | try { 282 | return require('@antoniomuso/lz4-napi-linux-riscv64-musl') 283 | } catch (e) { 284 | loadErrors.push(e) 285 | } 286 | 287 | } else { 288 | try { 289 | return require('./lz4-napi.linux-riscv64-gnu.node') 290 | } catch (e) { 291 | loadErrors.push(e) 292 | } 293 | try { 294 | return require('@antoniomuso/lz4-napi-linux-riscv64-gnu') 295 | } catch (e) { 296 | loadErrors.push(e) 297 | } 298 | 299 | } 300 | } else if (process.arch === 'ppc64') { 301 | try { 302 | return require('./lz4-napi.linux-ppc64-gnu.node') 303 | } catch (e) { 304 | loadErrors.push(e) 305 | } 306 | try { 307 | return require('@antoniomuso/lz4-napi-linux-ppc64-gnu') 308 | } catch (e) { 309 | loadErrors.push(e) 310 | } 311 | 312 | } else if (process.arch === 's390x') { 313 | try { 314 | return require('./lz4-napi.linux-s390x-gnu.node') 315 | } catch (e) { 316 | loadErrors.push(e) 317 | } 318 | try { 319 | return require('@antoniomuso/lz4-napi-linux-s390x-gnu') 320 | } catch (e) { 321 | loadErrors.push(e) 322 | } 323 | 324 | } else { 325 | loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)) 326 | } 327 | } else { 328 | loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)) 329 | } 330 | } 331 | 332 | nativeBinding = requireNative() 333 | 334 | if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { 335 | try { 336 | nativeBinding = require('./lz4-napi.wasi.cjs') 337 | } catch (err) { 338 | if (process.env.NAPI_RS_FORCE_WASI) { 339 | loadErrors.push(err) 340 | } 341 | } 342 | if (!nativeBinding) { 343 | try { 344 | nativeBinding = require('@antoniomuso/lz4-napi-wasm32-wasi') 345 | } catch (err) { 346 | if (process.env.NAPI_RS_FORCE_WASI) { 347 | loadErrors.push(err) 348 | } 349 | } 350 | } 351 | } 352 | 353 | if (!nativeBinding) { 354 | if (loadErrors.length > 0) { 355 | // TODO Link to documentation with potential fixes 356 | // - The package owner could build/publish bindings for this arch 357 | // - The user may need to bundle the correct files 358 | // - The user may need to re-install node_modules to get new packages 359 | throw new Error('Failed to load native binding', { cause: loadErrors }) 360 | } 361 | throw new Error(`Failed to load native binding`) 362 | } 363 | 364 | module.exports.compress = nativeBinding.compress 365 | module.exports.compressFrame = nativeBinding.compressFrame 366 | module.exports.compressSync = nativeBinding.compressSync 367 | module.exports.decompressFrame = nativeBinding.decompressFrame 368 | module.exports.uncompress = nativeBinding.uncompress 369 | module.exports.uncompressSync = nativeBinding.uncompressSync 370 | -------------------------------------------------------------------------------- /npm/android-arm-eabi/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-android-arm-eabi` 2 | 3 | This is the **arm-linux-androideabi** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/android-arm-eabi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-android-arm-eabi", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm" 6 | ], 7 | "main": "lz4-napi.android-arm-eabi.node", 8 | "files": [ 9 | "lz4-napi.android-arm-eabi.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "android" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/android-arm64/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-android-arm64` 2 | 3 | This is the **aarch64-linux-android** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/android-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-android-arm64", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm64" 6 | ], 7 | "main": "lz4-napi.android-arm64.node", 8 | "files": [ 9 | "lz4-napi.android-arm64.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "android" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/darwin-arm64/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-darwin-arm64` 2 | 3 | This is the **aarch64-apple-darwin** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/darwin-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-darwin-arm64", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm64" 6 | ], 7 | "main": "lz4-napi.darwin-arm64.node", 8 | "files": [ 9 | "lz4-napi.darwin-arm64.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "darwin" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/darwin-x64/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-darwin-x64` 2 | 3 | This is the **x86_64-apple-darwin** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/darwin-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-darwin-x64", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "x64" 6 | ], 7 | "main": "lz4-napi.darwin-x64.node", 8 | "files": [ 9 | "lz4-napi.darwin-x64.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "darwin" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/freebsd-x64/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-freebsd-x64` 2 | 3 | This is the **x86_64-unknown-freebsd** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/freebsd-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-freebsd-x64", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "x64" 6 | ], 7 | "main": "lz4-napi.freebsd-x64.node", 8 | "files": [ 9 | "lz4-napi.freebsd-x64.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "freebsd" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/linux-arm-gnueabihf/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-linux-arm-gnueabihf` 2 | 3 | This is the **armv7-unknown-linux-gnueabihf** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/linux-arm-gnueabihf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-linux-arm-gnueabihf", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm" 6 | ], 7 | "main": "lz4-napi.linux-arm-gnueabihf.node", 8 | "files": [ 9 | "lz4-napi.linux-arm-gnueabihf.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "linux" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/linux-arm64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-linux-arm64-gnu` 2 | 3 | This is the **aarch64-unknown-linux-gnu** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/linux-arm64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-linux-arm64-gnu", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm64" 6 | ], 7 | "main": "lz4-napi.linux-arm64-gnu.node", 8 | "files": [ 9 | "lz4-napi.linux-arm64-gnu.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "linux" 36 | ], 37 | "libc": [ 38 | "glibc" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /npm/linux-arm64-musl/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-linux-arm64-musl` 2 | 3 | This is the **aarch64-unknown-linux-musl** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/linux-arm64-musl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-linux-arm64-musl", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm64" 6 | ], 7 | "main": "lz4-napi.linux-arm64-musl.node", 8 | "files": [ 9 | "lz4-napi.linux-arm64-musl.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "linux" 36 | ], 37 | "libc": [ 38 | "musl" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /npm/linux-x64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-linux-x64-gnu` 2 | 3 | This is the **x86_64-unknown-linux-gnu** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/linux-x64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-linux-x64-gnu", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "x64" 6 | ], 7 | "main": "lz4-napi.linux-x64-gnu.node", 8 | "files": [ 9 | "lz4-napi.linux-x64-gnu.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "linux" 36 | ], 37 | "libc": [ 38 | "glibc" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /npm/linux-x64-musl/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-linux-x64-musl` 2 | 3 | This is the **x86_64-unknown-linux-musl** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/linux-x64-musl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-linux-x64-musl", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "x64" 6 | ], 7 | "main": "lz4-napi.linux-x64-musl.node", 8 | "files": [ 9 | "lz4-napi.linux-x64-musl.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "engines": { 23 | "node": ">= 10" 24 | }, 25 | "publishConfig": { 26 | "registry": "https://registry.npmjs.org/", 27 | "access": "public" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/antoniomuso/lz4-napi.git" 32 | }, 33 | "os": [ 34 | "linux" 35 | ], 36 | "libc": [ 37 | "musl" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /npm/win32-arm64-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-win32-arm64-msvc` 2 | 3 | This is the **aarch64-pc-windows-msvc** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/win32-arm64-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-win32-arm64-msvc", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "arm64" 6 | ], 7 | "main": "lz4-napi.win32-arm64-msvc.node", 8 | "files": [ 9 | "lz4-napi.win32-arm64-msvc.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "access": "public" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/antoniomuso/lz4-napi.git" 32 | }, 33 | "os": [ 34 | "win32" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /npm/win32-ia32-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-win32-ia32-msvc` 2 | 3 | This is the **i686-pc-windows-msvc** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/win32-ia32-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-win32-ia32-msvc", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "ia32" 6 | ], 7 | "main": "lz4-napi.win32-ia32-msvc.node", 8 | "files": [ 9 | "lz4-napi.win32-ia32-msvc.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "win32" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /npm/win32-x64-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `lz4-napi-win32-x64-msvc` 2 | 3 | This is the **x86_64-pc-windows-msvc** binary for `lz4-napi` 4 | -------------------------------------------------------------------------------- /npm/win32-x64-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@antoniomuso/lz4-napi-win32-x64-msvc", 3 | "version":"2.8.0", 4 | "cpu": [ 5 | "x64" 6 | ], 7 | "main": "lz4-napi.win32-x64-msvc.node", 8 | "files": [ 9 | "lz4-napi.win32-x64-msvc.node" 10 | ], 11 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 12 | "keywords": [ 13 | "napi-rs", 14 | "NAPI", 15 | "N-API", 16 | "Rust", 17 | "node-addon", 18 | "node-addon-api", 19 | "lz4", 20 | "node" 21 | ], 22 | "license": "MIT", 23 | "engines": { 24 | "node": ">= 10" 25 | }, 26 | "publishConfig": { 27 | "registry": "https://registry.npmjs.org/", 28 | "access": "public" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/antoniomuso/lz4-napi.git" 33 | }, 34 | "os": [ 35 | "win32" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lz4-napi", 3 | "version": "2.8.0", 4 | "description": "Fastest lz4 compression library in Node.js, powered by napi-rs and lz4-flex.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/antoniomuso/lz4-napi.git" 9 | }, 10 | "license": "MIT", 11 | "keywords": [ 12 | "napi-rs", 13 | "NAPI", 14 | "N-API", 15 | "Rust", 16 | "node-addon", 17 | "node-addon-api", 18 | "lz4", 19 | "node" 20 | ], 21 | "files": [ 22 | "index.d.ts", 23 | "index.js" 24 | ], 25 | "napi": { 26 | "binaryName": "lz4-napi", 27 | "package": { 28 | "name": "@antoniomuso/lz4-napi" 29 | }, 30 | "targets": [ 31 | "x86_64-unknown-linux-gnu", 32 | "x86_64-apple-darwin", 33 | "x86_64-pc-windows-msvc", 34 | "x86_64-unknown-linux-musl", 35 | "aarch64-unknown-linux-gnu", 36 | "i686-pc-windows-msvc", 37 | "armv7-unknown-linux-gnueabihf", 38 | "aarch64-apple-darwin", 39 | "aarch64-linux-android", 40 | "arm-linux-androideabi", 41 | "x86_64-unknown-freebsd", 42 | "aarch64-unknown-linux-musl", 43 | "aarch64-pc-windows-msvc" 44 | ] 45 | }, 46 | "engines": { 47 | "node": ">= 10" 48 | }, 49 | "publishConfig": { 50 | "registry": "https://registry.npmjs.org/", 51 | "access": "public" 52 | }, 53 | "scripts": { 54 | "artifacts": "napi artifacts --output-dir artifacts --npm-dir ./npm", 55 | "bench": "node -r @swc-node/register benchmark/bench.ts", 56 | "build": "napi build --platform --release", 57 | "build:debug": "napi build --platform", 58 | "format": "run-p format:source format:rs format:toml", 59 | "format:toml": "taplo format", 60 | "format:rs": "cargo fmt", 61 | "format:source": "prettier --config ./package.json --write .", 62 | "lint": "eslint -c ./.eslintrc.yml .", 63 | "prepublishOnly": "napi prepublish -t npm && esbuild --minify --outfile=index.js --allow-overwrite index.js && yarn addNamespaces", 64 | "addNamespaces": "cat package.json | jq '.optionalDependencies |= with_entries(.key |= \"@antoniomuso/\" + .)' > package.json", 65 | "test": "ava", 66 | "test:mem": "node ./memory-leak-detect.mjs", 67 | "version": "napi version && conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md" 68 | }, 69 | "devDependencies": { 70 | "@napi-rs/cli": "^3.0.0-alpha.63", 71 | "@swc-node/register": "^1.6.8", 72 | "@swc/core": "^1.3.96", 73 | "@taplo/cli": "^0.7.0", 74 | "@types/node": "^20.8.10", 75 | "@typescript-eslint/eslint-plugin": "^7.0.0", 76 | "@typescript-eslint/parser": "^7.0.0", 77 | "ava": "^6.0.0", 78 | "benny": "^3.7.1", 79 | "chalk": "^5.3.0", 80 | "conventional-changelog-cli": "^4.1.0", 81 | "esbuild": "^0.24.0", 82 | "eslint": "^8.53.0", 83 | "eslint-config-prettier": "^9.0.0", 84 | "eslint-plugin-import": "^2.29.0", 85 | "husky": "^9.1.5", 86 | "lint-staged": "^15.2.9", 87 | "npm-run-all2": "^6.2.2", 88 | "prettier": "^3.3.3", 89 | "pretty-bytes": "^6.1.1", 90 | "snappy": "^7.2.2", 91 | "table": "^6.8.2", 92 | "typescript": "^5.5.4" 93 | }, 94 | "dependencies": { 95 | "@node-rs/helper": "^1.3.3" 96 | }, 97 | "lint-staged": { 98 | "*.@(js|ts|tsx)": [ 99 | "prettier --write", 100 | "eslint -c .eslintrc.yml --fix" 101 | ], 102 | "*.@(yml|yaml)": [ 103 | "prettier --parser yaml --write" 104 | ], 105 | "*.md": [ 106 | "prettier --parser markdown --write" 107 | ], 108 | "*.json": [ 109 | "prettier --parser json --write" 110 | ] 111 | }, 112 | "ava": { 113 | "require": [ 114 | "@swc-node/register" 115 | ], 116 | "extensions": [ 117 | "ts" 118 | ], 119 | "timeout": "2m", 120 | "workerThreads": false, 121 | "environmentVariables": { 122 | "TS_NODE_PROJECT": "./tsconfig.json" 123 | } 124 | }, 125 | "prettier": { 126 | "printWidth": 120, 127 | "semi": false, 128 | "trailingComma": "all", 129 | "singleQuote": true, 130 | "arrowParens": "always", 131 | "parser": "typescript" 132 | }, 133 | "packageManager": "yarn@4.5.0", 134 | "exports": { 135 | ".": { 136 | "import": "./index.js", 137 | "require": "./index.js" 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 2 | -------------------------------------------------------------------------------- /simple-test.js: -------------------------------------------------------------------------------- 1 | const { sync } = require('./index') 2 | 3 | console.assert(sync(0) === 100, 'Simple test failed') 4 | 5 | console.info('Simple test passed') 6 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(clippy::all)] 2 | 3 | #[macro_use] 4 | extern crate napi_derive; 5 | 6 | use std::io::{BufWriter, Read, Write}; 7 | 8 | use lz4_flex::block::{compress_prepend_size_with_dict, decompress_size_prepended_with_dict}; 9 | use lz4_flex::frame::{FrameDecoder, FrameEncoder}; 10 | use lz4_flex::{compress_prepend_size, decompress_size_prepended}; 11 | use napi::{ 12 | bindgen_prelude::{AsyncTask, Buffer}, 13 | Either, Env, Error, JsBuffer, JsBufferValue, Ref, Result, Status, Task, 14 | }; 15 | 16 | #[cfg(all( 17 | target_arch = "x86_64", 18 | not(target_env = "musl"), 19 | not(debug_assertions) 20 | ))] 21 | #[global_allocator] 22 | static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; 23 | 24 | pub enum Data { 25 | Buffer(Ref), 26 | String(String), 27 | } 28 | 29 | impl TryFrom> for Data { 30 | type Error = Error; 31 | 32 | fn try_from(value: Either) -> Result { 33 | match value { 34 | Either::A(s) => Ok(Data::String(s)), 35 | Either::B(b) => Ok(Data::Buffer(b.into_ref()?)), 36 | } 37 | } 38 | } 39 | 40 | struct Enc { 41 | data: Data, 42 | } 43 | 44 | #[napi] 45 | impl Task for Enc { 46 | type Output = Vec; 47 | type JsValue = JsBuffer; 48 | 49 | fn compute(&mut self) -> Result { 50 | let data: &[u8] = match self.data { 51 | Data::Buffer(ref b) => b.as_ref(), 52 | Data::String(ref s) => s.as_bytes(), 53 | }; 54 | Ok(compress_prepend_size(data)) 55 | } 56 | 57 | fn resolve(&mut self, env: Env, output: Self::Output) -> Result { 58 | env.create_buffer_with_data(output).map(|b| b.into_raw()) 59 | } 60 | 61 | fn finally(&mut self, env: Env) -> Result<()> { 62 | if let Data::Buffer(b) = &mut self.data { 63 | b.unref(env)?; 64 | } 65 | Ok(()) 66 | } 67 | } 68 | 69 | struct Dec { 70 | data: Data, 71 | } 72 | 73 | #[napi] 74 | impl Task for Dec { 75 | type Output = Vec; 76 | type JsValue = JsBuffer; 77 | 78 | fn compute(&mut self) -> Result { 79 | let data: &[u8] = match self.data { 80 | Data::Buffer(ref b) => b.as_ref(), 81 | Data::String(ref s) => s.as_bytes(), 82 | }; 83 | decompress_size_prepended(data).map_err(|e| Error::new(Status::GenericFailure, format!("{e}"))) 84 | } 85 | 86 | fn resolve(&mut self, env: Env, output: Self::Output) -> Result { 87 | env.create_buffer_with_data(output).map(|b| b.into_raw()) 88 | } 89 | 90 | fn finally(&mut self, env: Env) -> Result<()> { 91 | if let Data::Buffer(b) = &mut self.data { 92 | b.unref(env)?; 93 | } 94 | Ok(()) 95 | } 96 | } 97 | 98 | struct EncDict { 99 | data: Data, 100 | dict: Data, 101 | } 102 | 103 | #[napi] 104 | impl Task for EncDict { 105 | type Output = Vec; 106 | type JsValue = JsBuffer; 107 | 108 | fn compute(&mut self) -> Result { 109 | let data: &[u8] = match self.data { 110 | Data::Buffer(ref b) => b.as_ref(), 111 | Data::String(ref s) => s.as_bytes(), 112 | }; 113 | 114 | let dict: &[u8] = match self.dict { 115 | Data::Buffer(ref b) => b.as_ref(), 116 | Data::String(ref s) => s.as_bytes(), 117 | }; 118 | 119 | Ok(compress_prepend_size_with_dict(data, dict)) 120 | } 121 | 122 | fn resolve(&mut self, env: Env, output: Self::Output) -> Result { 123 | env.create_buffer_with_data(output).map(|b| b.into_raw()) 124 | } 125 | 126 | fn finally(&mut self, env: Env) -> Result<()> { 127 | if let Data::Buffer(b) = &mut self.data { 128 | b.unref(env)?; 129 | } 130 | Ok(()) 131 | } 132 | } 133 | 134 | struct DecDict { 135 | data: Data, 136 | dict: Data, 137 | } 138 | 139 | #[napi] 140 | impl Task for DecDict { 141 | type Output = Vec; 142 | type JsValue = JsBuffer; 143 | 144 | fn compute(&mut self) -> Result { 145 | let data: &[u8] = match self.data { 146 | Data::Buffer(ref b) => b.as_ref(), 147 | Data::String(ref s) => s.as_bytes(), 148 | }; 149 | 150 | let dict: &[u8] = match self.dict { 151 | Data::Buffer(ref b) => b.as_ref(), 152 | Data::String(ref s) => s.as_bytes(), 153 | }; 154 | 155 | decompress_size_prepended_with_dict(data, dict) 156 | .map_err(|e| Error::new(Status::GenericFailure, format!("{e}"))) 157 | } 158 | 159 | fn resolve(&mut self, env: Env, output: Self::Output) -> Result { 160 | env.create_buffer_with_data(output).map(|b| b.into_raw()) 161 | } 162 | 163 | fn finally(&mut self, env: Env) -> Result<()> { 164 | if let Data::Buffer(b) = &mut self.data { 165 | b.unref(env)?; 166 | } 167 | Ok(()) 168 | } 169 | } 170 | 171 | struct FrameDec { 172 | data: Data, 173 | } 174 | 175 | #[napi] 176 | impl Task for FrameDec { 177 | type Output = Vec; 178 | type JsValue = JsBuffer; 179 | 180 | fn compute(&mut self) -> Result { 181 | let data: &[u8] = match self.data { 182 | Data::Buffer(ref b) => b.as_ref(), 183 | Data::String(ref s) => s.as_bytes(), 184 | }; 185 | 186 | let mut buf = vec![]; 187 | 188 | let mut decoder = FrameDecoder::new(data); 189 | decoder.read_to_end(&mut buf)?; 190 | 191 | Ok(buf) 192 | } 193 | 194 | fn resolve(&mut self, env: Env, output: Self::Output) -> Result { 195 | env.create_buffer_with_data(output).map(|b| b.into_raw()) 196 | } 197 | 198 | fn finally(&mut self, env: Env) -> Result<()> { 199 | if let Data::Buffer(b) = &mut self.data { 200 | b.unref(env)?; 201 | } 202 | Ok(()) 203 | } 204 | } 205 | 206 | struct FrameEnc { 207 | data: Data, 208 | } 209 | 210 | #[napi] 211 | impl Task for FrameEnc { 212 | type Output = Vec; 213 | type JsValue = JsBuffer; 214 | 215 | fn compute(&mut self) -> Result { 216 | let data: &[u8] = match self.data { 217 | Data::Buffer(ref b) => b.as_ref(), 218 | Data::String(ref s) => s.as_bytes(), 219 | }; 220 | 221 | let mut buffer = vec![]; 222 | 223 | let buf = BufWriter::new(&mut buffer); 224 | 225 | let mut encoder = FrameEncoder::new(buf); 226 | 227 | encoder.write_all(data)?; 228 | 229 | encoder 230 | .finish() 231 | .map_err(|e| Error::new(napi::Status::Unknown, e.to_string()))?; 232 | 233 | Ok(buffer) 234 | } 235 | 236 | fn resolve(&mut self, env: Env, output: Self::Output) -> Result { 237 | env.create_buffer_with_data(output).map(|b| b.into_raw()) 238 | } 239 | 240 | fn finally(&mut self, env: Env) -> Result<()> { 241 | if let Data::Buffer(b) = &mut self.data { 242 | b.unref(env)?; 243 | } 244 | Ok(()) 245 | } 246 | } 247 | 248 | #[napi] 249 | fn compress( 250 | data: Either, 251 | dict: Option>, 252 | ) -> Result, AsyncTask>> { 253 | if let Option::Some(v) = dict { 254 | let encoder = EncDict { 255 | data: data.try_into()?, 256 | dict: v.try_into()?, 257 | }; 258 | return Ok(Either::B(AsyncTask::new(encoder))); 259 | } 260 | let encoder = Enc { 261 | data: data.try_into()?, 262 | }; 263 | Ok(Either::A(AsyncTask::new(encoder))) 264 | } 265 | 266 | #[napi] 267 | fn uncompress( 268 | data: Either, 269 | dict: Option>, 270 | ) -> Result, AsyncTask>> { 271 | if let Option::Some(v) = dict { 272 | let decoder = DecDict { 273 | data: data.try_into()?, 274 | dict: v.try_into()?, 275 | }; 276 | return Ok(Either::B(AsyncTask::new(decoder))); 277 | } 278 | let decoder = Dec { 279 | data: data.try_into()?, 280 | }; 281 | Ok(Either::A(AsyncTask::new(decoder))) 282 | } 283 | 284 | #[napi] 285 | fn uncompress_sync( 286 | data: Either, 287 | dict: Option>, 288 | ) -> Result { 289 | if let Option::Some(v) = dict { 290 | return decompress_size_prepended_with_dict( 291 | match data { 292 | Either::A(ref s) => s.as_bytes(), 293 | Either::B(ref b) => b.as_ref(), 294 | }, 295 | match v { 296 | Either::A(ref s) => s.as_bytes(), 297 | Either::B(ref b) => b.as_ref(), 298 | }, 299 | ) 300 | .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}"))) 301 | .map(|d| d.into()); 302 | } 303 | decompress_size_prepended(match data { 304 | Either::A(ref s) => s.as_bytes(), 305 | Either::B(ref b) => b.as_ref(), 306 | }) 307 | .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}"))) 308 | .map(|d| d.into()) 309 | } 310 | 311 | #[napi] 312 | fn compress_sync( 313 | data: Either, 314 | dict: Option>, 315 | ) -> Result { 316 | if let Option::Some(v) = dict { 317 | return Ok( 318 | compress_prepend_size_with_dict( 319 | match data { 320 | Either::A(ref b) => b.as_bytes(), 321 | Either::B(ref s) => s.as_ref(), 322 | }, 323 | match v { 324 | Either::A(ref b) => b.as_bytes(), 325 | Either::B(ref s) => s.as_ref(), 326 | }, 327 | ) 328 | .into(), 329 | ); 330 | } 331 | Ok( 332 | compress_prepend_size(match data { 333 | Either::A(ref b) => b.as_bytes(), 334 | Either::B(ref s) => s.as_ref(), 335 | }) 336 | .into(), 337 | ) 338 | } 339 | 340 | #[napi] 341 | fn compress_frame(data: Either) -> Result> { 342 | let encoder = FrameEnc { 343 | data: data.try_into()?, 344 | }; 345 | Ok(AsyncTask::new(encoder)) 346 | } 347 | 348 | #[napi] 349 | fn decompress_frame(data: Either) -> Result> { 350 | let decoder = FrameDec { 351 | data: data.try_into()?, 352 | }; 353 | Ok(AsyncTask::new(decoder)) 354 | } 355 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "strict": true, 5 | "moduleResolution": "node", 6 | "module": "CommonJS", 7 | "noUnusedLocals": true, 8 | "noUnusedParameters": true, 9 | "esModuleInterop": true, 10 | "allowJs": true, 11 | "outDir": "dist", 12 | "allowSyntheticDefaultImports": true 13 | }, 14 | "include": ["./**/*.js", "./**/*.mjs", "./**/*.ts", "./**/*.tsx"], 15 | "files": ["index.js"], 16 | "exclude": ["node_modules"] 17 | } 18 | -------------------------------------------------------------------------------- /util.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const prettyBytes = require('pretty-bytes') 3 | const { table } = require('table') 4 | 5 | module.exports.displayMemoryUsageFromNode = function displayMemoryUsageFromNode(initialMemoryUsage) { 6 | const finalMemoryUsage = process.memoryUsage() 7 | const titles = Object.keys(initialMemoryUsage).map((k) => chalk.whiteBright(k)) 8 | const tableData = [titles] 9 | const diffColumn = [] 10 | for (const [key, value] of Object.entries(initialMemoryUsage)) { 11 | const diff = finalMemoryUsage[key] - value 12 | const prettyDiff = prettyBytes(diff, { signed: true }) 13 | if (diff > 0) { 14 | diffColumn.push(chalk.red(prettyDiff)) 15 | } else if (diff < 0) { 16 | diffColumn.push(chalk.green(prettyDiff)) 17 | } else { 18 | diffColumn.push(chalk.grey(prettyDiff)) 19 | } 20 | } 21 | tableData.push(diffColumn) 22 | console.info(table(tableData)) 23 | } 24 | --------------------------------------------------------------------------------