diff --git a/.github/workflows/ci-build-upload-binaries.yml b/.github/workflows/ci-build-upload-binaries.yml index 928cd92a52..5e693bbe69 100644 --- a/.github/workflows/ci-build-upload-binaries.yml +++ b/.github/workflows/ci-build-upload-binaries.yml @@ -26,6 +26,7 @@ jobs: runs-on: ${{ matrix.platform }} env: CARGO_TERM_COLOR: always + RUSTUP_PERMIT_COPY_RENAME: 1 steps: - uses: actions/checkout@v4 @@ -99,7 +100,6 @@ jobs: cp target/release/nymvisor $OUTPUT_DIR cp target/release/nym-node $OUTPUT_DIR cp target/release/nym-cli $OUTPUT_DIR - cp target/release/explorer-api $OUTPUT_DIR if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then cp target/debian/*.deb $OUTPUT_DIR fi diff --git a/.github/workflows/ci-build-vpn-api-wasm.yml b/.github/workflows/ci-build-vpn-api-wasm.yml index a4abd8fa3e..76694ecca0 100644 --- a/.github/workflows/ci-build-vpn-api-wasm.yml +++ b/.github/workflows/ci-build-vpn-api-wasm.yml @@ -12,6 +12,7 @@ jobs: runs-on: arc-ubuntu-22.04 env: CARGO_TERM_COLOR: always + RUSTUP_PERMIT_COPY_RENAME: 1 steps: - name: Check out repository code uses: actions/checkout@v4 diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 72ee5560ec..314b8176d8 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -37,6 +37,7 @@ jobs: env: CARGO_TERM_COLOR: always IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }} + RUSTUP_PERMIT_COPY_RENAME: 1 steps: - name: Install Dependencies (Linux) run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4e17091f..439e561002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,104 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// ## [Unreleased] +## [2025.5-chokito] (2025-03-18) + +- build(deps): bump braces from 3.0.2 to 3.0.3 in /sdk/typescript/packages/nodejs-client ([#5611]) +- build(deps-dev): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /wasm/client/internal-dev ([#5610]) +- Export lane queue lengths in sdk ([#5609]) +- Chore/more payment watcher debug endpoints ([#5608]) +- build(deps): bump @babel/helpers from 7.24.4 to 7.26.10 ([#5606]) +- Chore/update bls12 381 fork ([#5605]) +- chore: change auth v2 timestamp skew and allow values from the future ([#5604]) +- Chore/payment watcher debug endpoints ([#5601]) +- Allow resetting all SURB sender tags ([#5600]) +- introduce internal tool for checking signer status ([#5598]) +- build(deps-dev): bump webpack from 5.77.0 to 5.98.0 in /wasm/mix-fetch/internal-dev ([#5597]) +- build(deps): bump body-parser and express in /wasm/mix-fetch/internal-dev ([#5596]) +- build(deps): bump serve-static and express in /wasm/mix-fetch/internal-dev ([#5594]) +- build(deps-dev): bump ws from 8.13.0 to 8.18.1 in /wasm/mix-fetch/internal-dev ([#5593]) +- build(deps): bump cookie and express in /wasm/client/internal-dev ([#5592]) +- build(deps): bump cookie and express in /wasm/mix-fetch/internal-dev ([#5591]) +- build(deps): bump braces from 3.0.2 to 3.0.3 in /wasm/zknym-lib/internal-dev ([#5590]) +- build(deps): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /wasm/zknym-lib/internal-dev ([#5589]) +- build(deps): bump tempfile from 3.17.1 to 3.18.0 ([#5588]) +- build(deps): bump tokio from 1.43.0 to 1.44.0 ([#5587]) +- build(deps): bump the patch-updates group with 8 updates ([#5585]) +- build(deps): bump ring from 0.17.9 to 0.17.13 ([#5583]) +- delete double memo field in send modal ([#5578]) +- Server Side internal DoT/DoH opt out ([#5577]) +- Rust SDK SURB example: change hardcoded file to tempdir ([#5576]) +- Add /v3/nym-nodes ([#5569]) +- chore: start sending v2 sphinx packets ([#5554]) +- build(deps): bump the patch-updates group across 1 directory with 14 updates ([#5549]) +- build(deps): bump uuid from 1.13.2 to 1.15.1 ([#5542]) +- build(deps): bump rs_merkle from 1.4.2 to 1.5.0 ([#5541]) +- feature: v2 authentication request ([#5537]) +- Set RUSTUP_PERMIT_COPY_RENAME ([#5533]) +- feature: disallow routing mix packets to nodes not present in the topology ([#5526]) +- Make "Memo" visible per default on send NYM ([#5524]) +- feat: make sure any terminated task kills the watcher and write run info to db ([#5517]) +- Another total_stake SQL fix ([#5516]) +- Fix total_stake on SQL update ([#5514]) +- build(deps): bump flate2 from 1.0.35 to 1.1.0 ([#5510]) +- build(deps): bump itertools from 0.13.0 to 0.14.0 ([#5509]) +- build(deps): bump the patch-updates group with 2 updates ([#5505]) +- Treat gateways as Nym Nodes ([#5504]) +- Update version in Cargo.toml ([#5503]) +- feat: use ct_eq for checking bearer token ([#5501]) +- Add extra args for the probe ([#5499]) +- Fix stats bug & remove HM caching ([#5495]) +- fix: Cargo.lock for contracts ([#5489]) +- Display error messages if IPv4 or IPv6 address not found on nymtun0 ([#5465]) + +[#5611]: https://github.com/nymtech/nym/pull/5611 +[#5610]: https://github.com/nymtech/nym/pull/5610 +[#5609]: https://github.com/nymtech/nym/pull/5609 +[#5608]: https://github.com/nymtech/nym/pull/5608 +[#5606]: https://github.com/nymtech/nym/pull/5606 +[#5605]: https://github.com/nymtech/nym/pull/5605 +[#5604]: https://github.com/nymtech/nym/pull/5604 +[#5601]: https://github.com/nymtech/nym/pull/5601 +[#5600]: https://github.com/nymtech/nym/pull/5600 +[#5598]: https://github.com/nymtech/nym/pull/5598 +[#5597]: https://github.com/nymtech/nym/pull/5597 +[#5596]: https://github.com/nymtech/nym/pull/5596 +[#5594]: https://github.com/nymtech/nym/pull/5594 +[#5593]: https://github.com/nymtech/nym/pull/5593 +[#5592]: https://github.com/nymtech/nym/pull/5592 +[#5591]: https://github.com/nymtech/nym/pull/5591 +[#5590]: https://github.com/nymtech/nym/pull/5590 +[#5589]: https://github.com/nymtech/nym/pull/5589 +[#5588]: https://github.com/nymtech/nym/pull/5588 +[#5587]: https://github.com/nymtech/nym/pull/5587 +[#5585]: https://github.com/nymtech/nym/pull/5585 +[#5583]: https://github.com/nymtech/nym/pull/5583 +[#5578]: https://github.com/nymtech/nym/pull/5578 +[#5577]: https://github.com/nymtech/nym/pull/5577 +[#5576]: https://github.com/nymtech/nym/pull/5576 +[#5569]: https://github.com/nymtech/nym/pull/5569 +[#5554]: https://github.com/nymtech/nym/pull/5554 +[#5549]: https://github.com/nymtech/nym/pull/5549 +[#5542]: https://github.com/nymtech/nym/pull/5542 +[#5541]: https://github.com/nymtech/nym/pull/5541 +[#5537]: https://github.com/nymtech/nym/pull/5537 +[#5533]: https://github.com/nymtech/nym/pull/5533 +[#5526]: https://github.com/nymtech/nym/pull/5526 +[#5524]: https://github.com/nymtech/nym/pull/5524 +[#5517]: https://github.com/nymtech/nym/pull/5517 +[#5516]: https://github.com/nymtech/nym/pull/5516 +[#5514]: https://github.com/nymtech/nym/pull/5514 +[#5510]: https://github.com/nymtech/nym/pull/5510 +[#5509]: https://github.com/nymtech/nym/pull/5509 +[#5505]: https://github.com/nymtech/nym/pull/5505 +[#5504]: https://github.com/nymtech/nym/pull/5504 +[#5503]: https://github.com/nymtech/nym/pull/5503 +[#5501]: https://github.com/nymtech/nym/pull/5501 +[#5499]: https://github.com/nymtech/nym/pull/5499 +[#5495]: https://github.com/nymtech/nym/pull/5495 +[#5489]: https://github.com/nymtech/nym/pull/5489 +[#5465]: https://github.com/nymtech/nym/pull/5465 + ## [2025.4-dorina-patched] (2025-03-06) - use legacy crypto for constructing SURB headers ([#5579]) diff --git a/Cargo.lock b/Cargo.lock index 1d41821313..1f46209661 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ dependencies = [ "macroific", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -26,19 +26,13 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -77,7 +71,7 @@ dependencies = [ "cipher", "ctr", "ghash", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -91,7 +85,7 @@ dependencies = [ "cipher", "ctr", "polyval", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -116,7 +110,7 @@ dependencies = [ "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy 0.7.34", + "zerocopy 0.7.35", ] [[package]] @@ -145,9 +139,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "ammonia" @@ -185,9 +179,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -200,49 +194,50 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -267,15 +262,15 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "assert-json-diff" @@ -320,16 +315,16 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.0", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -338,24 +333,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -368,7 +363,7 @@ dependencies = [ "futures-util", "log", "pin-project-lite", - "rustls-native-certs 0.7.0", + "rustls-native-certs 0.7.3", "rustls-pki-types", "tokio", "tokio-rustls 0.25.0", @@ -418,9 +413,9 @@ checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "autodoc" @@ -443,7 +438,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.32", "itoa", "matchit", "memchr", @@ -460,9 +455,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core 0.4.5", @@ -470,7 +465,7 @@ dependencies = [ "bytes", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "hyper 1.6.0", "hyper-util", @@ -485,7 +480,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tower 0.5.2", "tower-layer", @@ -499,7 +494,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eefda7e2b27e1bda4d6fa8a06b50803b8793769045918bc37ad062d48a6efac" dependencies = [ - "axum 0.7.7", + "axum 0.7.9", "forwarded-header-value", "serde", ] @@ -531,12 +526,12 @@ dependencies = [ "bytes", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", @@ -544,25 +539,26 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" +checksum = "c794b30c904f0a1c2fb7740f7df7f7972dfaa14ef6f57cb6178dc63e5dca2f04" dependencies = [ - "axum 0.7.7", + "axum 0.7.9", "axum-core 0.4.5", "bytes", + "fastrand 2.3.0", "futures-util", "headers", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "mime", + "multer 3.1.0", "pin-project-lite", "serde", "tower 0.5.2", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -573,20 +569,21 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "axum-test" -version = "16.2.0" +version = "16.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3254184de359bbae2a8ca10b050870a7a4f1c8332a2c27d53f360b9835bb3911" +checksum = "63e3a443d2608936a02a222da7b746eb412fede7225b3030b64fe9be99eab8dc" dependencies = [ "anyhow", "assert-json-diff", "auto-future", - "axum 0.7.7", + "axum 0.7.9", "bytes", + "bytesize", "cookie", "http 1.2.0", "http-body-util", @@ -607,17 +604,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.3", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -693,15 +690,15 @@ dependencies = [ "ripemd", "secp256k1", "sha2 0.10.8", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] [[package]] name = "bip39" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ "bitcoin_hashes", "rand 0.8.5", @@ -712,10 +709,20 @@ dependencies = [ ] [[package]] -name = "bitcoin_hashes" -version = "0.11.0" +name = "bitcoin-internals" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] [[package]] name = "bitflags" @@ -725,9 +732,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" dependencies = [ "serde", ] @@ -767,9 +774,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.5" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +checksum = "675f87afced0413c9bb02843499dbbd3882a237645883f71a2b59644a6d2f753" dependencies = [ "arrayref", "arrayvec", @@ -809,16 +816,16 @@ dependencies = [ [[package]] name = "bls12_381" version = "0.8.0" -source = "git+https://github.com/jstuczyn/bls12_381?branch=temp/experimental-serdect#22cd0a16b674af1629110a2dc8b6cf6c73ea4cd9" +source = "git+https://github.com/jstuczyn/bls12_381?branch=temp/experimental-serdect-updated#9bf520059cb28323fc51469cae86868ef4fa6fbd" dependencies = [ - "digest 0.9.0", + "digest 0.10.7", "ff", "group", "pairing", "rand_core 0.6.4", "serde", - "serdect 0.3.0-pre.0", - "subtle 2.5.0", + "serdect 0.3.0", + "subtle 2.6.1", "zeroize", ] @@ -861,9 +868,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-tools" @@ -883,9 +890,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.16.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" [[package]] name = "byteorder" @@ -895,27 +902,33 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" dependencies = [ "serde", ] [[package]] -name = "camino" -version = "1.1.7" +name = "bytesize" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "2d2c12f985c78475a6b8d629afd0c360260ef34cfef52efccdcfd31972f81c2e" + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -928,7 +941,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "thiserror 1.0.69", @@ -942,7 +955,7 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "thiserror 1.0.69", @@ -962,9 +975,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.1.18" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" dependencies = [ "jobserver", "libc", @@ -1028,9 +1041,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1038,7 +1051,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1081,9 +1094,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.30" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -1091,9 +1104,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.30" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -1103,9 +1116,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.45" +version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e3040c8291884ddf39445dc033c70abc2bc44a42f0a3a00571a0f483a83f0cd" +checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98" dependencies = [ "clap", ] @@ -1129,7 +1142,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1140,9 +1153,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -1176,9 +1189,9 @@ dependencies = [ [[package]] name = "console" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", "libc", @@ -1376,9 +1389,9 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.5.5" +version = "1.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "242e98e7a231c122e08f300d9db3262d1007b51758a8732cd6210b3e9faa4f3a" +checksum = "343f5ce9f8f83dc2b3c03cb51ac2d39315ac4defd200d544e5a190726e01d2d5" dependencies = [ "syn 1.0.109", ] @@ -1439,9 +1452,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -1508,18 +1521,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1536,18 +1549,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -1571,10 +1584,10 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "crossterm_winapi", "parking_lot", - "rustix", + "rustix 0.38.44", "winapi", ] @@ -1589,9 +1602,9 @@ dependencies = [ [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -1601,7 +1614,7 @@ checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -1640,9 +1653,9 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] @@ -1668,9 +1681,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.46" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" dependencies = [ "curl-sys", "libc", @@ -1683,9 +1696,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.72+curl-8.6.0" +version = "0.4.80+curl-8.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734" dependencies = [ "cc", "libc", @@ -1705,7 +1718,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -1720,9 +1733,9 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "serde", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -1734,7 +1747,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1786,7 +1799,7 @@ dependencies = [ "cosmwasm-std", "cw2", "schemars", - "semver 1.0.25", + "semver 1.0.26", "serde", "thiserror 1.0.69", ] @@ -1801,7 +1814,7 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "schemars", - "semver 1.0.25", + "semver 1.0.26", "serde", "thiserror 1.0.69", ] @@ -1859,12 +1872,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ - "darling_core 0.20.9", - "darling_macro 0.20.9", + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -1883,16 +1896,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1908,13 +1921,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.9" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ - "darling_core 0.20.9", + "darling_core 0.20.10", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -1933,9 +1946,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" [[package]] name = "defguard_wireguard_rs" @@ -1967,7 +1980,7 @@ dependencies = [ "macroific", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2004,13 +2017,13 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2030,15 +2043,15 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "unicode-xid", ] [[package]] name = "devise" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" +checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" dependencies = [ "devise_codegen", "devise_core", @@ -2046,9 +2059,9 @@ dependencies = [ [[package]] name = "devise_codegen" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" +checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" dependencies = [ "devise_core", "quote", @@ -2056,15 +2069,15 @@ dependencies = [ [[package]] name = "devise_core" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" +checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2100,7 +2113,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -2126,13 +2139,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2161,9 +2174,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35" [[package]] name = "ecdsa" @@ -2235,7 +2248,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "sha2 0.10.8", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -2256,9 +2269,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ "serde", ] @@ -2279,7 +2292,7 @@ dependencies = [ "rand_core 0.6.4", "sec1", "serdect 0.2.0", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -2307,14 +2320,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -2357,18 +2370,18 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2399,9 +2412,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", @@ -2410,11 +2423,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.0", "pin-project-lite", ] @@ -2427,7 +2440,7 @@ dependencies = [ "dotenvy", "humantime-serde", "isocountry", - "itertools 0.13.0", + "itertools 0.14.0", "log", "maxminddb", "nym-bin-common", @@ -2449,7 +2462,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", ] @@ -2461,7 +2474,7 @@ dependencies = [ "console_error_panic_hook", "js-sys", "serde-wasm-bindgen 0.6.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "wasm-bindgen", "wasm-bindgen-futures", "wasm-storage", @@ -2494,7 +2507,7 @@ dependencies = [ "macroific", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2508,18 +2521,18 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -2544,14 +2557,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -2562,12 +2575,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -2582,9 +2595,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -2738,7 +2751,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2851,14 +2864,14 @@ dependencies = [ [[package]] name = "getset" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" +checksum = "f3586f256131df87204eb733da72e3d3eb4f343c639f4b7be279ac7c48baeafe" dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -2873,15 +2886,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "gloo-net" @@ -2961,7 +2974,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -2976,7 +2989,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -3117,12 +3130,24 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + [[package]] name = "hex-literal" version = "0.3.4" @@ -3131,9 +3156,9 @@ checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] name = "hickory-proto" -version = "0.24.3" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad3d6d98c648ed628df039541a5577bee1a7c83e9e16fe3dbedeea4cdfeb971" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" dependencies = [ "async-trait", "bytes", @@ -3216,11 +3241,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3245,7 +3270,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3283,9 +3308,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.2.0", @@ -3300,21 +3325,21 @@ dependencies = [ "bytes", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "http-range-header" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "httparse" -version = "1.9.3" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpcodec" @@ -3365,9 +3390,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes", "futures-channel", @@ -3397,7 +3422,7 @@ dependencies = [ "futures-channel", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -3415,7 +3440,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.29", + "hyper 0.14.32", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", @@ -3444,7 +3469,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.29", + "hyper 0.14.32", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -3460,7 +3485,7 @@ dependencies = [ "futures-channel", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "hyper 1.6.0", "pin-project-lite", "socket2", @@ -3471,9 +3496,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3607,7 +3632,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3645,7 +3670,7 @@ checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3715,7 +3740,7 @@ dependencies = [ "macroific", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -3731,9 +3756,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -3802,7 +3827,7 @@ dependencies = [ "newline-converter", "thiserror 1.0.69", "unicode-segmentation", - "unicode-width 0.1.13", + "unicode-width 0.1.14", ] [[package]] @@ -3849,9 +3874,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "ipnetwork" @@ -3873,20 +3898,20 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "isahc" @@ -3943,18 +3968,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -3967,9 +3992,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -4069,9 +4094,9 @@ checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -4079,8 +4104,9 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "libc", + "redox_syscall", ] [[package]] @@ -4096,9 +4122,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" dependencies = [ "cc", "libc", @@ -4114,9 +4140,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" [[package]] name = "lioness" @@ -4154,9 +4186,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "loom" @@ -4221,7 +4253,7 @@ dependencies = [ "proc-macro2", "quote", "sealed", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -4233,7 +4265,7 @@ dependencies = [ "proc-macro2", "quote", "sealed", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -4246,7 +4278,7 @@ dependencies = [ "macroific_core", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -4314,9 +4346,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -4335,9 +4367,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -4345,9 +4377,9 @@ dependencies = [ [[package]] name = "minicov" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", @@ -4361,18 +4393,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ "adler2", ] @@ -4391,11 +4414,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -4416,7 +4438,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde-wasm-bindgen 0.6.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tsify", "url", @@ -4451,12 +4473,12 @@ dependencies = [ "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "event-listener 5.3.1", + "event-listener 5.4.0", "futures-util", "loom 0.7.2", "parking_lot", "portable-atomic", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "smallvec", "tagptr", "thiserror 1.0.69", @@ -4483,6 +4505,23 @@ dependencies = [ "version_check", ] +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.2.0", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + [[package]] name = "netlink-packet-core" version = "0.7.0" @@ -4513,7 +4552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55e5bda7ca0f9ac5e75b5debac3b75e29a8ac8e2171106a2c3bb466389a8dd83" dependencies = [ "anyhow", - "bitflags 2.5.0", + "bitflags 2.8.0", "byteorder", "libc", "log", @@ -4549,9 +4588,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" dependencies = [ "bytes", "libc", @@ -4579,7 +4618,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "cfg-if", "libc", ] @@ -4590,7 +4629,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "cfg-if", "cfg_aliases", "libc", @@ -4747,11 +4786,11 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "nym-api" -version = "1.1.53" +version = "1.1.54" dependencies = [ "anyhow", "async-trait", - "axum 0.7.7", + "axum 0.7.9", "axum-extra", "axum-test", "bincode", @@ -4770,7 +4809,7 @@ dependencies = [ "futures", "getset", "humantime-serde", - "itertools 0.13.0", + "itertools 0.14.0", "k256", "nym-api-requests", "nym-bandwidth-controller", @@ -4808,14 +4847,14 @@ dependencies = [ "rand_chacha 0.3.1", "reqwest 0.12.4", "schemars", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.8", "sqlx", "tempfile", "tendermint 0.40.1", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-stream", @@ -4857,7 +4896,8 @@ dependencies = [ "serde_json", "sha2 0.10.8", "tendermint 0.40.1", - "thiserror 2.0.11", + "tendermint-rpc", + "thiserror 2.0.12", "time", "ts-rs", "utoipa", @@ -4883,7 +4923,7 @@ dependencies = [ "bytes", "clap", "defguard_wireguard_rs", - "fastrand 2.1.1", + "fastrand 2.3.0", "futures", "ipnetwork 0.20.0", "log", @@ -4909,7 +4949,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-stream", "tokio-util", @@ -4932,7 +4972,7 @@ dependencies = [ "rand 0.8.5", "serde", "sha2 0.10.8", - "thiserror 2.0.11", + "thiserror 2.0.12", "x25519-dalek", ] @@ -4952,7 +4992,7 @@ dependencies = [ "nym-task", "nym-validator-client", "rand 0.8.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "url", "zeroize", ] @@ -4991,12 +5031,12 @@ dependencies = [ "nym-validator-client", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] name = "nym-cli" -version = "1.1.50" +version = "1.1.51" dependencies = [ "anyhow", "base64 0.22.1", @@ -5069,7 +5109,7 @@ dependencies = [ "serde_json", "tap", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "toml 0.8.20", @@ -5079,7 +5119,7 @@ dependencies = [ [[package]] name = "nym-client" -version = "1.1.50" +version = "1.1.51" dependencies = [ "bs58", "clap", @@ -5106,7 +5146,7 @@ dependencies = [ "serde", "serde_json", "tap", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-tungstenite", @@ -5164,7 +5204,7 @@ dependencies = [ "si-scale", "tap", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-stream", @@ -5189,7 +5229,7 @@ dependencies = [ "nym-sphinx-addressing", "nym-sphinx-params", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "url", ] @@ -5204,7 +5244,7 @@ dependencies = [ "nym-gateway-requests", "serde", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "url", @@ -5222,7 +5262,7 @@ dependencies = [ "nym-sphinx", "nym-task", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", ] @@ -5241,7 +5281,7 @@ dependencies = [ "serde", "serde-wasm-bindgen 0.6.5", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tsify", "wasm-bindgen", "wasm-bindgen-futures", @@ -5291,18 +5331,18 @@ dependencies = [ "bs58", "cfg-if", "criterion", - "digest 0.9.0", + "digest 0.10.7", "ff", "group", - "itertools 0.13.0", + "itertools 0.14.0", "nym-network-defaults", "nym-pemstore", "rand 0.8.5", "rayon", "serde", - "sha2 0.9.9", - "subtle 2.5.0", - "thiserror 2.0.11", + "sha2 0.10.8", + "subtle 2.6.1", + "thiserror 2.0.12", "zeroize", ] @@ -5315,7 +5355,7 @@ dependencies = [ "log", "nym-network-defaults", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "toml 0.8.20", "url", ] @@ -5331,7 +5371,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "utoipa", "vergen", ] @@ -5364,7 +5404,7 @@ version = "0.1.7" dependencies = [ "anyhow", "async-trait", - "axum 0.7.7", + "axum 0.7.9", "bip39", "bs58", "cfg-if", @@ -5392,7 +5432,7 @@ dependencies = [ "strum 0.26.3", "strum_macros 0.26.4", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -5440,7 +5480,7 @@ dependencies = [ "nym-ecash-time", "serde", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "zeroize", ] @@ -5458,7 +5498,7 @@ dependencies = [ "nym-credentials-interface", "nym-ecash-time", "nym-validator-client", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", ] @@ -5481,7 +5521,7 @@ dependencies = [ "nym-validator-client", "rand 0.8.5", "si-scale", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -5505,7 +5545,7 @@ dependencies = [ "nym-validator-client", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "zeroize", ] @@ -5521,7 +5561,7 @@ dependencies = [ "rand 0.8.5", "serde", "strum 0.26.3", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "utoipa", ] @@ -5550,7 +5590,7 @@ dependencies = [ "serde_bytes", "sha2 0.10.8", "subtle-encoding", - "thiserror 2.0.11", + "thiserror 2.0.12", "x25519-dalek", "zeroize", ] @@ -5573,8 +5613,8 @@ dependencies = [ "rand_core 0.6.4", "serde", "serde_derive", - "sha2 0.9.9", - "thiserror 2.0.11", + "sha2 0.10.8", + "thiserror 2.0.12", "zeroize", ] @@ -5589,7 +5629,7 @@ dependencies = [ "cw-utils", "cw2", "nym-multisig-contract-common", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -5615,7 +5655,7 @@ dependencies = [ "reqwest 0.12.4", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "utoipa", ] @@ -5639,7 +5679,7 @@ dependencies = [ "nym-explorer-api-requests", "reqwest 0.12.4", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "url", @@ -5699,7 +5739,7 @@ dependencies = [ "rand 0.8.5", "sha2 0.10.8", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-stream", @@ -5733,7 +5773,7 @@ dependencies = [ "rand 0.8.5", "serde", "si-scale", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-stream", @@ -5767,8 +5807,8 @@ dependencies = [ "serde", "serde_json", "strum 0.26.3", - "subtle 2.5.0", - "thiserror 2.0.11", + "subtle 2.6.1", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -5787,7 +5827,7 @@ dependencies = [ "nym-statistics-common", "sqlx", "strum 0.26.3", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -5803,7 +5843,7 @@ dependencies = [ "nym-gateway-requests", "nym-sphinx", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -5819,7 +5859,7 @@ dependencies = [ "nym-ffi-shared", "nym-sdk", "nym-sphinx-anonymous-replies", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "uniffi", "uniffi_build", @@ -5851,7 +5891,7 @@ dependencies = [ "reqwest 0.12.4", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "url", @@ -5862,7 +5902,7 @@ dependencies = [ name = "nym-http-api-common" version = "0.1.0" dependencies = [ - "axum 0.7.7", + "axum 0.7.9", "axum-client-ip", "bytes", "colored", @@ -5871,7 +5911,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "subtle 2.5.0", + "subtle 2.6.1", "tower 0.5.2", "tracing", "utoipa", @@ -5884,7 +5924,7 @@ version = "0.1.0" dependencies = [ "nym-credential-storage", "nym-credentials", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tracing", "zeroize", @@ -5910,7 +5950,7 @@ version = "0.1.0" dependencies = [ "log", "rand 0.8.5", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -5925,7 +5965,7 @@ dependencies = [ "nym-sphinx", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -5965,7 +6005,7 @@ dependencies = [ "reqwest 0.12.4", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-tun", @@ -5981,7 +6021,7 @@ dependencies = [ "k256", "ledger-transport", "ledger-transport-hid", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6022,11 +6062,11 @@ dependencies = [ "nym-contracts-common", "rand_chacha 0.3.1", "schemars", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde-json-wasm", "serde_repr", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "ts-rs", "utoipa", @@ -6052,7 +6092,7 @@ dependencies = [ "nym-task", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -6071,7 +6111,7 @@ dependencies = [ "cw4", "schemars", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6093,7 +6133,7 @@ name = "nym-network-monitor" version = "1.0.2" dependencies = [ "anyhow", - "axum 0.7.7", + "axum 0.7.9", "clap", "dashmap", "futures", @@ -6123,7 +6163,7 @@ dependencies = [ [[package]] name = "nym-network-requester" -version = "1.1.51" +version = "1.1.52" dependencies = [ "addr", "anyhow", @@ -6164,7 +6204,7 @@ dependencies = [ "sqlx", "tap", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-tungstenite", @@ -6174,12 +6214,12 @@ dependencies = [ [[package]] name = "nym-node" -version = "1.6.2" +version = "1.7.0" dependencies = [ "anyhow", "arc-swap", "async-trait", - "axum 0.7.7", + "axum 0.7.9", "axum-extra", "bip39", "bs58", @@ -6201,6 +6241,7 @@ dependencies = [ "nym-crypto", "nym-gateway", "nym-gateway-stats-storage", + "nym-http-api-client", "nym-http-api-common", "nym-ip-packet-router", "nym-metrics", @@ -6223,12 +6264,12 @@ dependencies = [ "nym-wireguard", "nym-wireguard-types", "rand 0.8.5", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_json", "si-scale", "sysinfo", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -6274,7 +6315,7 @@ dependencies = [ "serde", "serde_json", "strum 0.26.3", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "utoipa", @@ -6282,7 +6323,7 @@ dependencies = [ [[package]] name = "nym-node-status-agent" -version = "1.0.0-rc.1" +version = "1.0.0-rc.2" dependencies = [ "anyhow", "clap", @@ -6302,17 +6343,20 @@ version = "1.0.2" dependencies = [ "ammonia", "anyhow", - "axum 0.7.7", + "axum 0.7.9", + "bip39", "chrono", "clap", "cosmwasm-std", "envy", "futures-util", + "itertools 0.14.0", "moka", "nym-bin-common", "nym-contracts-common", "nym-crypto", "nym-explorer-client", + "nym-http-api-client", "nym-network-defaults", "nym-node-metrics", "nym-node-requests", @@ -6321,6 +6365,8 @@ dependencies = [ "nym-statistics-common", "nym-task", "nym-validator-client", + "rand 0.8.5", + "rand_chacha 0.3.1", "regex", "reqwest 0.12.4", "serde", @@ -6329,7 +6375,7 @@ dependencies = [ "sqlx", "strum 0.26.3", "strum_macros 0.26.4", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -6372,7 +6418,7 @@ dependencies = [ "rand_chacha 0.3.1", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "wasm-utils", ] @@ -6387,7 +6433,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde-wasm-bindgen 0.6.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tsify", "wasm-bindgen", @@ -6428,7 +6474,7 @@ name = "nym-ordered-buffer" version = "0.1.0" dependencies = [ "log", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6439,13 +6485,13 @@ dependencies = [ "chacha20", "chacha20poly1305", "criterion", - "fastrand 2.1.1", + "fastrand 2.3.0", "getrandom 0.2.15", "log", "rand 0.8.5", "rayon", "sphinx-packet", - "thiserror 2.0.11", + "thiserror 2.0.12", "x25519-dalek", "zeroize", ] @@ -6468,6 +6514,7 @@ dependencies = [ "bip39", "bytecodec", "bytes", + "clap", "dashmap", "dirs", "dotenvy", @@ -6491,6 +6538,7 @@ dependencies = [ "nym-socks5-client-core", "nym-socks5-requests", "nym-sphinx", + "nym-sphinx-addressing", "nym-statistics-common", "nym-task", "nym-topology", @@ -6501,7 +6549,8 @@ dependencies = [ "reqwest 0.12.4", "serde", "tap", - "thiserror 2.0.11", + "tempfile", + "thiserror 2.0.12", "tokio", "tokio-stream", "tokio-util", @@ -6530,7 +6579,7 @@ version = "0.1.0" dependencies = [ "bincode", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6546,13 +6595,13 @@ dependencies = [ "nym-sphinx-anonymous-replies", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", ] [[package]] name = "nym-socks5-client" -version = "1.1.50" +version = "1.1.51" dependencies = [ "bs58", "clap", @@ -6576,7 +6625,7 @@ dependencies = [ "serde", "serde_json", "tap", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "url", @@ -6610,7 +6659,7 @@ dependencies = [ "schemars", "serde", "tap", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "url", ] @@ -6642,7 +6691,7 @@ dependencies = [ "serde", "serde_json", "tap", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6667,7 +6716,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_distr", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", ] @@ -6685,7 +6734,7 @@ dependencies = [ "nym-topology", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "zeroize", ] @@ -6697,7 +6746,7 @@ dependencies = [ "nym-sphinx-types", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6714,7 +6763,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "wasm-bindgen", ] @@ -6731,7 +6780,7 @@ dependencies = [ "nym-sphinx-types", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "utoipa", ] @@ -6749,7 +6798,7 @@ dependencies = [ "nym-sphinx-types", "nym-topology", "rand 0.8.5", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6760,7 +6809,7 @@ dependencies = [ "nym-sphinx-addressing", "nym-sphinx-params", "nym-sphinx-types", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6775,7 +6824,7 @@ dependencies = [ "nym-sphinx-forwarding", "nym-sphinx-params", "nym-sphinx-types", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-util", ] @@ -6787,7 +6836,7 @@ dependencies = [ "nym-crypto", "nym-sphinx-types", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6796,7 +6845,7 @@ version = "0.1.0" dependencies = [ "nym-sphinx-addressing", "nym-sphinx-types", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6805,7 +6854,7 @@ version = "0.2.0" dependencies = [ "nym-outfox", "sphinx-packet", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6824,7 +6873,7 @@ dependencies = [ "sha2 0.10.8", "si-scale", "sysinfo", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "wasmtimer", @@ -6841,7 +6890,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "zeroize", ] @@ -6852,7 +6901,7 @@ dependencies = [ "cfg-if", "futures", "log", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-util", "tracing", @@ -6894,7 +6943,7 @@ dependencies = [ "reqwest 0.12.4", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", "tsify", "wasm-bindgen", @@ -6908,7 +6957,7 @@ dependencies = [ "etherparse", "log", "nym-wireguard-types", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-tun", ] @@ -6922,7 +6971,7 @@ dependencies = [ "cosmwasm-std", "eyre", "hmac", - "itertools 0.13.0", + "itertools 0.14.0", "log", "nym-config", "nym-crypto", @@ -6936,7 +6985,7 @@ dependencies = [ "sha2 0.10.8", "strum 0.26.3", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "ts-rs", "url", "utoipa", @@ -6962,7 +7011,7 @@ dependencies = [ "eyre", "flate2", "futures", - "itertools 0.13.0", + "itertools 0.14.0", "nym-api-requests", "nym-coconut-bandwidth-contract-common", "nym-coconut-dkg-common", @@ -6983,7 +7032,7 @@ dependencies = [ "serde_json", "sha2 0.9.9", "tendermint-rpc", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -7027,7 +7076,7 @@ dependencies = [ "serde_with", "sha2 0.10.8", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -7046,7 +7095,7 @@ dependencies = [ "nym-task", "nym-validator-client", "rand 0.8.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -7064,7 +7113,7 @@ dependencies = [ "nym-contracts-common", "nym-mixnet-contract-common", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "ts-rs", ] @@ -7085,7 +7134,7 @@ dependencies = [ "serde", "serde-wasm-bindgen 0.6.5", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tsify", "wasm-bindgen", @@ -7132,7 +7181,7 @@ dependencies = [ "nym-node-metrics", "nym-task", "nym-wireguard-types", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-stream", @@ -7151,13 +7200,13 @@ dependencies = [ "nym-network-defaults", "rand 0.8.5", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "x25519-dalek", ] [[package]] name = "nymvisor" -version = "0.1.15" +version = "0.1.16" dependencies = [ "anyhow", "bytes", @@ -7178,7 +7227,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "tar", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tracing", @@ -7187,27 +7236,24 @@ dependencies = [ [[package]] name = "nyx-chain-watcher" -version = "0.1.11" +version = "0.1.14" dependencies = [ "anyhow", "async-trait", - "axum 0.7.7", + "axum 0.7.9", "chrono", "clap", "nym-bin-common", "nym-config", "nym-network-defaults", - "nym-node-requests", "nym-task", "nym-validator-client", "nyxd-scraper", "reqwest 0.12.4", - "rocket", "schemars", "serde", - "serde_json", "sqlx", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -7234,7 +7280,7 @@ dependencies = [ "sqlx", "tendermint 0.40.1", "tendermint-rpc", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "tokio-stream", @@ -7245,9 +7291,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -7272,9 +7318,9 @@ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "opaque-debug" @@ -7290,15 +7336,15 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" dependencies = [ "cc", "libc", @@ -7428,9 +7474,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -7450,7 +7496,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -7463,7 +7509,7 @@ checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -7492,14 +7538,14 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "peg" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a625d12ad770914cbf7eff6f9314c3ef803bfe364a1b20bc36ddf56673e71e5" +checksum = "295283b02df346d1ef66052a757869b2876ac29a6bb0ac3f5f7cd44aebe40e8f" dependencies = [ "peg-macros", "peg-runtime", @@ -7507,9 +7553,9 @@ dependencies = [ [[package]] name = "peg-macros" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f241d42067ed3ab6a4fece1db720838e1418f36d868585a27931f95d6bc03582" +checksum = "bdad6a1d9cf116a059582ce415d5f5566aabcd4008646779dab7fdc2a9a9d426" dependencies = [ "peg-runtime", "proc-macro2", @@ -7550,20 +7596,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.10" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 1.0.69", + "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.10" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" dependencies = [ "pest", "pest_generator", @@ -7571,22 +7617,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.10" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "pest_meta" -version = "2.7.10" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" dependencies = [ "once_cell", "pest", @@ -7600,16 +7646,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.7.0", + "indexmap 2.7.1", ] [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_shared 0.11.2", + "phf_shared", ] [[package]] @@ -7618,18 +7664,8 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", + "phf_generator", + "phf_shared", ] [[package]] @@ -7638,53 +7674,44 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared 0.11.2", + "phf_shared", "rand 0.8.5", ] [[package]] name = "phf_shared" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", + "siphasher 1.0.1", ] [[package]] name = "pin-project" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -7715,9 +7742,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain" @@ -7727,9 +7754,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -7740,15 +7767,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -7794,9 +7821,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "postgres-protocol" @@ -7835,9 +7862,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy 0.7.35", +] [[package]] name = "precomputed-hash" @@ -7884,14 +7914,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -7904,7 +7934,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "version_check", "yansi", ] @@ -7977,7 +8007,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -7987,10 +8017,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -8019,9 +8049,9 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" [[package]] name = "psl" -version = "2.1.43" +version = "2.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecec637c2e9d0c8c4bf78df069a53a103ebe3dbd0dc7eff1d60c1006a1c97254" +checksum = "138e02ed846877ce4044391085ca68b470b0d379cd18a9be0666161764d35448" dependencies = [ "psl-types", ] @@ -8056,9 +8086,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] @@ -8087,8 +8117,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.0", - "zerocopy 0.8.17", + "rand_core 0.9.1", + "zerocopy 0.8.20", ] [[package]] @@ -8108,7 +8138,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.1", ] [[package]] @@ -8128,12 +8158,12 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" dependencies = [ "getrandom 0.3.1", - "zerocopy 0.8.17", + "zerocopy 0.8.20", ] [[package]] @@ -8186,27 +8216,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", @@ -8230,7 +8251,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -8291,7 +8312,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.32", "hyper-rustls 0.24.2", "ipnet", "js-sys", @@ -8330,7 +8351,7 @@ dependencies = [ "futures-core", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "hyper 1.6.0", "hyper-rustls 0.26.0", @@ -8343,7 +8364,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.22.4", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -8359,18 +8380,18 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.2", + "webpki-roots 0.26.8", "winreg 0.52.0", ] [[package]] name = "reserve-port" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9838134a2bfaa8e1f40738fcc972ac799de6e0e06b5157acb95fc2b05a0ea283" +checksum = "359fc315ed556eb0e42ce74e76f4b1cd807b50fa6307f3de4e51f92dbe86e2d5" dependencies = [ "lazy_static", - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] @@ -8390,20 +8411,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] name = "ring" -version = "0.17.8" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -8433,7 +8453,7 @@ dependencies = [ "rinja_parser", "rustc-hash", "serde", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -8470,10 +8490,10 @@ dependencies = [ "either", "figment", "futures", - "indexmap 2.7.0", + "indexmap 2.7.1", "log", "memchr", - "multer", + "multer 2.1.0", "num_cpus", "parking_lot", "pin-project-lite", @@ -8502,11 +8522,11 @@ checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" dependencies = [ "devise", "glob", - "indexmap 2.7.0", + "indexmap 2.7.1", "proc-macro2", "quote", "rocket_http", - "syn 2.0.90", + "syn 2.0.98", "unicode-xid", "version_check", ] @@ -8538,8 +8558,8 @@ dependencies = [ "either", "futures", "http 0.2.12", - "hyper 0.14.29", - "indexmap 2.7.0", + "hyper 0.14.32", + "indexmap 2.7.1", "log", "memchr", "pear", @@ -8585,18 +8605,18 @@ dependencies = [ [[package]] name = "rs_merkle" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b241d2e59b74ef9e98d94c78c47623d04c8392abaf82014dfd372a16041128f" +checksum = "bb09b49230ba22e8c676e7b75dfe2887dea8121f18b530ae0ba519ce442d2b21" dependencies = [ "sha2 0.10.8", ] [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid", "digest 0.10.7", @@ -8608,15 +8628,15 @@ dependencies = [ "rand_core 0.6.4", "signature", "spki", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] [[package]] name = "rust-embed" -version = "8.4.0" +version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a" +checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -8625,22 +8645,22 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.4.0" +version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4" +checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.90", + "syn 2.0.98", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.4.0" +version = "8.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32" +checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" dependencies = [ "sha2 0.10.8", "walkdir", @@ -8685,24 +8705,37 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.25", + "semver 1.0.26", ] [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.52.0", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys 0.9.2", + "windows-sys 0.59.0", ] [[package]] @@ -8726,8 +8759,8 @@ dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki 0.102.4", - "subtle 2.5.0", + "rustls-webpki 0.102.8", + "subtle 2.6.1", "zeroize", ] @@ -8745,12 +8778,12 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -8767,19 +8800,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-webpki" @@ -8793,9 +8825,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -8804,15 +8836,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -8825,18 +8857,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -8848,14 +8880,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", "serde_derive_internals 0.29.1", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -8887,7 +8919,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -8908,7 +8940,7 @@ checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -8922,7 +8954,7 @@ dependencies = [ "generic-array 0.14.7", "pkcs8", "serdect 0.2.0", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -8946,11 +8978,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", "core-foundation", "core-foundation-sys", "libc", @@ -8959,9 +8991,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -8978,9 +9010,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] @@ -8993,9 +9025,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -9033,22 +9065,22 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.15" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9059,7 +9091,7 @@ checksum = "e578a843d40b4189a4d66bba51d7684f57da5bd7c304c64e14bd63efbef49509" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9070,14 +9102,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -9098,7 +9130,7 @@ dependencies = [ "serde_json", "serde_json_path_core", "serde_json_path_macros", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -9110,7 +9142,7 @@ dependencies = [ "inventory", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -9132,7 +9164,7 @@ checksum = "aafbefbe175fa9bf03ca83ef89beecff7d2a95aaacd5732325b90ac8c3bd7b90" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9147,13 +9179,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9179,15 +9211,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_derive", "serde_json", @@ -9197,14 +9229,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling 0.20.9", + "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9213,7 +9245,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "itoa", "ryu", "serde", @@ -9232,9 +9264,9 @@ dependencies = [ [[package]] name = "serdect" -version = "0.3.0-pre.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791ef964bfaba6be28a5c3f0c56836e17cb711ac009ca1074b9c735a3ebf240a" +checksum = "f42f67da2385b51a5f9652db9c93d78aeaf7610bf5ec366080b6de810604af53" dependencies = [ "base16ct", "serde", @@ -9308,9 +9340,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio 0.8.11", @@ -9348,6 +9380,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -9370,9 +9408,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smawk" @@ -9404,9 +9442,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -9433,7 +9471,7 @@ dependencies = [ "rand 0.8.5", "rand_distr", "sha2 0.10.8", - "subtle 2.5.0", + "subtle 2.6.1", "x25519-dalek", ] @@ -9458,9 +9496,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom", "unicode_categories", @@ -9501,7 +9539,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.7.0", + "indexmap 2.7.1", "log", "memchr", "once_cell", @@ -9570,7 +9608,7 @@ checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.5.0", + "bitflags 2.8.0", "byteorder", "bytes", "chrono", @@ -9614,7 +9652,7 @@ checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.5.0", + "bitflags 2.8.0", "byteorder", "chrono", "crc", @@ -9713,26 +9751,25 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", - "phf_shared 0.10.0", + "phf_shared", "precomputed-hash", "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "244292f3441c89febe5b5bdfbb6863aeaf4f64da810ea3050fd927b27b8d92ce" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -9801,7 +9838,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9812,9 +9849,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "subtle-encoding" @@ -9844,9 +9881,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -9861,9 +9898,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "synstructure" @@ -9873,7 +9910,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -9936,15 +9973,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" dependencies = [ "cfg-if", - "fastrand 2.1.1", - "getrandom 0.2.15", + "fastrand 2.3.0", + "getrandom 0.3.1", "once_cell", - "rustix", + "rustix 1.0.1", "windows-sys 0.59.0", ] @@ -9972,7 +10009,7 @@ dependencies = [ "serde_repr", "sha2 0.10.8", "signature", - "subtle 2.5.0", + "subtle 2.6.1", "subtle-encoding", "tendermint-proto 0.34.1", "time", @@ -10002,7 +10039,7 @@ dependencies = [ "serde_repr", "sha2 0.10.8", "signature", - "subtle 2.5.0", + "subtle 2.6.1", "subtle-encoding", "tendermint-proto 0.40.1", "time", @@ -10072,11 +10109,11 @@ dependencies = [ "pin-project", "rand 0.8.5", "reqwest 0.11.27", - "semver 1.0.25", + "semver 1.0.26", "serde", "serde_bytes", "serde_json", - "subtle 2.5.0", + "subtle 2.6.1", "subtle-encoding", "tendermint 0.40.1", "tendermint-config", @@ -10140,7 +10177,7 @@ dependencies = [ "serde_json", "sqlx", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tokio", "toml 0.8.20", @@ -10169,11 +10206,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -10184,18 +10221,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -10232,9 +10269,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" dependencies = [ "deranged", "itoa", @@ -10250,15 +10287,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" dependencies = [ "num-conv", "time-core", @@ -10286,9 +10323,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -10301,14 +10338,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.1", + "mio 1.0.3", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -10336,7 +10373,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -10388,9 +10425,9 @@ dependencies = [ [[package]] name = "tokio-socks" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" dependencies = [ "either", "futures-util", @@ -10498,11 +10535,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.23" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", @@ -10524,7 +10561,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.29", + "hyper 0.14.32", "hyper-timeout", "percent-encoding", "pin-project", @@ -10566,7 +10603,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tower-layer", "tower-service", @@ -10580,12 +10617,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "async-compression", - "bitflags 2.5.0", + "bitflags 2.8.0", "bytes", "futures-core", "futures-util", "http 1.2.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "http-range-header", "httpdate", @@ -10632,7 +10669,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -10763,7 +10800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e640d9b0964e9d39df633548591090ab92f7a4567bc31d3891af23471a3365c6" dependencies = [ "lazy_static", - "thiserror 2.0.11", + "thiserror 2.0.12", "ts-rs-macros", ] @@ -10790,7 +10827,7 @@ checksum = "0e9d8656589772eeec2cf7a8264d9cda40fb28b9bc53118ceb9e8c07f8f38730" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "termcolor", ] @@ -10817,7 +10854,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals 0.28.0", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -10864,9 +10901,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ubyte" @@ -10879,9 +10916,9 @@ dependencies = [ [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uncased" @@ -10895,12 +10932,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicase_serde" @@ -10914,15 +10948,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] name = "unicode-normalization" @@ -10935,21 +10969,21 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" @@ -10959,9 +10993,9 @@ checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -11039,7 +11073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22a9dba1d78b9ce429439891089c223478043d52a1c3176a0fcea2b5573a7fcf" dependencies = [ "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -11054,7 +11088,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.90", + "syn 2.0.98", "toml 0.5.11", "uniffi_meta", ] @@ -11066,7 +11100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5965b1d4ffacef1eaa72fef9c00d2491641e87ad910f6c5859b9c503ddb16a" dependencies = [ "anyhow", - "siphasher", + "siphasher 0.3.11", "uniffi_internal_macros", ] @@ -11089,7 +11123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -11148,11 +11182,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utoipa" -version = "5.2.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514a48569e4e21c86d0b84b5612b5e73c0b2cf09db63260134ba426d4e8ea714" +checksum = "435c6f69ef38c9017b4b4eea965dfb91e71e53d869e896db40d1cf2441dd75c0" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_json", "utoipa-gen", @@ -11160,14 +11194,14 @@ dependencies = [ [[package]] name = "utoipa-gen" -version = "5.2.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5629efe65599d0ccd5d493688cbf6e03aa7c1da07fe59ff97cf5977ed0637f66" +checksum = "a77d306bc75294fd52f3e99b13ece67c02c1a2789190a6f31d32f736624326f7" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.90", + "syn 2.0.98", "uuid", ] @@ -11177,7 +11211,7 @@ version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db4b5ac679cc6dfc5ea3f2823b0291c777750ffd5e13b21137e0f7ac0e8f9617" dependencies = [ - "axum 0.7.7", + "axum 0.7.9", "base64 0.22.1", "mime_guess", "regex", @@ -11206,7 +11240,7 @@ checksum = "268d76aaebb80eba79240b805972e52d7d410d4bcc52321b951318b0f440cd60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -11217,25 +11251,43 @@ checksum = "382673bda1d05c85b4550d32fd4192ccd4cffe9a908543a0795d1e7682b36246" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "utoipauto-core", ] [[package]] name = "uuid" -version = "1.10.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.1", "serde", ] [[package]] -name = "valuable" +name = "validator-status-check" version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "comfy-table", + "nym-bin-common", + "nym-network-defaults", + "nym-validator-client", + "serde", + "serde_json", + "strum 0.26.3", + "time", + "tokio", + "tracing", +] + +[[package]] +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -11253,16 +11305,16 @@ dependencies = [ "cargo_metadata 0.18.1", "cfg-if", "regex", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "rustversion", "time", ] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "waker-fn" @@ -11312,34 +11364,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -11350,9 +11403,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11360,32 +11413,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-bindgen-test" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d44563646eb934577f2772656c7ad5e9c90fac78aa8013d776fcdaf24625d" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" dependencies = [ "js-sys", "minicov", - "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", @@ -11393,13 +11448,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54171416ce73aa0b9c377b51cc3cb542becee1cd678204812e8392e5b0e4a031" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -11424,7 +11479,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde-wasm-bindgen 0.6.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", "tsify", "url", @@ -11446,16 +11501,16 @@ dependencies = [ "nym-store-cipher", "serde", "serde-wasm-bindgen 0.6.5", - "thiserror 2.0.11", + "thiserror 2.0.12", "wasm-bindgen", "wasm-utils", ] [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -11496,9 +11551,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -11531,9 +11586,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.2" +version = "0.26.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" dependencies = [ "rustls-pki-types", ] @@ -11553,7 +11608,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.5.1", + "redox_syscall", "wasite", "web-sys", ] @@ -11582,11 +11637,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -11666,7 +11721,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -11677,7 +11732,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -11688,7 +11743,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -11699,9 +11754,15 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] +[[package]] +name = "windows-link" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" + [[package]] name = "windows-result" version = "0.1.2" @@ -11946,9 +12007,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] @@ -11979,7 +12040,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.8.0", ] [[package]] @@ -12017,13 +12078,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "linux-raw-sys 0.4.15", + "rustix 0.38.44", ] [[package]] @@ -12055,48 +12116,49 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive 0.7.34", + "byteorder", + "zerocopy-derive 0.7.35", ] [[package]] name = "zerocopy" -version = "0.8.17" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c" dependencies = [ - "zerocopy-derive 0.8.17", + "zerocopy-derive 0.8.20", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "zerocopy-derive" -version = "0.8.17" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -12116,7 +12178,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", "synstructure", ] @@ -12137,7 +12199,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] @@ -12159,23 +12221,23 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.98", ] [[package]] name = "zip" -version = "2.1.6" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e" +checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" dependencies = [ "arbitrary", "crc32fast", "crossbeam-utils", "displaydoc", "flate2", - "indexmap 2.7.0", + "indexmap 2.7.1", "memchr", - "thiserror 1.0.69", + "thiserror 2.0.12", "zopfli", ] @@ -12196,7 +12258,7 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.4", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tsify", "uuid", diff --git a/Cargo.toml b/Cargo.toml index 80d483f003..8ecb2f35ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,7 +137,7 @@ members = [ "tools/internal/testnet-manager", "tools/internal/testnet-manager", "tools/internal/testnet-manager/dkg-bypass-contract", - "tools/internal/testnet-manager/dkg-bypass-contract", + "tools/internal/testnet-manager/dkg-bypass-contract", "tools/internal/validator-status-check", "tools/nym-cli", "tools/nym-id-cli", "tools/nym-nr-query", @@ -191,10 +191,10 @@ aes = "0.8.1" aes-gcm = "0.10.1" aes-gcm-siv = "0.11.1" ammonia = "4" -anyhow = "1.0.95" +anyhow = "1.0.97" arc-swap = "1.7.1" argon2 = "0.5.0" -async-trait = "0.1.86" +async-trait = "0.1.87" axum = "0.7.5" axum-client-ip = "0.6.1" axum-extra = "0.9.4" @@ -205,24 +205,24 @@ bincode = "1.3.3" bip39 = { version = "2.0.0", features = ["zeroize"] } bit-vec = "0.7.0" # can we unify those? bitvec = "1.0.0" -blake3 = "1.5.5" +blake3 = "1.6.1" bloomfilter = "1.0.14" bs58 = "0.5.1" bytecodec = "0.4.15" -bytes = "1.7.2" +bytes = "1.10.1" cargo_metadata = "0.18.1" celes = "2.5.0" cfg-if = "1.0.0" chacha20 = "0.9.0" chacha20poly1305 = "0.10.1" -chrono = "0.4.39" +chrono = "0.4.40" cipher = "0.4.3" -clap = "4.5.30" +clap = "4.5.31" clap_complete = "4.5" clap_complete_fig = "4.5" colored = "2.2" comfy-table = "7.1.4" -console = "0.15.10" +console = "0.15.11" console-subscriber = "0.1.1" console_error_panic_hook = "0.1" const-str = "0.5.6" @@ -247,12 +247,12 @@ envy = "0.4" etherparse = "0.13.0" eyre = "0.6.9" fastrand = "2.1.1" -flate2 = "1.0.35" +flate2 = "1.1.0" futures = "0.3.31" futures-util = "0.3" generic-array = "0.14.7" getrandom = "0.2.10" -getset = "0.1.4" +getset = "0.1.5" handlebars = "3.5.5" headers = "0.4.0" hex = "0.4.3" @@ -273,7 +273,7 @@ inquire = "0.6.2" ip_network = "0.4.1" ipnetwork = "0.20" isocountry = "0.3.2" -itertools = "0.13.0" +itertools = "0.14.0" k256 = "0.13" lazy_static = "1.5.0" ledger-transport = "0.10.0" @@ -308,14 +308,14 @@ reqwest = { version = "0.12.4", default-features = false } rocket = "0.5.0" rocket_cors = "0.6.0" rocket_okapi = "0.8.0" -rs_merkle = "1.4.2" +rs_merkle = "1.5.0" safer-ffi = "0.1.13" -schemars = "0.8.21" -semver = "1.0.25" -serde = "1.0.217" -serde_bytes = "0.11.15" +schemars = "0.8.22" +semver = "1.0.26" +serde = "1.0.219" +serde_bytes = "0.11.17" serde_derive = "1.0" -serde_json = "1.0.138" +serde_json = "1.0.140" serde_json_path = "0.7.2" serde_repr = "0.1" serde_with = "3.9.0" @@ -331,10 +331,10 @@ syn = "1" sysinfo = "0.33.0" tap = "1.0.1" tar = "0.4.44" -tempfile = "3.15" +tempfile = "3.18" thiserror = "2.0" -time = "0.3.37" -tokio = "1.43" +time = "0.3.39" +tokio = "1.44" tokio-postgres = "0.7" tokio-stream = "0.1.17" tokio-test = "0.4.4" @@ -370,9 +370,9 @@ prometheus = { version = "0.13.0" } # unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork # as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm # plus to make our live easier we need serde support from https://github.com/zkcrypto/bls12_381/pull/125 -bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" } +bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect-updated" } group = { version = "0.13.0", default-features = false } -ff = { version = "0.13.0", default-features = false } +ff = { version = "0.13.1", default-features = false } subtle = "2.5.0" # cosmwasm-related @@ -447,4 +447,4 @@ dbg_macro = "deny" exit = "deny" panic = "deny" unimplemented = "deny" -unreachable = "deny" \ No newline at end of file +unreachable = "deny" diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index 9663b41d78..3211e70146 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-client" -version = "1.1.50" +version = "1.1.51" authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] description = "Implementation of the Nym Client" edition = "2021" diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 9c4b1522ca..b764847432 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-socks5-client" -version = "1.1.50" +version = "1.1.51" authors = ["Dave Hrycyszyn "] description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" edition = "2021" diff --git a/common/client-core/config-types/src/lib.rs b/common/client-core/config-types/src/lib.rs index 5930245e51..92925dcfdf 100644 --- a/common/client-core/config-types/src/lib.rs +++ b/common/client-core/config-types/src/lib.rs @@ -658,6 +658,9 @@ pub struct ReplySurbs { /// Specifies the number of mixnet hops the packet should go through. If not specified, then /// the default value is used. pub surb_mix_hops: Option, + + /// Specifies if we should reset all the sender tags on startup + pub fresh_sender_tags: bool, } impl Default for ReplySurbs { @@ -675,6 +678,7 @@ impl Default for ReplySurbs { maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE, maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE, surb_mix_hops: None, + fresh_sender_tags: false, } } } diff --git a/common/client-core/src/client/base_client/non_wasm_helpers.rs b/common/client-core/src/client/base_client/non_wasm_helpers.rs index ce3f05b0f2..e7ef621c9d 100644 --- a/common/client-core/src/client/base_client/non_wasm_helpers.rs +++ b/common/client-core/src/client/base_client/non_wasm_helpers.rs @@ -88,7 +88,7 @@ pub async fn setup_fs_reply_surb_backend>( let db_path = db_path.as_ref(); if db_path.exists() { info!("loading existing surb database"); - match fs_backend::Backend::try_load(db_path).await { + match fs_backend::Backend::try_load(db_path, surb_config.fresh_sender_tags).await { Ok(backend) => Ok(backend), Err(err) => { error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future"); diff --git a/common/client-core/surb-storage/src/backend/fs_backend/mod.rs b/common/client-core/surb-storage/src/backend/fs_backend/mod.rs index 4914f6621f..4467e17538 100644 --- a/common/client-core/surb-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/surb-storage/src/backend/fs_backend/mod.rs @@ -10,7 +10,7 @@ use crate::{ CombinedReplyStorage, ReceivedReplySurbsMap, ReplyStorageBackend, SentReplyKeys, UsedSenderTags, }; use async_trait::async_trait; -use log::{error, info, warn}; +use log::{debug, error, info, warn}; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use std::fs; use std::path::{Path, PathBuf}; @@ -52,7 +52,10 @@ impl Backend { Ok(backend) } - pub async fn try_load>(database_path: P) -> Result { + pub async fn try_load>( + database_path: P, + fresh_sender_tags: bool, + ) -> Result { let owned_path: PathBuf = database_path.as_ref().into(); if owned_path.file_name().is_none() { return Err(StorageError::DatabasePathWithoutFilename { @@ -118,6 +121,9 @@ impl Backend { if days > 2 { info!("it's been over {days} days and {hours} hours since we last used our data store. our used sender tags are already outdated - we're going to purge them now."); manager.delete_all_tags().await?; + } else if fresh_sender_tags { + debug!("starting with fresh sender tags"); + manager.delete_all_tags().await?; } Ok(Backend { diff --git a/common/client-libs/gateway-client/src/client/mod.rs b/common/client-libs/gateway-client/src/client/mod.rs index 6bff2c1805..88a55dd850 100644 --- a/common/client-libs/gateway-client/src/client/mod.rs +++ b/common/client-libs/gateway-client/src/client/mod.rs @@ -204,15 +204,15 @@ impl GatewayClient { "Attemting to establish connection to gateway at: {}", self.gateway_address ); - let (ws_stream, _) = connect_async(&self.gateway_address).await?; + let (ws_stream, _) = connect_async( + &self.gateway_address, + #[cfg(unix)] + self.connection_fd_callback.clone(), + ) + .await?; self.connection = SocketState::Available(Box::new(ws_stream)); - #[cfg(unix)] - if let (Some(callback), Some(fd)) = (self.connection_fd_callback.as_ref(), self.ws_fd()) { - callback.as_ref()(fd); - } - Ok(()) } diff --git a/common/client-libs/gateway-client/src/client/websockets.rs b/common/client-libs/gateway-client/src/client/websockets.rs index 32527571ec..293435b1cf 100644 --- a/common/client-libs/gateway-client/src/client/websockets.rs +++ b/common/client-libs/gateway-client/src/client/websockets.rs @@ -1,6 +1,11 @@ use crate::error::GatewayClientError; use nym_http_api_client::HickoryDnsResolver; +#[cfg(unix)] +use std::{ + os::fd::{AsRawFd, RawFd}, + sync::Arc, +}; use tokio::net::TcpStream; use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; use tungstenite::handshake::client::Response; @@ -11,7 +16,10 @@ use std::net::SocketAddr; #[cfg(not(target_arch = "wasm32"))] pub(crate) async fn connect_async( endpoint: &str, + #[cfg(unix)] connection_fd_callback: Option>, ) -> Result<(WebSocketStream>, Response), GatewayClientError> { + use tokio::net::TcpSocket; + let resolver = HickoryDnsResolver::default(); let uri = Url::parse(endpoint).map_err(|_| GatewayClientError::InvalidUrl(endpoint.to_owned()))?; @@ -37,14 +45,41 @@ pub(crate) async fn connect_async( } }; - let stream = TcpStream::connect(&sock_addrs[..]).await.map_err(|error| { - GatewayClientError::NetworkConnectionFailed { - address: endpoint.to_owned(), - source: error.into(), + let mut stream = Err(GatewayClientError::NoEndpointForConnection { + address: endpoint.to_owned(), + }); + for sock_addr in sock_addrs { + let socket = if sock_addr.is_ipv4() { + TcpSocket::new_v4() + } else { + TcpSocket::new_v6() } - })?; + .map_err(|err| GatewayClientError::NetworkConnectionFailed { + address: endpoint.to_owned(), + source: err.into(), + })?; - tokio_tungstenite::client_async_tls(endpoint, stream) + #[cfg(unix)] + if let Some(callback) = connection_fd_callback.as_ref() { + callback.as_ref()(socket.as_raw_fd()); + } + + match socket.connect(sock_addr).await { + Ok(s) => { + stream = Ok(s); + break; + } + Err(err) => { + stream = Err(GatewayClientError::NetworkConnectionFailed { + address: endpoint.to_owned(), + source: err.into(), + }); + continue; + } + } + } + + tokio_tungstenite::client_async_tls(endpoint, stream?) .await .map_err(|error| GatewayClientError::NetworkConnectionFailed { address: endpoint.to_owned(), diff --git a/common/client-libs/gateway-client/src/error.rs b/common/client-libs/gateway-client/src/error.rs index 3432f43131..a9ce175504 100644 --- a/common/client-libs/gateway-client/src/error.rs +++ b/common/client-libs/gateway-client/src/error.rs @@ -43,6 +43,9 @@ pub enum GatewayClientError { #[error("connection failed: {address}: {source}")] NetworkConnectionFailed { address: String, source: WsError }, + #[error("no socket address for endpoint: {address}")] + NoEndpointForConnection { address: String }, + #[error("Invalid URL: {0}")] InvalidUrl(String), diff --git a/common/client-libs/validator-client/src/client.rs b/common/client-libs/validator-client/src/client.rs index e5a9a7ea8a..c41ba519d4 100644 --- a/common/client-libs/validator-client/src/client.rs +++ b/common/client-libs/validator-client/src/client.rs @@ -23,11 +23,12 @@ use nym_api_requests::models::{ NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse, }; use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated}; -use nym_api_requests::nym_nodes::SkimmedNode; +use nym_api_requests::nym_nodes::{NodesByAddressesResponse, SkimmedNode}; use nym_coconut_dkg_common::types::EpochId; use nym_ecash_contract_common::deposit::DepositId; use nym_http_api_client::UserAgent; use nym_network_defaults::NymNetworkDetails; +use std::net::IpAddr; use time::Date; use url::Url; @@ -710,4 +711,11 @@ impl NymApiClient { .issued_ticketbooks_challenge(expiration_date, deposits) .await?) } + + pub async fn nodes_by_addresses( + &self, + addresses: Vec, + ) -> Result { + Ok(self.nym_api.nodes_by_addresses(addresses).await?) + } } diff --git a/common/client-libs/validator-client/src/coconut/mod.rs b/common/client-libs/validator-client/src/coconut/mod.rs index 95270a25ed..67974c0170 100644 --- a/common/client-libs/validator-client/src/coconut/mod.rs +++ b/common/client-libs/validator-client/src/coconut/mod.rs @@ -83,6 +83,12 @@ impl TryFrom for EcashApiClient { let url_address = Url::parse(&share.announce_address)?; + // The NymApiClient constructed here uses the default (hickory DoT/DoH) resolver because + // this EcashApiClient is used by both client and non-client applications. + // + // In non-client applications this resolver can cause warning logs about H2 connection + // failure. This indicates that the long lived https connection was closed by the remote + // peer and the resolver will have to reconnect. It should not impact actual functionality Ok(EcashApiClient { api_client: NymApiClient::new(url_address), verification_key: VerificationKeyAuth::try_from_bs58(&share.share)?, diff --git a/common/client-libs/validator-client/src/nym_api/mod.rs b/common/client-libs/validator-client/src/nym_api/mod.rs index e1bac67513..a9b1bc54d5 100644 --- a/common/client-libs/validator-client/src/nym_api/mod.rs +++ b/common/client-libs/validator-client/src/nym_api/mod.rs @@ -12,10 +12,13 @@ use nym_api_requests::ecash::models::{ }; use nym_api_requests::ecash::VerificationKeyResponse; use nym_api_requests::models::{ - AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse, - NodeRefreshBody, NymNodeDescription, PerformanceHistoryResponse, RewardedSetResponse, + AnnotationResponse, ApiHealthResponse, BinaryBuildInformationOwned, ChainStatusResponse, + LegacyDescribedMixNode, NodePerformanceResponse, NodeRefreshBody, NymNodeDescription, + PerformanceHistoryResponse, RewardedSetResponse, +}; +use nym_api_requests::nym_nodes::{ + NodesByAddressesRequestBody, NodesByAddressesResponse, PaginatedCachedNodesResponse, }; -use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse; use nym_api_requests::pagination::PaginatedResponse; pub use nym_api_requests::{ ecash::{ @@ -40,6 +43,7 @@ pub use nym_http_api_client::Client; use nym_http_api_client::{ApiClient, NO_PARAMS}; use nym_mixnet_contract_common::mixnode::MixNodeDetails; use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, NodeId, NymNodeDetails}; +use std::net::IpAddr; use time::format_description::BorrowedFormatItem; use time::Date; use tracing::instrument; @@ -66,6 +70,19 @@ pub trait NymApiClientExt: ApiClient { .await } + #[instrument(level = "debug", skip(self))] + async fn build_information(&self) -> Result { + self.get_json( + &[ + routes::API_VERSION, + routes::API_STATUS_ROUTES, + routes::BUILD_INFORMATION, + ], + NO_PARAMS, + ) + .await + } + #[deprecated] #[instrument(level = "debug", skip(self))] async fn get_mixnodes(&self) -> Result, NymAPIError> { @@ -1015,6 +1032,23 @@ pub trait NymApiClientExt: ApiClient { .await } + async fn nodes_by_addresses( + &self, + addresses: Vec, + ) -> Result { + self.post_json( + &[ + routes::API_VERSION, + "unstable", + routes::NYM_NODES_ROUTES, + routes::nym_nodes::BY_ADDRESSES, + ], + NO_PARAMS, + &NodesByAddressesRequestBody { addresses }, + ) + .await + } + #[instrument(level = "debug", skip(self))] async fn get_network_details(&self) -> Result { self.get_json( @@ -1023,6 +1057,15 @@ pub trait NymApiClientExt: ApiClient { ) .await } + + #[instrument(level = "debug", skip(self))] + async fn get_chain_status(&self) -> Result { + self.get_json( + &[routes::API_VERSION, routes::NETWORK, routes::CHAIN_STATUS], + NO_PARAMS, + ) + .await + } } #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] diff --git a/common/client-libs/validator-client/src/nym_api/routes.rs b/common/client-libs/validator-client/src/nym_api/routes.rs index 767acc0b8d..8787264c4a 100644 --- a/common/client-libs/validator-client/src/nym_api/routes.rs +++ b/common/client-libs/validator-client/src/nym_api/routes.rs @@ -43,11 +43,14 @@ pub mod nym_nodes { pub const NYM_NODES_BONDED: &str = "bonded"; pub const NYM_NODES_REWARDED_SET: &str = "rewarded-set"; pub const NYM_NODES_REFRESH_DESCRIBED: &str = "refresh-described"; + pub const BY_ADDRESSES: &str = "by-addresses"; } pub const STATUS_ROUTES: &str = "status"; pub const API_STATUS_ROUTES: &str = "api-status"; pub const HEALTH: &str = "health"; +pub const BUILD_INFORMATION: &str = "build-information"; + pub const MIXNODE: &str = "mixnode"; pub const GATEWAY: &str = "gateway"; pub const NYM_NODES: &str = "nym-nodes"; @@ -69,4 +72,5 @@ pub const SUBMIT_NODE: &str = "submit-node-monitoring-results"; pub const SERVICE_PROVIDERS: &str = "services"; pub const DETAILS: &str = "details"; +pub const CHAIN_STATUS: &str = "chain-status"; pub const NETWORK: &str = "network"; diff --git a/common/client-libs/validator-client/src/nyxd/mod.rs b/common/client-libs/validator-client/src/nyxd/mod.rs index 458ba45c27..03746e305e 100644 --- a/common/client-libs/validator-client/src/nyxd/mod.rs +++ b/common/client-libs/validator-client/src/nyxd/mod.rs @@ -62,6 +62,7 @@ pub use cw3; pub use cw4; pub use cw_controllers; pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment}; +pub use prost::Name; pub use tendermint_rpc::endpoint::block::Response as BlockResponse; pub use tendermint_rpc::{ endpoint::{tx::Response as TxResponse, validators::Response as ValidatorResponse}, diff --git a/common/config/src/helpers.rs b/common/config/src/helpers.rs index cfed0dc1c7..d1ea90010b 100644 --- a/common/config/src/helpers.rs +++ b/common/config/src/helpers.rs @@ -25,15 +25,6 @@ pub fn in6addr_any_init() -> IpAddr { IpAddr::V6(Ipv6Addr::UNSPECIFIED) } -/// Helper for providing binding warnings if node tries to bind to any of those -pub const SPECIAL_ADDRESSES: &[IpAddr] = &[ - IpAddr::V4(Ipv4Addr::LOCALHOST), - IpAddr::V4(Ipv4Addr::UNSPECIFIED), - IpAddr::V4(Ipv4Addr::BROADCAST), - IpAddr::V6(Ipv6Addr::LOCALHOST), - IpAddr::V6(Ipv6Addr::UNSPECIFIED), -]; - // TODO: is it really part of 'Config'? pub trait OptionalSet { /// If the value is available (i.e. `Some`), the provided closure is applied. diff --git a/common/dkg/Cargo.toml b/common/dkg/Cargo.toml index 799e38a702..58e899d7b3 100644 --- a/common/dkg/Cargo.toml +++ b/common/dkg/Cargo.toml @@ -21,7 +21,7 @@ lazy_static = { workspace = true } rand = { workspace = true } rand_chacha = { workspace = true } rand_core = { workspace = true } -sha2 = "0.9" +sha2 = { workspace = true } serde = { workspace = true } serde_derive = { workspace = true } thiserror = { workspace = true } diff --git a/common/dkg/src/utils.rs b/common/dkg/src/utils.rs index 28fb99ad5d..e654a83f8c 100644 --- a/common/dkg/src/utils.rs +++ b/common/dkg/src/utils.rs @@ -54,12 +54,12 @@ pub(crate) fn hash_to_scalar>(msg: M, domain: &[u8]) -> Scalar { pub(crate) fn hash_to_scalars>(msg: M, domain: &[u8], n: usize) -> Vec { let mut output = vec![Scalar::zero(); n]; - Scalar::hash_to_field::>(msg.as_ref(), domain, &mut output); + Scalar::hash_to_field::, _>([msg], domain, &mut output); output } pub(crate) fn hash_g2>(msg: M, domain: &[u8]) -> G2Projective { - >>::hash_to_curve(msg, domain) + >>::hash_to_curve([msg], domain) } pub(crate) fn combine_scalar_chunks(chunks: &[Scalar]) -> Scalar { @@ -112,3 +112,97 @@ pub(crate) fn deserialize_g2(b: &[u8]) -> Option { G2Projective::from_bytes(&encoding).into() } } + +#[cfg(test)] +mod tests { + use super::*; + use bls12_381::G2Affine; + + #[test] + fn test_hash_to_scalar() { + let msg1 = "foo"; + let expected1 = Scalar::from_bytes(&[ + 253, 57, 224, 227, 175, 195, 226, 82, 46, 175, 33, 126, 171, 239, 255, 92, 108, 168, 6, + 79, 90, 11, 235, 236, 221, 10, 85, 133, 42, 81, 95, 30, + ]) + .unwrap(); + + let msg2 = "bar"; + let expected2 = Scalar::from_bytes(&[ + 48, 83, 69, 52, 42, 18, 135, 244, 211, 190, 160, 196, 118, 154, 24, 126, 0, 125, 72, + 201, 170, 225, 123, 201, 52, 120, 171, 132, 235, 182, 20, 26, + ]) + .unwrap(); + + let msg3 = [ + 33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123, + 250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27, + 115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101, + 60, 42, 92, 128, 131, 161, 43, + ]; + let expected3 = Scalar::from_bytes(&[ + 128, 189, 8, 43, 186, 55, 52, 61, 171, 196, 159, 177, 162, 100, 27, 143, 85, 83, 218, + 171, 91, 220, 155, 25, 7, 38, 2, 36, 4, 93, 136, 4, + ]) + .unwrap(); + + assert_eq!( + hash_to_scalar(msg1, b"NYMECASH-V01-CS02-with-expander-SHA256"), + expected1 + ); + assert_eq!( + hash_to_scalar(msg2, b"NYMECASH-V01-CS02-with-expander-SHA256"), + expected2 + ); + assert_eq!( + hash_to_scalar(msg3, b"NYMECASH-V01-CS02-with-expander-SHA256"), + expected3 + ); + } + + #[test] + fn test_hash_g2() { + let msg1 = "foo"; + let expected1 = G2Affine::from_compressed(&[ + 175, 187, 62, 7, 29, 17, 42, 93, 28, 93, 234, 253, 101, 166, 158, 187, 153, 82, 93, 18, + 11, 233, 36, 107, 51, 117, 30, 127, 32, 254, 210, 77, 133, 12, 253, 255, 84, 128, 36, + 214, 234, 103, 50, 21, 26, 78, 112, 49, 20, 69, 19, 109, 7, 78, 33, 227, 196, 180, 168, + 219, 73, 251, 192, 221, 41, 138, 160, 131, 191, 186, 156, 117, 179, 179, 191, 235, 171, + 26, 219, 148, 170, 179, 11, 38, 137, 14, 95, 115, 171, 186, 163, 82, 158, 6, 239, 88, + ]) + .unwrap() + .into(); + + let msg2 = "bar"; + let expected2 = G2Affine::from_compressed(&[ + 183, 25, 90, 187, 34, 184, 30, 182, 215, 242, 158, 83, 116, 34, 210, 96, 188, 79, 83, + 255, 100, 122, 90, 188, 196, 93, 164, 253, 20, 106, 205, 33, 48, 140, 60, 149, 66, 246, + 121, 244, 146, 66, 170, 60, 113, 95, 102, 237, 25, 231, 8, 42, 121, 124, 180, 140, 34, + 104, 173, 251, 89, 189, 28, 196, 49, 66, 101, 38, 68, 44, 40, 235, 21, 35, 204, 123, + 218, 238, 216, 92, 134, 217, 212, 246, 176, 77, 187, 0, 245, 134, 132, 73, 31, 44, 137, + 197, + ]) + .unwrap() + .into(); + let msg3 = [ + 33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123, + 250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27, + 115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101, + 60, 42, 92, 128, 131, 161, 43, + ]; + let expected3 = G2Affine::from_compressed(&[ + 151, 185, 8, 123, 223, 150, 192, 192, 115, 10, 3, 129, 49, 179, 31, 108, 0, 17, 46, + 231, 184, 164, 247, 228, 22, 142, 87, 70, 120, 111, 154, 15, 245, 110, 32, 84, 53, 117, + 239, 93, 89, 119, 32, 17, 39, 250, 198, 137, 6, 95, 137, 202, 54, 244, 238, 190, 11, + 217, 237, 95, 72, 59, 140, 56, 3, 42, 61, 195, 192, 101, 46, 204, 207, 75, 70, 176, + 207, 48, 24, 195, 248, 234, 178, 168, 54, 109, 19, 189, 51, 52, 120, 69, 248, 226, 102, + 91, + ]) + .unwrap() + .into(); + + assert_eq!(hash_g2(msg1, b"DUMMY_TEST_DOMAIN"), expected1); + assert_eq!(hash_g2(msg2, b"DUMMY_TEST_DOMAIN"), expected2); + assert_eq!(hash_g2(msg3, b"DUMMY_TEST_DOMAIN"), expected3); + } +} diff --git a/common/gateway-requests/src/types/error.rs b/common/gateway-requests/src/types/error.rs index 0a785e60ec..edd8e41b22 100644 --- a/common/gateway-requests/src/types/error.rs +++ b/common/gateway-requests/src/types/error.rs @@ -10,6 +10,7 @@ use nym_sphinx::params::packet_sizes::PacketSize; use serde::{Deserialize, Serialize}; use std::string::FromUtf8Error; use thiserror::Error; +use time::OffsetDateTime; // specific errors (that should not be nested!!) for clients to match on #[derive(Debug, Copy, Clone, Error, Serialize, Deserialize)] @@ -112,15 +113,15 @@ pub enum AuthenticationFailure { #[error("failed to verify request signature")] InvalidSignature(#[from] SignatureError), - #[error("provided request timestamp is in the future")] - RequestTimestampInFuture, - #[error("the client is not registered")] NotRegistered, - #[error("the provided request is too stale to process")] - StaleRequest, + #[error("the provided request timestamp is excessively skewed. got {received} whilst the server time is {server}")] + ExcessiveTimestampSkew { + received: OffsetDateTime, + server: OffsetDateTime, + }, - #[error("the provided request timestamp is smaller or equal to a one previously used")] + #[error("the provided request timestamp is smaller or equal to one previously used")] RequestReuse, } diff --git a/common/gateway-requests/src/types/text_request/authenticate.rs b/common/gateway-requests/src/types/text_request/authenticate.rs index 6015beb8ad..6c4c884957 100644 --- a/common/gateway-requests/src/types/text_request/authenticate.rs +++ b/common/gateway-requests/src/types/text_request/authenticate.rs @@ -38,13 +38,22 @@ impl AuthenticateRequest { }) } - pub fn verify_timestamp(&self, max_request_age: Duration) -> Result<(), AuthenticationFailure> { + pub fn verify_timestamp( + &self, + max_request_timestamp_skew: Duration, + ) -> Result<(), AuthenticationFailure> { let now = OffsetDateTime::now_utc(); - if self.content.request_timestamp() + max_request_age < now { - return Err(AuthenticationFailure::StaleRequest); + if self.content.request_timestamp() < now - max_request_timestamp_skew { + return Err(AuthenticationFailure::ExcessiveTimestampSkew { + received: self.content.request_timestamp(), + server: now, + }); } - if self.content.request_timestamp() > now { - return Err(AuthenticationFailure::RequestTimestampInFuture); + if self.content.request_timestamp() - max_request_timestamp_skew > now { + return Err(AuthenticationFailure::ExcessiveTimestampSkew { + received: self.content.request_timestamp(), + server: now, + }); } Ok(()) } diff --git a/common/http-api-client/src/dns.rs b/common/http-api-client/src/dns.rs index 7e0519de98..4d4aae82d6 100644 --- a/common/http-api-client/src/dns.rs +++ b/common/http-api-client/src/dns.rs @@ -1,3 +1,6 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + //! DNS resolver configuration for internal lookups. //! //! The resolver itself is the set combination of the google, cloudflare, and quad9 endpoints @@ -9,6 +12,19 @@ //! //! Requires the `dns-over-https-rustls`, `webpki-roots` feature for the //! `hickory-resolver` crate +//! +//! +//! Note: The hickory DoH resolver can cause warning logs about H2 connection failure. This +//! indicates that the long lived https connection was closed by the remote peer and the resolver +//! will have to reconnect. It should not impact actual functionality. +//! +//! code ref: https://github.com/hickory-dns/hickory-dns/blob/06a8b1ce9bd9322d8e6accf857d30257e1274427/crates/proto/src/h2/h2_client_stream.rs#L534 +//! +//! example log: +//! +//! ```txt +//! WARN /home/ubuntu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/hickory-proto-0.24.3/src/h2/h2_client_stream.rs:493: h2 connection failed: unexpected end of file +//! ``` #![deny(missing_docs)] use crate::ClientBuilder; @@ -33,6 +49,13 @@ impl ClientBuilder { /// Override the DNS resolver implementation used by the underlying http client. pub fn dns_resolver(mut self, resolver: Arc) -> Self { self.reqwest_client_builder = self.reqwest_client_builder.dns_resolver(resolver); + self.use_secure_dns = false; + self + } + + /// Override the DNS resolver implementation used by the underlying http client. + pub fn no_hickory_dns(mut self) -> Self { + self.use_secure_dns = false; self } } diff --git a/common/http-api-client/src/lib.rs b/common/http-api-client/src/lib.rs index 4b2938daa4..5a360f7be1 100644 --- a/common/http-api-client/src/lib.rs +++ b/common/http-api-client/src/lib.rs @@ -228,6 +228,8 @@ pub struct ClientBuilder { timeout: Option, custom_user_agent: bool, reqwest_client_builder: reqwest::ClientBuilder, + #[allow(dead_code)] // not dead code, just unused in wasm + use_secure_dns: bool, } impl ClientBuilder { @@ -239,37 +241,46 @@ impl ClientBuilder { U: IntoUrl, E: Display, { - // a naive check: if the provided URL does not start with http(s), add that scheme let str_url = url.as_str(); + // a naive check: if the provided URL does not start with http(s), add that scheme if !str_url.starts_with("http") { let alt = format!("http://{str_url}"); warn!("the provided url ('{str_url}') does not contain scheme information. Changing it to '{alt}' ..."); // TODO: or should we maybe default to https? Self::new(alt) } else { - #[cfg(target_arch = "wasm32")] - let reqwest_client_builder = reqwest::ClientBuilder::new(); + Ok(Self::new_with_url(url.into_url()?)) + } + } - #[cfg(not(target_arch = "wasm32"))] - let reqwest_client_builder = { - let r = reqwest::ClientBuilder::new() - .dns_resolver(Arc::new(HickoryDnsResolver::default())); + /// Constructs a new http `ClientBuilder` from a valid url. + pub fn new_with_url(url: Url) -> Self { + if !url.scheme().starts_with("http") { + warn!("the provided url ('{url}') does not use HTTP / HTTPS scheme"); + } - // Note this is extra as the `gzip` feature for `reqwest` crate should be enabled which - // `"Enable[s] auto gzip decompression by checking the Content-Encoding response header."` - // - // I am going to leave it here anyways so that gzip decompression is attempted even if - // that feature is removed. - r.gzip(true) - }; + #[cfg(target_arch = "wasm32")] + let reqwest_client_builder = reqwest::ClientBuilder::new(); - Ok(ClientBuilder { - url: url.into_url()?, - timeout: None, - custom_user_agent: false, - reqwest_client_builder, - }) + #[cfg(not(target_arch = "wasm32"))] + let reqwest_client_builder = { + let r = reqwest::ClientBuilder::new(); + + // Note this is extra as the `gzip` feature for `reqwest` crate should be enabled which + // `"Enable[s] auto gzip decompression by checking the Content-Encoding response header."` + // + // I am going to leave it here anyways so that gzip decompression is attempted even if + // that feature is removed. + r.gzip(true) + }; + + ClientBuilder { + url, + timeout: None, + custom_user_agent: false, + reqwest_client_builder, + use_secure_dns: true, } } @@ -325,10 +336,18 @@ impl ClientBuilder { let mut builder = self .reqwest_client_builder .timeout(self.timeout.unwrap_or(DEFAULT_TIMEOUT)); + + // if no custom user agent was set, use a default if !self.custom_user_agent { builder = builder.user_agent(format!("nym-http-api-client/{}", env!("CARGO_PKG_VERSION"))) } + + // unless explicitly disabled use the DoT/DoH enabled resolver + if self.use_secure_dns { + builder = builder.dns_resolver(Arc::new(HickoryDnsResolver::default())); + } + builder.build()? }; @@ -355,6 +374,9 @@ pub struct Client { impl Client { /// Create a new http `Client` // no timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed + // + // In order to prevent interference in API requests at the DNS phase we default to a resolver + // that uses DoT and DoH. pub fn new(base_url: Url, timeout: Option) -> Self { Self::new_url::<_, String>(base_url, timeout).expect( "we provided valid url and we were unwrapping previous construction errors anyway", diff --git a/common/nym_offline_compact_ecash/Cargo.toml b/common/nym_offline_compact_ecash/Cargo.toml index 9b29d818fe..718787b457 100644 --- a/common/nym_offline_compact_ecash/Cargo.toml +++ b/common/nym_offline_compact_ecash/Cargo.toml @@ -15,10 +15,10 @@ bls12_381 = { workspace = true, features = ["alloc", "pairings", "experimental", bincode.workspace = true cfg-if.workspace = true itertools = { workspace = true } -digest = "0.9" +digest = { workspace = true } rand = { workspace = true } thiserror = { workspace = true } -sha2 = "0.9" +sha2 = { workspace = true } bs58 = { workspace = true } serde = { workspace = true, features = ["derive"] } rayon = { workspace = true, optional = true } diff --git a/common/nym_offline_compact_ecash/src/utils.rs b/common/nym_offline_compact_ecash/src/utils.rs index 57a648fff2..a04f377ddf 100644 --- a/common/nym_offline_compact_ecash/src/utils.rs +++ b/common/nym_offline_compact_ecash/src/utils.rs @@ -113,17 +113,13 @@ const G1_HASH_DOMAIN: &[u8] = b"NYMECASH-V01-CS02-with-BLS12381G1_XMD:SHA-256_SS const SCALAR_HASH_DOMAIN: &[u8] = b"NYMECASH-V01-CS02-with-expander-SHA256"; pub fn hash_g1>(msg: M) -> G1Projective { - >>::hash_to_curve(msg, G1_HASH_DOMAIN) + >>::hash_to_curve([msg], G1_HASH_DOMAIN) } pub fn hash_to_scalar>(msg: M) -> Scalar { let mut output = vec![Scalar::zero()]; - Scalar::hash_to_field::>( - msg.as_ref(), - SCALAR_HASH_DOMAIN, - &mut output, - ); + Scalar::hash_to_field::, _>([msg], SCALAR_HASH_DOMAIN, &mut output); output[0] } @@ -401,4 +397,75 @@ mod tests { assert_eq!(hash_to_scalar(msg2), hash_to_scalar(msg2)); assert_ne!(hash_to_scalar(msg1), hash_to_scalar(msg2)); } + + #[test] + fn test_hash_to_scalar() { + let msg1 = "foo"; + let expected1 = Scalar::from_bytes(&[ + 253, 57, 224, 227, 175, 195, 226, 82, 46, 175, 33, 126, 171, 239, 255, 92, 108, 168, 6, + 79, 90, 11, 235, 236, 221, 10, 85, 133, 42, 81, 95, 30, + ]) + .unwrap(); + + let msg2 = "bar"; + let expected2 = Scalar::from_bytes(&[ + 48, 83, 69, 52, 42, 18, 135, 244, 211, 190, 160, 196, 118, 154, 24, 126, 0, 125, 72, + 201, 170, 225, 123, 201, 52, 120, 171, 132, 235, 182, 20, 26, + ]) + .unwrap(); + + let msg3 = [ + 33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123, + 250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27, + 115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101, + 60, 42, 92, 128, 131, 161, 43, + ]; + let expected3 = Scalar::from_bytes(&[ + 128, 189, 8, 43, 186, 55, 52, 61, 171, 196, 159, 177, 162, 100, 27, 143, 85, 83, 218, + 171, 91, 220, 155, 25, 7, 38, 2, 36, 4, 93, 136, 4, + ]) + .unwrap(); + + assert_eq!(hash_to_scalar(msg1), expected1); + assert_eq!(hash_to_scalar(msg2), expected2); + assert_eq!(hash_to_scalar(msg3), expected3); + } + + #[test] + fn test_hash_to_g1() { + let msg1 = "foo"; + let expected1 = G1Affine::from_compressed(&[ + 161, 109, 186, 0, 192, 221, 83, 87, 71, 31, 120, 201, 185, 35, 62, 239, 46, 120, 117, + 150, 191, 227, 128, 161, 78, 201, 207, 167, 86, 181, 229, 115, 2, 6, 178, 16, 251, 118, + 219, 115, 184, 96, 2, 10, 31, 63, 150, 70, + ]) + .unwrap() + .into(); + + let msg2 = "bar"; + let expected2 = G1Affine::from_compressed(&[ + 135, 102, 204, 42, 221, 49, 209, 192, 250, 87, 59, 255, 197, 93, 37, 113, 38, 2, 154, + 233, 68, 234, 206, 182, 121, 212, 166, 210, 74, 155, 190, 33, 203, 237, 176, 60, 249, + 241, 53, 170, 18, 168, 49, 35, 1, 151, 205, 174, + ]) + .unwrap() + .into(); + let msg3 = [ + 33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123, + 250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27, + 115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101, + 60, 42, 92, 128, 131, 161, 43, + ]; + let expected3 = G1Affine::from_compressed(&[ + 184, 200, 211, 115, 47, 45, 39, 185, 105, 9, 222, 247, 132, 241, 121, 130, 238, 224, + 155, 109, 105, 201, 137, 154, 132, 149, 214, 233, 136, 69, 77, 132, 174, 30, 46, 123, + 20, 92, 219, 18, 45, 29, 208, 127, 158, 145, 130, 41, + ]) + .unwrap() + .into(); + + assert_eq!(hash_g1(msg1), expected1); + assert_eq!(hash_g1(msg2), expected2); + assert_eq!(hash_g1(msg3), expected3); + } } diff --git a/common/nymsphinx/addressing/src/nodes.rs b/common/nymsphinx/addressing/src/nodes.rs index c748a72dcd..4171410b6c 100644 --- a/common/nymsphinx/addressing/src/nodes.rs +++ b/common/nymsphinx/addressing/src/nodes.rs @@ -161,6 +161,12 @@ impl From for SocketAddr { } } +impl AsRef for NymNodeRoutingAddress { + fn as_ref(&self) -> &SocketAddr { + &self.0 + } +} + impl TryInto for NymNodeRoutingAddress { type Error = NymNodeRoutingAddressError; diff --git a/common/nymsphinx/anonymous-replies/src/reply_surb.rs b/common/nymsphinx/anonymous-replies/src/reply_surb.rs index a6729e7e5d..90bd892d78 100644 --- a/common/nymsphinx/anonymous-replies/src/reply_surb.rs +++ b/common/nymsphinx/anonymous-replies/src/reply_surb.rs @@ -7,7 +7,7 @@ use nym_sphinx_addressing::clients::Recipient; use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN}; use nym_sphinx_params::packet_sizes::PacketSize; use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm}; -use nym_sphinx_types::{NymPacket, SURBMaterial, SphinxError, SURB, UPDATED_LEGACY_VERSION}; +use nym_sphinx_types::{NymPacket, SURBMaterial, SphinxError, SURB}; use nym_topology::{NymRouteProvider, NymTopologyError}; use rand::{CryptoRng, RngCore}; use serde::de::{Error as SerdeError, Visitor}; @@ -101,8 +101,7 @@ impl ReplySurb { let delays = nym_sphinx_routing::generate_hop_delays(average_delay, route.len()); let destination = recipient.as_sphinx_destination(); - let surb_material = - SURBMaterial::new(route, delays, destination).with_version(UPDATED_LEGACY_VERSION); + let surb_material = SURBMaterial::new(route, delays, destination); // this can't fail as we know we have a valid route to gateway and have correct number of delays Ok(ReplySurb { diff --git a/common/nymsphinx/types/src/lib.rs b/common/nymsphinx/types/src/lib.rs index c9441dbc4d..517e45e783 100644 --- a/common/nymsphinx/types/src/lib.rs +++ b/common/nymsphinx/types/src/lib.rs @@ -30,7 +30,6 @@ pub use sphinx_packet::{ route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier}, surb::{SURBMaterial, SURB}, version::Version, - version::UPDATED_LEGACY_VERSION, Error as SphinxError, ProcessedPacket, ProcessedPacketData, }; @@ -91,12 +90,8 @@ impl NymPacket { destination: &Destination, delays: &[Delay], ) -> Result { - // FIXME: - // for now explicitly use the legacy version until sufficient number of nodes - // understand both variants Ok(NymPacket::Sphinx( SphinxPacketBuilder::new() - .with_version(UPDATED_LEGACY_VERSION) .with_payload_size(size) .build_packet(message, route, destination, delays)?, )) diff --git a/common/nyxd-scraper/src/block_processor/mod.rs b/common/nyxd-scraper/src/block_processor/mod.rs index e75d62b7df..d4007de96b 100644 --- a/common/nyxd-scraper/src/block_processor/mod.rs +++ b/common/nyxd-scraper/src/block_processor/mod.rs @@ -182,9 +182,11 @@ impl BlockProcessor { // the ones concerned with individual messages for (index, msg) in block_tx.tx.body.messages.iter().enumerate() { for msg_module in &mut self.msg_modules { - msg_module - .handle_msg(index, msg, &block_tx, &mut tx) - .await? + if msg.type_url == msg_module.type_url() { + msg_module + .handle_msg(index, msg, &block_tx, &mut tx) + .await? + } } } } diff --git a/common/nyxd-scraper/src/error.rs b/common/nyxd-scraper/src/error.rs index 6e413983bd..3337ee969c 100644 --- a/common/nyxd-scraper/src/error.rs +++ b/common/nyxd-scraper/src/error.rs @@ -83,6 +83,15 @@ pub enum ScraperError { source: cosmrs::ErrorReport, }, + #[error("could not parse msg in tx {hash} at index {index} into {type_url}: {source}")] + MsgParseFailure { + hash: Hash, + index: usize, + type_url: String, + #[source] + source: cosmrs::ErrorReport, + }, + #[error("received an invalid chain subscription event of kind {kind} while we were waiting for new block data (query: '{query}')")] InvalidSubscriptionEvent { query: String, kind: String }, diff --git a/common/nyxd-scraper/src/modules/msg_module.rs b/common/nyxd-scraper/src/modules/msg_module.rs index df64761f7d..1d195bee14 100644 --- a/common/nyxd-scraper/src/modules/msg_module.rs +++ b/common/nyxd-scraper/src/modules/msg_module.rs @@ -9,6 +9,8 @@ use cosmrs::Any; #[async_trait] pub trait MsgModule { + fn type_url(&self) -> String; + async fn handle_msg( &mut self, index: usize, diff --git a/common/task/src/connections.rs b/common/task/src/connections.rs index af13111526..6739ecf9f5 100644 --- a/common/task/src/connections.rs +++ b/common/task/src/connections.rs @@ -103,4 +103,8 @@ impl LaneQueueLengthsInner { { self.map.entry(*lane).and_modify(f); } + + pub fn total(&self) -> usize { + self.map.values().sum() + } } diff --git a/common/topology/src/lib.rs b/common/topology/src/lib.rs index 2150d587cb..4354721bc5 100644 --- a/common/topology/src/lib.rs +++ b/common/topology/src/lib.rs @@ -254,6 +254,15 @@ impl NymTopology { } } + pub fn with_additional_nodes(mut self, nodes: impl Iterator) -> Self + where + N: TryInto, + >::Error: Display, + { + self.add_additional_nodes(nodes); + self + } + pub fn has_node_details(&self, node_id: NodeId) -> bool { self.node_details.contains_key(&node_id) } diff --git a/common/wasm/client-core/src/config/mod.rs b/common/wasm/client-core/src/config/mod.rs index 64b8be5d40..b038e20737 100644 --- a/common/wasm/client-core/src/config/mod.rs +++ b/common/wasm/client-core/src/config/mod.rs @@ -494,6 +494,9 @@ pub struct ReplySurbsWasm { /// Defines how many mix nodes the reply surb should go through. /// If not set, the default value is going to be used. pub surb_mix_hops: Option, + + /// Specifies if we should reset all the sender tags on startup + pub fresh_sender_tags: bool, } impl Default for ReplySurbsWasm { @@ -525,6 +528,7 @@ impl From for ConfigReplySurbs { reply_surbs.maximum_reply_key_age_ms as u64, ), surb_mix_hops: reply_surbs.surb_mix_hops, + fresh_sender_tags: reply_surbs.fresh_sender_tags, } } } @@ -548,6 +552,7 @@ impl From for ReplySurbsWasm { maximum_reply_surb_age_ms: reply_surbs.maximum_reply_surb_age.as_millis() as u32, maximum_reply_key_age_ms: reply_surbs.maximum_reply_key_age.as_millis() as u32, surb_mix_hops: reply_surbs.surb_mix_hops, + fresh_sender_tags: reply_surbs.fresh_sender_tags, } } } diff --git a/common/wasm/client-core/src/config/override.rs b/common/wasm/client-core/src/config/override.rs index 72da8bd43d..bc9275660a 100644 --- a/common/wasm/client-core/src/config/override.rs +++ b/common/wasm/client-core/src/config/override.rs @@ -378,6 +378,9 @@ pub struct ReplySurbsWasmOverride { #[tsify(optional)] pub surb_mix_hops: Option, + + /// Specifies if we should reset all the sender tags on startup + pub fresh_sender_tags: bool, } impl From for ReplySurbsWasm { @@ -416,6 +419,7 @@ impl From for ReplySurbsWasm { .maximum_reply_key_age_ms .unwrap_or(def.maximum_reply_key_age_ms), surb_mix_hops: value.surb_mix_hops, + fresh_sender_tags: value.fresh_sender_tags, } } } diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index ddf71c7999..3f161750a1 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -1185,6 +1185,7 @@ name = "nym-pemstore" version = "0.3.0" dependencies = [ "pem", + "tracing", ] [[package]] @@ -1251,6 +1252,12 @@ dependencies = [ "regex", ] +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "pkcs8" version = "0.9.0" @@ -1470,9 +1477,9 @@ checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", "schemars_derive", @@ -1482,9 +1489,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", @@ -1522,18 +1529,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -1558,9 +1565,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -1777,9 +1784,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" dependencies = [ "deranged", "itoa", @@ -1794,15 +1801,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" dependencies = [ "num-conv", "time-core", @@ -1840,6 +1847,37 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + [[package]] name = "typenum" version = "1.18.0" diff --git a/documentation/docs/.gitignore b/documentation/docs/.gitignore index 515d7fce8d..60d8350455 100644 --- a/documentation/docs/.gitignore +++ b/documentation/docs/.gitignore @@ -7,4 +7,6 @@ package-lock.json # local env files .env*.local -.env \ No newline at end of file +.env + +scratch.md diff --git a/documentation/docs/components/operators/snippets/ntp-time-sync.mdx b/documentation/docs/components/operators/snippets/ntp-time-sync.mdx new file mode 100644 index 0000000000..945a39470a --- /dev/null +++ b/documentation/docs/components/operators/snippets/ntp-time-sync.mdx @@ -0,0 +1,10 @@ +- Run synchronization against [pool.ntp.org](https://www.ntppool.org/en/): +```bash +ntpdate -q pool.ntp.org +``` +- Enable `ntp` service, start and review the status: +```bash +systemctl enable --now ntp +service ntp start +service ntp status +``` diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/circulating-supply.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/circulating-supply.md index 16f5edc4de..f71e380d34 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/circulating-supply.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/circulating-supply.md @@ -1 +1 @@ -807_251_217 +808_623_916 diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md index 39bbb86bce..a0b4b18b43 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-percent-stake.md @@ -1 +1 @@ -0.64% +0.68% diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md index 64cb46e4ca..05292828a2 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/nyx-total-stake.md @@ -1 +1 @@ -44.332 +42.157 diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/stake-saturation.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/stake-saturation.md index 11c0eeb3d3..6a6f41769e 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/stake-saturation.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/stake-saturation.md @@ -1 +1 @@ -1_025_628 +1_028_488 diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/staking-target.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/staking-target.md index 8bf62f72c2..dd8fe066d0 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/staking-target.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/staking-target.md @@ -1 +1 @@ -403_625_608 +404_311_958 diff --git a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/token-table.md b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/token-table.md index dabaa45e3a..d4a66cde69 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/token-table.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/nyx-outputs/token-table.md @@ -1,7 +1,7 @@ | **Item** | **Description** | **Amount in NYM** | |:-------------------|:------------------------------------------------------|--------------------:| | Total Supply | Maximum amount of NYM token in existence | 1_000_000_000 | -| Mixmining Reserve | Tokens releasing for operators rewards | 192_748_782 | +| Mixmining Reserve | Tokens releasing for operators rewards | 191_376_083 | | Vesting Tokens | Tokens locked outside of cicrulation for future claim | 0 | -| Circulating Supply | Amount of unlocked tokens | 807_251_217 | -| Stake Saturation | Optimal size of node self-bond + delegation | 1_025_628 | +| Circulating Supply | Amount of unlocked tokens | 808_623_916 | +| Stake Saturation | Optimal size of node self-bond + delegation | 1_028_488 | diff --git a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md index 6b6e11be89..dddd026436 100644 --- a/documentation/docs/components/outputs/api-scraping-outputs/time-now.md +++ b/documentation/docs/components/outputs/api-scraping-outputs/time-now.md @@ -1 +1 @@ -Monday, February 3rd 2025, 13:47:19 UTC +Tuesday, March 11th 2025, 11:04:18 UTC diff --git a/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md b/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md index 32508afe64..1a70eacf1d 100644 --- a/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md +++ b/documentation/docs/components/outputs/command-outputs/nym-node-run-help.md @@ -16,8 +16,10 @@ Options: If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses [env: NYMNODE_INIT_ONLY=] --local Flag specifying this node will be running in a local setting [env: NYMNODE_LOCAL=] - --mode - Specifies the current mode of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway] + --mode [...] + Specifies the current mode(s) of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only] + --modes + Specifies the current mode(s) of this nym-node as a single flag [env: NYMNODE_MODES=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only] -w, --write-changes If this node has been initialised before, specify whether to write any new changes to the config file [env: NYMNODE_WRITE_CONFIG_CHANGES=] --bonding-information-output @@ -31,7 +33,7 @@ Options: --location Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=] --http-bind-address - Socket address this node will use for binding its http API. default: `0.0.0.0:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=] + Socket address this node will use for binding its http API. default: `[::]:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=] --landing-page-assets-path Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=] --http-access-token @@ -43,27 +45,29 @@ Options: --expose-crypto-hardware Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false] --mixnet-bind-address - Address this node will bind to for listening for mixnet packets default: `0.0.0.0:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=] + Address this node will bind to for listening for mixnet packets default: `[::]:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=] --mixnet-announce-port If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=] --nym-api-urls Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=] --nyxd-urls Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=] + --enable-console-logging + Specify whether running statistics of this node should be logged to the console [env: NYMNODE_ENABLE_CONSOLE_LOGGING=] [possible values: true, false] --wireguard-enabled Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false] --wireguard-bind-address - Socket address this node will use for binding its wireguard interface. default: `0.0.0.0:51822` [env: NYMNODE_WG_BIND_ADDRESS=] + Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env: NYMNODE_WG_BIND_ADDRESS=] --wireguard-announced-port Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=] --wireguard-private-network-prefix The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=] --verloc-bind-address - Socket address this node will use for binding its verloc API. default: `0.0.0.0:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=] + Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=] --verloc-announce-port If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=] --entry-bind-address - Socket address this node will use for binding its client websocket API. default: `0.0.0.0:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=] + Socket address this node will use for binding its client websocket API. default: `[::]:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=] --announce-ws-port Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=] --announce-wss-port diff --git a/documentation/docs/pages/apis/cosmos-sdk-nyx/_meta.json b/documentation/docs/pages/apis/cosmos-sdk-nyx/_meta.json new file mode 100644 index 0000000000..8e5aad88d7 --- /dev/null +++ b/documentation/docs/pages/apis/cosmos-sdk-nyx/_meta.json @@ -0,0 +1,5 @@ + +{ + "mainnet":"Mainnet Endpoints", + "sandbox":"Sandbox Endpoints" +} diff --git a/documentation/docs/pages/apis/explorer-api/_meta.json b/documentation/docs/pages/apis/explorer-api/_meta.json new file mode 100644 index 0000000000..8e5aad88d7 --- /dev/null +++ b/documentation/docs/pages/apis/explorer-api/_meta.json @@ -0,0 +1,5 @@ + +{ + "mainnet":"Mainnet Endpoints", + "sandbox":"Sandbox Endpoints" +} diff --git a/documentation/docs/pages/apis/ns-api.mdx b/documentation/docs/pages/apis/ns-api.mdx index 85d2ea4566..9e14e1509c 100644 --- a/documentation/docs/pages/apis/ns-api.mdx +++ b/documentation/docs/pages/apis/ns-api.mdx @@ -1,11 +1,8 @@ import { Callout } from 'nextra/components' # Node Status API - -The Node Status API contains information about the network, its topology, and the routing scores of all nodes within it. It offers broadly similar information to the experimental [Habourmaster frontend](https://harbourmaster.nymtech.net/) but is stable where the Harbourmaster is subject to sudden changes as we modify and experiment with how we scrape and present data about the Mixnet infrastructure. +The Node Status API serves information about individual `nym-nodes` in the Mixnet, such as which role they are operating in, statistics about them, services such as Network Requesters, as well as summaries of the state of the Mixnet. -People building applications or dashboards which requires information about nodes, their uptime, and their delegations should use this instead of Habourmaster. +We recommend that developers building applications such as explorers or analytics interfaces about the Mixnet run their own instance of the API, in order to promote a robust network of downstream services, and spread the load of API calls amongst as many endpoints as possible. - -The code for this service can be found [in our monorepo](https://github.com/nymtech/nym/tree/develop/nym-node-status-api). In the future we will encourage developers to run their own instance of this API in order to distribute endpoints and query load. diff --git a/documentation/docs/pages/apis/ns-api/_meta.json b/documentation/docs/pages/apis/ns-api/_meta.json new file mode 100644 index 0000000000..7d443d9f6d --- /dev/null +++ b/documentation/docs/pages/apis/ns-api/_meta.json @@ -0,0 +1,5 @@ +{ + "ns-api-run-deploy":"Run Instance", + "mainnet":"Mainnet Endpoints", + "sandbox":"Sandbox Endpoints" +} diff --git a/documentation/docs/pages/apis/ns-api/mainnet.mdx b/documentation/docs/pages/apis/ns-api/mainnet.mdx index a517ba0edd..00a6523ae7 100644 --- a/documentation/docs/pages/apis/ns-api/mainnet.mdx +++ b/documentation/docs/pages/apis/ns-api/mainnet.mdx @@ -1,9 +1,11 @@ import { RedocStandalone } from 'redoc'; +import { Callout } from 'nextra/components' The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://mainnet-node-status-api.nymtech.cc/swagger/](https://mainnet-node-status-api.nymtech.cc/swagger/).

+ +We invite developers to roll their own UI for their Node Status API instance. + + +## Docker Images +We will ship Docker images for both the `agent` and `api` in the future. There are Docker images for both in root of each corresponding crate ([`agent`](https://github.com/nymtech/nym/blob/09ea406c02e9a3beebc062f525e4ea1b4222dcbb/nym-node-status-api/nym-node-status-agent/Dockerfile), [`api`](https://github.com/nymtech/nym/blob/develop/nym-node-status-api/nym-node-status-api/Dockerfile)) which are used internally, which could be a starting point for developers to dockerize their instance for the moment. + +## Build +### Prerequisites +- Rust +- SQLite +- Get an `ipinfo` key following instructions [here](https://github.com/ipinfo/rust?tab=readme-ov-file#getting-started). + +### Compilation +```shell +cargo build --release --package nym-node-status-api --package nym-node-status-agent --package nym-node-status-client +``` + +## Run +Since the Node Status API depends on both flags and environmental variables, it might be easier to run the binary via a script like the one below - this this script essentially just `source`-s the defined `.env` file after exporting certain binary-specific variables, and then runs the binary. You can find the `.env` files [here](https://github.com/nymtech/nym/tree/master/envs). + + + All CLI flags are configurable as environmental variables and vice versa, so take the following scripts / setups as guides that you can change however best suits your setup. You can see all definitions [here](https://github.com/nymtech/nym/blob/develop/nym-node-status-api/nym-node-status-api/src/cli/mod.rs#L14). + + +```bash +#!/bin/bash + +set -e + +export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} # see nym/envs/ for all possible environments +export NYM_API_CLIENT_TIMEOUT=60 +export NODE_STATUS_API_TESTRUN_REFRESH_INTERVAL=120 +export IPINFO_API_TOKEN= + +monorepo_root= +set -a +source "${monorepo_root}/envs/${ENVIRONMENT}.env" +echo ${monorepo_root}/envs/${ENVIRONMENT}.env +set +a +export RUST_LOG=${RUST_LOG:-debug} # debug is useful to check everything is working initially, but quite verbose + +echo "Verifying environment variables were properly sourced:" +echo "RUST_LOG=${RUST_LOG}" +echo "BECH32_PREFIX=${BECH32_PREFIX}" +echo "NETWORK_NAME=${NETWORK_NAME}" + +nym-node-status-api -- --ipinfo-api-token $IPINFO_API_TOKEN +``` + +### Functionality Without Gateway Probe +Data will be restricted to information that doesn't involve Probe results; `routing` and `config` scores will be `0` and `last_probe` results `null`, as you can see in this snipped output of the `gateways` endpoint: + + +```shell +{ + "gateway_identity_key": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb", + "bonded": true, + "performance": 99, + "self_described": { + "authenticator": { + "address": "6Gdtw13Fa46AvkqkHELZZCMKWASDodoJeK9APRNpjjdj.7ji8DDkpjA2AdgwK7wbZm8yi4xZGogGJeypBQt4hAw3P@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb" + }, + "auxiliary_details": { + "accepted_operator_terms_and_conditions": true, + "announce_ports": { + "mix_port": null, + "verloc_port": null + }, + "location": null + }, + "build_information": { + "binary_name": "nym-node", + "build_timestamp": "2025-02-13T11:49:34.670488195Z", + "build_version": "1.5.0", + "cargo_profile": "release", + "cargo_triple": "x86_64-unknown-linux-gnu", + "commit_branch": "HEAD", + "commit_sha": "a3e19b4563843055b305ea9a397eb1ad84b5c378", + "commit_timestamp": "2025-02-10T18:14:47.000000000+01:00", + "rustc_channel": "stable", + "rustc_version": "1.84.1" + }, + "declared_role": { + "entry": true, + "exit_ipr": true, + "exit_nr": true, + "mixnode": false + }, + "host_information": { + "hostname": "bwng1.bwnym.xyz", + "ip_address": [ + "95.164.2.86" + ], + "keys": { + "ed25519": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb", + "x25519": "H6pFjqtdSVxkxEQ3wFnuSoobDAUqHx1bYMVJzPZdRByn", + "x25519_noise": null + } + }, + "ip_packet_router": { + "address": "7ms2D2uYiTuhX6MKeVL5rz5usgehEoxAAovwYm9nJyBF.3siMjk3wTU7ykaXLNi9c7LpX8yonYKPCA4BQoMwhsfTV@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb" + }, + "last_polled": "2025-03-03 09:48:03.635274187 +00:00:00", + "mixnet_websockets": { + "ws_port": 9000, + "wss_port": 9001 + }, + "network_requester": { + "address": "HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb", + "uses_exit_policy": true + }, + "wireguard": { + "port": 51822, + "public_key": "6o8x9GitFjcrkjrJnivWaQCPnxXykQPYLneNr2FEB8Vq" + } + }, + "explorer_pretty_bond": { + "identity_key": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb", + "location": { + "latitude": 52.5083, + "longitude": 5.475, + "two_letter_iso_country_code": "NL" + }, + "owner": "n1cp5gq0apat6c7qmenqp5zjprn2vwvc7jl29j8r", + "pledge_amount": { + "amount": "100000000", + "denom": "unym" + } + }, + "description": { + "moniker": "bwn_g1", + "website": "https://bwnym.xyz", + "security_contact": "bwnym@proton.me", + "details": "This gateway is part of the NYM project, which is dedicated to create outstanding privacy software that is legally compliant without sacrificing integrity or having any backdoors." + }, + "last_probe_result": null, + "last_probe_log": null, + "last_testrun_utc": null, + "last_updated_utc": "2025-03-03T10:45:48+00:00", + "routing_score": 0.0, + "config_score": 0 + }, +``` + + +If you have already run the API before, make sure to add the following to your script `--database-url "sqlite://node-status-api.sqlite?mode=rwc` so it will continue using the same DB. + +### Functionality with Gateway Probe +If you want to enable Gateway node probes and have the NS API store that data, you need to periodically run the `nym-node-status-agent`, authenticated with your `nym-node-status-api` instance. Authentication is to make sure that only the `-agent` you are operating (or others you trust) are submitting data to your API instance. + +#### Compile Gateway Probe +The `nym-node-status-agent` is a thin wrapper around the Gateway Probe binary which currently is in the NymVPN repo. `git checkout` to the most recent [release](https://github.com/nymtech/nym-vpn-client/releases), and compile the probe by following the [readme instructions](https://github.com/nymtech/nym-vpn-client/tree/develop/nym-vpn-core/crates/nym-gateway-probe). You will point the `-agent` at this binary when doing Probe testruns. + +#### Generate Keypair +```shell +nym-node-status-agent generate-keypair --path / +# e.g. +# nym-node-status-agent generate-keypair --path ~/.ssh/ns-agent-key +``` + +You will then want to export the generated `public-key` so its accessible to the `nym-node-status-api` however you are setting your environmental variables, as `NODE_STATUS_API_AGENT_KEY_LIST`: + +```bash +export NODE_STATUS_API_AGENT_KEY_LIST= # e.g. "H4z8kx5Kkf5JNQHfxaE1MwRndjDCD1C7HsVhHTFfBZ4J" +``` + +In this situation, you are probably only using one key. However, it is possible to set multiple keys as a comma seperated list, in case you wish to whitelist multiple `-agent`s to be able to submit to a single `-api` instance. + +#### Run the Node Status Agent +```shell +nym-node-status-agent run-probe --server-address http://127.0.0.1 --server-port 8000 --ns-api-auth-key "" --probe-path nym-gateway-probe +``` + +You will see a lot of output like so: + + +```shell +listen_port=48586 +public_key=3f95caf771b8a63b9bdae6c186f7aba2eae93483f1c82c0243b5e00c85b4ec26 +preshared_key=0000000000000000000000000000000000000000000000000000000000000000 +protocol_version=1 +endpoint=185.186.78.251:51822 +last_handshake_time_sec=0 +last_handshake_time_nsec=0 +tx_bytes=0 +rx_bytes=0 +persistent_keepalive_interval=0 +allowed_ip=0.0.0.0/0 +2025/03/03 18:58:28 Pinging nymtech.net seq=0 +2025/03/03 18:58:29 Ping latency: 44.503483ms +2025/03/03 18:58:29 Pinging nymtech.net seq=1 +2025/03/03 18:58:29 Ping latency: 42.852414ms +2025/03/03 18:58:29 Pinging nymtech.net seq=2 +2025/03/03 18:58:29 Ping latency: 43.627256ms +2025/03/03 18:58:29 Pinging nymtech.net seq=3 +2025/03/03 18:58:29 Ping latency: 43.638839ms +2025/03/03 18:58:29 Pinging nymtech.net seq=4 +2025/03/03 18:58:29 Ping latency: 43.345357ms +2025/03/03 18:58:29 Pinging 1.1.1.1 seq=0 +2025/03/03 18:58:29 Ping latency: 46.327233ms +2025/03/03 18:58:34 Pinging 1.1.1.1 seq=1 +2025/03/03 18:58:34 Ping latency: 46.273726ms +2025/03/03 18:58:39 Pinging 1.1.1.1 seq=2 +2025/03/03 18:58:39 Ping latency: 46.542774ms +2025/03/03 18:58:44 Pinging 1.1.1.1 seq=3 +2025/03/03 18:58:44 Ping latency: 45.663545ms +2025/03/03 18:58:49 Pinging 1.1.1.1 seq=4 +2025/03/03 18:58:49 Ping latency: 43.803063ms +2025/03/03 18:58:56 Downloaded file content length: 1.00 MB +2025/03/03 18:58:56 Download duration: 1.308072386s +2025/03/03 18:58:56 private_key=1083749e43f4f8fb008f3f7deef9107ef86a68969670ddbb9f07bf85f94fb564 +listen_port=39129 +public_key=3f95caf771b8a63b9bdae6c186f7aba2eae93483f1c82c0243b5e00c85b4ec26 +preshared_key=0000000000000000000000000000000000000000000000000000000000000000 +protocol_version=1 +endpoint=185.186.78.251:51822 +last_handshake_time_sec=0 +last_handshake_time_nsec=0 +tx_bytes=0 +rx_bytes=0 +persistent_keepalive_interval=0 +allowed_ip=::/0 +2025/03/03 18:58:56 Pinging ipv6.google.com seq=0 +2025/03/03 18:58:56 Ping latency: 42.839528ms +2025/03/03 18:58:56 Pinging ipv6.google.com seq=1 +2025/03/03 18:58:56 Ping latency: 54.844651ms +2025/03/03 18:58:56 Pinging ipv6.google.com seq=2 +2025/03/03 18:58:56 Ping latency: 51.23104ms +2025/03/03 18:58:56 Pinging ipv6.google.com seq=3 +2025/03/03 18:58:56 Ping latency: 43.320409ms +2025/03/03 18:58:56 Pinging ipv6.google.com seq=4 +2025/03/03 18:58:56 Ping latency: 63.517358ms +2025/03/03 18:58:56 Pinging 2001:4860:4860::8888 seq=0 +2025/03/03 18:58:56 Ping latency: 54.682534ms +2025/03/03 18:59:01 Pinging 2001:4860:4860::8888 seq=1 +2025/03/03 18:59:01 Ping latency: 55.56235ms +2025/03/03 18:59:06 Pinging 2001:4860:4860::8888 seq=2 +2025/03/03 18:59:06 Ping latency: 55.970418ms +2025/03/03 18:59:11 Pinging 2001:4860:4860::8888 seq=3 +2025/03/03 18:59:14 Failed to send ping: i/o timeout +2025/03/03 18:59:19 Pinging 2001:4860:4860::8888 seq=4 +2025/03/03 18:59:22 Failed to send ping: i/o timeout +2025/03/03 18:59:27 Pinging 2606:4700:4700::1111 seq=0 +2025/03/03 18:59:27 Ping latency: 45.072616ms +2025/03/03 18:59:32 Pinging 2606:4700:4700::1111 seq=1 +2025/03/03 18:59:32 Ping latency: 44.357306ms +2025/03/03 18:59:37 Pinging 2606:4700:4700::1111 seq=2 +2025/03/03 18:59:37 Ping latency: 44.013562ms +2025/03/03 18:59:42 Pinging 2606:4700:4700::1111 seq=3 +2025/03/03 18:59:42 Ping latency: 46.94342ms +2025/03/03 18:59:47 Pinging 2606:4700:4700::1111 seq=4 +2025/03/03 18:59:48 Ping latency: 43.372288ms +2025/03/03 18:59:53 Pinging 2620:fe::fe seq=0 +2025/03/03 18:59:53 Ping latency: 42.164952ms +2025/03/03 18:59:58 Pinging 2620:fe::fe seq=1 +2025/03/03 18:59:58 Ping latency: 42.295812ms +2025/03/03 19:00:03 Pinging 2620:fe::fe seq=2 +2025/03/03 19:00:03 Ping latency: 43.117534ms +2025/03/03 19:00:08 Pinging 2620:fe::fe seq=3 +2025/03/03 19:00:08 Ping latency: 44.26068ms +2025/03/03 19:00:13 Pinging 2620:fe::fe seq=4 +2025/03/03 19:00:13 Ping latency: 45.29956ms +2025/03/03 19:00:21 Downloaded file content length: 10.00 MB +2025/03/03 19:00:21 Download duration: 3.39529252s +``` + + +Whilst you can run the `-agent` directly, it might be easier to run multiple instances in parallel with a script like so: + +```bash +#!/bin/bash + +set -eu +export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} + +probe_git_ref="nym-vpn-core-v1.4.0" # check for the most recent release +monorepo_root= + +set -a +source "${monorepo_root}/envs/${ENVIRONMENT}.env" +set +a + +export RUST_LOG="info" +export NODE_STATUS_AGENT_SERVER_ADDRESS="http://127.0.0.1" +export NODE_STATUS_AGENT_SERVER_PORT="8000" +export NODE_STATUS_AGENT_AUTH_KEY= +export NODE_STATUS_AGENT_PROBE_EXTRA_ARGS="netstack-download-timeout-sec=30,netstack-num-ping=2,netstack-send-timeout-sec=1,netstack-recv-timeout-sec=1" + +workers=${1:-1} +echo "Running $workers workers in parallel" + +function swarm() { + local workers=$1 + + for ((i = 1; i <= workers; i++)); do + ${monorepo_root}/target/release/nym-node-status-agent run-probe --probe-path ~//nym-vpn-client/nym-vpn-core/target/debug/nym-gateway-probe & + done + + wait + + echo "All agents completed" +} + +swarm $workers +``` + +And run specifying the number of workers with `./.sh `. + + +When running the probe, use logging level `RUST_LOG=info`. The Node Status API relies on that granularity for parsing probe results, and the logs grow incessantly if a lower level (e.g. `DEBUG`) is used. + + +### Ports +By default the API listens on `8000`, so you will need to configure this post to be reachable on your remote server. You can modify this with the `--http_port` flag. diff --git a/documentation/docs/pages/apis/nym-api/_meta.json b/documentation/docs/pages/apis/nym-api/_meta.json new file mode 100644 index 0000000000..3949bf02de --- /dev/null +++ b/documentation/docs/pages/apis/nym-api/_meta.json @@ -0,0 +1,3 @@ +{ + "mainnet":"Mainnet Endpoints" +} diff --git a/documentation/docs/pages/operators/changelog.mdx b/documentation/docs/pages/operators/changelog.mdx index c4c88b6812..61304c6904 100644 --- a/documentation/docs/pages/operators/changelog.mdx +++ b/documentation/docs/pages/operators/changelog.mdx @@ -47,6 +47,218 @@ This page displays a full list of all the changes during our release cycle from +## `v2025.4-dorina-patched` + +Patched version of `dorina` with a few fixes and tweaks to the release. We would like to ask `nym-node` operators to upgrade to this version as quickly as possible to implement the fixes across the network and improve general quality before NymVPN launch. + +- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina-patched) +- [`nym-node`](nodes/nym-node.mdx) version `1.6.2` + +```shell +nym-node +Binary Name: nym-node +Build Timestamp: 2025-03-06T20:32:36.922212778Z +Build Version: 1.6.2 +Commit SHA: 247ebb7c4339de0a298a7fcb2574122a8306c3b8 +Commit Date: 2025-03-06T21:26:16.000000000+01:00 +Commit Branch: HEAD +rustc Version: 1.85.0 +rustc Channel: stable +cargo Profile: release +``` + +- Use legacy crypto for constructing SURB headers ([#5579]) +- Bugfix: make sure to correctly decode response content when putting it into error message ([#5571]) +- Tweak surb management to be more conservative ([#5570]) +- Deserialize v5 authenticator requests ([#5568]) +- Chore: additional logs when attempting to load ecash keys ([#5567]) +- Add full response body to error message upon decoding failure ([#5566]) +- Hotfix: ensure we bail on merkle leaves insertion upon missing data ([#5565]) +- Feature: v2 authentication request (#5537) ([#5563]) +- Create authenticator v5 request/response types ([#5561]) + +[#5579]: https://github.com/nymtech/nym/pull/5579 +[#5571]: https://github.com/nymtech/nym/pull/5571 +[#5570]: https://github.com/nymtech/nym/pull/5570 +[#5568]: https://github.com/nymtech/nym/pull/5568 +[#5567]: https://github.com/nymtech/nym/pull/5567 +[#5566]: https://github.com/nymtech/nym/pull/5566 +[#5565]: https://github.com/nymtech/nym/pull/5565 +[#5563]: https://github.com/nymtech/nym/pull/5563 +[#5561]: https://github.com/nymtech/nym/pull/5561 + + +## `v2025.4-dorina` +- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina) +- [`nym-node`](nodes/nym-node.mdx) version `1.6.0` +```shell +Binary Name: nym-node +Build Timestamp: 2025-03-04T09:03:11.322601809Z +Build Version: 1.6.0 +Commit SHA: 7060fa6dad58f17543f5086c73b1854ad1ceae60 +Commit Date: 2025-03-03T17:24:10.000000000Z +Commit Branch: release/2025.4-dorina +rustc Version: 1.86.0-nightly +rustc Channel: nightly +cargo Profile: release +``` + +### Operators Updates & Tools + +- New advanced [guide to virtualise a dedicated server](nodes/preliminary-steps/vps-setup/advanced), providing steps for experienced operators and aspiring sys-admins who seek for higher optimisation and better efficiency of their work orchestrating multiple nodes. +- New Service Grant program is being implemented by operators setting up new ~150 Exit Gateways following the updated [specs for `nym-node`](nodes#minimum-requirements) + +### Features +- [Feature/chain status api](https://github.com/nymtech/nym/pull/5539): +this PR introduces `/v1/network/chain-status` endpoint on nym api to give basic information about the current block as seen by this API (with some caching) and updates `/health` endpoint to give stall information. + +- [Add SURBs soft threshold](https://github.com/nymtech/nym/pull/5535): the IPR should try to keep a buffer of available SURBs to reduce latency. + +- [Simplify IPR v8](https://github.com/nymtech/nym/pull/5532): purge stuff from IPR v8 to simplify; use protocol field in v8. + +- [Shared instance for DNS AsyncResolver](https://github.com/nymtech/nym/pull/5523): +make the `HickoryDnsResolver` use a shared instance by default to limit fd use. Now the multiple `nym_http_api_client::Client`s that get built should take advantage of a shared connection pool for DNS lookups. If for some reason a client does need an independent AsyncResolver this can still be done with the added `thread_resolver` function. + +- [cherry-pick 17d3ff2d775f61aee381d90a304ed416c08f33fc onto dorina](https://github.com/nymtech/nym/pull/5519) + +- [cherry-pick 6e5d0dac1b75413c5f09122b0d953f8ec6ef48df onto dorina](https://github.com/nymtech/nym/pull/5518) + +- [feat: add config option for maximum number of client connections](https://github.com/nymtech/nym/pull/5513) + +- [IPR request types v8](https://github.com/nymtech/nym/pull/5498): Bump IPR request/response types to v8 + +- [Support static routes for HTTP requests](https://github.com/nymtech/nym/pull/5487) + +- [added missing import to doctest](https://github.com/nymtech/nym/pull/5480) + +- [adjusted TestSetup::new_complex to ensure bonded node's existence](https://github.com/nymtech/nym/pull/5478) + +- [Trigger contracts CI on main workspace Cargo changes](https://github.com/nymtech/nym/pull/5477): since the contracts workspace depends on the common code in the main workspace, and since the contracts are critical to not have regressions in, trigger contracts CI on any changes to the workspace Cargo.toml and lock files. + +- [Run cargo autoinherit](https://github.com/nymtech/nym/pull/5460): run `cargo autoinherit` to move a bunch of dependencies to the workspace level. `Cargo.lock` remains untouched. + +- [Disable debug in wasm and wallet workflows too](https://github.com/nymtech/nym/pull/5459) + +- [Fix clippy::precedence](https://github.com/nymtech/nym/pull/5457): fix clippy warnings for the Rust beta toolchain. + +- [Provide Interval context with node descriptor endpoints](https://github.com/nymtech/nym/pull/5456): add current interval context information to existing enpoints using `build_skimmed_nodes_response` under the hood. This allows clients checking for a refresh to send the `epoch_uid` as a query parameter when fetching updates so the server can tell it that there have been no changes, instead of sending duplicate data over and over. The changes in this PR should be backwards compatible and never interfere with existing clients. The additions to the `NodeParams` are optional, so there is no error if a client does not send them. Old clients will not send `epoch_uid` by accident so they cannot accidentally clear their set of known nodes. In the response the status field is optional so if it is missing (e.g. if a new client talks to an old server) the connection still works. For old clients speaking to new servers, the json parsing will simply ignore extra information not included in the objects json spec. + +}> + + Made a request to the `/api/v1/unstable/nym-nodes/semi-skimmed` endpoint: + - without entering an epoch_id + - with entering the current epoch_id + - with entering an old epoch_id + - with entering a future epoch_id + All results returned the same data, as expected + + + +- [Feature/add gbp currency](https://github.com/nymtech/nym/pull/5453) + +- [Add helper to extract a list of sqlite files with journal files wal/shm](https://github.com/nymtech/nym/pull/5452) + +- [Add a middleware layer to the nym api allowing for data compression](https://github.com/nymtech/nym/pull/5451): after Testing in a minimal example, this does work as expected. Routes still default to plain encoding, however if a client indicates support for a compressed encoding using the `Accept-Encoding` header then the served response will be compressed with the appropriate `Content-Encoding` header. ([Proof-of-Concept](https://gist.github.com/jmwample/c15a983e804fc338fee3d1b037d216b0)) + +}> + Sent requests with and without Accept-Encoding: gzip to observe response behaviour + Verified if responses included content-encoding: gzip when compression was requested + Checked response file output to confirm actual compression occurred + + +- [Condense core API functionalities and enable gzip decompression for reqwest payloads](https://github.com/nymtech/nym/pull/5450): this PR is intended to take out variables from our usage of HTTP requests in the `nym-http-api-client`. To do this the PR: (1) adds the `ApiClientCore` trait with the minimal feature required to send a request, (2) turns all request sending into trait extension automatically implemented for any type that implements `ApiClientCore`. This has the benefit of consistent expected behavior for all clients using `nym-http-api-client`, including features added going forward. FOR EXAMPLE this pr adds a default header `"accept-encoding: gzip;q=1.0, *;q=0.5"` which indicates that compression is preferred whenever available. Other features to keep in mind here are things like configurable retries, domain fallbacks, etc. Note: the `Apiclient` interface could be simplified, but that would require refactoring our downstream usages of the API. For now this isn't necessary as `ApiClient` is implemented automatically so it costs nothing to have it this way. It just allows divergent usage in downstream crates. + +}> + Measured nym-api response times before and after updating the API client using curl + Checked if the client automatically decompressed Gzip responses + + +- [Seedable clients](https://github.com/nymtech/nym/pull/5440): Adds `DerivationMaterial` and accompanying methods to builders. `DerivationMaterial` encapsulates parameters for deterministic key derivation using HKDF (SHA-512). Use the `derive_secret()` method to generate a 32-byte secret. To prepare for a new derivation, call the `next()` method which increments the index. **It is the caller's responsibility to track and persist the derivation index if keys need to be rederived.** + + + + ```rust + let master_key = [0u8; 32]; // your secret master key + let salt = "unique-salt-value".to_string(); + let material = DerivationMaterial::new(master_key, 0, salt.as_bytes()); + + // Derive a secret + let secret = material.derive_secret().expect("Failed to derive secret"); + + // Prepare for the next derivation + let next_material = material.next(); + ``` + + + +- [Remove all recv_with_delay and add shutdown condition to loops in client-core](https://github.com/nymtech/nym/pull/5435): inside client-core we want to prepare the ground for moving a behaviour close to what we have in the vpn client. Remove all the recv_with_delay since we want to just stop. Add shutdown condition to all select loops to guard against the shutdown listener being polled inside the select blocks. Remove unwraps when sending on unbounded channels in case the receiver exits before the sender. Move `TaskClient` to be a member field so make it easier to wrap log errors in a shutdown check. Update all fork names to use underscore consistently, since the task separator is hyphen + +}> + Validated that all binaries including `nym-node`, `nym-client`, `nym-network-requester`, and `nym-socks5-client` are behaving well without indicating the presence of any unexpected errors or crashes + + +- [Disable the test for checking the remaining bandwidth in nym-node-status-api](https://github.com/nymtech/nym/pull/5425): this check fails almost every time on CI, possibly due to rate limiting? It's not good to disable the check, but it's blocking CI as it stands now. Given that we have the check above for locating the ip, we at least have a little coverage. + +- [Dz nym node stats](https://github.com/nymtech/nym/pull/5418): removed obsolete fields from stats (blacklisted mixnodes, blacklisted gateways, bonded mixnodes, bonded gateways). Introduced nym-node scraping, beside just mixnodes. `/mixnodes/stats` now returns data for nym-nodes as well, which results in much more accurate "packets mixed" stats. + +- [Nymnode entrypoint docker](https://github.com/nymtech/nym/pull/5300) + +### Bugfix +- [bugfix: dont query for ecash apis unless necessary when spending ticketbooks](https://github.com/nymtech/nym/pull/5508) + +- [bugfix: bound check when recovering a reply SURB](https://github.com/nymtech/nym/pull/5502) + +- [fix: update fx average rate calcs to ignore 0 values](https://github.com/nymtech/nym/pull/5454) + +### Chore +- [chore: workspace global panic preventing lints](https://github.com/nymtech/nym/pull/5512) + +- [chore: removed all old coconut code](https://github.com/nymtech/nym/pull/5500) + +- [build(deps): bump the patch-updates group across 1 directory with 3 updates](https://github.com/nymtech/nym/pull/5482): updates `clap` from 4.5.28 to 4.5.30, updates `clap` from 4.5.28 to 4.5.30, updates `prost` from 0.13.4 to 0.13.5. + +- [build(deps): bump http from 1.1.0 to 1.2.0](https://github.com/nymtech/nym/pull/5472) + +- [build(deps): bump utoipa-swagger-ui from 8.0.3 to 8.1.0](https://github.com/nymtech/nym/pull/5471) + +- [build(deps): bump colored from 2.1.0 to 2.2.0](https://github.com/nymtech/nym/pull/5470) + +- [build(deps): bump celes from 2.4.0 to 2.5.0](https://github.com/nymtech/nym/pull/5469) + +- [build(deps): bump the patch-updates group with 2 updates](https://github.com/nymtech/nym/pull/5467): updates `clap` from 4.5.28 to 4.5.29, updates `prost` from 0.13.4 to 0.13.5. + +- [build(deps): bump elliptic from 6.5.4 to 6.6.1 in /docker/typescript_client/upload_contract](https://github.com/nymtech/nym/pull/5463): bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.4 to 6.6.1. + +- [build(deps): bump uniffi_build from 0.25.3 to 0.29.0](https://github.com/nymtech/nym/pull/5448) + +- [Upgrade tower to 0.5.2](https://github.com/nymtech/nym/pull/5446) + +- [build(deps): bump hickory-proto from 0.24.2 to 0.24.3 in /nym-wallet](https://github.com/nymtech/nym/pull/5445) + +- [build(deps): bump hickory-proto from 0.24.2 to 0.24.3](https://github.com/nymtech/nym/pull/5444) + +- [build(deps): bump the patch-updates group across 1 directory with 10 updates](https://github.com/nymtech/nym/pull/5439): +Bumps the patch-updates group with 10 updates in the directory: + +| Package | From | To | +| --- | --- | --- | +| [async-trait](https://github.com/dtolnay/async-trait) | `0.1.85` | `0.1.86` | +| [clap](https://github.com/clap-rs/clap) | `4.5.27` | `4.5.28` | +| [comfy-table](https://github.com/nukesor/comfy-table) | `7.1.3` | `7.1.4` | +| [hickory-resolver](https://github.com/hickory-dns/hickory-dns) | `0.24.2` | `0.24.3` | +| [once_cell](https://github.com/matklad/once_cell) | `1.20.2` | `1.20.3` | +| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.8` | `1.1.9` | +| [serde_json_path](https://github.com/hiltontj/serde_json_path) | `0.7.1` | `0.7.2` | +| [toml](https://github.com/toml-rs/toml) | `0.8.19` | `0.8.20` | +| [cosmrs](https://github.com/cosmos/cosmos-rust) | `0.21.0` | `0.21.1` | +| [tokio-postgres](https://github.com/sfackler/rust-postgres) | `0.7.12` | `0.7.13` | + +- [build(deps): bump openssl from 0.10.56 to 0.10.70 in /nym-wallet](https://github.com/nymtech/nym/pull/5422) + +- [build(deps): bump hyper from 1.4.1 to 1.6.0](https://github.com/nymtech/nym/pull/5416) + +- [build(deps): bump publicsuffix from 2.2.3 to 2.3.0](https://github.com/nymtech/nym/pull/5367) + ## `v2025.3-ruta` - [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.3-ruta) @@ -97,7 +309,7 @@ As we announced in [`hu` release notes](#service-grant-program-v2), we are opene ##### Locations -These locations and slots are approximate and constantly change based on new operators submissions. Please keep in mind that we are going to chose people with respect to empty slots in the given location at the time of their submission. In case of competing submissions in the same location we will take the one with better specs vs price ratio. +These locations and slots are approximate and constantly change based on new operators submissions. Please keep in mind that we are going to chose people with respect to empty slots in the given location at the time of their submission. In case of competing submissions in the same location we will take the one with better specs vs price ratio. | LOCATION | SLOTS | | :-- | --: | @@ -151,7 +363,7 @@ These locations and slots are approximate and constantly change based on new ope - [Send shutdown instead of panic when reaching max fail](https://github.com/nymtech/nym/pull/5398): Remove a panic and an unwrap inside `client-core` that is hit occasionally in the vpn client. This is a change that can have wide ranging impact since it changes the task handling and it's inside `client-core`, which is used in many components and services, so preventing regressions is important. -- [Relocate a validator api function](https://github.com/nymtech/nym/pull/5401): Adds a function to the `nym-validator-client` crate that hits the network details endpoint and returns an object parsed from `json`. This was floating loose in the `nym-vpn-client` repo. +- [Relocate a validator api function](https://github.com/nymtech/nym/pull/5401): Adds a function to the `nym-validator-client` crate that hits the network details endpoint and returns an object parsed from `json`. This was floating loose in the `nym-vpn-client` repo. - [Bump the patch-updates group across 1 directory with 9 updates](https://github.com/nymtech/nym/pull/5406) @@ -199,7 +411,7 @@ From `nym-node v1.3.0` operators can technically choose multiple functionalities - Updated maintenance guides to [backup](nodes/maintenance#backup-a-node), [restore](nodes/maintenance#restoring-a-node) and [move](nodes/maintenance#moving-a-node) a node, containing a new and important commands to backup and restore `clients.sqlite` database. -- [New explanation of `nym-node` functionalities](nodes/nym-node/setup#functionality-mode) describing how Gateways get selected in Mixnet mode and Wireguard mode. +- [New explanation of `nym-node` functionalities](nodes/nym-node/setup#functionality-mode) describing how Gateways get selected in Mixnet mode and Wireguard mode. Wireguard nodes route data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run a node with active wireguard routing, please read our [Community Counsel pages](community-counsel/exit-gateway) containing more information and some legal content. @@ -223,7 +435,7 @@ We have been notified that a handful of nodes have been taken down by abuse repo - Join [Community legal counsel](https://nym.com/docs/operators/community-counsel) - our collective knowledge hub. Add your findings by opening a [Pull Request](https://nym.com/docs/operators/add-content) - While we are working on a new list of more friendly providers, consider to move away from these provides as soon as possible: - + - Servinga / VPS2day (AS39378) - Frantech / Ponynet / BuyVM (AS53667) - OVH SAS / OVHcloud (AS16276) @@ -233,7 +445,7 @@ We have been notified that a handful of nodes have been taken down by abuse repo - Psychz Networks (AS40676) - 1337 Services GmbH / RDP.sh (AS210558) -- Backup your nodes to have access to `.nym` directory locally. Follow [node](nodes/maintenance#backup-a-node) and [proxy configuration](nodes/maintenance#backup-proxy-configuration) backup guides to be able to [restore your node](nodes/maintenance#restoring-a-node) later on on another machine, without losing your delegation. +- Backup your nodes to have access to `.nym` directory locally. Follow [node](nodes/maintenance#backup-a-node) and [proxy configuration](nodes/maintenance#backup-proxy-configuration) backup guides to be able to [restore your node](nodes/maintenance#restoring-a-node) later on on another machine, without losing your delegation. - We would like to ask operators who use reverse proxy and a domain (required for Gateways) to start using a common convention starting with `nym-exit` for their nodes URL. The entire address should have this new format: ``` @@ -258,7 +470,7 @@ nym-exit.mysquad.org **The `NYM-EXIT` part in the beginning is what's important.** -- When registering a domain, check [Top Level Domain (TLD)](https://www.techopedia.com/definition/1348/top-level-domain-tld) terms and conditions. For example `.icu` is a no go. Having a wrong TLD may lead to your domain being taken away from you when facing a DMCA report. +- When registering a domain, check [Top Level Domain (TLD)](https://www.techopedia.com/definition/1348/top-level-domain-tld) terms and conditions. For example `.icu` is a no go. Having a wrong TLD may lead to your domain being taken away from you when facing a DMCA report. - Write a message to your provider and introduce your intention to run a Nym Node on their service @@ -322,7 +534,7 @@ Undelegated due to high saturation: #### Service Grant Program v2 -Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to support Exit Gateway operators before they will be rewarded by collecting [zk-nym tickets](../network/cryptography/zk-nym) from users subscription. Operators included in SGP are long term active community members with the highest requirements on the technical setup and upgrading pace. We are about to start a second iteration of SGP very soon (SGPv2). The final slots and locations are yet to be concluded. Priority to participate in SGPv2 will be given to the current operators in SGP. Based on the number of slots, we will then determine how many more operators can sign up. +Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to support Exit Gateway operators before they will be rewarded by collecting [zk-nym tickets](../network/cryptography/zk-nym) from users subscription. Operators included in SGP are long term active community members with the highest requirements on the technical setup and upgrading pace. We are about to start a second iteration of SGP very soon (SGPv2). The final slots and locations are yet to be concluded. Priority to participate in SGPv2 will be given to the current operators in SGP. Based on the number of slots, we will then determine how many more operators can sign up. ##### Rules of SGPv2 @@ -330,7 +542,7 @@ Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to **We will share more info soon in the channels. The rules are not set in stone and could potentially be altered or updated in the future! Do *not* purchase new servers neither migrate your nodes just yet.** -As we finalising last details of *"Project Smoosh"*, where one binary - `nym-node` - can run as an `entry-gateway`, `mixnode` or `exit-gateway` in Mixnet mode as well as `entry-gateway` or `exit-gateway` in Wireguard mode, we plan to step up the game. SGPv2 grants will be higher if operators can meet new requirements. +As we finalising last details of *"Project Smoosh"*, where one binary - `nym-node` - can run as an `entry-gateway`, `mixnode` or `exit-gateway` in Mixnet mode as well as `entry-gateway` or `exit-gateway` in Wireguard mode, we plan to step up the game. SGPv2 grants will be higher if operators can meet new requirements. **Minimum Specs & Requirements** @@ -402,7 +614,7 @@ These are minimum requirements to become a part of SGPv2. We aim to have nodes o - [build(deps): bump criterion from `0.4.0` to `0.5.1`](https://github.com/nymtech/nym/pull/4911): Bumps [criterion](https://github.com/bheisler/criterion.rs) from `0.4.0` to `0.5.1`. -- [NS API: add mixnet scraper](https://github.com/nymtech/nym/pull/5200) +- [NS API: add mixnet scraper](https://github.com/nymtech/nym/pull/5200) - [build(deps): bump http from `1.1.0` to `1.2.0`](https://github.com/nymtech/nym/pull/5228): Bumps [http](https://github.com/hyperium/http) from `1.1.0` to `1.2.0`. @@ -410,41 +622,41 @@ These are minimum requirements to become a part of SGPv2. We aim to have nodes o - [Add windows to CI builds](https://github.com/nymtech/nym/pull/5269) -- [nym topology revamp](https://github.com/nymtech/nym/pull/5271): This PR changes the internals of the `NymTopology` to blur the lines between explicit mixnodes and gateways so that what used to be considered a "mixnode" could be a valid egress point of the network. `NymTopology` is no longer divided into `BTreeMap>` and `Vec`. instead there's information about the current rewarded set (to support future VRF work) and a simple map of `HashMap`. The new features are mostly controlled via 2 new flags/config values: +- [nym topology revamp](https://github.com/nymtech/nym/pull/5271): This PR changes the internals of the `NymTopology` to blur the lines between explicit mixnodes and gateways so that what used to be considered a "mixnode" could be a valid egress point of the network. `NymTopology` is no longer divided into `BTreeMap>` and `Vec`. instead there's information about the current rewarded set (to support future VRF work) and a simple map of `HashMap`. The new features are mostly controlled via 2 new flags/config values: - `use_extended_topology` that tells the client to retrieve **all** network nodes rather than the ones that got assigned "active" mixnode role (or support being a gateway) - `ignore_egress_epoch_role` that tells the client it's fine to construct egress packets to nodes that are **not** assigned entry or exit gateway role - + - [Nyx Chain Watcher](https://github.com/nymtech/nym/pull/5274) - [Include `IPINFO_API_TOKEN` in nightly CI](https://github.com/nymtech/nym/pull/5285) -- [Move tun constants to network defaults](https://github.com/nymtech/nym/pull/5286): +- [Move tun constants to network defaults](https://github.com/nymtech/nym/pull/5286): }> 1. **Regression Testing**: -- Verified no issues arose when running tests for the affected files. -- Tested TUN behaviour with new nym-nodes in the hu branch. - -**Results**: +- Verified no issues arose when running tests for the affected files. +- Tested TUN behaviour with new nym-nodes in the hu branch. -- **No bugs detected**. -- Tunnels are functioning as expected, with traffic routing and IP generation working seamlessly. - +**Results**: + +- **No bugs detected**. +- Tunnels are functioning as expected, with traffic routing and IP generation working seamlessly. + - [Add dependabot assignes for the root cargo ecosystem](https://github.com/nymtech/nym/pull/5297) - [build(deps): bump the patch-updates group across 1 directory with 35 updates](https://github.com/nymtech/nym/pull/5310): Bumps the `patch-updates` group with 33 updates -- [Periodically remove stale gateway messages](https://github.com/nymtech/nym/pull/5312): This PR introduces a simple task that removes gateway messages that haven't been retrieved in (by default) 24h. +- [Periodically remove stale gateway messages](https://github.com/nymtech/nym/pull/5312): This PR introduces a simple task that removes gateway messages that haven't been retrieved in (by default) 24h. }> **Automation Script for Data Cleanup Validation** Test Objective: Validate that the stale message cleanup mechanism in the database correctly removes records older than the configured threshold (24 hours). - + Test Setup: 1. Environment: * SQLite database * Bash script: used to insert data. - + Steps Performed: 1. Ran the insert_data.sh script to populate the database with test data: * Recent records inserted successfully. @@ -452,8 +664,8 @@ Steps Performed: 3. Confirmed that all 20 records (10 recent + 10 stale) were present. 4. Allowed the system to run for 24 hours to trigger the cleanup mechanism. 5. Queried the database again after 24 hours: sqlite3 gateway_storage.db "SELECT * FROM message_store;" -6. - +6. + Expected Result: * All stale records (older than 24 hours) should be removed. * Recent records should remain in the database. @@ -464,18 +676,18 @@ Actual Result: - [Use expect in geodata test to give error message on failure](https://github.com/nymtech/nym/pull/5314): Keep hitting this error on CI, from what I think is network hickup. But it's hard to tell form the log since the error is swallowed. Explicitly unwrap the result so we get a more detailed error output. }> -**Quick Code Review** - -**Summary** +**Quick Code Review** + +**Summary** 1. **CI Workflow**: Adjusted paths to optimise build triggers, avoiding unnecessary CI runs while ensuring coverage for key directories 2. **Geolocation Test**: Improved error handling by replacing assertions with `.expect` for clearer debugging in API regression tests - -**Conclusion** + +**Conclusion** Regression testing confirms everything works as intended. **Approved**. -- [`CancellationToken`-based shutdowns](https://github.com/nymtech/nym/pull/5325): This PR introduces scaffolding for using `CancellationToken` and `TaskTracker` for our graceful shutdowns rather than the existing `TaskClient` and `TaskManager`. +- [`CancellationToken`-based shutdowns](https://github.com/nymtech/nym/pull/5325): This PR introduces scaffolding for using `CancellationToken` and `TaskTracker` for our graceful shutdowns rather than the existing `TaskClient` and `TaskManager`. - [Introduce `/load` endpoint for self-reported quantised Nym Node load](https://github.com/nymtech/nym/pull/5326): This PR introduces a new `/load` endpoint on a `NymNode` to return its current load. It returns the following data: ```rust @@ -505,7 +717,7 @@ The actual values for`NodeLoad` are determined as follows: - Thus we calculate two additional auxiliary `Load` values, for memory usage and swap usage, i.e.: `used_memory / total_memory` and `used_swap / total_swap` respectively. - Then we check whether either of the `MemoryLoad` or `SwapLoad` is bigger than the current base `Load` of the machine we have determined, if so, it's increased by one tier / bucket. For example, say the current machine load is `Load::Low`, but the memory usage is at 90% (`Load::VeryHigh`). that would result in the reported `Load` being bumped up to `Load::Medium` instead. The same logic applies with swap load, **however, only if the total swap > 1GB**. this is to prevent weird edge cases where the machine has hardly any swap. - Finally, the `.total` `Load` uses the same "tier bumping" behaviour using the `.total` and `.network` loads, i.e. `if network > machine`, then `total = machine + 1`. for example if `machine` `Load` is `Load::Low`, but `network` `Load` is `Load::Medium`, then the `total` `Load` is set to `Load::Medium` instead. - + - [Bump the `patch-updates` group with 8 updates](https://github.com/nymtech/nym/pull/5336) @@ -517,29 +729,29 @@ The actual values for`NodeLoad` are determined as follows: - [Bump mikefarah/yq from `4.44.6` to `4.45.1`](https://github.com/nymtech/nym/pull/5342) -- [Update `indexed_db_futures`](https://github.com/nymtech/nym/pull/5347): Updates the `indexed_db_futures` dependency to stop relying on the fork. +- [Update `indexed_db_futures`](https://github.com/nymtech/nym/pull/5347): Updates the `indexed_db_futures` dependency to stop relying on the fork. - [Refresh wasm sdk](https://github.com/nymtech/nym/pull/5353): This PR refreshes the wasm clients to make them usable in the current network - [Client gateway selection](https://github.com/nymtech/nym/pull/5358): Changed how gateway is selected. - For init the target gateway can't support mixing - For egress, unless `ignore_epoch_roles` is specified, the gateway can't be currently assigned to a mixing layer. But it can be standby or inactive - + - [Exposed `NymApiClient` method for obtaining node performance history](https://github.com/nymtech/nym/pull/5360) - [Bind to `[::]` on `nym-node` for both IP versions](https://github.com/nymtech/nym/pull/5361) }> **IPv4 Configuration and Migration Testing** - + Testing Steps: - Initiated and ran a nym-node with version 1.3.1 on an IPv4-only machine, then updated it to the new 'hu', 1.4.0 version. - Initiated and ran a new nym-node with 'hu', 1.4.0 always on a machine with only IPv4. - Initiated and ran a new nym-node with 'hu', 1.4.0 on a machine with both IPv4 and IPv6 for regression testing. - + Results: - No functional issues during version updates. - Logged message on all versions: "no registered client for destination: ff02::2" - + Status: Pass @@ -554,10 +766,10 @@ Status: Pass - Ensured a client is able to select a node which aside from a gateway, can also act as a mixnode - Verified 'ignore_epoch_roles' is the default mode - _note; this is most likely not going to be a permanent solution_ - + **Results:** -- Clients and topology are behaving correctly - +- Clients and topology are behaving correctly + Status: Pass @@ -612,7 +824,7 @@ We are developing a design where operators can enable multiple modes, and let th - Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR - Added general `debug` section - Added `metrics` section -- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation. +- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation. - Updated [network architecture diagrams](https://nym.com/docs/network/architecture) - New blow-by-blow mixnet [traffic flow](https://nym.com/docs/network/architecture) section - [Winter Nym Squad League started](https://forum.nym.com/t/nym-squad-league-farewell-fall-welcome-winter/977) @@ -648,11 +860,11 @@ We are developing a design where operators can enable multiple modes, and let th - Everything in `mixnode` directory has been removed because there was nothing really left there. The mixing socket listener was unified in `nym-node` and similarly `verloc` was also moved there - `gateway` directory was similarly reduced in size. Now it also creates appropriate tasks as opposed to the whole gateway process. eventually it might also be further stripped, but today is not that day. - Removed the generic parameter on the `GatewayStorage` to simplify all the generics down the stack. it wasn't used anyway - + CLI: - Added `--modes` argument to specify all node modes with a single command (or `env` variable). for example: `--modes="mixnode,entry"`. Can't be used alongside `--modes` - Extended `--mode` argument to allow specifying it multiple times, for example: `--mode mixnode --mode entry`. can't be used alongside `--mode` - + Config changes: - Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously - Added `maximum_forward_packet_delay` to `mixnet.debug` section @@ -677,17 +889,17 @@ Config changes: - [Remove unneeded async function annotation](https://github.com/nymtech/nym/pull/5246) - [Add control messages to `GatewayTransciver`](https://github.com/nymtech/nym/pull/5247) }> -**Review and Testing: Forget Me Implementation** +**Review and Testing: Forget Me Implementation** -- Validated the encryption and delivery of `ForgetMe` control messages to the gateway - -**Testing: MixTrafficController Integration** +- Validated the encryption and delivery of `ForgetMe` control messages to the gateway -- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown -- Tested behaviour for gateway transceiver failures while sending control messages - -**Testing: Gateway Storage Updates** -- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage +**Testing: MixTrafficController Integration** + +- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown +- Tested behaviour for gateway transceiver failures while sending control messages + +**Testing: Gateway Storage Updates** +- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage - [Add conversion unit tests for auth msg](https://github.com/nymtech/nym/pull/5251) @@ -704,13 +916,13 @@ Config changes: }> 1. **Review File: `common/credential-storage/src/backends/sqlite.rs`** - Verified addition of `close` method for the SQLite backend - + 2. **Review File: `common/credential-storage/src/ephemeral_storage.rs`** - Confirmed addition of `close` method for ephemeral storage with no action required - + 3. **Review File: `common/credential-storage/src/persistent_storage/mod.rs`** - Ensured `close` method integration for persistent storage - + 4. **Review File: `common/credential-storage/src/storage.rs`** - Verified updates to the `Storage` trait to include `close` and `cleanup_expired` methods @@ -719,15 +931,15 @@ Config changes: }> 1. **Review File: `common/network-defaults/src/constants.rs`** - Confirmed updated `mixnet_vpn` constants were added. - + 2. **Review File: `service-providers/ip-packet-router/src/constants.rs`** - Checked replacement of legacy `TUN_*` constants with new `mixnet_vpn` constants. - Validated alignment of routing traffic configurations. - + 3. **Review File: `service-providers/ip-packet-router/src/ip_packet_router.rs`** - Ensured new `nym_network_defaults::constants::mixnet_vpn` constants replaced old references. - Verified `TunDeviceConfig` consistency. - + 4. **Review File: `service-providers/ip-packet-router/src/util/generate_new_ip.rs`** - Confirmed substitution of `TUN_DEVICE_*` constants with `NYM_TUN_DEVICE_*` constants. - Tested functionality for generating random IPs within subnet. @@ -743,54 +955,54 @@ Config changes: - `nym_node_mixnet_ingress_excessive_delay_packets` - `nym_node_mixnet_ingress_forward_hop_packets_dropped` - `nym_node_mixnet_ingress_final_hop_packets_dropped` - + - `nym_node_mixnet_ingress_forward_hop_packets_received_rate` - - `nym_node_mixnet_ingress_final_hop_packets_received_rate` - - `nym_node_mixnet_ingress_malformed_packets_received_rate` - - `nym_node_mixnet_ingress_excessive_delay_packets_rate` + - `nym_node_mixnet_ingress_final_hop_packets_received_rate` + - `nym_node_mixnet_ingress_malformed_packets_received_rate` + - `nym_node_mixnet_ingress_excessive_delay_packets_rate` - `nym_node_mixnet_ingress_forward_hop_packets_dropped_rate` - `nym_node_mixnet_ingress_final_hop_packets_dropped_rate` - + - egress: - `nym_node_mixnet_egress_stored_on_disk_final_hop_packets` - `nym_node_mixnet_egress_forward_hop_packets_sent` - `nym_node_mixnet_egress_ack_packets_sent` - `nym_node_mixnet_egress_forward_hop_packets_dropped` - + - `nym_node_mixnet_egress_forward_hop_packets_sent_rate` - `nym_node_mixnet_egress_ack_packets_sent_rate` - `nym_node_mixnet_egress_forward_hop_packets_dropped_rate` - + - client sessions - `nym_node_entry_client_sessions_unique_users` - `nym_node_entry_client_sessions_sessions_started` - `nym_node_entry_client_sessions_finished_sessions` - `nym_node_entry_client_sessions_durations_{TYP}` (histogram), for example `nym_node_entry_client_sessions_durations_vpn` - + - wireguard: - `nym_node_wireguard_bytes_rx` - `nym_node_wireguard_bytes_tx` - `nym_node_wireguard_bytes_total_peers` - `nym_node_wireguard_bytes_active_peers` - + - `nym_node_wireguard_bytes_rx_rate` - `nym_node_wireguard_bytes_tx_rate` - - + + - network - `nym_node_network_active_ingress_mixnet_connections` - `nym_node_network_active_ingress_web_socket_connections` - `nym_node_network_active_egress_mixnet_connections` - + - process - `nym_node_process_forward_hop_packets_being_delayed` - `nym_node_process_packet_forwarder_queue_size` - `nym_node_process_topology_query_resolution_latency` (histogram) - `nym_node_process_final_hop_packets_pending_delivery` - - `nym_node_process_forward_hop_packets_pending_delivery` + - `nym_node_process_forward_hop_packets_pending_delivery` -- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb +- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb - [Warn users if node is run in exit mode only](https://github.com/nymtech/nym/pull/5320): Throws a warning if node is run in "exit" mode only as by default, this will **NOT** enable entry capabilities, i.e. opening the websocket. thus making it ineligible for rewarded set selection (and rewards) - [Reduce log severity for number of packets being delayed](https://github.com/nymtech/nym/pull/5321) - [Apply 1.84 linter suggestions](https://github.com/nymtech/nym/pull/5330) @@ -806,7 +1018,7 @@ Config changes: - [Make sure to apply gateway score filtering when choosing initial node](https://github.com/nymtech/nym/pull/5256) - [Fixed client session histogram buckets](https://github.com/nymtech/nym/pull/5316) - [Contract version assignment](https://github.com/nymtech/nym/pull/5318): This PR fixes updates to current nym-node version as well as introduces migration to fix the existing state of the mainnet contract - - [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness) + - [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness) ## Archived Changelog diff --git a/documentation/docs/pages/operators/nodes/maintenance.mdx b/documentation/docs/pages/operators/nodes/maintenance.mdx index 5819fde852..a825b3ab32 100644 --- a/documentation/docs/pages/operators/nodes/maintenance.mdx +++ b/documentation/docs/pages/operators/nodes/maintenance.mdx @@ -128,10 +128,15 @@ mkdir -pv ###### 2. Backup `clients.sqlite` database + - Install `sqlite3` ```sh apt install sqlite3 ``` +- **Stop your node** +```sh +service nym-node stop +``` - Open sqlite CLI shell inside `clients.sqlite` database ```sh sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite @@ -151,10 +156,14 @@ sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite scp -r @:~/.nym/nym-nodes/ ``` -###### 4. Verify the success of the backup +###### 4. Verify the success of the backup & start your node The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the backup target directory. +- Start your node +```sh +service nym-node start && journalctl -u nym-node -f +``` Now you have everything needed to restore your `nym-node` on another server. If you are in a need of doing so, follow the steps in [*Restoring a node*](#restoring-a-node) chapter below. @@ -360,7 +369,7 @@ mkdir ~/.nym/nym-nodes ``` ###### 2. Backup `clients.sqlite` database -- Stop your node +- **Stop your node** ```sh service nym-node stop ``` diff --git a/documentation/docs/pages/operators/nodes/nym-node/setup.mdx b/documentation/docs/pages/operators/nodes/nym-node/setup.mdx index 8290f14411..6d4a09b4b6 100644 --- a/documentation/docs/pages/operators/nodes/nym-node/setup.mdx +++ b/documentation/docs/pages/operators/nodes/nym-node/setup.mdx @@ -20,12 +20,12 @@ This documentation page provides a guide on how to set up and run a [NYM NODE](. ```sh nym-node Binary Name: nym-node -Build Timestamp: 2025-02-13T11:49:34.670488195Z -Build Version: 1.5.0 -Commit SHA: a3e19b4563843055b305ea9a397eb1ad84b5c378 -Commit Date: 2025-02-10T18:14:47.000000000+01:00 +Build Timestamp: 2025-03-06T20:32:36.922212778Z +Build Version: 1.6.2 +Commit SHA: 247ebb7c4339de0a298a7fcb2574122a8306c3b8 +Commit Date: 2025-03-06T21:26:16.000000000+01:00 Commit Branch: HEAD -rustc Version: 1.84.1 +rustc Version: 1.85.0 rustc Channel: stable cargo Profile: release ``` diff --git a/documentation/docs/pages/operators/nodes/preliminary-steps/vps-setup.mdx b/documentation/docs/pages/operators/nodes/preliminary-steps/vps-setup.mdx index 3488295629..5cba5bdbed 100644 --- a/documentation/docs/pages/operators/nodes/preliminary-steps/vps-setup.mdx +++ b/documentation/docs/pages/operators/nodes/preliminary-steps/vps-setup.mdx @@ -3,8 +3,9 @@ import { VarInfo } from 'components/variable-info.tsx'; import { Steps } from 'nextra/components';import { Tabs } from 'nextra/components'; import { MyTab } from 'components/generic-tabs.tsx'; import PortsNymNode from 'components/operators/snippets/ports-nym-node.mdx'; -import PortsValidator from 'components/operators/snippets/ports-validator.mdx' -import NymNodeSpecs from 'components/operators/snippets/nym-node-specs.mdx' +import PortsValidator from 'components/operators/snippets/ports-validator.mdx'; +import NymNodeSpecs from 'components/operators/snippets/nym-node-specs.mdx'; +import NTPSync from 'components/operators/snippets/ntp-time-sync.mdx' # VPS Setup & Configuration @@ -42,14 +43,18 @@ apt update -y && apt --fix-broken install ``` - Install dependencies ```sh -apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git +apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git ntp ntpdate ``` - Double check ufw is installed correctly ```sh apt install ufw --fix-missing ``` -###### 2. Configure your firewall using Uncomplicated Firewall (UFW) +###### 2. Synchronize time of your server + + + +###### 3. Configure your firewall using Uncomplicated Firewall (UFW) For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on the server. The following commands will allow you to set up a firewall using `ufw`. @@ -70,7 +75,7 @@ ufw enable ufw status ``` -###### 3. Open all needed ports to have your firewall for `nym-node` working correctly +###### 4. Open all needed ports to have your firewall for `nym-node` working correctly
+ +## Virtualising a Dedicated Server + +Some operators or squads of operators orchestrate multiple Nym nodes. Among other benefits (which are out of scope of this page), these operators can decide to acquire one larger dedicated (or bare-metal) server with enough specs (CPU, RAM, storage, bandwidth and port speed) to meet [minimum requirements](../../../nodes#minimum-requirements) for multiple nodes run in parallel. + +This guide explains how to prepare your server in order to be able to host multiple nodes running on separated VMs. + + +This guide is based on Ubuntu 22.04, in case you prefer another OS, you may have to do a bit of your own research to troubleshoot networking configuration and other parameters. + + +### Installing KVM on a Server with Ubuntu 22.04 + +**KVM** stands for **Kernel-based Virtual Machine**. It is a virtualization technology for Linux that allows a user to run multiple virtual machines (VMs) on a single physical machine. KVM turns the Linux kernel into a hypervisor, enabling it to manage multiple virtualised systems. + +Follow the steps below to install KVM on Ubuntu 22.04 LTS. + +#### Prerequisites + + +Operators aiming to run Nym node as mixnet [Exit Gateway](../../../community-counsel/exit-gateway) or with wireguard enabled should familiarize themselves with the challenges possibly coming along `nym-node` operation, described in our [community counsel](../../../community-counsel) and follow up with [legal suggestions](../../../community-counsel/legal). Particularly important is to [introduce yourself](../../../community-counsel/legal#introduce-nym-node-to-your-provider) and your intentions to run a Nym node to your provider. + +This step is essential part of legal self defense because it may prevent your provider immediately shutting down your entire service (with all the VMs on it) when receiving first abuse report. + +Additionally, before purchasing a large server, **contact the provider and ask if the offered CPU supports Virtualization Technology (VT)**, without this feature you will not be able to proceed. + + +Start with obtaining a server with Ubuntu 22.04 LTS: +- Make sure that your server meets [minimum requirements](../vps-setup#nym-node---dedicated-server) multiplied by number of `nym-node` instance you aim to run on it. +- Most people rent a server from a provider and it comes with a pre-installed OS (in this guide we use Ubuntu 22.04). In case your choice is a bare-metal machine, you probably know what you are doing, there are some useful guides to install a new OS, like [this one on ostechnix.com](https://ostechnix.com/install-ubuntu-server/). + +Make sure thay your system actually supports hardware virtualisation: +- Check out the methods documented in [this guide by ostechnix.com](https://ostechnix.com/how-to-find-if-a-cpu-supports-virtualization-technology-vt/). + +Order enough IPv4 and IPv6 (static and public) addresses to have one of each for each planned VM plus one extra for the main machine. + + +When you have your OS installed, validated CPU virtualisation support and obtained IP addresses, you can start configuring your VMs, following the steps below. + +> Note that the commands below require root permission. You can either go through the setup as `root` or use `sudo` prefix with the commands used in the guide. You can switch to `root` shell by entering one of these commands `sudo su` or `sudo -i`. + + +##### 1. Install KVM + +- Install KVM and required components: +```sh +apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst +``` +
+ +- `qemu-kvm`: Provides the core **KVM virtualization** support using QEMU. +- `libvirt-daemon-system`: Manages virtual machines via the **libvirt daemon**. +- `libvirt-clients` Provides command-line tools like `virsh` to manage VMs. +- `bridge-utils`: Enables **network bridging**, allowing VMs to communicate over the network. +- `virtinst`: Includes `virt-install` for **creating virtual machines** via CLI. + + +- Start the `libvertd` service: +```sh +systemctl enable libvirtd +systemctl start libvirtd +``` +- Validate by checking status of `libvirt` service: +```sh +systemctl status libvirtd +``` +
+ +The command output should look similar to this one: +``` +root@nym-exit:~# systemctl status libvirtd +● libvirtd.service - Virtualization daemon + Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled) + Active: active (running) since Thu 2025-02-27 14:25:28 MSK; 2min 1s ago +TriggeredBy: ● libvirtd-ro.socket + ● libvirtd.socket + ● libvirtd-admin.socket + Docs: man:libvirtd(8) + https://libvirt.org + Main PID: 6232 (libvirtd) + Tasks: 21 (limit: 32768) + Memory: 11.8M + CPU: 852ms + CGroup: /system.slice/libvirtd.service + ├─6232 /usr/sbin/libvirtd + ├─6460 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper + └─6461 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper + +Feb 27 14:25:28 nym-exit.example.com systemd[1]: Started Virtualization daemon. +Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: started, version 2.90 cachesize 150 +Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset no-nftset auth cryptohash DNSSEC loop-detect inotify dump> +Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: DHCP, IP range 192.168.122.2 -- 192.168.122.254, lease time 1h +Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: DHCP, sockets bound exclusively to interface virbr0 +Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: reading /etc/resolv.conf +Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: using nameserver 127.0.0.53#53 +Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: read /etc/hosts - 8 names +Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 names +Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: read /var/lib/libvirt/dnsmasq/default.hostsfile +``` + + +- In case you don't configure KVM as `root`, add your current user to the `kvm` and `libvirt` groups to enable VM creation and management using the `virsh` command-line tool or the `virt-manager` GUI: +```bash +usermod -aG kvm $USER +usermod -aG libvirt $USER +``` + +##### 2. Setup Bridge Networking with KVM + +A **bridged network** lets VMs share the host’s network interface, allowing direct IPv4/IPv6 access like a physical machine. + +By default, KVM sets up a **private virtual bridge**, enabling VM-to-VM communication within the host. It provides its own subnet, DHCP, and NAT for external access. + +Check the IP of KVM’s default virtual interfaces with: + +```bash +ip a +``` +
+ +The command output should look similar to this one: +``` +root@nym-exit:~# ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: eno1: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff + altname enp2s0f0 +3: eno49: mtu 1500 qdisc mq state UP group default qlen 1000 + link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff + altname enp4s0f0 + inet 31.222.238.222/24 brd 31.222.238.255 scope global eno49 + valid_lft forever preferred_lft forever + inet6 fe80::3a63:bbff:fe2e:9d20/64 scope link + valid_lft forever preferred_lft forever +4: eno2: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff + altname enp2s0f1 +5: eno3: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff + altname enp2s0f2 +6: eno50: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff + altname enp4s0f1 +7: eno4: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff + altname enp2s0f3 +8: virbr0: mtu 1500 qdisc noqueue state DOWN group default qlen 1000 + link/ether 52:54:00:ac:d3:ba brd ff:ff:ff:ff:ff:ff + inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 + valid_lft forever preferred_lft forever +``` + + + +By default, KVM uses the `virbr0` network with `.1/24`, assigning guest VMs IPs in the `.0/24` range. The host OS is reachable at `.1`, allowing SSH and file transfers (`scp`) between the host and guests. + +This setup works if you only access VMs from the host. However, remote systems on a different subnet (e.g., `.0/24`) **cannot** reach the VMs. + +To enable external access, we need a *public bridge* that connects VMs to the host’s main network, using its DHCP. This ensures VMs get IPs in the same range as the host. + +Before configuring a public bridge, **disable Netfilter** on bridges for better performance and security, as it is enabled by default. + +- Create a file located at `/etc/sysctl.d/bridge.conf`: +```bash +nano /etc/sysctl.d/bridge.conf + +# in case of using custom editor, replace nano in the syntax +``` + +- Paste inside the following block, save and exit: +```ini +net.bridge.bridge-nf-call-ip6tables=0 +net.bridge.bridge-nf-call-iptables=0 +net.bridge.bridge-nf-call-arptables=0 +``` + +- Create a file `/etc/udev/rules.d/99-bridge.rules`: +```bash +nano /etc/udev/rules.d/99-bridge.rules +``` + +- Paste this line, save and exit: +```bash +ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf" +``` + +This disables Netfilter on bridges at startup. Save, exit, and reboot to apply changes. + +- Disable KVM’s default networking. Find the default network interface with: +```bash +ip link +``` + +
+ +The command output should look similar to this one: +``` +root@nym-exit:~# ip link +1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 +2: eno1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff + altname enp2s0f0 +3: eno2: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff + altname enp2s0f1 +4: eno49: mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 + link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff + altname enp4s0f0 +5: eno3: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff + altname enp2s0f2 +6: eno50: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff + altname enp4s0f1 +7: eno4: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff + altname enp2s0f3 +8: virbr0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000 + link/ether 52:54:00:ac:d3:ba brd ff:ff:ff:ff:ff:ff +``` + +The `virbr0` interface is KVM’s default network. Note your physical interface’s MAC address (e.g., `eno49`). It's the only interface that is currently `UP` and running (`LOWER_UP` state). Other interfaces are `DOWN` and not in use. + + +- Remove the default KVM network: +```bash +virsh net-destroy default +``` + +- Remove the default network configuration: +```bash +virsh net-undefine default +``` + +- In case last two commands didn't work, try this: +```bash +ip link delete virbr0 type bridge +``` +- Verify that the `virbr0` and `virbr0-nic` interfaces are deleted: +```bash +ip link +``` + +The command output should look similar to this one: +``` +root@nym-exit:~# ip link +1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 +2: eno1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff + altname enp2s0f0 +3: eno2: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff + altname enp2s0f1 +4: eno49: mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 + link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff + altname enp4s0f0 +5: eno3: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff + altname enp2s0f2 +6: eno50: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff + altname enp4s0f1 +7: eno4: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 + link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff + altname enp2s0f3 +``` +KVM network is gone. + + + +##### 3. Setup KVM public bridge for new VMs + +To create a KVM network bridge on Ubuntu, edit a config file located in `/etc/netplan/` either called `00-installer.yaml` or `00-installer-config.yaml` and add the bridge details. + +- Before you edit the file, make a backup to stay on the save side: +```bash +cp /etc/netplan/00-installer-config.yaml /etc/netplan/00-installer-config.yaml.bak +# or +cp /etc/netplan/00-installer.yaml /etc/netplan/00-installer.yaml.bak +``` + +- Open `00-installer-config.yaml` or `00-installer.yaml.`config in a text editor: +```bash +nano /etc/netplan/00-installer.yaml +# or +nano /etc/netplan/00-installer-config.yaml +``` + +- Edit the block below and paste it to the config file, save and exit: +```ini +##################################################### +######## CHANGE ALL VARIABLES IN <> BRACKETS ######## +##################################################### + +# is your own one, you can get with command ip link show +# is your server main IPv4 address +# value can be found by running: ip route | grep default + + +# This is the network config written by 'subiquity' +network: + version: 2 + ethernets: + : + dhcp4: false + dhcp6: false + + # Bridge interface configuration + bridges: + br0: + interfaces: [] + addresses: [/24] + routes: + - to: default + via: + mtu: 1500 + nameservers: + addresses: + - 8.8.8.8 + - 1.1.1.1 + - 77.88.8.8 + parameters: + stp: false # Disable STP unless multiple bridges exist + forward-delay: 15 # Can be shortened, 15 sec is a common default +``` + + +Ensure the indentation matches exactly as shown above. Incorrect spacing will prevent the bridged network interface from activating. + + +- Validate `netplan` configuration without applying to prevent breaking network changes: +```bash +netplan generate + +# Correct configuration output will show nothing +``` + +- Safety test your changes to catch syntax errors before applying: +```bash +netplan try +``` + +- Apply your changes: +```bash +netplan --debug apply +``` + +- In case of proubems try some of these steps: + +- Validate YAML configuration, given that YAML is syntax sensitive: +```bash +apt install yamllint -y + +yamllint /etc/netplan/00-installer.yaml +# or +yamllint /etc/netplan/00-installer-config.yaml + + +``` +- Apply correct permissions: +```bash +chmod 600 /etc/netplan/00-installer.yaml +chown root:root /etc/netplan/00-installer.yaml +``` + +- Manually bring up the bridge: +```bash +ip link add name br0 type bridge +ip link set br0 up +ip a show br0 +``` + +- ensure `systemd-networkd` is enabled: +```bash +systemctl restart systemd-networkd +systemctl status systemd-networkd +# if inactive, enable it: +systemctl enable --now systemd-networkd +``` + + +- If things went wrong, you can always revert from the backed up file: +```bash +cp /etc/netplan/00-installer-config.yaml.bak /etc/netplan/00-installer-config.yaml +# or +cp /etc/netplan/00-installer.yaml.bak /etc/netplan/00-installer.yaml +# and +netplan apply +``` + + +Using different IPs for your physical NIC and KVM bridge will disconnect SSH when applying changes. Reconnect using the bridge's new IP. If both share the same IP, no disruption occurs. + + + +- Verify that the IP address has been assigned to the bridge interface: +```bash +ip a +``` + +The command output should look similar to this one: +``` +root@nym-exit:~# ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: eno1: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff + altname enp2s0f0 +3: eno2: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff + altname enp2s0f1 +4: eno3: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff + altname enp2s0f2 +5: eno49: mtu 1500 qdisc mq master br0 state UP group default qlen 1000 + link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff + altname enp4s0f0 +6: eno4: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff + altname enp2s0f3 +7: eno50: mtu 1500 qdisc noop state DOWN group default qlen 1000 + link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff + altname enp4s0f1 +8: br0: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 46:50:aa:c0:49:a5 brd ff:ff:ff:ff:ff:ff + inet 31.222.238.222/24 brd 31.222.238.255 scope global br0 + valid_lft forever preferred_lft forever + inet6 fe80::4450:aaff:fec0:49a5/64 scope link + valid_lft forever preferred_lft forever +``` +The bridged interface `br0` now has the IP ``, and `` shows `master br0`, indicating it is part of the bridge. + + +Alternatively you can use `brctl` command to display the KVM bridge network status: +```bash +brctl show br0 +``` + +##### 4. Add Bridge Network to KVM + +- Configure KVM to use the bridge by creating `host-bridge.xml`, open a text editor and pate the block below: +```bash +nano host-bridge.xml +``` + +```xml + + host-bridge + + + +``` + +- Start the new bridge and set it as the default for VMs: +```bash +virsh net-define host-bridge.xml +virsh net-start host-bridge +virsh net-autostart host-bridge +``` + +- Verify that the KVM bridge is active: +```bash +virsh net-list --all +``` + +```bash +root@nym-exit:~# virsh net-list --all + Name State Autostart Persistent +------------------------------------------------ + host-bridge active yes yes +``` + + +KVM bridge networking is successfully set up and active! + +Your KVM installation is now ready to deploy and manage VMs. + +
+ +### Setting Up Virtual Machines + +After finishing the [installation of KVM](#installing-kvm-on-a-server-with-ubuntu-2204), we can move to the virtualisation configuration. + +> **The steps below will guide you through a setup of one VM, therefore you will have to repeat this process for each VM**. That also means that you have to be mindful of space and memory allocation. + + +##### 1. Install OS for VMs + +This is the OS on which the nodes themselves will run. You can chose any GNU/Linux of your preference. For this guide we are going to be using Ubuntu 24.04 LTS (Noble Numbat) cloud image from [cloud-images.ubuntu.com](https://cloud-images.ubuntu.com/noble/current/). + +- Download Ubuntu Cloud image: +```bash +wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img +``` +- Copy the image to to `/var/lib/libvirt/images/` asigning to it a name your VM +```bash +cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/.img + +# for example: +# cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/ubuntu-1.img +``` + +##### 2. Create and resize a virtual machine + +- Get `guestfs-tools` to be able to customize your login credentials: +```bash +apt install guestfs-tools +``` + +- Define login credentials: +```bash +virt-customize -a /var/lib/libvirt/images/.img --root-password password: +# for example +# virt-customize -a /var/lib/libvirt/images/ubuntu-1.img --root-password password:makesuretosaveyourpasswordslocallytoapasswordmanager +``` + +- Use `qemu-img` tool with a command `resize` to create a VM according your needs. You can see `qemu` [documentation page`](https://www.qemu.org/docs/master/tools/qemu-img.html) for more info on how to use it correctly. +```bash +qemu-img resize /var/lib/libvirt/images/.img +G +# for example +# qemu-img resize /var/lib/libvirt/images/ubuntu-1.img +100G +``` + +- Resize it from within it after `virt-install` command: +```bash +virt-install \ +--name \ +--ram= \ +--vcpus= \ +--cpu host \ +--hvm \ +--disk bus=virtio,path=/var/lib/libvirt/images/.img \ +--network bridge=br0 \ +--graphics none \ +--console pty,target_type=serial \ +--osinfo \ +--import +``` + +- In our example we go with 4 GB RAM on the same machine as before: +
+ +```bash +virt-install \ +--name ubuntu-1 \ +--ram=4096 \ +--vcpus=4 \ +--cpu host \ +--hvm \ +--disk bus=virtio,path=/var/lib/libvirt/images/ubuntu-1.img \ +--network bridge=br0 \ +--graphics none \ +--console pty,target_type=serial \ +--osinfo ubuntunoble \ +--import +``` + + +- After loading you should see a login console, you can also initiate it by: +```bash +virsh console +# for example +# virsh console ubuntu-1 +``` + +- Log in to your new VM using your credentials. + +##### 3. Validate your setup + +- Make sure the `root` disk has the expected space by running: +```bash +df -h +``` + +- If not, run: +```bash +growpart /dev/vda 1 +resize2fs /dev/vda1 +``` + +##### 4. Configure networking for the VM + +As this guide is based on a newer Ubuntu, we use `netplan`, this may be different on different OS. + +- Open `/etc/netplan/01-network-config.yaml` in your favourite text editor: +```bash +nano /etc/netplan/01-network-config.yaml +``` + +- Insert this config, using your correct IP configuration, save and exit: +```ini +network: + version: 2 + renderer: networkd + ethernets: + : + dhcp4: false + dhcp6: false # Set to true if you want automatic IPv6 assignment + addresses: + - /24 # Assign IPv4 address to the VM + - /64 # Assign IPv6 address to the VM + routes: + - to: default + via: # IPv4 gateway (host machine) + - to: default + via: # IPv6 gateway (host machine) + nameservers: + addresses: + - 1.1.1.1 # Cloudflare IPv4 DNS + - 8.8.8.8 # Google IPv4 DNS + - 2606:4700:4700::1111 # Cloudflare IPv6 DNS + - 2001:4860:4860::8888 # Google IPv6 DNS +``` +- Fix wide permissions on the config file: +```bash +chmod 600 /etc/netplan/01-network-config.yaml +``` + +- Check if the config has any errors: +```bash +netplan generate +``` + +- Apply the configuration: +```bash +netplan --debug apply +``` + +- Verify by checking if IPv4 and IPv6 are assigned correctly and if they route: +```bash +ip -4 a +ip -6 a +``` +```bash +ip -4 r +ip -6 r +``` +```bash +# to ping through IPv6, use: +ping6 nym.com +``` +- You should be able to ping your new VM from a local machine: +```bash +ping +ping6 +``` + +
+ +Your VM should be working and fully routable. To be able to use it properly, we will create a direct SSH access to the VM. + +#### Configure VM SSH access + + + +##### 1. Log in to your VM, update and upgrade your OS: +- Log in to your server using as `root` or as a non-root user with `sudo` privileges +```bash +apt update; apt upgrade +``` + +##### 2. Generate new host SSH keys + +Since we used a `cloud-init` image without an SSH server, we need to generate SSH host keys for client authentication and server identity verification. All of them will be saved to this location: `/etc/ssh/`. + +- Generate a new RSA host key: +```bash +ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key +``` +- Generate a new DSA host key: +```bash +ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key +``` +- Generate a new ECDSA host key: +```bash +ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key +``` +- Finally, generate a new ED25519 host key: +```bash +ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key +``` +##### 3. Restart the SSH service on the server +- Run: +```bash +systemctl restart ssh.service +``` + +##### 4. Check if the SSH serice is active +- Run: +```bash +systemctl status ssh.service +``` + +##### 5. Create file `~/.ssh/authorized_keys` and add you public key: +- Create `.ssh` directory: +```bash +mkdir ~/.ssh +``` + +- Open with your favourite text editor: +```bash +nano ~/.ssh/authorized_keys +``` +- Paste your SSH public key, save and exit + +- In case of non-root, setup a correct ownership and permissions: +```bash +chmod 600 ~/.ssh/authorized_keys +chmod 700 ~/.ssh +chown : ~/.ssh +``` + +##### 5. Test by connecting via SSH + +- Now you should be able to connect to the VM directly from your local terminal +```bash +ssh root@ -i ~/.ssh/your_ssh_key +``` + + +Now your VM is almost ready for `nym-node` [setup](../../nym-node/setup). Before you proceed, ssh in and [configure all prerequisities](../vps-setup#vps-configuration) needed for `nym-node` installation and operation. diff --git a/documentation/docs/vercel.json b/documentation/docs/vercel.json new file mode 100644 index 0000000000..ccbd4d0782 --- /dev/null +++ b/documentation/docs/vercel.json @@ -0,0 +1,7 @@ +{ + "git": { + "deploymentEnabled": { + "master": false + } + } +} diff --git a/gateway/src/config.rs b/gateway/src/config.rs index 1f6db8f0b8..363ddbb88e 100644 --- a/gateway/src/config.rs +++ b/gateway/src/config.rs @@ -102,8 +102,8 @@ pub struct Debug { pub zk_nym_tickets: ZkNymTicketHandlerDebug, - /// Defines the maximum age of a signed authentication request before it's deemed too stale to process. - pub maximum_auth_request_age: Duration, + /// Defines the timestamp skew of a signed authentication request before it's deemed too excessive to process. + pub max_request_timestamp_skew: Duration, } #[derive(Debug, Clone)] diff --git a/gateway/src/node/client_handling/websocket/common_state.rs b/gateway/src/node/client_handling/websocket/common_state.rs index a571117895..fc66e855be 100644 --- a/gateway/src/node/client_handling/websocket/common_state.rs +++ b/gateway/src/node/client_handling/websocket/common_state.rs @@ -14,12 +14,11 @@ use std::time::Duration; #[derive(Clone)] pub(crate) struct Config { pub(crate) enforce_zk_nym: bool, - pub(crate) max_auth_request_age: Duration, + pub(crate) max_request_timestamp_skew: Duration, pub(crate) bandwidth: BandwidthFlushingBehaviourConfig, } -// I can see this being possible expanded with say storage or client store #[derive(Clone)] pub(crate) struct CommonHandlerState { pub(crate) cfg: Config, diff --git a/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs b/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs index bd1f9fd601..23d9604814 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/fresh.rs @@ -131,9 +131,6 @@ impl FreshHandler { // for time being we assume handle is always constructed from raw socket. // if we decide we want to change it, that's not too difficult - // also at this point I'm not entirely sure how to deal with this warning without - // some considerable refactoring - #[allow(clippy::too_many_arguments)] pub(crate) fn new( rng: R, conn: S, @@ -641,7 +638,7 @@ impl FreshHandler { // do cheap checks first // is the provided timestamp relatively recent (and not in the future?) - request.verify_timestamp(self.shared_state.cfg.max_auth_request_age)?; + request.verify_timestamp(self.shared_state.cfg.max_request_timestamp_skew)?; // does the message signature verify? request.verify_signature()?; diff --git a/gateway/src/node/client_handling/websocket/listener.rs b/gateway/src/node/client_handling/websocket/listener.rs index 2d358840e7..94e11122ef 100644 --- a/gateway/src/node/client_handling/websocket/listener.rs +++ b/gateway/src/node/client_handling/websocket/listener.rs @@ -6,9 +6,8 @@ use crate::node::client_handling::websocket::connection_handler::FreshHandler; use nym_task::TaskClient; use rand::rngs::OsRng; use std::net::SocketAddr; -use std::process; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; +use std::{io, process}; +use tokio::net::TcpStream; use tokio::task::JoinHandle; use tracing::*; @@ -34,6 +33,76 @@ impl Listener { } } + fn active_connections(&self) -> usize { + self.shared_state + .metrics + .network + .active_ingress_websocket_connections_count() + } + + fn prepare_connection_handler( + &self, + socket: TcpStream, + remote_address: SocketAddr, + ) -> FreshHandler { + let shutdown = self + .shutdown + .fork(format!("websocket_handler_{remote_address}")); + FreshHandler::new( + OsRng, + socket, + self.shared_state.clone(), + remote_address, + shutdown, + ) + } + + fn try_handle_accepted_connection(&self, accepted: io::Result<(TcpStream, SocketAddr)>) { + match accepted { + Ok((socket, remote_address)) => { + trace!("received a socket connection from {remote_address}"); + + let active = self.active_connections(); + + // 1. check if we're within the connection limit + if active >= self.maximum_open_connections { + warn!( + "connection limit exceeded ({}). can't accept request from {remote_address}", + self.maximum_open_connections + ); + return; + } + + debug!("there are currently {active} connected clients on the gateway websocket"); + + // 2. prepare shared data for the new connection handler + let handle = self.prepare_connection_handler(socket, remote_address); + + // 3. increment the connection counter. + // make sure to do it before spawning the task, + // as another connection might get accepted before the task is scheduled + // for execution + self.shared_state + .metrics + .network + .new_ingress_websocket_client(); + + // 4. spawn the task handling the client connection + tokio::spawn(async move { + // TODO: refactor it similarly to the mixnet listener on the nym-node + let metrics_ref = handle.shared_state.metrics.clone(); + + // 4.1. handle all client requests until connection gets terminated + handle.start_handling().await; + + // 4.2. decrement the connection counter + metrics_ref.network.disconnected_ingress_websocket_client(); + }); + } + Err(err) => warn!("failed to accept client connection: {err}"), + } + } + // TODO: change the signature to pub(crate) async fn run(&self, handler: Handler) pub(crate) async fn run(&mut self) { @@ -46,8 +115,6 @@ impl Listener { } }; - let open_connections = Arc::new(AtomicUsize::new(0)); - while !self.shutdown.is_shutdown() { tokio::select! { biased; @@ -55,38 +122,7 @@ impl Listener { trace!("client_handling::Listener: received shutdown"); } connection = tcp_listener.accept() => { - match connection { - Ok((socket, remote_addr)) => { - let shutdown = self.shutdown.fork(format!("websocket_handler_{remote_addr}")); - trace!("received a socket connection from {remote_addr}"); - - if open_connections.fetch_add(1, Ordering::SeqCst) >= self.maximum_open_connections { - warn!("connection limit exceeded ({}). can't accept request from {remote_addr}", self.maximum_open_connections); - continue; - } - - // TODO: I think we *REALLY* need a mechanism for having a maximum number of connected - // clients or spawned tokio tasks -> perhaps a worker system? - let handle = FreshHandler::new( - OsRng, - socket, - self.shared_state.clone(), - remote_addr, - shutdown, - ); - let open_connections = open_connections.clone(); - tokio::spawn(async move { - // TODO: refactor it similarly to the mixnet listener on the nym-node - let metrics_ref = handle.shared_state.metrics.clone(); - metrics_ref.network.new_ingress_websocket_client(); - open_connections.fetch_add(1, Ordering::SeqCst); - handle.start_handling().await; - metrics_ref.network.disconnected_ingress_websocket_client(); - open_connections.fetch_sub(1, Ordering::SeqCst); - }); - } - Err(err) => warn!("failed to get client: {err}"), - } + self.try_handle_accepted_connection(connection) } } diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index a582a24735..c13df9f241 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -251,7 +251,7 @@ impl GatewayTasksBuilder { let shared_state = websocket::CommonHandlerState { cfg: websocket::Config { enforce_zk_nym: self.config.gateway.enforce_zk_nyms, - max_auth_request_age: self.config.debug.maximum_auth_request_age, + max_request_timestamp_skew: self.config.debug.max_request_timestamp_skew, bandwidth: (&self.config).into(), }, ecash_verifier: self.ecash_manager().await?, diff --git a/nym-api.dockerfile b/nym-api.dockerfile index 7ee95379dc..5701fbb395 100644 --- a/nym-api.dockerfile +++ b/nym-api.dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nym-api diff --git a/nym-api/Cargo.toml b/nym-api/Cargo.toml index aa6b966b7f..eaf4ec5b08 100644 --- a/nym-api/Cargo.toml +++ b/nym-api/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "nym-api" license = "GPL-3.0" -version = "1.1.53" +version = "1.1.54" authors.workspace = true edition = "2021" rust-version.workspace = true @@ -141,7 +141,7 @@ tempfile = { workspace = true } cw3 = { workspace = true } cw-utils = { workspace = true } rand_chacha = { workspace = true } -sha2 = "0.9" +sha2 = { workspace = true } [lints] workspace = true diff --git a/nym-api/nym-api-requests/Cargo.toml b/nym-api/nym-api-requests/Cargo.toml index 9ca0fe6ea4..5c9ee287b6 100644 --- a/nym-api/nym-api-requests/Cargo.toml +++ b/nym-api/nym-api-requests/Cargo.toml @@ -17,6 +17,7 @@ humantime-serde = { workspace = true } serde_json = { workspace = true } sha2.workspace = true tendermint = { workspace = true } +tendermint-rpc = { workspace = true } thiserror.workspace = true time = { workspace = true, features = ["serde", "parsing", "formatting"] } ts-rs = { workspace = true, optional = true } diff --git a/nym-api/nym-api-requests/src/models.rs b/nym-api/nym-api-requests/src/models.rs index 2558613c8c..a39b6f25c7 100644 --- a/nym-api/nym-api-requests/src/models.rs +++ b/nym-api/nym-api-requests/src/models.rs @@ -27,9 +27,7 @@ use nym_network_defaults::{DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_ use nym_node_requests::api::v1::authenticator::models::Authenticator; use nym_node_requests::api::v1::gateway::models::Wireguard; use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter; -use nym_node_requests::api::v1::node::models::{ - AuxiliaryDetails, BinaryBuildInformationOwned, NodeRoles, -}; +use nym_node_requests::api::v1::node::models::{AuxiliaryDetails, NodeRoles}; use schemars::gen::SchemaGenerator; use schemars::schema::{InstanceType, Schema, SchemaObject}; use schemars::JsonSchema; @@ -43,6 +41,8 @@ use thiserror::Error; use time::{Date, OffsetDateTime}; use utoipa::{IntoParams, ToResponse, ToSchema}; +pub use nym_node_requests::api::v1::node::models::BinaryBuildInformationOwned; + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] pub struct RequestError { message: String, @@ -1215,6 +1215,7 @@ impl From for WireguardDetails { #[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)] pub struct ApiHealthResponse { pub status: ApiStatus, + #[serde(default)] pub chain_status: ChainStatus, pub uptime: u64, } @@ -1225,10 +1226,11 @@ pub enum ApiStatus { Up, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Default, schemars::JsonSchema, ToSchema)] #[serde(rename_all = "snake_case")] pub enum ChainStatus { Synced, + #[default] Unknown, Stalled { #[serde( @@ -1428,7 +1430,297 @@ impl From for RewardedSetResponse } } +#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +pub struct ChainStatusResponse { + pub connected_nyxd: String, + pub status: DetailedChainStatus, +} + +#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +pub struct DetailedChainStatus { + pub abci: crate::models::tendermint_types::AbciInfo, + pub latest_block: BlockInfo, +} + +#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +pub struct BlockInfo { + pub block_id: BlockId, + pub block: FullBlockInfo, + // if necessary we might put block data here later too +} + +impl From for BlockInfo { + fn from(value: tendermint_rpc::endpoint::block::Response) -> Self { + BlockInfo { + block_id: value.block_id.into(), + block: FullBlockInfo { + header: value.block.header.into(), + }, + } + } +} + +#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] +pub struct FullBlockInfo { + pub header: BlockHeader, +} + +// copy tendermint types definitions whilst deriving schema types on them and dropping unwanted fields +pub mod tendermint_types { + use schemars::JsonSchema; + use serde::{Deserialize, Serialize}; + use tendermint::abci::response::Info; + use tendermint::block::header::Version; + use tendermint::{block, Hash}; + use utoipa::ToSchema; + + #[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] + pub struct AbciInfo { + /// Some arbitrary information. + pub data: String, + + /// The application software semantic version. + pub version: String, + + /// The application protocol version. + pub app_version: u64, + + /// The latest block for which the app has called [`Commit`]. + pub last_block_height: u64, + + /// The latest result of [`Commit`]. + pub last_block_app_hash: String, + } + + impl From for AbciInfo { + fn from(value: Info) -> Self { + AbciInfo { + data: value.data, + version: value.version, + app_version: value.app_version, + last_block_height: value.last_block_height.value(), + last_block_app_hash: value.last_block_app_hash.to_string(), + } + } + } + + /// `Version` contains the protocol version for the blockchain and the + /// application. + /// + /// + #[derive( + Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema, ToSchema, + )] + pub struct HeaderVersion { + /// Block version + pub block: u64, + + /// App version + pub app: u64, + } + + impl From for HeaderVersion { + fn from(value: Version) -> Self { + HeaderVersion { + block: value.block, + app: value.app, + } + } + } + + /// Block identifiers which contain two distinct Merkle roots of the block, + /// as well as the number of parts in the block. + /// + /// + /// + /// Default implementation is an empty Id as defined by the Go implementation in + /// . + /// + /// If the Hash is empty in BlockId, the BlockId should be empty (encoded to None). + /// This is implemented outside of this struct. Use the Default trait to check for an empty BlockId. + /// See: + #[derive( + Serialize, + Deserialize, + Copy, + Clone, + Debug, + Default, + Hash, + Eq, + PartialEq, + PartialOrd, + Ord, + JsonSchema, + ToSchema, + )] + pub struct BlockId { + /// The block's main hash is the Merkle root of all the fields in the + /// block header. + #[schemars(with = "String")] + #[schema(value_type = String)] + pub hash: Hash, + + /// Parts header (if available) is used for secure gossipping of the block + /// during consensus. It is the Merkle root of the complete serialized block + /// cut into parts. + /// + /// PartSet is used to split a byteslice of data into parts (pieces) for + /// transmission. By splitting data into smaller parts and computing a + /// Merkle root hash on the list, you can verify that a part is + /// legitimately part of the complete data, and the part can be forwarded + /// to other peers before all the parts are known. In short, it's a fast + /// way to propagate a large file over a gossip network. + /// + /// + /// + /// PartSetHeader in protobuf is defined as never nil using the gogoproto + /// annotations. This does not translate to Rust, but we can indicate this + /// in the domain type. + pub part_set_header: PartSetHeader, + } + + impl From for BlockId { + fn from(value: block::Id) -> Self { + BlockId { + hash: value.hash, + part_set_header: value.part_set_header.into(), + } + } + } + + /// Block parts header + #[derive( + Clone, + Copy, + Debug, + Default, + Hash, + Eq, + PartialEq, + PartialOrd, + Ord, + Deserialize, + Serialize, + JsonSchema, + ToSchema, + )] + #[non_exhaustive] + pub struct PartSetHeader { + /// Number of parts in this block + pub total: u32, + + /// Hash of the parts set header, + #[schemars(with = "String")] + #[schema(value_type = String)] + pub hash: Hash, + } + + impl From for PartSetHeader { + fn from(value: block::parts::Header) -> Self { + PartSetHeader { + total: value.total, + hash: value.hash, + } + } + } + + /// Block `Header` values contain metadata about the block and about the + /// consensus, as well as commitments to the data in the current block, the + /// previous block, and the results returned by the application. + /// + /// + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, ToSchema)] + pub struct BlockHeader { + /// Header version + pub version: HeaderVersion, + + /// Chain ID + pub chain_id: String, + + /// Current block height + pub height: u64, + + /// Current timestamp + #[schemars(with = "String")] + #[schema(value_type = String)] + pub time: tendermint::Time, + + /// Previous block info + pub last_block_id: Option, + + /// Commit from validators from the last block + #[schemars(with = "Option")] + #[schema(value_type = Option)] + pub last_commit_hash: Option, + + /// Merkle root of transaction hashes + #[schemars(with = "Option")] + #[schema(value_type = Option)] + pub data_hash: Option, + + /// Validators for the current block + #[schemars(with = "String")] + #[schema(value_type = String)] + pub validators_hash: Hash, + + /// Validators for the next block + #[schemars(with = "String")] + #[schema(value_type = String)] + pub next_validators_hash: Hash, + + /// Consensus params for the current block + #[schemars(with = "String")] + #[schema(value_type = String)] + pub consensus_hash: Hash, + + /// State after txs from the previous block + #[schemars(with = "String")] + #[schema(value_type = String)] + pub app_hash: Hash, + + /// Root hash of all results from the txs from the previous block + #[schemars(with = "Option")] + #[schema(value_type = Option)] + pub last_results_hash: Option, + + /// Hash of evidence included in the block + #[schemars(with = "Option")] + #[schema(value_type = Option)] + pub evidence_hash: Option, + + /// Original proposer of the block + #[serde(with = "nym_serde_helpers::hex")] + #[schemars(with = "String")] + #[schema(value_type = String)] + pub proposer_address: Vec, + } + + impl From for BlockHeader { + fn from(value: block::Header) -> Self { + BlockHeader { + version: value.version.into(), + chain_id: value.chain_id.to_string(), + height: value.height.value(), + time: value.time, + last_block_id: value.last_block_id.map(Into::into), + last_commit_hash: value.last_commit_hash, + data_hash: value.data_hash, + validators_hash: value.validators_hash, + next_validators_hash: value.next_validators_hash, + consensus_hash: value.consensus_hash, + app_hash: Hash::try_from(value.app_hash.as_bytes().to_vec()).unwrap_or_default(), + last_results_hash: value.last_results_hash, + evidence_hash: value.evidence_hash, + proposer_address: value.proposer_address.as_bytes().to_vec(), + } + } + } +} + +use crate::models::tendermint_types::{BlockHeader, BlockId}; pub use config_score::*; + pub mod config_score { use nym_contracts_common::NaiveFloat; use serde::{Deserialize, Serialize}; diff --git a/nym-api/nym-api-requests/src/nym_nodes.rs b/nym-api/nym-api-requests/src/nym_nodes.rs index 96c981c8a1..544e07a861 100644 --- a/nym-api/nym-api-requests/src/nym_nodes.rs +++ b/nym-api/nym-api-requests/src/nym_nodes.rs @@ -10,6 +10,7 @@ use nym_mixnet_contract_common::nym_node::Role; use nym_mixnet_contract_common::reward_params::Performance; use nym_mixnet_contract_common::{Interval, NodeId}; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::net::IpAddr; use time::OffsetDateTime; use utoipa::ToSchema; @@ -212,3 +213,15 @@ pub struct FullFatNode { // kinda temporary for now to make as few changes as possible for now pub self_described: Option, } + +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, ToSchema)] +pub struct NodesByAddressesRequestBody { + #[schema(value_type = Vec)] + pub addresses: Vec, +} + +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, ToSchema)] +pub struct NodesByAddressesResponse { + #[schema(value_type = HashMap>)] + pub existence: HashMap>, +} diff --git a/nym-api/src/ecash/tests/mod.rs b/nym-api/src/ecash/tests/mod.rs index e1f0c38083..3afd91f7e7 100644 --- a/nym-api/src/ecash/tests/mod.rs +++ b/nym-api/src/ecash/tests/mod.rs @@ -109,7 +109,7 @@ impl InternalCounters { // just hash the current counter self.tx_hash_counter += 1; - Hash::Sha256(sha2::Sha256::digest(&self.tx_hash_counter.to_be_bytes()).into()) + Hash::Sha256(sha2::Sha256::digest(self.tx_hash_counter.to_be_bytes()).into()) } #[allow(dead_code)] diff --git a/nym-api/src/network/handlers.rs b/nym-api/src/network/handlers.rs index a308a9fa82..380e78e736 100644 --- a/nym-api/src/network/handlers.rs +++ b/nym-api/src/network/handlers.rs @@ -1,11 +1,12 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::network::models::{ChainStatusResponse, ContractInformation, NetworkDetails}; +use crate::network::models::{ContractInformation, NetworkDetails}; use crate::node_status_api::models::AxumResult; use crate::support::http::state::AppState; use axum::extract::State; use axum::{extract, Json, Router}; +use nym_api_requests::models::ChainStatusResponse; use nym_contracts_common::ContractBuildInformation; use std::collections::HashMap; use tower_http::compression::CompressionLayer; diff --git a/nym-api/src/network/models.rs b/nym-api/src/network/models.rs index 066b473921..1819ce024d 100644 --- a/nym-api/src/network/models.rs +++ b/nym-api/src/network/models.rs @@ -1,9 +1,7 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::network::models::tendermint_types::{AbciInfo, BlockHeader, BlockId}; use nym_config::defaults::NymNetworkDetails; -use nym_validator_client::nyxd::BlockResponse; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; @@ -29,292 +27,3 @@ pub struct ContractInformation { pub(crate) address: Option, pub(crate) details: Option, } - -#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] -pub struct ChainStatusResponse { - pub connected_nyxd: String, - pub status: ChainStatus, -} - -#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] -pub struct ChainStatus { - pub abci: AbciInfo, - pub latest_block: BlockInfo, -} - -#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] -pub struct BlockInfo { - pub block_id: BlockId, - pub block: FullBlockInfo, - // if necessary we might put block data here later too -} - -impl From for BlockInfo { - fn from(value: BlockResponse) -> Self { - BlockInfo { - block_id: value.block_id.into(), - block: FullBlockInfo { - header: value.block.header.into(), - }, - } - } -} - -#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] -pub struct FullBlockInfo { - pub header: BlockHeader, -} - -// copy tendermint types definitions whilst deriving schema types on them and dropping unwanted fields -pub mod tendermint_types { - use nym_validator_client::nyxd::Hash; - use schemars::JsonSchema; - use serde::{Deserialize, Serialize}; - use tendermint::abci::response::Info; - use tendermint::block; - use tendermint::block::header::Version; - use utoipa::ToSchema; - - #[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)] - pub struct AbciInfo { - /// Some arbitrary information. - pub data: String, - - /// The application software semantic version. - pub version: String, - - /// The application protocol version. - pub app_version: u64, - - /// The latest block for which the app has called [`Commit`]. - pub last_block_height: u64, - - /// The latest result of [`Commit`]. - pub last_block_app_hash: String, - } - - impl From for AbciInfo { - fn from(value: Info) -> Self { - AbciInfo { - data: value.data, - version: value.version, - app_version: value.app_version, - last_block_height: value.last_block_height.value(), - last_block_app_hash: value.last_block_app_hash.to_string(), - } - } - } - - /// `Version` contains the protocol version for the blockchain and the - /// application. - /// - /// - #[derive( - Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema, ToSchema, - )] - pub struct HeaderVersion { - /// Block version - pub block: u64, - - /// App version - pub app: u64, - } - - impl From for HeaderVersion { - fn from(value: Version) -> Self { - HeaderVersion { - block: value.block, - app: value.app, - } - } - } - - /// Block identifiers which contain two distinct Merkle roots of the block, - /// as well as the number of parts in the block. - /// - /// - /// - /// Default implementation is an empty Id as defined by the Go implementation in - /// . - /// - /// If the Hash is empty in BlockId, the BlockId should be empty (encoded to None). - /// This is implemented outside of this struct. Use the Default trait to check for an empty BlockId. - /// See: - #[derive( - Serialize, - Deserialize, - Copy, - Clone, - Debug, - Default, - Hash, - Eq, - PartialEq, - PartialOrd, - Ord, - JsonSchema, - ToSchema, - )] - pub struct BlockId { - /// The block's main hash is the Merkle root of all the fields in the - /// block header. - #[schemars(with = "String")] - #[schema(value_type = String)] - pub hash: Hash, - - /// Parts header (if available) is used for secure gossipping of the block - /// during consensus. It is the Merkle root of the complete serialized block - /// cut into parts. - /// - /// PartSet is used to split a byteslice of data into parts (pieces) for - /// transmission. By splitting data into smaller parts and computing a - /// Merkle root hash on the list, you can verify that a part is - /// legitimately part of the complete data, and the part can be forwarded - /// to other peers before all the parts are known. In short, it's a fast - /// way to propagate a large file over a gossip network. - /// - /// - /// - /// PartSetHeader in protobuf is defined as never nil using the gogoproto - /// annotations. This does not translate to Rust, but we can indicate this - /// in the domain type. - pub part_set_header: PartSetHeader, - } - - impl From for BlockId { - fn from(value: block::Id) -> Self { - BlockId { - hash: value.hash, - part_set_header: value.part_set_header.into(), - } - } - } - - /// Block parts header - #[derive( - Clone, - Copy, - Debug, - Default, - Hash, - Eq, - PartialEq, - PartialOrd, - Ord, - Deserialize, - Serialize, - JsonSchema, - ToSchema, - )] - #[non_exhaustive] - pub struct PartSetHeader { - /// Number of parts in this block - pub total: u32, - - /// Hash of the parts set header, - #[schemars(with = "String")] - #[schema(value_type = String)] - pub hash: Hash, - } - - impl From for PartSetHeader { - fn from(value: block::parts::Header) -> Self { - PartSetHeader { - total: value.total, - hash: value.hash, - } - } - } - - /// Block `Header` values contain metadata about the block and about the - /// consensus, as well as commitments to the data in the current block, the - /// previous block, and the results returned by the application. - /// - /// - #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, ToSchema)] - pub struct BlockHeader { - /// Header version - pub version: HeaderVersion, - - /// Chain ID - pub chain_id: String, - - /// Current block height - pub height: u64, - - /// Current timestamp - #[schemars(with = "String")] - #[schema(value_type = String)] - pub time: tendermint::Time, - - /// Previous block info - pub last_block_id: Option, - - /// Commit from validators from the last block - #[schemars(with = "Option")] - #[schema(value_type = Option)] - pub last_commit_hash: Option, - - /// Merkle root of transaction hashes - #[schemars(with = "Option")] - #[schema(value_type = Option)] - pub data_hash: Option, - - /// Validators for the current block - #[schemars(with = "String")] - #[schema(value_type = String)] - pub validators_hash: Hash, - - /// Validators for the next block - #[schemars(with = "String")] - #[schema(value_type = String)] - pub next_validators_hash: Hash, - - /// Consensus params for the current block - #[schemars(with = "String")] - #[schema(value_type = String)] - pub consensus_hash: Hash, - - /// State after txs from the previous block - #[schemars(with = "String")] - #[schema(value_type = String)] - pub app_hash: Hash, - - /// Root hash of all results from the txs from the previous block - #[schemars(with = "Option")] - #[schema(value_type = Option)] - pub last_results_hash: Option, - - /// Hash of evidence included in the block - #[schemars(with = "Option")] - #[schema(value_type = Option)] - pub evidence_hash: Option, - - /// Original proposer of the block - #[serde(with = "nym_serde_helpers::hex")] - #[schemars(with = "String")] - #[schema(value_type = String)] - pub proposer_address: Vec, - } - - impl From for BlockHeader { - fn from(value: block::Header) -> Self { - BlockHeader { - version: value.version.into(), - chain_id: value.chain_id.to_string(), - height: value.height.value(), - time: value.time, - last_block_id: value.last_block_id.map(Into::into), - last_commit_hash: value.last_commit_hash, - data_hash: value.data_hash, - validators_hash: value.validators_hash, - next_validators_hash: value.next_validators_hash, - consensus_hash: value.consensus_hash, - app_hash: Hash::try_from(value.app_hash.as_bytes().to_vec()).unwrap_or_default(), - last_results_hash: value.last_results_hash, - evidence_hash: value.evidence_hash, - proposer_address: value.proposer_address.as_bytes().to_vec(), - } - } - } -} diff --git a/nym-api/src/node_describe_cache/mod.rs b/nym-api/src/node_describe_cache/mod.rs index 9cecb37e1e..cdb9ab67b8 100644 --- a/nym-api/src/node_describe_cache/mod.rs +++ b/nym-api/src/node_describe_cache/mod.rs @@ -17,6 +17,7 @@ use nym_mixnet_contract_common::{NodeId, NymNodeDetails}; use nym_node_requests::api::client::{NymNodeApiClientError, NymNodeApiClientExt}; use nym_topology::node::{RoutingNode, RoutingNodeError}; use std::collections::HashMap; +use std::net::IpAddr; use std::time::Duration; use thiserror::Error; use tracing::{debug, error, info}; @@ -84,10 +85,14 @@ impl NodeDescriptionTopologyExt for NymNodeDescription { #[derive(Debug, Clone)] pub struct DescribedNodes { nodes: HashMap, + addresses_cache: HashMap, } impl DescribedNodes { pub fn force_update(&mut self, node: NymNodeDescription) { + for ip in &node.description.host_information.ip_address { + self.addresses_cache.insert(*ip, node.node_id); + } self.nodes.insert(node.node_id, node); } @@ -129,6 +134,10 @@ impl DescribedNodes { .filter(|n| n.contract_node_type == DescribedNodeType::NymNode) .filter(|n| n.description.declared_role.can_operate_exit_gateway()) } + + pub fn node_with_address(&self, address: IpAddr) -> Option { + self.addresses_cache.get(&address).copied() + } } pub struct NodeDescriptionProvider { @@ -182,6 +191,7 @@ async fn try_get_client( // if provided host was malformed, no point in continuing let client = match nym_node_requests::api::Client::builder(address).and_then(|b| { b.with_timeout(Duration::from_secs(5)) + .no_hickory_dns() .with_user_agent("nym-api-describe-cache") .build() }) { @@ -396,9 +406,20 @@ impl CacheItemProvider for NodeDescriptionProvider { .collect::>() .await; - info!("refreshed self described data for {} nodes", nodes.len()); + let mut addresses_cache = HashMap::new(); + for node in nodes.values() { + for ip in &node.description.host_information.ip_address { + addresses_cache.insert(*ip, node.node_id); + } + } - Ok(DescribedNodes { nodes }) + info!("refreshed self described data for {} nodes", nodes.len()); + info!("with {} unique ip addresses", addresses_cache.len()); + + Ok(DescribedNodes { + nodes, + addresses_cache, + }) } } diff --git a/nym-api/src/nym_nodes/handlers/unstable/mod.rs b/nym-api/src/nym_nodes/handlers/unstable/mod.rs index d1ee06ed1e..f858065d2b 100644 --- a/nym-api/src/nym_nodes/handlers/unstable/mod.rs +++ b/nym-api/src/nym_nodes/handlers/unstable/mod.rs @@ -20,6 +20,7 @@ //! - `/mixnodes/` => only returns mixnode role data //! - `/gateway/` => only returns (entry) gateway role data +use crate::node_status_api::models::{AxumErrorResponse, AxumResult}; use crate::nym_nodes::handlers::unstable::full_fat::nodes_detailed; use crate::nym_nodes::handlers::unstable::semi_skimmed::nodes_expanded; use crate::nym_nodes::handlers::unstable::skimmed::{ @@ -29,10 +30,14 @@ use crate::nym_nodes::handlers::unstable::skimmed::{ }; use crate::support::http::helpers::PaginationRequest; use crate::support::http::state::AppState; -use axum::routing::get; -use axum::Router; -use nym_api_requests::nym_nodes::NodeRoleQueryParam; +use axum::extract::State; +use axum::routing::{get, post}; +use axum::{Json, Router}; +use nym_api_requests::nym_nodes::{ + NodeRoleQueryParam, NodesByAddressesRequestBody, NodesByAddressesResponse, +}; use serde::Deserialize; +use std::collections::HashMap; use tower_http::compression::CompressionLayer; pub(crate) mod full_fat; @@ -74,6 +79,7 @@ pub(crate) fn nym_node_routes_unstable() -> Router { .nest("/full-fat", Router::new().route("/", get(nodes_detailed))) .route("/gateways/skimmed", get(skimmed::deprecated_gateways_basic)) .route("/mixnodes/skimmed", get(skimmed::deprecated_mixnodes_basic)) + .route("/by-addresses", post(nodes_by_addresses)) .layer(CompressionLayer::new()) } @@ -129,3 +135,36 @@ impl<'a> From<&'a NodesParams> for PaginationRequest { } } } + +#[utoipa::path( + tag = "Unstable Nym Nodes", + post, + request_body = NodesByAddressesRequestBody, + path = "/by-addresses", + context_path = "/v1/unstable/nym-nodes", + responses( + (status = 200, body = NodesByAddressesResponse) + ) +)] +async fn nodes_by_addresses( + state: State, + Json(body): Json, +) -> AxumResult> { + // if the request is too big, simply reject it + if body.addresses.len() > 100 { + return Err(AxumErrorResponse::bad_request( + "requested too many addresses", + )); + } + + // TODO: perhaps introduce different cache because realistically nym-api will receive + // request for the same couple addresses from all nodes in quick succession + let describe_cache = state.describe_nodes_cache_data().await?; + + let mut existence = HashMap::new(); + for address in body.addresses { + existence.insert(address, describe_cache.node_with_address(address)); + } + + Ok(Json(NodesByAddressesResponse { existence })) +} diff --git a/nym-api/src/support/http/state.rs b/nym-api/src/support/http/state.rs index 6bda58cb6c..224db98e53 100644 --- a/nym-api/src/support/http/state.rs +++ b/nym-api/src/support/http/state.rs @@ -3,7 +3,7 @@ use crate::circulating_supply_api::cache::CirculatingSupplyCache; use crate::ecash::state::EcashState; -use crate::network::models::{ChainStatus, NetworkDetails}; +use crate::network::models::NetworkDetails; use crate::node_describe_cache::DescribedNodes; use crate::node_status_api::handlers::unstable; use crate::node_status_api::models::AxumErrorResponse; @@ -15,7 +15,9 @@ use crate::support::caching::Cache; use crate::support::nyxd::Client; use crate::support::storage; use axum::extract::FromRef; -use nym_api_requests::models::{GatewayBondAnnotated, MixNodeBondAnnotated, NodeAnnotation}; +use nym_api_requests::models::{ + DetailedChainStatus, GatewayBondAnnotated, MixNodeBondAnnotated, NodeAnnotation, +}; use nym_mixnet_contract_common::NodeId; use nym_task::TaskManager; use nym_topology::CachedEpochRewardedSet; @@ -151,7 +153,7 @@ impl ChainStatusCache { struct ChainStatusCacheInner { last_refreshed_at: OffsetDateTime, - cache_value: ChainStatus, + cache_value: DetailedChainStatus, } impl ChainStatusCacheInner { @@ -167,7 +169,7 @@ impl ChainStatusCache { pub(crate) async fn get_or_refresh( &self, client: &Client, - ) -> Result { + ) -> Result { if let Some(cached) = self.check_cache().await { return Ok(cached); } @@ -175,7 +177,7 @@ impl ChainStatusCache { self.refresh(client).await } - async fn check_cache(&self) -> Option { + async fn check_cache(&self) -> Option { let guard = self.inner.read().await; let inner = guard.as_ref()?; if inner.is_valid(self.cache_ttl) { @@ -184,7 +186,7 @@ impl ChainStatusCache { None } - async fn refresh(&self, client: &Client) -> Result { + async fn refresh(&self, client: &Client) -> Result { // 1. attempt to get write lock permit let mut guard = self.inner.write().await; @@ -201,7 +203,7 @@ impl ChainStatusCache { .block_info(abci.last_block_height.value() as u32) .await?; - let status = ChainStatus { + let status = DetailedChainStatus { abci: abci.into(), latest_block: block.into(), }; diff --git a/nym-credential-proxy/nym-credential-proxy/Dockerfile b/nym-credential-proxy/nym-credential-proxy/Dockerfile index b6da10f4f5..e0fbc7fc05 100644 --- a/nym-credential-proxy/nym-credential-proxy/Dockerfile +++ b/nym-credential-proxy/nym-credential-proxy/Dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nym-credential-proxy/nym-credential-proxy @@ -24,7 +25,7 @@ RUN cargo build --release # see https://github.com/nymtech/nym/blob/develop/nym-credential-proxy/nym-credential-proxy/src/cli.rs for details #------------------------------------------------------------------- -FROM ubuntu:24.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:24.04 RUN apt update && apt install -yy curl ca-certificates diff --git a/nym-network-monitor.dockerfile b/nym-network-monitor.dockerfile index f25b93156e..22a2ca0c1d 100644 --- a/nym-network-monitor.dockerfile +++ b/nym-network-monitor.dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nym-network-monitor diff --git a/nym-node-status-api/README.md b/nym-node-status-api/README.md new file mode 100644 index 0000000000..03da6ca3cb --- /dev/null +++ b/nym-node-status-api/README.md @@ -0,0 +1,6 @@ +# Nym Node Status API +The Node Status API serves information about individual `nym-nodes` in the Mixnet, such as which role they are operating in, statistics about them, services such as Network Requesters, as well as summaries of the state of the Mixnet. + +We recommend that developers building applications such as explorers or analytics interfaces about the Mixnet run their own instance of the API, in order to promote a robust network of downstream services, and spread the load of API calls amongst as many endpoints as possible. + +You can find build and operation instructions in the [docs](https://nym.com/docs/apis/ns-api). diff --git a/nym-node-status-api/nym-node-status-agent/Cargo.toml b/nym-node-status-api/nym-node-status-agent/Cargo.toml index d9f11f518e..5e01d55df7 100644 --- a/nym-node-status-api/nym-node-status-agent/Cargo.toml +++ b/nym-node-status-api/nym-node-status-agent/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-node-status-agent" -version = "1.0.0-rc.1" +version = "1.0.0-rc.2" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/nym-node-status-api/nym-node-status-agent/Dockerfile b/nym-node-status-api/nym-node-status-agent/Dockerfile index b50ce8be3d..fcab377e26 100644 --- a/nym-node-status-api/nym-node-status-agent/Dockerfile +++ b/nym-node-status-api/nym-node-status-agent/Dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder ARG GIT_REF=main @@ -27,7 +28,7 @@ RUN cargo build --release # see https://github.com/nymtech/nym/blob/develop/nym-node-status-agent/src/cli.rs for details #------------------------------------------------------------------- -FROM ubuntu:24.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:24.04 RUN apt-get update && apt-get install -y ca-certificates @@ -37,4 +38,4 @@ COPY --from=builder /usr/src/nym/target/release/nym-node-status-agent ./ COPY --from=builder /usr/src/nym-vpn-client/nym-vpn-core/target/release/nym-gateway-probe ./ ENV NODE_STATUS_AGENT_PROBE_PATH=/nym/nym-gateway-probe -ENTRYPOINT [ "/nym/nym-node-status-agent", "run-probe" ] \ No newline at end of file +ENTRYPOINT [ "/nym/nym-node-status-agent", "run-probe" ] diff --git a/nym-node-status-api/nym-node-status-agent/run.sh b/nym-node-status-api/nym-node-status-agent/run.sh index f3900ec227..a01e513a1c 100755 --- a/nym-node-status-api/nym-node-status-agent/run.sh +++ b/nym-node-status-api/nym-node-status-agent/run.sh @@ -1,9 +1,9 @@ #!/bin/bash set -eu -export ENVIRONMENT=${ENVIRONMENT:-"sandbox"} +export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} -probe_git_ref="nym-vpn-core-v1.1.0" +probe_git_ref="nym-vpn-core-v1.3.2" crate_root=$(dirname $(realpath "$0")) monorepo_root=$(realpath "${crate_root}/../..") @@ -21,6 +21,7 @@ export NODE_STATUS_AGENT_SERVER_ADDRESS="http://127.0.0.1" export NODE_STATUS_AGENT_SERVER_PORT="8000" export NODE_STATUS_AGENT_PROBE_PATH="$crate_root/nym-gateway-probe" export NODE_STATUS_AGENT_AUTH_KEY="BjyC9SsHAZUzPRkQR4sPTvVrp4GgaquTh5YfSJksvvWT" +export NODE_STATUS_AGENT_PROBE_EXTRA_ARGS="netstack-download-timeout-sec=30,netstack-num-ping=2,netstack-send-timeout-sec=1,netstack-recv-timeout-sec=1" workers=${1:-1} echo "Running $workers workers in parallel" @@ -54,7 +55,7 @@ function swarm() { echo "All agents completed" } -# copy_gw_probe +copy_gw_probe build_agent swarm $workers diff --git a/nym-node-status-api/nym-node-status-agent/src/cli/generate_keypair.rs b/nym-node-status-api/nym-node-status-agent/src/cli/generate_keypair.rs index e8360af47f..f769d3acb0 100644 --- a/nym-node-status-api/nym-node-status-agent/src/cli/generate_keypair.rs +++ b/nym-node-status-api/nym-node-status-agent/src/cli/generate_keypair.rs @@ -10,7 +10,8 @@ pub(crate) fn generate_key_pair(path: impl AsRef) -> anyhow::Result<()> { let mut private_key_file = File::create(priv_key_path)?; private_key_file.write_all(keypair.private_key().to_base58_string().as_bytes())?; - let pub_key_path = priv_key_path.with_extension("public"); + let pub_key_path = priv_key_path.with_file_name("public-key"); + let mut public_key_file = File::create(&pub_key_path)?; public_key_file.write_all(keypair.public_key().to_base58_string().as_bytes())?; diff --git a/nym-node-status-api/nym-node-status-agent/src/cli/mod.rs b/nym-node-status-api/nym-node-status-agent/src/cli/mod.rs index 5b7b7beadb..75601548ed 100644 --- a/nym-node-status-api/nym-node-status-agent/src/cli/mod.rs +++ b/nym-node-status-api/nym-node-status-agent/src/cli/mod.rs @@ -35,6 +35,13 @@ pub(crate) enum Command { /// path of binary to run #[arg(long, env = "NODE_STATUS_AGENT_PROBE_PATH")] probe_path: String, + + #[arg( + long, + env = "NODE_STATUS_AGENT_PROBE_EXTRA_ARGS", + value_delimiter = ',' + )] + probe_extra_args: Vec, }, GenerateKeypair { @@ -51,11 +58,13 @@ impl Args { server_port, ns_api_auth_key, probe_path, + probe_extra_args, } => run_probe::run_probe( server_address, server_port.to_owned(), ns_api_auth_key, probe_path, + probe_extra_args, ) .await .inspect_err(|err| { diff --git a/nym-node-status-api/nym-node-status-agent/src/cli/run_probe.rs b/nym-node-status-api/nym-node-status-agent/src/cli/run_probe.rs index e9b7eaf44a..8cf779cfbc 100644 --- a/nym-node-status-api/nym-node-status-agent/src/cli/run_probe.rs +++ b/nym-node-status-api/nym-node-status-agent/src/cli/run_probe.rs @@ -7,6 +7,7 @@ pub(crate) async fn run_probe( server_port: u16, ns_api_auth_key: &str, probe_path: &str, + probe_extra_args: &Vec, ) -> anyhow::Result<()> { let auth_key = PrivateKey::from_base58_string(ns_api_auth_key) .context("Couldn't parse auth key, exiting")?; @@ -19,7 +20,7 @@ pub(crate) async fn run_probe( tracing::info!("Probe version:\n{}", version); if let Some(testrun) = ns_api_client.request_testrun().await? { - let log = probe.run_and_get_log(&Some(testrun.gateway_identity_key)); + let log = probe.run_and_get_log(&Some(testrun.gateway_identity_key), probe_extra_args); ns_api_client .submit_results(testrun.testrun_id, log, testrun.assigned_at_utc) diff --git a/nym-node-status-api/nym-node-status-agent/src/probe.rs b/nym-node-status-api/nym-node-status-agent/src/probe.rs index f779f3af53..67e7e508c6 100644 --- a/nym-node-status-api/nym-node-status-agent/src/probe.rs +++ b/nym-node-status-api/nym-node-status-agent/src/probe.rs @@ -1,4 +1,4 @@ -use tracing::error; +use tracing::{debug, error, info}; pub(crate) struct GwProbe { path: String, @@ -10,26 +10,71 @@ impl GwProbe { } pub(crate) async fn version(&self) -> String { + debug!("Attempting to execute binary at: {}", &self.path); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + + match tokio::fs::metadata(&self.path).await { + Ok(metadata) => { + let perms = metadata.permissions(); + let mode = perms.mode(); + if mode & 0o111 == 0 { + error!( + "Binary is not executable: {} (mode: {:o})", + &self.path, mode + ); + return "Binary is not executable".to_string(); + } + debug!("Binary exists with permissions: {:o}", mode); + } + Err(e) => { + error!("Failed to stat binary at {}: {}", &self.path, e); + return format!("Failed to access binary: {}", e); + } + } + } + let mut command = tokio::process::Command::new(&self.path); command.stdout(std::process::Stdio::piped()); command.arg("--version"); + info!("Executing command: {:?} --version", &self.path); + match command.spawn() { - Ok(child) => { - if let Ok(output) = child.wait_with_output().await { - return String::from_utf8(output.stdout) - .unwrap_or("Unable to get log from test run".to_string()); + Ok(child) => match child.wait_with_output().await { + Ok(output) => { + if output.status.success() { + String::from_utf8(output.stdout) + .unwrap_or_else(|_| "Unable to parse version output".to_string()) + } else { + let stderr = String::from_utf8(output.stderr) + .unwrap_or_else(|_| "Unable to parse error output".to_string()); + error!( + "Command failed with exit code {}: {}", + output.status.code().unwrap_or(-1), + stderr + ); + format!("Command failed: {}", stderr) + } } - "Unable to get probe version".to_string() - } + Err(e) => { + error!("Failed to get command output: {}", e); + format!("Failed to get command output: {}", e) + } + }, Err(e) => { - error!("Failed to get probe version: {}", e); - "Failed to get probe version".to_string() + error!("Failed to spawn process: {}", e); + format!("Failed to spawn process: {}", e) } } } - pub(crate) fn run_and_get_log(&self, gateway_key: &Option) -> String { + pub(crate) fn run_and_get_log( + &self, + gateway_key: &Option, + probe_extra_args: &Vec, + ) -> String { let mut command = std::process::Command::new(&self.path); command.stdout(std::process::Stdio::piped()); @@ -37,6 +82,16 @@ impl GwProbe { command.arg("--gateway").arg(gateway_id); } + tracing::info!("Extra args for the probe:"); + for arg in probe_extra_args { + let mut split = arg.splitn(2, '='); + let name = split.next().unwrap_or_default(); + let value = split.next().unwrap_or_default(); + tracing::info!("{} {}", name, value); + + command.arg(format!("--{name}")).arg(value); + } + match command.spawn() { Ok(child) => { if let Ok(output) = child.wait_with_output() { diff --git a/nym-node-status-api/nym-node-status-api/Cargo.toml b/nym-node-status-api/nym-node-status-api/Cargo.toml index 1e41d4d41d..f78218e246 100644 --- a/nym-node-status-api/nym-node-status-api/Cargo.toml +++ b/nym-node-status-api/nym-node-status-api/Cargo.toml @@ -16,23 +16,28 @@ rust-version.workspace = true ammonia = { workspace = true } anyhow = { workspace = true } axum = { workspace = true, features = ["tokio", "macros"] } +bip39 = { workspace = true } chrono = { workspace = true } clap = { workspace = true, features = ["cargo", "derive", "env", "string"] } cosmwasm-std = { workspace = true } envy = { workspace = true } futures-util = { workspace = true } +itertools = { workspace = true } moka = { workspace = true, features = ["future"] } nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" } nym-bin-common = { path = "../../common/bin-common", features = ["models"] } nym-node-status-client = { path = "../nym-node-status-client" } nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "serde"] } nym-explorer-client = { path = "../../explorer-api/explorer-client" } +nym-http-api-client = { path = "../../common/http-api-client" } nym-network-defaults = { path = "../../common/network-defaults" } nym-serde-helpers = { path = "../../common/serde-helpers"} nym-statistics-common = { path = "../../common/statistics" } nym-validator-client = { path = "../../common/client-libs/validator-client" } nym-task = { path = "../../common/task" } nym-node-requests = { path = "../../nym-node/nym-node-requests", features = ["openapi"] } +rand = { workspace = true } +rand_chacha = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/nym-node-status-api/nym-node-status-api/Dockerfile b/nym-node-status-api/nym-node-status-api/Dockerfile index 035f186c65..6eeaf8c6ee 100644 --- a/nym-node-status-api/nym-node-status-api/Dockerfile +++ b/nym-node-status-api/nym-node-status-api/Dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nym-node-status-api @@ -26,7 +27,7 @@ RUN cargo build --release # see https://github.com/nymtech/nym/blob/develop/nym-node-status-api/src/cli.rs for details #------------------------------------------------------------------- -FROM ubuntu:24.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:24.04 RUN apt-get update && apt-get install -y ca-certificates diff --git a/nym-node-status-api/nym-node-status-api/Dockerfile.dev b/nym-node-status-api/nym-node-status-api/Dockerfile.dev index 2967a6e605..3811074734 100644 --- a/nym-node-status-api/nym-node-status-api/Dockerfile.dev +++ b/nym-node-status-api/nym-node-status-api/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:22.04 RUN apt-get update && apt-get install -y ca-certificates diff --git a/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh b/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh index eca23c67a8..b8a16eb3ce 100755 --- a/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh +++ b/nym-node-status-api/nym-node-status-api/launch_node_status_api.sh @@ -3,7 +3,7 @@ set -e user_rust_log_preference=$RUST_LOG -export ENVIRONMENT=${ENVIRONMENT:-"sandbox"} +export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} export NYM_API_CLIENT_TIMEOUT=60 export EXPLORER_CLIENT_TIMEOUT=60 export NODE_STATUS_API_TESTRUN_REFRESH_INTERVAL=120 diff --git a/nym-node-status-api/nym-node-status-api/src/cli/mod.rs b/nym-node-status-api/nym-node-status-api/src/cli/mod.rs index 291597bb7c..e9d76a1f75 100644 --- a/nym-node-status-api/nym-node-status-api/src/cli/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/cli/mod.rs @@ -83,9 +83,6 @@ pub(crate) struct Cli { env = "NYM_NODE_STATUS_API_MAX_AGENT_COUNT" )] pub(crate) max_agent_count: i64, - - #[clap(long, default_value = "", env = "NYM_NODE_STATUS_API_HM_URL")] - pub(crate) hm_url: String, } fn parse_duration(arg: &str) -> Result { diff --git a/nym-node-status-api/nym-node-status-api/src/db/models.rs b/nym-node-status-api/nym-node-status-api/src/db/models.rs index deb55a14fd..2bd0931ffa 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/models.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/models.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use crate::{ http::{self, models::SummaryHistory}, - monitor::NumericalCheckedCast, + utils::NumericalCheckedCast, }; use anyhow::Context; use nym_contracts_common::Percent; @@ -16,7 +16,7 @@ use strum_macros::{EnumString, FromRepr}; use time::{Date, OffsetDateTime}; use utoipa::ToSchema; -pub(crate) struct GatewayRecord { +pub(crate) struct GatewayInsertRecord { pub(crate) identity_key: String, pub(crate) bonded: bool, pub(crate) self_described: String, @@ -360,14 +360,24 @@ impl TryFrom for http::models::SessionStats { } } -pub(crate) enum MixingNodeKind { - LegacyMixnode, - NymNode, +pub(crate) enum ScrapeNodeKind { + LegacyMixnode { mix_id: i64 }, + MixingNymNode { node_id: i64 }, + EntryExitNymNode { node_id: i64, identity_key: String }, +} + +impl ScrapeNodeKind { + pub(crate) fn node_id(&self) -> &i64 { + match self { + ScrapeNodeKind::LegacyMixnode { mix_id } => mix_id, + ScrapeNodeKind::MixingNymNode { node_id } => node_id, + ScrapeNodeKind::EntryExitNymNode { node_id, .. } => node_id, + } + } } pub(crate) struct ScraperNodeInfo { - pub node_id: i64, - pub node_kind: MixingNodeKind, + pub node_kind: ScrapeNodeKind, pub hosts: Vec, pub http_api_port: i64, } @@ -390,6 +400,10 @@ impl ScraperNodeInfo { urls } + + pub(crate) fn node_id(&self) -> &i64 { + self.node_kind.node_id() + } } #[derive(sqlx::Decode, Debug)] diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs index 9dc3ddbb11..cf23115ea1 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/gateways.rs @@ -1,6 +1,8 @@ +use std::collections::HashSet; + use crate::{ db::{ - models::{GatewayDto, GatewayRecord}, + models::{GatewayDto, GatewayInsertRecord}, DbPool, }, http::models::Gateway, @@ -30,7 +32,7 @@ pub(crate) async fn select_gateway_identity( pub(crate) async fn insert_gateways( pool: &DbPool, - gateways: Vec, + gateways: Vec, ) -> anyhow::Result<()> { let mut db = pool.acquire().await?; for record in gateways { @@ -98,3 +100,21 @@ pub(crate) async fn get_all_gateways(pool: &DbPool) -> anyhow::Result anyhow::Result> { + let mut conn = pool.acquire().await?; + let items = sqlx::query!( + r#" + SELECT gateway_identity_key + FROM gateways + WHERE bonded = true + "# + ) + .fetch_all(&mut *conn) + .await? + .into_iter() + .map(|record| record.gateway_identity_key) + .collect::>(); + + Ok(items) +} diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs index 09f185d5cd..67cb3d554f 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/mixnodes.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use futures_util::TryStreamExt; use tracing::error; @@ -83,8 +85,7 @@ pub(crate) async fn get_all_mixnodes(pool: &DbPool) -> anyhow::Result anyhow::Result> { +pub(crate) async fn get_daily_stats(pool: &DbPool) -> anyhow::Result> { let mut conn = pool.acquire().await?; let items = sqlx::query_as!( DailyStats, @@ -115,11 +116,8 @@ pub(crate) async fn get_daily_stats(pool: &DbPool, offset: i64) -> anyhow::Resul WHERE nym_node_daily_mixing_stats.node_id IS NULL ) GROUP BY date_utc - ORDER BY date_utc DESC - LIMIT 30 - OFFSET ? + ORDER BY date_utc ASC "#, - offset ) .fetch(&mut *conn) .try_collect::>() @@ -127,3 +125,21 @@ pub(crate) async fn get_daily_stats(pool: &DbPool, offset: i64) -> anyhow::Resul Ok(items) } + +pub(crate) async fn get_all_mix_ids(pool: &DbPool) -> anyhow::Result> { + let mut conn = pool.acquire().await?; + let items = sqlx::query!( + r#" + SELECT mix_id + FROM mixnodes + WHERE bonded = true + "# + ) + .fetch_all(&mut *conn) + .await? + .into_iter() + .map(|record| record.mix_id) + .collect::>(); + + Ok(items) +} diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs index 86b9475e25..4103df77b4 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/mod.rs @@ -8,13 +8,15 @@ pub(crate) mod scraper; mod summary; pub(crate) mod testruns; -pub(crate) use gateways::{get_all_gateways, insert_gateways, select_gateway_identity}; +pub(crate) use gateways::{ + get_all_gateway_id_keys, get_all_gateways, insert_gateways, select_gateway_identity, +}; pub(crate) use gateways_stats::{delete_old_records, get_sessions_stats, insert_session_records}; pub(crate) use misc::insert_summaries; -pub(crate) use mixnodes::{get_all_mixnodes, get_daily_stats, insert_mixnodes}; +pub(crate) use mixnodes::{get_all_mix_ids, get_all_mixnodes, get_daily_stats, insert_mixnodes}; pub(crate) use nym_nodes::{get_nym_nodes, insert_nym_nodes}; pub(crate) use packet_stats::{ get_raw_node_stats, insert_daily_node_stats, insert_node_packet_stats, }; -pub(crate) use scraper::{get_mixing_nodes_for_scraping, insert_scraped_node_description}; +pub(crate) use scraper::{get_nodes_for_scraping, insert_scraped_node_description}; pub(crate) use summary::{get_summary, get_summary_history}; diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs index c7dbf82ca9..fcfbe8d8e3 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/nym_nodes.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use anyhow::Context; use futures_util::TryStreamExt; use nym_validator_client::{client::NymNodeDetails, nym_api::SkimmedNode}; use tracing::instrument; @@ -9,7 +10,7 @@ use crate::{ models::{NymNodeDto, NymNodeInsertRecord}, DbPool, }, - monitor::decimal_to_i64, + utils::decimal_to_i64, }; pub(crate) async fn get_nym_nodes(pool: &DbPool) -> anyhow::Result> { @@ -100,7 +101,8 @@ pub(crate) async fn insert_nym_nodes( record.last_updated_utc, ) .execute(&mut *conn) - .await?; + .await + .with_context(|| format!("node_id={}", record.node_id))?; } Ok(()) diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/packet_stats.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/packet_stats.rs index fd9195ec0c..6041103096 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/packet_stats.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/packet_stats.rs @@ -1,27 +1,26 @@ use crate::db::{ - models::{MixingNodeKind, NodeStats, ScraperNodeInfo}, + models::{NodeStats, ScrapeNodeKind, ScraperNodeInfo}, DbPool, }; use anyhow::Result; pub(crate) async fn insert_node_packet_stats( pool: &DbPool, - node_id: i64, - node_kind: &MixingNodeKind, + node_kind: &ScrapeNodeKind, stats: &NodeStats, timestamp_utc: i64, ) -> Result<()> { let mut conn = pool.acquire().await?; match node_kind { - MixingNodeKind::LegacyMixnode => { + ScrapeNodeKind::LegacyMixnode { mix_id } => { sqlx::query!( r#" INSERT INTO mixnode_packet_stats_raw ( mix_id, timestamp_utc, packets_received, packets_sent, packets_dropped ) VALUES (?, ?, ?, ?, ?) "#, - node_id, + mix_id, timestamp_utc, stats.packets_received, stats.packets_sent, @@ -30,7 +29,8 @@ pub(crate) async fn insert_node_packet_stats( .execute(&mut *conn) .await?; } - MixingNodeKind::NymNode => { + ScrapeNodeKind::MixingNymNode { node_id } + | ScrapeNodeKind::EntryExitNymNode { node_id, .. } => { sqlx::query!( r#" INSERT INTO nym_nodes_packet_stats_raw ( @@ -60,7 +60,7 @@ pub(crate) async fn get_raw_node_stats( let packets = match node.node_kind { // if no packets are found, it's fine to assume 0 because that's also // SQL default value if none provided - MixingNodeKind::LegacyMixnode => { + ScrapeNodeKind::LegacyMixnode { mix_id } => { sqlx::query_as!( NodeStats, r#" @@ -73,12 +73,13 @@ pub(crate) async fn get_raw_node_stats( ORDER BY timestamp_utc DESC LIMIT 1 OFFSET 1 "#, - node.node_id + mix_id ) .fetch_optional(&mut *conn) .await? } - MixingNodeKind::NymNode => { + ScrapeNodeKind::MixingNymNode { node_id } + | ScrapeNodeKind::EntryExitNymNode { node_id, .. } => { sqlx::query_as!( NodeStats, r#" @@ -91,7 +92,7 @@ pub(crate) async fn get_raw_node_stats( ORDER BY timestamp_utc DESC LIMIT 1 OFFSET 1 "#, - node.node_id + node_id ) .fetch_optional(&mut *conn) .await? @@ -110,7 +111,7 @@ pub(crate) async fn insert_daily_node_stats( let mut conn = pool.acquire().await?; match node.node_kind { - MixingNodeKind::LegacyMixnode => { + ScrapeNodeKind::LegacyMixnode { mix_id } => { let total_stake = sqlx::query_scalar!( r#" SELECT @@ -118,7 +119,7 @@ pub(crate) async fn insert_daily_node_stats( FROM mixnodes WHERE mix_id = ? "#, - node.node_id + mix_id ) .fetch_one(&mut *conn) .await?; @@ -136,7 +137,7 @@ pub(crate) async fn insert_daily_node_stats( packets_sent = mixnode_daily_stats.packets_sent + excluded.packets_sent, packets_dropped = mixnode_daily_stats.packets_dropped + excluded.packets_dropped "#, - node.node_id, + mix_id, date_utc, total_stake, packets.packets_received, @@ -146,7 +147,8 @@ pub(crate) async fn insert_daily_node_stats( .execute(&mut *conn) .await?; } - MixingNodeKind::NymNode => { + ScrapeNodeKind::MixingNymNode { node_id } + | ScrapeNodeKind::EntryExitNymNode { node_id, .. } => { let total_stake = sqlx::query_scalar!( r#" SELECT @@ -154,7 +156,7 @@ pub(crate) async fn insert_daily_node_stats( FROM nym_nodes WHERE node_id = ? "#, - node.node_id + node_id ) .fetch_one(&mut *conn) .await?; @@ -167,12 +169,12 @@ pub(crate) async fn insert_daily_node_stats( packets_sent, packets_dropped ) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(node_id, date_utc) DO UPDATE SET - total_stake = nym_node_daily_mixing_stats.total_stake + excluded.total_stake, + total_stake = excluded.total_stake, packets_received = nym_node_daily_mixing_stats.packets_received + excluded.packets_received, packets_sent = nym_node_daily_mixing_stats.packets_sent + excluded.packets_sent, packets_dropped = nym_node_daily_mixing_stats.packets_dropped + excluded.packets_dropped "#, - node.node_id, + node_id, date_utc, total_stake, packets.packets_received, diff --git a/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs b/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs index 2da881964f..52cff30a01 100644 --- a/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs +++ b/nym-node-status-api/nym-node-status-api/src/db/queries/scraper.rs @@ -1,6 +1,6 @@ use crate::{ db::{ - models::{MixingNodeKind, ScraperNodeInfo}, + models::{ScrapeNodeKind, ScraperNodeInfo}, queries, DbPool, }, mixnet_scraper::helpers::NodeDescriptionResponse, @@ -8,16 +8,36 @@ use crate::{ use anyhow::Result; use chrono::Utc; -pub(crate) async fn get_mixing_nodes_for_scraping(pool: &DbPool) -> Result> { +pub(crate) async fn get_nodes_for_scraping(pool: &DbPool) -> Result> { let mut nodes_to_scrape = Vec::new(); + let mixnode_ids = queries::get_all_mix_ids(pool).await?; + let gateway_keys = queries::get_all_gateway_id_keys(pool).await?; + + let mut entry_exit_nodes = 0; queries::get_nym_nodes(pool) .await? .into_iter() .for_each(|node| { + // due to polyfilling, Nym nodes table might contain legacy mixnodes + // as well. Mark them as such here. + let node_kind = if mixnode_ids.contains(&node.node_id.into()) { + ScrapeNodeKind::LegacyMixnode { + mix_id: node.node_id.into(), + } + } else if gateway_keys.contains(&node.ed25519_identity_pubkey.to_base58_string()) { + entry_exit_nodes += 1; + ScrapeNodeKind::EntryExitNymNode { + node_id: node.node_id.into(), + identity_key: node.ed25519_identity_pubkey.to_base58_string(), + } + } else { + ScrapeNodeKind::MixingNymNode { + node_id: node.node_id.into(), + } + }; nodes_to_scrape.push(ScraperNodeInfo { - node_id: node.node_id.into(), - node_kind: MixingNodeKind::NymNode, + node_kind, hosts: node .ip_addresses .into_iter() @@ -27,7 +47,8 @@ pub(crate) async fn get_mixing_nodes_for_scraping(pool: &DbPool) -> Result Result Result Result Result<()> { let timestamp = Utc::now().timestamp(); let mut conn = pool.acquire().await?; match node_kind { - MixingNodeKind::LegacyMixnode => { + ScrapeNodeKind::LegacyMixnode { mix_id } => { sqlx::query!( r#" INSERT INTO mixnode_description ( @@ -110,7 +124,7 @@ pub(crate) async fn insert_scraped_node_description( details = excluded.details, last_updated_utc = excluded.last_updated_utc "#, - node_id, + mix_id, description.moniker, description.website, description.security_contact, @@ -120,7 +134,7 @@ pub(crate) async fn insert_scraped_node_description( .execute(&mut *conn) .await?; } - MixingNodeKind::NymNode => { + ScrapeNodeKind::MixingNymNode { node_id } => { sqlx::query!( r#" INSERT INTO nym_node_descriptions ( @@ -143,6 +157,34 @@ pub(crate) async fn insert_scraped_node_description( .execute(&mut *conn) .await?; } + ScrapeNodeKind::EntryExitNymNode { identity_key, .. } => { + sqlx::query!( + r#" + INSERT INTO gateway_description ( + gateway_identity_key, + moniker, + website, + security_contact, + details, + last_updated_utc + ) VALUES (?, ?, ?, ?, ?, ?) + ON CONFLICT (gateway_identity_key) DO UPDATE SET + moniker = excluded.moniker, + website = excluded.website, + security_contact = excluded.security_contact, + details = excluded.details, + last_updated_utc = excluded.last_updated_utc + "#, + identity_key, + description.moniker, + description.website, + description.security_contact, + description.details, + timestamp, + ) + .execute(&mut *conn) + .await?; + } } Ok(()) diff --git a/nym-node-status-api/nym-node-status-api/src/http/api/mixnodes.rs b/nym-node-status-api/nym-node-status-api/src/http/api/mixnodes.rs index 096c9fa27a..cbcfe1fb85 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/api/mixnodes.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/api/mixnodes.rs @@ -99,7 +99,10 @@ async fn get_stats( Query(MixStatsQueryParams { offset }): Query, State(state): State, ) -> HttpResult>> { - let offset = offset.unwrap_or(0); + let offset: usize = offset + .unwrap_or(0) + .try_into() + .map_err(|_| HttpError::invalid_input("Offset must be non-negative"))?; let last_30_days = state .cache() .get_mixnode_stats(state.db_pool(), offset) diff --git a/nym-node-status-api/nym-node-status-api/src/http/server.rs b/nym-node-status-api/nym-node-status-api/src/http/server.rs index b0613ca1c1..3c43c5efea 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/server.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/server.rs @@ -17,18 +17,10 @@ pub(crate) async fn start_http_api( nym_http_cache_ttl: u64, agent_key_list: Vec, agent_max_count: i64, - hm_url: String, ) -> anyhow::Result { let router_builder = RouterBuilder::with_default_routes(); - let state = AppState::new( - db_pool, - nym_http_cache_ttl, - agent_key_list, - agent_max_count, - hm_url, - ) - .await; + let state = AppState::new(db_pool, nym_http_cache_ttl, agent_key_list, agent_max_count).await; let router = router_builder.with_state(state); let bind_addr = format!("0.0.0.0:{}", http_port); diff --git a/nym-node-status-api/nym-node-status-api/src/http/state.rs b/nym-node-status-api/nym-node-status-api/src/http/state.rs index a8a41fc73f..f1aea18cb8 100644 --- a/nym-node-status-api/nym-node-status-api/src/http/state.rs +++ b/nym-node-status-api/nym-node-status-api/src/http/state.rs @@ -25,11 +25,10 @@ impl AppState { cache_ttl: u64, agent_key_list: Vec, agent_max_count: i64, - hm_url: String, ) -> Self { Self { db_pool, - cache: HttpCache::new(cache_ttl, hm_url).await, + cache: HttpCache::new(cache_ttl).await, agent_key_list, agent_max_count, } @@ -52,96 +51,14 @@ impl AppState { } } -#[derive(Debug, Clone)] -struct HistoricMixingStats { - historic_stats: Vec, -} - -impl HistoricMixingStats { - /// Collect historic stats only on initialization. From this point onwards, - /// service will collect its own stats - async fn init(hm_url: String) -> Self { - tracing::info!("Fetching historic mixnode stats from {}", hm_url); - - let target_url = format!("{}/v2/mixnodes/stats", hm_url); - if let Ok(response) = reqwest::get(&target_url) - .await - .and_then(|res| res.error_for_status()) - .inspect_err(|err| tracing::error!("Failed to fetch cache from HM: {}", err)) - { - if let Ok(mut daily_stats) = response.json::>().await { - // sorting required for seamless comparison later (descending, newest first) - daily_stats.sort_by(|left, right| right.date_utc.cmp(&left.date_utc)); - - tracing::info!( - "Successfully fetched {} historic entries from {}", - daily_stats.len(), - hm_url - ); - return Self { - historic_stats: daily_stats, - }; - } - }; - - tracing::warn!("Failed to get historic daily stats from {}", hm_url); - Self { - historic_stats: Vec::new(), - } - } - - /// polyfill with historical data obtained from Harbour Master - fn merge_with_historic_stats(&self, mut new_stats: Vec) -> Vec { - // newest first - new_stats.sort_by(|left, right| right.date_utc.cmp(&left.date_utc)); - - // historic stats are only used for dates when we don't have new data - let oldest_date_in_new_stats = new_stats - .last() - .map(|day| day.date_utc.to_owned()) - .unwrap_or(String::from("1900-01-01")); - - // given 2 arrays - // index historic_stats new_stats - // 0 30-01 31-01 - // 1 29-01 30-01 - // 2 28-01 - // ... - // N 01-01 - // cutoff point would be at historic_stats[1] - // (first date smaller than oldest we've already got) - if let Some(cutoff) = self - .historic_stats - .iter() - .position(|elem| elem.date_utc < oldest_date_in_new_stats) - { - // missing data = (all historic data) - (however many days we already have) - let missing_data = self.historic_stats.iter().skip(cutoff).cloned(); - - // extend new data with missing days - tracing::debug!( - "Polyfilled with {} historic records from {:?} to {:?}", - missing_data.len(), - self.historic_stats.last(), - self.historic_stats.get(cutoff) - ); - new_stats.extend(missing_data); - - // oldest first - new_stats.into_iter().rev().collect::>() - } else { - // if all historic data is older than what we've got, don't use it - new_stats - } - } -} - static GATEWAYS_LIST_KEY: &str = "gateways"; static MIXNODES_LIST_KEY: &str = "mixnodes"; static MIXSTATS_LIST_KEY: &str = "mixstats"; static SUMMARY_HISTORY_LIST_KEY: &str = "summary-history"; static SESSION_STATS_LIST_KEY: &str = "session-stats"; +const MIXNODE_STATS_HISTORY_DAYS: usize = 30; + #[derive(Debug, Clone)] pub(crate) struct HttpCache { gateways: Cache>>>, @@ -149,11 +66,10 @@ pub(crate) struct HttpCache { mixstats: Cache>>>, history: Cache>>>, session_stats: Cache>>>, - mixnode_historic_daily_stats: HistoricMixingStats, } impl HttpCache { - pub async fn new(ttl_seconds: u64, hm_url: String) -> Self { + pub async fn new(ttl_seconds: u64) -> Self { HttpCache { gateways: Cache::builder() .max_capacity(2) @@ -175,7 +91,6 @@ impl HttpCache { .max_capacity(2) .time_to_live(Duration::from_secs(ttl_seconds)) .build(), - mixnode_historic_daily_stats: HistoricMixingStats::init(hm_url).await, } } @@ -285,26 +200,27 @@ impl HttpCache { .await } - pub async fn get_mixnode_stats(&self, db: &DbPool, offset: i64) -> Vec { - match self.mixstats.get(MIXSTATS_LIST_KEY).await { + pub async fn get_mixnode_stats(&self, db: &DbPool, offset: usize) -> Vec { + let mut stats = match self.mixstats.get(MIXSTATS_LIST_KEY).await { Some(guard) => { let read_lock = guard.read().await; read_lock.to_vec() } None => { - let new_node_stats = crate::db::queries::get_daily_stats(db, offset) + let new_node_stats = crate::db::queries::get_daily_stats(db) .await - .unwrap_or_default(); - // for every day that's missing, fill it with cached historic data - let mut mixnode_stats = self - .mixnode_historic_daily_stats - .merge_with_historic_stats(new_node_stats); - mixnode_stats.truncate(30); - - self.upsert_mixnode_stats(mixnode_stats.clone()).await; - mixnode_stats + .unwrap_or_default() + .into_iter() + .rev() + .collect::>(); + // cache result without offset + self.upsert_mixnode_stats(new_node_stats.clone()).await; + new_node_stats } - } + }; + + stats.truncate(MIXNODE_STATS_HISTORY_DAYS + offset); + stats.into_iter().skip(offset).rev().collect() } pub async fn get_summary_history(&self, db: &DbPool) -> Vec { diff --git a/nym-node-status-api/nym-node-status-api/src/logging.rs b/nym-node-status-api/nym-node-status-api/src/logging.rs index 8d94549885..bf3960e27b 100644 --- a/nym-node-status-api/nym-node-status-api/src/logging.rs +++ b/nym-node-status-api/nym-node-status-api/src/logging.rs @@ -34,6 +34,8 @@ pub(crate) fn setup_tracing_logger() -> anyhow::Result<()> { "tower_http", "axum", "html5ever", + "hickory_proto", + "hickory_resolver", ]; for crate_name in warn_crates { filter = filter.add_directive(directive_checked(format!("{}=warn", crate_name))?); diff --git a/nym-node-status-api/nym-node-status-api/src/main.rs b/nym-node-status-api/nym-node-status-api/src/main.rs index 0cde5a440f..122a3b713f 100644 --- a/nym-node-status-api/nym-node-status-api/src/main.rs +++ b/nym-node-status-api/nym-node-status-api/src/main.rs @@ -10,6 +10,7 @@ mod mixnet_scraper; mod monitor; mod node_scraper; mod testruns; +mod utils; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -66,7 +67,6 @@ async fn main() -> anyhow::Result<()> { args.nym_http_cache_ttl, agent_key_list.to_owned(), args.max_agent_count, - args.hm_url, ) .await .expect("Failed to start server"); diff --git a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs index 6190978268..dfce27ad51 100644 --- a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs +++ b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/helpers.rs @@ -1,12 +1,15 @@ -use crate::db::{ - models::{NodeStats, ScraperNodeInfo}, - queries::{ - get_raw_node_stats, insert_daily_node_stats, insert_node_packet_stats, - insert_scraped_node_description, +use crate::{ + db::{ + models::{NodeStats, ScraperNodeInfo}, + queries::{ + get_raw_node_stats, insert_daily_node_stats, insert_node_packet_stats, + insert_scraped_node_description, + }, }, + utils::generate_node_name, }; use ammonia::Builder; -use anyhow::Result; +use anyhow::{anyhow, Result}; use chrono::{DateTime, Datelike, Utc}; use reqwest; use serde::{Deserialize, Serialize}; @@ -80,22 +83,33 @@ pub fn build_client() -> Result { .map_err(|e| anyhow::anyhow!("Failed to build HTTP client: {}", e)) } -pub fn sanitize_description(description: NodeDescriptionResponse) -> NodeDescriptionResponse { +pub fn sanitize_description( + description: NodeDescriptionResponse, + node_id: i64, +) -> NodeDescriptionResponse { let mut sanitizer = Builder::new(); sanitizer .tags(std::collections::HashSet::new()) .generic_attributes(std::collections::HashSet::new()) .url_schemes(std::collections::HashSet::new()); + const UNKNOWN: &str = "N/A"; let sanitize_field = |opt: Option| -> Option { Some( opt.filter(|s| !s.trim().is_empty()) - .map_or_else(|| "N/A".to_string(), |s| sanitizer.clean(&s).to_string()), + .map_or_else(|| UNKNOWN.to_string(), |s| sanitizer.clean(&s).to_string()), ) }; + let mut moniker = sanitize_field(description.moniker); + if let Some(sanitized) = &moniker { + if sanitized == UNKNOWN { + moniker = Some(generate_node_name(node_id)); + } + }; + NodeDescriptionResponse { - moniker: sanitize_field(description.moniker), + moniker, website: sanitize_field(description.website), security_contact: sanitize_field(description.security_contact), details: sanitize_field(description.details), @@ -108,18 +122,26 @@ pub async fn scrape_and_store_description(pool: &SqlitePool, node: &ScraperNodeI let mut description = None; let mut error = None; + let mut tried_url_list = Vec::new(); for mut url in urls { url = format!("{}{}", url.trim_end_matches('/'), DESCRIPTION_URL); + tried_url_list.push(url.clone()); - match client.get(&url).send().await { + match client + .get(&url) + .send() + .await + // convert 404 and similar to error + .and_then(|res| res.error_for_status()) + { Ok(response) => { if let Ok(desc) = response.json::().await { description = Some(desc); break; } } - Err(e) => error = Some(e), + Err(e) => error = Some(anyhow!("{:?} ({})", tried_url_list, e)), } } @@ -128,9 +150,8 @@ pub async fn scrape_and_store_description(pool: &SqlitePool, node: &ScraperNodeI anyhow::anyhow!("Failed to fetch description from any URL: {}", err_msg) })?; - let sanitized_description = sanitize_description(description); - insert_scraped_node_description(pool, &node.node_kind, node.node_id, &sanitized_description) - .await?; + let sanitized_description = sanitize_description(description, *node.node_id()); + insert_scraped_node_description(pool, &node.node_kind, &sanitized_description).await?; Ok(()) } @@ -144,9 +165,11 @@ pub async fn scrape_and_store_packet_stats( let mut stats = None; let mut error = None; + let mut tried_url_list = Vec::new(); for mut url in urls { url = format!("{}{}", url.trim_end_matches('/'), PACKET_STATS_URL); + tried_url_list.push(url.clone()); match client.get(&url).send().await { Ok(response) => { @@ -155,18 +178,18 @@ pub async fn scrape_and_store_packet_stats( break; } } - Err(e) => error = Some(e), + Err(e) => error = Some(anyhow!("{:?} ({})", tried_url_list, e)), } } let stats = stats.ok_or_else(|| { let err_msg = error.map_or_else(|| "Unknown error".to_string(), |e| e.to_string()); - anyhow::anyhow!("Failed to fetch stats from any URL: {}", err_msg) + anyhow::anyhow!("Failed to fetch description from any URL: {}", err_msg) })?; let timestamp = Utc::now(); let timestamp_utc = timestamp.timestamp(); - insert_node_packet_stats(pool, node.node_id, &node.node_kind, &stats, timestamp_utc).await?; + insert_node_packet_stats(pool, &node.node_kind, &stats, timestamp_utc).await?; // Update daily stats update_daily_stats(pool, node, timestamp, &stats).await?; diff --git a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs index 73169c2804..983775eec9 100644 --- a/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/mixnet_scraper/mod.rs @@ -8,7 +8,7 @@ use sqlx::SqlitePool; use tracing::{debug, error, instrument, warn}; use crate::db::models::ScraperNodeInfo; -use crate::db::queries::get_mixing_nodes_for_scraping; +use crate::db::queries::get_nodes_for_scraping; const DESCRIPTION_SCRAPE_INTERVAL: Duration = Duration::from_secs(60 * 60 * 4); const PACKET_SCRAPE_INTERVAL: Duration = Duration::from_secs(60 * 60); @@ -74,7 +74,7 @@ impl Scraper { pool: &SqlitePool, queue: Arc>>, ) -> Result<()> { - let nodes = get_mixing_nodes_for_scraping(pool).await?; + let nodes = get_nodes_for_scraping(pool).await?; if let Ok(mut queue_lock) = queue.lock() { queue_lock.extend(nodes); } else { @@ -82,7 +82,7 @@ impl Scraper { return Ok(()); } - Self::process_description_queue(pool, queue).await?; + Self::process_description_queue(pool, queue).await; Ok(()) } @@ -91,7 +91,7 @@ impl Scraper { pool: &SqlitePool, queue: Arc>>, ) -> Result<()> { - let nodes = get_mixing_nodes_for_scraping(pool).await?; + let nodes = get_nodes_for_scraping(pool).await?; tracing::info!("Querying {} mixing nodes", nodes.len()); if let Ok(mut queue_lock) = queue.lock() { queue_lock.extend(nodes); @@ -100,14 +100,11 @@ impl Scraper { return Ok(()); } - Self::process_packet_queue(pool, queue).await?; + Self::process_packet_queue(pool, queue).await; Ok(()) } - async fn process_description_queue( - pool: &SqlitePool, - queue: Arc>>, - ) -> Result<()> { + async fn process_description_queue(pool: &SqlitePool, queue: Arc>>) { loop { let running_tasks = TASK_COUNTER.load(Ordering::Relaxed); @@ -132,12 +129,15 @@ impl Scraper { tokio::spawn(async move { match scrape_and_store_description(&pool, &node).await { Ok(_) => debug!( - "✅ Description task #{} for node {} complete", - task_id, node.node_id + "📝 ✅ Description task #{} for node {} complete", + task_id, + node.node_id() ), Err(e) => debug!( - "❌ Description task #{} for node {} failed: {}", - task_id, node.node_id, e + "📝 ❌ Description task #{} for node {} failed: {}", + task_id, + node.node_id(), + e ), } TASK_COUNTER.fetch_sub(1, Ordering::Relaxed); @@ -146,13 +146,9 @@ impl Scraper { tokio::time::sleep(QUEUE_CHECK_INTERVAL).await; } } - Ok(()) } - async fn process_packet_queue( - pool: &SqlitePool, - queue: Arc>>, - ) -> Result<()> { + async fn process_packet_queue(pool: &SqlitePool, queue: Arc>>) { loop { let running_tasks = TASK_COUNTER.load(Ordering::Relaxed); @@ -177,12 +173,15 @@ impl Scraper { tokio::spawn(async move { match scrape_and_store_packet_stats(&pool, &node).await { Ok(_) => debug!( - "✅ Packet stats task #{} for node {} complete", - task_id, node.node_id + "📊 ✅ Packet stats task #{} for node {} complete", + task_id, + node.node_id() ), Err(e) => debug!( - "❌ Packet stats task #{} for node {} failed: {}", - task_id, node.node_id, e + "📊 ❌ Packet stats task #{} for node {} failed: {}", + task_id, + node.node_id(), + e ), } TASK_COUNTER.fetch_sub(1, Ordering::Relaxed); @@ -191,6 +190,5 @@ impl Scraper { tokio::time::sleep(QUEUE_CHECK_INTERVAL).await; } } - Ok(()) } } diff --git a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs index afb77ed8d7..81711d7640 100644 --- a/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/monitor/mod.rs @@ -1,14 +1,14 @@ #![allow(deprecated)] use crate::db::models::{ - gateway, mixnode, GatewayRecord, MixnodeRecord, NetworkSummary, ASSIGNED_ENTRY_COUNT, + gateway, mixnode, GatewayInsertRecord, MixnodeRecord, NetworkSummary, ASSIGNED_ENTRY_COUNT, ASSIGNED_EXIT_COUNT, ASSIGNED_MIXING_COUNT, GATEWAYS_BONDED_COUNT, GATEWAYS_HISTORICAL_COUNT, MIXNODES_HISTORICAL_COUNT, MIXNODES_LEGACY_COUNT, NYMNODES_DESCRIBED_COUNT, NYMNODE_COUNT, }; use crate::db::{queries, DbPool}; use crate::monitor::geodata::{Location, NodeGeoData}; +use crate::utils::{decimal_to_i64, LogError, NumericalCheckedCast}; use anyhow::anyhow; -use cosmwasm_std::Decimal; use moka::future::Cache; use nym_network_defaults::NymNetworkDetails; use nym_validator_client::client::{NodeId, NymApiClientExt}; @@ -29,7 +29,6 @@ pub(crate) use geodata::IpInfoClient; mod geodata; -// TODO dz should be configurable const FAILURE_RETRY_DELAY: Duration = Duration::from_secs(60); static DELEGATION_PROGRAM_WALLET: &str = "n1rnxpdpx3kldygsklfft0gech7fhfcux4zst5lw"; @@ -98,8 +97,12 @@ impl Monitor { .clone() .expect("rust sdk mainnet default missing api_url"); - let api_client = - NymApiClient::new_with_timeout(default_api_url, self.nym_api_client_timeout); + let nym_api = nym_http_api_client::ClientBuilder::new_with_url(default_api_url) + .no_hickory_dns() + .with_timeout(self.nym_api_client_timeout) + .build::<&str>()?; + + let api_client = NymApiClient { nym_api }; let described_nodes = api_client .get_all_described_nodes() @@ -109,7 +112,11 @@ impl Monitor { let gateways = described_nodes .iter() - .filter(|node| node.description.declared_role.entry) + .filter(|node| { + node.description.declared_role.entry + || node.description.declared_role.exit_ipr + || node.description.declared_role.exit_nr + }) .collect::>(); let bonded_node_info = api_client @@ -120,12 +127,18 @@ impl Monitor { // for faster reads .collect::>(); + tracing::info!("🟣 bonded_nodes: {}", bonded_node_info.len()); + let nym_nodes = api_client .get_all_basic_nodes() .await .log_error("get_all_basic_nodes")?; - queries::insert_nym_nodes(&self.db_pool, nym_nodes.clone(), &bonded_node_info).await?; + queries::insert_nym_nodes(&self.db_pool, nym_nodes.clone(), &bonded_node_info) + .await + .map(|_| { + tracing::debug!("{} nym nodes written to DB!", nym_nodes.len()); + })?; let mut gateway_geodata = Vec::new(); for gateway in gateways.iter() { @@ -198,10 +211,11 @@ impl Monitor { let gateway_records = self.prepare_gateway_data(&gateways, gateway_geodata, &nym_nodes)?; let pool = self.db_pool.clone(); + let gateways_count = gateway_records.len(); queries::insert_gateways(&pool, gateway_records) .await .map(|_| { - tracing::debug!("Gateway info written to DB!"); + tracing::debug!("{} gateway records written to DB!", gateways_count); })?; let mixnode_records = self.prepare_mixnode_data( @@ -209,10 +223,11 @@ impl Monitor { mixnodes_described, delegation_program_members, )?; + let mixnodes_count = mixnode_records.len(); queries::insert_mixnodes(&pool, mixnode_records) .await .map(|_| { - tracing::debug!("Mixnode info written to DB!"); + tracing::debug!("{} mixnode info written to DB!", mixnodes_count); })?; let (all_historical_gateways, all_historical_mixnodes) = calculate_stats(&pool).await?; @@ -285,9 +300,14 @@ impl Monitor { Some(location) => return location, None => { for ip in node.description.host_information.ip_address.iter() { - if let Ok(location) = self.ipinfo.locate_ip(ip.to_string()).await { - self.geocache.insert(node_id, location.clone()).await; - return location; + match self.ipinfo.locate_ip(ip.to_string()).await { + Ok(location) => { + self.geocache.insert(node_id, location.clone()).await; + return location; + } + Err(err) => { + tracing::warn!("Couldn't locate IP {} due to: {}", ip, err) + } } } // if no data could be retrieved @@ -299,13 +319,13 @@ impl Monitor { fn prepare_gateway_data( &self, - gateways: &[&NymNodeDescription], + described_gateways: &[&NymNodeDescription], gateway_geodata: Vec, skimmed_gateways: &[SkimmedNode], - ) -> anyhow::Result> { + ) -> anyhow::Result> { let mut gateway_records = Vec::new(); - for gateway in gateways { + for gateway in described_gateways { let identity_key = gateway.ed25519_identity_key().to_base58_string(); let bonded = true; let last_updated_utc = chrono::offset::Utc::now().timestamp(); @@ -329,7 +349,7 @@ impl Monitor { .unwrap_or_default() .round_to_integer(); - gateway_records.push(GatewayRecord { + gateway_records.push(GatewayInsertRecord { identity_key: identity_key.to_owned(), bonded, self_described, @@ -400,33 +420,6 @@ impl Monitor { } } -// TODO dz is there a common monorepo place this can be put? -pub trait NumericalCheckedCast -where - T: TryFrom, - >::Error: std::error::Error, - Self: std::fmt::Display + Copy, -{ - fn cast_checked(self) -> anyhow::Result { - T::try_from(self).map_err(|e| { - anyhow::anyhow!( - "Couldn't cast {} to {}: {}", - self, - std::any::type_name::(), - e - ) - }) - } -} - -impl NumericalCheckedCast for T -where - U: TryFrom, - >::Error: std::error::Error, - T: std::fmt::Display + Copy, -{ -} - async fn calculate_stats(pool: &DbPool) -> anyhow::Result<(usize, usize)> { let mut conn = pool.acquire().await?; @@ -464,39 +457,3 @@ async fn get_delegation_program_details( Ok(mix_ids) } - -pub(crate) fn decimal_to_i64(decimal: Decimal) -> i64 { - // Convert the underlying Uint128 to a u128 - let atomics = decimal.atomics().u128(); - let precision = 1_000_000_000_000_000_000u128; - - // Get the fractional part - let fractional = atomics % precision; - - // Get the integer part - let integer = atomics / precision; - - // Combine them into a float - let float_value = integer as f64 + (fractional as f64 / 1_000_000_000_000_000_000_f64); - - // Limit to 6 decimal places - let rounded_value = (float_value * 1_000_000.0).round() / 1_000_000.0; - - rounded_value as i64 -} - -trait LogError { - fn log_error(self, msg: &str) -> Result; -} - -impl LogError for anyhow::Result -where - E: std::error::Error, -{ - fn log_error(self, msg: &str) -> Result { - if let Err(e) = &self { - tracing::error!("[{msg}]:\t{e}"); - } - self - } -} diff --git a/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs b/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs index 76f68a6549..f294b47b0f 100644 --- a/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs +++ b/nym-node-status-api/nym-node-status-api/src/node_scraper/mod.rs @@ -17,15 +17,14 @@ use tracing::instrument; mod error; const FAILURE_RETRY_DELAY: Duration = Duration::from_secs(60); -const REFRESH_INTERVAL: Duration = Duration::from_secs(60 * 60 * 6); //6h, data only update once a day +const REFRESH_INTERVAL: Duration = Duration::from_secs(60 * 60 * 6); const STALE_DURATION: Duration = Duration::from_secs(86400 * 365); //one year -#[instrument(level = "debug", name = "node_scraper", skip_all)] +#[instrument(level = "info", name = "metrics_scraper", skip_all)] pub(crate) async fn spawn_in_background(db_pool: DbPool, nym_api_client_timeout: Duration) { let network_defaults = nym_network_defaults::NymNetworkDetails::new_from_env(); loop { - //No graceful shutdown? tracing::info!("Refreshing node self-described metrics..."); if let Err(e) = run(&db_pool, &network_defaults, nym_api_client_timeout).await { @@ -58,7 +57,12 @@ async fn run( .clone() .expect("rust sdk mainnet default missing api_url"); - let api_client = NymApiClient::new_with_timeout(default_api_url, nym_api_client_timeout); + let nym_api = nym_http_api_client::ClientBuilder::new_with_url(default_api_url) + .no_hickory_dns() + .with_timeout(nym_api_client_timeout) + .build::<&str>()?; + + let api_client = NymApiClient { nym_api }; //SW TBC what nodes exactly need to be scraped, the skimmed node endpoint seems to return more nodes let bonded_nodes = api_client.get_all_bonded_nym_nodes().await?; @@ -123,7 +127,7 @@ impl MetricsScrapingData { } } - #[instrument(level = "debug", name = "metrics_scraper", skip_all)] + #[instrument(level = "info", name = "metrics_scraper", skip_all)] async fn try_scrape_metrics(&self) -> Option { match self.try_get_client().await { Ok(client) => { @@ -171,6 +175,7 @@ impl MetricsScrapingData { let client = match nym_node_requests::api::Client::builder(address).and_then(|b| { b.with_timeout(Duration::from_secs(5)) .with_user_agent("node-status-api-metrics-scraper") + .no_hickory_dns() .build() }) { Ok(client) => client, diff --git a/nym-node-status-api/nym-node-status-api/src/utils.rs b/nym-node-status-api/nym-node-status-api/src/utils.rs new file mode 100644 index 0000000000..f315cee744 --- /dev/null +++ b/nym-node-status-api/nym-node-status-api/src/utils.rs @@ -0,0 +1,104 @@ +use cosmwasm_std::Decimal; +use itertools::Itertools; +use rand::prelude::SliceRandom; +use rand::SeedableRng; + +// pub(crate) fn generate_node_name(identity: ed25519::PublicKey) -> String { +pub(crate) fn generate_node_name(node_id: i64) -> String { + let seed = { + let node_id_bytes = node_id.to_le_bytes(); + let mut seed = [0u8; 32]; + for i in 0..4 { + seed[i * 8..(i + 1) * 8].copy_from_slice(&node_id_bytes); + } + seed + }; + let mut rng = rand_chacha::ChaCha20Rng::from_seed(seed); + let words = bip39::Language::English.word_list(); + words.choose_multiple(&mut rng, 3).join(" ") +} + +#[allow(clippy::items_after_test_module)] +#[cfg(test)] +mod test { + use rand::Rng; + + use super::*; + + #[test] + fn generate_node_name_should_be_deterministic() { + let mut rng = rand::thread_rng(); + + let node_id: i64 = rng.gen(); + let different_node_id: i64 = rng.gen(); + + let node_name = generate_node_name(node_id); + let node_name_different = generate_node_name(different_node_id); + assert_ne!(node_name, node_name_different); + + let node_name_same = generate_node_name(node_id); + assert_eq!(node_name, node_name_same); + } +} + +pub trait NumericalCheckedCast +where + T: TryFrom, + >::Error: std::error::Error, + Self: std::fmt::Display + Copy, +{ + fn cast_checked(self) -> anyhow::Result { + T::try_from(self).map_err(|e| { + anyhow::anyhow!( + "Couldn't cast {} to {}: {}", + self, + std::any::type_name::(), + e + ) + }) + } +} + +impl NumericalCheckedCast for T +where + U: TryFrom, + >::Error: std::error::Error, + T: std::fmt::Display + Copy, +{ +} + +pub(crate) fn decimal_to_i64(decimal: Decimal) -> i64 { + // Convert the underlying Uint128 to a u128 + let atomics = decimal.atomics().u128(); + let precision = 1_000_000_000_000_000_000u128; + + // Get the fractional part + let fractional = atomics % precision; + + // Get the integer part + let integer = atomics / precision; + + // Combine them into a float + let float_value = integer as f64 + (fractional as f64 / 1_000_000_000_000_000_000_f64); + + // Limit to 6 decimal places + let rounded_value = (float_value * 1_000_000.0).round() / 1_000_000.0; + + rounded_value as i64 +} + +pub(crate) trait LogError { + fn log_error(self, msg: &str) -> Result; +} + +impl LogError for anyhow::Result +where + E: std::error::Error, +{ + fn log_error(self, msg: &str) -> Result { + if let Err(e) = &self { + tracing::error!("[{msg}]:\t{e}"); + } + self + } +} diff --git a/nym-node/Cargo.toml b/nym-node/Cargo.toml index 0cf816ba5b..45f65f3b8d 100644 --- a/nym-node/Cargo.toml +++ b/nym-node/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nym-node" -version = "1.6.2" +version = "1.7.0" authors.workspace = true repository.workspace = true homepage.workspace = true @@ -71,7 +71,7 @@ nym-verloc = { path = "../common/verloc" } nym-metrics = { path = "../common/nym-metrics" } nym-gateway-stats-storage = { path = "../common/gateway-stats-storage" } nym-topology = { path = "../common/topology" } - +nym-http-api-client = { path = "../common/http-api-client" } # http server # useful for `#[axum_macros::debug_handler]` diff --git a/nym-node/Dockerfile b/nym-node/Dockerfile index 53faa4ce3f..d7ef3012f2 100644 --- a/nym-node/Dockerfile +++ b/nym-node/Dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nym-node @@ -65,7 +66,7 @@ RUN cargo build --release # see https://github.com/nymtech/nym/blob/develop/nym-node/src/env.rs for details #------------------------------------------------------------------- -FROM ubuntu:24.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:24.04 WORKDIR /nym diff --git a/nym-node/nym-node-metrics/src/mixnet.rs b/nym-node/nym-node-metrics/src/mixnet.rs index f4b9da4722..baece8e17f 100644 --- a/nym-node/nym-node-metrics/src/mixnet.rs +++ b/nym-node/nym-node-metrics/src/mixnet.rs @@ -63,7 +63,6 @@ impl MixingStats { .or_default() .forward_packets .received += 1; - *self.ingress.received_versions.entry(version).or_default() += 1; } diff --git a/nym-node/nym-node-metrics/src/network.rs b/nym-node/nym-node-metrics/src/network.rs index 7de912fc3c..ea2b41ff52 100644 --- a/nym-node/nym-node-metrics/src/network.rs +++ b/nym-node/nym-node-metrics/src/network.rs @@ -45,7 +45,7 @@ impl NetworkStats { pub fn active_ingress_websocket_connections_count(&self) -> usize { self.active_ingress_websocket_connections - .load(Ordering::Relaxed) + .load(Ordering::SeqCst) } pub fn active_egress_mixnet_connections_counter(&self) -> Arc { diff --git a/nym-node/src/cli/commands/run/mod.rs b/nym-node/src/cli/commands/run/mod.rs index 9dfd1061f0..8b568150ed 100644 --- a/nym-node/src/cli/commands/run/mod.rs +++ b/nym-node/src/cli/commands/run/mod.rs @@ -4,8 +4,8 @@ use crate::config::upgrade_helpers::try_load_current_config; use crate::error::NymNodeError; use crate::node::bonding_information::BondingInformation; +use crate::node::mixnet::packet_forwarding::global::is_global_ip; use crate::node::NymNode; -use nym_config::helpers::SPECIAL_ADDRESSES; use std::fs; use std::net::IpAddr; use tracing::{debug, info, trace, warn}; @@ -17,7 +17,7 @@ pub(crate) use args::Args; fn check_public_ips(ips: &[IpAddr], local: bool) -> Result<(), NymNodeError> { let mut suspicious_ip = Vec::new(); for ip in ips { - if SPECIAL_ADDRESSES.contains(ip) { + if !is_global_ip(ip) { if !local { return Err(NymNodeError::InvalidPublicIp { address: *ip }); } @@ -92,6 +92,11 @@ pub(crate) async fn execute(mut args: Args) -> Result<(), NymNodeError> { } check_public_ips(&config.host.public_ips, local)?; + let mut config = config; + if local { + config.debug.testnet = true + } + let nym_node = NymNode::new(config) .await? .with_accepted_operator_terms_and_conditions(accepted_operator_terms_and_conditions); diff --git a/nym-node/src/config/gateway_tasks.rs b/nym-node/src/config/gateway_tasks.rs index 97a086177e..0fcf54d9dd 100644 --- a/nym-node/src/config/gateway_tasks.rs +++ b/nym-node/src/config/gateway_tasks.rs @@ -50,8 +50,13 @@ pub struct Debug { /// The maximum number of client connections the gateway will keep open at once. pub maximum_open_connections: usize, - /// Defines the maximum age of a signed authentication request before it's deemed too stale to process. - pub maximum_auth_request_age: Duration, + /// Specifies the minimum performance of mixnodes in the network that are to be used in internal topologies + /// of the services providers + pub minimum_mix_performance: u8, + + /// Defines the timestamp skew of a signed authentication request before it's deemed too excessive to process. + #[serde(alias = "maximum_auth_request_age")] + pub max_request_timestamp_skew: Duration, pub stale_messages: StaleMessageDebug, @@ -61,9 +66,10 @@ pub struct Debug { } impl Debug { - pub const DEFAULT_MAXIMUM_OPEN_CONNECTIONS: usize = 8192; pub const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100; - pub const DEFAULT_MAXIMUM_AUTH_REQUEST_AGE: Duration = Duration::from_secs(30); + pub const DEFAULT_MINIMUM_MIX_PERFORMANCE: u8 = 50; + pub const DEFAULT_MAXIMUM_AUTH_REQUEST_TIMESTAMP_SKEW: Duration = Duration::from_secs(120); + pub const DEFAULT_MAXIMUM_OPEN_CONNECTIONS: usize = 8192; } impl Default for Debug { @@ -71,7 +77,8 @@ impl Default for Debug { Debug { message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT, maximum_open_connections: Self::DEFAULT_MAXIMUM_OPEN_CONNECTIONS, - maximum_auth_request_age: Self::DEFAULT_MAXIMUM_AUTH_REQUEST_AGE, + max_request_timestamp_skew: Self::DEFAULT_MAXIMUM_AUTH_REQUEST_TIMESTAMP_SKEW, + minimum_mix_performance: Self::DEFAULT_MINIMUM_MIX_PERFORMANCE, stale_messages: Default::default(), client_bandwidth: Default::default(), zk_nym_tickets: Default::default(), diff --git a/nym-node/src/config/helpers.rs b/nym-node/src/config/helpers.rs index a56e0442e0..0dae4e17db 100644 --- a/nym-node/src/config/helpers.rs +++ b/nym-node/src/config/helpers.rs @@ -60,7 +60,7 @@ fn ephemeral_gateway_config(config: &Config) -> nym_gateway::config::Config { .zk_nym_tickets .maximum_time_between_redemption, }, - maximum_auth_request_age: config.gateway_tasks.debug.maximum_auth_request_age, + max_request_timestamp_skew: config.gateway_tasks.debug.max_request_timestamp_skew, }, ) } diff --git a/nym-node/src/config/mod.rs b/nym-node/src/config/mod.rs index b46d19e370..c71f003fbc 100644 --- a/nym-node/src/config/mod.rs +++ b/nym-node/src/config/mod.rs @@ -780,16 +780,26 @@ pub struct Debug { /// Specifies the time to live of the internal topology provider cache. #[serde(with = "humantime_serde")] pub topology_cache_ttl: Duration, + + /// Specifies the time between attempting to resolve any pending unknown nodes in the routing filter + #[serde(with = "humantime_serde")] + pub routing_nodes_check_interval: Duration, + + /// Specifies whether this node runs in testnet mode thus allowing it to route packets on local interfaces + pub testnet: bool, } impl Debug { - pub const DEFAULT_TOPOLOGY_CACHE_TTL: Duration = Duration::from_secs(5 * 60); + pub const DEFAULT_TOPOLOGY_CACHE_TTL: Duration = Duration::from_secs(10 * 60); + pub const DEFAULT_ROUTING_NODES_CHECK_INTERVAL: Duration = Duration::from_secs(5 * 60); } impl Default for Debug { fn default() -> Self { Debug { topology_cache_ttl: Self::DEFAULT_TOPOLOGY_CACHE_TTL, + routing_nodes_check_interval: Self::DEFAULT_ROUTING_NODES_CHECK_INTERVAL, + testnet: false, } } } diff --git a/nym-node/src/error.rs b/nym-node/src/error.rs index 3c50451e07..d7cec1edbd 100644 --- a/nym-node/src/error.rs +++ b/nym-node/src/error.rs @@ -3,7 +3,9 @@ use crate::node::http::error::NymNodeHttpError; use crate::wireguard::error::WireguardError; +use nym_http_api_client::HttpClientError; use nym_ip_packet_router::error::ClientCoreError; +use nym_validator_client::ValidatorClientError; use std::io; use std::net::IpAddr; use std::path::PathBuf; @@ -141,6 +143,11 @@ pub enum NymNodeError { source: ipnetwork::IpNetworkError, }, + #[error( + "failed to retrieve initial network topology - can't start the node without it: {source}" + )] + InitialTopologyQueryFailure { source: ValidatorClientError }, + #[error(transparent)] GatewayFailure(#[from] nym_gateway::GatewayError), @@ -203,3 +210,9 @@ pub enum ServiceProvidersError { #[error(transparent)] ExternalClientCore(#[from] ClientCoreError), } + +impl From for NymNodeError { + fn from(value: HttpClientError) -> Self { + Self::HttpFailure(NymNodeHttpError::ClientError { source: value }) + } +} diff --git a/nym-node/src/node/http/error.rs b/nym-node/src/node/http/error.rs index 251705f520..f63ed26f49 100644 --- a/nym-node/src/node/http/error.rs +++ b/nym-node/src/node/http/error.rs @@ -1,6 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use nym_http_api_client::HttpClientError; use std::io; use std::net::SocketAddr; use thiserror::Error; @@ -24,4 +25,10 @@ pub enum NymNodeHttpError { #[from] source: nym_crypto::asymmetric::encryption::KeyRecoveryError, }, + + #[error("error building or using HTTP client: {source}")] + ClientError { + #[from] + source: HttpClientError, + }, } diff --git a/nym-node/src/node/mixnet/packet_forwarding/global.rs b/nym-node/src/node/mixnet/packet_forwarding/global.rs new file mode 100644 index 0000000000..6f27444a57 --- /dev/null +++ b/nym-node/src/node/mixnet/packet_forwarding/global.rs @@ -0,0 +1,79 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + +// use `ip` feature without nightly +// issue: https://github.com/rust-lang/rust/issues/27709 +pub(crate) const fn is_global_ip(ip: &IpAddr) -> bool { + match ip { + IpAddr::V4(addr) => is_global_ipv4(addr), + IpAddr::V6(addr) => is_global_ipv6(addr), + } +} + +const fn is_shared_ipv4(ip: &Ipv4Addr) -> bool { + ip.octets()[0] == 100 && (ip.octets()[1] & 0b1100_0000 == 0b0100_0000) +} + +const fn is_benchmarking_ipv4(ip: &Ipv4Addr) -> bool { + ip.octets()[0] == 198 && (ip.octets()[1] & 0xfe) == 18 +} + +const fn is_reserved_ipv4(ip: &Ipv4Addr) -> bool { + ip.octets()[0] & 240 == 240 && !ip.is_broadcast() +} + +const fn is_global_ipv4(ip: &Ipv4Addr) -> bool { + !(ip.octets()[0] == 0 // "This network" + || ip.is_private() + || is_shared_ipv4(ip) + || ip.is_loopback() + || ip.is_link_local() + // addresses reserved for future protocols (`192.0.0.0/24`) + // .9 and .10 are documented as globally reachable so they're excluded + || ( + ip.octets()[0] == 192 && ip.octets()[1] == 0 && ip.octets()[2] == 0 + && ip.octets()[3] != 9 && ip.octets()[3] != 10 + ) + || ip.is_documentation() + || is_benchmarking_ipv4(ip) + || is_reserved_ipv4(ip) + || ip.is_broadcast()) +} + +const fn is_documentation_ipv6(ip: &Ipv6Addr) -> bool { + (ip.segments()[0] == 0x2001) && (ip.segments()[1] == 0xdb8) +} + +const fn is_global_ipv6(ip: &Ipv6Addr) -> bool { + !(ip.is_unspecified() + || ip.is_loopback() + // IPv4-mapped Address (`::ffff:0:0/96`) + || matches!(ip.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) + // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) + || matches!(ip.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) + // Discard-Only Address Block (`100::/64`) + || matches!(ip.segments(), [0x100, 0, 0, 0, _, _, _, _]) + // IETF Protocol Assignments (`2001::/23`) + || (matches!(ip.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) + && !( + // Port Control Protocol Anycast (`2001:1::1`) + u128::from_be_bytes(ip.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 + // Traversal Using Relays around NAT Anycast (`2001:1::2`) + || u128::from_be_bytes(ip.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 + // AMT (`2001:3::/32`) + || matches!(ip.segments(), [0x2001, 3, _, _, _, _, _, _]) + // AS112-v6 (`2001:4:112::/48`) + || matches!(ip.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) + // ORCHIDv2 (`2001:20::/28`) + // Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)` + || matches!(ip.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F) + )) + // 6to4 (`2002::/16`) – it's not explicitly documented as globally reachable, + // IANA says N/A. + || matches!(ip.segments(), [0x2002, _, _, _, _, _, _, _]) + || is_documentation_ipv6(ip) + || ip.is_unique_local() + || ip.is_unicast_link_local()) +} diff --git a/nym-node/src/node/mixnet/packet_forwarding.rs b/nym-node/src/node/mixnet/packet_forwarding/mod.rs similarity index 85% rename from nym-node/src/node/mixnet/packet_forwarding.rs rename to nym-node/src/node/mixnet/packet_forwarding/mod.rs index cb85fc5af9..a61f5517ec 100644 --- a/nym-node/src/node/mixnet/packet_forwarding.rs +++ b/nym-node/src/node/mixnet/packet_forwarding/mod.rs @@ -1,6 +1,8 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use crate::node::mixnet::packet_forwarding::global::is_global_ip; +use crate::node::shared_network::RoutingFilter; use futures::StreamExt; use nym_mixnet_client::forwarder::{ mix_forwarding_channels, MixForwardingReceiver, MixForwardingSender, PacketToForward, @@ -11,14 +13,20 @@ use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue}; use nym_sphinx_forwarding::packet::MixPacket; use nym_task::ShutdownToken; use std::io; +use std::net::IpAddr; use tokio::time::Instant; use tracing::{debug, error, trace, warn}; +pub(crate) mod global; + pub struct PacketForwarder { + testnet: bool, + delay_queue: NonExhaustiveDelayQueue, mixnet_client: C, metrics: NymNodeMetrics, + routing_filter: RoutingFilter, packet_sender: MixForwardingSender, packet_receiver: MixForwardingReceiver, @@ -26,13 +34,21 @@ pub struct PacketForwarder { } impl PacketForwarder { - pub fn new(client: C, metrics: NymNodeMetrics, shutdown: ShutdownToken) -> Self { + pub fn new( + client: C, + testnet: bool, + routing_filter: RoutingFilter, + metrics: NymNodeMetrics, + shutdown: ShutdownToken, + ) -> Self { let (packet_sender, packet_receiver) = mix_forwarding_channels(); PacketForwarder { + testnet, delay_queue: NonExhaustiveDelayQueue::new(), mixnet_client: client, metrics, + routing_filter, packet_sender, packet_receiver, shutdown, @@ -43,11 +59,29 @@ impl PacketForwarder { self.packet_sender.clone() } + fn should_route(&mut self, ip_addr: IpAddr) -> bool { + // only allow non-global ips on testnets + if self.testnet && !is_global_ip(&ip_addr) { + return true; + } + + self.routing_filter.attempt_resolve(ip_addr).should_route() + } + fn forward_packet(&mut self, packet: MixPacket) where C: SendWithoutResponse, { let next_hop = packet.next_hop(); + + if !self.should_route(next_hop.as_ref().ip()) { + debug!("dropping packet as the egress address does not belong to any known node"); + self.metrics + .mixnet + .egress_dropped_forward_packet(next_hop.into()); + return; + } + let packet_type = packet.packet_type(); let packet = packet.into_packet(); diff --git a/nym-node/src/node/mod.rs b/nym-node/src/node/mod.rs index b803d772d0..f68a2d5553 100644 --- a/nym-node/src/node/mod.rs +++ b/nym-node/src/node/mod.rs @@ -28,7 +28,9 @@ use crate::node::metrics::handler::pending_egress_packets_updater::PendingEgress use crate::node::mixnet::packet_forwarding::PacketForwarder; use crate::node::mixnet::shared::ProcessingConfig; use crate::node::mixnet::SharedFinalHopData; -use crate::node::shared_topology::NymNodeTopologyProvider; +use crate::node::shared_network::{ + CachedNetwork, CachedTopologyProvider, NetworkRefresher, RoutingFilter, +}; use nym_bin_common::bin_info; use nym_crypto::asymmetric::{ed25519, x25519}; use nym_gateway::node::{ActiveClientsStore, GatewayTasksBuilder}; @@ -67,7 +69,7 @@ pub mod helpers; pub(crate) mod http; pub(crate) mod metrics; pub(crate) mod mixnet; -mod shared_topology; +mod shared_network; pub struct GatewayTasksData { mnemonic: Arc>, @@ -530,16 +532,15 @@ impl NymNode { self.x25519_noise_keys.public_key() } - // the reason it's here as opposed to in the gateway directly, - // is that other nym-node tasks will also eventually need it - // (such as the ones for obtaining noise keys of other nodes) - fn build_topology_provider(&self) -> Result { - Ok(NymNodeTopologyProvider::new( - self.as_gateway_topology_node()?, - self.config.debug.topology_cache_ttl, + async fn build_network_refresher(&self) -> Result { + NetworkRefresher::initialise_new( self.user_agent(), self.config.mixnet.nym_api_urls.clone(), - )) + self.config.debug.topology_cache_ttl, + self.config.debug.routing_nodes_check_interval, + self.shutdown_manager.clone_token("network-refresher"), + ) + .await } fn as_gateway_topology_node(&self) -> Result { @@ -583,13 +584,19 @@ impl NymNode { async fn start_gateway_tasks( &mut self, + cached_network: CachedNetwork, metrics_sender: MetricEventsSender, active_clients_store: ActiveClientsStore, mix_packet_sender: MixForwardingSender, task_client: TaskClient, ) -> Result<(), NymNodeError> { let config = gateway_tasks_config(&self.config); - let topology_provider = Box::new(self.build_topology_provider()?); + + let topology_provider = Box::new(CachedTopologyProvider::new( + self.as_gateway_topology_node()?, + cached_network, + self.config.gateway_tasks.debug.minimum_mix_performance, + )); let mut gateway_tasks_builder = GatewayTasksBuilder::new( config.gateway, @@ -807,9 +814,23 @@ impl NymNode { return; } - for nym_api in &self.config.mixnet.nym_api_urls { - info!("trying {nym_api}..."); - let client = NymApiClient::new_with_user_agent(nym_api.clone(), self.user_agent()); + for nym_api_url in &self.config.mixnet.nym_api_urls { + info!("trying {nym_api_url}..."); + + let nym_api = + match nym_http_api_client::ClientBuilder::new_with_url(nym_api_url.clone()) + .no_hickory_dns() + .with_user_agent(self.user_agent()) + .build::<&str>() + { + Ok(b) => b, + Err(e) => { + warn!("failed to build http client for \"{nym_api_url}\": {e}",); + continue; + } + }; + + let client = NymApiClient { nym_api }; // make new request every time in case previous one takes longer and invalidates the signature let request = NodeRefreshBody::new(self.ed25519_identity_keys.private_key()); @@ -952,6 +973,7 @@ impl NymNode { pub(crate) fn start_mixnet_listener( &self, active_clients_store: &ActiveClientsStore, + routing_filter: RoutingFilter, shutdown: ShutdownToken, ) -> (MixForwardingSender, ActiveConnections) { let processing_config = ProcessingConfig::new(&self.config); @@ -980,6 +1002,8 @@ impl NymNode { let mut packet_forwarder = PacketForwarder::new( mixnet_client, + self.config.debug.testnet, + routing_filter, self.metrics.clone(), shutdown.clone_with_suffix("mix-packet-forwarder"), ); @@ -1028,13 +1052,14 @@ impl NymNode { }); self.try_refresh_remote_nym_api_cache().await; - self.start_verloc_measurements(); + let network_refresher = self.build_network_refresher().await?; let active_clients_store = ActiveClientsStore::new(); let (mix_packet_sender, active_egress_mixnet_connections) = self.start_mixnet_listener( &active_clients_store, + network_refresher.routing_filter(), self.shutdown_manager.clone_token("mixnet-traffic"), ); @@ -1045,6 +1070,7 @@ impl NymNode { ); self.start_gateway_tasks( + network_refresher.cached_network(), metrics_sender, active_clients_store, mix_packet_sender, @@ -1052,6 +1078,8 @@ impl NymNode { ) .await?; + network_refresher.start(); + self.shutdown_manager.close(); self.shutdown_manager.wait_for_shutdown_signal().await; diff --git a/nym-node/src/node/shared_network.rs b/nym-node/src/node/shared_network.rs new file mode 100644 index 0000000000..aa2e378541 --- /dev/null +++ b/nym-node/src/node/shared_network.rs @@ -0,0 +1,441 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::error::NymNodeError; +use arc_swap::ArcSwap; +use async_trait::async_trait; +use nym_gateway::node::UserAgent; +use nym_node_metrics::prometheus_wrapper::{PrometheusMetric, PROMETHEUS_METRICS}; +use nym_task::ShutdownToken; +use nym_topology::node::RoutingNode; +use nym_topology::{EpochRewardedSet, NymTopology, Role, TopologyProvider}; +use nym_validator_client::nym_api::NymApiClientExt; +use nym_validator_client::nym_nodes::{NodesByAddressesResponse, SkimmedNode}; +use nym_validator_client::{NymApiClient, ValidatorClientError}; +use std::collections::HashSet; +use std::net::IpAddr; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::RwLock; +use tokio::time::interval; +use tracing::log::error; +use tracing::{debug, trace, warn}; +use url::Url; + +#[derive(Clone)] +pub(crate) struct RoutingFilter { + resolved: KnownNodes, + + // while this is technically behind a lock, it should not be called too often as once resolved it will + // be present on the arcswap in either allowed or denied section + pending: UnknownNodes, +} + +impl RoutingFilter { + fn new_empty() -> Self { + RoutingFilter { + resolved: Default::default(), + pending: Default::default(), + } + } + + pub(crate) fn attempt_resolve(&self, ip: IpAddr) -> Resolution { + if self.resolved.inner.allowed.load().contains(&ip) { + Resolution::Accept + } else if self.resolved.inner.denied.load().contains(&ip) { + Resolution::Deny + } else { + self.pending.try_insert(ip); + Resolution::Unknown + } + } +} + +#[derive(Clone, Default)] +struct UnknownNodes(Arc>>); + +impl UnknownNodes { + fn try_insert(&self, ip: IpAddr) { + // if we can immediately grab the lock to push it into the pending queue, amazing, let's do it + // otherwise we can do it next time we see this ip + // (if we can't hold the lock, it means it's being updated at this very moment which is actually a good thing) + if let Ok(mut guard) = self.0.try_write() { + guard.insert(ip); + } + } + + async fn clear(&self) { + self.0.write().await.clear(); + } + + async fn nodes(&self) -> HashSet { + self.0.read().await.clone() + } +} + +// for now we don't care about keys, etc. +// we only want to know if given ip belongs to a known node +#[derive(Debug, Default, Clone)] +pub(crate) struct KnownNodes { + inner: Arc, +} + +#[derive(Debug, Default)] +struct KnownNodesInner { + allowed: ArcSwap>, + denied: ArcSwap>, +} + +pub(crate) enum Resolution { + Unknown, + Deny, + Accept, +} + +impl From for Resolution { + fn from(value: bool) -> Self { + if value { + Resolution::Accept + } else { + Resolution::Deny + } + } +} + +impl Resolution { + pub(crate) fn should_route(&self) -> bool { + matches!(self, Resolution::Accept) + } +} + +impl KnownNodes { + fn swap_allowed(&self, new: HashSet) { + self.inner.allowed.store(Arc::new(new)) + } + + fn swap_denied(&self, new: HashSet) { + self.inner.denied.store(Arc::new(new)) + } +} + +struct NodesQuerier { + client: NymApiClient, + nym_api_urls: Vec, + currently_used_api: usize, +} + +impl NodesQuerier { + fn use_next_nym_api(&mut self) { + if self.nym_api_urls.len() == 1 { + warn!("There's only a single nym API available - it won't be possible to use a different one"); + return; + } + + self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len(); + self.client + .change_nym_api(self.nym_api_urls[self.currently_used_api].clone()) + } + + async fn rewarded_set(&mut self) -> Result { + let res = self + .client + .get_current_rewarded_set() + .await + .inspect_err(|err| error!("failed to get current rewarded set: {err}")); + + if res.is_err() { + self.use_next_nym_api() + } + res + } + + async fn current_nymnodes(&mut self) -> Result, ValidatorClientError> { + let res = self + .client + .get_all_basic_nodes() + .await + .inspect_err(|err| error!("failed to get network nodes: {err}")); + + if res.is_err() { + self.use_next_nym_api() + } + res + } + + async fn query_for_info( + &mut self, + ips: Vec, + ) -> Result { + let res = self + .client + .nym_api + .nodes_by_addresses(ips) + .await + .inspect_err(|err| error!("failed to obtain node information: {err}")); + + if res.is_err() { + self.use_next_nym_api() + } + Ok(res?) + } +} + +#[derive(Clone)] +pub struct CachedTopologyProvider { + gateway_node: Arc, + cached_network: CachedNetwork, + min_mix_performance: u8, +} + +impl CachedTopologyProvider { + pub(crate) fn new( + gateway_node: RoutingNode, + cached_network: CachedNetwork, + min_mix_performance: u8, + ) -> Self { + CachedTopologyProvider { + gateway_node: Arc::new(gateway_node), + cached_network, + min_mix_performance, + } + } +} + +#[async_trait] +impl TopologyProvider for CachedTopologyProvider { + async fn get_new_topology(&mut self) -> Option { + let network_guard = self.cached_network.inner.read().await; + let self_node = self.gateway_node.identity_key; + + let mut topology = NymTopology::new_empty(network_guard.rewarded_set.clone()) + .with_additional_nodes(network_guard.network_nodes.iter().filter(|node| { + if node.supported_roles.mixnode { + node.performance.round_to_integer() >= self.min_mix_performance + } else { + true + } + })); + + if !topology.has_node_details(self.gateway_node.node_id) { + debug!("{self_node} didn't exist in topology. inserting it.",); + topology.insert_node_details(self.gateway_node.as_ref().clone()); + } + topology.force_set_active(self.gateway_node.node_id, Role::EntryGateway); + + Some(topology) + } +} + +#[derive(Clone)] +pub(crate) struct CachedNetwork { + inner: Arc>, +} + +impl CachedNetwork { + fn new_empty() -> Self { + CachedNetwork { + inner: Arc::new(RwLock::new(CachedNetworkInner { + rewarded_set: Default::default(), + network_nodes: vec![], + })), + } + } +} + +struct CachedNetworkInner { + rewarded_set: EpochRewardedSet, + network_nodes: Vec, +} + +pub struct NetworkRefresher { + querier: NodesQuerier, + full_refresh_interval: Duration, + pending_check_interval: Duration, + shutdown_token: ShutdownToken, + + network: CachedNetwork, + routing_filter: RoutingFilter, +} + +impl NetworkRefresher { + pub(crate) async fn initialise_new( + user_agent: UserAgent, + nym_api_urls: Vec, + full_refresh_interval: Duration, + pending_check_interval: Duration, + shutdown_token: ShutdownToken, + ) -> Result { + let nym_api = nym_http_api_client::Client::builder(nym_api_urls[0].clone())? + .no_hickory_dns() + .with_user_agent(user_agent) + .build()?; + + let mut this = NetworkRefresher { + querier: NodesQuerier { + client: NymApiClient { nym_api }, + nym_api_urls, + currently_used_api: 0, + }, + full_refresh_interval, + pending_check_interval, + shutdown_token, + network: CachedNetwork::new_empty(), + routing_filter: RoutingFilter::new_empty(), + }; + + this.obtain_initial_network().await?; + Ok(this) + } + + fn allowed_nodes_copy(&self) -> HashSet { + self.routing_filter + .resolved + .inner + .allowed + .load_full() + .as_ref() + .clone() + } + + fn denied_nodes_copy(&self) -> HashSet { + self.routing_filter + .resolved + .inner + .denied + .load_full() + .as_ref() + .clone() + } + + async fn inspect_pending(&mut self) { + let to_resolve = self.routing_filter.pending.nodes().await; + + // no pending requests to resolve + if to_resolve.is_empty() { + return; + } + + let mut allowed = self.allowed_nodes_copy(); + let mut denied = self.denied_nodes_copy(); + + // short circuit: check if the pending nodes are not already resolved + // (it could happen due to lack of full sync between pending lock and arcswap(s)) + if to_resolve + .iter() + .all(|p| allowed.contains(p) || denied.contains(p)) + { + return; + } + + // 1. attempt to use the new nym-api query to get information just by ips + let nodes = to_resolve.into_iter().collect(); + if let Ok(res) = self.querier.query_for_info(nodes).await { + for (ip, maybe_id) in res.existence { + if maybe_id.is_some() { + allowed.insert(ip); + } else { + denied.insert(ip); + } + } + + self.routing_filter.resolved.swap_allowed(allowed); + self.routing_filter.resolved.swap_denied(denied); + self.routing_filter.pending.clear().await; + return; + } + + // 2. we assume nym-api doesn't support that query yet - we have to do the full refresh + self.refresh_network_nodes().await; + } + + async fn refresh_network_nodes_inner(&mut self) -> Result<(), ValidatorClientError> { + let rewarded_set = self.querier.rewarded_set().await?; + let nodes = self.querier.current_nymnodes().await?; + + // collect all known/allowed nodes information + let known_nodes = nodes + .iter() + .flat_map(|n| n.ip_addresses.iter()) + .copied() + .collect::>(); + + let pending = self.routing_filter.pending.nodes().await; + let mut current_denied = self.denied_nodes_copy(); + + for allowed in &known_nodes { + // if some node has become known, it should be removed from the denied set + current_denied.remove(allowed); + } + + // any pending node, if not present in the new set of allowed nodes, should be added in the denied set + for pending_node in pending { + if !known_nodes.contains(&pending_node) { + current_denied.insert(pending_node); + } + } + + self.routing_filter.resolved.swap_allowed(known_nodes); + self.routing_filter.resolved.swap_denied(current_denied); + self.routing_filter.pending.clear().await; + + let mut network_guard = self.network.inner.write().await; + network_guard.network_nodes = nodes; + network_guard.rewarded_set = rewarded_set; + + Ok(()) + } + + async fn refresh_network_nodes(&mut self) { + let timer = + PROMETHEUS_METRICS.start_timer(PrometheusMetric::ProcessTopologyQueryResolutionLatency); + + if self.refresh_network_nodes_inner().await.is_err() { + // don't use the histogram observation as some queries didn't complete + if let Some(obs) = timer { + obs.stop_and_discard(); + } + } + } + + pub(crate) async fn obtain_initial_network(&mut self) -> Result<(), NymNodeError> { + self.refresh_network_nodes_inner() + .await + .map_err(|source| NymNodeError::InitialTopologyQueryFailure { source }) + } + + pub(crate) fn routing_filter(&self) -> RoutingFilter { + self.routing_filter.clone() + } + + pub(crate) fn cached_network(&self) -> CachedNetwork { + self.network.clone() + } + + pub(crate) async fn run(&mut self) { + let mut full_refresh_interval = interval(self.full_refresh_interval); + full_refresh_interval.reset(); + + let mut pending_check_interval = interval(self.pending_check_interval); + pending_check_interval.reset(); + + while !self.shutdown_token.is_cancelled() { + tokio::select! { + biased; + _ = self.shutdown_token.cancelled() => { + trace!("NetworkRefresher: Received shutdown"); + } + _ = pending_check_interval.tick() => { + self.inspect_pending().await; + } + _ = full_refresh_interval.tick() => { + self.refresh_network_nodes().await; + } + } + } + trace!("NetworkRefresher: Exiting"); + } + + pub(crate) fn start(mut self) { + tokio::spawn(async move { self.run().await }); + } +} diff --git a/nym-node/src/node/shared_topology.rs b/nym-node/src/node/shared_topology.rs deleted file mode 100644 index f3ba72fd00..0000000000 --- a/nym-node/src/node/shared_topology.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2024 - Nym Technologies SA -// SPDX-License-Identifier: GPL-3.0-only - -use async_trait::async_trait; -use nym_gateway::node::{NymApiTopologyProvider, NymApiTopologyProviderConfig, UserAgent}; -use nym_node_metrics::prometheus_wrapper::{PrometheusMetric, PROMETHEUS_METRICS}; -use nym_topology::node::RoutingNode; -use nym_topology::{NymTopology, Role, TopologyProvider}; -use std::sync::Arc; -use std::time::Duration; -use time::OffsetDateTime; -use tokio::sync::Mutex; -use tracing::debug; -use url::Url; -// I wouldn't be surprised if this became the start of the node topology cache - -#[derive(Clone)] -pub struct NymNodeTopologyProvider { - inner: Arc>, -} - -impl NymNodeTopologyProvider { - pub fn new( - gateway_node: RoutingNode, - cache_ttl: Duration, - user_agent: UserAgent, - nym_api_url: Vec, - ) -> NymNodeTopologyProvider { - NymNodeTopologyProvider { - inner: Arc::new(Mutex::new(NymNodeTopologyProviderInner { - inner: NymApiTopologyProvider::new( - NymApiTopologyProviderConfig { - min_mixnode_performance: 50, - min_gateway_performance: 0, - use_extended_topology: false, - ignore_egress_epoch_role: true, - }, - nym_api_url, - Some(user_agent), - ), - cache_ttl, - cached_at: OffsetDateTime::UNIX_EPOCH, - cached: None, - gateway_node, - })), - } - } -} - -struct NymNodeTopologyProviderInner { - inner: NymApiTopologyProvider, - cache_ttl: Duration, - cached_at: OffsetDateTime, - cached: Option, - gateway_node: RoutingNode, -} - -impl NymNodeTopologyProviderInner { - fn cached_topology(&self) -> Option { - if let Some(cached_topology) = &self.cached { - if self.cached_at + self.cache_ttl > OffsetDateTime::now_utc() { - return Some(cached_topology.clone()); - } - } - - None - } - - async fn update_cache(&mut self) -> Option { - let updated_cache = match self.inner.get_new_topology().await { - None => None, - Some(mut base) => { - if !base.has_node_details(self.gateway_node.node_id) { - debug!( - "{} didn't exist in topology. inserting it.", - self.gateway_node.identity_key - ); - base.insert_node_details(self.gateway_node.clone()); - } - base.force_set_active(self.gateway_node.node_id, Role::EntryGateway); - Some(base) - } - }; - - self.cached_at = OffsetDateTime::now_utc(); - self.cached = updated_cache.clone(); - - updated_cache - } -} - -#[async_trait] -impl TopologyProvider for NymNodeTopologyProvider { - async fn get_new_topology(&mut self) -> Option { - let mut guard = self.inner.lock().await; - // check the cache - if let Some(cached) = guard.cached_topology() { - return Some(cached); - } - - // the observation will be included on drop - let _timer = - PROMETHEUS_METRICS.start_timer(PrometheusMetric::ProcessTopologyQueryResolutionLatency); - guard.update_cache().await - } -} diff --git a/nym-validator-rewarder/Dockerfile b/nym-validator-rewarder/Dockerfile index e4543a16a7..c690adb9c6 100644 --- a/nym-validator-rewarder/Dockerfile +++ b/nym-validator-rewarder/Dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nym-validator-rewarder @@ -16,7 +17,7 @@ RUN cargo build --release # see https://github.com/nymtech/nym/blob/develop/nym-validator-rewarder/src/cli/mod.rs for details #------------------------------------------------------------------- -FROM ubuntu:24.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:24.04 RUN apt-get update && apt-get install -y ca-certificates diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index e92a03c300..556fbb5ddf 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.86" +version = "0.1.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", @@ -385,15 +385,15 @@ dependencies = [ [[package]] name = "bls12_381" version = "0.8.0" -source = "git+https://github.com/jstuczyn/bls12_381?branch=temp/experimental-serdect#22cd0a16b674af1629110a2dc8b6cf6c73ea4cd9" +source = "git+https://github.com/jstuczyn/bls12_381?branch=temp/experimental-serdect-updated#9bf520059cb28323fc51469cae86868ef4fa6fbd" dependencies = [ - "digest 0.9.0", + "digest 0.10.7", "ff", "group", "pairing", "rand_core 0.6.4", "serde", - "serdect 0.3.0-pre.0", + "serdect 0.3.0", "subtle", "zeroize", ] @@ -540,11 +540,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.82" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ - "libc", + "shlex", ] [[package]] @@ -1583,9 +1583,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core 0.6.4", "subtle", @@ -1621,12 +1621,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide 0.8.5", ] [[package]] @@ -1905,9 +1905,9 @@ dependencies = [ [[package]] name = "getset" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded738faa0e88d3abc9d1a13cb11adc2073c400969eeb8793cf7132589959fc" +checksum = "f3586f256131df87204eb733da72e3d3eb4f343c639f4b7be279ac7c48baeafe" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2822,6 +2822,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -3094,9 +3103,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -3284,6 +3293,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "tendermint 0.40.1", + "tendermint-rpc", "thiserror 2.0.11", "time", "utoipa", @@ -3332,15 +3342,15 @@ dependencies = [ "bls12_381", "bs58", "cfg-if", - "digest 0.9.0", + "digest 0.10.7", "ff", "group", - "itertools 0.13.0", + "itertools 0.14.0", "nym-network-defaults", "nym-pemstore", "rand 0.8.5", "serde", - "sha2 0.9.9", + "sha2 0.10.8", "subtle", "thiserror 2.0.11", "zeroize", @@ -3607,7 +3617,7 @@ dependencies = [ "cosmwasm-std", "eyre", "hmac", - "itertools 0.13.0", + "itertools 0.14.0", "log", "nym-config", "nym-crypto", @@ -3646,7 +3656,7 @@ dependencies = [ "eyre", "flate2", "futures", - "itertools 0.13.0", + "itertools 0.14.0", "nym-api-requests", "nym-coconut-bandwidth-contract-common", "nym-coconut-dkg-common", @@ -4751,16 +4761,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.3" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", + "cfg-if", "getrandom 0.2.10", "libc", - "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4774,9 +4784,9 @@ dependencies = [ [[package]] name = "rs_merkle" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b241d2e59b74ef9e98d94c78c47623d04c8392abaf82014dfd372a16041128f" +checksum = "bb09b49230ba22e8c676e7b75dfe2887dea8121f18b530ae0ba519ce442d2b21" dependencies = [ "sha2 0.10.8", ] @@ -4931,9 +4941,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", "indexmap 1.9.3", @@ -4944,9 +4954,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", @@ -5054,18 +5064,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -5081,18 +5091,18 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.15" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -5112,9 +5122,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa 1.0.9", "memchr", @@ -5188,9 +5198,9 @@ dependencies = [ [[package]] name = "serdect" -version = "0.3.0-pre.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791ef964bfaba6be28a5c3f0c56836e17cb711ac009ca1074b9c735a3ebf240a" +checksum = "f42f67da2385b51a5f9652db9c93d78aeaf7610bf5ec366080b6de810604af53" dependencies = [ "base16ct", "serde", @@ -5261,6 +5271,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -5355,12 +5371,6 @@ dependencies = [ "system-deps 5.0.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "spki" version = "0.7.2" @@ -6047,9 +6057,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" dependencies = [ "deranged", "itoa 1.0.9", @@ -6064,15 +6074,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" dependencies = [ "num-conv", "time-core", @@ -6105,9 +6115,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" dependencies = [ "backtrace", "bytes", diff --git a/nym-wallet/src/components/Send/SendInputModal.tsx b/nym-wallet/src/components/Send/SendInputModal.tsx index 0ac77f4b28..7ca8bc3623 100644 --- a/nym-wallet/src/components/Send/SendInputModal.tsx +++ b/nym-wallet/src/components/Send/SendInputModal.tsx @@ -121,6 +121,19 @@ export const SendInputModal = ({ initialValue={amount?.amount} denom={denom} /> + onMemoChange(e.target.value)} + value={memo} + error={!memoIsValid} + placeholder="Optional" + helperText={ + !memoIsValid ? ' The text is invalid, only alphanumeric characters and white spaces are allowed' : undefined + } + InputLabelProps={{ shrink: true }} + fullWidth + /> {error} @@ -144,20 +157,6 @@ export const SendInputModal = ({ initialValue={userFees?.amount} fullWidth /> - onMemoChange(e.target.value)} - value={memo} - error={!memoIsValid} - helperText={ - !memoIsValid - ? ' The text is invalid, only alphanumeric characters and white spaces are allowed' - : undefined - } - InputLabelProps={{ shrink: true }} - fullWidth - /> )} diff --git a/nyx-chain-watcher/.sqlx/query-1aa7733ad4bbf3e6b8db909b8646bee247bc021b9534f1d4b0fcad32e2e56218.json b/nyx-chain-watcher/.sqlx/query-1aa7733ad4bbf3e6b8db909b8646bee247bc021b9534f1d4b0fcad32e2e56218.json new file mode 100644 index 0000000000..d1fd65f596 --- /dev/null +++ b/nyx-chain-watcher/.sqlx/query-1aa7733ad4bbf3e6b8db909b8646bee247bc021b9534f1d4b0fcad32e2e56218.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO watcher_execution(start, end, error_message)\n VALUES (?, ?, ?)\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "1aa7733ad4bbf3e6b8db909b8646bee247bc021b9534f1d4b0fcad32e2e56218" +} diff --git a/nyx-chain-watcher/.sqlx/query-7b9abf4ff422b8d7a942955dc4fba380e7d5f0127f4745705b8ac9af6c170d19.json b/nyx-chain-watcher/.sqlx/query-f69907735e9b1e1572c4bf6fe8d44d4ea4e55c2a9c4d4f7e1c7e57bcb848ee08.json similarity index 71% rename from nyx-chain-watcher/.sqlx/query-7b9abf4ff422b8d7a942955dc4fba380e7d5f0127f4745705b8ac9af6c170d19.json rename to nyx-chain-watcher/.sqlx/query-f69907735e9b1e1572c4bf6fe8d44d4ea4e55c2a9c4d4f7e1c7e57bcb848ee08.json index c873acca91..bd0a1777e5 100644 --- a/nyx-chain-watcher/.sqlx/query-7b9abf4ff422b8d7a942955dc4fba380e7d5f0127f4745705b8ac9af6c170d19.json +++ b/nyx-chain-watcher/.sqlx/query-f69907735e9b1e1572c4bf6fe8d44d4ea4e55c2a9c4d4f7e1c7e57bcb848ee08.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT * FROM transactions\n WHERE height > ? \n ORDER BY height ASC, message_index ASC\n ", + "query": "\n SELECT id, tx_hash, height, message_index, sender, recipient, amount, memo, created_at as \"created_at: ::time::OffsetDateTime\"\n FROM transactions\n WHERE height > ?\n ORDER BY height ASC, message_index ASC\n ", "describe": { "columns": [ { @@ -44,7 +44,7 @@ "type_info": "Text" }, { - "name": "created_at", + "name": "created_at: ::time::OffsetDateTime", "ordinal": 8, "type_info": "Datetime" } @@ -64,5 +64,5 @@ true ] }, - "hash": "7b9abf4ff422b8d7a942955dc4fba380e7d5f0127f4745705b8ac9af6c170d19" + "hash": "f69907735e9b1e1572c4bf6fe8d44d4ea4e55c2a9c4d4f7e1c7e57bcb848ee08" } diff --git a/nyx-chain-watcher/Cargo.toml b/nyx-chain-watcher/Cargo.toml index 285ca3c319..bbc2ed1939 100644 --- a/nyx-chain-watcher/Cargo.toml +++ b/nyx-chain-watcher/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "nyx-chain-watcher" -version = "0.1.11" +version = "0.1.14" authors.workspace = true repository.workspace = true homepage.workspace = true @@ -23,16 +23,11 @@ nym-config = { path = "../common/config" } nym-bin-common = { path = "../common/bin-common", features = ["output_format"] } nym-network-defaults = { path = "../common/network-defaults" } nym-task = { path = "../common/task" } -nym-node-requests = { path = "../nym-node/nym-node-requests", features = [ - "openapi", -] } nym-validator-client = { path = "../common/client-libs/validator-client" } nyxd-scraper = { path = "../common/nyxd-scraper" } reqwest = { workspace = true, features = ["rustls-tls"] } -rocket = { workspace = true } schemars = { workspace = true } serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "time"] } thiserror = { workspace = true } time = { workspace = true } diff --git a/nyx-chain-watcher/Dockerfile b/nyx-chain-watcher/Dockerfile index e4419d4664..57076b18b7 100644 --- a/nyx-chain-watcher/Dockerfile +++ b/nyx-chain-watcher/Dockerfile @@ -1,4 +1,5 @@ -FROM rust:latest AS builder +# this will only work with VPN, otherwise remove the harbor part +FROM harbor.nymte.ch/dockerhub/rust:latest AS builder COPY ./ /usr/src/nym WORKDIR /usr/src/nym/nyx-chain-watcher @@ -21,7 +22,7 @@ RUN cargo build --release # and https://github.com/nymtech/nym/blob/develop/nyx-chain-watcher/src/env.rs for env vars #------------------------------------------------------------------- -FROM ubuntu:24.04 +FROM harbor.nymte.ch/dockerhub/ubuntu:24.04 RUN apt update && apt install -yy curl ca-certificates diff --git a/nyx-chain-watcher/build.rs b/nyx-chain-watcher/build.rs index 5cfb413716..5cf16e56f8 100644 --- a/nyx-chain-watcher/build.rs +++ b/nyx-chain-watcher/build.rs @@ -1,13 +1,12 @@ use anyhow::Result; use sqlx::{sqlite::SqliteConnectOptions, Connection, SqliteConnection}; +use std::env::var; use std::io::Write; use std::{collections::HashMap, fs::File, path::PathBuf, str::FromStr}; #[tokio::main] async fn main() -> Result<()> { - let db_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join(".build") - .join("nyx_chain_watcher.sqlite"); + let db_path = PathBuf::from(var("OUT_DIR").unwrap()).join("nyx_chain_watcher.sqlite"); // Create the database directory if it doesn't exist if let Some(parent) = db_path.parent() { diff --git a/nyx-chain-watcher/migrations/005_add_listener_failure_table.sql b/nyx-chain-watcher/migrations/005_add_listener_failure_table.sql new file mode 100644 index 0000000000..6a5cdac6de --- /dev/null +++ b/nyx-chain-watcher/migrations/005_add_listener_failure_table.sql @@ -0,0 +1,11 @@ +/* + * Copyright 2025 - Nym Technologies SA + * SPDX-License-Identifier: GPL-3.0-only + */ + +CREATE TABLE watcher_execution +( + start TIMESTAMP WITHOUT TIME ZONE NOT NULL, + end TIMESTAMP WITHOUT TIME ZONE NOT NULL, + error_message TEXT +) \ No newline at end of file diff --git a/nyx-chain-watcher/src/chain_scraper/mod.rs b/nyx-chain-watcher/src/chain_scraper/mod.rs index 93f768a236..21e716d580 100644 --- a/nyx-chain-watcher/src/chain_scraper/mod.rs +++ b/nyx-chain-watcher/src/chain_scraper/mod.rs @@ -1,12 +1,14 @@ -use crate::config::PaymentWatcherConfig; +use crate::config::PaymentWatchersConfig; use crate::env::vars::{ NYXD_SCRAPER_START_HEIGHT, NYXD_SCRAPER_UNSAFE_NUKE_DB, NYXD_SCRAPER_USE_BEST_EFFORT_START_HEIGHT, }; +use crate::http::state::BankScraperModuleState; use async_trait::async_trait; +use nym_validator_client::nyxd::{Any, Coin, CosmosCoin, Hash, Msg, MsgSend, Name}; use nyxd_scraper::{ - error::ScraperError, storage::StorageTransaction, NyxdScraper, ParsedTransactionResponse, - PruningOptions, TxModule, + error::ScraperError, storage::StorageTransaction, MsgModule, NyxdScraper, + ParsedTransactionResponse, PruningOptions, }; use sqlx::SqlitePool; use std::fs; @@ -15,6 +17,7 @@ use tracing::{info, warn}; pub(crate) async fn run_chain_scraper( config: &crate::config::Config, db_pool: SqlitePool, + shared_state: BankScraperModuleState, ) -> anyhow::Result { let websocket_url = std::env::var("NYXD_WS").expect("NYXD_WS not defined"); @@ -58,9 +61,10 @@ pub(crate) async fn run_chain_scraper( use_best_effort_start_height, }, }) - .with_tx_module(EventScraperModule::new( + .with_msg_module(BankScraperModule::new( db_pool, - config.payment_watcher_config.clone().unwrap_or_default(), + config.payment_watcher_config.clone(), + shared_state, )); let instance = scraper.build_and_start().await?; @@ -71,16 +75,22 @@ pub(crate) async fn run_chain_scraper( Ok(instance) } -pub struct EventScraperModule { +pub struct BankScraperModule { db_pool: SqlitePool, - payment_config: PaymentWatcherConfig, + payment_config: PaymentWatchersConfig, + shared_state: BankScraperModuleState, } -impl EventScraperModule { - pub fn new(db_pool: SqlitePool, payment_config: PaymentWatcherConfig) -> Self { +impl BankScraperModule { + pub fn new( + db_pool: SqlitePool, + payment_config: PaymentWatchersConfig, + shared_state: BankScraperModuleState, + ) -> Self { Self { db_pool, payment_config, + shared_state, } } @@ -108,23 +118,47 @@ impl EventScraperModule { amount, memo ) - .execute(&self.db_pool) - .await?; + .execute(&self.db_pool) + .await?; Ok(()) } -} + fn get_unym_coin(&self, coins: &[CosmosCoin]) -> Option { + coins + .iter() + .find(|coin| coin.denom.as_ref() == "unym") + .map(|c| c.clone().into()) + } + + // TODO: ideally this should be done by the scraper itself + fn recover_bank_msg( + &self, + tx_hash: Hash, + index: usize, + msg: &Any, + ) -> Result { + MsgSend::from_any(msg).map_err(|source| ScraperError::MsgParseFailure { + hash: tx_hash, + index, + type_url: self.type_url(), + source, + }) + } +} #[async_trait] -impl TxModule for EventScraperModule { - async fn handle_tx( +impl MsgModule for BankScraperModule { + fn type_url(&self) -> String { + ::Proto::type_url() + } + + async fn handle_msg( &mut self, + index: usize, + msg: &Any, tx: &ParsedTransactionResponse, - _: &mut StorageTransaction, + _storage_tx: &mut StorageTransaction, ) -> Result<(), ScraperError> { - let events = &tx.tx_result.events; - let height = tx.height.value() as i64; - let tx_hash = tx.hash.to_string(); let memo = tx.tx.body.memo.clone(); // Don't process failed transactions @@ -132,60 +166,53 @@ impl TxModule for EventScraperModule { return Ok(()); } - // Process each event - for event in events { - // Only process transfer events - if event.kind == "transfer" { - let mut recipient = None; - let mut sender = None; - let mut amount = None; - // TODO: get message index from event - let message_index = 0; + let msg = self.recover_bank_msg(tx.hash, index, msg)?; - // Extract transfer event attributes - for attr in &event.attributes { - if let (Ok(key), Ok(value)) = (attr.key_str(), attr.value_str()) { - match key { - "recipient" => recipient = Some(value.to_string()), - "sender" => sender = Some(value.to_string()), - "amount" => amount = Some(value.to_string()), - _ => continue, - } - } - } + // Check if any watcher is watching this recipient + let is_watched = self + .payment_config + .is_being_watched(msg.to_address.as_ref()); - // If we have all required fields, check if recipient is watched and store - if let (Some(recipient), Some(sender), Some(amount)) = (recipient, sender, amount) { - // Check if any watcher is watching this recipient - let is_watched = self.payment_config.watchers.iter().any(|watcher| { - if let Some(watched_accounts) = - &watcher.watch_for_transfer_recipient_accounts - { - watched_accounts - .iter() - .any(|account| account.to_string() == recipient) - } else { - false - } - }); + self.shared_state + .new_bank_msg(tx, index, &msg, is_watched) + .await; - if is_watched { - if let Err(e) = self - .store_transfer_event( - &tx_hash, - height, - message_index, - sender, - recipient, - amount, - Some(memo.clone()), - ) - .await - { - warn!("Failed to store transfer event: {}", e); - } - } - } + if is_watched { + let Some(unym_coin) = self.get_unym_coin(&msg.amount) else { + let warn = format!( + "{} sent {:?} instead of unym!", + msg.from_address, msg.amount + ); + warn!("{warn}"); + self.shared_state + .new_rejection(tx.hash.to_string(), tx.height.value(), index as u32, warn) + .await; + + // we don't want to fail the whole processing - this is not a failure in that sense! + return Ok(()); + }; + + if let Err(err) = self + .store_transfer_event( + &tx.hash.to_string(), + tx.height.value() as i64, + index as i64, + msg.from_address.to_string(), + msg.to_address.to_string(), + unym_coin.to_string(), + Some(memo.clone()), + ) + .await + { + warn!("Failed to store transfer event: {err}"); + self.shared_state + .new_rejection( + tx.hash.to_string(), + tx.height.value(), + index as u32, + format!("storage failure: {err}"), + ) + .await; } } diff --git a/nyx-chain-watcher/src/cli/commands/init.rs b/nyx-chain-watcher/src/cli/commands/init.rs index a545552556..50be4f056b 100644 --- a/nyx-chain-watcher/src/cli/commands/init.rs +++ b/nyx-chain-watcher/src/cli/commands/init.rs @@ -3,8 +3,8 @@ use crate::cli::DEFAULT_NYX_CHAIN_WATCHER_ID; use crate::config::payments_watcher::HttpAuthenticationOptions::AuthorizationBearerToken; -use crate::config::payments_watcher::PaymentWatcherEntry; -use crate::config::{default_config_filepath, Config, ConfigBuilder, PaymentWatcherConfig}; +use crate::config::payments_watcher::PaymentWatcherConfig; +use crate::config::{default_config_filepath, Config, ConfigBuilder, PaymentWatchersConfig}; use crate::error::NyxChainWatcherError; use nym_config::save_unformatted_config_to_file; use nym_validator_client::nyxd::AccountId; @@ -18,22 +18,22 @@ pub(crate) async fn execute(_args: Args) -> Result<(), NyxChainWatcherError> { let data_dir = Config::default_data_directory(&config_path)?; let builder = ConfigBuilder::new(config_path.clone(), data_dir).with_payment_watcher_config( - PaymentWatcherConfig { - watchers: vec![PaymentWatcherEntry { + PaymentWatchersConfig { + watchers: vec![PaymentWatcherConfig { id: DEFAULT_NYX_CHAIN_WATCHER_ID.to_string(), webhook_url: "https://webhook.site".to_string(), - watch_for_transfer_recipient_accounts: Some(vec![AccountId::from_str( + watch_for_transfer_recipient_accounts: vec![AccountId::from_str( "n17g9a2pwwkg8m60wf59pq6mv0c2wusg9ukparkz", ) - .unwrap()]), + .unwrap()], authentication: Some(AuthorizationBearerToken { token: "1234".to_string(), }), description: None, - watch_for_chain_message_types: Some(vec![ + watch_for_chain_message_types: vec![ "/cosmos.bank.v1beta1.MsgSend".to_string(), "/ibc.applications.transfer.v1.MsgTransfer".to_string(), - ]), + ], }], }, ); diff --git a/nyx-chain-watcher/src/cli/commands/run/args.rs b/nyx-chain-watcher/src/cli/commands/run/args.rs index cc20ae2bac..acc1a04573 100644 --- a/nyx-chain-watcher/src/cli/commands/run/args.rs +++ b/nyx-chain-watcher/src/cli/commands/run/args.rs @@ -20,7 +20,7 @@ pub(crate) struct Args { value_delimiter = ',', env = NYX_CHAIN_WATCHER_WATCH_ACCOUNTS )] - pub watch_for_transfer_recipient_accounts: Option>, + pub watch_for_transfer_recipient_accounts: Vec, /// (Override) Watch for chain messages of these types #[clap( @@ -28,7 +28,7 @@ pub(crate) struct Args { value_delimiter = ',', env = NYX_CHAIN_WATCHER_WATCH_CHAIN_MESSAGE_TYPES )] - pub watch_for_chain_message_types: Option>, + pub watch_for_chain_message_types: Vec, /// (Override) The webhook to call when we find something #[clap( diff --git a/nyx-chain-watcher/src/cli/commands/run/config.rs b/nyx-chain-watcher/src/cli/commands/run/config.rs index 02e5a2fadc..73e923a888 100644 --- a/nyx-chain-watcher/src/cli/commands/run/config.rs +++ b/nyx-chain-watcher/src/cli/commands/run/config.rs @@ -1,7 +1,7 @@ use crate::cli::commands::run::args::Args; use crate::cli::DEFAULT_NYX_CHAIN_WATCHER_ID; -use crate::config::payments_watcher::{HttpAuthenticationOptions, PaymentWatcherEntry}; -use crate::config::{default_config_filepath, Config, ConfigBuilder, PaymentWatcherConfig}; +use crate::config::payments_watcher::{HttpAuthenticationOptions, PaymentWatcherConfig}; +use crate::config::{default_config_filepath, Config, ConfigBuilder, PaymentWatchersConfig}; use crate::error::NyxChainWatcherError; use tracing::{info, warn}; @@ -18,8 +18,8 @@ pub(crate) fn get_run_config(args: Args) -> Result } = args; // if there are no args set, then try load the config - if args.watch_for_transfer_recipient_accounts.is_none() - && args.watch_for_transfer_recipient_accounts.is_none() + if args.watch_for_transfer_recipient_accounts.is_empty() + && args.watch_for_transfer_recipient_accounts.is_empty() && args.chain_watcher_db_path.is_none() { info!("Loading default config file..."); @@ -27,12 +27,12 @@ pub(crate) fn get_run_config(args: Args) -> Result } // set default messages - if watch_for_chain_message_types.is_none() { - watch_for_chain_message_types = Some(vec!["/cosmos.bank.v1beta1.MsgSend".to_string()]); + if watch_for_chain_message_types.is_empty() { + watch_for_chain_message_types = vec!["/cosmos.bank.v1beta1.MsgSend".to_string()]; } // warn if no accounts set - if watch_for_transfer_recipient_accounts.is_none() { + if watch_for_transfer_recipient_accounts.is_empty() { warn!( "You did not specify any accounts to watch in {}. Only chain data will be stored.", crate::env::vars::NYX_CHAIN_WATCHER_WATCH_ACCOUNTS @@ -58,8 +58,8 @@ pub(crate) fn get_run_config(args: Args) -> Result let authentication = webhook_auth.map(|token| HttpAuthenticationOptions::AuthorizationBearerToken { token }); - let watcher_config = PaymentWatcherConfig { - watchers: vec![PaymentWatcherEntry { + let watcher_config = PaymentWatchersConfig { + watchers: vec![PaymentWatcherConfig { id: DEFAULT_NYX_CHAIN_WATCHER_ID.to_string(), description: None, watch_for_transfer_recipient_accounts: watch_for_transfer_recipient_accounts diff --git a/nyx-chain-watcher/src/cli/commands/run/mod.rs b/nyx-chain-watcher/src/cli/commands/run/mod.rs index ef2a553995..84d9f10f3b 100644 --- a/nyx-chain-watcher/src/cli/commands/run/mod.rs +++ b/nyx-chain-watcher/src/cli/commands/run/mod.rs @@ -2,19 +2,115 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::error::NyxChainWatcherError; -use tokio::join; -use tracing::{error, info, trace}; +use anyhow::Context; +use std::time::Duration; +use time::OffsetDateTime; +use tokio::task::{JoinHandle, JoinSet}; +use tokio_util::sync::CancellationToken; +use tracing::{error, info}; mod args; mod config; use crate::chain_scraper::run_chain_scraper; -use crate::{db, http, payment_listener, price_scraper}; +use crate::db::DbPool; +use crate::http::state::{BankScraperModuleState, PaymentListenerState, PriceScraperState}; +use crate::payment_listener::PaymentListener; +use crate::price_scraper::PriceScraper; +use crate::{db, http}; pub(crate) use args::Args; use nym_task::signal::wait_for_signal; +async fn try_insert_watcher_execution_information( + db_pool: DbPool, + start: OffsetDateTime, + end: OffsetDateTime, + error_message: Option, +) { + let _ = sqlx::query!( + r#" + INSERT INTO watcher_execution(start, end, error_message) + VALUES (?, ?, ?) + "#, + start, + end, + error_message + ) + .execute(&db_pool) + .await + .inspect_err(|err| error!("failed to insert run information: {err}")); +} + +async fn wait_for_shutdown( + db_pool: DbPool, + start: OffsetDateTime, + main_cancellation_token: CancellationToken, + scraper_cancellation_token: CancellationToken, + mut tasks: JoinSet>>, +) { + async fn finalize_shutdown( + db_pool: DbPool, + start: OffsetDateTime, + main_cancellation_token: CancellationToken, + scraper_cancellation_token: CancellationToken, + mut tasks: JoinSet>>, + error_message: Option, + ) { + // cancel all tasks + main_cancellation_token.cancel(); + scraper_cancellation_token.cancel(); + + // stupid nasty and hacky workaround to make sure all relevant tasks have finished before hard aborting them + // nasty stupid and hacky workaround + tokio::time::sleep(Duration::from_secs(1)).await; + tasks.abort_all(); + + // insert execution result into the db + try_insert_watcher_execution_information( + db_pool, + start, + OffsetDateTime::now_utc(), + error_message, + ) + .await + } + + tokio::select! { + // graceful shutdown + _ = wait_for_signal() => { + info!("received shutdown signal"); + finalize_shutdown(db_pool, start, main_cancellation_token, scraper_cancellation_token, tasks, None).await; + } + _ = scraper_cancellation_token.cancelled() => { + info!("the scraper has issued cancellation"); + finalize_shutdown(db_pool, start, main_cancellation_token, scraper_cancellation_token, tasks, Some("unexpected scraper task cancellation".into())).await; + } + _ = main_cancellation_token.cancelled() => { + info!("one of the tasks has cancelled the token"); + finalize_shutdown(db_pool, start, main_cancellation_token, scraper_cancellation_token, tasks, Some("unexpected main task cancellation".into())).await; + } + task_result = tasks.join_next() => { + // the first unwrap is fine => join set was not empty + let error_message = match task_result.unwrap() { + Err(_join_err) => Some("unexpected join error".to_string()), + Ok(Some(Ok(_))) => None, + Ok(Some(Err(err))) => Some(err.to_string()), + Ok(None) => { + Some("unexpected task cancellation".to_string()) + } + }; + + error!("unexpected task termination: {error_message:?}"); + finalize_shutdown(db_pool, start, main_cancellation_token, scraper_cancellation_token, tasks, error_message).await; + } + + } +} + pub(crate) async fn execute(args: Args, http_port: u16) -> Result<(), NyxChainWatcherError> { - trace!("passed arguments: {args:#?}"); + let start = OffsetDateTime::now_utc(); + + info!("passed arguments: {args:#?}"); let config = config::get_run_config(args)?; @@ -29,9 +125,7 @@ pub(crate) async fn execute(args: Args, http_port: u16) -> Result<(), NyxChainWa ); info!( "Chain History Database path is {:?}", - std::path::Path::new(&config.chain_scraper_database_path()) - .canonicalize() - .unwrap_or_default() + std::path::Path::new(&config.chain_scraper_database_path()).canonicalize() ); // Ensure parent directory exists @@ -41,50 +135,115 @@ pub(crate) async fn execute(args: Args, http_port: u16) -> Result<(), NyxChainWa let connection_url = format!("sqlite://{}?mode=rwc", db_path); let storage = db::Storage::init(connection_url).await?; - let watcher_pool = storage.pool_owned().await; + let watcher_pool = storage.pool_owned(); - // Spawn the chain scraper and get its storage + let mut tasks = JoinSet::new(); + let cancellation_token = CancellationToken::new(); - // Spawn the payment listener task - let payment_listener_handle = tokio::spawn({ - let price_scraper_pool = storage.pool_owned().await; - let scraper_pool = storage.pool_owned().await; - run_chain_scraper(&config, scraper_pool).await?; - let payment_watcher_config = config.payment_watcher_config.unwrap_or_default(); + let price_scraper_pool = storage.pool_owned(); + let scraper_pool = storage.pool_owned(); + let shutdown_pool = storage.pool_owned(); + // construct shared state + let payment_listener_shared_state = PaymentListenerState::new(); + let price_scraper_shared_state = PriceScraperState::new(); + let bank_scraper_module_shared_state = BankScraperModuleState::new(); + + // spawn all the tasks + + // 1. chain scraper (note: this doesn't really spawn the full scraper on this task, but we don't want to be blocking waiting for its startup) + let scraper_token_handle: JoinHandle> = tokio::spawn({ + let config = config.clone(); + let shared_state = bank_scraper_module_shared_state.clone(); async move { - if let Err(e) = - payment_listener::run_payment_listener(payment_watcher_config, price_scraper_pool) - .await - { - error!("Payment listener error: {}", e); - } - Ok::<_, anyhow::Error>(()) + // this only blocks until startup sync is done; it then runs on its own set of tasks + let scraper = run_chain_scraper(&config, scraper_pool, shared_state).await?; + Ok(scraper.cancel_token()) } }); - // Clone pool for each task that needs it - //let background_pool = db_pool.clone(); + // 2. payment listener + let token = cancellation_token.clone(); + let payment_watcher_config = config.payment_watcher_config.clone(); + let payment_listener = PaymentListener::new( + price_scraper_pool, + payment_watcher_config, + payment_listener_shared_state.clone(), + )?; + { + tasks.spawn(async move { + token + .run_until_cancelled(async move { + payment_listener.run().await; + Ok(()) + }) + .await + }); + } - let price_scraper_handle = tokio::spawn(async move { - price_scraper::run_price_scraper(&watcher_pool).await; - }); + // 3. price scraper (note, this task never terminates on its own) + let price_scraper = PriceScraper::new(price_scraper_shared_state.clone(), watcher_pool); + { + let token = cancellation_token.clone(); + tasks.spawn(async move { + token + .run_until_cancelled(async move { + price_scraper.run().await; + Ok(()) + }) + .await + }); + } - let shutdown_handles = http::server::start_http_api(storage.pool_owned().await, http_port) - .await - .expect("Failed to start server"); + // 4. http api + let http_server = http::server::build_http_api( + storage.pool_owned(), + &config, + http_port, + payment_listener_shared_state, + price_scraper_shared_state, + bank_scraper_module_shared_state, + ) + .await?; + { + let token = cancellation_token.clone(); + tasks.spawn(async move { + info!("Starting HTTP server on port {http_port}",); + async move { + Some( + http_server + .run(token.cancelled_owned()) + .await + .context("http server failure"), + ) + } + .await + }); + } - info!("Started HTTP server on port {}", http_port); + // 1. wait for either shutdown or scraper having finished startup + tokio::select! { + _ = wait_for_signal() => { + info!("received shutdown signal while waiting for scraper to finish its startup"); + return Ok(()) + } + scraper_token = scraper_token_handle => { + let scraper_token = match scraper_token { + Ok(Ok(token)) => token, + Ok(Err(startup_err)) => { + error!("failed to startup the chain scraper: {startup_err}"); + return Err(startup_err.into()); + } + Err(runtime_err) => { + error!("failed to finish the scraper startup task: {runtime_err}"); + return Ok(()) - // Wait for the short-lived tasks to complete - let _ = join!(price_scraper_handle, payment_listener_handle); + } + }; - // Wait for a signal to terminate the long-running task - wait_for_signal().await; - - if let Err(err) = shutdown_handles.shutdown().await { - error!("{err}"); - }; + wait_for_shutdown(shutdown_pool, start, cancellation_token, scraper_token, tasks).await + } + } Ok(()) } diff --git a/nyx-chain-watcher/src/config/mod.rs b/nyx-chain-watcher/src/config/mod.rs index 73419a2e9e..ce4e9448a5 100644 --- a/nyx-chain-watcher/src/config/mod.rs +++ b/nyx-chain-watcher/src/config/mod.rs @@ -14,7 +14,7 @@ use tracing::{debug, error}; pub(crate) mod payments_watcher; mod template; -pub use crate::config::payments_watcher::PaymentWatcherConfig; +pub use crate::config::payments_watcher::PaymentWatchersConfig; use crate::error::NyxChainWatcherError; const DEFAULT_NYM_CHAIN_WATCHER_DIR: &str = "nym-chain-watcher"; @@ -46,7 +46,7 @@ pub struct ConfigBuilder { pub chain_scraper_db_path: Option, - pub payment_watcher_config: Option, + pub payment_watcher_config: Option, pub logging: Option, } @@ -76,7 +76,7 @@ impl ConfigBuilder { #[allow(dead_code)] pub fn with_payment_watcher_config( mut self, - payment_watcher_config: impl Into, + payment_watcher_config: impl Into, ) -> Self { self.payment_watcher_config = Some(payment_watcher_config.into()); self @@ -92,7 +92,7 @@ impl ConfigBuilder { Config { logging: self.logging.unwrap_or_default(), save_path: Some(self.config_path), - payment_watcher_config: self.payment_watcher_config, + payment_watcher_config: self.payment_watcher_config.unwrap_or_default(), data_dir: self.data_dir, db_path: self.db_path, chain_scraper_db_path: self.chain_scraper_db_path, @@ -116,7 +116,8 @@ pub struct Config { #[serde(skip)] chain_scraper_db_path: Option, - pub payment_watcher_config: Option, + #[serde(default)] + pub payment_watcher_config: PaymentWatchersConfig, #[serde(default)] pub logging: LoggingSettings, diff --git a/nyx-chain-watcher/src/config/payments_watcher.rs b/nyx-chain-watcher/src/config/payments_watcher.rs index a335830a85..8092b773c7 100644 --- a/nyx-chain-watcher/src/config/payments_watcher.rs +++ b/nyx-chain-watcher/src/config/payments_watcher.rs @@ -1,19 +1,29 @@ use nym_validator_client::nyxd::AccountId; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PaymentWatcherConfig { - pub watchers: Vec, +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct PaymentWatchersConfig { + pub watchers: Vec, +} + +impl PaymentWatchersConfig { + pub fn is_being_watched(&self, account: &str) -> bool { + self.watchers.iter().any(|watcher| { + watcher + .watch_for_transfer_recipient_accounts + .iter() + .any(|acc| acc.as_ref() == account) + }) + } } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PaymentWatcherEntry { +pub struct PaymentWatcherConfig { pub id: String, pub description: Option, pub webhook_url: String, - pub watch_for_transfer_recipient_accounts: Option>, - pub watch_for_chain_message_types: Option>, + pub watch_for_transfer_recipient_accounts: Vec, + pub watch_for_chain_message_types: Vec, pub authentication: Option, } diff --git a/nyx-chain-watcher/src/db/mod.rs b/nyx-chain-watcher/src/db/mod.rs index 74339ca575..00368afb6e 100644 --- a/nyx-chain-watcher/src/db/mod.rs +++ b/nyx-chain-watcher/src/db/mod.rs @@ -34,7 +34,7 @@ impl Storage { } /// Cloning pool is cheap, it's the same underlying set of connections - pub async fn pool_owned(&self) -> DbPool { + pub fn pool_owned(&self) -> DbPool { self.pool.clone() } } diff --git a/nyx-chain-watcher/src/db/models.rs b/nyx-chain-watcher/src/db/models.rs index 8cddac7f30..fa49317cda 100644 --- a/nyx-chain-watcher/src/db/models.rs +++ b/nyx-chain-watcher/src/db/models.rs @@ -1,7 +1,11 @@ +use anyhow::Context; +use nym_validator_client::nyxd::Coin; use serde::{Deserialize, Serialize}; +use sqlx::FromRow; +use time::OffsetDateTime; use utoipa::ToSchema; -#[derive(Clone, Deserialize, Debug, ToSchema)] +#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)] pub(crate) struct CurrencyPrices { pub(crate) chf: f32, pub(crate) usd: f32, @@ -11,7 +15,7 @@ pub(crate) struct CurrencyPrices { } // Struct to hold Coingecko response -#[derive(Clone, Deserialize, Debug, ToSchema)] +#[derive(Clone, Serialize, Deserialize, Debug, ToSchema)] pub(crate) struct CoingeckoPriceResponse { pub(crate) nym: CurrencyPrices, } @@ -41,3 +45,25 @@ pub(crate) struct PaymentRecord { pub(crate) timestamp: i64, pub(crate) height: i64, } + +#[derive(Serialize, Deserialize, Debug, FromRow)] +pub(crate) struct Transaction { + pub(crate) id: i64, + pub(crate) tx_hash: String, + pub(crate) height: i64, + pub(crate) message_index: i64, + pub(crate) sender: String, + pub(crate) recipient: String, + pub(crate) amount: String, + pub(crate) memo: Option, + pub(crate) created_at: Option, +} + +impl Transaction { + pub(crate) fn funds(&self) -> anyhow::Result { + self.amount + .as_str() + .parse() + .context("failed to parse transaction amount") + } +} diff --git a/nyx-chain-watcher/src/helpers.rs b/nyx-chain-watcher/src/helpers.rs new file mode 100644 index 0000000000..88f250cf68 --- /dev/null +++ b/nyx-chain-watcher/src/helpers.rs @@ -0,0 +1,55 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use serde::{Deserialize, Serialize}; +use std::collections::vec_deque::{IntoIter, Iter}; +use std::collections::VecDeque; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct RingBuffer { + #[serde(flatten)] + inner: VecDeque, +} + +impl RingBuffer { + pub fn new(capacity: usize) -> Self { + Self { + inner: VecDeque::with_capacity(capacity), + } + } + + pub fn push(&mut self, item: T) { + if self.inner.len() == self.inner.capacity() { + self.inner.pop_front(); + self.inner.push_back(item); + debug_assert!(self.inner.len() == self.inner.capacity()); + } else { + self.inner.push_back(item); + } + } + + pub fn iter(&self) -> Iter<'_, T> { + self.inner.iter() + } +} + +impl From> for VecDeque { + fn from(value: RingBuffer) -> Self { + value.inner + } +} + +impl From> for Vec { + fn from(value: RingBuffer) -> Self { + value.inner.into() + } +} + +impl IntoIterator for RingBuffer { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.inner.into_iter() + } +} diff --git a/nyx-chain-watcher/src/http/api/mod.rs b/nyx-chain-watcher/src/http/api/mod.rs index 9e405a439d..6374f4ca9f 100644 --- a/nyx-chain-watcher/src/http/api/mod.rs +++ b/nyx-chain-watcher/src/http/api/mod.rs @@ -8,6 +8,7 @@ use utoipa_swagger_ui::SwaggerUi; use crate::http::{api_docs, server::HttpServer, state::AppState}; pub(crate) mod price; +pub(crate) mod status; pub(crate) mod watcher; pub(crate) struct RouterBuilder { @@ -25,8 +26,13 @@ impl RouterBuilder { "/", axum::routing::get(|| async { Redirect::permanent("/swagger") }), ) - .nest("/v1", Router::new().nest("/price", price::routes())) - .nest("/v1", Router::new().nest("/watcher", watcher::routes())); + .nest( + "/v1", + Router::new() + .nest("/status", status::routes()) + .nest("/price", price::routes()) + .nest("/watcher", watcher::routes()), + ); Self { unfinished_router: router, diff --git a/nyx-chain-watcher/src/http/api/status.rs b/nyx-chain-watcher/src/http/api/status.rs new file mode 100644 index 0000000000..df6ec70a91 --- /dev/null +++ b/nyx-chain-watcher/src/http/api/status.rs @@ -0,0 +1,228 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::http::models::status::{ + ActivePaymentWatchersResponse, ApiStatus, BankModuleStatusResponse, BankMsgDetails, + BankMsgRejection, HealthResponse, PaymentListenerFailureDetails, PaymentListenerStatusResponse, + PriceScraperLastError, PriceScraperLastSuccess, PriceScraperStatusResponse, ProcessedPayment, + WatcherFailureDetails, WatcherState, +}; +use crate::http::state::{ + AppState, BankScraperModuleState, PaymentListenerState, PriceScraperState, StatusState, +}; +use axum::extract::State; +use axum::routing::get; +use axum::{Json, Router}; +use nym_bin_common::build_information::BinaryBuildInformationOwned; +use std::ops::Deref; + +pub(crate) fn routes() -> Router { + Router::new() + .route("/health", get(health)) + .route("/build-information", get(build_information)) + .route("/active-payment-watchers", get(active_payment_watchers)) + .route("/payment-listener", get(payment_listener_status)) + .route("/price-scraper", get(price_scraper_status)) + .route("/bank-module-scraper", get(bank_module_status)) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/build-information", + context_path = "/v1/status", + responses( + (status = 200, body = BinaryBuildInformationOwned) + ) +)] +async fn build_information(State(state): State) -> Json { + Json(state.build_information.to_owned()) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/health", + context_path = "/v1/status", + responses( + (status = 200, body = HealthResponse) + ) +)] +async fn health(State(state): State) -> Json { + let uptime = state.startup_time.elapsed(); + + let health = HealthResponse { + status: ApiStatus::Up, + uptime: uptime.as_secs(), + }; + Json(health) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/active-payment-watchers", + context_path = "/v1/status", + responses( + (status = 200, body = ActivePaymentWatchersResponse) + ) +)] +pub(crate) async fn active_payment_watchers( + State(state): State, +) -> Json { + Json(ActivePaymentWatchersResponse { + watchers: state.registered_payment_watchers.deref().clone(), + }) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/payment-listener", + context_path = "/v1/status", + responses( + (status = 200, body = PaymentListenerStatusResponse) + ) +)] +pub(crate) async fn payment_listener_status( + State(state): State, +) -> Json { + let guard = state.inner.read().await; + + // sorry for the nasty conversion code here, run out of time : ( + Json(PaymentListenerStatusResponse { + last_checked: guard.last_checked, + processed_payments_since_startup: guard.processed_payments_since_startup, + watcher_errors_since_startup: guard.watcher_errors_since_startup, + payment_listener_errors_since_startup: guard.payment_listener_errors_since_startup, + last_processed_payment: guard + .last_processed_payment + .as_ref() + .map(|p| ProcessedPayment { + processed_at: p.processed_at, + tx_hash: p.tx_hash.clone(), + message_index: p.message_index, + height: p.height, + sender: p.sender.clone(), + receiver: p.receiver.clone(), + funds: p.funds.clone(), + memo: p.memo.clone(), + }), + latest_failures: guard + .latest_failures + .iter() + .map(|f| PaymentListenerFailureDetails { + timestamp: f.timestamp, + error: f.error.clone(), + }) + .collect(), + watchers: guard + .watchers + .iter() + .map(|(w, state)| { + ( + w.clone(), + WatcherState { + latest_failures: state + .latest_failures + .iter() + .map(|f| WatcherFailureDetails { + timestamp: f.timestamp, + error: f.error.clone(), + }) + .collect(), + }, + ) + }) + .collect(), + }) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/price-scraper", + context_path = "/v1/status", + responses( + (status = 200, body = PriceScraperStatusResponse) + ) +)] +pub(crate) async fn price_scraper_status( + State(state): State, +) -> Json { + let guard = state.inner.read().await; + Json(PriceScraperStatusResponse { + last_success: guard + .last_success + .as_ref() + .map(|s| PriceScraperLastSuccess { + timestamp: s.timestamp, + response: s.response.clone(), + }), + last_failure: guard.last_failure.as_ref().map(|f| PriceScraperLastError { + timestamp: f.timestamp, + message: f.message.clone(), + }), + }) +} + +#[utoipa::path( + tag = "Status", + get, + path = "/bank-module-scraper", + context_path = "/v1/status", + responses( + (status = 200, body = BankModuleStatusResponse) + ) +)] +pub(crate) async fn bank_module_status( + State(state): State, +) -> Json { + let guard = state.inner.read().await; + Json(BankModuleStatusResponse { + processed_bank_msgs_since_startup: guard.processed_bank_msgs_since_startup, + processed_bank_msgs_to_watched_addresses_since_startup: guard + .processed_bank_msgs_to_watched_addresses_since_startup, + rejected_bank_msgs_to_watched_addresses_since_startup: guard + .rejected_bank_msgs_to_watched_addresses_since_startup, + last_seen_bank_msgs: guard + .last_seen_bank_msgs + .iter() + .map(|msg| BankMsgDetails { + processed_at: msg.processed_at, + tx_hash: msg.tx_hash.clone(), + height: msg.height, + index: msg.index, + from: msg.from.clone(), + to: msg.to.clone(), + amount: msg.amount.clone(), + memo: msg.memo.clone(), + }) + .collect(), + last_seen_watched_bank_msgs: guard + .last_seen_watched_bank_msgs + .iter() + .map(|msg| BankMsgDetails { + processed_at: msg.processed_at, + tx_hash: msg.tx_hash.clone(), + height: msg.height, + index: msg.index, + from: msg.from.clone(), + to: msg.to.clone(), + amount: msg.amount.clone(), + memo: msg.memo.clone(), + }) + .collect(), + last_rejected_watched_bank_msgs: guard + .last_rejected_watched_bank_msgs + .iter() + .map(|r| BankMsgRejection { + rejected_at: r.rejected_at, + tx_hash: r.tx_hash.clone(), + height: r.height, + index: r.index, + error: r.error.clone(), + }) + .collect(), + }) +} diff --git a/nyx-chain-watcher/src/http/api/watcher.rs b/nyx-chain-watcher/src/http/api/watcher.rs index 68e6f4f91c..585bec1278 100644 --- a/nyx-chain-watcher/src/http/api/watcher.rs +++ b/nyx-chain-watcher/src/http/api/watcher.rs @@ -1,9 +1,7 @@ -use crate::config::Config; -use crate::env; use crate::http::error::HttpResult; use crate::http::state::AppState; +use axum::extract::State; use axum::{Json, Router}; -use std::env::var; pub(crate) fn routes() -> Router { Router::new().route("/addresses", axum::routing::get(get_addresses)) @@ -19,30 +17,6 @@ pub(crate) fn routes() -> Router { )] /// Fetch the addresses being watched by the chain watcher -async fn get_addresses() -> HttpResult>> { - let addresses = match Config::read_from_toml_file_in_default_location() { - Ok(config) => config - .payment_watcher_config - .as_ref() - .and_then(|config| { - config.watchers.iter().find_map(|watcher| { - watcher - .watch_for_transfer_recipient_accounts - .as_ref() - .map(|accounts| { - accounts - .iter() - .map(|account| account.to_string()) - .collect::>() - }) - }) - }) - .unwrap_or_default(), - // If the config file doesn't exist, fall back to env variable - Err(_) => var(env::vars::NYX_CHAIN_WATCHER_WATCH_ACCOUNTS) - .map(|accounts| accounts.split(',').map(String::from).collect()) - .unwrap_or_default(), - }; - - Ok(Json(addresses)) +async fn get_addresses(State(state): State) -> HttpResult>> { + Ok(Json(state.watched_accounts())) } diff --git a/nyx-chain-watcher/src/http/mod.rs b/nyx-chain-watcher/src/http/mod.rs index 1506514f0f..c57d17c47b 100644 --- a/nyx-chain-watcher/src/http/mod.rs +++ b/nyx-chain-watcher/src/http/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod api; pub(crate) mod api_docs; pub(crate) mod error; +pub(crate) mod models; pub(crate) mod server; pub(crate) mod state; diff --git a/nyx-chain-watcher/src/http/models.rs b/nyx-chain-watcher/src/http/models.rs new file mode 100644 index 0000000000..c433ea9702 --- /dev/null +++ b/nyx-chain-watcher/src/http/models.rs @@ -0,0 +1,162 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +// if we ever create some sort of chain watcher client, those would need to be extracted + +pub mod status { + use crate::config::payments_watcher::PaymentWatcherConfig; + use crate::db::models::CoingeckoPriceResponse; + use crate::models::openapi_schema; + use nym_validator_client::nyxd::Coin; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; + use time::OffsetDateTime; + use utoipa::ToSchema; + + #[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)] + #[serde(rename_all = "lowercase")] + pub enum ApiStatus { + Up, + } + + #[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)] + pub struct HealthResponse { + pub status: ApiStatus, + pub uptime: u64, + } + + #[derive(Debug, Serialize, Deserialize, ToSchema)] + pub struct ActivePaymentWatchersResponse { + pub watchers: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub struct PaymentWatcher { + pub id: String, + pub description: String, + pub webhook_url: String, + pub watched_accounts: Vec, + pub watched_message_types: Vec, + } + + impl From<&PaymentWatcherConfig> for PaymentWatcher { + fn from(value: &PaymentWatcherConfig) -> Self { + PaymentWatcher { + id: value.id.clone(), + description: value.description.clone().unwrap_or_default(), + webhook_url: value.webhook_url.clone(), + watched_accounts: value + .watch_for_transfer_recipient_accounts + .iter() + .map(|a| a.to_string()) + .collect(), + watched_message_types: value.watch_for_chain_message_types.clone(), + } + } + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub struct PaymentListenerStatusResponse { + #[serde(with = "time::serde::rfc3339")] + pub last_checked: OffsetDateTime, + + pub processed_payments_since_startup: u64, + pub watcher_errors_since_startup: u64, + pub payment_listener_errors_since_startup: u64, + + pub last_processed_payment: Option, + + pub latest_failures: Vec, + pub watchers: HashMap, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct ProcessedPayment { + #[serde(with = "time::serde::rfc3339")] + pub processed_at: OffsetDateTime, + + pub tx_hash: String, + pub message_index: u64, + pub height: u64, + pub sender: String, + pub receiver: String, + + #[schema(value_type = openapi_schema::Coin)] + pub funds: Coin, + + pub memo: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct PaymentListenerFailureDetails { + #[serde(with = "time::serde::rfc3339")] + pub(crate) timestamp: OffsetDateTime, + pub(crate) error: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct WatcherState { + pub(crate) latest_failures: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct WatcherFailureDetails { + #[serde(with = "time::serde::rfc3339")] + pub(crate) timestamp: OffsetDateTime, + pub(crate) error: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct PriceScraperStatusResponse { + pub(crate) last_success: Option, + pub(crate) last_failure: Option, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct PriceScraperLastSuccess { + #[serde(with = "time::serde::rfc3339")] + pub(crate) timestamp: OffsetDateTime, + pub(crate) response: CoingeckoPriceResponse, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct PriceScraperLastError { + #[serde(with = "time::serde::rfc3339")] + pub(crate) timestamp: OffsetDateTime, + pub(crate) message: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct BankModuleStatusResponse { + pub(crate) processed_bank_msgs_since_startup: usize, + pub(crate) processed_bank_msgs_to_watched_addresses_since_startup: usize, + pub(crate) rejected_bank_msgs_to_watched_addresses_since_startup: usize, + + pub(crate) last_seen_bank_msgs: Vec, + pub(crate) last_seen_watched_bank_msgs: Vec, + pub(crate) last_rejected_watched_bank_msgs: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct BankMsgDetails { + #[serde(with = "time::serde::rfc3339")] + pub(crate) processed_at: OffsetDateTime, + pub(crate) tx_hash: String, + pub(crate) height: u64, + pub(crate) index: u32, + pub(crate) from: String, + pub(crate) to: String, + pub(crate) amount: Vec, + pub(crate) memo: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] + pub(crate) struct BankMsgRejection { + #[serde(with = "time::serde::rfc3339")] + pub(crate) rejected_at: OffsetDateTime, + pub(crate) tx_hash: String, + pub(crate) height: u64, + pub(crate) index: u32, + pub(crate) error: String, + } +} diff --git a/nyx-chain-watcher/src/http/server.rs b/nyx-chain-watcher/src/http/server.rs index 375774bd18..96e7d47f95 100644 --- a/nyx-chain-watcher/src/http/server.rs +++ b/nyx-chain-watcher/src/http/server.rs @@ -1,70 +1,42 @@ use axum::Router; use core::net::SocketAddr; -use tokio::{net::TcpListener, task::JoinHandle}; -use tokio_util::sync::{CancellationToken, WaitForCancellationFutureOwned}; +use tokio::net::TcpListener; +use tokio_util::sync::WaitForCancellationFutureOwned; +use crate::config::Config; +use crate::http::state::{BankScraperModuleState, PaymentListenerState, PriceScraperState}; use crate::{ db::DbPool, http::{api::RouterBuilder, state::AppState}, }; -/// Return handles that allow for graceful shutdown of server + awaiting its -/// background tokio task -pub(crate) async fn start_http_api( +pub(crate) async fn build_http_api( db_pool: DbPool, + config: &Config, http_port: u16, -) -> anyhow::Result { + payment_listener_state: PaymentListenerState, + price_scraper_state: PriceScraperState, + bank_scraper_module_shared_state: BankScraperModuleState, +) -> anyhow::Result { let router_builder = RouterBuilder::with_default_routes(); - let state = AppState::new(db_pool); + let state = AppState::new( + db_pool, + config + .payment_watcher_config + .watchers + .iter() + .map(Into::into) + .collect(), + payment_listener_state, + price_scraper_state, + bank_scraper_module_shared_state, + ); let router = router_builder.with_state(state); let bind_addr = format!("0.0.0.0:{}", http_port); let server = router.build_server(bind_addr).await?; - - Ok(start_server(server)) -} - -fn start_server(server: HttpServer) -> ShutdownHandles { - // one copy is stored to trigger a graceful shutdown later - let shutdown_button = CancellationToken::new(); - // other copy is given to server to listen for a shutdown - let shutdown_receiver = shutdown_button.clone(); - let shutdown_receiver = shutdown_receiver.cancelled_owned(); - - let server_handle = tokio::spawn(async move { server.run(shutdown_receiver).await }); - - ShutdownHandles { - server_handle, - shutdown_button, - } -} - -pub(crate) struct ShutdownHandles { - server_handle: JoinHandle>, - shutdown_button: CancellationToken, -} - -impl ShutdownHandles { - /// Send graceful shutdown signal to server and wait for server task to complete - pub(crate) async fn shutdown(self) -> anyhow::Result<()> { - self.shutdown_button.cancel(); - - match self.server_handle.await { - Ok(Ok(_)) => { - tracing::info!("HTTP server shut down without errors"); - } - Ok(Err(err)) => { - tracing::error!("HTTP server terminated with: {err}"); - anyhow::bail!(err) - } - Err(err) => { - tracing::error!("Server task panicked: {err}"); - } - }; - - Ok(()) - } + Ok(server) } pub(crate) struct HttpServer { diff --git a/nyx-chain-watcher/src/http/state.rs b/nyx-chain-watcher/src/http/state.rs index 3f72135cf1..3f0d813f44 100644 --- a/nyx-chain-watcher/src/http/state.rs +++ b/nyx-chain-watcher/src/http/state.rs @@ -1,16 +1,392 @@ +use crate::db::models::CoingeckoPriceResponse; use crate::db::DbPool; +use crate::helpers::RingBuffer; +use crate::http::models::status::PaymentWatcher; +use crate::models::WebhookPayload; +use axum::extract::FromRef; +use nym_bin_common::bin_info; +use nym_bin_common::build_information::BinaryBuildInformation; +use nym_validator_client::nyxd::{Coin, MsgSend}; +use nyxd_scraper::ParsedTransactionResponse; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::ops::Deref; +use std::sync::Arc; +use time::OffsetDateTime; +use tokio::sync::RwLock; +use tokio::time::Instant; #[derive(Debug, Clone)] pub(crate) struct AppState { db_pool: DbPool, + pub(crate) registered_payment_watchers: Arc>, + pub(crate) payment_listener_state: PaymentListenerState, + pub(crate) status_state: StatusState, + pub(crate) price_scraper_state: PriceScraperState, + pub(crate) bank_scraper_module_state: BankScraperModuleState, } impl AppState { - pub(crate) fn new(db_pool: DbPool) -> Self { - Self { db_pool } + pub(crate) fn new( + db_pool: DbPool, + registered_payment_watchers: Vec, + payment_listener_state: PaymentListenerState, + price_scraper_state: PriceScraperState, + bank_scraper_module_state: BankScraperModuleState, + ) -> Self { + Self { + db_pool, + registered_payment_watchers: Arc::new(registered_payment_watchers), + payment_listener_state, + status_state: Default::default(), + price_scraper_state, + bank_scraper_module_state, + } } pub(crate) fn db_pool(&self) -> &DbPool { &self.db_pool } + + pub(crate) fn watched_accounts(&self) -> Vec { + self.registered_payment_watchers + .iter() + .flat_map(|w| w.watched_accounts.iter()) + .cloned() + .collect() + } +} + +#[derive(Clone, Debug)] +pub(crate) struct StatusState { + inner: Arc, +} + +impl Default for StatusState { + fn default() -> Self { + StatusState { + inner: Arc::new(StatusStateInner { + startup_time: Instant::now(), + build_information: bin_info!(), + }), + } + } +} + +impl Deref for StatusState { + type Target = StatusStateInner; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Debug)] +pub(crate) struct StatusStateInner { + pub(crate) startup_time: Instant, + pub(crate) build_information: BinaryBuildInformation, +} + +#[derive(Debug, Clone)] +pub(crate) struct PriceScraperState { + pub(crate) inner: Arc>, +} + +impl PriceScraperState { + pub(crate) fn new() -> Self { + PriceScraperState { + inner: Arc::new(Default::default()), + } + } + + pub(crate) async fn new_failure>(&self, error: S) { + self.inner.write().await.last_failure = Some(PriceScraperLastError { + timestamp: OffsetDateTime::now_utc(), + message: error.into(), + }) + } + pub(crate) async fn new_success(&self, response: CoingeckoPriceResponse) { + self.inner.write().await.last_success = Some(PriceScraperLastSuccess { + timestamp: OffsetDateTime::now_utc(), + response, + }) + } +} + +#[derive(Debug, Default)] +pub(crate) struct PriceScraperStateInner { + pub(crate) last_success: Option, + pub(crate) last_failure: Option, +} + +#[derive(Debug)] +pub(crate) struct PriceScraperLastSuccess { + pub(crate) timestamp: OffsetDateTime, + pub(crate) response: CoingeckoPriceResponse, +} + +#[derive(Debug)] +pub(crate) struct PriceScraperLastError { + pub(crate) timestamp: OffsetDateTime, + pub(crate) message: String, +} + +#[derive(Debug, Clone)] +pub(crate) struct PaymentListenerState { + pub(crate) inner: Arc>, +} + +impl PaymentListenerState { + // TODO: make those configurable + const MAX_WATCHER_FAILURES: usize = 20; + const MAX_PAYMENT_LISTENER_FAILURES: usize = 50; + + pub(crate) fn new() -> Self { + PaymentListenerState { + inner: Arc::new(RwLock::new(PaymentListenerStateInner { + last_checked: OffsetDateTime::UNIX_EPOCH, + processed_payments_since_startup: 0, + watcher_errors_since_startup: 0, + payment_listener_errors_since_startup: 0, + last_processed_payment: None, + latest_failures: RingBuffer::new(Self::MAX_PAYMENT_LISTENER_FAILURES), + watchers: Default::default(), + })), + } + } + + pub(crate) async fn insert_listener_failure(&self, failure: PaymentListenerFailureDetails) { + let mut guard = self.inner.write().await; + + guard.payment_listener_errors_since_startup += 1; + guard.latest_failures.push(failure); + } + + pub(crate) async fn insert_watcher_failure(&self, id: &str, failure: WatcherFailureDetails) { + self.inner + .write() + .await + .watchers + .entry(id.to_string()) + .or_insert(WatcherState { + latest_failures: RingBuffer::new(Self::MAX_WATCHER_FAILURES), + }) + .latest_failures + .push(failure); + } + + pub(crate) async fn processed_payment_transaction(&self, payment: ProcessedPayment) { + let mut guard = self.inner.write().await; + + guard.processed_payments_since_startup += 1; + guard.last_processed_payment = Some(payment) + } + + pub(crate) async fn update_last_checked(&self) { + self.inner.write().await.last_checked = OffsetDateTime::now_utc(); + } +} + +#[derive(Debug)] +pub(crate) struct PaymentListenerStateInner { + pub(crate) last_checked: OffsetDateTime, + + pub(crate) processed_payments_since_startup: u64, + pub(crate) watcher_errors_since_startup: u64, + pub(crate) payment_listener_errors_since_startup: u64, + + pub(crate) last_processed_payment: Option, + + pub(crate) latest_failures: RingBuffer, + pub(crate) watchers: HashMap, +} + +#[derive(Debug, Serialize, Deserialize)] +pub(crate) struct ProcessedPayment { + pub processed_at: OffsetDateTime, + + pub tx_hash: String, + pub message_index: u64, + pub height: u64, + pub sender: String, + pub receiver: String, + pub funds: Coin, + pub memo: String, +} + +impl From for ProcessedPayment { + fn from(payload: WebhookPayload) -> Self { + ProcessedPayment { + processed_at: OffsetDateTime::now_utc(), + tx_hash: payload.transaction_hash, + message_index: payload.message_index, + height: payload.height as u64, + sender: payload.sender_address, + receiver: payload.receiver_address, + funds: payload.funds.into(), + memo: payload.memo.unwrap_or_default(), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct PaymentListenerFailureDetails { + pub(crate) timestamp: OffsetDateTime, + pub(crate) error: String, +} + +impl PaymentListenerFailureDetails { + pub(crate) fn new(error: String) -> Self { + PaymentListenerFailureDetails { + timestamp: OffsetDateTime::now_utc(), + error, + } + } +} + +#[derive(Debug)] +pub(crate) struct WatcherState { + pub(crate) latest_failures: RingBuffer, +} + +#[derive(Debug)] +pub(crate) struct WatcherFailureDetails { + pub(crate) timestamp: OffsetDateTime, + pub(crate) error: String, +} + +impl WatcherFailureDetails { + pub(crate) fn new(error: String) -> Self { + WatcherFailureDetails { + timestamp: OffsetDateTime::now_utc(), + error, + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct BankScraperModuleState { + pub(crate) inner: Arc>, +} + +impl BankScraperModuleState { + // TODO: make those configurable + const MAX_LAST_BANK_MSGS: usize = 20; + const MAX_LAST_WATCHED_BANK_MSGS: usize = 10; + const MAX_LAST_REJECTED_BANK_MSGS: usize = 25; + + pub(crate) fn new() -> Self { + BankScraperModuleState { + inner: Arc::new(RwLock::new(BankScraperModuleStateInner { + processed_bank_msgs_since_startup: 0, + processed_bank_msgs_to_watched_addresses_since_startup: 0, + rejected_bank_msgs_to_watched_addresses_since_startup: 0, + last_seen_bank_msgs: RingBuffer::new(Self::MAX_LAST_BANK_MSGS), + last_seen_watched_bank_msgs: RingBuffer::new(Self::MAX_LAST_WATCHED_BANK_MSGS), + last_rejected_watched_bank_msgs: RingBuffer::new(Self::MAX_LAST_REJECTED_BANK_MSGS), + })), + } + } + + pub(crate) async fn new_bank_msg( + &self, + tx: &ParsedTransactionResponse, + index: usize, + msg: &MsgSend, + is_watched: bool, + ) { + let mut guard = self.inner.write().await; + guard.processed_bank_msgs_since_startup += 1; + + let details = BankMsgDetails { + processed_at: OffsetDateTime::now_utc(), + tx_hash: tx.hash.to_string(), + height: tx.height.value(), + index: index as u32, + from: msg.from_address.to_string(), + to: msg.to_address.to_string(), + amount: msg.amount.iter().map(|c| c.to_string()).collect(), + memo: tx.tx.body.memo.clone(), + }; + guard.last_seen_bank_msgs.push(details.clone()); + + if is_watched { + guard.processed_bank_msgs_to_watched_addresses_since_startup += 1; + guard.last_seen_watched_bank_msgs.push(details.clone()); + } + } + + pub(crate) async fn new_rejection>( + &self, + tx_hash: String, + height: u64, + index: u32, + error: S, + ) { + self.inner + .write() + .await + .last_rejected_watched_bank_msgs + .push(BankMsgRejection { + rejected_at: OffsetDateTime::now_utc(), + tx_hash, + height, + index, + error: error.into(), + }) + } +} + +#[derive(Debug)] +pub(crate) struct BankScraperModuleStateInner { + pub(crate) processed_bank_msgs_since_startup: usize, + pub(crate) processed_bank_msgs_to_watched_addresses_since_startup: usize, + pub(crate) rejected_bank_msgs_to_watched_addresses_since_startup: usize, + + pub(crate) last_seen_bank_msgs: RingBuffer, + pub(crate) last_seen_watched_bank_msgs: RingBuffer, + pub(crate) last_rejected_watched_bank_msgs: RingBuffer, +} + +#[derive(Debug, Clone)] +pub(crate) struct BankMsgDetails { + pub(crate) processed_at: OffsetDateTime, + pub(crate) tx_hash: String, + pub(crate) height: u64, + pub(crate) index: u32, + pub(crate) from: String, + pub(crate) to: String, + pub(crate) amount: Vec, + pub(crate) memo: String, +} + +#[derive(Debug)] +pub(crate) struct BankMsgRejection { + pub(crate) rejected_at: OffsetDateTime, + pub(crate) tx_hash: String, + pub(crate) height: u64, + pub(crate) index: u32, + pub(crate) error: String, +} + +impl FromRef for PaymentListenerState { + fn from_ref(input: &AppState) -> Self { + input.payment_listener_state.clone() + } +} +impl FromRef for StatusState { + fn from_ref(input: &AppState) -> Self { + input.status_state.clone() + } +} + +impl FromRef for PriceScraperState { + fn from_ref(input: &AppState) -> Self { + input.price_scraper_state.clone() + } +} + +impl FromRef for BankScraperModuleState { + fn from_ref(input: &AppState) -> Self { + input.bank_scraper_module_state.clone() + } } diff --git a/nyx-chain-watcher/src/main.rs b/nyx-chain-watcher/src/main.rs index e6c3f8ea26..96b531ddba 100644 --- a/nyx-chain-watcher/src/main.rs +++ b/nyx-chain-watcher/src/main.rs @@ -10,6 +10,7 @@ mod config; mod db; mod env; mod error; +pub(crate) mod helpers; mod http; mod logging; pub mod models; diff --git a/nyx-chain-watcher/src/models.rs b/nyx-chain-watcher/src/models.rs index ce1c0886f4..1fc0ca2636 100644 --- a/nyx-chain-watcher/src/models.rs +++ b/nyx-chain-watcher/src/models.rs @@ -1,6 +1,6 @@ use nym_validator_client::nyxd::CosmWasmCoin; -use rocket::serde::{Deserialize, Serialize}; use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; use utoipa::ToSchema; #[derive(Serialize, Deserialize, Clone, JsonSchema, ToSchema)] diff --git a/nyx-chain-watcher/src/payment_listener/mod.rs b/nyx-chain-watcher/src/payment_listener/mod.rs index 826f23dfd8..f941e6c012 100644 --- a/nyx-chain-watcher/src/payment_listener/mod.rs +++ b/nyx-chain-watcher/src/payment_listener/mod.rs @@ -1,108 +1,152 @@ -use crate::config::payments_watcher::HttpAuthenticationOptions; -use crate::config::PaymentWatcherConfig; +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::config::PaymentWatchersConfig; +use crate::db::models::Transaction; use crate::db::queries; +use crate::http::state::{ + PaymentListenerFailureDetails, PaymentListenerState, ProcessedPayment, WatcherFailureDetails, +}; use crate::models::WebhookPayload; -use nym_validator_client::nyxd::Coin; -use reqwest::Client; +use crate::payment_listener::watcher::PaymentWatcher; +use anyhow::Context; use sqlx::SqlitePool; -use std::str::FromStr; use tokio::time::{self, Duration}; -use tracing::{error, info}; +use tracing::{debug, error, info}; -pub(crate) async fn run_payment_listener( - payment_watcher_config: PaymentWatcherConfig, - watcher_pool: SqlitePool, -) -> anyhow::Result<()> { - let client = Client::new(); +pub(crate) mod watcher; - loop { - // 1. get the last height this watcher ran at - let last_checked_height = queries::payments::get_last_checked_height(&watcher_pool).await?; - info!("Last checked height: {}", last_checked_height); +pub(crate) struct PaymentListener { + db_pool: SqlitePool, + payment_watchers: Vec, + shared_state: PaymentListenerState, +} - // 2. iterate through watchers - for watcher in &payment_watcher_config.watchers { - if watcher.watch_for_transfer_recipient_accounts.is_some() { - // 3. Query new transactions for this watcher's recipient accounts - let transactions = sqlx::query!( - r#" - SELECT * FROM transactions - WHERE height > ? - ORDER BY height ASC, message_index ASC - "#, - last_checked_height - ) - .fetch_all(&watcher_pool) - .await?; +impl PaymentListener { + pub(crate) fn new( + db_pool: SqlitePool, + config: PaymentWatchersConfig, + shared_state: PaymentListenerState, + ) -> anyhow::Result { + Ok(PaymentListener { + db_pool, + payment_watchers: config + .watchers + .iter() + .map(|watcher_cfg| PaymentWatcher::new(watcher_cfg.clone())) + .collect::>>()?, + shared_state, + }) + } - if !transactions.is_empty() { - info!( - "[watcher = {}] Processing {} transactions", - watcher.id, - transactions.len() - ); - } + async fn retrieve_unprocessed_transactions(&self) -> anyhow::Result> { + let last_checked_height = queries::payments::get_last_checked_height(&self.db_pool).await?; + let txs = sqlx::query_as!( + Transaction, + r#" + SELECT id, tx_hash, height, message_index, sender, recipient, amount, memo, created_at as "created_at: ::time::OffsetDateTime" + FROM transactions + WHERE height > ? + ORDER BY height ASC, message_index ASC + "#, + last_checked_height + ) + .fetch_all(&self.db_pool) + .await?; - for tx in transactions { - let funds = Coin::from_str(&tx.amount)?; - let amount: f64 = funds.amount as f64 / 1e6f64; // convert to major value, there will be precision loss + Ok(txs) + } - // Store transaction hash for later use - let tx_hash = tx.tx_hash.clone(); - let message_index = tx.message_index; + async fn process_transaction(&self, tx: Transaction) -> anyhow::Result<()> { + // 3.1 process any payments + let funds = tx.funds()?; + let amount: f64 = funds.amount as f64 / 1e6f64; // convert to major value, there will be precision loss - queries::payments::insert_payment( - &watcher_pool, - tx.tx_hash, - tx.sender.clone(), - tx.recipient.clone(), - amount, - tx.height, - tx.memo.clone(), + // TODO: FIXME: it may happen that we insert a payment but fail to invoke all webhooks + + queries::payments::insert_payment( + &self.db_pool, + tx.tx_hash.clone(), + tx.sender.clone(), + tx.recipient.clone(), + amount, + tx.height, + tx.memo.clone(), + ) + .await?; + + // 3.1. invoke all relevant webhooks for all registered watchers + let webhook_data = WebhookPayload { + transaction_hash: tx.tx_hash, + message_index: tx.message_index as u64, + sender_address: tx.sender, + receiver_address: tx.recipient, + funds: funds.into(), + height: tx.height as u128, + memo: tx.memo, + }; + + for watcher in &self.payment_watchers { + if let Err(err) = watcher.invoke_webhook(&webhook_data).await { + error!("watcher {} failure: {err:#}", watcher.id()); + self.shared_state + .insert_watcher_failure( + watcher.id(), + WatcherFailureDetails::new(err.to_string()), ) - .await?; - - let webhook_data = WebhookPayload { - transaction_hash: tx_hash.clone(), - message_index: message_index as u64, - sender_address: tx.sender, - receiver_address: tx.recipient, - funds: funds.into(), - height: tx.height as u128, - memo: tx.memo, - }; - - let mut request_builder = client.post(&watcher.webhook_url).json(&webhook_data); - - if let Some(auth) = &watcher.authentication { - match auth { - HttpAuthenticationOptions::AuthorizationBearerToken { token } => { - request_builder = request_builder.bearer_auth(token); - } - } - } - - match request_builder.send().await { - Ok(res) => info!( - "[watcher = {}] ✅ Webhook {} {} - tx {}, index {}", - watcher.id, - res.status(), - res.url(), - tx_hash, - message_index, - ), - Err(e) => error!( - "[watcher = {}] ❌ Webhook {:?} {:?} error = {}", - watcher.id, - e.status(), - e.url(), - e, - ), - } - } + .await } } - time::sleep(Duration::from_secs(10)).await; + self.shared_state + .processed_payment_transaction(ProcessedPayment::from(webhook_data)) + .await; + + Ok(()) + } + + async fn check_for_unprocessed_payments(&self) -> anyhow::Result<()> { + // 1. retrieve any unprocessed transactions + let unprocessed_transactions = self + .retrieve_unprocessed_transactions() + .await + .context("failed to retrieve unprocessed transactions")?; + + if unprocessed_transactions.is_empty() { + debug!("no payment transactions to process."); + return Ok(()); + } else { + info!( + "processing {} payment transactions", + unprocessed_transactions.len() + ); + } + + // 2. attempt to process them + for tx in unprocessed_transactions { + let hash = tx.tx_hash.clone(); + let height = tx.height; + self.process_transaction(tx).await.with_context(|| { + format!("failed to process transaction {hash} at height {height}") + })?; + } + + Ok(()) + } + + pub(crate) async fn run(&self) { + loop { + time::sleep(Duration::from_secs(10)).await; + + if let Err(err) = self.check_for_unprocessed_payments().await { + error!("failed to fully process payments: {err:#}"); + self.shared_state + .insert_listener_failure(PaymentListenerFailureDetails::new(err.to_string())) + .await; + continue; + } + + self.shared_state.update_last_checked().await; + } } } diff --git a/nyx-chain-watcher/src/payment_listener/watcher.rs b/nyx-chain-watcher/src/payment_listener/watcher.rs new file mode 100644 index 0000000000..5feddfb39b --- /dev/null +++ b/nyx-chain-watcher/src/payment_listener/watcher.rs @@ -0,0 +1,73 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::config::payments_watcher::{HttpAuthenticationOptions, PaymentWatcherConfig}; +use crate::models::WebhookPayload; +use anyhow::Context; +use reqwest::{Client, Url}; +use tracing::{error, info}; + +pub(crate) struct PaymentWatcher { + webhook_url: Url, + config: PaymentWatcherConfig, +} + +impl PaymentWatcher { + pub(crate) fn new(config: PaymentWatcherConfig) -> anyhow::Result { + Ok(PaymentWatcher { + webhook_url: config + .webhook_url + .as_str() + .parse() + .context("couldn't create payment watcher: provided webhook URL is malformed")?, + config, + }) + } + + pub(super) fn id(&self) -> &str { + &self.config.id + } + + pub(crate) async fn invoke_webhook(&self, payload: &WebhookPayload) -> anyhow::Result<()> { + let client = Client::builder() + .user_agent(format!( + "nyx-chain-watcher/{}/watcher-{}", + env!("CARGO_PKG_VERSION"), + self.config.id + )) + .build() + .context("failed to build reqwest client")?; + + let mut request_builder = client.post(self.webhook_url.clone()).json(payload); + + if let Some(auth) = &self.config.authentication { + match auth { + HttpAuthenticationOptions::AuthorizationBearerToken { token } => { + request_builder = request_builder.bearer_auth(token); + } + } + } + + match request_builder.send().await { + Ok(res) => info!( + "[watcher = {}] ✅ Webhook {} {} - tx {}, index {}", + self.config.id, + res.status(), + res.url(), + payload.transaction_hash, + payload.message_index, + ), + Err(err) => { + error!( + "[watcher = {}] ❌ Webhook {:?} {:?} error = {err}", + self.config.id, + err.status(), + err.url(), + ); + return Err(err.into()); + } + } + + Ok(()) + } +} diff --git a/nyx-chain-watcher/src/price_scraper/mod.rs b/nyx-chain-watcher/src/price_scraper/mod.rs index b0ab2676b6..6442118579 100644 --- a/nyx-chain-watcher/src/price_scraper/mod.rs +++ b/nyx-chain-watcher/src/price_scraper/mod.rs @@ -3,53 +3,74 @@ use crate::db::{ queries::price::insert_nym_prices, }; use core::str; -use tokio::task::JoinHandle; use tokio::time::Duration; use crate::db::DbPool; +use crate::http::state::PriceScraperState; const REFRESH_DELAY: Duration = Duration::from_secs(300); const FAILURE_RETRY_DELAY: Duration = Duration::from_secs(60 * 2); const COINGECKO_API_URL: &str = "https://api.coingecko.com/api/v3/simple/price?ids=nym&vs_currencies=chf,usd,eur,gbp,btc"; -pub(crate) async fn run_price_scraper(db_pool: &DbPool) -> JoinHandle<()> { - loop { - tracing::info!("Running in a loop 🏃"); - if let Err(e) = get_coingecko_prices(db_pool).await { - tracing::error!("❌ Failed to get CoinGecko prices: {e}"); - tracing::info!("Retrying in {}s...", FAILURE_RETRY_DELAY.as_secs()); - tokio::time::sleep(FAILURE_RETRY_DELAY).await; - } else { - tracing::info!("✅ Successfully fetched CoinGecko prices"); - tokio::time::sleep(REFRESH_DELAY).await; - } - } +pub(crate) struct PriceScraper { + shared_state: PriceScraperState, + db_pool: DbPool, } -async fn get_coingecko_prices(pool: &DbPool) -> anyhow::Result<()> { - tracing::info!("💰 Fetching CoinGecko prices from {}", COINGECKO_API_URL); - - let response = reqwest::get(COINGECKO_API_URL) - .await? - .json::() - .await; - - tracing::info!("Got response {:?}", response); - match response { - Ok(resp) => { - let price_record = PriceRecord { - timestamp: time::OffsetDateTime::now_utc().unix_timestamp(), - nym: resp.nym, - }; - - insert_nym_prices(pool, price_record).await?; - } - Err(e) => { - //tracing::info!("💰 CoinGecko price response: {:?}", response); - tracing::error!("Error sending request: {}", e); +impl PriceScraper { + pub(crate) fn new(shared_state: PriceScraperState, db_pool: DbPool) -> Self { + PriceScraper { + shared_state, + db_pool, } } - Ok(()) + async fn get_coingecko_prices(&self) -> anyhow::Result { + tracing::info!("💰 Fetching CoinGecko prices from {COINGECKO_API_URL}"); + + let response = reqwest::get(COINGECKO_API_URL) + .await? + .json::() + .await; + + tracing::info!("Got response {:?}", response); + match response { + Ok(resp) => { + let price_record = PriceRecord { + timestamp: time::OffsetDateTime::now_utc().unix_timestamp(), + nym: resp.nym.clone(), + }; + + insert_nym_prices(&self.db_pool, price_record).await?; + Ok(resp) + } + Err(err) => { + //tracing::info!("💰 CoinGecko price response: {:?}", response); + tracing::error!("Error sending request: {err}"); + Err(err.into()) + } + } + } + + pub(crate) async fn run(&self) { + loop { + tracing::info!("Running in a loop 🏃"); + match self.get_coingecko_prices().await { + Ok(coingecko_price_response) => { + self.shared_state + .new_success(coingecko_price_response) + .await; + tracing::info!("✅ Successfully fetched CoinGecko prices"); + tokio::time::sleep(REFRESH_DELAY).await; + } + Err(err) => { + tracing::error!("❌ Failed to get CoinGecko prices: {err}"); + tracing::info!("Retrying in {}s...", FAILURE_RETRY_DELAY.as_secs()); + self.shared_state.new_failure(err.to_string()).await; + tokio::time::sleep(FAILURE_RETRY_DELAY).await; + } + } + } + } } diff --git a/scripts/network_tunnel_manager.sh b/scripts/network_tunnel_manager.sh index 93e6f73ada..58eff34565 100644 --- a/scripts/network_tunnel_manager.sh +++ b/scripts/network_tunnel_manager.sh @@ -167,6 +167,8 @@ joke_through_tunnel() { else echo -e "${red}IPv4 connectivity is not working for $interface. verify your routing and NAT settings.${reset}" fi + else + echo -e "${red}no IPv4 address found on $interface. unable to fetch a joke via IPv4.${reset}" fi if [[ -n "$ipv6_address" ]]; then @@ -183,6 +185,8 @@ joke_through_tunnel() { else echo -e "${red}IPv6 connectivity is not working for $interface. verify your routing and NAT settings.${reset}" fi + else + echo -e "${red}no IPv6 address found on $interface. unable to fetch a joke via IPv6.${reset}" fi echo -e "${green}joke fetching processes completed for $interface.${reset}" diff --git a/sdk/rust/nym-sdk/Cargo.toml b/sdk/rust/nym-sdk/Cargo.toml index 7a50e11982..c95118cf3c 100644 --- a/sdk/rust/nym-sdk/Cargo.toml +++ b/sdk/rust/nym-sdk/Cargo.toml @@ -6,6 +6,14 @@ license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "nym-proxy-server" +path = "src/tcp_proxy/bin/proxy_server.rs" + +[[bin]] +name = "nym-proxy-client" +path = "src/tcp_proxy/bin/proxy_client.rs" + [dependencies] async-trait = { workspace = true } bip39 = { workspace = true } @@ -33,6 +41,10 @@ nym-validator-client = { path = "../../../common/client-libs/validator-client", nym-socks5-requests = { path = "../../../common/socks5/requests" } nym-ordered-buffer = { path = "../../../common/socks5/ordered-buffer" } nym-service-providers-common = { path = "../../../service-providers/common" } +nym-sphinx-addressing = { path = "../../../common/nymsphinx/addressing" } +nym-bin-common = { path = "../../../common/bin-common", features = [ + "basic_tracing", +] } bytecodec = { workspace = true } httpcodec = { workspace = true } bytes = { workspace = true } @@ -46,8 +58,10 @@ tap = { workspace = true } thiserror = { workspace = true } url = { workspace = true } toml = { workspace = true } +tempfile = { workspace = true } # tcpproxy dependencies +clap = { workspace = true, features = ["derive"] } anyhow.workspace = true dashmap.workspace = true tokio.workspace = true diff --git a/sdk/rust/nym-sdk/README.md b/sdk/rust/nym-sdk/README.md new file mode 100644 index 0000000000..16f1989414 --- /dev/null +++ b/sdk/rust/nym-sdk/README.md @@ -0,0 +1,8 @@ +# Nym Rust SDK + +This repo contains several components: +- `mixnet`: exposes Nym Client builders and methods. This is useful if you want to interact directly with the Client, or build transport abstractions. +- `tcp_proxy`: exposes functionality to set up client/server instances that expose a localhost TcpSocket to read/write to like a 'normal' socket connection. `tcp_proxy/bin/` contains standalone `nym-proxy-client` and `nym-proxy-server` binaries. +- `clientpool`: a configurable pool of ephemeral Nym Clients which can be created as a background process and quickly grabbed. + +Documentation can be found [here](https://nym.com/docs/developers/rust). diff --git a/sdk/rust/nym-sdk/examples/surb_reply.rs b/sdk/rust/nym-sdk/examples/surb_reply.rs index 926cac0314..649c8aaf7e 100644 --- a/sdk/rust/nym-sdk/examples/surb_reply.rs +++ b/sdk/rust/nym-sdk/examples/surb_reply.rs @@ -3,13 +3,14 @@ use nym_sdk::mixnet::{ StoragePaths, }; use std::path::PathBuf; +use tempfile::TempDir; #[tokio::main] async fn main() { nym_bin_common::logging::setup_logging(); // Specify some config options - let config_dir = PathBuf::from("/tmp/surb-example"); + let config_dir: PathBuf = TempDir::new().unwrap().path().to_path_buf(); let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap(); // Create the client with a storage backend, and enable it by giving it some paths. If keys diff --git a/sdk/rust/nym-sdk/src/mixnet.rs b/sdk/rust/nym-sdk/src/mixnet.rs index 6fc8cae2dc..b540aa752d 100644 --- a/sdk/rust/nym-sdk/src/mixnet.rs +++ b/sdk/rust/nym-sdk/src/mixnet.rs @@ -82,7 +82,7 @@ pub use nym_sphinx::{ pub use nym_statistics_common::clients::{ connection::ConnectionStatsEvent, ClientStatsEvents, ClientStatsSender, }; -pub use nym_task::connections::TransmissionLane; +pub use nym_task::connections::{LaneQueueLengths, TransmissionLane}; pub use nym_topology::{provider_trait::TopologyProvider, NymTopology}; pub use paths::StoragePaths; pub use socks5_client::Socks5MixnetClient; diff --git a/sdk/rust/nym-sdk/src/tcp_proxy/bin/proxy_client.rs b/sdk/rust/nym-sdk/src/tcp_proxy/bin/proxy_client.rs new file mode 100644 index 0000000000..3b6d24da1d --- /dev/null +++ b/sdk/rust/nym-sdk/src/tcp_proxy/bin/proxy_client.rs @@ -0,0 +1,54 @@ +use anyhow::Result; +use clap::Parser; +use nym_sdk::tcp_proxy; +use nym_sphinx_addressing::Recipient; + +#[derive(Parser, Debug)] +struct Args { + /// Send timeout in seconds + #[clap(long, default_value_t = 30)] + close_timeout: u64, + + /// Nym address of the NymProxyServer e.g. EjYsntVxxBJrcRugiX5VnbKMbg7gyBGSp9SLt7RgeVFV.EzRtVdHCHoP2ho3DJgKMisMQ3zHkqMtAFAW4pxsq7Y2a@Hs463Wh5LtWZU@NyAmt4trcCbNVsuUhry1wpEXpVnAAfn + #[clap(short, long)] + server_address: String, + + /// Listen address + #[clap(long, default_value = "127.0.0.1")] + listen_address: String, + + /// Listen port + #[clap(long, default_value = "8080")] + listen_port: String, + + /// Optional env filepath - if none is supplied then the proxy defaults to using mainnet else just use a path to one of the supplied files in envs/ e.g. ./envs/sandbox.env + #[clap(short, long)] + env_path: Option, + + /// How many clients to have running in reserve for quick access by incoming connections + #[clap(long, default_value_t = 2)] + client_pool_reserve: usize, +} + +#[tokio::main] +async fn main() -> Result<()> { + nym_bin_common::logging::setup_tracing_logger(); + let args = Args::parse(); + + let nym_addr: Recipient = + Recipient::try_from_base58_string(&args.server_address).expect("Invalid server address"); + + let proxy_client = tcp_proxy::NymProxyClient::new( + nym_addr, + &args.listen_address, + &args.listen_port, + args.close_timeout, + args.env_path.clone(), + args.client_pool_reserve, + ) + .await?; + + proxy_client.run().await.unwrap(); + + Ok(()) +} diff --git a/sdk/rust/nym-sdk/src/tcp_proxy/bin/proxy_server.rs b/sdk/rust/nym-sdk/src/tcp_proxy/bin/proxy_server.rs new file mode 100644 index 0000000000..44686b438a --- /dev/null +++ b/sdk/rust/nym-sdk/src/tcp_proxy/bin/proxy_server.rs @@ -0,0 +1,37 @@ +use anyhow::Result; +use clap::Parser; +use nym_sdk::tcp_proxy; + +#[derive(Parser, Debug)] +struct Args { + /// Upstream address of the server process we want to proxy traffic to e.g. 127.0.0.1:9067 + #[clap(short, long)] + upstream_tcp_address: String, + + /// Config directory + #[clap(short, long, default_value = "/tmp/nym-tcp-proxy-server")] + config_dir: String, + + /// Optional env filepath - if none is supplied then the proxy defaults to using mainnet else just use a path to one of the supplied files in envs/ e.g. ./envs/sandbox.env + #[clap(short, long)] + env_path: Option, +} + +#[tokio::main] +async fn main() -> Result<()> { + nym_bin_common::logging::setup_logging(); + + let args = Args::parse(); + + let home_dir = dirs::home_dir().expect("Unable to get home directory"); + let conf_path = format!("{}{}", home_dir.display(), args.config_dir); + + let mut proxy_server = tcp_proxy::NymProxyServer::new( + &args.upstream_tcp_address, + &conf_path, + args.env_path.clone(), + ) + .await?; + + proxy_server.run_with_shutdown().await +} diff --git a/sdk/typescript/packages/nodejs-client/yarn.lock b/sdk/typescript/packages/nodejs-client/yarn.lock index 2736c80b20..e2fdd3fe38 100644 --- a/sdk/typescript/packages/nodejs-client/yarn.lock +++ b/sdk/typescript/packages/nodejs-client/yarn.lock @@ -506,11 +506,11 @@ brace-expansion@^2.0.1: balanced-match "^1.0.0" braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" builtin-modules@^3.3.0: version "3.3.0" @@ -1215,10 +1215,10 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 207f3960c2..e62df11646 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "nym-network-requester" license = "GPL-3.0" -version = "1.1.51" +version = "1.1.52" authors.workspace = true edition.workspace = true rust-version = "1.70" diff --git a/tools/internal/validator-status-check/Cargo.toml b/tools/internal/validator-status-check/Cargo.toml new file mode 100644 index 0000000000..99eb182621 --- /dev/null +++ b/tools/internal/validator-status-check/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "validator-status-check" +version = "0.1.0" +authors.workspace = true +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +readme.workspace = true + +[dependencies] +anyhow = { workspace = true } +clap = { workspace = true, features = ["cargo", "derive"] } +comfy-table = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +strum = { workspace = true, features = ["derive"] } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +tracing = { workspace = true } +time = { workspace = true } + + +nym-validator-client = { path = "../../../common/client-libs/validator-client" } +nym-bin-common = { path = "../../../common/bin-common", features = ["output_format", "basic_tracing"] } +nym-network-defaults = { path = "../../../common/network-defaults" } + +[lints] +workspace = true diff --git a/tools/internal/validator-status-check/src/commands/build_info.rs b/tools/internal/validator-status-check/src/commands/build_info.rs new file mode 100644 index 0000000000..7b682aac12 --- /dev/null +++ b/tools/internal/validator-status-check/src/commands/build_info.rs @@ -0,0 +1,15 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use nym_bin_common::bin_info_owned; +use nym_bin_common::output_format::OutputFormat; + +#[derive(clap::Args, Debug)] +pub(crate) struct Args { + #[clap(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +pub(crate) fn execute(args: Args) { + println!("{}", args.output.format(&bin_info_owned!())) +} diff --git a/tools/internal/validator-status-check/src/commands/check_network.rs b/tools/internal/validator-status-check/src/commands/check_network.rs new file mode 100644 index 0000000000..e388e90c74 --- /dev/null +++ b/tools/internal/validator-status-check/src/commands/check_network.rs @@ -0,0 +1,73 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::helpers::{get_known_dealers, get_signer_status}; +use crate::models::SignerStatus; +use comfy_table::Table; +use nym_bin_common::output_format::OutputFormat; +use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; + +#[derive(clap::Args, Debug)] +pub(crate) struct Args { + #[clap(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +#[derive(Serialize, Deserialize)] +struct NetworkStatus { + available_api_nodes: f64, + available_rpc_nodes: f64, + detailed: Vec, +} + +impl From> for NetworkStatus { + fn from(value: Vec) -> Self { + let nodes = value.len() as f64; + let api = value.iter().filter(|s| s.api_up()).count() as f64; + let rpc = value.iter().filter(|s| s.rpc_up()).count() as f64; + + NetworkStatus { + available_api_nodes: api / nodes, + available_rpc_nodes: rpc / nodes, + detailed: value, + } + } +} + +impl Display for NetworkStatus { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "available signers: {:.2}%, available rpc nodes: {:.2}%", + self.available_api_nodes, self.available_rpc_nodes + )?; + + let mut table = Table::new(); + table.set_header(vec![ + "signer", + "api version", + "rpc status", + "rpc endpoint", + "abci version", + ]); + for signer in &self.detailed { + table.add_row(signer.to_table_row()); + } + write!(f, "{table}") + } +} + +pub(crate) async fn execute(args: Args) -> anyhow::Result<()> { + let dealers = get_known_dealers().await?; + + let mut signers = Vec::new(); + for dealer in dealers { + signers.push(get_signer_status(&dealer.announce_address).await) + } + + let out = args.output.format(&NetworkStatus::from(signers)); + println!("{out}"); + + Ok(()) +} diff --git a/tools/internal/validator-status-check/src/commands/check_signer.rs b/tools/internal/validator-status-check/src/commands/check_signer.rs new file mode 100644 index 0000000000..ee50e3ab04 --- /dev/null +++ b/tools/internal/validator-status-check/src/commands/check_signer.rs @@ -0,0 +1,21 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::helpers::get_signer_status; +use nym_bin_common::output_format::OutputFormat; + +#[derive(clap::Args, Debug)] +pub(crate) struct Args { + #[clap(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, + + /// api address of the specified signer + #[clap(long)] + signer: String, +} + +pub(crate) async fn execute(args: Args) -> anyhow::Result<()> { + let out = args.output.format(&get_signer_status(&args.signer).await); + println!("{out}"); + Ok(()) +} diff --git a/tools/internal/validator-status-check/src/commands/mod.rs b/tools/internal/validator-status-check/src/commands/mod.rs new file mode 100644 index 0000000000..abf0f5c8b1 --- /dev/null +++ b/tools/internal/validator-status-check/src/commands/mod.rs @@ -0,0 +1,51 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use clap::{Parser, Subcommand}; +use nym_bin_common::bin_info; +use std::path::PathBuf; +use std::sync::OnceLock; + +mod build_info; +mod check_network; +mod check_signer; + +fn pretty_build_info_static() -> &'static str { + static PRETTY_BUILD_INFORMATION: OnceLock = OnceLock::new(); + PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print()) +} + +#[derive(Parser, Debug)] +#[clap(author = "Nymtech", version, long_version = pretty_build_info_static(), about)] +pub struct Cli { + /// Path pointing to an env file that configures the CLI. + #[clap(short, long)] + pub(crate) config_env_file: Option, + + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +pub(crate) enum Commands { + /// Check status of an individual signer + CheckSigner(check_signer::Args), + + /// Check status of all signers + CheckNetwork(check_network::Args), + + /// Show build information of this binary + BuildInfo(build_info::Args), +} + +impl Cli { + pub async fn execute(self) -> anyhow::Result<()> { + match self.command { + Commands::CheckSigner(args) => check_signer::execute(args).await?, + Commands::CheckNetwork(args) => check_network::execute(args).await?, + Commands::BuildInfo(args) => build_info::execute(args), + } + + Ok(()) + } +} diff --git a/tools/internal/validator-status-check/src/helpers.rs b/tools/internal/validator-status-check/src/helpers.rs new file mode 100644 index 0000000000..feb4dd488e --- /dev/null +++ b/tools/internal/validator-status-check/src/helpers.rs @@ -0,0 +1,39 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::models::SignerStatus; +use anyhow::bail; +use nym_network_defaults::NymNetworkDetails; +use nym_validator_client::nyxd::contract_traits::dkg_query_client::DealerDetails; +use nym_validator_client::nyxd::contract_traits::PagedDkgQueryClient; +use nym_validator_client::nyxd::Config; +use nym_validator_client::QueryHttpRpcNyxdClient; +use tracing::info; + +async fn get_query_client() -> anyhow::Result { + let network = NymNetworkDetails::new_from_env(); + + let Some(endpoint_info) = network.endpoints.first() else { + bail!("no known rpc endpoints available") + }; + + let config = Config::try_from_nym_network_details(&network)?; + Ok(QueryHttpRpcNyxdClient::connect( + config, + endpoint_info.nyxd_url.as_str(), + )?) +} + +pub(crate) async fn get_known_dealers() -> anyhow::Result> { + let client = get_query_client().await?; + Ok(client.get_all_current_dealers().await?) +} + +pub(crate) async fn get_signer_status(raw_api_endpoint: &str) -> SignerStatus { + info!("attempting to get signer status of {raw_api_endpoint}..."); + let mut status = SignerStatus::new(raw_api_endpoint.to_string()); + + status.try_update_api_version().await; + status.try_update_rpc_status().await; + status +} diff --git a/tools/internal/validator-status-check/src/main.rs b/tools/internal/validator-status-check/src/main.rs new file mode 100644 index 0000000000..668aa5dd2b --- /dev/null +++ b/tools/internal/validator-status-check/src/main.rs @@ -0,0 +1,24 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::commands::Cli; +use clap::Parser; +use nym_bin_common::logging::setup_tracing_logger; +use nym_network_defaults::setup_env; +use tracing::trace; + +mod commands; +mod helpers; +mod models; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + trace!("args: {cli:#?}"); + + setup_env(cli.config_env_file.as_ref()); + setup_tracing_logger(); + + cli.execute().await?; + Ok(()) +} diff --git a/tools/internal/validator-status-check/src/models.rs b/tools/internal/validator-status-check/src/models.rs new file mode 100644 index 0000000000..12b8337f5d --- /dev/null +++ b/tools/internal/validator-status-check/src/models.rs @@ -0,0 +1,222 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use nym_validator_client::client::NymApiClientExt; +use nym_validator_client::NymApiClient; +use serde::{Deserialize, Serialize}; +use std::fmt::Display; +use strum::{Display, EnumProperty}; +use time::{Duration, OffsetDateTime}; +use tracing::error; + +#[derive(Serialize, Deserialize)] +pub(crate) struct SignerStatus { + api_endpoint: String, + api_version: ApiVersion, + rpc_status: RpcStatus, + used_rpc_endpoint: RpcEndpoint, + abci_version: AbciVersion, +} + +impl Display for SignerStatus { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + writeln!(f, "api_endpoint: {}", self.api_endpoint)?; + writeln!(f, "api_version: {}", self.api_version)?; + writeln!(f, "rpc_status: {}", self.rpc_status)?; + writeln!(f, "used_rpc_endpoint: {}", self.used_rpc_endpoint)?; + writeln!(f, "abci_version: {}", self.abci_version)?; + Ok(()) + } +} + +impl SignerStatus { + pub(crate) fn new(api_endpoint: String) -> Self { + SignerStatus { + api_endpoint, + api_version: Default::default(), + rpc_status: Default::default(), + used_rpc_endpoint: Default::default(), + abci_version: Default::default(), + } + } + + pub(crate) fn api_up(&self) -> bool { + matches!(self.api_version, ApiVersion::Available { .. }) + } + + pub(crate) fn rpc_up(&self) -> bool { + matches!(self.rpc_status, RpcStatus::Up) + } + + fn build_api_client(&self) -> Option { + let api_endpoint = match self.api_endpoint.as_str().parse() { + Ok(endpoint) => endpoint, + Err(err) => { + error!("{} is not a valid api endpoint: {err}", self.api_endpoint); + return None; + } + }; + + Some(NymApiClient::new(api_endpoint)) + } + + pub(crate) async fn try_update_api_version(&mut self) { + let Some(client) = self.build_api_client() else { + return; + }; + match client.nym_api.build_information().await { + Ok(build_info) => { + self.api_version = ApiVersion::Available { + version: build_info.build_version, + }; + } + Err(err) => { + error!( + "failed to retrieve build information of {}: {err}", + self.api_endpoint + ) + } + } + } + + pub(crate) async fn try_update_rpc_status(&mut self) { + let Some(client) = self.build_api_client() else { + return; + }; + + match client.nym_api.get_chain_status().await { + Ok(chain_status) => { + self.used_rpc_endpoint = RpcEndpoint(chain_status.connected_nyxd); + let last_block = + OffsetDateTime::from(chain_status.status.latest_block.block.header.time); + let now = OffsetDateTime::now_utc(); + let diff = now - last_block; + if diff < Duration::minutes(2) { + self.rpc_status = RpcStatus::Up + } else { + self.rpc_status = RpcStatus::Down + } + self.abci_version = AbciVersion::Available { + version: chain_status.status.abci.version, + } + } + Err(err) => { + error!( + "failed to retrieve chain status from {}: {err}", + self.api_endpoint + ); + } + } + } + + pub(crate) fn to_table_row(&self) -> Vec { + vec![ + self.api_endpoint.to_string(), + self.api_version.as_cell(), + self.rpc_status.as_cell(), + self.used_rpc_endpoint.as_cell(), + self.abci_version.as_cell(), + ] + } +} + +#[derive(Serialize, Deserialize, Default)] +struct RpcEndpoint(String); + +impl Display for RpcEndpoint { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.0.fmt(f) + } +} + +impl RpcEndpoint { + fn as_cell(&self) -> String { + if self.0.contains("localhost") || self.0.contains("127.0.0.1") { + format!("✅ {}", self.0) + } else if self.0.contains("nymtech") { + format!("❗ {}", self.0) + } else if self.0.is_empty() { + "⚠️ unknown".to_string() + } else { + format!("⚠️ {}", self.0) + } + } +} + +#[derive( + Clone, Default, PartialOrd, PartialEq, Ord, Eq, Display, EnumProperty, Serialize, Deserialize, +)] +#[strum(serialize_all = "snake_case")] +enum AbciVersion { + #[strum(props(emoji = "✅"))] + #[strum(to_string = "{version}")] + Available { version: String }, + + #[strum(props(emoji = "❗"))] + #[default] + Unavailable, +} + +impl AbciVersion { + // SAFETY: every variant has a `emoji` prop defined + #[allow(clippy::unwrap_used)] + fn as_cell(&self) -> String { + format!("{} {}", self.get_str("emoji").unwrap(), self) + } +} + +#[derive( + Clone, Default, PartialOrd, PartialEq, Ord, Eq, Display, EnumProperty, Serialize, Deserialize, +)] +#[strum(serialize_all = "snake_case")] +enum ApiVersion { + #[strum(props(emoji = "✅"))] + #[strum(to_string = "{version}")] + Available { version: String }, + + #[strum(props(emoji = "❗"))] + #[default] + Unavailable, +} + +impl ApiVersion { + // SAFETY: every variant has a `emoji` prop defined + #[allow(clippy::unwrap_used)] + fn as_cell(&self) -> String { + format!("{} {}", self.get_str("emoji").unwrap(), self) + } +} + +#[derive( + Copy, + Clone, + Default, + PartialOrd, + PartialEq, + Ord, + Eq, + Display, + EnumProperty, + Serialize, + Deserialize, +)] +#[strum(serialize_all = "snake_case")] +enum RpcStatus { + #[strum(props(emoji = "❗"))] + Down, + + #[strum(props(emoji = "✅"))] + Up, + + #[strum(props(emoji = "⚠️"))] + #[default] + Unknown, +} + +impl RpcStatus { + // SAFETY: every variant has a `emoji` prop defined + #[allow(clippy::unwrap_used)] + fn as_cell(&self) -> String { + format!("{} {}", self.get_str("emoji").unwrap(), self) + } +} diff --git a/tools/nym-cli/Cargo.toml b/tools/nym-cli/Cargo.toml index a9b24b4ced..8ff180c91b 100644 --- a/tools/nym-cli/Cargo.toml +++ b/tools/nym-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nym-cli" -version = "1.1.50" +version = "1.1.51" authors.workspace = true edition = "2021" license.workspace = true diff --git a/tools/nymvisor/Cargo.toml b/tools/nymvisor/Cargo.toml index 15de5e1610..4347eadd37 100644 --- a/tools/nymvisor/Cargo.toml +++ b/tools/nymvisor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nymvisor" -version = "0.1.15" +version = "0.1.16" authors.workspace = true repository.workspace = true homepage.workspace = true diff --git a/wasm/client/internal-dev/package-lock.json b/wasm/client/internal-dev/package-lock.json index ac154b841a..24a84309c8 100644 --- a/wasm/client/internal-dev/package-lock.json +++ b/wasm/client/internal-dev/package-lock.json @@ -24,8 +24,7 @@ }, "../pkg": { "name": "@nymproject/nym-client-wasm", - "version": "1.4.0-rc.0", - "license": "Apache-2.0" + "version": "1.4.0-rc.0" }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", @@ -698,9 +697,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -712,7 +711,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -815,15 +814,32 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1010,9 +1026,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", "engines": { @@ -1167,6 +1183,21 @@ "node": ">=6" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1182,9 +1213,9 @@ "license": "ISC" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -1218,6 +1249,26 @@ "node": ">=4" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -1225,6 +1276,19 @@ "dev": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1341,38 +1405,38 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1381,6 +1445,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/array-flatten": { @@ -1481,14 +1549,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1584,27 +1652,54 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -1680,6 +1775,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1718,9 +1826,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -1730,6 +1838,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hello-wasm-pack": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/hello-wasm-pack/-/hello-wasm-pack-0.1.0.tgz", @@ -2176,6 +2297,16 @@ "node": ">=8" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2200,11 +2331,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -2392,11 +2526,14 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2576,9 +2713,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true, "license": "MIT" }, @@ -2667,13 +2804,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -2979,9 +3116,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "license": "MIT", "dependencies": { @@ -3003,6 +3140,16 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3090,16 +3237,16 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -3159,15 +3306,76 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3743,9 +3951,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, "license": "MIT", "dependencies": { diff --git a/wasm/client/internal-dev/yarn.lock b/wasm/client/internal-dev/yarn.lock index f65c73527d..84f64331bc 100644 --- a/wasm/client/internal-dev/yarn.lock +++ b/wasm/client/internal-dev/yarn.lock @@ -34,7 +34,7 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@1.4.14": +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -60,7 +60,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -75,7 +75,6 @@ "@nymproject/nym-client-wasm@file:../pkg": version "1.4.0-rc.0" - resolved "file:../pkg" "@types/body-parser@*": version "1.19.2" @@ -374,7 +373,7 @@ acorn-import-assertions@^1.7.6: resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== -acorn@^8, acorn@^8.5.0, acorn@^8.7.1: +acorn@^8.5.0, acorn@^8.7.1: version "8.8.2" resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== @@ -398,7 +397,7 @@ ajv-keywords@^5.0.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.5, ajv@^6.9.1: +ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -408,7 +407,7 @@ ajv@^6.12.5, ajv@^6.9.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.8.0, ajv@^8.8.2: +ajv@^8.0.0, ajv@^8.8.0: version "8.12.0" resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -431,16 +430,16 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -array-flatten@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -456,10 +455,10 @@ binary-extensions@^2.0.0: resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -469,7 +468,7 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -499,7 +498,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, "browserslist@>= 4.21.0": +browserslist@^4.14.5: version "4.21.5" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== @@ -524,13 +523,21 @@ bytes@3.1.2: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.0: +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" caniuse-lite@^1.0.30001449: version "1.0.30001474" @@ -628,10 +635,10 @@ cookie-signature@1.0.6: resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== copy-webpack-plugin@^11.0.0: version "11.0.0" @@ -659,13 +666,6 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -673,6 +673,13 @@ debug@2.6.9: dependencies: ms "2.0.0" +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + default-gateway@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz" @@ -685,16 +692,16 @@ define-lazy-prop@^2.0.0: resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + destroy@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" @@ -724,6 +731,15 @@ dns-packet@^5.2.2: dependencies: "@leichtgewicht/ip-codec" "^2.0.1" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" @@ -739,6 +755,11 @@ encodeurl@~1.0.2: resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + enhanced-resolve@^5.10.0: version "5.12.0" resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz" @@ -752,11 +773,28 @@ envinfo@^7.7.3: resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz" integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" @@ -823,36 +861,36 @@ execa@^5.0.0: strip-final-newline "^2.0.0" express@^4.17.3: - version "4.19.2" - resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.6.0" + cookie "0.7.1" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.12" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -906,13 +944,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -952,26 +990,51 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -get-intrinsic@^1.0.2: - version "1.2.0" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" get-stream@^6.0.0: version "6.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -985,13 +1048,6 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" @@ -1020,6 +1076,11 @@ globby@^13.1.1: merge2 "^1.4.1" slash "^4.0.0" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" @@ -1035,10 +1096,10 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== has@^1.0.3: version "1.0.3" @@ -1047,6 +1108,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + hello-wasm-pack@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/hello-wasm-pack/-/hello-wasm-pack-0.1.0.tgz" @@ -1072,16 +1140,6 @@ http-deceiver@^1.2.7: resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz" integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" - integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -1093,6 +1151,16 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + http-parser-js@>=0.5.1: version "0.5.8" resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz" @@ -1151,7 +1219,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1166,16 +1234,16 @@ interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" @@ -1300,6 +1368,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" @@ -1312,10 +1385,10 @@ memfs@^3.4.3: dependencies: fs-monkey "^1.0.3" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -1340,7 +1413,7 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -1429,10 +1502,10 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" @@ -1526,10 +1599,10 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== path-type@^4.0.0: version "4.0.0" @@ -1571,12 +1644,12 @@ punycode@^2.1.0: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" queue-microtask@^1.2.2: version "1.2.3" @@ -1696,36 +1769,22 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.1.0, safe-buffer@>=5.1.0, safe-buffer@~5.2.0, safe-buffer@5.2.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -schema-utils@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.1.1: +schema-utils@^3.1.0, schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== @@ -1756,10 +1815,10 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" -send@0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -1795,15 +1854,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" setprototypeof@1.1.0: version "1.1.0" @@ -1839,14 +1898,45 @@ shell-quote@^1.7.3: resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz" integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.0.6: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" signal-exit@^3.0.3: version "3.0.7" @@ -1903,16 +1993,16 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -1995,7 +2085,7 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -2050,7 +2140,7 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -webpack-cli@^4.9.2, webpack-cli@4.x.x: +webpack-cli@^4.9.2: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -2069,9 +2159,9 @@ webpack-cli@^4.9.2, webpack-cli@4.x.x: webpack-merge "^5.7.3" webpack-dev-middleware@^5.3.1: - version "5.3.3" - resolved "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz" - integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== dependencies: colorette "^2.0.10" memfs "^3.4.3" @@ -2128,7 +2218,7 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -"webpack@^4.0.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", webpack@^5.1.0, webpack@^5.70.0, "webpack@4.x.x || 5.x.x": +webpack@^5.70.0: version "5.77.0" resolved "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz" integrity sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q== @@ -2158,7 +2248,7 @@ webpack-sources@^3.2.3: watchpack "^2.4.0" webpack-sources "^3.2.3" -websocket-driver@^0.7.4, websocket-driver@>=0.5.1: +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz" integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== diff --git a/wasm/mix-fetch/internal-dev/package-lock.json b/wasm/mix-fetch/internal-dev/package-lock.json index cdf4937a9e..596dca6c6f 100644 --- a/wasm/mix-fetch/internal-dev/package-lock.json +++ b/wasm/mix-fetch/internal-dev/package-lock.json @@ -18,16 +18,18 @@ "devDependencies": { "copy-webpack-plugin": "^11.0.0", "hello-wasm-pack": "^0.1.0", - "webpack": "^5.70.0", + "webpack": "^5.98.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.7.4" } }, - "../go-mix-conn/build": {}, + "../go-mix-conn/build": { + "name": "go-mix-conn", + "version": "0.0.1" + }, "../pkg": { "name": "@nymproject/mix-fetch-wasm", - "version": "1.2.2", - "license": "Apache-2.0" + "version": "1.2.2" }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", @@ -40,24 +42,24 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -65,9 +67,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", "engines": { @@ -75,32 +77,32 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@leichtgewicht/ip-codec": { @@ -195,9 +197,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", "dependencies": { @@ -206,9 +208,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "license": "MIT", "dependencies": { @@ -217,9 +219,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, @@ -342,73 +344,73 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "license": "MIT", "dependencies": { @@ -416,9 +418,9 @@ } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -426,79 +428,79 @@ } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -570,9 +572,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "license": "MIT", "bin": { @@ -582,16 +584,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -699,9 +691,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -713,7 +705,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -771,9 +763,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { @@ -783,14 +775,18 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -816,24 +812,41 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001474", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz", - "integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==", + "version": "1.0.30001703", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001703.tgz", + "integrity": "sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==", "dev": true, "funding": [ { @@ -1011,9 +1024,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", "engines": { @@ -1168,6 +1181,21 @@ "node": ">=6" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1176,16 +1204,16 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.352", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.352.tgz", - "integrity": "sha512-ikFUEyu5/q+wJpMOxWxTaEVk2M1qKqTGKKyfJmod1CPZxKfYnxVS41/GCBQg21ItBpZybyN8sNpRqCUGm+Zc4Q==", + "version": "1.5.114", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.114.tgz", + "integrity": "sha512-DFptFef3iktoKlFQK/afbo274/XNWD00Am0xa7M8FZUepHlHT8PEuiNBoRfFHbH1okqN58AlhbJ4QTkcnXorjA==", "dev": true, "license": "ISC" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -1193,9 +1221,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", "dev": true, "license": "MIT", "dependencies": { @@ -1219,17 +1247,50 @@ "node": ">=4" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", "dev": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -1342,38 +1403,38 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1382,6 +1443,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/array-flatten": { @@ -1428,13 +1493,6 @@ "node": ">= 6" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -1482,14 +1540,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1570,27 +1628,54 @@ "license": "ISC" }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -1669,6 +1754,19 @@ "resolved": "../go-mix-conn/build", "link": true }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1707,9 +1805,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -1719,6 +1817,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hello-wasm-pack": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/hello-wasm-pack/-/hello-wasm-pack-0.1.0.tgz", @@ -2164,6 +2275,16 @@ "node": ">=8" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2188,11 +2309,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -2350,9 +2474,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, "license": "MIT" }, @@ -2380,11 +2504,14 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2564,9 +2691,9 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true, "license": "MIT" }, @@ -2581,9 +2708,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -2655,13 +2782,13 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -2926,19 +3053,19 @@ "license": "MIT" }, "node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", "dev": true, "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", + "ajv": "^8.9.0", "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", @@ -2966,9 +3093,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "license": "MIT", "dependencies": { @@ -2990,6 +3117,16 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2998,9 +3135,9 @@ "license": "MIT" }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -3077,16 +3214,16 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -3146,15 +3283,76 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3365,14 +3563,14 @@ } }, "node_modules/terser": { - "version": "5.16.8", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz", - "integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==", + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -3384,17 +3582,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -3418,59 +3616,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -3526,9 +3671,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -3538,15 +3683,19 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -3600,9 +3749,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dev": true, "license": "MIT", "dependencies": { @@ -3624,35 +3773,34 @@ } }, "node_modules/webpack": { - "version": "5.77.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", - "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "version": "5.98.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", + "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^4.3.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -3837,59 +3985,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -3946,9 +4041,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "dev": true, "license": "MIT", "engines": { diff --git a/wasm/mix-fetch/internal-dev/package.json b/wasm/mix-fetch/internal-dev/package.json index 439def5de3..1e813770d9 100644 --- a/wasm/mix-fetch/internal-dev/package.json +++ b/wasm/mix-fetch/internal-dev/package.json @@ -30,7 +30,7 @@ "devDependencies": { "copy-webpack-plugin": "^11.0.0", "hello-wasm-pack": "^0.1.0", - "webpack": "^5.70.0", + "webpack": "^5.98.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.7.4" }, diff --git a/wasm/mix-fetch/internal-dev/yarn.lock b/wasm/mix-fetch/internal-dev/yarn.lock index bc06468f0a..c9e1578198 100644 --- a/wasm/mix-fetch/internal-dev/yarn.lock +++ b/wasm/mix-fetch/internal-dev/yarn.lock @@ -7,45 +7,50 @@ resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.2" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== dependencies: - "@jridgewell/set-array" "^1.0.1" + "@jridgewell/set-array" "^1.2.1" "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== +"@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" @@ -60,7 +65,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -75,7 +80,6 @@ "@nymproject/mix-fetch-wasm@file:../pkg": version "1.2.2" - resolved "file:../pkg" "@types/body-parser@*": version "1.19.2" @@ -107,10 +111,10 @@ dependencies: "@types/node" "*" -"@types/eslint-scope@^3.7.3": - version "3.7.4" - resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz" - integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== +"@types/eslint-scope@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== dependencies: "@types/eslint" "*" "@types/estree" "*" @@ -123,10 +127,10 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^0.0.51": - version "0.0.51" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/estree@*", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": version "4.17.33" @@ -154,7 +158,7 @@ dependencies: "@types/node" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== @@ -213,125 +217,125 @@ dependencies: "@types/node" "*" -"@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== +"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" + integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-numbers" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" -"@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== +"@webassemblyjs/floating-point-hex-parser@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb" + integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA== -"@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== +"@webassemblyjs/helper-api-error@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7" + integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ== -"@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== +"@webassemblyjs/helper-buffer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b" + integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA== -"@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== +"@webassemblyjs/helper-numbers@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d" + integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/floating-point-hex-parser" "1.13.2" + "@webassemblyjs/helper-api-error" "1.13.2" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== +"@webassemblyjs/helper-wasm-bytecode@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b" + integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA== -"@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== +"@webassemblyjs/helper-wasm-section@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348" + integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/wasm-gen" "1.14.1" -"@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== +"@webassemblyjs/ieee754@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba" + integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== +"@webassemblyjs/leb128@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0" + integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== +"@webassemblyjs/utf8@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" + integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== -"@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== +"@webassemblyjs/wasm-edit@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" + integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/helper-wasm-section" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-opt" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + "@webassemblyjs/wast-printer" "1.14.1" -"@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== +"@webassemblyjs/wasm-gen@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570" + integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" -"@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== +"@webassemblyjs/wasm-opt@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b" + integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" -"@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== +"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" + integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-api-error" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + "@webassemblyjs/ieee754" "1.13.2" + "@webassemblyjs/leb128" "1.13.2" + "@webassemblyjs/utf8" "1.13.2" -"@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== +"@webassemblyjs/wast-printer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07" + integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw== dependencies: - "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/ast" "1.14.1" "@xtuc/long" "4.2.2" "@webpack-cli/configtest@^1.2.0": @@ -369,15 +373,10 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== - -acorn@^8, acorn@^8.5.0, acorn@^8.7.1: - version "8.8.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.14.0, acorn@^8.8.2: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== ajv-formats@^2.1.1: version "2.1.1" @@ -386,29 +385,14 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv-keywords@^5.0.0: +ajv-keywords@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz" integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.5, ajv@^6.9.1: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.0, ajv@^8.8.0, ajv@^8.8.2: +ajv@^8.0.0: version "8.12.0" resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -418,6 +402,16 @@ ajv@^8.0.0, ajv@^8.8.0, ajv@^8.8.2: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ansi-html-community@^0.0.8: version "0.0.8" resolved "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz" @@ -431,16 +425,16 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -array-flatten@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +array-flatten@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -456,10 +450,10 @@ binary-extensions@^2.0.0: resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -469,7 +463,7 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -499,15 +493,15 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.14.5, "browserslist@>= 4.21.0": - version "4.21.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== +browserslist@^4.24.0: + version "4.24.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" buffer-from@^1.0.0: version "1.1.2" @@ -524,18 +518,26 @@ bytes@3.1.2: resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -call-bind@^1.0.0: +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-errors "^1.3.0" + function-bind "^1.1.2" -caniuse-lite@^1.0.30001449: - version "1.0.30001474" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz" - integrity sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q== +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +caniuse-lite@^1.0.30001688: + version "1.0.30001703" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001703.tgz#977cb4920598c158f491ecf4f4f2cfed9e354718" + integrity sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ== chokidar@^3.5.3: version "3.5.3" @@ -628,10 +630,10 @@ cookie-signature@1.0.6: resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== copy-webpack-plugin@^11.0.0: version "11.0.0" @@ -659,13 +661,6 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -debug@^4.1.0: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -673,6 +668,13 @@ debug@2.6.9: dependencies: ms "2.0.0" +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + default-gateway@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz" @@ -685,16 +687,16 @@ define-lazy-prop@^2.0.0: resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + destroy@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" @@ -724,25 +726,39 @@ dns-packet@^5.2.2: dependencies: "@leichtgewicht/ip-codec" "^2.0.1" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.284: - version "1.4.352" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.352.tgz" - integrity sha512-ikFUEyu5/q+wJpMOxWxTaEVk2M1qKqTGKKyfJmod1CPZxKfYnxVS41/GCBQg21ItBpZybyN8sNpRqCUGm+Zc4Q== +electron-to-chromium@^1.5.73: + version "1.5.114" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.114.tgz#f2bb4fda80a7db4ea273565e75b0ebbe19af0ac3" + integrity sha512-DFptFef3iktoKlFQK/afbo274/XNWD00Am0xa7M8FZUepHlHT8PEuiNBoRfFHbH1okqN58AlhbJ4QTkcnXorjA== encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -enhanced-resolve@^5.10.0: - version "5.12.0" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz" - integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +enhanced-resolve@^5.17.1: + version "5.18.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" + integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -752,15 +768,32 @@ envinfo@^7.7.3: resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== -es-module-lexer@^0.9.0: - version "0.9.3" - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz" - integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.6.0.tgz#da49f587fd9e68ee2404fe4e256c0c7d3a81be21" + integrity sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" @@ -823,36 +856,36 @@ execa@^5.0.0: strip-final-newline "^2.0.0" express@^4.17.3: - version "4.19.2" - resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.6.0" + cookie "0.7.1" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.12" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -875,10 +908,10 @@ fast-glob@^3.2.11, fast-glob@^3.3.0: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== fastest-levenshtein@^1.0.12: version "1.0.16" @@ -906,13 +939,13 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -952,26 +985,51 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -get-intrinsic@^1.0.2: - version "1.2.0" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" get-stream@^6.0.0: version "6.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -985,13 +1043,6 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" @@ -1021,9 +1072,14 @@ globby@^13.1.1: slash "^4.0.0" "go-mix-conn@file:../go-mix-conn/build": - resolved "file:../go-mix-conn/build" + version "0.0.1" -graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -1038,10 +1094,10 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== has@^1.0.3: version "1.0.3" @@ -1050,6 +1106,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + hello-wasm-pack@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/hello-wasm-pack/-/hello-wasm-pack-0.1.0.tgz" @@ -1075,16 +1138,6 @@ http-deceiver@^1.2.7: resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz" integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" - integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -1096,6 +1149,16 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + http-parser-js@>=0.5.1: version "0.5.8" resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz" @@ -1154,7 +1217,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3, inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1169,16 +1232,16 @@ interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" @@ -1268,11 +1331,6 @@ json-parse-even-better-errors@^2.3.1: resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - json-schema-traverse@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" @@ -1303,6 +1361,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" @@ -1315,10 +1378,10 @@ memfs@^3.4.3: dependencies: fs-monkey "^1.0.3" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -1343,7 +1406,7 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -1415,10 +1478,10 @@ node-forge@^1: resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -1432,10 +1495,10 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" @@ -1529,10 +1592,10 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== path-type@^4.0.0: version "4.0.0" @@ -1544,6 +1607,11 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" @@ -1574,12 +1642,12 @@ punycode@^2.1.0: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" queue-microtask@^1.2.2: version "1.2.3" @@ -1699,53 +1767,30 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.1.0, safe-buffer@>=5.1.0, safe-buffer@~5.2.0, safe-buffer@5.2.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -schema-utils@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz" - integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== +schema-utils@^4.0.0, schema-utils@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.3.0.tgz#3b669f04f71ff2dfb5aba7ce2d5a9d79b35622c0" + integrity sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g== dependencies: "@types/json-schema" "^7.0.9" - ajv "^8.8.0" + ajv "^8.9.0" ajv-formats "^2.1.1" - ajv-keywords "^5.0.0" + ajv-keywords "^5.1.0" select-hose@^2.0.0: version "2.0.0" @@ -1759,10 +1804,10 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" -send@0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -1778,13 +1823,20 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: +serialize-javascript@^6.0.0: version "6.0.1" resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz" integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== dependencies: randombytes "^2.1.0" +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz" @@ -1798,15 +1850,15 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" setprototypeof@1.1.0: version "1.1.0" @@ -1842,14 +1894,45 @@ shell-quote@^1.7.3: resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz" integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.0.6: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" signal-exit@^3.0.3: version "3.0.7" @@ -1906,16 +1989,16 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -1952,24 +2035,24 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser-webpack-plugin@^5.1.3: - version "5.3.7" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz" - integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw== +terser-webpack-plugin@^5.3.11: + version "5.3.14" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz#9031d48e57ab27567f02ace85c7d690db66c3e06" + integrity sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw== dependencies: - "@jridgewell/trace-mapping" "^0.3.17" + "@jridgewell/trace-mapping" "^0.3.25" jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.16.5" + schema-utils "^4.3.0" + serialize-javascript "^6.0.2" + terser "^5.31.1" -terser@^5.16.5: - version "5.16.8" - resolved "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz" - integrity sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA== +terser@^5.31.1: + version "5.39.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.39.0.tgz#0e82033ed57b3ddf1f96708d123cca717d86ca3a" + integrity sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw== dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" source-map-support "~0.5.20" @@ -1998,18 +2081,18 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.10: - version "1.0.10" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== +update-browserslist-db@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.1" uri-js@^4.2.2: version "4.4.1" @@ -2038,10 +2121,10 @@ vary@~1.1.2: resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -2053,7 +2136,7 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -webpack-cli@^4.9.2, webpack-cli@4.x.x: +webpack-cli@^4.9.2: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -2131,37 +2214,36 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -"webpack@^4.0.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", webpack@^5.1.0, webpack@^5.70.0, "webpack@4.x.x || 5.x.x": - version "5.77.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz" - integrity sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q== +webpack@^5.98.0: + version "5.98.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.98.0.tgz#44ae19a8f2ba97537978246072fb89d10d1fbd17" + integrity sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA== dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^0.0.51" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - acorn "^8.7.1" - acorn-import-assertions "^1.7.6" - browserslist "^4.14.5" + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.6" + "@webassemblyjs/ast" "^1.14.1" + "@webassemblyjs/wasm-edit" "^1.14.1" + "@webassemblyjs/wasm-parser" "^1.14.1" + acorn "^8.14.0" + browserslist "^4.24.0" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.10.0" - es-module-lexer "^0.9.0" + enhanced-resolve "^5.17.1" + es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" + graceful-fs "^4.2.11" json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.1.0" + schema-utils "^4.3.0" tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" - watchpack "^2.4.0" + terser-webpack-plugin "^5.3.11" + watchpack "^2.4.1" webpack-sources "^3.2.3" -websocket-driver@^0.7.4, websocket-driver@>=0.5.1: +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: version "0.7.4" resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz" integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== @@ -2193,6 +2275,6 @@ wrappy@1: integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@^8.13.0: - version "8.13.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + version "8.18.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== diff --git a/wasm/zknym-lib/internal-dev/yarn.lock b/wasm/zknym-lib/internal-dev/yarn.lock index 73b5db4071..a6b1fe07cb 100644 --- a/wasm/zknym-lib/internal-dev/yarn.lock +++ b/wasm/zknym-lib/internal-dev/yarn.lock @@ -497,11 +497,11 @@ brace-expansion@^1.1.7: concat-map "0.0.1" braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.14.5: version "4.21.5" @@ -903,10 +903,10 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2057,9 +2057,9 @@ webpack-cli@^4.9.2: webpack-merge "^5.7.3" webpack-dev-middleware@^5.3.1: - version "5.3.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" - integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== dependencies: colorette "^2.0.10" memfs "^3.4.3" diff --git a/yarn.lock b/yarn.lock index 7f26c95e1c..fd515a7129 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35,6 +35,15 @@ "@babel/highlight" "^7.24.2" picocolors "^1.0.0" +"@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" @@ -273,11 +282,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + "@babel/helper-validator-option@^7.23.5": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" @@ -293,13 +312,12 @@ "@babel/types" "^7.22.19" "@babel/helpers@^7.12.5", "@babel/helpers@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.4.tgz#dc00907fd0d95da74563c142ef4cd21f2cb856b6" - integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.10.tgz#6baea3cd62ec2d0c1068778d63cb1314f6637384" + integrity sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g== dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" + "@babel/template" "^7.26.9" + "@babel/types" "^7.26.10" "@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2": version "7.24.2" @@ -316,6 +334,13 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== +"@babel/parser@^7.26.9": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749" + integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA== + dependencies: + "@babel/types" "^7.26.10" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz#6125f0158543fb4edf1c22f322f3db67f21cb3e1" @@ -1242,6 +1267,15 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" +"@babel/template@^7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2" + integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/parser" "^7.26.9" + "@babel/types" "^7.26.9" + "@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.24.1", "@babel/traverse@^7.7.2": version "7.24.1" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" @@ -1267,6 +1301,14 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.26.10", "@babel/types@^7.26.9": + version "7.26.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259" + integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@base2/pretty-print-object@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz#371ba8be66d556812dc7fb169ebc3c08378f69d4"