diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0a5c66e9..34f2ac63 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,7 +54,29 @@ jobs: sed -i '/^\[workspace\.package\]/,/^\[/{s/^version = ".*"/version = "'"$VERSION"'"/}' Cargo.toml sed -i '/^\[workspace\.dependencies\]/,/^\[/{s/version = "'"$CURRENT_VERSION"'"/version = "'"$VERSION"'"/g}' Cargo.toml - sed -i '/^\[project\]/,/^\[/{s/^version = ".*"/version = "'"$VERSION"'"/}' pyproject.toml + sed -i '/^\[project\]/,/^\[/{s/^version = ".*"/version = "'"$VERSION"'"/}' python/pyasic-rs/pyproject.toml + python3 - <<'PY' + import json + import os + from pathlib import Path + + version = os.environ["VERSION"] + package_dir = Path("javascript/asic-js") + + package_json = package_dir / "package.json" + package = json.loads(package_json.read_text()) + package["version"] = version + package_json.write_text(json.dumps(package, indent=2) + "\n") + + package_lock_json = package_dir / "package-lock.json" + if package_lock_json.exists(): + package_lock = json.loads(package_lock_json.read_text()) + package_lock["version"] = version + root_package = package_lock.get("packages", {}).get("") + if root_package is not None: + root_package["version"] = version + package_lock_json.write_text(json.dumps(package_lock, indent=2) + "\n") + PY declare -A CARGO_MANIFESTS=() CARGO_MANIFESTS["./Cargo.toml"]=1 @@ -81,7 +103,7 @@ jobs: codeberg.org/msrd0/cargo-doc2readme:nightly \ cargo doc2readme --expand-macros - git add Cargo.toml pyproject.toml README.md + git add Cargo.toml python/pyasic-rs/pyproject.toml README.md javascript/asic-js/package.json javascript/asic-js/package-lock.json while IFS= read -r -d '' lockfile; do git add "$lockfile" @@ -193,8 +215,9 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: + working-directory: python/pyasic-rs target: ${{ matrix.target }} - args: --release --out dist --find-interpreter + args: --release --out ../../dist --find-interpreter sccache: true manylinux: ${{ matrix.manylinux }} @@ -216,8 +239,9 @@ jobs: - name: Build sdist uses: PyO3/maturin-action@v1 with: + working-directory: python/pyasic-rs command: sdist - args: --out dist + args: --out ../../dist - name: Upload sdist uses: actions/upload-artifact@v6 @@ -240,7 +264,89 @@ jobs: - name: Publish crates env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - run: cargo workspaces publish --from-git --yes --allow-dirty + run: cargo workspaces publish --from-git --yes --allow-dirty --exclude asic-js --exclude pyasic-rs + + build-js-bindings: + needs: prepare-release + name: Build JS binding (${{ matrix.artifact }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - artifact: linux-x64 + os: ubuntu-24.04 + - artifact: windows-x64 + os: windows-latest + - artifact: macos-arm64 + os: macos-14 + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ needs.prepare-release.outputs.tag }} + + - uses: actions/setup-node@v6 + with: + node-version: "22" + cache: npm + cache-dependency-path: javascript/asic-js/package-lock.json + + - uses: dtolnay/rust-toolchain@stable + + - name: Install dependencies + working-directory: javascript/asic-js + run: npm ci + + - name: Build native binding + working-directory: javascript/asic-js + run: npm run build + + - name: Upload native binding + uses: actions/upload-artifact@v6 + with: + name: js-native-${{ matrix.artifact }} + path: javascript/asic-js/*.node + if-no-files-found: error + + publish-js: + needs: + - prepare-release + - build-js-bindings + runs-on: ubuntu-24.04 + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ needs.prepare-release.outputs.tag }} + + - uses: actions/setup-node@v6 + with: + node-version: "22" + registry-url: https://registry.npmjs.org + cache: npm + cache-dependency-path: javascript/asic-js/package-lock.json + + - name: Install dependencies + working-directory: javascript/asic-js + run: npm ci + + - uses: actions/download-artifact@v4 + with: + pattern: js-native-* + path: javascript/asic-js + merge-multiple: true + + - name: Verify package contents + working-directory: javascript/asic-js + run: npm pack --dry-run + + - name: Publish to npm + working-directory: javascript/asic-js + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --provenance release: runs-on: ubuntu-24.04 @@ -249,6 +355,7 @@ jobs: - build-python-wheels - build-python-sdist - publish-rust + - publish-js permissions: contents: write id-token: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index acb6f311..7c6369b4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - name: Run tests - run: cargo test --all --locked --exclude asic-rs-pydantic --exclude asic-rs-pydantic-macros + run: cargo test --all --locked --exclude asic-rs-pydantic --exclude asic-rs-pydantic-macros --exclude asic-js --exclude pyasic-rs python-test: name: Python Test @@ -43,7 +43,8 @@ jobs: run: .venv/bin/python -m pip install --upgrade pip maturin - name: Build and install package with test dependencies - run: VIRTUAL_ENV="$PWD/.venv" .venv/bin/maturin develop --features python --extras test + working-directory: python/pyasic-rs + run: VIRTUAL_ENV="$GITHUB_WORKSPACE/.venv" "$GITHUB_WORKSPACE/.venv/bin/maturin" develop --features python --extras test - name: Run Python tests - run: .venv/bin/python -m pytest python/tests + run: .venv/bin/python -m pytest python/pyasic-rs/tests diff --git a/.gitignore b/.gitignore index f1f71ce1..d9d329cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,13 @@ /target /site +/javascript/asic-js/node_modules +/javascript/asic-js/index.js +/javascript/asic-js/index.d.ts +/javascript/asic-js/*.node +/python/**/__pycache__ +/python/pyasic-rs/pyasic_rs/*.pyd +/python/pyasic-rs/pyasic_rs/*.pdb +/python/pyasic-rs/pyasic_rs/*.so /.idea /.vscode /.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 613291de..96804bdd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,6 +18,7 @@ repos: - id: check-added-large-files - id: pretty-format-json args: ["--autofix", "--indent=2"] + exclude: (^|/)package(-lock)?\.json$ - repo: https://github.com/compilerla/conventional-pre-commit rev: v4.0.0 hooks: @@ -36,14 +37,14 @@ repos: - id: uv-lock alias: generate-pyo3-stubs name: generate PyO3 stubs - entry: uvx maturin generate-stubs --features python -o python/pyasic_rs + entry: uvx maturin generate-stubs --manifest-path python/pyasic-rs/Cargo.toml --features python -o python/pyasic-rs/pyasic_rs always_run: true pass_filenames: false - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.20.0 hooks: - id: mypy - args: ["--config-file=pyproject.toml"] + args: ["--config-file=python/pyasic-rs/pyproject.toml"] additional_dependencies: [pydantic==2.12.5] pass_filenames: false - repo: local diff --git a/Cargo.lock b/Cargo.lock index d6aebc39..9b33ab31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,21 @@ dependencies = [ "rustversion", ] +[[package]] +name = "asic-js" +version = "0.7.3" +dependencies = [ + "anyhow", + "asic-rs", + "measurements", + "napi", + "napi-build", + "napi-derive", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "asic-rs" version = "0.7.3" @@ -88,15 +103,10 @@ dependencies = [ "asic-rs-makes-sealminer", "asic-rs-makes-volcminer", "asic-rs-makes-whatsminer", - "asic-rs-pydantic", "async-stream", "futures", "ipnet", "measurements", - "pyo3", - "pyo3-async-runtimes", - "pyo3-build-config", - "pyo3-log", "rand 0.10.0", "rlimit", "serde", @@ -116,6 +126,8 @@ dependencies = [ "futures", "macaddr", "measurements", + "napi", + "napi-derive", "pyo3", "reqwest", "secrecy", @@ -853,6 +865,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -912,6 +933,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d83cb7e7a873830708d6b02a78cd36a592c6fa14bf267b68725103b85c0d77f" + [[package]] name = "deranged" version = "0.5.8" @@ -1589,6 +1616,16 @@ version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +[[package]] +name = "libloading" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" +dependencies = [ + "cfg-if", + "windows-link", +] + [[package]] name = "libm" version = "0.2.16" @@ -1709,6 +1746,72 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "napi" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f71d6bc097c4a6eb853c3f24991ab8c9f50f57d1f719e305175541482217e36" +dependencies = [ + "bitflags", + "ctor", + "futures", + "napi-build", + "napi-sys", + "nohash-hasher", + "rustc-hash", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "napi-build" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5282704fbe8d49b0cf8b08e3f33233416a528658f205c7e5ace63b582de0b11c" + +[[package]] +name = "napi-derive" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5c9c02556ea6dc99dffd36c1ce60141411657438501a125b675776d011ce92" +dependencies = [ + "convert_case", + "ctor", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "napi-derive-backend" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9d8365cf97f54d9b6d6dbf83a25ca227ad7d6e920717426c599225aca6740b" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "semver", + "syn", +] + +[[package]] +name = "napi-sys" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fbf1fa9f1babfe396d74bbbf52b3643770243e8f5b0b46715d4caf7f0dfc9a" +dependencies = [ + "libloading", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "num-conv" version = "0.2.1" @@ -1826,6 +1929,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pyasic-rs" +version = "0.7.3" +dependencies = [ + "anyhow", + "asic-rs", + "asic-rs-core", + "asic-rs-pydantic", + "async-stream", + "futures", + "measurements", + "pyo3", + "pyo3-async-runtimes", + "pyo3-build-config", + "pyo3-log", + "tokio", + "tokio-stream", +] + [[package]] name = "pyo3" version = "0.28.3" @@ -2813,6 +2935,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index dc3ba49a..1cd68bf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,8 @@ members = [ "asic-rs-firmwares/whatsminer", "asic-rs-pydantic", "asic-rs-pydantic-macros", + "python/pyasic-rs", + "javascript/asic-js", ] [workspace.dependencies] @@ -134,10 +136,12 @@ pyo3 = { version = "0.28.2", features = [ "experimental-inspect", "multiple-pymethods", "time", -]} +] } pyo3-async-runtimes = { version = "0.28.0", features = ["tokio-runtime", "unstable-streams"] } pyo3-build-config = { version = "0.28.2" } pyo3-log = { version = "0.13.3" } +napi = { version = "3.0.0", default-features = false } +napi-derive = "3.0.0" [workspace.lints.rust] warnings = "deny" @@ -187,10 +191,6 @@ volcminer = ["dep:asic-rs-firmwares-volcminer"] whatsminer = ["dep:asic-rs-firmwares-whatsminer"] python = [ - "dep:asic-rs-pydantic", - "dep:pyo3", - "dep:pyo3-async-runtimes", - "dep:pyo3-log", "asic-rs-core/python", "asic-rs-makes-antminer/python", "asic-rs-makes-auradine/python", @@ -224,9 +224,12 @@ python = [ "asic-rs-firmwares-whatsminer?/python", ] +javascript = [ + "asic-rs-core/javascript", +] + [dependencies] asic-rs-core.workspace = true -asic-rs-pydantic = { workspace = true, optional = true } asic-rs-makes-antminer.workspace = true asic-rs-makes-auradine.workspace = true @@ -273,13 +276,6 @@ async-stream.workspace = true tracing.workspace = true rlimit.workspace = true -pyo3 = {workspace = true, optional = true} -pyo3-async-runtimes = {workspace = true, optional = true} -pyo3-log = {workspace = true, optional = true} - -[build-dependencies] -pyo3-build-config.workspace = true - [lints] workspace = true @@ -293,4 +289,4 @@ strip = true [lib] name = "asic_rs" -crate-type = ["cdylib", "lib"] +crate-type = ["lib"] diff --git a/asic-rs-core/Cargo.toml b/asic-rs-core/Cargo.toml index 0a6ae047..18503fef 100644 --- a/asic-rs-core/Cargo.toml +++ b/asic-rs-core/Cargo.toml @@ -26,6 +26,9 @@ secrecy.workspace = true asic-rs-pydantic = { workspace = true, optional = true } pyo3 = {workspace = true, optional = true} +napi = { workspace = true, optional = true } +napi-derive = { workspace = true, optional = true } [features] python = ["dep:asic-rs-pydantic", "dep:pyo3"] +javascript = ["dep:napi", "dep:napi-derive"] diff --git a/asic-rs-core/src/data/device.rs b/asic-rs-core/src/data/device.rs index 38e85b2a..0e0b076b 100644 --- a/asic-rs-core/src/data/device.rs +++ b/asic-rs-core/src/data/device.rs @@ -8,6 +8,7 @@ use crate::traits::{firmware::MinerFirmware, model::MinerModel}; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[cfg_attr(feature = "python", pyclass(from_py_object, module = "asic_rs"))] #[cfg_attr(feature = "python", asic_rs_pydantic::py_pydantic_model(getters))] +#[cfg_attr(feature = "javascript", napi_derive::napi(object))] /// Static identity and hardware information for a miner model. pub struct DeviceInfo { /// Miner manufacturer or make. @@ -37,6 +38,7 @@ impl DeviceInfo { #[cfg_attr(feature = "python", pyclass(from_py_object, module = "asic_rs"))] #[cfg_attr(feature = "python", asic_rs_pydantic::py_pydantic_model(getters))] +#[cfg_attr(feature = "javascript", napi_derive::napi(object))] #[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize, Default)] /// Expected hardware counts for a miner model. pub struct MinerHardware { @@ -86,6 +88,7 @@ impl MinerHardware { #[cfg_attr(feature = "python", pyclass(from_py_object, module = "asic_rs"))] #[cfg_attr(feature = "python", derive(asic_rs_pydantic::PyPydanticEnum))] +#[cfg_attr(feature = "javascript", napi_derive::napi(string_enum))] #[derive( Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize, StrumDisplay, EnumString, )] diff --git a/asic-rs-core/src/data/hashrate.rs b/asic-rs-core/src/data/hashrate.rs index 45540f08..e6a365f8 100644 --- a/asic-rs-core/src/data/hashrate.rs +++ b/asic-rs-core/src/data/hashrate.rs @@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "python", pyclass(from_py_object, module = "asic_rs"))] #[cfg_attr(feature = "python", derive(asic_rs_pydantic::PyPydanticEnum))] +#[cfg_attr(feature = "javascript", napi_derive::napi(string_enum))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] /// Unit used to represent a [`HashRate`] value. pub enum HashRateUnit { @@ -181,6 +182,7 @@ impl HashRateUnit { pyclass(from_py_object, get_all, module = "asic_rs") )] #[cfg_attr(feature = "python", asic_rs_pydantic::py_pydantic_model)] +#[cfg_attr(feature = "javascript", napi_derive::napi(object))] #[derive(Debug, Clone, Serialize, Deserialize)] /// Hashrate value with unit and mining algorithm. pub struct HashRate { diff --git a/javascript/asic-js/Cargo.toml b/javascript/asic-js/Cargo.toml new file mode 100644 index 00000000..6b258bf6 --- /dev/null +++ b/javascript/asic-js/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "asic-js" +version.workspace = true +edition.workspace = true +license.workspace = true +documentation.workspace = true +repository.workspace = true +keywords.workspace = true +description = "Node.js bindings for asic-rs" +publish = false + +[lib] +crate-type = ["cdylib"] + +[features] +default = [ + "antminer", + "futurebit", + "auradine", + "avalonminer", + "bitaxe", + "braiins", + "elphapex", + "epic", + "luxminer", + "marathon", + "nerdaxe", + "proto", + "sealminer", + "vnish", + "volcminer", + "whatsminer", +] + +core = ["asic-rs/core", "asic-rs/javascript"] +antminer = ["core", "asic-rs/antminer"] +futurebit = ["core", "asic-rs/futurebit"] +auradine = ["core", "asic-rs/auradine"] +avalonminer = ["core", "asic-rs/avalonminer"] +bitaxe = ["core", "asic-rs/bitaxe"] +braiins = ["core", "asic-rs/braiins"] +elphapex = ["core", "asic-rs/elphapex"] +epic = ["core", "asic-rs/epic"] +luxminer = ["core", "asic-rs/luxminer"] +marathon = ["core", "asic-rs/marathon"] +nerdaxe = ["core", "asic-rs/nerdaxe"] +proto = ["core", "asic-rs/proto"] +sealminer = ["core", "asic-rs/sealminer"] +vnish = ["core", "asic-rs/vnish"] +volcminer = ["core", "asic-rs/volcminer"] +whatsminer = ["core", "asic-rs/whatsminer"] + +[dependencies] +asic-rs = { path = "../..", version = "0.7.3", default-features = false } +anyhow.workspace = true +measurements.workspace = true +napi = { version = "3.0.0", default-features = false, features = ["napi4", "serde-json", "tokio_rt"] } +napi-derive = "3.0.0" +serde.workspace = true +serde_json.workspace = true +tokio.workspace = true + +[build-dependencies] +napi-build = "2.2.3" diff --git a/javascript/asic-js/README.md b/javascript/asic-js/README.md new file mode 100644 index 00000000..fc5ff243 --- /dev/null +++ b/javascript/asic-js/README.md @@ -0,0 +1,42 @@ +# asic-js + +Node.js bindings for `asic-rs`. + +The package mirrors the Python binding's top-level shape: + +- `MinerFactory` discovers miners and constructs `Miner` handles. +- `Miner` exposes telemetry and control methods. +- Rust data models are returned as plain JavaScript objects. + +## Build + +```sh +npm install +npm run build +``` + +## Example + +```js +"use strict"; + +const { MinerFactory } = require("asic-js"); + +async function main() { + const miner = await new MinerFactory().getMiner("192.168.1.10"); + if (!miner) return; + + console.log(miner.make, miner.model, miner.ip); + console.log(miner.deviceInfo); + console.log(await miner.getData()); + + if (miner.supportsRestart) { + await miner.restart(); + } +} + +main().catch((err) => { + console.error(err); + process.exitCode = 1; +}); +``` diff --git a/javascript/asic-js/asic_js/index.d.ts b/javascript/asic-js/asic_js/index.d.ts new file mode 100644 index 00000000..a10ece37 --- /dev/null +++ b/javascript/asic-js/asic_js/index.d.ts @@ -0,0 +1,218 @@ +export type HashAlgorithm = "SHA256" | "Scrypt" | "X11" | "Blake2S256" | "Kadena"; +export type HashRateUnit = + | "Hash" + | "KiloHash" + | "MegaHash" + | "GigaHash" + | "TeraHash" + | "PetaHash" + | "ExaHash" + | "ZettaHash" + | "YottaHash"; +export type MessageSeverity = "Error" | "Warning" | "Info"; +export type PoolScheme = "StratumV1" | "StratumV1SSL" | "StratumV2"; +export type MiningMode = "Low" | "Normal" | "High"; + +export interface MinerHardware { + fans?: number | null; + boards?: Array | null; +} + +export interface DeviceInfo { + make: string; + model: string; + hardware: MinerHardware; + firmware: string; + algo: HashAlgorithm; +} + +export interface HashRate { + value: number; + unit: HashRateUnit; + algo: string; +} + +export interface FanData { + position: number; + rpm?: number | null; +} + +export interface PoolURL { + scheme: PoolScheme; + host: string; + port: number; + pubkey?: string | null; +} + +export interface PoolData { + position?: number | null; + url?: PoolURL | null; + accepted_shares?: number | null; + rejected_shares?: number | null; + active?: boolean | null; + alive?: boolean | null; + user?: string | null; +} + +export interface PoolGroupData { + name: string; + quota: number; + pools: PoolData[]; +} + +export interface MinerComponent { + type: "ControlBoard" | "HashBoard" | "Fan" | "PowerSupply"; + idx?: number; + chip_idx?: number | null; +} + +export interface MinerMessage { + timestamp: number; + code: number; + message: string; + severity: MessageSeverity; + component?: MinerComponent | null; +} + +export type TuningTarget = + | { Power: number } + | { HashRate: HashRate } + | { MiningMode: MiningMode }; + +export interface TuningCapabilities { + power?: { + default?: TuningTarget | null; + minimum?: TuningTarget | null; + maximum?: TuningTarget | null; + } | null; + hashrate?: { + default?: TuningTarget | null; + minimum?: TuningTarget | null; + maximum?: TuningTarget | null; + } | null; + presets?: { + default?: TuningTarget | null; + presets: TuningTarget[]; + } | null; +} + +export interface ChipData { + position: number; + hashrate?: HashRate | null; + temperature?: number | null; + voltage?: number | null; + frequency?: number | null; + tuned?: boolean | null; + working?: boolean | null; +} + +export interface BoardData { + position: number; + hashrate?: HashRate | null; + expected_hashrate?: HashRate | null; + board_temperature?: number | null; + inlet_chip_temperature?: number | null; + outlet_chip_temperature?: number | null; + expected_chips?: number | null; + working_chips?: number | null; + serial_number?: string | null; + chips: ChipData[]; + voltage?: number | null; + frequency?: number | null; + tuned?: boolean | null; + active?: boolean | null; +} + +export interface MinerControlBoard { + known: boolean; + name: string; +} + +export interface MinerData { + schema_version: string; + timestamp: number; + ip: string; + mac?: string | null; + device_info: DeviceInfo; + serial_number?: string | null; + hostname?: string | null; + api_version?: string | null; + firmware_version?: string | null; + control_board_version?: MinerControlBoard | null; + expected_hashboards?: number | null; + hashboards: BoardData[]; + hashrate?: HashRate | null; + expected_hashrate?: HashRate | null; + expected_chips?: number | null; + total_chips?: number | null; + expected_fans?: number | null; + fans: FanData[]; + psu_fans: FanData[]; + average_temperature?: number | null; + fluid_temperature?: number | null; + outlet_fluid_temperature?: number | null; + wattage?: number | null; + tuning_percent?: number | null; + tuning_target?: TuningTarget | null; + scaled_tuning_target?: TuningTarget | null; + tuning_capabilities?: TuningCapabilities | null; + efficiency?: number | null; + light_flashing?: boolean | null; + messages: MinerMessage[]; + uptime?: { secs: number; nanos: number } | null; + is_mining: boolean; + pools: PoolGroupData[]; +} + +export class MinerFactory { + constructor(); + static fromSubnet(subnet: string): MinerFactory; + static fromRange(range: string): MinerFactory; + static fromOctets(octet1: string | number, octet2: string | number, octet3: string | number, octet4: string | number): MinerFactory; + withSubnet(subnet: string): this; + withRange(range: string): this; + withOctets(octet1: string | number, octet2: string | number, octet3: string | number, octet4: string | number): this; + withConcurrentLimit(concurrent: number): this; + getMiner(ip: string): Promise; + scan(): Promise; +} + +export class Miner { + readonly ip: string; + readonly model: string; + readonly make: string; + readonly firmware: string; + readonly deviceInfo: DeviceInfo; + readonly supportsSetFaultLight: boolean; + readonly supportsSetPowerLimit: boolean; + readonly supportsSetTuningPercent: boolean; + readonly supportsRestart: boolean; + readonly supportsPause: boolean; + readonly supportsResume: boolean; + setAuth(username: string, password: string): Promise; + setToken(token: string): Promise; + getData(): Promise; + getHashrate(): Promise; + getExpectedHashrate(): Promise; + getFans(): Promise; + getPsuFans(): Promise; + getPools(): Promise; + getMessages(): Promise; + getDeviceInfo(): Promise; + getMac(): Promise; + getSerialNumber(): Promise; + getHostname(): Promise; + getApiVersion(): Promise; + getFirmwareVersion(): Promise; + getWattage(): Promise; + getFluidTemperature(): Promise; + getOutletFluidTemperature(): Promise; + getTuningPercent(): Promise; + getIsMining(): Promise; + restart(): Promise; + pause(): Promise; + resume(): Promise; + setFaultLight(fault: boolean): Promise; + setPowerLimit(watts: number): Promise; + setTuningPercent(percent: number): Promise; +} diff --git a/javascript/asic-js/asic_js/index.js b/javascript/asic-js/asic_js/index.js new file mode 100644 index 00000000..19edbdcf --- /dev/null +++ b/javascript/asic-js/asic_js/index.js @@ -0,0 +1,216 @@ +"use strict"; + +const native = require("./native"); + +class Miner { + constructor(inner) { + this.inner = inner; + } + + get ip() { + return this.inner.ip; + } + + get model() { + return this.inner.model; + } + + get make() { + return this.inner.make; + } + + get firmware() { + return this.inner.firmware; + } + + get deviceInfo() { + return this.inner.deviceInfo; + } + + get supportsSetFaultLight() { + return this.inner.supportsSetFaultLight; + } + + get supportsSetPowerLimit() { + return this.inner.supportsSetPowerLimit; + } + + get supportsSetTuningPercent() { + return this.inner.supportsSetTuningPercent; + } + + get supportsRestart() { + return this.inner.supportsRestart; + } + + get supportsPause() { + return this.inner.supportsPause; + } + + get supportsResume() { + return this.inner.supportsResume; + } + + async setAuth(username, password) { + return this.inner.setAuth(username, password); + } + + async setToken(token) { + return this.inner.setToken(token); + } + + async getData() { + return this.inner.getData(); + } + + async getHashrate() { + return this.inner.getHashrate(); + } + + async getExpectedHashrate() { + return this.inner.getExpectedHashrate(); + } + + async getFans() { + return this.inner.getFans(); + } + + async getPsuFans() { + return this.inner.getPsuFans(); + } + + async getPools() { + return this.inner.getPools(); + } + + async getMessages() { + return this.inner.getMessages(); + } + + async getDeviceInfo() { + return this.inner.getDeviceInfo(); + } + + getMac() { + return this.inner.getMac(); + } + + getSerialNumber() { + return this.inner.getSerialNumber(); + } + + getHostname() { + return this.inner.getHostname(); + } + + getApiVersion() { + return this.inner.getApiVersion(); + } + + getFirmwareVersion() { + return this.inner.getFirmwareVersion(); + } + + getWattage() { + return this.inner.getWattage(); + } + + getFluidTemperature() { + return this.inner.getFluidTemperature(); + } + + getOutletFluidTemperature() { + return this.inner.getOutletFluidTemperature(); + } + + getTuningPercent() { + return this.inner.getTuningPercent(); + } + + getIsMining() { + return this.inner.getIsMining(); + } + + restart() { + return this.inner.restart(); + } + + pause() { + return this.inner.pause(); + } + + resume() { + return this.inner.resume(); + } + + setFaultLight(fault) { + return this.inner.setFaultLight(fault); + } + + setPowerLimit(watts) { + return this.inner.setPowerLimit(watts); + } + + setTuningPercent(percent) { + return this.inner.setTuningPercent(percent); + } +} + +class MinerFactory { + constructor(inner = new native.MinerFactory()) { + this.inner = inner; + } + + static fromSubnet(subnet) { + return new MinerFactory(native.MinerFactory.fromSubnet(subnet)); + } + + static fromRange(range) { + return new MinerFactory(native.MinerFactory.fromRange(range)); + } + + static fromOctets(octet1, octet2, octet3, octet4) { + return new MinerFactory( + native.MinerFactory.fromOctets( + String(octet1), + String(octet2), + String(octet3), + String(octet4), + ), + ); + } + + withSubnet(subnet) { + this.inner.withSubnet(subnet); + return this; + } + + withRange(range) { + this.inner.withRange(range); + return this; + } + + withOctets(octet1, octet2, octet3, octet4) { + this.inner.withOctets(String(octet1), String(octet2), String(octet3), String(octet4)); + return this; + } + + withConcurrentLimit(concurrent) { + this.inner.withConcurrentLimit(concurrent); + return this; + } + + async getMiner(ip) { + const miner = await this.inner.getMiner(ip); + return miner ? new Miner(miner) : null; + } + + async scan() { + return (await this.inner.scan()).map((miner) => new Miner(miner)); + } +} + +module.exports = { + Miner, + MinerFactory, +}; diff --git a/javascript/asic-js/asic_js/native.js b/javascript/asic-js/asic_js/native.js new file mode 100644 index 00000000..408d31ce --- /dev/null +++ b/javascript/asic-js/asic_js/native.js @@ -0,0 +1,53 @@ +"use strict"; + +const path = require("path"); + +function platformCandidates() { + const platform = process.platform; + const arch = process.arch; + + if (platform === "win32") { + return [`../index.${platform}-${arch}-msvc.node`]; + } + + if (platform === "darwin") { + return [`../index.${platform}-${arch}.node`]; + } + + if (platform === "linux") { + return [ + `../index.${platform}-${arch}-gnu.node`, + `../index.${platform}-${arch}-musl.node`, + `../index.${platform}-${arch}-gnueabihf.node`, + ]; + } + + if (platform === "freebsd") { + return [`../index.${platform}-${arch}.node`]; + } + + return []; +} + +const candidates = [ + "../asic-js.node", + "../asic_js.node", + ...platformCandidates(), + "../target/release/asic_js.node", + "../target/debug/asic_js.node", + "../../../target/release/asic_js.node", + "../../../target/debug/asic_js.node", +]; + +for (const candidate of candidates) { + try { + module.exports = require(path.join(__dirname, candidate)); + return; + } catch (err) { + if (err.code !== "MODULE_NOT_FOUND") throw err; + } +} + +throw new Error( + "The asic-js native module is not built. Run `npm run build` in javascript/asic-js.", +); diff --git a/javascript/asic-js/build.rs b/javascript/asic-js/build.rs new file mode 100644 index 00000000..0f1b0100 --- /dev/null +++ b/javascript/asic-js/build.rs @@ -0,0 +1,3 @@ +fn main() { + napi_build::setup(); +} diff --git a/javascript/asic-js/package-lock.json b/javascript/asic-js/package-lock.json new file mode 100644 index 00000000..448fe4ed --- /dev/null +++ b/javascript/asic-js/package-lock.json @@ -0,0 +1,2005 @@ +{ + "lockfileVersion": 3, + "name": "asic-js", + "packages": { + "": { + "devDependencies": { + "@napi-rs/cli": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "license": "Apache-2.0", + "name": "asic-js", + "version": "0.7.3" + }, + "node_modules/@emnapi/core": { + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "version": "1.11.2" + }, + "node_modules/@emnapi/runtime": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==", + "license": "MIT", + "optional": true, + "peer": true, + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz", + "version": "2.0.0-alpha.3" + }, + "node_modules/@emnapi/wasi-threads": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "version": "1.2.2" + }, + "node_modules/@inquirer/ansi": { + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "version": "2.0.7" + }, + "node_modules/@inquirer/checkbox": { + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", + "version": "5.2.1" + }, + "node_modules/@inquirer/confirm": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", + "version": "6.1.1" + }, + "node_modules/@inquirer/core": { + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "version": "11.2.1" + }, + "node_modules/@inquirer/editor": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/external-editor": "^3.0.3", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", + "version": "5.2.2" + }, + "node_modules/@inquirer/expand": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", + "version": "5.1.1" + }, + "node_modules/@inquirer/external-editor": { + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", + "version": "3.0.3" + }, + "node_modules/@inquirer/figures": { + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "version": "2.0.7" + }, + "node_modules/@inquirer/input": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", + "version": "5.1.2" + }, + "node_modules/@inquirer/number": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", + "version": "4.1.1" + }, + "node_modules/@inquirer/password": { + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", + "version": "5.1.1" + }, + "node_modules/@inquirer/prompts": { + "dependencies": { + "@inquirer/checkbox": "^5.2.1", + "@inquirer/confirm": "^6.1.1", + "@inquirer/editor": "^5.2.2", + "@inquirer/expand": "^5.1.1", + "@inquirer/input": "^5.1.2", + "@inquirer/number": "^4.1.1", + "@inquirer/password": "^5.1.1", + "@inquirer/rawlist": "^5.3.1", + "@inquirer/search": "^4.2.1", + "@inquirer/select": "^5.2.1" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", + "version": "8.5.2" + }, + "node_modules/@inquirer/rawlist": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", + "version": "5.3.1" + }, + "node_modules/@inquirer/search": { + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", + "version": "4.2.1" + }, + "node_modules/@inquirer/select": { + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", + "version": "5.2.1" + }, + "node_modules/@inquirer/type": { + "dev": true, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", + "license": "MIT", + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "version": "4.0.7" + }, + "node_modules/@napi-rs/cli": { + "bin": { + "napi": "dist/cli.js", + "napi-raw": "cli.mjs" + }, + "dependencies": { + "@inquirer/prompts": "^8.5.2", + "@napi-rs/cross-toolchain": "^1.0.3", + "@napi-rs/wasm-tools": "^1.0.1", + "@octokit/rest": "^22.0.1", + "clipanion": "^4.0.0-rc.4", + "colorette": "^2.0.20", + "emnapi": "2.0.0-alpha.3", + "es-toolkit": "^1.47.0", + "js-yaml": "^4.2.0", + "obug": "^2.1.2", + "semver": "^7.8.2", + "typanion": "^3.14.0", + "typescript": "^6.0.3" + }, + "dev": true, + "engines": { + "node": "^20.17.0 || ^22.13.0 || >= 23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "integrity": "sha512-iFmp3Lo/ipXoJI1I/6V/xU4hQV42bXS3A7j8C+Wt3LOtYY7HFCilkhyUkN1igLJFXWMICq95kNxhNcwzNRd+Kw==", + "license": "MIT", + "peerDependencies": { + "@emnapi/runtime": "2.0.0-alpha.3" + }, + "peerDependenciesMeta": { + "@emnapi/runtime": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.8.2.tgz", + "version": "3.8.2" + }, + "node_modules/@napi-rs/cross-toolchain": { + "dependencies": { + "@napi-rs/lzma": "^1.4.5", + "@napi-rs/tar": "^1.1.0", + "debug": "^4.4.1" + }, + "dev": true, + "integrity": "sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==", + "license": "MIT", + "peerDependencies": { + "@napi-rs/cross-toolchain-arm64-target-aarch64": "^1.0.3", + "@napi-rs/cross-toolchain-arm64-target-armv7": "^1.0.3", + "@napi-rs/cross-toolchain-arm64-target-ppc64le": "^1.0.3", + "@napi-rs/cross-toolchain-arm64-target-s390x": "^1.0.3", + "@napi-rs/cross-toolchain-arm64-target-x86_64": "^1.0.3", + "@napi-rs/cross-toolchain-x64-target-aarch64": "^1.0.3", + "@napi-rs/cross-toolchain-x64-target-armv7": "^1.0.3", + "@napi-rs/cross-toolchain-x64-target-ppc64le": "^1.0.3", + "@napi-rs/cross-toolchain-x64-target-s390x": "^1.0.3", + "@napi-rs/cross-toolchain-x64-target-x86_64": "^1.0.3" + }, + "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-ppc64le": { + "optional": true + }, + "@napi-rs/cross-toolchain-arm64-target-s390x": { + "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-ppc64le": { + "optional": true + }, + "@napi-rs/cross-toolchain-x64-target-s390x": { + "optional": true + }, + "@napi-rs/cross-toolchain-x64-target-x86_64": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/@napi-rs/cross-toolchain/-/cross-toolchain-1.0.3.tgz", + "version": "1.0.3", + "workspaces": [ + ".", + "arm64/*", + "x64/*" + ] + }, + "node_modules/@napi-rs/lzma": { + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "integrity": "sha512-sgOZ89+y8cDbY+3WbzR8CtIhCuFRWotZ9/2PjPVDJHz6np5KFTAev0DrwiyTJTgFsCRDhfGlbmhMgyhHbWdZ6g==", + "license": "MIT", + "optionalDependencies": { + "@napi-rs/lzma-android-arm-eabi": "1.5.1", + "@napi-rs/lzma-android-arm64": "1.5.1", + "@napi-rs/lzma-darwin-arm64": "1.5.1", + "@napi-rs/lzma-darwin-x64": "1.5.1", + "@napi-rs/lzma-freebsd-x64": "1.5.1", + "@napi-rs/lzma-linux-arm-gnueabihf": "1.5.1", + "@napi-rs/lzma-linux-arm64-gnu": "1.5.1", + "@napi-rs/lzma-linux-arm64-musl": "1.5.1", + "@napi-rs/lzma-linux-ppc64-gnu": "1.5.1", + "@napi-rs/lzma-linux-riscv64-gnu": "1.5.1", + "@napi-rs/lzma-linux-s390x-gnu": "1.5.1", + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@napi-rs/lzma-linux-x64-musl": "1.5.1", + "@napi-rs/lzma-wasm32-wasi": "1.5.1", + "@napi-rs/lzma-win32-arm64-msvc": "1.5.1", + "@napi-rs/lzma-win32-ia32-msvc": "1.5.1", + "@napi-rs/lzma-win32-x64-msvc": "1.5.1" + }, + "resolved": "https://registry.npmjs.org/@napi-rs/lzma/-/lzma-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-android-arm-eabi": { + "cpu": [ + "arm" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-sahBe4ko2Z69NPTddaX6ZgbQZu9SDoITxw1S3dWl1gAGynZG34qHHCT8UaUMFxf3h3zMhCJjEzz4basaBxiTuQ==", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-android-arm-eabi/-/lzma-android-arm-eabi-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-android-arm64": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-7tkQAJJuBHxAxiEBNFgSTpvrtGpbwZYYJUSOmGEK3OfbdbNeoT2rdBxpM/gY1s+itEVbtOSlpaRPPG19MnwOzA==", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-android-arm64/-/lzma-android-arm64-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-darwin-arm64": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-XWX8gtF+GHGk3nH3Wm3QUZNcxw9QHsFVZz3MzVLhWWHhceede1J4/vD+3dj3E1iKB9G6mualaZxOoD08R3E+7g==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-darwin-arm64/-/lzma-darwin-arm64-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-darwin-x64": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-CfsqUpMTI1z8enrA/b+GcHM6YDI8D0kqCiqPYEnst4rbOABQ9KZ92ybTTNnlnZ7A017WoMZKUEWc36KXDwi0xg==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-darwin-x64/-/lzma-darwin-x64-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-freebsd-x64": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-bTyNfg90FXIgE61U7l14aMmVOqRQ6AyP5JMT3jmCStaZI18apLNPdzZ8i7yqxZfKvRMVfPjE2brXIw27c+RRgA==", + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-freebsd-x64/-/lzma-freebsd-x64-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-arm-gnueabihf": { + "cpu": [ + "arm" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-vNE+D8nrw+eOkBsdKCsmDhowDV3pIMKXEhedvXfbgrWbrO7GlZJH+RXL+X+RYLxGwi8Ym61ZMt15sIOnNmh9Sw==", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-arm-gnueabihf/-/lzma-linux-arm-gnueabihf-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-arm64-gnu": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-csUem4WgoKGTprv/pOPm9UIWbb+hrfUwYXefpTHPAEGVFLl5behEFabisJ7FtihCa3yG2Efcl+yw25rlhhrIYw==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-arm64-gnu/-/lzma-linux-arm64-gnu-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-arm64-musl": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-kB/xhlVN1eLvVmDJSKZEjp5Gg2xDYexNrB5jwpSMbOkeGS6N9AasByPBg5VqCpMYC+zZi7DM458DRhtWYhqXTQ==", + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-arm64-musl/-/lzma-linux-arm64-musl-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-ppc64-gnu": { + "cpu": [ + "ppc64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-s28RW0W1yBWQc1nbPdF7tp14koqslY3ZWLVI8uaanX292Dc6ezd4NPVwxEoCNBVON/oD7BmUbWGtyFvmm7dQ5A==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-ppc64-gnu/-/lzma-linux-ppc64-gnu-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-riscv64-gnu": { + "cpu": [ + "riscv64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-+lGNwYlIN14YPMTNvYtIJJqHFevDTd6Juw/1NmXbWx/iRd/LLrjhlM/yluMX6pxs6NkOGsuuEXJJrbbEUS59OQ==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-riscv64-gnu/-/lzma-linux-riscv64-gnu-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-s390x-gnu": { + "cpu": [ + "s390x" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-PB44FFWWFrLeQowhcep1hPD1YcLqKlnnY60RMU74qrxTlr4YGEyzeMItJqh2uivBfv9kQScOF/B0J9+Vab/oyw==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-s390x-gnu/-/lzma-linux-s390x-gnu-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-linux-x64-musl": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-I3nsYrWtrW9JpeCr+mkJIVDt0HY3m6qVUBs5vTtoIvJQxwqf1PBXSy5IS7T53ksQFH2kd2UX8rLxJ7B4WISpZg==", + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-musl/-/lzma-linux-x64-musl-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-wasm32-wasi": { + "cpu": [ + "wasm32" + ], + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-gy3wwPBa6+XEyA4fUzq6CClrXA1ajXjuVf5zbnHytJRgoHznj+mvpU3+co2fxXwqTCmIpn6KrzqH5bRDztBPhA==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-wasm32-wasi/-/lzma-wasm32-wasi-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-wasm32-wasi/node_modules/@emnapi/runtime": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "version": "1.11.2" + }, + "node_modules/@napi-rs/lzma-win32-arm64-msvc": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-dK+huOsHiyH6oJjij+cnjqFCakk2HgWmpI12Xm4pLUyPphe4ebYoJBgehaNAxprmjFqBQ7nL95YPVz9BHyqmPg==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-win32-arm64-msvc/-/lzma-win32-arm64-msvc-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-win32-ia32-msvc": { + "cpu": [ + "ia32" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-dGE8L+0EQ+GyU9ap9InqB/t/PmPG/bLj918q7OsJ29FuTdn8fK4OX3U4IQZhylHIA+/dQ/SXJk5n4yfah2XVvA==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-win32-ia32-msvc/-/lzma-win32-ia32-msvc-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/lzma-win32-x64-msvc": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": "^22.20 || ^24.12 || >=25" + }, + "integrity": "sha512-EKW4t/iqdCT/xnd5t9oXLvVER/PMNAWXKqUAl3fgvUcOILeZIIht77/dVnfFcc9htA/DCBXC/6YQWdW+LusjFA==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-win32-x64-msvc/-/lzma-win32-x64-msvc-1.5.1.tgz", + "version": "1.5.1" + }, + "node_modules/@napi-rs/tar": { + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-p6q2HhUc5vwH1CNwfOcrhLoxfgn8ust8Sqlfx+sA4VzAcp1cMbvbkl99tZZlDqOjCHgQNSiTfk/yWPjl/D42qA==", + "license": "MIT", + "optionalDependencies": { + "@napi-rs/tar-android-arm-eabi": "1.1.1", + "@napi-rs/tar-android-arm64": "1.1.1", + "@napi-rs/tar-darwin-arm64": "1.1.1", + "@napi-rs/tar-darwin-x64": "1.1.1", + "@napi-rs/tar-freebsd-x64": "1.1.1", + "@napi-rs/tar-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/tar-linux-arm64-gnu": "1.1.1", + "@napi-rs/tar-linux-arm64-musl": "1.1.1", + "@napi-rs/tar-linux-ppc64-gnu": "1.1.1", + "@napi-rs/tar-linux-s390x-gnu": "1.1.1", + "@napi-rs/tar-linux-x64-gnu": "1.1.1", + "@napi-rs/tar-linux-x64-musl": "1.1.1", + "@napi-rs/tar-wasm32-wasi": "1.1.1", + "@napi-rs/tar-win32-arm64-msvc": "1.1.1", + "@napi-rs/tar-win32-ia32-msvc": "1.1.1", + "@napi-rs/tar-win32-x64-msvc": "1.1.1" + }, + "resolved": "https://registry.npmjs.org/@napi-rs/tar/-/tar-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-android-arm-eabi": { + "cpu": [ + "arm" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-cAhnA10cSusAUbcE9HtjQY/tZ9BH/0w2sKtRcQc94TzIlnm7QSr1htJSd/PPrbWNPtrv1orXb2CkrHlVlbnlHA==", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-android-arm-eabi/-/tar-android-arm-eabi-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-android-arm64": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-EslUWHCDBY/g5abTPBiHLsMaML4GagV0TXLm5WL9hAjx/DDtlxz9fegMb77RJ+f7nFLOIsUxF/3QWFvgOT0sMQ==", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-android-arm64/-/tar-android-arm64-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-darwin-arm64": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-+A42/6ES5G9CQ35BOwzwA+WBjLID28r2jNPgc0dteD2hhClIhng0mva7D2ujUlXBNmgNOsr1LHn3stA4uTf4NQ==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-darwin-arm64/-/tar-darwin-arm64-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-darwin-x64": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-RYtE8w1dkEvj8hSJCDV5Jw0Rz2i13fsM7u893zv5O9n/4Ad5GNsw/f4RQ7/0YGSFaenkVxqPFrjmEvUHlKzsrg==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-darwin-x64/-/tar-darwin-x64-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-freebsd-x64": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-rEepBvCJUwcuvUYkY83e8aot8RsR5Jcnal4PsG3tbWGKW1yAvcXhyMXf0fN6ZGpVRZFnB+FJqDyBxvsCPEXKhw==", + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-freebsd-x64/-/tar-freebsd-x64-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-arm-gnueabihf": { + "cpu": [ + "arm" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-an1bJdfyhI5FpZYyTQ20mrqwR+a676i8GkaYc4Uy12dH/a7TJIfrK6Qa2Gm46arZvxUvx56qxoRKXbpOjUPvwA==", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-arm-gnueabihf/-/tar-linux-arm-gnueabihf-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-arm64-gnu": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-w++Vtx36T2yHTKws7GVnmHHcUT1ybB59xLWSh9A8bwEpJVG4dG7Qub9mFe5cpcbfrJ+XP2mKKxC3oUJSunK3iQ==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-arm64-gnu/-/tar-linux-arm64-gnu-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-arm64-musl": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-Rh6UFhNtj3i4deJHOBINFIeRL0072mgbeyuK5rl1HokKnNoMKx8qKIZNEzBTTqpogMfDHWGvzyTQdnVxes5dpA==", + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-arm64-musl/-/tar-linux-arm64-musl-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-ppc64-gnu": { + "cpu": [ + "ppc64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-Cp+AxFbv9zcyAXtnzQi0OzmgDnQgy2w9D4Ubr+iwzMtVgJcztzcEoCcCrN1k2ATdEB01LX2Vb49IaocGOZhC9Q==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-ppc64-gnu/-/tar-linux-ppc64-gnu-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-s390x-gnu": { + "cpu": [ + "s390x" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-ZyscC3SYKTBWyDRYjLOKAd5TyJ7q0KACRdQ8bWrb3rgrra1CCIJD66CsGTH6Dh0AVSdfLwZ8MfIIXU6+14BMjQ==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-s390x-gnu/-/tar-linux-s390x-gnu-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-x64-gnu": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-LlIv+zg4fiOQge9LQX/ieBdRWE2fhVDjCTHxnunZkbugNmdhdelxWf1RpZb/6ZujWpNF4LPu4N/MW7ygg2oYAQ==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-x64-gnu/-/tar-linux-x64-gnu-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-linux-x64-musl": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-gZBeoKLjanOVj55qk4EMu13P2i9M0SuINmlGQkOxm1niIJofexzddHUYtqO5o/5QqtyL8lADmAcZplLILMLhHA==", + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-linux-x64-musl/-/tar-linux-x64-musl-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-wasm32-wasi": { + "cpu": [ + "wasm32" + ], + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "integrity": "sha512-rwtQ1Mdt/ft6g6I54fJzbUeLspl4yTwj6I3UJ6mitKnrN42soJkcDrdh3Y/FGvlpqZTad2YMQ96fGJl3EtAm2Q==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@napi-rs/tar-wasm32-wasi/-/tar-wasm32-wasi-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-wasm32-wasi/node_modules/@emnapi/runtime": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "version": "1.11.2" + }, + "node_modules/@napi-rs/tar-win32-arm64-msvc": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-30PVp1AehRpfwxmv5wI4cg0yj3WmWBsZ+1QnLGnvEELu7Eu/+dhNU0nrmhI7VfPgLwSRK2eg9DQTB3tP7Wv9bA==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-win32-arm64-msvc/-/tar-win32-arm64-msvc-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-win32-ia32-msvc": { + "cpu": [ + "ia32" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-aI3/rmz+izUChiSeaPxcasAOxhf3FpJNuIHMXlxS/vpW+HIxUsSDR5+XV61PEG5DL4L/75iENVUxmSGM5l2yaw==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-win32-ia32-msvc/-/tar-win32-ia32-msvc-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/tar-win32-x64-msvc": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 10" + }, + "integrity": "sha512-yJsB2IsrODQVLKbm2Fg1nHiVRbEj49mSPbj4x7JPZWJI0jGVPjohE2Sif0FBbx8OxsVoUODvS0BwksZZ8jl/OA==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/tar-win32-x64-msvc/-/tar-win32-x64-msvc-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/@napi-rs/wasm-runtime": { + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "integrity": "sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==", + "license": "MIT", + "optional": true, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3" + }, + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", + "version": "1.2.2" + }, + "node_modules/@napi-rs/wasm-tools": { + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-VjHyKEqXAwYZK+HY7iJctYvRm3TFEbaQxeZwvAG1QRkoo1a39phMY8J6x9tUEqJI03W6MysB8F2jacI6wvcx+w==", + "license": "MIT", + "optionalDependencies": { + "@napi-rs/wasm-tools-android-arm-eabi": "1.1.0", + "@napi-rs/wasm-tools-android-arm64": "1.1.0", + "@napi-rs/wasm-tools-darwin-arm64": "1.1.0", + "@napi-rs/wasm-tools-darwin-x64": "1.1.0", + "@napi-rs/wasm-tools-freebsd-x64": "1.1.0", + "@napi-rs/wasm-tools-linux-arm64-gnu": "1.1.0", + "@napi-rs/wasm-tools-linux-arm64-musl": "1.1.0", + "@napi-rs/wasm-tools-linux-x64-gnu": "1.1.0", + "@napi-rs/wasm-tools-linux-x64-musl": "1.1.0", + "@napi-rs/wasm-tools-wasm32-wasi": "1.1.0", + "@napi-rs/wasm-tools-win32-arm64-msvc": "1.1.0", + "@napi-rs/wasm-tools-win32-ia32-msvc": "1.1.0", + "@napi-rs/wasm-tools-win32-x64-msvc": "1.1.0" + }, + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools/-/wasm-tools-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-android-arm-eabi": { + "cpu": [ + "arm" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-p6J8PB59I8d/XItXB/go5JH6nKW+xIbpzaL43EBTV0hi7mrS/Z4gs+MsB04ZrlqZN29BdZV8fChRyasuXLhRaA==", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-android-arm-eabi/-/wasm-tools-android-arm-eabi-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-android-arm64": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-lWoKN3suypeBSCIRPIw+++sH9V2K6nQkhtdt1opu7XY3v9JwLs6Gw063HWRqkNjphlYpkd/Qy8XcfSPGbJj7nQ==", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-android-arm64/-/wasm-tools-android-arm64-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-darwin-arm64": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-jfw5vyNDUf6oe0kP8lMveFN9U7cLk1cUosS7uMIfw/xmqmopYfKQ198DAx2g/6aEF7Tm+CqER2gpMpYKui30LA==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-darwin-arm64/-/wasm-tools-darwin-arm64-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-darwin-x64": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-R+pjeudAB7BYdH1vKkOJM61Tfv5jB6uXkxmFscYd+KKpdUpWBlNG+s4hr0w4i1rMBM91VhIAETZn2pz+MDHK9A==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-darwin-x64/-/wasm-tools-darwin-x64-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-freebsd-x64": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-hQJTe+aazrT++Vgm6I4lUd9099ItUCFYdd+aKg6Ys6nax6d/cZ1barDLTwA2lwOoVDsXMekJI/FOL6ZvVlIYBg==", + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-freebsd-x64/-/wasm-tools-freebsd-x64-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-linux-arm64-gnu": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-1TAXJxUHsWGar90k3W/MknavvBMwOWzjh7Q6Spxo8twRcWJbBD5Kow/Q2KhhDq5hxh2sKGDXn3uLc1tdtz4WUg==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-linux-arm64-gnu/-/wasm-tools-linux-arm64-gnu-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-linux-arm64-musl": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-7rw3nlubTjNAVRH2LwphCxHy1b/N2/TerXocQ6XRn4Q+buaY1Z7P/hbdALy1i1ex2yfOU2Xcij7ib7ZLi/lKfw==", + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-linux-arm64-musl/-/wasm-tools-linux-arm64-musl-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-linux-x64-gnu": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-1sel0t9MRjI/tdT89M8Dd6gPfANeeFP24Xa46R11WeHNwhjsXXZh+xUk50uWCRTSGcaCy3ugm3AMK/lmHYQJkg==", + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-linux-x64-gnu/-/wasm-tools-linux-x64-gnu-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-linux-x64-musl": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-o2jH5AMfor4EKF2HII1LBnMQxoWu7+usPifTEY8Zk6e9OiSi4EJkAXf9v3ANlX7TI2V/cUEV34OEW7r10GiVIA==", + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-linux-x64-musl/-/wasm-tools-linux-x64-musl-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-wasm32-wasi": { + "cpu": [ + "wasm32" + ], + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "integrity": "sha512-s6YDtDR1UWrsqJPtaxf+JLYLceWVyn3l8OpQYElHkDhf3Qfz9R6Ba3S0OgznTBv38L5/TIHysQ9Q4yO73Z0csg==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-wasm32-wasi/-/wasm-tools-wasm32-wasi-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-wasm32-wasi/node_modules/@emnapi/core": { + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "version": "1.9.2" + }, + "node_modules/@napi-rs/wasm-tools-wasm32-wasi/node_modules/@emnapi/runtime": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "version": "1.9.2" + }, + "node_modules/@napi-rs/wasm-tools-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "version": "1.2.1" + }, + "node_modules/@napi-rs/wasm-tools-win32-arm64-msvc": { + "cpu": [ + "arm64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-x+NuxbG84VxU68tU8w7Rf5lSyq0l584M6dVlke5DTweHYFZoMyeqkpbwEq+qsyAX6ivfipK8xRsmFwamb5uDnA==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-win32-arm64-msvc/-/wasm-tools-win32-arm64-msvc-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-win32-ia32-msvc": { + "cpu": [ + "ia32" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-mdD96QDEp70SX67rXFTY6c725nVYeqEEjyDqzzbNh6u1APj7CI7IMNpMmvE75XbCRl4C2MHZVU4U6AWdAzvyQQ==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-win32-ia32-msvc/-/wasm-tools-win32-ia32-msvc-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@napi-rs/wasm-tools-win32-x64-msvc": { + "cpu": [ + "x64" + ], + "dev": true, + "engines": { + "node": ">= 12.22.0" + }, + "integrity": "sha512-bVVjuvhlyVX++3eJXfDR63cXdw1ay5QYac6iq0MKQw8wZARInTM+bXCtByDT4fzVFI3+7ZthYb/ERWRdBNIqgQ==", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-tools-win32-x64-msvc/-/wasm-tools-win32-x64-msvc-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/@octokit/auth-token": { + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "version": "6.0.0" + }, + "node_modules/@octokit/core": { + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.4", + "@octokit/request": "^10.0.13", + "@octokit/request-error": "^7.1.1", + "@octokit/types": "^17.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-DcB0M3KFgr9ECI328lhBMVsyFT2DnmNucSBTqEN3exyNKUzkkpUSCHmTRcunF41Eou2TIQKW4seewri8ON9bSA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.7.tgz", + "version": "7.0.7" + }, + "node_modules/@octokit/endpoint": { + "dependencies": { + "@octokit/types": "^17.0.0", + "universal-user-agent": "^7.0.2" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-f1cOWoHPmxryJFknxbtDdjODWfV8A9tc8Aae6ermXPNgHFZ/x91AtHIz4gicEjL8hkJiip+u21QHJORfBv/qiA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.4.tgz", + "version": "11.0.4" + }, + "node_modules/@octokit/graphql": { + "dependencies": { + "@octokit/request": "^10.0.13", + "@octokit/types": "^17.0.0", + "universal-user-agent": "^7.0.0" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-5s15CCiY8XXQ+FG+b1YQcl6Z2FA++nwAz/tg2VUrTmnMncP+2nnGUEYANImdnxsA2Fnq+Mbl7hDjUTw7cFAwcg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.4.tgz", + "version": "9.0.4" + }, + "node_modules/@octokit/openapi-types": { + "dev": true, + "integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz", + "version": "28.0.0" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "license": "MIT", + "peerDependencies": { + "@octokit/core": ">=6" + }, + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "version": "14.0.0" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "dev": true, + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "version": "27.0.0" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + }, + "dev": true, + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "version": "16.0.0" + }, + "node_modules/@octokit/plugin-request-log": { + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "license": "MIT", + "peerDependencies": { + "@octokit/core": ">=6" + }, + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "version": "6.0.0" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", + "license": "MIT", + "peerDependencies": { + "@octokit/core": ">=6" + }, + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", + "version": "17.0.0" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { + "dev": true, + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "version": "27.0.0" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + }, + "dev": true, + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "version": "16.0.0" + }, + "node_modules/@octokit/request": { + "dependencies": { + "@octokit/endpoint": "^11.0.3", + "@octokit/request-error": "^7.1.1", + "@octokit/types": "^17.0.0", + "content-type": "^2.0.0", + "json-with-bigint": "^3.5.3", + "universal-user-agent": "^7.0.2" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-v2269YxL9Yf+x3d+gRI63FP0vFQEiWgLyBzxe/Y+0yFDg2B/Tzf5dhh9VNfccVAQnfcfwQWyk/y6Bn7rUXXs7A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.13.tgz", + "version": "10.0.13" + }, + "node_modules/@octokit/request-error": { + "dependencies": { + "@octokit/types": "^17.0.0" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-+eaY7G2VVpSf2pc5Gn1+mph837V/d/TYTJAgWL9Tb0ogGYcpN3IlAVFgjL+Vv93F/sevrxkvsYCedtpLdcFLzA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.1.tgz", + "version": "7.1.1" + }, + "node_modules/@octokit/rest": { + "dependencies": { + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-request-log": "^6.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0" + }, + "dev": true, + "engines": { + "node": ">= 20" + }, + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "version": "22.0.1" + }, + "node_modules/@octokit/types": { + "dependencies": { + "@octokit/openapi-types": "^28.0.0" + }, + "dev": true, + "integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz", + "version": "17.0.0" + }, + "node_modules/@tybys/wasm-util": { + "dependencies": { + "tslib": "^2.4.0" + }, + "dev": true, + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "version": "0.10.3" + }, + "node_modules/argparse": { + "dev": true, + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "version": "2.0.1" + }, + "node_modules/before-after-hook": { + "dev": true, + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "version": "4.0.0" + }, + "node_modules/chardet": { + "dev": true, + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "version": "2.2.0" + }, + "node_modules/cli-width": { + "dev": true, + "engines": { + "node": ">= 12" + }, + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "version": "4.1.0" + }, + "node_modules/clipanion": { + "dependencies": { + "typanion": "^3.8.0" + }, + "dev": true, + "integrity": "sha512-CXkMQxU6s9GklO/1f714dkKBMu1lopS1WFF0B8o4AxPykR1hpozxSiUZ5ZUeBjfPgCWqbcNOtZVFhB8Lkfp1+Q==", + "license": "MIT", + "peerDependencies": { + "typanion": "*" + }, + "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-4.0.0-rc.4.tgz", + "version": "4.0.0-rc.4", + "workspaces": [ + "website" + ] + }, + "node_modules/colorette": { + "dev": true, + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "version": "2.0.20" + }, + "node_modules/content-type": { + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + }, + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "version": "2.0.0" + }, + "node_modules/debug": { + "dependencies": { + "ms": "^2.1.3" + }, + "dev": true, + "engines": { + "node": ">=6.0" + }, + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "version": "4.4.3" + }, + "node_modules/emnapi": { + "dev": true, + "integrity": "sha512-K9bc9Xx4OwSfhJpdSOpcfIKzn7/6emuubaIorf6I5e7WBAM79665rf6iHr9y50NL4qYMUP/AheTpD1Z4yU1EBw==", + "license": "MIT", + "peerDependencies": { + "node-addon-api": ">= 6.1.0" + }, + "peerDependenciesMeta": { + "node-addon-api": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/emnapi/-/emnapi-2.0.0-alpha.3.tgz", + "version": "2.0.0-alpha.3" + }, + "node_modules/es-toolkit": { + "dev": true, + "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", + "version": "1.50.0", + "workspaces": [ + "docs", + "benchmarks", + "tests/types" + ] + }, + "node_modules/fast-string-truncated-width": { + "dev": true, + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "version": "3.0.3" + }, + "node_modules/fast-string-width": { + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + }, + "dev": true, + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "version": "3.0.2" + }, + "node_modules/fast-wrap-ansi": { + "dependencies": { + "fast-string-width": "^3.0.2" + }, + "dev": true, + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "version": "0.2.2" + }, + "node_modules/iconv-lite": { + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + }, + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "version": "0.7.3" + }, + "node_modules/js-yaml": { + "bin": { + "js-yaml": "bin/js-yaml.js" + }, + "dependencies": { + "argparse": "^2.0.1" + }, + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "version": "4.3.1" + }, + "node_modules/json-with-bigint": { + "dev": true, + "integrity": "sha512-Vcx+JVNEBts/xfcoCS69sKrOhOk/3TVlvlT+XzUOefVKnnrbYSCKpDCm10pohsJFtsJVYnwa/cXRZ4eElzaM6w==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.10.tgz", + "version": "3.5.10" + }, + "node_modules/ms": { + "dev": true, + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "version": "2.1.3" + }, + "node_modules/mute-stream": { + "dev": true, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "version": "3.0.0" + }, + "node_modules/obug": { + "dev": true, + "engines": { + "node": ">=12.20.0" + }, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "version": "2.1.4" + }, + "node_modules/safer-buffer": { + "dev": true, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "version": "2.1.2" + }, + "node_modules/semver": { + "bin": { + "semver": "bin/semver.js" + }, + "dev": true, + "engines": { + "node": ">=10" + }, + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "version": "7.8.5" + }, + "node_modules/signal-exit": { + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "version": "4.1.0" + }, + "node_modules/tslib": { + "dev": true, + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true, + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "version": "2.8.1" + }, + "node_modules/typanion": { + "dev": true, + "integrity": "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/typanion/-/typanion-3.14.0.tgz", + "version": "3.14.0", + "workspaces": [ + "website" + ] + }, + "node_modules/typescript": { + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "dev": true, + "engines": { + "node": ">=14.17" + }, + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "version": "6.0.3" + }, + "node_modules/universal-user-agent": { + "dev": true, + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "version": "7.0.3" + } + }, + "requires": true, + "version": "0.7.3" +} diff --git a/javascript/asic-js/package.json b/javascript/asic-js/package.json new file mode 100644 index 00000000..c804dc94 --- /dev/null +++ b/javascript/asic-js/package.json @@ -0,0 +1,30 @@ +{ + "description": "Node.js bindings for asic-rs", + "devDependencies": { + "@napi-rs/cli": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "files": [ + "asic_js", + "*.node" + ], + "license": "Apache-2.0", + "main": "asic_js/index.js", + "name": "asic-js", + "repository": { + "directory": "javascript/asic-js", + "type": "git", + "url": "https://github.com/256foundation/asic-rs.git" + }, + "scripts": { + "build": "napi build --platform --release", + "build:bitaxe": "napi build --platform --release --no-default-features --features bitaxe", + "build:debug": "napi build --platform", + "test": "node --test tests/*.test.js" + }, + "type": "commonjs", + "types": "asic_js/index.d.ts", + "version": "0.7.3" +} diff --git a/javascript/asic-js/src/factory.rs b/javascript/asic-js/src/factory.rs new file mode 100644 index 00000000..920df7d7 --- /dev/null +++ b/javascript/asic-js/src/factory.rs @@ -0,0 +1,113 @@ +use std::{net::IpAddr, str::FromStr, sync::Arc}; + +use asic_rs::MinerFactory as MinerFactoryBase; +use napi::Result; +use napi_derive::napi; + +use crate::{miner::JsMiner, to_napi_error}; + +#[napi(js_name = "MinerFactory")] +pub struct JsMinerFactory { + inner: Arc, +} + +#[napi] +impl JsMinerFactory { + #[napi(constructor)] + pub fn new() -> Self { + Self { + inner: Arc::new(MinerFactoryBase::new()), + } + } + + #[napi(factory, js_name = "fromSubnet")] + pub fn from_subnet(subnet: String) -> Result { + Ok(Self { + inner: Arc::new(MinerFactoryBase::from_subnet(&subnet).map_err(to_napi_error)?), + }) + } + + #[napi(factory, js_name = "fromRange")] + pub fn from_range(range: String) -> Result { + Ok(Self { + inner: Arc::new(MinerFactoryBase::from_range(&range).map_err(to_napi_error)?), + }) + } + + #[napi(factory, js_name = "fromOctets")] + pub fn from_octets( + octet1: String, + octet2: String, + octet3: String, + octet4: String, + ) -> Result { + Ok(Self { + inner: Arc::new( + MinerFactoryBase::from_octets(&octet1, &octet2, &octet3, &octet4) + .map_err(to_napi_error)?, + ), + }) + } + + #[napi(js_name = "withSubnet")] + pub fn with_subnet(&mut self, subnet: String) -> Result<&Self> { + let inner = Arc::::make_mut(&mut self.inner).clone(); + self.inner = Arc::new(inner.with_subnet(&subnet).map_err(to_napi_error)?); + Ok(self) + } + + #[napi(js_name = "withRange")] + pub fn with_range(&mut self, range: String) -> Result<&Self> { + let inner = Arc::::make_mut(&mut self.inner).clone(); + self.inner = Arc::new(inner.with_range(&range).map_err(to_napi_error)?); + Ok(self) + } + + #[napi(js_name = "withOctets")] + pub fn with_octets( + &mut self, + octet1: String, + octet2: String, + octet3: String, + octet4: String, + ) -> Result<&Self> { + let inner = Arc::::make_mut(&mut self.inner).clone(); + self.inner = Arc::new( + inner + .with_octets(&octet1, &octet2, &octet3, &octet4) + .map_err(to_napi_error)?, + ); + Ok(self) + } + + #[napi(js_name = "withConcurrentLimit")] + pub fn with_concurrent_limit(&mut self, concurrent: u32) -> &Self { + let inner = Arc::::make_mut(&mut self.inner).clone(); + self.inner = Arc::new(inner.with_concurrent_limit(concurrent as usize)); + self + } + + #[napi(js_name = "getMiner")] + pub async fn get_miner(&self, ip: String) -> Result> { + let ip = IpAddr::from_str(&ip).map_err(to_napi_error)?; + let miner = self + .inner + .get_miner(ip) + .await + .map_err(to_napi_error)? + .map(JsMiner::new); + Ok(miner) + } + + #[napi] + pub async fn scan(&self) -> Result> { + Ok(self + .inner + .scan() + .await + .map_err(to_napi_error)? + .into_iter() + .map(JsMiner::new) + .collect()) + } +} diff --git a/javascript/asic-js/src/lib.rs b/javascript/asic-js/src/lib.rs new file mode 100644 index 00000000..fc2d4ecd --- /dev/null +++ b/javascript/asic-js/src/lib.rs @@ -0,0 +1,12 @@ +mod factory; +mod miner; + +use napi::{Error, Result, Status}; + +fn to_napi_error(error: impl std::fmt::Display) -> Error { + Error::new(Status::GenericFailure, error.to_string()) +} + +fn to_js_value(value: T) -> Result { + serde_json::to_value(value).map_err(to_napi_error) +} diff --git a/javascript/asic-js/src/miner.rs b/javascript/asic-js/src/miner.rs new file mode 100644 index 00000000..d605910d --- /dev/null +++ b/javascript/asic-js/src/miner.rs @@ -0,0 +1,286 @@ +use std::sync::Arc; + +use asic_rs::core::{ + data::{device::DeviceInfo, hashrate::HashRate}, + traits::miner::{Miner as MinerTrait, MinerAuth}, +}; +use measurements::Power; +use napi::{Error, Result, Status}; +use napi_derive::napi; +use tokio::sync::RwLock; + +use crate::{to_js_value, to_napi_error}; + +#[napi(js_name = "Miner")] +pub struct JsMiner { + inner: Arc>>, +} + +impl JsMiner { + pub(crate) fn new(inner: Box) -> Self { + Self { + inner: Arc::new(RwLock::new(inner)), + } + } + + fn with_miner(&self, f: impl FnOnce(&dyn MinerTrait) -> T) -> T { + let inner = self.inner.blocking_read(); + f(inner.as_ref()) + } +} + +#[napi] +impl JsMiner { + #[napi(getter)] + pub fn ip(&self) -> String { + self.with_miner(|miner| miner.get_ip().to_string()) + } + + #[napi(getter)] + pub fn model(&self) -> String { + self.with_miner(|miner| miner.get_device_info().model) + } + + #[napi(getter)] + pub fn make(&self) -> String { + self.with_miner(|miner| miner.get_device_info().make) + } + + #[napi(getter)] + pub fn firmware(&self) -> String { + self.with_miner(|miner| miner.get_device_info().firmware) + } + + #[napi(getter, js_name = "deviceInfo")] + pub fn device_info(&self) -> DeviceInfo { + self.with_miner(|miner| miner.get_device_info()) + } + + #[napi(getter, js_name = "supportsSetFaultLight")] + pub fn supports_set_fault_light(&self) -> bool { + self.with_miner(|miner| miner.supports_set_fault_light()) + } + + #[napi(getter, js_name = "supportsSetPowerLimit")] + pub fn supports_set_power_limit(&self) -> bool { + self.with_miner(|miner| miner.supports_set_power_limit()) + } + + #[napi(getter, js_name = "supportsSetTuningPercent")] + pub fn supports_set_tuning_percent(&self) -> bool { + self.with_miner(|miner| miner.supports_set_tuning_percent()) + } + + #[napi(getter, js_name = "supportsRestart")] + pub fn supports_restart(&self) -> bool { + self.with_miner(|miner| miner.supports_restart()) + } + + #[napi(getter, js_name = "supportsPause")] + pub fn supports_pause(&self) -> bool { + self.with_miner(|miner| miner.supports_pause()) + } + + #[napi(getter, js_name = "supportsResume")] + pub fn supports_resume(&self) -> bool { + self.with_miner(|miner| miner.supports_resume()) + } + + #[napi(js_name = "setAuth")] + pub async fn set_auth(&self, username: String, password: String) { + self.inner + .write() + .await + .set_auth(MinerAuth::new(username, password)); + } + + #[napi(js_name = "setToken")] + pub async fn set_token(&self, token: String) { + self.inner + .write() + .await + .set_auth(MinerAuth::from_token(token)); + } + + #[napi(js_name = "getData")] + pub async fn get_data(&self) -> Result { + let data = self.inner.read().await.get_data().await; + to_js_value(data) + } + + #[napi(js_name = "getHashrate")] + pub async fn get_hashrate(&self) -> Option { + self.inner.read().await.get_hashrate().await + } + + #[napi(js_name = "getExpectedHashrate")] + pub async fn get_expected_hashrate(&self) -> Option { + self.inner.read().await.get_expected_hashrate().await + } + + #[napi(js_name = "getFans")] + pub async fn get_fans(&self) -> Result { + let data = self.inner.read().await.get_fans().await; + to_js_value(data) + } + + #[napi(js_name = "getPsuFans")] + pub async fn get_psu_fans(&self) -> Result { + let data = self.inner.read().await.get_psu_fans().await; + to_js_value(data) + } + + #[napi(js_name = "getPools")] + pub async fn get_pools(&self) -> Result { + let data = self.inner.read().await.get_pools().await; + to_js_value(data) + } + + #[napi(js_name = "getMessages")] + pub async fn get_messages(&self) -> Result { + let data = self.inner.read().await.get_messages().await; + to_js_value(data) + } + + #[napi(js_name = "getDeviceInfo")] + pub fn get_device_info(&self) -> DeviceInfo { + self.with_miner(|miner| miner.get_device_info()) + } + + #[napi(js_name = "getMac")] + pub async fn get_mac(&self) -> Option { + self.inner + .read() + .await + .get_mac() + .await + .map(|value| value.to_string()) + } + + #[napi(js_name = "getSerialNumber")] + pub async fn get_serial_number(&self) -> Option { + self.inner.read().await.get_serial_number().await + } + + #[napi(js_name = "getHostname")] + pub async fn get_hostname(&self) -> Option { + self.inner.read().await.get_hostname().await + } + + #[napi(js_name = "getApiVersion")] + pub async fn get_api_version(&self) -> Option { + self.inner.read().await.get_api_version().await + } + + #[napi(js_name = "getFirmwareVersion")] + pub async fn get_firmware_version(&self) -> Option { + self.inner.read().await.get_firmware_version().await + } + + #[napi(js_name = "getWattage")] + pub async fn get_wattage(&self) -> Option { + self.inner + .read() + .await + .get_wattage() + .await + .map(|p| p.as_watts()) + } + + #[napi(js_name = "getFluidTemperature")] + pub async fn get_fluid_temperature(&self) -> Option { + self.inner + .read() + .await + .get_fluid_temperature() + .await + .map(|t| t.as_celsius()) + } + + #[napi(js_name = "getOutletFluidTemperature")] + pub async fn get_outlet_fluid_temperature(&self) -> Option { + self.inner + .read() + .await + .get_outlet_fluid_temperature() + .await + .map(|t| t.as_celsius()) + } + + #[napi(js_name = "getTuningPercent")] + pub async fn get_tuning_percent(&self) -> Option { + self.inner + .read() + .await + .get_tuning_percent() + .await + .map(u32::from) + } + + #[napi(js_name = "getIsMining")] + pub async fn get_is_mining(&self) -> bool { + self.inner.read().await.get_is_mining().await + } + + #[napi(js_name = "restart")] + pub async fn restart(&self) -> Result { + self.inner + .read() + .await + .restart() + .await + .map_err(to_napi_error) + } + + #[napi(js_name = "pause")] + pub async fn pause(&self) -> Result { + self.inner + .read() + .await + .pause(None) + .await + .map_err(to_napi_error) + } + + #[napi(js_name = "resume")] + pub async fn resume(&self) -> Result { + self.inner + .read() + .await + .resume(None) + .await + .map_err(to_napi_error) + } + + #[napi(js_name = "setFaultLight")] + pub async fn set_fault_light(&self, fault: bool) -> Result { + self.inner + .read() + .await + .set_fault_light(fault) + .await + .map_err(to_napi_error) + } + + #[napi(js_name = "setPowerLimit")] + pub async fn set_power_limit(&self, watts: f64) -> Result { + self.inner + .read() + .await + .set_power_limit(Power::from_watts(watts)) + .await + .map_err(to_napi_error) + } + + #[napi(js_name = "setTuningPercent")] + pub async fn set_tuning_percent(&self, percent: u32) -> Result { + let percent = u8::try_from(percent) + .map_err(|_| Error::new(Status::InvalidArg, "percent must fit in u8"))?; + self.inner + .read() + .await + .set_tuning_percent(percent) + .await + .map_err(to_napi_error) + } +} diff --git a/python/__init__.py b/python/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/python/pyasic-rs/Cargo.toml b/python/pyasic-rs/Cargo.toml new file mode 100644 index 00000000..6fb7448a --- /dev/null +++ b/python/pyasic-rs/Cargo.toml @@ -0,0 +1,73 @@ +[package] +name = "pyasic-rs" +version.workspace = true +edition.workspace = true +license.workspace = true +documentation.workspace = true +repository.workspace = true +keywords.workspace = true +description = "Python bindings for asic-rs" +publish = false + +[lib] +name = "asic_rs" +crate-type = ["cdylib"] + +[features] +default = [ + "antminer", + "futurebit", + "auradine", + "avalonminer", + "bitaxe", + "braiins", + "elphapex", + "epic", + "luxminer", + "marathon", + "nerdaxe", + "proto", + "sealminer", + "vnish", + "volcminer", + "whatsminer", +] + +python = ["core"] +core = ["asic-rs/core", "asic-rs/python"] +antminer = ["core", "asic-rs/antminer"] +futurebit = ["core", "asic-rs/futurebit"] +auradine = ["core", "asic-rs/auradine"] +avalonminer = ["core", "asic-rs/avalonminer"] +bitaxe = ["core", "asic-rs/bitaxe"] +braiins = ["core", "asic-rs/braiins"] +elphapex = ["core", "asic-rs/elphapex"] +epic = ["core", "asic-rs/epic"] +luxminer = ["core", "asic-rs/luxminer"] +marathon = ["core", "asic-rs/marathon"] +nerdaxe = ["core", "asic-rs/nerdaxe"] +proto = ["core", "asic-rs/proto"] +sealminer = ["core", "asic-rs/sealminer"] +vnish = ["core", "asic-rs/vnish"] +volcminer = ["core", "asic-rs/volcminer"] +whatsminer = ["core", "asic-rs/whatsminer"] + +[dependencies] +asic-rs = { path = "../..", version = "0.7.3", default-features = false } +asic-rs-core.workspace = true +asic-rs-pydantic.workspace = true +anyhow.workspace = true +async-stream.workspace = true +futures.workspace = true +measurements.workspace = true +pyo3.workspace = true +pyo3-async-runtimes.workspace = true +pyo3-log.workspace = true +tokio.workspace = true +tokio-stream.workspace = true + +[build-dependencies] +pyo3-build-config.workspace = true + +[lints] +workspace = true diff --git a/build.rs b/python/pyasic-rs/build.rs similarity index 100% rename from build.rs rename to python/pyasic-rs/build.rs diff --git a/python/pyasic_rs/__init__.py b/python/pyasic-rs/pyasic_rs/__init__.py similarity index 100% rename from python/pyasic_rs/__init__.py rename to python/pyasic-rs/pyasic_rs/__init__.py diff --git a/python/pyasic_rs/asic_rs.pyi b/python/pyasic-rs/pyasic_rs/asic_rs.pyi similarity index 100% rename from python/pyasic_rs/asic_rs.pyi rename to python/pyasic-rs/pyasic_rs/asic_rs.pyi diff --git a/python/pyasic_rs/config.py b/python/pyasic-rs/pyasic_rs/config.py similarity index 100% rename from python/pyasic_rs/config.py rename to python/pyasic-rs/pyasic_rs/config.py diff --git a/python/pyasic_rs/data.py b/python/pyasic-rs/pyasic_rs/data.py similarity index 100% rename from python/pyasic_rs/data.py rename to python/pyasic-rs/pyasic_rs/data.py diff --git a/python/pyasic_rs/factory.py b/python/pyasic-rs/pyasic_rs/factory.py similarity index 100% rename from python/pyasic_rs/factory.py rename to python/pyasic-rs/pyasic_rs/factory.py diff --git a/python/pyasic_rs/listener.py b/python/pyasic-rs/pyasic_rs/listener.py similarity index 100% rename from python/pyasic_rs/listener.py rename to python/pyasic-rs/pyasic_rs/listener.py diff --git a/python/pyasic_rs/miner.py b/python/pyasic-rs/pyasic_rs/miner.py similarity index 100% rename from python/pyasic_rs/miner.py rename to python/pyasic-rs/pyasic_rs/miner.py diff --git a/python/pyasic_rs/py.typed b/python/pyasic-rs/pyasic_rs/py.typed similarity index 100% rename from python/pyasic_rs/py.typed rename to python/pyasic-rs/pyasic_rs/py.typed diff --git a/pyproject.toml b/python/pyasic-rs/pyproject.toml similarity index 91% rename from pyproject.toml rename to python/pyasic-rs/pyproject.toml index 65d7cab8..376b7247 100644 --- a/pyproject.toml +++ b/python/pyasic-rs/pyproject.toml @@ -14,7 +14,7 @@ documentation = "https://256foundation.github.io/asic-rs" issues = "https://github.com/256foundation/asic-rs/issues" license = "Apache-2.0" -readme = "docs-shared/guide.md" +readme = "../../docs-shared/guide.md" requires-python = ">=3.11, <4.0" dependencies = [ @@ -57,11 +57,12 @@ test = [ package-name = "pyasic_rs" module-name = "pyasic_rs.asic_rs" features = ["python"] -python-source = "python" +python-source = "." +manifest-path = "Cargo.toml" [tool.mypy] -files = ["python/pyasic_rs"] -mypy_path = ["python"] +files = ["python/pyasic-rs/pyasic_rs"] +mypy_path = ["python/pyasic-rs"] explicit_package_bases = true plugins = ["pydantic.mypy"] python_version = "3.11" diff --git a/src/python/factory.rs b/python/pyasic-rs/src/factory.rs similarity index 98% rename from src/python/factory.rs rename to python/pyasic-rs/src/factory.rs index cd0f719a..0acdb042 100644 --- a/src/python/factory.rs +++ b/python/pyasic-rs/src/factory.rs @@ -7,15 +7,13 @@ use std::{ }; use crate::{ - factory::MinerFactory as MinerFactory_Base, - python::{ - miner::Miner, - typing::{ - CancelAction, PyAsyncIterator, PyAwaitable, abortable_future_into_py_with_cancel, - future_into_py, - }, + miner::Miner, + typing::{ + CancelAction, PyAsyncIterator, PyAwaitable, abortable_future_into_py_with_cancel, + future_into_py, }, }; +use asic_rs::MinerFactory as MinerFactory_Base; use asic_rs_core::traits::miner::Miner as MinerTrait; use asic_rs_pydantic::py_to_string; use futures::{Stream, StreamExt}; diff --git a/src/python/mod.rs b/python/pyasic-rs/src/lib.rs similarity index 100% rename from src/python/mod.rs rename to python/pyasic-rs/src/lib.rs diff --git a/src/python/listener.rs b/python/pyasic-rs/src/listener.rs similarity index 97% rename from src/python/listener.rs rename to python/pyasic-rs/src/listener.rs index 55fbd012..7982c212 100644 --- a/src/python/listener.rs +++ b/python/pyasic-rs/src/listener.rs @@ -5,12 +5,10 @@ use std::{ }; use crate::{ - listener::MinerListener as MinerListenerBase, - python::{ - miner::Miner, - typing::{CancelAction, PyAsyncIterator, abortable_future_into_py_with_cancel}, - }, + miner::Miner, + typing::{CancelAction, PyAsyncIterator, abortable_future_into_py_with_cancel}, }; +use asic_rs::MinerListener as MinerListenerBase; use asic_rs_core::traits::miner::Miner as MinerTrait; use async_stream::stream; use futures::Stream; diff --git a/src/python/miner.rs b/python/pyasic-rs/src/miner.rs similarity index 100% rename from src/python/miner.rs rename to python/pyasic-rs/src/miner.rs diff --git a/src/python/typing.rs b/python/pyasic-rs/src/typing.rs similarity index 100% rename from src/python/typing.rs rename to python/pyasic-rs/src/typing.rs diff --git a/python/tests/test_pydantic_interop.py b/python/pyasic-rs/tests/test_pydantic_interop.py similarity index 100% rename from python/tests/test_pydantic_interop.py rename to python/pyasic-rs/tests/test_pydantic_interop.py diff --git a/src/factory.rs b/src/factory.rs index 9399e257..78d0aa28 100644 --- a/src/factory.rs +++ b/src/factory.rs @@ -137,6 +137,27 @@ async fn get_miner_type_from_command_catch_unwind( /// when multiple responses are received for the same device. #[allow(clippy::vec_init_then_push)] pub fn default_firmware_registry() -> Vec> { + #[cfg_attr( + not(any( + feature = "antminer", + feature = "auradine", + feature = "avalonminer", + feature = "bitaxe", + feature = "braiins", + feature = "elphapex", + feature = "epic", + feature = "futurebit", + feature = "luxminer", + feature = "marathon", + feature = "nerdaxe", + feature = "proto", + feature = "sealminer", + feature = "vnish", + feature = "volcminer", + feature = "whatsminer", + )), + allow(unused_mut) + )] let mut registry: Vec> = vec![]; #[cfg(feature = "braiins")] diff --git a/src/lib.rs b/src/lib.rs index a3394bcc..af5e7c26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,5 +39,3 @@ pub use asic_rs_firmwares_whatsminer as whatsminer; pub mod factory; pub mod listener; -#[cfg(feature = "python")] -mod python;