From 0effb1bdb5c72b8060672c7a49fe542693e0383d Mon Sep 17 00:00:00 2001 From: LongYinan Date: Wed, 7 Feb 2024 22:37:04 +0800 Subject: [PATCH] feat: add wasm build --- .cargo/config.toml | 2 + .github/workflows/CI.yml | 53 +- .gitignore | 1 + package.json | 2 +- packages/binding/Cargo.toml | 13 +- packages/binding/__test__/optimize.spec.mjs | 6 +- .../binding/__test__/transformer.spec.mjs | 22 +- packages/binding/browser.js | 1 + packages/binding/image.wasi-browser.js | 105 +++ packages/binding/image.wasi.cjs | 121 ++++ packages/binding/index.d.ts | 426 ++++++------ packages/binding/index.js | 107 +++- .../binding/npm/android-arm64/package.json | 11 +- .../binding/npm/darwin-arm64/package.json | 11 +- packages/binding/npm/darwin-x64/package.json | 11 +- packages/binding/npm/freebsd-x64/package.json | 11 +- .../npm/linux-arm-gnueabihf/package.json | 11 +- .../binding/npm/linux-arm64-gnu/package.json | 23 +- .../binding/npm/linux-arm64-musl/package.json | 23 +- .../binding/npm/linux-x64-gnu/package.json | 23 +- .../binding/npm/linux-x64-musl/package.json | 23 +- packages/binding/npm/wasm32-wasi/README.md | 3 + packages/binding/npm/wasm32-wasi/package.json | 43 ++ .../binding/npm/win32-ia32-msvc/package.json | 11 +- .../binding/npm/win32-x64-msvc/package.json | 11 +- packages/binding/package.json | 32 +- packages/binding/src/jpeg.rs | 4 +- packages/binding/wasi-worker-browser.mjs | 40 ++ packages/binding/wasi-worker.mjs | 50 ++ yarn.lock | 604 +++++++++++++++++- 30 files changed, 1442 insertions(+), 362 deletions(-) create mode 100644 packages/binding/browser.js create mode 100644 packages/binding/image.wasi-browser.js create mode 100644 packages/binding/image.wasi.cjs create mode 100644 packages/binding/npm/wasm32-wasi/README.md create mode 100644 packages/binding/npm/wasm32-wasi/package.json create mode 100644 packages/binding/wasi-worker-browser.mjs create mode 100644 packages/binding/wasi-worker.mjs diff --git a/.cargo/config.toml b/.cargo/config.toml index 3ce73f2..9b140bc 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,3 +9,5 @@ rustflags = ["-C", "target-feature=+crc"] [target.aarch64-unknown-linux-musl] linker = "aarch64-linux-musl-gcc" rustflags = ["-C", "target-feature=-crt-static"] +[target.wasm32-wasi-preview1-threads] +rustflags = ["-C", "target-feature=+simd128"] diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 5ad9c95..762d5f7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -110,9 +110,9 @@ jobs: target: armv7-unknown-linux-gnueabihf setup: | sudo apt-get update - sudo apt-get install meson gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y + sudo apt-get install meson build: | - yarn workspace @napi-rs/image build --target armv7-unknown-linux-gnueabihf --features oxipng_libdeflater --zig --zig-link-only + yarn workspace @napi-rs/image build --target armv7-unknown-linux-gnueabihf --features oxipng_libdeflater --use-napi-cross - host: ubuntu-latest target: aarch64-linux-android build: | @@ -121,7 +121,6 @@ jobs: yarn workspace @napi-rs/image build --target aarch64-linux-android --features with_simd - host: ubuntu-latest target: aarch64-unknown-linux-musl - downloadTarget: aarch64-unknown-linux-musl docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine build: >- set -e && @@ -131,6 +130,23 @@ jobs: apk add --update --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing --no-cache aom-dev perl meson && yarn workspace @napi-rs/image build --target aarch64-unknown-linux-musl --features with_simd && chmod -R 777 target + - host: macos-14 + target: wasm32-wasi-preview1-threads + setup: | + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/wasi-sdk-21.0-macos.tar.gz + tar -xvf wasi-sdk-21.0-macos.tar.gz + build: | + export WASI_SDK_PATH="$(pwd)/wasi-sdk-21.0" + export CC="${WASI_SDK_PATH}/bin/clang" + export CXX="${WASI_SDK_PATH}/bin/clang++" + export AR="${WASI_SDK_PATH}/bin/ar" + export CFLAGS="--target=wasm32-wasi-threads -pthread --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot" + export CXXFLAGS="--target=wasm32-wasi-threads -pthread --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot" + export LDFLAGS="-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-wasi-threads" + export CARGO_TARGET_WASM32_WASI_PREVIEW1_THREADS_LINKER="${WASI_SDK_PATH}/bin/wasm-ld" + export PATH="$WASI_SDK_PATH/bin:$PATH" + yarn workspace @napi-rs/image build --target wasm32-wasi-preview1-threads + name: stable - ${{ matrix.settings.target }} - node@20 runs-on: ${{ matrix.settings.host }} env: @@ -159,6 +175,7 @@ jobs: ~/.cargo/git/db/ .cargo-cache .xwin + ~/.napi-rs target/ key: ${{ matrix.settings.target }}-cargo-cache - uses: goto-bus-stop/setup-zig@v2 @@ -186,7 +203,9 @@ jobs: uses: actions/upload-artifact@v4 with: name: bindings-${{ matrix.settings.target }} - path: packages/*/*.node + path: | + packages/*/*.node + packages/*/*.wasm if-no-files-found: error build-freebsd: runs-on: macos-12 @@ -438,6 +457,31 @@ jobs: set -e yarn test ls -la + test-wasi-on-nodejs: + name: Test wasi on Node.js + runs-on: macos-14 + needs: + - build + steps: + - uses: actions/checkout@v4 + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: bindings-wasm32-wasi-preview1-threads + path: artifacts + - name: Install dependencies + run: yarn install --immutable --mode=skip-build + - name: Move artifacts + run: yarn artifacts + shell: bash + - name: List packages + run: ls -R packages + shell: bash + - name: Run tests + run: yarn test packages/binding/__test__/transformer.spec.mjs -s + env: + NAPI_RS_FORCE_WASI: '1' + publish: name: Publish runs-on: ubuntu-latest @@ -448,6 +492,7 @@ jobs: - test-linux-x64-musl-binding - test-linux-aarch64-gnu-binding - test-linux-arm-gnueabihf-binding + - test-wasi-on-nodejs steps: - uses: actions/checkout@v4 - name: Setup node diff --git a/.gitignore b/.gitignore index 07acd64..f149fdc 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ output-exif.* nasa-small.* output-overlay-png.png output-debian.jpeg +*.wasm diff --git a/package.json b/package.json index 7c0c66d..b028e31 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "website" ], "devDependencies": { - "@napi-rs/cli": "^2.18.0", + "@napi-rs/cli": "^3.0.0-alpha.36", "@taplo/cli": "^0.7.0", "@types/node": "^20.11.16", "@types/sharp": "^0.31.1", diff --git a/packages/binding/Cargo.toml b/packages/binding/Cargo.toml index 0229f66..8f2e9a1 100644 --- a/packages/binding/Cargo.toml +++ b/packages/binding/Cargo.toml @@ -35,9 +35,6 @@ image = { version = "0.24", default-features = false, features = [ "openexr", ] } jpeg-decoder = "0.3" -libavif = { version = "0.12", default-features = false, features = [ - "codec-aom", -] } libc = "0.2" lodepng = "3" napi = { version = "2", default-features = false, features = ["napi3"] } @@ -67,5 +64,15 @@ libwebp-sys = { version = "0.9", default-features = false, features = ["std", "p [target.'cfg(all(target_os = "macos", target_arch = "x86_64"))'.dependencies] libwebp-sys = { version = "0.9", default-features = false, features = ["std", "parallel"] } +[target.'cfg(target_family = "wasm")'.dependencies] +libavif = { git="https://github.com/Brooooooklyn/libavif-rs.git", rev = "4e108c4", version = "0.12", default-features = false, features = [ + "codec-rav1e", +] } + +[target.'cfg(not(target_family = "wasm"))'.dependencies] +libavif = { git="https://github.com/Brooooooklyn/libavif-rs.git", rev = "4e108c4", version = "0.12", default-features = false, features = [ + "codec-aom", +] } + [build-dependencies] napi-build = "2" diff --git a/packages/binding/__test__/optimize.spec.mjs b/packages/binding/__test__/optimize.spec.mjs index c90d4ab..f56bfdc 100644 --- a/packages/binding/__test__/optimize.spec.mjs +++ b/packages/binding/__test__/optimize.spec.mjs @@ -1,6 +1,6 @@ -import { promises as fs } from 'fs' -import { join } from 'path' -import { fileURLToPath } from 'url' +import { promises as fs } from 'node:fs' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' import test from 'ava' diff --git a/packages/binding/__test__/transformer.spec.mjs b/packages/binding/__test__/transformer.spec.mjs index 41832bd..27a8c22 100644 --- a/packages/binding/__test__/transformer.spec.mjs +++ b/packages/binding/__test__/transformer.spec.mjs @@ -1,6 +1,6 @@ -import { promises as fs } from 'fs' -import { join } from 'path' -import { fileURLToPath } from 'url' +import { promises as fs } from 'node:fs' +import { join } from 'node:path' +import { fileURLToPath } from 'node:url' import test from 'ava' import { decode } from 'blurhash' @@ -38,11 +38,19 @@ test('should be able to get exif from jpg', async (t) => { }) test('should be able to encode into webp', async (t) => { + if (process.env.NAPI_RS_FORCE_WASI) { + t.pass() + return + } const decoder = new Transformer(PNG) await t.notThrowsAsync(() => decoder.webp(75)) }) test('should be able to decode from avif', async (t) => { + if (process.env.NAPI_RS_FORCE_WASI) { + t.pass() + return + } const decoder = new Transformer(PNG) const AVIF = await decoder.avif() const avifDecoder = new Transformer(AVIF) @@ -50,6 +58,10 @@ test('should be able to decode from avif', async (t) => { }) test('should be able to decode from webp', async (t) => { + if (process.env.NAPI_RS_FORCE_WASI) { + t.pass() + return + } const decoder = new Transformer(PNG) const WEBP = await decoder.webpLossless() const webpDecoder = new Transformer(WEBP) @@ -57,6 +69,10 @@ test('should be able to decode from webp', async (t) => { }) test('should be able to create transformer from raw rgba pixels', async (t) => { + if (process.env.NAPI_RS_FORCE_WASI) { + t.pass() + return + } const pixels = decode('LEHV6nWB2yk8pyo0adR*.7kCMdnj', 32, 32) await t.notThrowsAsync(() => Transformer.fromRgbaPixels(pixels, 32, 32).webpLossless()) }) diff --git a/packages/binding/browser.js b/packages/binding/browser.js new file mode 100644 index 0000000..1c082b1 --- /dev/null +++ b/packages/binding/browser.js @@ -0,0 +1 @@ +export * from '@napi-rs/image-wasm32-wasi' diff --git a/packages/binding/image.wasi-browser.js b/packages/binding/image.wasi-browser.js new file mode 100644 index 0000000..0fb9b98 --- /dev/null +++ b/packages/binding/image.wasi-browser.js @@ -0,0 +1,105 @@ +import { + instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync, + getDefaultContext as __emnapiGetDefaultContext, + WASI as __WASI, +} from '@napi-rs/wasm-runtime' +import { Volume as __Volume, createFsFromVolume as __createFsFromVolume } from '@napi-rs/wasm-runtime/fs' + +import __wasmUrl from './image.wasm32-wasi.wasm?url' + +const __fs = __createFsFromVolume( + __Volume.fromJSON({ + '/': null, + }), +) + +const __wasi = new __WASI({ + version: 'preview1', + fs: __fs, +}) + +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 1024, + maximum: 10240, + shared: true, +}) + +const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) + +const { + instance: __napiInstance, + module: __wasiModule, + napiModule: __napiModule, +} = __emnapiInstantiateNapiModuleSync(__wasmFile, { + context: __emnapiContext, + asyncWorkPoolSize: 4, + wasi: __wasi, + onCreateWorker() { + return new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { + type: 'module', + }) + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + __napi_rs_initialize_modules(instance) + }, +}) + +function __napi_rs_initialize_modules(__napiInstance) { + __napiInstance.exports['__napi_register__AvifConfig_struct_0']?.() + __napiInstance.exports['__napi_register__ChromaSubsampling_1']?.() + __napiInstance.exports['__napi_register__FastResizeFilter_2']?.() + __napiInstance.exports['__napi_register__ResizeFit_3']?.() + __napiInstance.exports['__napi_register__FastResizeOptions_struct_4']?.() + __napiInstance.exports['__napi_register__JpegCompressOptions_struct_5']?.() + __napiInstance.exports['__napi_register__compress_jpeg_sync_6']?.() + __napiInstance.exports['__napi_register__CompressJpegTask_impl_7']?.() + __napiInstance.exports['__napi_register__compress_jpeg_8']?.() + __napiInstance.exports['__napi_register__CompressionType_9']?.() + __napiInstance.exports['__napi_register__FilterType_10']?.() + __napiInstance.exports['__napi_register__PngEncodeOptions_struct_11']?.() + __napiInstance.exports['__napi_register__PngRowFilter_12']?.() + __napiInstance.exports['__napi_register__PNGLosslessOptions_struct_13']?.() + __napiInstance.exports['__napi_register__lossless_compress_png_sync_14']?.() + __napiInstance.exports['__napi_register__LosslessPngTask_impl_15']?.() + __napiInstance.exports['__napi_register__lossless_compress_png_16']?.() + __napiInstance.exports['__napi_register__PngQuantOptions_struct_17']?.() + __napiInstance.exports['__napi_register__png_quantize_sync_18']?.() + __napiInstance.exports['__napi_register__PngQuantTask_impl_19']?.() + __napiInstance.exports['__napi_register__png_quantize_20']?.() + __napiInstance.exports['__napi_register__Orientation_21']?.() + __napiInstance.exports['__napi_register__ResizeFilterType_22']?.() + __napiInstance.exports['__napi_register__JsColorType_23']?.() + __napiInstance.exports['__napi_register__Metadata_struct_24']?.() + __napiInstance.exports['__napi_register__MetadataTask_impl_25']?.() + __napiInstance.exports['__napi_register__ResizeOptions_struct_26']?.() + __napiInstance.exports['__napi_register__EncodeTask_impl_27']?.() + __napiInstance.exports['__napi_register__Transformer_struct_28']?.() + __napiInstance.exports['__napi_register__Transformer_impl_70']?.() +} +export const Transformer = __napiModule.exports.Transformer +export const ChromaSubsampling = __napiModule.exports.ChromaSubsampling +export const CompressionType = __napiModule.exports.CompressionType +export const compressJpeg = __napiModule.exports.compressJpeg +export const compressJpegSync = __napiModule.exports.compressJpegSync +export const FastResizeFilter = __napiModule.exports.FastResizeFilter +export const FilterType = __napiModule.exports.FilterType +export const JsColorType = __napiModule.exports.JsColorType +export const losslessCompressPng = __napiModule.exports.losslessCompressPng +export const losslessCompressPngSync = __napiModule.exports.losslessCompressPngSync +export const Orientation = __napiModule.exports.Orientation +export const pngQuantize = __napiModule.exports.pngQuantize +export const pngQuantizeSync = __napiModule.exports.pngQuantizeSync +export const PngRowFilter = __napiModule.exports.PngRowFilter +export const ResizeFilterType = __napiModule.exports.ResizeFilterType +export const ResizeFit = __napiModule.exports.ResizeFit diff --git a/packages/binding/image.wasi.cjs b/packages/binding/image.wasi.cjs new file mode 100644 index 0000000..165d5dd --- /dev/null +++ b/packages/binding/image.wasi.cjs @@ -0,0 +1,121 @@ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const __nodeFs= require('node:fs') +const __nodePath = require('node:path') +const { WASI: __nodeWASI } = require('node:wasi') +const { Worker } = require('node:worker_threads') + +const { + instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, + getDefaultContext: __emnapiGetDefaultContext, +} = require('@napi-rs/wasm-runtime') + +const __wasi = new __nodeWASI({ + version: 'preview1', + env: process.env, + preopens: { + '/': '/' + } +}) + +const __emnapiContext = __emnapiGetDefaultContext() + +const __sharedMemory = new WebAssembly.Memory({ + initial: 1024, + maximum: 10240, + shared: true, +}) + +let __wasmFilePath = __nodePath.join(__dirname, 'image.wasm32-wasi.wasm') + +if (!__nodeFs.existsSync(__wasmFilePath)) { + try { + __wasmFilePath = __nodePath.resolve('@napi-rs/image-wasm32-wasi') + } catch { + throw new Error('Cannot find image.wasm32-wasi.wasm file, and @napi-rs/image-wasm32-wasi package is not installed.') + } +} + +const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { + context: __emnapiContext, + asyncWorkPoolSize: (function() { + const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) + // NaN > 0 is false + if (threadsSizeFromEnv > 0) { + return threadsSizeFromEnv + } else { + return 4 + } + })(), + wasi: __wasi, + onCreateWorker() { + return new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { + env: process.env, + execArgv: ['--experimental-wasi-unstable-preview1'], + }) + }, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: __sharedMemory, + } + return importObject + }, + beforeInit({ instance }) { + __napi_rs_initialize_modules(instance) + } +}) + +function __napi_rs_initialize_modules(__napiInstance) { + __napiInstance.exports['__napi_register__AvifConfig_struct_0']?.() + __napiInstance.exports['__napi_register__ChromaSubsampling_1']?.() + __napiInstance.exports['__napi_register__FastResizeFilter_2']?.() + __napiInstance.exports['__napi_register__ResizeFit_3']?.() + __napiInstance.exports['__napi_register__FastResizeOptions_struct_4']?.() + __napiInstance.exports['__napi_register__JpegCompressOptions_struct_5']?.() + __napiInstance.exports['__napi_register__compress_jpeg_sync_6']?.() + __napiInstance.exports['__napi_register__CompressJpegTask_impl_7']?.() + __napiInstance.exports['__napi_register__compress_jpeg_8']?.() + __napiInstance.exports['__napi_register__CompressionType_9']?.() + __napiInstance.exports['__napi_register__FilterType_10']?.() + __napiInstance.exports['__napi_register__PngEncodeOptions_struct_11']?.() + __napiInstance.exports['__napi_register__PngRowFilter_12']?.() + __napiInstance.exports['__napi_register__PNGLosslessOptions_struct_13']?.() + __napiInstance.exports['__napi_register__lossless_compress_png_sync_14']?.() + __napiInstance.exports['__napi_register__LosslessPngTask_impl_15']?.() + __napiInstance.exports['__napi_register__lossless_compress_png_16']?.() + __napiInstance.exports['__napi_register__PngQuantOptions_struct_17']?.() + __napiInstance.exports['__napi_register__png_quantize_sync_18']?.() + __napiInstance.exports['__napi_register__PngQuantTask_impl_19']?.() + __napiInstance.exports['__napi_register__png_quantize_20']?.() + __napiInstance.exports['__napi_register__Orientation_21']?.() + __napiInstance.exports['__napi_register__ResizeFilterType_22']?.() + __napiInstance.exports['__napi_register__JsColorType_23']?.() + __napiInstance.exports['__napi_register__Metadata_struct_24']?.() + __napiInstance.exports['__napi_register__MetadataTask_impl_25']?.() + __napiInstance.exports['__napi_register__ResizeOptions_struct_26']?.() + __napiInstance.exports['__napi_register__EncodeTask_impl_27']?.() + __napiInstance.exports['__napi_register__Transformer_struct_28']?.() + __napiInstance.exports['__napi_register__Transformer_impl_70']?.() +} +module.exports.Transformer = __napiModule.exports.Transformer +module.exports.ChromaSubsampling = __napiModule.exports.ChromaSubsampling +module.exports.CompressionType = __napiModule.exports.CompressionType +module.exports.compressJpeg = __napiModule.exports.compressJpeg +module.exports.compressJpegSync = __napiModule.exports.compressJpegSync +module.exports.FastResizeFilter = __napiModule.exports.FastResizeFilter +module.exports.FilterType = __napiModule.exports.FilterType +module.exports.JsColorType = __napiModule.exports.JsColorType +module.exports.losslessCompressPng = __napiModule.exports.losslessCompressPng +module.exports.losslessCompressPngSync = __napiModule.exports.losslessCompressPngSync +module.exports.Orientation = __napiModule.exports.Orientation +module.exports.pngQuantize = __napiModule.exports.pngQuantize +module.exports.pngQuantizeSync = __napiModule.exports.pngQuantizeSync +module.exports.PngRowFilter = __napiModule.exports.PngRowFilter +module.exports.ResizeFilterType = __napiModule.exports.ResizeFilterType +module.exports.ResizeFit = __napiModule.exports.ResizeFit diff --git a/packages/binding/index.d.ts b/packages/binding/index.d.ts index 074cd4d..d2365b9 100644 --- a/packages/binding/index.d.ts +++ b/packages/binding/index.d.ts @@ -1,7 +1,118 @@ -/* tslint:disable */ +/* auto-generated by NAPI-RS */ /* eslint-disable */ -/* auto-generated by NAPI-RS */ +export class Transformer { + constructor(input: Buffer) + /** Support CSS3 color, e.g. rgba(255, 255, 255, .8) */ + static fromSvg(input: string | Buffer, background?: string | undefined | null): Transformer + static fromRgbaPixels(input: Uint8Array | Uint8ClampedArray, width: number, height: number): Transformer + metadata(withExif?: boolean | undefined | null, signal?: AbortSignal | undefined | null): Promise + /** + * Rotate with exif orientation + * If the orientation param is not null, + * the new orientation value will override the exif orientation value + */ + rotate(orientation?: Orientation | undefined | null): this + /** + * Return a grayscale version of this image. + * Returns `Luma` images in most cases. However, for `f32` images, + * this will return a greyscale `Rgb/Rgba` image instead. + */ + grayscale(): this + /** Invert the colors of this image. */ + invert(): this + /** + * Resize this image using the specified filter algorithm. + * The image is scaled to the maximum possible size that fits + * within the bounds specified by `width` and `height`. + */ + resize(widthOrOptions: number | ResizeOptions, height?: number | undefined | null, filter?: ResizeFilterType | undefined | null, fit?: ResizeFit | undefined | null): this + /** + * Resize this image using the specified filter algorithm. + * The image is scaled to the maximum possible size that fits + * within the bounds specified by `width` and `height`. + * + * This is using faster SIMD based resize implementation + * the resize filter is different from `resize` method + */ + fastResize(options: FastResizeOptions): this + /** + * Performs a Gaussian blur on this image. + * `sigma` is a measure of how much to blur by. + */ + blur(sigma: number): this + /** + * Performs an unsharpen mask on this image. + * `sigma` is the amount to blur the image by. + * `threshold` is a control of how much to sharpen. + * + * See + */ + unsharpen(sigma: number, threshold: number): this + /** Filters this image with the specified 3x3 kernel. */ + filter3x3(kernel: Array): this + /** + * Adjust the contrast of this image. + * `contrast` is the amount to adjust the contrast by. + * Negative values decrease the contrast and positive values increase the contrast. + */ + adjustContrast(contrast: number): this + /** + * Brighten the pixels of this image. + * `value` is the amount to brighten each pixel by. + * Negative values decrease the brightness and positive values increase it. + */ + brighten(brightness: number): this + /** + * Hue rotate the supplied image. + * `value` is the degrees to rotate each pixel by. + * 0 and 360 do nothing, the rest rotates by the given degree value. + * just like the css webkit filter hue-rotate(180) + */ + huerotate(hue: number): this + /** Crop a cut-out of this image delimited by the bounding rectangle. */ + crop(x: number, y: number, width: number, height: number): this + /** Overlay an image at a given coordinate (x, y) */ + overlay(onTop: Buffer, x: number, y: number): this + /** Return this image's pixels as a native endian byte slice. */ + rawPixels(signal?: AbortSignal | undefined | null): Promise + /** Return this image's pixels as a native endian byte slice. */ + rawPixelsSync(): Buffer + /** + * The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression. + * The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size. + * https://developers.google.com/speed/webp/docs/api#simple_encoding_api + */ + webp(qualityFactor?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise + /** + * The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression. + * The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size. + * https://developers.google.com/speed/webp/docs/api#simple_encoding_api + */ + webpSync(qualityFactor?: number | undefined | null): Buffer + webpLossless(signal?: AbortSignal | undefined | null): Promise + webpLosslessSync(): Buffer + avif(options?: AvifConfig | undefined | null, signal?: AbortSignal | undefined | null): Promise + avifSync(options?: AvifConfig | undefined | null): Buffer + png(options?: PngEncodeOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise + pngSync(options?: PngEncodeOptions | undefined | null): Buffer + /** default `quality` is 90 */ + jpeg(quality?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise + /** default `quality` is 90 */ + jpegSync(quality?: number | undefined | null): Buffer + bmp(signal?: AbortSignal | undefined | null): Promise + bmpSync(): Buffer + ico(signal?: AbortSignal | undefined | null): Promise + icoSync(): Buffer + tiff(signal?: AbortSignal | undefined | null): Promise + tiffSync(): Buffer + pnm(signal?: AbortSignal | undefined | null): Promise + pnmSync(): Buffer + tga(signal?: AbortSignal | undefined | null): Promise + tgaSync(): Buffer + farbfeld(signal?: AbortSignal | undefined | null): Promise + farbfeldSync(): Buffer +} export interface AvifConfig { /** 0-100 scale, 100 is lossless */ @@ -15,6 +126,7 @@ export interface AvifConfig { /** set to '4:2:0' to use chroma subsampling, default '4:4:4' */ chromaSubsampling?: ChromaSubsampling } + /** * https://en.wikipedia.org/wiki/Chroma_subsampling#Types_of_sampling_and_subsampling * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_concepts @@ -57,6 +169,20 @@ export const enum ChromaSubsampling { */ Yuv400 = 3 } + +export const enum CompressionType { + /** Default compression level */ + Default = 0, + /** Fast, minimal compression */ + Fast = 1, + /** High compression level */ + Best = 2 +} + +export function compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise + +export function compressJpegSync(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer + export const enum FastResizeFilter { /** * Each pixel of source image contributes to one pixel of the @@ -96,45 +222,14 @@ export const enum FastResizeFilter { */ Lanczos3 = 5 } -export const enum ResizeFit { - /** - * (default) Preserving aspect ratio - * ensure the image covers both provided dimensions by cropping/clipping to fit. - */ - Cover = 0, - /** Ignore the aspect ratio of the input and stretch to both provided dimensions. */ - Fill = 1, - /** - * Preserving aspect ratio - * resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified. - */ - Inside = 2 -} + export interface FastResizeOptions { width: number height?: number filter?: FastResizeFilter fit?: ResizeFit } -export interface JpegCompressOptions { - /** Output quality, default is 100 (lossless) */ - quality?: number - /** - * If true, it will use MozJPEG’s scan optimization. Makes progressive image files smaller. - * Default is `true` - */ - optimizeScans?: boolean -} -export function compressJpegSync(input: Buffer, options?: JpegCompressOptions | undefined | null): Buffer -export function compressJpeg(input: Buffer, options?: JpegCompressOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise -export const enum CompressionType { - /** Default compression level */ - Default = 0, - /** Fast, minimal compression */ - Fast = 1, - /** High compression level */ - Best = 2 -} + export const enum FilterType { /** * No processing done, best used for low bit depth greyscale or data with a @@ -155,24 +250,72 @@ export const enum FilterType { */ Adaptive = 5 } + +export interface JpegCompressOptions { + /** Output quality, default is 100 (lossless) */ + quality?: number + /** + * If true, it will use MozJPEG’s scan optimization. Makes progressive image files smaller. + * Default is `true` + */ + optimizeScans?: boolean +} + +export const enum JsColorType { + /** Pixel is 8-bit luminance */ + L8 = 0, + /** Pixel is 8-bit luminance with an alpha channel */ + La8 = 1, + /** Pixel contains 8-bit R, G and B channels */ + Rgb8 = 2, + /** Pixel is 8-bit RGB with an alpha channel */ + Rgba8 = 3, + /** Pixel is 16-bit luminance */ + L16 = 4, + /** Pixel is 16-bit luminance with an alpha channel */ + La16 = 5, + /** Pixel is 16-bit RGB */ + Rgb16 = 6, + /** Pixel is 16-bit RGBA */ + Rgba16 = 7, + /** Pixel is 32-bit float RGB */ + Rgb32F = 8, + /** Pixel is 32-bit float RGBA */ + Rgba32F = 9 +} + +export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise + +export function losslessCompressPngSync(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer + +export interface Metadata { + width: number + height: number + exif?: Record + orientation?: number + format: string + colorType: JsColorType +} + +export const enum Orientation { + /** Normal */ + Horizontal = 1, + MirrorHorizontal = 2, + Rotate180 = 3, + MirrorVertical = 4, + MirrorHorizontalAndRotate270Cw = 5, + Rotate90Cw = 6, + MirrorHorizontalAndRotate90Cw = 7, + Rotate270Cw = 8 +} + export interface PngEncodeOptions { /** Default is `CompressionType::Default` */ compressionType?: CompressionType /** Default is `FilterType::NoFilter` */ filterType?: FilterType } -export const enum PngRowFilter { - None = 0, - Sub = 1, - Up = 2, - Average = 3, - Paeth = 4, - MinSum = 5, - Entropy = 6, - Bigrams = 7, - BigEnt = 8, - Brute = 9 -} + export interface PNGLosslessOptions { /** * Attempt to fix errors when decoding the input file rather than returning an Err. @@ -215,8 +358,11 @@ export interface PNGLosslessOptions { /** Whether to remove ***All non-critical headers*** on PNG */ strip?: boolean } -export function losslessCompressPngSync(input: Buffer, options?: PNGLosslessOptions | undefined | null): Buffer -export function losslessCompressPng(input: Buffer, options?: PNGLosslessOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise + +export function pngQuantize(input: Buffer, options?: PngQuantOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise + +export function pngQuantizeSync(input: Buffer, options?: PngQuantOptions | undefined | null): Buffer + export interface PngQuantOptions { /** default is 70 */ minQuality?: number @@ -234,19 +380,20 @@ export interface PngQuantOptions { */ posterization?: number } -export function pngQuantizeSync(input: Buffer, options?: PngQuantOptions | undefined | null): Buffer -export function pngQuantize(input: Buffer, options?: PngQuantOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise -export const enum Orientation { - /** Normal */ - Horizontal = 1, - MirrorHorizontal = 2, - Rotate180 = 3, - MirrorVertical = 4, - MirrorHorizontalAndRotate270Cw = 5, - Rotate90Cw = 6, - MirrorHorizontalAndRotate90Cw = 7, - Rotate270Cw = 8 + +export const enum PngRowFilter { + None = 0, + Sub = 1, + Up = 2, + Average = 3, + Paeth = 4, + MinSum = 5, + Entropy = 6, + Bigrams = 7, + BigEnt = 8, + Brute = 9 } + /** * Available Sampling Filters. * @@ -327,151 +474,26 @@ export const enum ResizeFilterType { /** Lanczos with window 3 */ Lanczos3 = 4 } -export const enum JsColorType { - /** Pixel is 8-bit luminance */ - L8 = 0, - /** Pixel is 8-bit luminance with an alpha channel */ - La8 = 1, - /** Pixel contains 8-bit R, G and B channels */ - Rgb8 = 2, - /** Pixel is 8-bit RGB with an alpha channel */ - Rgba8 = 3, - /** Pixel is 16-bit luminance */ - L16 = 4, - /** Pixel is 16-bit luminance with an alpha channel */ - La16 = 5, - /** Pixel is 16-bit RGB */ - Rgb16 = 6, - /** Pixel is 16-bit RGBA */ - Rgba16 = 7, - /** Pixel is 32-bit float RGB */ - Rgb32F = 8, - /** Pixel is 32-bit float RGBA */ - Rgba32F = 9 -} -export interface Metadata { - width: number - height: number - exif?: Record - orientation?: number - format: string - colorType: JsColorType + +export const enum ResizeFit { + /** + * (default) Preserving aspect ratio + * ensure the image covers both provided dimensions by cropping/clipping to fit. + */ + Cover = 0, + /** Ignore the aspect ratio of the input and stretch to both provided dimensions. */ + Fill = 1, + /** + * Preserving aspect ratio + * resize the image to be as large as possible while ensuring its dimensions are less than or equal to both those specified. + */ + Inside = 2 } + export interface ResizeOptions { width: number height?: number filter?: ResizeFilterType fit?: ResizeFit } -export class Transformer { - constructor(input: Buffer) - /** Support CSS3 color, e.g. rgba(255, 255, 255, .8) */ - static fromSvg(input: string | Buffer, background?: string | undefined | null): Transformer - static fromRgbaPixels(input: Uint8Array | Uint8ClampedArray, width: number, height: number): Transformer - metadata(withExif?: boolean | undefined | null, signal?: AbortSignal | undefined | null): Promise - /** - * Rotate with exif orientation - * If the orientation param is not null, - * the new orientation value will override the exif orientation value - */ - rotate(orientation?: Orientation | undefined | null): this - /** - * Return a grayscale version of this image. - * Returns `Luma` images in most cases. However, for `f32` images, - * this will return a greyscale `Rgb/Rgba` image instead. - */ - grayscale(): this - /** Invert the colors of this image. */ - invert(): this - /** - * Resize this image using the specified filter algorithm. - * The image is scaled to the maximum possible size that fits - * within the bounds specified by `width` and `height`. - */ - resize(widthOrOptions: number | ResizeOptions, height?: number | undefined | null, filter?: ResizeFilterType | undefined | null, fit?: ResizeFit | undefined | null): this - /** - * Resize this image using the specified filter algorithm. - * The image is scaled to the maximum possible size that fits - * within the bounds specified by `width` and `height`. - * - * This is using faster SIMD based resize implementation - * the resize filter is different from `resize` method - */ - fastResize(options: FastResizeOptions): this - /** - * Performs a Gaussian blur on this image. - * `sigma` is a measure of how much to blur by. - */ - blur(sigma: number): this - /** - * Performs an unsharpen mask on this image. - * `sigma` is the amount to blur the image by. - * `threshold` is a control of how much to sharpen. - * - * See - */ - unsharpen(sigma: number, threshold: number): this - /** Filters this image with the specified 3x3 kernel. */ - filter3x3(kernel: Array): this - /** - * Adjust the contrast of this image. - * `contrast` is the amount to adjust the contrast by. - * Negative values decrease the contrast and positive values increase the contrast. - */ - adjustContrast(contrast: number): this - /** - * Brighten the pixels of this image. - * `value` is the amount to brighten each pixel by. - * Negative values decrease the brightness and positive values increase it. - */ - brighten(brightness: number): this - /** - * Hue rotate the supplied image. - * `value` is the degrees to rotate each pixel by. - * 0 and 360 do nothing, the rest rotates by the given degree value. - * just like the css webkit filter hue-rotate(180) - */ - huerotate(hue: number): this - /** Crop a cut-out of this image delimited by the bounding rectangle. */ - crop(x: number, y: number, width: number, height: number): this - /** Overlay an image at a given coordinate (x, y) */ - overlay(onTop: Buffer, x: number, y: number): this - /** Return this image's pixels as a native endian byte slice. */ - rawPixels(signal?: AbortSignal | undefined | null): Promise - /** Return this image's pixels as a native endian byte slice. */ - rawPixelsSync(): Buffer - /** - * The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression. - * The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size. - * https://developers.google.com/speed/webp/docs/api#simple_encoding_api - */ - webp(qualityFactor?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise - /** - * The quality factor `quality_factor` ranges from 0 to 100 and controls the loss and quality during compression. - * The value 0 corresponds to low quality and small output sizes, whereas 100 is the highest quality and largest output size. - * https://developers.google.com/speed/webp/docs/api#simple_encoding_api - */ - webpSync(qualityFactor?: number | undefined | null): Buffer - webpLossless(signal?: AbortSignal | undefined | null): Promise - webpLosslessSync(): Buffer - avif(options?: AvifConfig | undefined | null, signal?: AbortSignal | undefined | null): Promise - avifSync(options?: AvifConfig | undefined | null): Buffer - png(options?: PngEncodeOptions | undefined | null, signal?: AbortSignal | undefined | null): Promise - pngSync(options?: PngEncodeOptions | undefined | null): Buffer - /** default `quality` is 90 */ - jpeg(quality?: number | undefined | null, signal?: AbortSignal | undefined | null): Promise - /** default `quality` is 90 */ - jpegSync(quality?: number | undefined | null): Buffer - bmp(signal?: AbortSignal | undefined | null): Promise - bmpSync(): Buffer - ico(signal?: AbortSignal | undefined | null): Promise - icoSync(): Buffer - tiff(signal?: AbortSignal | undefined | null): Promise - tiffSync(): Buffer - pnm(signal?: AbortSignal | undefined | null): Promise - pnmSync(): Buffer - tga(signal?: AbortSignal | undefined | null): Promise - tgaSync(): Buffer - farbfeld(signal?: AbortSignal | undefined | null): Promise - farbfeldSync(): Buffer -} + diff --git a/packages/binding/index.js b/packages/binding/index.js index 48d91ee..83bff31 100644 --- a/packages/binding/index.js +++ b/packages/binding/index.js @@ -1,7 +1,5 @@ -/* tslint:disable */ +// prettier-ignore /* eslint-disable */ -/* prettier-ignore */ - /* auto-generated by NAPI-RS */ const { existsSync, readFileSync } = require('fs') @@ -13,18 +11,52 @@ let nativeBinding = null let localFileExisted = false let loadError = null -function isMusl() { - // For Node 10 - if (!process.report || typeof process.report.getReport !== 'function') { - try { - const lddPath = require('child_process').execSync('which ldd').toString().trim() - return readFileSync(lddPath, 'utf8').includes('musl') - } catch (e) { +const isMusl = () => { + let musl = false + if (process.platform === 'linux') { + musl = isMuslFromFilesystem() + if (musl === null) { + musl = isMuslFromReport() + } + if (musl === null) { + musl = isMuslFromChildProcess() + } + } + return musl +} + +const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') + +const isMuslFromFilesystem = () => { + try { + return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') + } catch { + return null + } +} + +const isMuslFromReport = () => { + const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null + if (!report) { + return null + } + if (report.header && report.header.glibcVersionRuntime) { + return false + } + if (Array.isArray(report.sharedObjects)) { + if (report.sharedObjects.some(isFileMusl)) { return true } - } else { - const { glibcVersionRuntime } = process.report.getReport().header - return !glibcVersionRuntime + } + return false +} + +const isMuslFromChildProcess = () => { + try { + return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') + } catch (e) { + // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false + return false } } @@ -288,6 +320,21 @@ switch (platform) { throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) } +if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { + try { + nativeBinding = require('./image.wasi.cjs') + } catch { + // ignore + } + if (!nativeBinding) { + try { + nativeBinding = require('@napi-rs/image-wasm32-wasi') + } catch (err) { + console.error(err) + } + } +} + if (!nativeBinding) { if (loadError) { throw loadError @@ -295,21 +342,19 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { ChromaSubsampling, FastResizeFilter, ResizeFit, compressJpegSync, compressJpeg, CompressionType, FilterType, PngRowFilter, losslessCompressPngSync, losslessCompressPng, pngQuantizeSync, pngQuantize, Orientation, ResizeFilterType, JsColorType, Transformer } = nativeBinding - -module.exports.ChromaSubsampling = ChromaSubsampling -module.exports.FastResizeFilter = FastResizeFilter -module.exports.ResizeFit = ResizeFit -module.exports.compressJpegSync = compressJpegSync -module.exports.compressJpeg = compressJpeg -module.exports.CompressionType = CompressionType -module.exports.FilterType = FilterType -module.exports.PngRowFilter = PngRowFilter -module.exports.losslessCompressPngSync = losslessCompressPngSync -module.exports.losslessCompressPng = losslessCompressPng -module.exports.pngQuantizeSync = pngQuantizeSync -module.exports.pngQuantize = pngQuantize -module.exports.Orientation = Orientation -module.exports.ResizeFilterType = ResizeFilterType -module.exports.JsColorType = JsColorType -module.exports.Transformer = Transformer +module.exports.Transformer = nativeBinding.Transformer +module.exports.ChromaSubsampling = nativeBinding.ChromaSubsampling +module.exports.CompressionType = nativeBinding.CompressionType +module.exports.compressJpeg = nativeBinding.compressJpeg +module.exports.compressJpegSync = nativeBinding.compressJpegSync +module.exports.FastResizeFilter = nativeBinding.FastResizeFilter +module.exports.FilterType = nativeBinding.FilterType +module.exports.JsColorType = nativeBinding.JsColorType +module.exports.losslessCompressPng = nativeBinding.losslessCompressPng +module.exports.losslessCompressPngSync = nativeBinding.losslessCompressPngSync +module.exports.Orientation = nativeBinding.Orientation +module.exports.pngQuantize = nativeBinding.pngQuantize +module.exports.pngQuantizeSync = nativeBinding.pngQuantizeSync +module.exports.PngRowFilter = nativeBinding.PngRowFilter +module.exports.ResizeFilterType = nativeBinding.ResizeFilterType +module.exports.ResizeFit = nativeBinding.ResizeFit diff --git a/packages/binding/npm/android-arm64/package.json b/packages/binding/npm/android-arm64/package.json index 701acab..294cebb 100644 --- a/packages/binding/npm/android-arm64/package.json +++ b/packages/binding/npm/android-arm64/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-android-arm64", "version": "1.7.0", - "os": [ - "android" - ], "cpu": [ "arm64" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "android" + ] } \ No newline at end of file diff --git a/packages/binding/npm/darwin-arm64/package.json b/packages/binding/npm/darwin-arm64/package.json index 06abb7c..2acafbb 100644 --- a/packages/binding/npm/darwin-arm64/package.json +++ b/packages/binding/npm/darwin-arm64/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-darwin-arm64", "version": "1.7.0", - "os": [ - "darwin" - ], "cpu": [ "arm64" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "darwin" + ] } \ No newline at end of file diff --git a/packages/binding/npm/darwin-x64/package.json b/packages/binding/npm/darwin-x64/package.json index a4e9a1a..a7622bb 100644 --- a/packages/binding/npm/darwin-x64/package.json +++ b/packages/binding/npm/darwin-x64/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-darwin-x64", "version": "1.7.0", - "os": [ - "darwin" - ], "cpu": [ "x64" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "darwin" + ] } \ No newline at end of file diff --git a/packages/binding/npm/freebsd-x64/package.json b/packages/binding/npm/freebsd-x64/package.json index caf3e16..f80c3f5 100644 --- a/packages/binding/npm/freebsd-x64/package.json +++ b/packages/binding/npm/freebsd-x64/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-freebsd-x64", "version": "1.7.0", - "os": [ - "freebsd" - ], "cpu": [ "x64" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "freebsd" + ] } \ No newline at end of file diff --git a/packages/binding/npm/linux-arm-gnueabihf/package.json b/packages/binding/npm/linux-arm-gnueabihf/package.json index 57687b1..99f9c3c 100644 --- a/packages/binding/npm/linux-arm-gnueabihf/package.json +++ b/packages/binding/npm/linux-arm-gnueabihf/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-linux-arm-gnueabihf", "version": "1.7.0", - "os": [ - "linux" - ], "cpu": [ "arm" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "linux" + ] } \ No newline at end of file diff --git a/packages/binding/npm/linux-arm64-gnu/package.json b/packages/binding/npm/linux-arm64-gnu/package.json index c5e65ba..3355482 100644 --- a/packages/binding/npm/linux-arm64-gnu/package.json +++ b/packages/binding/npm/linux-arm64-gnu/package.json @@ -1,16 +1,12 @@ { "name": "@napi-rs/image-linux-arm64-gnu", "version": "1.7.0", - "os": [ - "linux" - ], "cpu": [ "arm64" ], "main": "image.linux-arm64-gnu.node", "files": [ - "image.linux-arm64-gnu.node", - "install.js" + "image.linux-arm64-gnu.node" ], "description": "Image processing library", "keywords": [ @@ -19,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -30,15 +27,15 @@ "engines": { "node": ">= 10" }, - "libc": [ - "glibc" - ], - "scripts": { - "install": "node install.js" - }, "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "linux" + ], + "libc": [ + "glibc" + ] } \ No newline at end of file diff --git a/packages/binding/npm/linux-arm64-musl/package.json b/packages/binding/npm/linux-arm64-musl/package.json index 0d993ab..f50f9d4 100644 --- a/packages/binding/npm/linux-arm64-musl/package.json +++ b/packages/binding/npm/linux-arm64-musl/package.json @@ -1,16 +1,12 @@ { "name": "@napi-rs/image-linux-arm64-musl", "version": "1.7.0", - "os": [ - "linux" - ], "cpu": [ "arm64" ], "main": "image.linux-arm64-musl.node", "files": [ - "image.linux-arm64-musl.node", - "install.js" + "image.linux-arm64-musl.node" ], "description": "Image processing library", "keywords": [ @@ -19,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -30,15 +27,15 @@ "engines": { "node": ">= 10" }, - "libc": [ - "musl" - ], - "scripts": { - "install": "node install.js" - }, "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "linux" + ], + "libc": [ + "musl" + ] } \ No newline at end of file diff --git a/packages/binding/npm/linux-x64-gnu/package.json b/packages/binding/npm/linux-x64-gnu/package.json index 187d068..e160c88 100644 --- a/packages/binding/npm/linux-x64-gnu/package.json +++ b/packages/binding/npm/linux-x64-gnu/package.json @@ -1,16 +1,12 @@ { "name": "@napi-rs/image-linux-x64-gnu", "version": "1.7.0", - "os": [ - "linux" - ], "cpu": [ "x64" ], "main": "image.linux-x64-gnu.node", "files": [ - "image.linux-x64-gnu.node", - "install.js" + "image.linux-x64-gnu.node" ], "description": "Image processing library", "keywords": [ @@ -19,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -30,15 +27,15 @@ "engines": { "node": ">= 10" }, - "libc": [ - "glibc" - ], - "scripts": { - "install": "node install.js" - }, "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "linux" + ], + "libc": [ + "glibc" + ] } \ No newline at end of file diff --git a/packages/binding/npm/linux-x64-musl/package.json b/packages/binding/npm/linux-x64-musl/package.json index 85546a8..807d481 100644 --- a/packages/binding/npm/linux-x64-musl/package.json +++ b/packages/binding/npm/linux-x64-musl/package.json @@ -1,16 +1,12 @@ { "name": "@napi-rs/image-linux-x64-musl", "version": "1.7.0", - "os": [ - "linux" - ], "cpu": [ "x64" ], "main": "image.linux-x64-musl.node", "files": [ - "image.linux-x64-musl.node", - "install.js" + "image.linux-x64-musl.node" ], "description": "Image processing library", "keywords": [ @@ -19,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -30,15 +27,15 @@ "engines": { "node": ">= 10" }, - "libc": [ - "musl" - ], - "scripts": { - "install": "node install.js" - }, "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "linux" + ], + "libc": [ + "musl" + ] } \ No newline at end of file diff --git a/packages/binding/npm/wasm32-wasi/README.md b/packages/binding/npm/wasm32-wasi/README.md new file mode 100644 index 0000000..bd2222a --- /dev/null +++ b/packages/binding/npm/wasm32-wasi/README.md @@ -0,0 +1,3 @@ +# `@napi-rs/image-wasm32-wasi` + +This is the **wasm32-wasi-preview1-threads** binary for `@napi-rs/image` diff --git a/packages/binding/npm/wasm32-wasi/package.json b/packages/binding/npm/wasm32-wasi/package.json new file mode 100644 index 0000000..097003f --- /dev/null +++ b/packages/binding/npm/wasm32-wasi/package.json @@ -0,0 +1,43 @@ +{ + "name": "@napi-rs/image-wasm32-wasi", + "version": "1.7.0", + "cpu": [ + "wasm32" + ], + "main": "image.wasi.cjs", + "files": [ + "image.wasm32-wasi.wasm", + "image.wasi.cjs", + "image.wasi-browser.js", + "wasi-worker.mjs", + "wasi-worker-browser.mjs" + ], + "description": "Image processing library", + "keywords": [ + "image", + "lossless", + "compression", + "jpeg", + "jpg", + "png", + "svg" + ], + "author": { + "email": "github@lyn.one", + "name": "LongYinan", + "url": "https://lyn.one" + }, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public" + }, + "repository": "git@github.com:Brooooooklyn/Image.git", + "browser": "image.wasi-browser.js", + "dependencies": { + "@napi-rs/wasm-runtime": "^0.1.1" + } +} \ No newline at end of file diff --git a/packages/binding/npm/win32-ia32-msvc/package.json b/packages/binding/npm/win32-ia32-msvc/package.json index 7b660c8..dc83720 100644 --- a/packages/binding/npm/win32-ia32-msvc/package.json +++ b/packages/binding/npm/win32-ia32-msvc/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-win32-ia32-msvc", "version": "1.7.0", - "os": [ - "win32" - ], "cpu": [ "ia32" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "win32" + ] } \ No newline at end of file diff --git a/packages/binding/npm/win32-x64-msvc/package.json b/packages/binding/npm/win32-x64-msvc/package.json index c90c58c..ce32280 100644 --- a/packages/binding/npm/win32-x64-msvc/package.json +++ b/packages/binding/npm/win32-x64-msvc/package.json @@ -1,9 +1,6 @@ { "name": "@napi-rs/image-win32-x64-msvc", "version": "1.7.0", - "os": [ - "win32" - ], "cpu": [ "x64" ], @@ -18,7 +15,8 @@ "compression", "jpeg", "jpg", - "png" + "png", + "svg" ], "author": { "email": "github@lyn.one", @@ -33,5 +31,8 @@ "registry": "https://registry.npmjs.org/", "access": "public" }, - "repository": "git@github.com:Brooooooklyn/Image.git" + "repository": "git@github.com:Brooooooklyn/Image.git", + "os": [ + "win32" + ] } \ No newline at end of file diff --git a/packages/binding/package.json b/packages/binding/package.json index 0fb95b6..c6426d7 100644 --- a/packages/binding/package.json +++ b/packages/binding/package.json @@ -2,6 +2,7 @@ "name": "@napi-rs/image", "version": "1.7.0", "main": "index.js", + "browser": "browser.js", "types": "index.d.ts", "description": "Image processing library", "author": { @@ -27,19 +28,21 @@ "access": "public" }, "napi": { - "name": "image", - "triples": { - "additional": [ - "aarch64-apple-darwin", - "aarch64-linux-android", - "aarch64-unknown-linux-gnu", - "aarch64-unknown-linux-musl", - "armv7-unknown-linux-gnueabihf", - "x86_64-unknown-linux-musl", - "x86_64-unknown-freebsd", - "i686-pc-windows-msvc" - ] - } + "binaryName": "image", + "targets": [ + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "aarch64-apple-darwin", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", + "armv7-unknown-linux-gnueabihf", + "x86_64-unknown-linux-musl", + "x86_64-unknown-freebsd", + "i686-pc-windows-msvc", + "wasm32-wasi-preview1-threads" + ] }, "license": "MIT", "engines": { @@ -61,6 +64,7 @@ }, "repository": "git@github.com:Brooooooklyn/Image.git", "devDependencies": { - "@napi-rs/cli": "^2.18.0" + "@napi-rs/cli": "^3.0.0-alpha.36", + "@napi-rs/wasm-runtime": "^0.1.1" } } diff --git a/packages/binding/src/jpeg.rs b/packages/binding/src/jpeg.rs index 010ccd4..4cfc80d 100644 --- a/packages/binding/src/jpeg.rs +++ b/packages/binding/src/jpeg.rs @@ -76,9 +76,9 @@ unsafe fn moz_jpeg_compress( de_c_info.common.err = &mut err_handler; mozjpeg_sys::jpeg_create_decompress(&mut de_c_info); let input_buf = input; - #[cfg(any(target_os = "windows", target_arch = "arm"))] + #[cfg(any(target_os = "windows", target_arch = "arm", target_arch = "wasm32"))] mozjpeg_sys::jpeg_mem_src(&mut de_c_info, input_buf.as_ptr(), input_buf.len() as u32); - #[cfg(not(any(target_os = "windows", target_arch = "arm")))] + #[cfg(not(any(target_os = "windows", target_arch = "arm", target_arch = "wasm32")))] mozjpeg_sys::jpeg_mem_src(&mut de_c_info, input_buf.as_ptr(), input_buf.len() as u64); let mut compress_c_info: mozjpeg_sys::jpeg_compress_struct = std::mem::zeroed(); compress_c_info.optimize_coding = 1; diff --git a/packages/binding/wasi-worker-browser.mjs b/packages/binding/wasi-worker-browser.mjs new file mode 100644 index 0000000..9f5e224 --- /dev/null +++ b/packages/binding/wasi-worker-browser.mjs @@ -0,0 +1,40 @@ +import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime' +import { Volume, createFsFromVolume } from '@napi-rs/wasm-runtime/fs' + +const fs = createFsFromVolume( + Volume.fromJSON({ + '/': null, + }), +) + +const handler = new MessageHandler({ + onLoad({ wasmModule, wasmMemory }) { + const wasi = new WASI({ + fs, + print: function () { + // eslint-disable-next-line no-console + console.log.apply(console, arguments) + }, + printErr: function() { + // eslint-disable-next-line no-console + console.error.apply(console, arguments) + }, + }) + return instantiateNapiModuleSync(wasmModule, { + childThread: true, + wasi, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: wasmMemory, + } + }, + }) + }, +}) + +globalThis.onmessage = function (e) { + handler.handle(e) +} diff --git a/packages/binding/wasi-worker.mjs b/packages/binding/wasi-worker.mjs new file mode 100644 index 0000000..11e930b --- /dev/null +++ b/packages/binding/wasi-worker.mjs @@ -0,0 +1,50 @@ +import fs from "node:fs"; +import { createRequire } from "node:module"; +import { parentPort, Worker } from "node:worker_threads"; + +import { instantiateNapiModuleSync, MessageHandler, WASI } from "@napi-rs/wasm-runtime"; + +const require = createRequire(import.meta.url); + +if (parentPort) { + parentPort.on("message", (data) => { + globalThis.onmessage({ data }); + }); +} + +Object.assign(globalThis, { + self: globalThis, + require, + Worker, + importScripts: function (f) { + ;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f); + }, + postMessage: function (msg) { + if (parentPort) { + parentPort.postMessage(msg); + } + }, +}); + +const handler = new MessageHandler({ + onLoad({ wasmModule, wasmMemory }) { + const wasi = new WASI({ fs }); + + return instantiateNapiModuleSync(wasmModule, { + childThread: true, + wasi, + overwriteImports(importObject) { + importObject.env = { + ...importObject.env, + ...importObject.napi, + ...importObject.emnapi, + memory: wasmMemory + }; + }, + }); + }, +}); + +globalThis.onmessage = function (e) { + handler.handle(e); +}; diff --git a/yarn.lock b/yarn.lock index e8d4021..7a099b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -68,6 +68,15 @@ __metadata: languageName: node linkType: hard +"@emnapi/core@npm:^0.45.0": + version: 0.45.0 + resolution: "@emnapi/core@npm:0.45.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/26071cfe32a5a15068483ed36a152c03add319166c30e6cb81f0d6eb2614e69f836daa2d69af5af2e00fc2b8335f172e5ce2ee91f1819b3e689c908a7883433f + languageName: node + linkType: hard + "@emnapi/runtime@npm:^0.45.0": version: 0.45.0 resolution: "@emnapi/runtime@npm:0.45.0" @@ -367,6 +376,15 @@ __metadata: languageName: node linkType: hard +"@ljharb/through@npm:^2.3.12": + version: 2.3.12 + resolution: "@ljharb/through@npm:2.3.12" + dependencies: + call-bind: "npm:^1.0.5" + checksum: 10c0/7560aaef7b6ef88c16783ffde37278e2177c7f0f5427400059a8a7687b144dc711bf5b2347ab27e858a29f25e4b868d77c915c9614bc399b82b8123430614653 + languageName: node + linkType: hard + "@mapbox/node-pre-gyp@npm:^1.0.5": version: 1.0.11 resolution: "@mapbox/node-pre-gyp@npm:1.0.11" @@ -522,12 +540,69 @@ __metadata: languageName: node linkType: hard -"@napi-rs/cli@npm:^2.18.0": - version: 2.18.0 - resolution: "@napi-rs/cli@npm:2.18.0" +"@napi-rs/cli@npm:^3.0.0-alpha.36": + version: 3.0.0-alpha.36 + resolution: "@napi-rs/cli@npm:3.0.0-alpha.36" + dependencies: + "@napi-rs/cross-toolchain": "npm:^0.0.14" + "@octokit/rest": "npm:^20.0.2" + "@tybys/wasm-util": "npm:0.8.1" + clipanion: "npm:^3.2.1" + colorette: "npm:^2.0.20" + debug: "npm:^4.3.4" + emnapi: "npm:0.45.0" + inquirer: "npm:^9.2.12" + js-yaml: "npm:^4.1.0" + lodash-es: "npm:^4.17.21" + semver: "npm:^7.5.4" + toml: "npm:^3.0.0" + typanion: "npm:^3.14.0" + peerDependencies: + "@emnapi/runtime": ^0.45.0 + "@tybys/wasm-util": ^0.8.0 + emnapi: ^0.45.0 + peerDependenciesMeta: + "@emnapi/runtime": + optional: true + "@tybys/wasm-util": + optional: true + emnapi: + optional: true bin: - napi: scripts/index.js - checksum: 10c0/db00a70212511bf19a5165bb5397af40b8ee8be26345fa0c7fe3f35803216603f6f757dec99bf385e6db377b8eb82d69956e073c315e3e1f8e0452af04a7ce7f + napi: dist/cli.js + napi-raw: cli.mjs + checksum: 10c0/cbcd0fee9ac93d71e5a56a8a82bd6ffa75e1f51816bf38edee94b88bda611eb281e8f2eb8c415145da1c15d9c56c49f9d65f6d23a92bbf7d4f16d5fff780ad79 + languageName: node + linkType: hard + +"@napi-rs/cross-toolchain@npm:^0.0.14": + version: 0.0.14 + resolution: "@napi-rs/cross-toolchain@npm:0.0.14" + dependencies: + "@napi-rs/lzma": "npm:^1.2.1" + "@napi-rs/tar": "npm:^0.1.0" + debug: "npm:^4.3.4" + peerDependencies: + "@napi-rs/cross-toolchain-arm64-target-aarch64": ^0.0.14 + "@napi-rs/cross-toolchain-arm64-target-armv7": ^0.0.14 + "@napi-rs/cross-toolchain-arm64-target-x86_64": ^0.0.14 + "@napi-rs/cross-toolchain-x64-target-aarch64": ^0.0.14 + "@napi-rs/cross-toolchain-x64-target-armv7": ^0.0.14 + "@napi-rs/cross-toolchain-x64-target-x86_64": ^0.0.14 + peerDependenciesMeta: + "@napi-rs/cross-toolchain-arm64-target-aarch64": + optional: true + "@napi-rs/cross-toolchain-arm64-target-armv7": + optional: true + "@napi-rs/cross-toolchain-arm64-target-x86_64": + optional: true + "@napi-rs/cross-toolchain-x64-target-aarch64": + optional: true + "@napi-rs/cross-toolchain-x64-target-armv7": + optional: true + "@napi-rs/cross-toolchain-x64-target-x86_64": + optional: true + checksum: 10c0/177f126e2324af95e76b88b9ebfcf562659ccfdbb2fe2ee6bfe2079ab3a5d573f5df62e9c065bfbd31cda834fefb38d72ca92cafee759f74a33298266592c72a languageName: node linkType: hard @@ -541,10 +616,150 @@ __metadata: version: 0.0.0-use.local resolution: "@napi-rs/image@workspace:packages/binding" dependencies: - "@napi-rs/cli": "npm:^2.18.0" + "@napi-rs/cli": "npm:^3.0.0-alpha.36" + "@napi-rs/wasm-runtime": "npm:^0.1.1" languageName: unknown linkType: soft +"@napi-rs/lzma-android-arm-eabi@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-android-arm-eabi@npm:1.2.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/lzma-android-arm64@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-android-arm64@npm:1.2.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/lzma-darwin-arm64@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-darwin-arm64@npm:1.2.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/lzma-darwin-x64@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-darwin-x64@npm:1.2.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/lzma-freebsd-x64@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-freebsd-x64@npm:1.2.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-arm-gnueabihf@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-linux-arm-gnueabihf@npm:1.2.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-arm64-gnu@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-linux-arm64-gnu@npm:1.2.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-arm64-musl@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-linux-arm64-musl@npm:1.2.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-x64-gnu@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-linux-x64-gnu@npm:1.2.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-x64-musl@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-linux-x64-musl@npm:1.2.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/lzma-win32-arm64-msvc@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-win32-arm64-msvc@npm:1.2.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/lzma-win32-ia32-msvc@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-win32-ia32-msvc@npm:1.2.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@napi-rs/lzma-win32-x64-msvc@npm:1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma-win32-x64-msvc@npm:1.2.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/lzma@npm:^1.2.1": + version: 1.2.1 + resolution: "@napi-rs/lzma@npm:1.2.1" + dependencies: + "@napi-rs/lzma-android-arm-eabi": "npm:1.2.1" + "@napi-rs/lzma-android-arm64": "npm:1.2.1" + "@napi-rs/lzma-darwin-arm64": "npm:1.2.1" + "@napi-rs/lzma-darwin-x64": "npm:1.2.1" + "@napi-rs/lzma-freebsd-x64": "npm:1.2.1" + "@napi-rs/lzma-linux-arm-gnueabihf": "npm:1.2.1" + "@napi-rs/lzma-linux-arm64-gnu": "npm:1.2.1" + "@napi-rs/lzma-linux-arm64-musl": "npm:1.2.1" + "@napi-rs/lzma-linux-x64-gnu": "npm:1.2.1" + "@napi-rs/lzma-linux-x64-musl": "npm:1.2.1" + "@napi-rs/lzma-win32-arm64-msvc": "npm:1.2.1" + "@napi-rs/lzma-win32-ia32-msvc": "npm:1.2.1" + "@napi-rs/lzma-win32-x64-msvc": "npm:1.2.1" + dependenciesMeta: + "@napi-rs/lzma-android-arm-eabi": + optional: true + "@napi-rs/lzma-android-arm64": + optional: true + "@napi-rs/lzma-darwin-arm64": + optional: true + "@napi-rs/lzma-darwin-x64": + optional: true + "@napi-rs/lzma-freebsd-x64": + optional: true + "@napi-rs/lzma-linux-arm-gnueabihf": + optional: true + "@napi-rs/lzma-linux-arm64-gnu": + optional: true + "@napi-rs/lzma-linux-arm64-musl": + optional: true + "@napi-rs/lzma-linux-x64-gnu": + optional: true + "@napi-rs/lzma-linux-x64-musl": + optional: true + "@napi-rs/lzma-win32-arm64-msvc": + optional: true + "@napi-rs/lzma-win32-ia32-msvc": + optional: true + "@napi-rs/lzma-win32-x64-msvc": + optional: true + checksum: 10c0/8fc856aa1f547a2ca5477afd4aa7079069d7fb0ce5da64ba4a3d5eb243210a6bb591f1f0fa9584f0f272952bd1d11b99eb097a1d2be9f919c8a9dcd1d8bceb2c + languageName: node + linkType: hard + "@napi-rs/simple-git-android-arm-eabi@npm:0.1.16": version: 0.1.16 resolution: "@napi-rs/simple-git-android-arm-eabi@npm:0.1.16" @@ -664,6 +879,156 @@ __metadata: languageName: node linkType: hard +"@napi-rs/tar-android-arm-eabi@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-android-arm-eabi@npm:0.1.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/tar-android-arm64@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-android-arm64@npm:0.1.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/tar-darwin-arm64@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-darwin-arm64@npm:0.1.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/tar-darwin-x64@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-darwin-x64@npm:0.1.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/tar-freebsd-x64@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-freebsd-x64@npm:0.1.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/tar-linux-arm-gnueabihf@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-linux-arm-gnueabihf@npm:0.1.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/tar-linux-arm64-gnu@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-linux-arm64-gnu@npm:0.1.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/tar-linux-arm64-musl@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-linux-arm64-musl@npm:0.1.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/tar-linux-x64-gnu@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-linux-x64-gnu@npm:0.1.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/tar-linux-x64-musl@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-linux-x64-musl@npm:0.1.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/tar-win32-arm64-msvc@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-win32-arm64-msvc@npm:0.1.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/tar-win32-ia32-msvc@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-win32-ia32-msvc@npm:0.1.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@napi-rs/tar-win32-x64-msvc@npm:0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar-win32-x64-msvc@npm:0.1.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/tar@npm:^0.1.0": + version: 0.1.0 + resolution: "@napi-rs/tar@npm:0.1.0" + dependencies: + "@napi-rs/tar-android-arm-eabi": "npm:0.1.0" + "@napi-rs/tar-android-arm64": "npm:0.1.0" + "@napi-rs/tar-darwin-arm64": "npm:0.1.0" + "@napi-rs/tar-darwin-x64": "npm:0.1.0" + "@napi-rs/tar-freebsd-x64": "npm:0.1.0" + "@napi-rs/tar-linux-arm-gnueabihf": "npm:0.1.0" + "@napi-rs/tar-linux-arm64-gnu": "npm:0.1.0" + "@napi-rs/tar-linux-arm64-musl": "npm:0.1.0" + "@napi-rs/tar-linux-x64-gnu": "npm:0.1.0" + "@napi-rs/tar-linux-x64-musl": "npm:0.1.0" + "@napi-rs/tar-win32-arm64-msvc": "npm:0.1.0" + "@napi-rs/tar-win32-ia32-msvc": "npm:0.1.0" + "@napi-rs/tar-win32-x64-msvc": "npm:0.1.0" + dependenciesMeta: + "@napi-rs/tar-android-arm-eabi": + optional: true + "@napi-rs/tar-android-arm64": + optional: true + "@napi-rs/tar-darwin-arm64": + optional: true + "@napi-rs/tar-darwin-x64": + optional: true + "@napi-rs/tar-freebsd-x64": + optional: true + "@napi-rs/tar-linux-arm-gnueabihf": + optional: true + "@napi-rs/tar-linux-arm64-gnu": + optional: true + "@napi-rs/tar-linux-arm64-musl": + optional: true + "@napi-rs/tar-linux-x64-gnu": + optional: true + "@napi-rs/tar-linux-x64-musl": + optional: true + "@napi-rs/tar-win32-arm64-msvc": + optional: true + "@napi-rs/tar-win32-ia32-msvc": + optional: true + "@napi-rs/tar-win32-x64-msvc": + optional: true + checksum: 10c0/e034179204d99db042c03b2a43ec2b6ceff49b4c7ccbd5f76f2f79457de2951018a683b402878900fd3dd177fc842d880c9a40a634deb138c66778a5c91ae076 + languageName: node + linkType: hard + +"@napi-rs/wasm-runtime@npm:^0.1.1": + version: 0.1.1 + resolution: "@napi-rs/wasm-runtime@npm:0.1.1" + dependencies: + "@emnapi/core": "npm:^0.45.0" + "@emnapi/runtime": "npm:^0.45.0" + "@tybys/wasm-util": "npm:^0.8.1" + checksum: 10c0/e9718b1ec7d6754f04bcd4df05993347360d17889a357be1d6d1b6f26fc52f70a2b73149c2bcf6bd204c5e3abd8656e086feeb5a04a9a3114bc90e8b3a72ff74 + languageName: node + linkType: hard + "@next/env@npm:14.1.1-canary.36": version: 14.1.1-canary.36 resolution: "@next/env@npm:14.1.1-canary.36" @@ -984,6 +1349,13 @@ __metadata: languageName: node linkType: hard +"@octokit/auth-token@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/auth-token@npm:4.0.0" + checksum: 10c0/57acaa6c394c5abab2f74e8e1dcf4e7a16b236f713c77a54b8f08e2d14114de94b37946259e33ec2aab0566b26f724c2b71d2602352b59e541a9854897618f3c + languageName: node + linkType: hard + "@octokit/core@npm:^4.2.1": version: 4.2.4 resolution: "@octokit/core@npm:4.2.4" @@ -999,6 +1371,21 @@ __metadata: languageName: node linkType: hard +"@octokit/core@npm:^5.0.0": + version: 5.1.0 + resolution: "@octokit/core@npm:5.1.0" + dependencies: + "@octokit/auth-token": "npm:^4.0.0" + "@octokit/graphql": "npm:^7.0.0" + "@octokit/request": "npm:^8.0.2" + "@octokit/request-error": "npm:^5.0.0" + "@octokit/types": "npm:^12.0.0" + before-after-hook: "npm:^2.2.0" + universal-user-agent: "npm:^6.0.0" + checksum: 10c0/a1d2882373b4a33cd9f6e56d76bcc82e5589a477829fc3491b1ef471a8a83fa437b339a2c76d97d9e8ea4ca12bf3ebf32e66119ba16977e542d98f1f5dd3c994 + languageName: node + linkType: hard + "@octokit/endpoint@npm:^7.0.0": version: 7.0.6 resolution: "@octokit/endpoint@npm:7.0.6" @@ -1010,6 +1397,16 @@ __metadata: languageName: node linkType: hard +"@octokit/endpoint@npm:^9.0.0": + version: 9.0.4 + resolution: "@octokit/endpoint@npm:9.0.4" + dependencies: + "@octokit/types": "npm:^12.0.0" + universal-user-agent: "npm:^6.0.0" + checksum: 10c0/f1c857c5d85afa9d7e8857f7f97dbec28d3b6ab1dc21fe35172f1bc9e5512c8a3a26edabf6b2d83bb60d700f7ad290c96be960496aa83606095630edfad06db4 + languageName: node + linkType: hard + "@octokit/graphql@npm:^5.0.0": version: 5.0.6 resolution: "@octokit/graphql@npm:5.0.6" @@ -1021,6 +1418,17 @@ __metadata: languageName: node linkType: hard +"@octokit/graphql@npm:^7.0.0": + version: 7.0.2 + resolution: "@octokit/graphql@npm:7.0.2" + dependencies: + "@octokit/request": "npm:^8.0.1" + "@octokit/types": "npm:^12.0.0" + universal-user-agent: "npm:^6.0.0" + checksum: 10c0/96e5d6b970be60877134cc147b9249534f3a79d691b9932d731d453426fa1e1a0a36111a1b0a6ab43d61309c630903a65db5559b5c800300dc26cf588f50fea8 + languageName: node + linkType: hard + "@octokit/openapi-types@npm:^18.0.0": version: 18.1.1 resolution: "@octokit/openapi-types@npm:18.1.1" @@ -1028,6 +1436,13 @@ __metadata: languageName: node linkType: hard +"@octokit/openapi-types@npm:^19.1.0": + version: 19.1.0 + resolution: "@octokit/openapi-types@npm:19.1.0" + checksum: 10c0/ae8081f52b797b91a12d4f6cddc475699c9d34b06645b337adc77d30b583d8fe8506597a45c42f8f1a96bfb2a9d092cee257d8a65d718bfeed23a0d153448eea + languageName: node + linkType: hard + "@octokit/plugin-enterprise-rest@npm:6.0.1": version: 6.0.1 resolution: "@octokit/plugin-enterprise-rest@npm:6.0.1" @@ -1047,6 +1462,17 @@ __metadata: languageName: node linkType: hard +"@octokit/plugin-paginate-rest@npm:^9.0.0": + version: 9.1.5 + resolution: "@octokit/plugin-paginate-rest@npm:9.1.5" + dependencies: + "@octokit/types": "npm:^12.4.0" + peerDependencies: + "@octokit/core": ">=5" + checksum: 10c0/a17055dff8fde5ebc03bf935294ffa4605ed714cb15252f0fa63cda1b95e738fafb5ab9748b18fbdfa5615d5f6686cbf193c6d6426e7dc4fd1dda91c87263f3b + languageName: node + linkType: hard + "@octokit/plugin-request-log@npm:^1.0.4": version: 1.0.4 resolution: "@octokit/plugin-request-log@npm:1.0.4" @@ -1056,6 +1482,26 @@ __metadata: languageName: node linkType: hard +"@octokit/plugin-request-log@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/plugin-request-log@npm:4.0.0" + peerDependencies: + "@octokit/core": ">=5" + checksum: 10c0/ca6db112f288326d2f11de5170e7d6429ba54f04a22dc1e5d06c8d626f72bd2effeb0218a8f73bc9e23657b5a89194cd297964ace54693d2dfdfba3828920b45 + languageName: node + linkType: hard + +"@octokit/plugin-rest-endpoint-methods@npm:^10.0.0": + version: 10.2.0 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:10.2.0" + dependencies: + "@octokit/types": "npm:^12.3.0" + peerDependencies: + "@octokit/core": ">=5" + checksum: 10c0/4d00a2334753955f0c3841ba8fc0880c093b94838e011864ee737d958d2d64e3d45d34fa4c8b64bccf9e13c6de81318cbd6e2b24df37992941d12f54def28432 + languageName: node + linkType: hard + "@octokit/plugin-rest-endpoint-methods@npm:^7.1.2": version: 7.2.3 resolution: "@octokit/plugin-rest-endpoint-methods@npm:7.2.3" @@ -1078,6 +1524,17 @@ __metadata: languageName: node linkType: hard +"@octokit/request-error@npm:^5.0.0": + version: 5.0.1 + resolution: "@octokit/request-error@npm:5.0.1" + dependencies: + "@octokit/types": "npm:^12.0.0" + deprecation: "npm:^2.0.0" + once: "npm:^1.4.0" + checksum: 10c0/e72a4627120de345b54876a1f007664095e5be9d624fce2e14fccf7668cd8f5e4929d444d8fc085d48e1fb5cd548538453974aab129a669101110d6679dce6c6 + languageName: node + linkType: hard + "@octokit/request@npm:^6.0.0": version: 6.2.8 resolution: "@octokit/request@npm:6.2.8" @@ -1092,6 +1549,18 @@ __metadata: languageName: node linkType: hard +"@octokit/request@npm:^8.0.1, @octokit/request@npm:^8.0.2": + version: 8.1.6 + resolution: "@octokit/request@npm:8.1.6" + dependencies: + "@octokit/endpoint": "npm:^9.0.0" + "@octokit/request-error": "npm:^5.0.0" + "@octokit/types": "npm:^12.0.0" + universal-user-agent: "npm:^6.0.0" + checksum: 10c0/ef84418e0b1f28335c105bca2b1518b04797791761024d26f80f60a528cdcf468baf9897fd34f535c42af0643a598884f882bc832e68edbfe1ea530c2df563a4 + languageName: node + linkType: hard + "@octokit/rest@npm:19.0.11": version: 19.0.11 resolution: "@octokit/rest@npm:19.0.11" @@ -1104,6 +1573,18 @@ __metadata: languageName: node linkType: hard +"@octokit/rest@npm:^20.0.2": + version: 20.0.2 + resolution: "@octokit/rest@npm:20.0.2" + dependencies: + "@octokit/core": "npm:^5.0.0" + "@octokit/plugin-paginate-rest": "npm:^9.0.0" + "@octokit/plugin-request-log": "npm:^4.0.0" + "@octokit/plugin-rest-endpoint-methods": "npm:^10.0.0" + checksum: 10c0/e9bfc617d0e0bfb0ba9dea3d1e0a19167c5a255beac622dd34280e1754dfab7688323b3251f8e8c85494b39548ecc52385e8b84e21ce0627f58176562a6e2fae + languageName: node + linkType: hard + "@octokit/tsconfig@npm:^1.0.2": version: 1.0.2 resolution: "@octokit/tsconfig@npm:1.0.2" @@ -1120,6 +1601,15 @@ __metadata: languageName: node linkType: hard +"@octokit/types@npm:^12.0.0, @octokit/types@npm:^12.3.0, @octokit/types@npm:^12.4.0": + version: 12.4.0 + resolution: "@octokit/types@npm:12.4.0" + dependencies: + "@octokit/openapi-types": "npm:^19.1.0" + checksum: 10c0/b52b3fd8af307a1868846991f8376548a790814b20639dee1110271a768c0489081970df893ca2230f6285066003230d22f5877eeac90418971a475c79808241 + languageName: node + linkType: hard + "@octokit/types@npm:^9.0.0, @octokit/types@npm:^9.2.3": version: 9.3.2 resolution: "@octokit/types@npm:9.3.2" @@ -1377,6 +1867,15 @@ __metadata: languageName: node linkType: hard +"@tybys/wasm-util@npm:0.8.1, @tybys/wasm-util@npm:^0.8.1": + version: 0.8.1 + resolution: "@tybys/wasm-util@npm:0.8.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/4e0975ee0ed8202e4af0be45a379ac11fa98e8c17cb5a038bc1d29f6e1bd37eb84be991d725d214d0f257d4aaccd67e5ac6e68c3c81cdd3c7f3f678d05d52cb7 + languageName: node + linkType: hard + "@types/acorn@npm:^4.0.0": version: 4.0.6 resolution: "@types/acorn@npm:4.0.6" @@ -1799,7 +2298,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.2.1": +"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" dependencies: @@ -2550,6 +3049,13 @@ __metadata: languageName: node linkType: hard +"cli-width@npm:^4.1.0": + version: 4.1.0 + resolution: "cli-width@npm:4.1.0" + checksum: 10c0/1fbd56413578f6117abcaf858903ba1f4ad78370a4032f916745fa2c7e390183a9d9029cf837df320b0fdce8137668e522f60a30a5f3d6529ff3872d265a955f + languageName: node + linkType: hard + "client-only@npm:0.0.1, client-only@npm:^0.0.1": version: 0.0.1 resolution: "client-only@npm:0.0.1" @@ -2557,6 +3063,17 @@ __metadata: languageName: node linkType: hard +"clipanion@npm:^3.2.1": + version: 3.2.1 + resolution: "clipanion@npm:3.2.1" + dependencies: + typanion: "npm:^3.8.0" + peerDependencies: + typanion: "*" + checksum: 10c0/6c148bd01ae645031aeb6e9a1a16f3ce07eb754cd9981c91edcab82b09e063b805ac41e4f36039d07602334b6dbba036b030d1807c12acd7f90778a696b7ac6e + languageName: node + linkType: hard + "clipboardy@npm:1.2.2": version: 1.2.2 resolution: "clipboardy@npm:1.2.2" @@ -2700,6 +3217,13 @@ __metadata: languageName: node linkType: hard +"colorette@npm:^2.0.20": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 10c0/e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 + languageName: node + linkType: hard + "columnify@npm:1.6.0": version: 1.6.0 resolution: "columnify@npm:1.6.0" @@ -3682,6 +4206,18 @@ __metadata: languageName: node linkType: hard +"emnapi@npm:0.45.0": + version: 0.45.0 + resolution: "emnapi@npm:0.45.0" + peerDependencies: + node-addon-api: ">= 6.1.0" + peerDependenciesMeta: + node-addon-api: + optional: true + checksum: 10c0/076411fc611c0e3f1c08a9260babbeac8094474d8a4174e6b9f27dc5ba569b51fd42c2513d17d4056680a680a575fb8c81f18259d7208327b53195bf3f58483b + languageName: node + linkType: hard + "emoji-regex@npm:^10.3.0": version: 10.3.0 resolution: "emoji-regex@npm:10.3.0" @@ -4039,7 +4575,7 @@ __metadata: languageName: node linkType: hard -"external-editor@npm:^3.0.3": +"external-editor@npm:^3.0.3, external-editor@npm:^3.1.0": version: 3.1.0 resolution: "external-editor@npm:3.1.0" dependencies: @@ -4115,7 +4651,7 @@ __metadata: languageName: node linkType: hard -"figures@npm:3.2.0, figures@npm:^3.0.0": +"figures@npm:3.2.0, figures@npm:^3.0.0, figures@npm:^3.2.0": version: 3.2.0 resolution: "figures@npm:3.2.0" dependencies: @@ -5163,7 +5699,7 @@ __metadata: version: 0.0.0-use.local resolution: "image@workspace:." dependencies: - "@napi-rs/cli": "npm:^2.18.0" + "@napi-rs/cli": "npm:^3.0.0-alpha.36" "@taplo/cli": "npm:^0.7.0" "@types/node": "npm:^20.11.16" "@types/sharp": "npm:^0.31.1" @@ -5292,6 +5828,29 @@ __metadata: languageName: node linkType: hard +"inquirer@npm:^9.2.12": + version: 9.2.14 + resolution: "inquirer@npm:9.2.14" + dependencies: + "@ljharb/through": "npm:^2.3.12" + ansi-escapes: "npm:^4.3.2" + chalk: "npm:^5.3.0" + cli-cursor: "npm:^3.1.0" + cli-width: "npm:^4.1.0" + external-editor: "npm:^3.1.0" + figures: "npm:^3.2.0" + lodash: "npm:^4.17.21" + mute-stream: "npm:1.0.0" + ora: "npm:^5.4.1" + run-async: "npm:^3.0.0" + rxjs: "npm:^7.8.1" + string-width: "npm:^4.2.3" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^6.2.0" + checksum: 10c0/de4fc9054e4816835bfc1cee1db254b0b8df816fb57fc13d694cd4e80c13e43230b01bde0526e74f620910a64e3ad0f99ec89869f88e1cf50aa70d4958ef62cb + languageName: node + linkType: hard + "internal-slot@npm:^1.0.5": version: 1.0.6 resolution: "internal-slot@npm:1.0.6" @@ -7495,7 +8054,7 @@ __metadata: languageName: node linkType: hard -"mute-stream@npm:~1.0.0": +"mute-stream@npm:1.0.0, mute-stream@npm:~1.0.0": version: 1.0.0 resolution: "mute-stream@npm:1.0.0" checksum: 10c0/dce2a9ccda171ec979a3b4f869a102b1343dee35e920146776780de182f16eae459644d187e38d59a3d37adf85685e1c17c38cf7bfda7e39a9880f7a1d10a74c @@ -9283,6 +9842,13 @@ __metadata: languageName: node linkType: hard +"run-async@npm:^3.0.0": + version: 3.0.0 + resolution: "run-async@npm:3.0.0" + checksum: 10c0/b18b562ae37c3020083dcaae29642e4cc360c824fbfb6b7d50d809a9d5227bb986152d09310255842c8dce40526e82ca768f02f00806c91ba92a8dfa6159cb85 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -10267,6 +10833,13 @@ __metadata: languageName: node linkType: hard +"toml@npm:^3.0.0": + version: 3.0.0 + resolution: "toml@npm:3.0.0" + checksum: 10c0/8d7ed3e700ca602e5419fca343e1c595eb7aa177745141f0761a5b20874b58ee5c878cd045c408da9d130cb2b611c639912210ba96ce2f78e443569aa8060c18 + languageName: node + linkType: hard + "tr46@npm:~0.0.3": version: 0.0.3 resolution: "tr46@npm:0.0.3" @@ -10342,6 +10915,13 @@ __metadata: languageName: node linkType: hard +"typanion@npm:^3.14.0, typanion@npm:^3.8.0": + version: 3.14.0 + resolution: "typanion@npm:3.14.0" + checksum: 10c0/8b03b19844e6955bfd906c31dc781bae6d7f1fb3ce4fe24b7501557013d4889ae5cefe671dafe98d87ead0adceb8afcb8bc16df7dc0bd2b7331bac96f3a7cae2 + languageName: node + linkType: hard + "type-fest@npm:^0.13.1": version: 0.13.1 resolution: "type-fest@npm:0.13.1" @@ -11029,7 +11609,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^6.0.1": +"wrap-ansi@npm:^6.0.1, wrap-ansi@npm:^6.2.0": version: 6.2.0 resolution: "wrap-ansi@npm:6.2.0" dependencies: