diff --git a/.changeset/eighty-news-peel.md b/.changeset/eighty-news-peel.md new file mode 100644 index 0000000..0fc995f --- /dev/null +++ b/.changeset/eighty-news-peel.md @@ -0,0 +1,5 @@ +--- +'@rosen-bridge/rosenet-node': minor +--- + +Add `getDiscoveredPeers` to public APIs for gettting a list of discovered peer ids diff --git a/.changeset/lazy-laws-shout.md b/.changeset/lazy-laws-shout.md new file mode 100644 index 0000000..f1aeb88 --- /dev/null +++ b/.changeset/lazy-laws-shout.md @@ -0,0 +1,5 @@ +--- +'@rosen-bridge/rosenet-utils': minor +--- + +Add `readPrivateKeyFromFile` utility function for the management of a RoseNet private key in a file diff --git a/.changeset/seven-carrots-refuse.md b/.changeset/seven-carrots-refuse.md new file mode 100644 index 0000000..520d009 --- /dev/null +++ b/.changeset/seven-carrots-refuse.md @@ -0,0 +1,5 @@ +--- +"@rosen-bridge/rosenet-node": patch +--- + +Change level of peer id log to info diff --git a/.changeset/sweet-cars-cross.md b/.changeset/sweet-cars-cross.md new file mode 100644 index 0000000..a845151 --- /dev/null +++ b/.changeset/sweet-cars-cross.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/tough-insects-behave.md b/.changeset/tough-insects-behave.md new file mode 100644 index 0000000..5267966 --- /dev/null +++ b/.changeset/tough-insects-behave.md @@ -0,0 +1,5 @@ +--- +'@rosen-bridge/rosenet-node': patch +--- + +Fix failing dials when nodes are behind a non-symmetric NAT diff --git a/.dockerignore b/.dockerignore index fb0c88b..61de704 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,7 @@ **/node_modules **/coverage **/.terraform +.git +.gitignore +*.md +**/Dockerfile diff --git a/package-lock.json b/package-lock.json index 51f3042..f792839 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1167,11 +1167,18 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -1183,12 +1190,21 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -1651,6 +1667,11 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@influxdata/influxdb-client": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@influxdata/influxdb-client/-/influxdb-client-1.35.0.tgz", + "integrity": "sha512-woWMi8PDpPQpvTsRaUw4Ig+nOGS/CWwAwS66Fa1Vr/EkW+NEwxI8YfPBsdBMn33jK2Y86/qMiiuX/ROHIkJLTw==" + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1690,7 +1711,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1707,8 +1727,7 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.22", @@ -2188,6 +2207,201 @@ "multiformats": "^13.0.0" } }, + "node_modules/@napi-rs/snappy-android-arm-eabi": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm-eabi/-/snappy-android-arm-eabi-7.2.2.tgz", + "integrity": "sha512-H7DuVkPCK5BlAr1NfSU8bDEN7gYs+R78pSHhDng83QxRnCLmVIZk33ymmIwurmoA1HrdTxbkbuNl+lMvNqnytw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-android-arm64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm64/-/snappy-android-arm64-7.2.2.tgz", + "integrity": "sha512-2R/A3qok+nGtpVK8oUMcrIi5OMDckGYNoBLFyli3zp8w6IArPRfg1yOfVUcHvpUDTo9T7LOS1fXgMOoC796eQw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-darwin-arm64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.2.2.tgz", + "integrity": "sha512-USgArHbfrmdbuq33bD5ssbkPIoT7YCXCRLmZpDS6dMDrx+iM7eD2BecNbOOo7/v1eu6TRmQ0xOzeQ6I/9FIi5g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-darwin-x64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-x64/-/snappy-darwin-x64-7.2.2.tgz", + "integrity": "sha512-0APDu8iO5iT0IJKblk2lH0VpWSl9zOZndZKnBYIc+ei1npw2L5QvuErFOTeTdHBtzvUHASB+9bvgaWnQo4PvTQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-freebsd-x64": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-freebsd-x64/-/snappy-freebsd-x64-7.2.2.tgz", + "integrity": "sha512-mRTCJsuzy0o/B0Hnp9CwNB5V6cOJ4wedDTWEthsdKHSsQlO7WU9W1yP7H3Qv3Ccp/ZfMyrmG98Ad7u7lG58WXA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm-gnueabihf": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm-gnueabihf/-/snappy-linux-arm-gnueabihf-7.2.2.tgz", + "integrity": "sha512-v1uzm8+6uYjasBPcFkv90VLZ+WhLzr/tnfkZ/iD9mHYiULqkqpRuC8zvc3FZaJy5wLQE9zTDkTJN1IvUcZ+Vcg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm64-gnu": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-gnu/-/snappy-linux-arm64-gnu-7.2.2.tgz", + "integrity": "sha512-LrEMa5pBScs4GXWOn6ZYXfQ72IzoolZw5txqUHVGs8eK4g1HR9HTHhb2oY5ySNaKakG5sOgMsb1rwaEnjhChmQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-arm64-musl": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-musl/-/snappy-linux-arm64-musl-7.2.2.tgz", + "integrity": "sha512-3orWZo9hUpGQcB+3aTLW7UFDqNCQfbr0+MvV67x8nMNYj5eAeUtMmUE/HxLznHO4eZ1qSqiTwLbVx05/Socdlw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-x64-gnu": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-gnu/-/snappy-linux-x64-gnu-7.2.2.tgz", + "integrity": "sha512-jZt8Jit/HHDcavt80zxEkDpH+R1Ic0ssiVCoueASzMXa7vwPJeF4ZxZyqUw4qeSy7n8UUExomu8G8ZbP6VKhgw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-linux-x64-musl": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-musl/-/snappy-linux-x64-musl-7.2.2.tgz", + "integrity": "sha512-Dh96IXgcZrV39a+Tej/owcd9vr5ihiZ3KRix11rr1v0MWtVb61+H1GXXlz6+Zcx9y8jM1NmOuiIuJwkV4vZ4WA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-arm64-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-arm64-msvc/-/snappy-win32-arm64-msvc-7.2.2.tgz", + "integrity": "sha512-9No0b3xGbHSWv2wtLEn3MO76Yopn1U2TdemZpCaEgOGccz1V+a/1d16Piz3ofSmnA13HGFz3h9NwZH9EOaIgYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-ia32-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-ia32-msvc/-/snappy-win32-ia32-msvc-7.2.2.tgz", + "integrity": "sha512-QiGe+0G86J74Qz1JcHtBwM3OYdTni1hX1PFyLRo3HhQUSpmi13Bzc1En7APn+6Pvo7gkrcy81dObGLDSxFAkQQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/snappy-win32-x64-msvc": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz", + "integrity": "sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@noble/curves": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.5.0.tgz", @@ -2242,6 +2456,60 @@ "node": ">= 8" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.9.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", @@ -2411,6 +2679,11 @@ "win32" ] }, + "node_modules/@rosen-bridge/abstract-logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rosen-bridge/abstract-logger/-/abstract-logger-2.0.1.tgz", + "integrity": "sha512-GC2TpPxrDRkwJvhBVdaQCrkkUkp1DwwzCGT2akUv6HKfHijrNMv9BVus9ia7mv//Cy4zJCq0yw9N1n48lD2aOg==" + }, "node_modules/@rosen-bridge/changeset-formatter": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@rosen-bridge/changeset-formatter/-/changeset-formatter-0.1.0.tgz", @@ -2420,6 +2693,17 @@ "node": ">=20.11.0" } }, + "node_modules/@rosen-bridge/json-bigint": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@rosen-bridge/json-bigint/-/json-bigint-0.1.0.tgz", + "integrity": "sha512-38+N0/rxjyO57MOdDJHaq+4F0H9X0Pom/qyG7zMkdWN2fTtoWg++BmKZL7Cm5CH8QgX2w+6SqdLoEVC0AWTD0g==", + "dependencies": { + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/@rosen-bridge/logger-interface": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@rosen-bridge/logger-interface/-/logger-interface-0.2.0.tgz", @@ -2438,6 +2722,25 @@ "resolved": "packages/utils", "link": true }, + "node_modules/@rosen-bridge/winston-logger": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rosen-bridge/winston-logger/-/winston-logger-1.0.2.tgz", + "integrity": "sha512-ihPjybyjZSheYCYOij0M7i+lMyFxvXCAF9qLAUi4Ih2WIiWX8fyTbwcfZ5nt3oVIHUZt9jHgqFgwaSylrEvB/Q==", + "dependencies": { + "@rosen-bridge/abstract-logger": "^2.0.1", + "@rosen-bridge/json-bigint": "^0.1.0", + "winston": "^3.10.0", + "winston-daily-rotate-file": "^4.7.1", + "winston-loki": "^6.0.7" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@rosenet-tests/global": { + "resolved": "tests/global", + "link": true + }, "node_modules/@rosenet-tests/scale": { "resolved": "tests/scale", "link": true @@ -2484,26 +2787,41 @@ "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/dns-packet": { "version": "5.6.5", @@ -2519,11 +2837,41 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/express": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", + "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "node_modules/@types/http-cache-semantics": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -2543,11 +2891,20 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==", + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz", + "integrity": "sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==", "dev": true }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/lodash.merge": { "version": "4.6.9", "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz", @@ -2557,6 +2914,12 @@ "@types/lodash": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, "node_modules/@types/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", @@ -2582,12 +2945,45 @@ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, + "node_modules/@types/qs": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, "node_modules/@types/sinon": { "version": "17.0.3", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", @@ -2601,6 +2997,11 @@ "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==" }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz", @@ -2940,11 +3341,21 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -2965,7 +3376,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -3066,8 +3476,7 @@ "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "node_modules/argparse": { "version": "2.0.1", @@ -3175,6 +3584,19 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -3220,7 +3642,15 @@ "is-windows": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">=4" + } + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" } }, "node_modules/brace-expansion": { @@ -3284,6 +3714,17 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -3342,14 +3783,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3570,6 +4016,15 @@ "node": ">=16" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -3583,9 +4038,30 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, "node_modules/colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -3594,6 +4070,15 @@ "node": ">=0.1.90" } }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/commander": { "version": "9.4.1", "dev": true, @@ -3616,8 +4101,7 @@ "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -3805,17 +4289,20 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-properties": { @@ -3867,7 +4354,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, "engines": { "node": ">=0.3.1" } @@ -3953,6 +4439,11 @@ "dev": true, "license": "MIT" }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -4033,6 +4524,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "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, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", @@ -4328,11 +4840,27 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -4416,8 +4944,7 @@ "node_modules/extensionless": { "version": "1.9.6", "resolved": "https://registry.npmjs.org/extensionless/-/extensionless-1.9.6.tgz", - "integrity": "sha512-40F6zThJu1MxaT1A1pJ/2SHlU1BPYYnQNHt0j2ZlPuxxm2ddMcNc1D7uS/LGc4K3VwMEMaZLkCdHWaKk0LnQXA==", - "dev": true + "integrity": "sha512-40F6zThJu1MxaT1A1pJ/2SHlU1BPYYnQNHt0j2ZlPuxxm2ddMcNc1D7uS/LGc4K3VwMEMaZLkCdHWaKk0LnQXA==" }, "node_modules/external-editor": { "version": "3.1.0", @@ -4482,6 +5009,11 @@ "reusify": "^1.0.4" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "dev": true, @@ -4493,6 +5025,14 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-stream-rotator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz", + "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==", + "dependencies": { + "moment": "^2.29.1" + } + }, "node_modules/fill-range": { "version": "7.0.1", "dev": true, @@ -4546,6 +5086,11 @@ "dev": true, "license": "ISC" }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -4660,16 +5205,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4867,12 +5416,12 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5090,7 +5639,6 @@ }, "node_modules/inherits": { "version": "2.0.4", - "dev": true, "license": "ISC" }, "node_modules/interface-datastore": { @@ -5734,6 +6282,14 @@ "node": ">=4" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5776,7 +6332,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -5825,6 +6380,11 @@ "node": ">=6" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -6118,6 +6678,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "license": "MIT" @@ -6200,6 +6765,22 @@ "node": ">=8" } }, + "node_modules/logform": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/long": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", @@ -6277,8 +6858,7 @@ "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "node_modules/map-obj": { "version": "4.3.0", @@ -6417,7 +6997,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6457,6 +7036,14 @@ "ufo": "^1.3.2" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/mortice": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/mortice/-/mortice-3.0.4.tgz", @@ -6469,7 +7056,6 @@ }, "node_modules/ms": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/multiformats": { @@ -6589,6 +7175,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -6642,6 +7236,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/onetime": { "version": "5.1.2", "dev": true, @@ -7101,6 +7703,14 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/progress-events": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.0.tgz", @@ -7110,6 +7720,29 @@ "npm": ">=7.0.0" } }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/protons-runtime": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.4.0.tgz", @@ -7411,6 +8044,19 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -7627,6 +8273,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", @@ -7644,6 +8309,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7671,16 +8344,17 @@ "dev": true }, "node_modules/set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "dependencies": { - "define-data-property": "^1.1.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7720,14 +8394,18 @@ } }, "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.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7744,6 +8422,19 @@ "dev": true, "license": "ISC" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7933,6 +8624,34 @@ "node": ">=8" } }, + "node_modules/snappy": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-7.2.2.tgz", + "integrity": "sha512-iADMq1kY0v3vJmGTuKcFWSXt15qYUz7wFkArOrsSg0IFfI3nJqIJvK2/ZbEIndg7erIJLtAVX2nSOqPz7DcwbA==", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/snappy-android-arm-eabi": "7.2.2", + "@napi-rs/snappy-android-arm64": "7.2.2", + "@napi-rs/snappy-darwin-arm64": "7.2.2", + "@napi-rs/snappy-darwin-x64": "7.2.2", + "@napi-rs/snappy-freebsd-x64": "7.2.2", + "@napi-rs/snappy-linux-arm-gnueabihf": "7.2.2", + "@napi-rs/snappy-linux-arm64-gnu": "7.2.2", + "@napi-rs/snappy-linux-arm64-musl": "7.2.2", + "@napi-rs/snappy-linux-x64-gnu": "7.2.2", + "@napi-rs/snappy-linux-x64-musl": "7.2.2", + "@napi-rs/snappy-win32-arm64-msvc": "7.2.2", + "@napi-rs/snappy-win32-ia32-msvc": "7.2.2", + "@napi-rs/snappy-win32-x64-msvc": "7.2.2" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -8059,6 +8778,14 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -8088,6 +8815,14 @@ "mixme": "^0.5.1" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-argv": { "version": "0.3.1", "dev": true, @@ -8197,7 +8932,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, "engines": { "node": ">=4" } @@ -8299,6 +9033,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -8374,6 +9113,14 @@ "node": ">=8" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ts-api-utils": { "version": "1.0.3", "dev": true, @@ -8389,7 +9136,6 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -8432,7 +9178,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, "dependencies": { "json5": "^2.2.2", "minimist": "^1.2.6", @@ -8569,7 +9314,6 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8677,11 +9421,20 @@ "punycode": "^2.1.0" } }, + "node_modules/url-polyfill": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.12.tgz", + "integrity": "sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "node_modules/v8-to-istanbul": { "version": "9.2.0", @@ -8983,6 +9736,98 @@ "node": ">=8" } }, + "node_modules/winston": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", + "integrity": "sha512-RhruH2Cj0bV0WgNL+lOfoUBI4DVfdUNjVnJGVovWZmrcKtrFTTRzgXYK2O9cymSGjrERCtaAeHwMNnUWXlwZow==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.6.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-daily-rotate-file": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.7.1.tgz", + "integrity": "sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==", + "dependencies": { + "file-stream-rotator": "^0.6.1", + "object-hash": "^2.0.1", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "winston": "^3" + } + }, + "node_modules/winston-loki": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/winston-loki/-/winston-loki-6.1.3.tgz", + "integrity": "sha512-DjWtJ230xHyYQWr9mZJa93yhwHttn3JEtSYWP8vXZWJOahiQheUhf+88dSIidbGXB3u0oLweV6G1vkL/ouT62Q==", + "dependencies": { + "async-exit-hook": "2.0.1", + "btoa": "^1.2.1", + "protobufjs": "^7.2.4", + "url-polyfill": "^1.1.12", + "winston-transport": "^4.3.0" + }, + "optionalDependencies": { + "snappy": "^7.2.2" + } + }, + "node_modules/winston-transport": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.8.0.tgz", + "integrity": "sha512-qxSTKswC6llEMZKgCQdaWgDuMJQnhuvF5f2Nk3SNXc4byfQ+voo2mX1Px9dkNOuR8p0KAjfPG29PuYUSIb+vSA==", + "dependencies": { + "logform": "^2.6.1", + "readable-stream": "^4.5.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/winston/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -9130,7 +9975,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, "engines": { "node": ">=6" } @@ -9967,6 +10811,33 @@ "typescript": "^5.3.3" } }, + "tests/global": { + "name": "@rosenet-tests/global", + "version": "0.1.0", + "license": "GPL-3.0", + "dependencies": { + "@influxdata/influxdb-client": "^1.35.0", + "@rosen-bridge/abstract-logger": "^2.0.1", + "@rosen-bridge/rosenet-node": "^0.1.0", + "@rosen-bridge/rosenet-relay": "^0.1.0", + "@rosen-bridge/winston-logger": "^1.0.2", + "extensionless": "^1.9.6", + "lodash-es": "^4.17.21", + "ts-node": "^10.7.0", + "tsconfig-paths": "^4.1.2" + }, + "devDependencies": { + "@types/express": "^5.0.0", + "@types/lodash-es": "^4.17.12", + "@types/node": "^20.11.9", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.2.4", + "typescript": "^5.3.3" + } + }, "tests/scale": { "name": "@rosenet-tests/scale", "version": "0.0.0", diff --git a/package.json b/package.json index ff8db37..7c2d7bc 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "npm run build --workspaces", "coverage": "npm run coverage --workspaces", "lint": "npm run lint --workspaces", - "prepare": "husky install", + "prepare": "husky install || true", "release": "npm run release --workspaces", "test": "npm run test --workspaces", "type-check": "npm run type-check --workspaces", diff --git a/packages/rosenet-node/lib/constants.ts b/packages/rosenet-node/lib/constants.ts index 6f874ae..c5257da 100644 --- a/packages/rosenet-node/lib/constants.ts +++ b/packages/rosenet-node/lib/constants.ts @@ -119,3 +119,7 @@ export const DEFAULT_FAIL_FAST_THRESHOLD = * Default gossipsubMaxInboundDataLength config of Gossipsub */ export const DEFAULT_GOSSIPSUB_MAX_INBOUND_DATA_LENGTH = 170_000_000; +/** + * Timeout used when dialing a peer's hopefully public multiaddress + */ +export const PUBLIC_MULTIADDR_DIAL_TIMEOUT = 5000; diff --git a/packages/rosenet-node/lib/createRoseNetNode.ts b/packages/rosenet-node/lib/createRoseNetNode.ts index e364544..78093e2 100644 --- a/packages/rosenet-node/lib/createRoseNetNode.ts +++ b/packages/rosenet-node/lib/createRoseNetNode.ts @@ -64,7 +64,7 @@ const createRoseNetNode = async (config: PartialRoseNetNodeConfig) => { const peerId = await privateKeyToPeerId(RoseNetNodeContext.config.privateKey); - RoseNetNodeContext.logger.debug(`PeerId ${peerId.toString()} generated`); + RoseNetNodeContext.logger.info(`PeerId ${peerId.toString()} generated`); const announceMultiaddr = await addressService.getAnnounceMultiaddr( RoseNetNodeContext.config.port, @@ -90,13 +90,13 @@ const createRoseNetNode = async (config: PartialRoseNetNodeConfig) => { listen: [ `/ip4/${RoseNetNodeContext.config.host}/tcp/${RoseNetNodeContext.config.port}`, ...sampledRelayMultiaddrs.map( - (multiaddr) => `${multiaddr}/p2p-circuit`, + (multiaddr) => `${multiaddr}/p2p-circuit/p2p/${peerId.toString()}`, ), ], announce: [ announceMultiaddr, ...sampledRelayMultiaddrs.map( - (multiaddr) => `${multiaddr}/p2p-circuit`, + (multiaddr) => `${multiaddr}/p2p-circuit/p2p/${peerId.toString()}`, ), ], }, @@ -164,6 +164,10 @@ const createRoseNetNode = async (config: PartialRoseNetNodeConfig) => { info: { getPeerId: () => node.peerId.toString(), getConnectedPeers: () => node.getPeers().map((peer) => peer.toString()), + getDiscoveredPeers: async () => { + const peers = await node.peerStore.all(); + return peers.map((peer) => peer.id.toString()); + }, }, }; }; diff --git a/packages/rosenet-node/lib/rosenet-direct/sendMessage.ts b/packages/rosenet-node/lib/rosenet-direct/sendMessage.ts index f597faf..049d06d 100644 --- a/packages/rosenet-node/lib/rosenet-direct/sendMessage.ts +++ b/packages/rosenet-node/lib/rosenet-direct/sendMessage.ts @@ -135,16 +135,16 @@ const sendMessageWithRetryAndBulkheadFactory = (node: Libp2p) => { const sendMessageInner = sendMessageFactory(node); const shouldFailFast = - bulkheadPolicy.executionSlots > + bulkheadPolicy.executionSlots < RoseNetNodeContext.config.direct.failFastThreshold; const maxAttempts = shouldFailFast - ? RoseNetNodeContext.config.direct.maxRetryAttempts - : RoseNetNodeContext.config.direct.failFastMaxRetryAttempts; + ? RoseNetNodeContext.config.direct.failFastMaxRetryAttempts + : RoseNetNodeContext.config.direct.maxRetryAttempts; const initialDelay = shouldFailFast - ? RoseNetNodeContext.config.direct.retryInitialDelay - : RoseNetNodeContext.config.direct.failFastRetryInitialDelay; + ? RoseNetNodeContext.config.direct.failFastRetryInitialDelay + : RoseNetNodeContext.config.direct.retryInitialDelay; const retryPolicy = retry(handleAll, { maxAttempts, @@ -160,7 +160,7 @@ const sendMessageWithRetryAndBulkheadFactory = (node: Libp2p) => { }); retryPolicy.onRetry((data) => { RoseNetNodeContext.logger.debug( - `Retry sending message (attempt #${data.attempt}/${RoseNetNodeContext.config.direct.maxRetryAttempts})`, + `Retry sending message (attempt #${data.attempt}/${maxAttempts})`, { message, }, @@ -176,7 +176,7 @@ const sendMessageWithRetryAndBulkheadFactory = (node: Libp2p) => { RoseNetNodeContext.logger.warn( 'Message sending failed, dropping message', { - lastOccurredError: error, + lastOccurredError: JSON.stringify(error), isFailFastEnabled: shouldFailFast, }, ); diff --git a/packages/rosenet-node/lib/stream/stream-service.ts b/packages/rosenet-node/lib/stream/stream-service.ts index 6c836e8..3de2621 100644 --- a/packages/rosenet-node/lib/stream/stream-service.ts +++ b/packages/rosenet-node/lib/stream/stream-service.ts @@ -1,4 +1,5 @@ import { peerIdFromString } from '@libp2p/peer-id'; +import { Multiaddr } from '@multiformats/multiaddr'; import { circuitBreaker, CircuitBreakerPolicy, @@ -14,7 +15,10 @@ import { Libp2p } from 'libp2p'; import RoseNetNodeContext from '../context/RoseNetNodeContext'; -import { ROSENET_DIRECT_PROTOCOL_V1 } from '../constants'; +import { + ROSENET_DIRECT_PROTOCOL_V1, + PUBLIC_MULTIADDR_DIAL_TIMEOUT, +} from '../constants'; import { RoseNetNodeError } from '../errors'; @@ -70,7 +74,73 @@ async function getRoseNetDirectStreamTo(to: string, node: Libp2p) { */ const connection = possibleOpenConnectionToPeer ?? - (await peerBreakers[to].execute(() => node.dial(peerId))); + (await peerBreakers[to].execute(async () => { + /** + * The nodes advertise hopefully public multiaddresses, but these + * multiaddresses may be wrong because of being behind a non-symmetric + * NAT. In addition, there is a bug in libp2p that allows the dial to a + * single multiaddress of a peer to take all the timeout of a dial to the + * peer. These combined will cause the dial to nodes with unreachable + * public multiaddresses to always fail, because their relayed + * multiaddress is never tried. + * + * As a workaround, we manually first try to dial the public multiaddress + * but with a reduced timeout, and then the other ones if the first dial + * fails. + * + * Libp2p bug GitHub issue: + * https://github.com/libp2p/js-libp2p/issues/2368 + */ + const peerAddresses = (await node.peerStore.get(peerId)).addresses; + const [publicAddresses, otherAddresses] = peerAddresses.reduce( + (partialPartitions, address) => + address.multiaddr.isThinWaistAddress() + ? [ + [...partialPartitions[0], address.multiaddr], + partialPartitions[1], + ] + : [ + partialPartitions[0], + [ + ...partialPartitions[1], + address.multiaddr.toString().endsWith('p2p-circuit') + ? address.multiaddr.encapsulate(`/p2p/${peerId.toString()}`) + : address.multiaddr, + ], + ], + [[], []] as [Multiaddr[], Multiaddr[]], + ); + + RoseNetNodeContext.logger.debug( + `Fetched and partitioned peer multiaddresses`, + { + publicAddresses: publicAddresses.map((address) => address.toString()), + otherAddresses: otherAddresses.map((address) => address.toString()), + }, + ); + + if (publicAddresses) { + try { + const connection = await node.dial(publicAddresses, { + signal: AbortSignal.timeout(PUBLIC_MULTIADDR_DIAL_TIMEOUT), + }); + RoseNetNodeContext.logger.debug( + `Public multiaddress dialed successfully`, + ); + return connection; + } catch { + RoseNetNodeContext.logger.debug( + `Couldn't dial any public multiaddresses, trying relayed addresses`, + ); + return await node.dial(otherAddresses); + } + } else { + RoseNetNodeContext.logger.debug( + 'No public multiaddress found for this peer, trying relayed addresses', + ); + return await node.dial(otherAddresses); + } + })); RoseNetNodeContext.logger.debug( possibleOpenConnectionToPeer diff --git a/packages/utils/lib/index.ts b/packages/utils/lib/index.ts index 4baa595..ec9d7d6 100644 --- a/packages/utils/lib/index.ts +++ b/packages/utils/lib/index.ts @@ -1,3 +1,4 @@ export { default as addEventListeners } from './addEventListeners'; -export { default as privateKeyToPeerId } from './privateKeyToPeerId'; export { default as libp2pLoggerFactory } from './logger'; +export { default as privateKeyToPeerId } from './privateKeyToPeerId'; +export { default as readPrivateKeyFromFile } from './readPrivateKeyFromFile'; diff --git a/packages/utils/lib/readPrivateKeyFromFile.ts b/packages/utils/lib/readPrivateKeyFromFile.ts new file mode 100644 index 0000000..90a4c77 --- /dev/null +++ b/packages/utils/lib/readPrivateKeyFromFile.ts @@ -0,0 +1,26 @@ +import { generateKeyPair, marshalPrivateKey } from '@libp2p/crypto/keys'; +import { readFile, writeFile } from 'fs/promises'; +import { resolve } from 'path'; + +/** + * read private key from a file and return its string representation, creating + * the file with a random private key if it doesn't exist + * @param path relative or absolute path to the file + */ +const readPrivateKeyFromFile = async (path: string) => { + const fullPath = resolve(path); + try { + return await readFile(fullPath, 'utf-8'); + } catch (error) { + const privateKey = await generateKeyPair('Ed25519'); + const privateKeyString = Buffer.from( + marshalPrivateKey(privateKey), + ).toString('hex'); + + await writeFile(fullPath, privateKeyString, 'utf-8'); + + return privateKeyString; + } +}; + +export default readPrivateKeyFromFile; diff --git a/tests/global/.eslintignore b/tests/global/.eslintignore new file mode 100644 index 0000000..1521c8b --- /dev/null +++ b/tests/global/.eslintignore @@ -0,0 +1 @@ +dist diff --git a/tests/global/.gitignore b/tests/global/.gitignore new file mode 100644 index 0000000..98d8a5a --- /dev/null +++ b/tests/global/.gitignore @@ -0,0 +1 @@ +logs diff --git a/tests/global/README.md b/tests/global/README.md new file mode 100644 index 0000000..6e1fdce --- /dev/null +++ b/tests/global/README.md @@ -0,0 +1,141 @@ +# RoseNet global test + +## Table of contents + +- [RoseNet global test](#rosenet-global-test) + - [Table of contents](#table-of-contents) + - [System Requirements](#system-requirements) + - [Quick Start](#quick-start) + - [Detailed Setup Instructions](#detailed-setup-instructions) + - [Relay Setup](#relay-setup) + - [Node Setup](#node-setup) + - [Test Execution](#test-execution) + - [Data Collection and Analysis](#data-collection-and-analysis) + +## System Requirements + +- Git +- Docker and Docker Compose +- Access to a server with a public ip (for relay setup) + +## Quick Start + +```bash +# Clone the repository +git clone https://github.com/rosen-bridge/rosenet.git + +# Choose your setup type: +# For relay setup: +cd rosenet/tests/global/src/relay + +# For node setup: +cd rosenet/tests/global/src/node + +# Create service configuration file +cp .env.example .env +# Edit .env file with your configuration +docker compose up -d +``` + +## Detailed Setup Instructions + +### Relay Setup + +1. **Clone the Repository** + + ```bash + git clone https://github.com/rosen-bridge/rosenet.git + cd rosenet/tests/global/src/relay + ``` + +2. **Configure Environment** + + ```bash + cp .env.example .env + ``` + +3. **Configuration Options** + + - Required: + - `WHITELIST`: Comma-separated list of allowed node peer IDs + +4. **Launch Relay** + + ```bash + docker compose up -d + ``` + +5. **Get Relay Multiaddress** + + - Check debug logs at `tests/global/src/relay/logs/debug/*.log` + - Format your multiaddress: + ``` + /ip4//tcp//p2p/ + # or + /dns4//tcp//p2p/ + ``` + + For example, having this log entry in a server with ip address of `100.100.100.100`, domain of `example.com`, and default 44123 port: + + ```log + 2024-10-26T07:36:54.652Z debug: [rosenet] PeerId 12D3KooWDvTUsPV6DSCJXJWJQjSoJ4q172kPRe4MHgxYqTz7J4jp generated + ``` + + Your multiaddr can be represented as either `/ip4/100.100.100.100/tcp/44123/p2p/12D3KooWDvTUsPV6DSCJXJWJQjSoJ4q172kPRe4MHgxYqTz7J4jp` or `/dns4/example.com/tcp/44123/p2p/12D3KooWDvTUsPV6DSCJXJWJQjSoJ4q172kPRe4MHgxYqTz7J4jp`. + +### Node Setup + +1. **Clone and Navigate** + + ```bash + git clone https://github.com/rosen-bridge/rosenet.git + cd tests/global/src/node + ``` + +2. **Configure Environment** + + ```bash + cp .env.example .env + ``` + +3. **Configuration Options** + + - Required: + - `RELAY_MULTIADDRS`: Comma-separated list of relay multiaddresses + +4. **Initial Run and Whitelisting** + + ```bash + docker compose up -d + ``` + + > **Note**: The first run will fail as your node needs whitelisting. Check debug logs at `tests/global/src/node/logs/debug/*.log` to find your node's peer ID. + +5. **Complete Setup** + - Get your node's peer ID from the debug logs + - Have it whitelisted in at least one relay + - Restart the service: + ```bash + docker compose up -d + ``` + +## Test Execution + +Once properly configured, your node will automatically participate in the test network by sending and receiving pubsub and direct messages, and logging relevant activities. + +## Data Collection and Analysis + +After the test is over, the results can be analyzed by checking the database of the nodes: + +1. **Access InfluxDB Dashboard** + + - URL: `http://localhost:8086` + - Credentials: + - Username: `admin` + - Password: `admin1234` + +2. **Extract Test Results** + - Navigate to "Data Explorer" + - Select bucket: `RoseNet` + - Choose measurements: `direct` and `pubsub` + - Export data using the CSV button diff --git a/tests/global/package.json b/tests/global/package.json new file mode 100644 index 0000000..0a6c030 --- /dev/null +++ b/tests/global/package.json @@ -0,0 +1,41 @@ +{ + "name": "@rosenet-tests/global", + "private": true, + "version": "0.1.0", + "description": "RoseNet global test", + "repository": "https://github.com/rosen-bridge/rosenet", + "license": "GPL-3.0", + "author": "Rosen Team", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "lint": "eslint --fix . && npm run prettify", + "prettify": "prettier --write . --ignore-path ./.gitignore", + "start:node": "node --loader ./ts-node-esm-loader.js --loader extensionless ./src/node/node.ts", + "start:relay": "node --loader ./ts-node-esm-loader.js --loader extensionless ./src/relay/relay.ts", + "type-check": "tsc --noEmit" + }, + "devDependencies": { + "@types/express": "^5.0.0", + "@types/lodash-es": "^4.17.12", + "@types/node": "^20.11.9", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.2.4", + "typescript": "^5.3.3" + }, + "dependencies": { + "@influxdata/influxdb-client": "^1.35.0", + "@rosen-bridge/abstract-logger": "^2.0.1", + "@rosen-bridge/rosenet-node": "^0.1.0", + "@rosen-bridge/rosenet-relay": "^0.1.0", + "@rosen-bridge/winston-logger": "^1.0.2", + "extensionless": "^1.9.6", + "lodash-es": "^4.17.21", + "ts-node": "^10.7.0", + "tsconfig-paths": "^4.1.2" + } +} diff --git a/tests/global/src/node/.env.example b/tests/global/src/node/.env.example new file mode 100644 index 0000000..34025ce --- /dev/null +++ b/tests/global/src/node/.env.example @@ -0,0 +1,20 @@ +# Required +RELAY_MULTIADDRS= + +# Optional +SHOULD_SEND_DIRECT_TO_OLD_PEERS= +DIRECT_BURST_SIZE= +PUBSUB_BURST_SIZE= +MIN_IDLE_TIME= +MAX_IDLE_TIME= +MIN_MESSAGE_SIZE= +MAX_MESSAGE_SIZE= +MIN_SCNEARIO_DURATION= +MAX_SCNEARIO_DURATION= +SERVICE_PORT= +LOGS_DIRECTORY= +INFLUXDB_HOST= +INFLUXDB_PORT= +INFLUXDB_USERNAME= +INFLUXDB_PASSWORD= +INFLUXDB_ADMIN_TOKEN= diff --git a/tests/global/src/node/.env.influxdb b/tests/global/src/node/.env.influxdb new file mode 100644 index 0000000..431a3b9 --- /dev/null +++ b/tests/global/src/node/.env.influxdb @@ -0,0 +1,6 @@ +DOCKER_INFLUXDB_INIT_MODE=setup +DOCKER_INFLUXDB_INIT_USERNAME=${INFLUXDB_USERNAME:-admin} +DOCKER_INFLUXDB_INIT_PASSWORD=${INFLUXDB_PASSWORD:-admin1234} +DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${INFLUXDB_ADMIN_TOKEN:-admintoken} +DOCKER_INFLUXDB_INIT_ORG=Rosen +DOCKER_INFLUXDB_INIT_BUCKET=RoseNet diff --git a/tests/global/src/node/.env.service b/tests/global/src/node/.env.service new file mode 100644 index 0000000..8b0748b --- /dev/null +++ b/tests/global/src/node/.env.service @@ -0,0 +1,11 @@ +SHOULD_SEND_DIRECT_TO_OLD_PEERS=${SHOULD_SEND_DIRECT_TO_OLD_PEERS:-} +DIRECT_BURST_SIZE=${DIRECT_BURST_SIZE:-} +PUBSUB_BURST_SIZE=${PUBSUB_BURST_SIZE:-} +MIN_IDLE_TIME=${MIN_IDLE_TIME:-} +MAX_IDLE_TIME=${MAX_IDLE_TIME:-} +MIN_MESSAGE_SIZE=${MIN_MESSAGE_SIZE:-} +MAX_MESSAGE_SIZE=${MAX_MESSAGE_SIZE:-} +MIN_SCNEARIO_DURATION=${MIN_SCNEARIO_DURATION:-} +MAX_SCNEARIO_DURATION=${MAX_SCNEARIO_DURATION:-} +RELAY_MULTIADDRS=${RELAY_MULTIADDRS:?} +INFLUXDB_ADMIN_TOKEN=${INFLUXDB_ADMIN_TOKEN:-admintoken} diff --git a/tests/global/src/node/Dockerfile b/tests/global/src/node/Dockerfile new file mode 100644 index 0000000..f1cfe82 --- /dev/null +++ b/tests/global/src/node/Dockerfile @@ -0,0 +1,24 @@ +FROM node:20-slim AS base +WORKDIR /app +COPY . /app + +FROM base as build +RUN --mount=type=cache,target=/root/.npm npm i +RUN npm run build + +FROM base as prod-deps +RUN --mount=type=cache,target=/root/.npm npm i --omit=dev +RUN mkdir -p /app/packages/rosenet-node/node_modules +RUN mkdir -p /app/packages/utils/node_modules +RUN mkdir -p /app/tests/global/node_modules + +FROM base +COPY --from=build /app/packages/rosenet-node/dist /app/packages/rosenet-node/dist +COPY --from=build /app/packages/utils/dist /app/packages/utils/dist +COPY --from=prod-deps /app/node_modules /app/node_modules +COPY --from=prod-deps /app/packages/rosenet-node/node_modules /app/packages/rosenet-node/node_modules +COPY --from=prod-deps /app/packages/utils/node_modules /app/packages/utils/node_modules +COPY --from=prod-deps /app/tests/global/node_modules /app/tests/global/node_modules +WORKDIR /app/tests/global + +CMD npm run start:node diff --git a/tests/global/src/node/bootstrap.ts b/tests/global/src/node/bootstrap.ts new file mode 100644 index 0000000..9a1a687 --- /dev/null +++ b/tests/global/src/node/bootstrap.ts @@ -0,0 +1,25 @@ +import { DefaultLoggerFactory } from '@rosen-bridge/abstract-logger'; +import WinstonLogger from '@rosen-bridge/winston-logger'; + +const winstonLogger = new WinstonLogger([ + { + type: 'console', + level: 'info', + }, + { + type: 'file', + level: 'info', + maxFiles: '10', + maxSize: '20m', + path: './logs/info/', + }, + { + type: 'file', + level: 'debug', + maxFiles: '100', + maxSize: '20m', + path: './logs/debug/', + }, +]); + +DefaultLoggerFactory.init(winstonLogger); diff --git a/tests/global/src/node/config.ts b/tests/global/src/node/config.ts new file mode 100644 index 0000000..197acfe --- /dev/null +++ b/tests/global/src/node/config.ts @@ -0,0 +1,17 @@ +const optional = (value: string | undefined, fallbackValue: number) => + value ? +value : fallbackValue; + +export default { + shouldSendDirectToOldPeers: + process.env.SHOULD_SEND_DIRECT_TO_OLD_PEERS === 'true', + directBurstSize: optional(process.env.DIRECT_BURST_SIZE, 100), + pubsubBurstSize: optional(process.env.PUBSUB_BURST_SIZE, 10), + minIdleTime: optional(process.env.MIN_IDLE_TIME, 5), + maxIdleTime: optional(process.env.MAX_IDLE_TIME, 10_000), + minMessageSize: optional(process.env.MIN_MESSAGE_SIZE, 10_000), + maxMessageSize: optional(process.env.MAX_MESSAGE_SIZE, 500_000), + minScenarioDuration: optional(process.env.MIN_SCNEARIO_DURATION, 60_000), + maxScenarioDuration: optional(process.env.MAX_SCNEARIO_DURATION, 300_000), + relayMultiaddrs: process.env.RELAY_MULTIADDRS!.split(','), + influxdbToken: process.env.INFLUXDB_ADMIN_TOKEN!, +}; diff --git a/tests/global/src/node/docker-compose.yaml b/tests/global/src/node/docker-compose.yaml new file mode 100644 index 0000000..1629abc --- /dev/null +++ b/tests/global/src/node/docker-compose.yaml @@ -0,0 +1,44 @@ +name: 'global-rosenet-test' + +services: + rosenet-node: + build: + context: ../../../.. + dockerfile: ./tests/global/src/node/Dockerfile + env_file: + - .env.service + ports: + - ${SERVICE_PORT:-55123}:55123 + networks: + - internal + volumes: + - rosenet-node-pk:/app/tests/global/.rosenet + - ${LOGS_DIRECTORY:-./logs}:/app/tests/global/logs + depends_on: + - influxdb + + influxdb: + image: influxdb + env_file: + - .env.influxdb + ports: + - ${INFLUXDB_HOST:-127.0.0.1}:${INFLUXDB_PORT:-8086}:8086 + networks: + - internal + volumes: + - influxdb-data:/var/lib/influxdb2 + - influxdb2-config:/etc/influxdb2 + healthcheck: + test: ['CMD', 'influx', 'ping'] + timeout: 5s + interval: 5s + retries: 2 + start_period: 10s + +volumes: + rosenet-node-pk: + influxdb-data: + influxdb2-config: + +networks: + internal: diff --git a/tests/global/src/node/logger.ts b/tests/global/src/node/logger.ts new file mode 100644 index 0000000..c65b75d --- /dev/null +++ b/tests/global/src/node/logger.ts @@ -0,0 +1,6 @@ +import { DefaultLoggerFactory } from '@rosen-bridge/abstract-logger'; + +export const serviceLogger = + DefaultLoggerFactory.getInstance().getLogger('service'); +export const rosenetLogger = + DefaultLoggerFactory.getInstance().getLogger('rosenet'); diff --git a/tests/global/src/node/metric-store.ts b/tests/global/src/node/metric-store.ts new file mode 100644 index 0000000..55b2124 --- /dev/null +++ b/tests/global/src/node/metric-store.ts @@ -0,0 +1,79 @@ +import { InfluxDB, Point } from '@influxdata/influxdb-client'; + +import { serviceLogger } from './logger'; + +import config from './config'; + +const influxDB = new InfluxDB({ + url: 'http://influxdb:8086', + token: config.influxdbToken, +}); +const writeApi = influxDB.getWriteApi('Rosen', 'RoseNet'); + +/** + * Save data about a direct message + * + * @param direction + * @param status + * @param peer + * @param latency + * @param size + */ +export const saveDirect = async ( + direction: 'send' | 'receive', + status: 'success' | 'failure', + peer: string, + latency: number, + size: number, +) => { + try { + const point = new Point('direct') + .tag('direction', direction) + .tag('status', status) + .tag('peer', peer) + .floatField('latency', latency) + .uintField('size', size); + + writeApi.writePoint(point); + await writeApi.flush(); + serviceLogger.debug('Direct message data saved in database'); + } catch (error) { + serviceLogger.warn( + 'An error occurred while saving direct message data in database', + ); + serviceLogger.debug( + (error instanceof Error && error.message) || 'Unknown error message', + ); + } +}; + +/** + * Save data about a pubsub message + * + * @param direction + * @param latency + * @param size + */ +export const savePubsub = async ( + direction: 'send' | 'receive', + latency: number, + size: number, +) => { + try { + const point = new Point('pubsub') + .tag('direction', direction) + .floatField('latency', latency) + .uintField('size', size); + + writeApi.writePoint(point); + await writeApi.flush(); + serviceLogger.debug('Pubsub message data saved in database'); + } catch (error) { + serviceLogger.warn( + 'An error occurred while saving pubsub message data in database', + ); + serviceLogger.debug( + (error instanceof Error && error.message) || 'Unknown error message', + ); + } +}; diff --git a/tests/global/src/node/node.ts b/tests/global/src/node/node.ts new file mode 100644 index 0000000..5e64ffd --- /dev/null +++ b/tests/global/src/node/node.ts @@ -0,0 +1,58 @@ +import './bootstrap'; + +import { createRoseNetNode } from '@rosen-bridge/rosenet-node'; +import { readPrivateKeyFromFile } from '@rosen-bridge/rosenet-utils'; +import { random, sample } from 'lodash-es'; + +import config from './config'; +import { registerHandlers } from './registerHandlers'; +import { breakScenario } from './scenarios/break'; +import { combinedScenario } from './scenarios/combined'; +import { directScenario } from './scenarios/direct'; +import { pubsubScenario } from './scenarios/pubsub'; + +import { serviceLogger, rosenetLogger } from './logger'; + +process.on('uncaughtExceptionMonitor', (error) => { + serviceLogger.error('An uncaught exception occurred', { error }); +}); + +const privateKey = await readPrivateKeyFromFile('.rosenet/pk').catch( + (error) => { + serviceLogger.error( + 'An error occurred while getting private key from file', + ); + serviceLogger.debug(error?.message ?? 'Unknown error message'); + process.exit(1); + }, +); + +const node = await createRoseNetNode({ + relay: { + multiaddrs: config.relayMultiaddrs, + }, + privateKey, + logger: rosenetLogger, +}); +await node.start(); +serviceLogger.info('RoseNet node started'); + +registerHandlers(node); +serviceLogger.debug('Message handlers registered'); + +const scenarios = [ + directScenario(node), + pubsubScenario(node), + combinedScenario(node), + breakScenario(), +]; + +await Promise.all(scenarios.map((scenario) => scenario.next())); + +// eslint-disable-next-line no-constant-condition +while (true) { + const scenario = sample(scenarios)!; + await scenario.next( + random(config.minScenarioDuration, config.maxScenarioDuration), + ); +} diff --git a/tests/global/src/node/registerHandlers.ts b/tests/global/src/node/registerHandlers.ts new file mode 100644 index 0000000..9245340 --- /dev/null +++ b/tests/global/src/node/registerHandlers.ts @@ -0,0 +1,37 @@ +import { createRoseNetNode } from '@rosen-bridge/rosenet-node'; + +import { saveDirect, savePubsub } from './metric-store'; + +import { serviceLogger } from './logger'; + +/** + * Register pubsub and direct message handlers + * + * @param node + */ +export const registerHandlers = ( + node: Awaited>, +) => { + node.handleIncomingMessage(async (from, message) => { + const roundtripEnd = Date.now(); + const roundtripStart = +message!.slice(-13); + const latency = roundtripEnd - roundtripStart; + saveDirect('receive', 'success', from, latency, message!.length); + serviceLogger.info('Direct message received', { + from, + latency, + messageLength: message!.length, + }); + }); + + node.subscribe('rosenet-news', (message) => { + const roundtripEnd = Date.now(); + const roundtripStart = +message.slice(-13); + const latency = roundtripEnd - roundtripStart; + savePubsub('receive', latency, message.length); + serviceLogger.info('Pubsub message received', { + latency, + messageLength: message!.length, + }); + }); +}; diff --git a/tests/global/src/node/scenarios/break.ts b/tests/global/src/node/scenarios/break.ts new file mode 100644 index 0000000..abbc487 --- /dev/null +++ b/tests/global/src/node/scenarios/break.ts @@ -0,0 +1,17 @@ +import { waitMs } from '../utils'; + +import { serviceLogger } from '../logger'; + +import { Scenario } from '../types'; + +/** + * A scenario during which the node simply does nothing + */ +export async function* breakScenario(): Scenario { + while (true) { + const timeout = yield; + serviceLogger.info(`Running break scenario for ${timeout}ms`); + await waitMs(timeout); + serviceLogger.info('Break scenario finished'); + } +} diff --git a/tests/global/src/node/scenarios/combined.ts b/tests/global/src/node/scenarios/combined.ts new file mode 100644 index 0000000..5663c76 --- /dev/null +++ b/tests/global/src/node/scenarios/combined.ts @@ -0,0 +1,26 @@ +import { createRoseNetNode } from '@rosen-bridge/rosenet-node'; + +import { directScenario } from './direct'; +import { pubsubScenario } from './pubsub'; + +import { serviceLogger } from '../logger'; + +import { Scenario } from '../types'; + +/** + * A scenario during which the node runs direct and pubsub scenarios + * concurrently + */ +export async function* combinedScenario( + node: Awaited>, +): Scenario { + const direct = directScenario(node); + const pubsub = pubsubScenario(node); + + while (true) { + const timeout = yield; + serviceLogger.info(`Running combined scenario for ${timeout}ms`); + await Promise.all([direct.next(timeout), pubsub.next(timeout)]); + serviceLogger.info('Combined scenario finished'); + } +} diff --git a/tests/global/src/node/scenarios/direct.ts b/tests/global/src/node/scenarios/direct.ts new file mode 100644 index 0000000..3a79323 --- /dev/null +++ b/tests/global/src/node/scenarios/direct.ts @@ -0,0 +1,82 @@ +import { createRoseNetNode } from '@rosen-bridge/rosenet-node'; +import { random, sample } from 'lodash-es'; + +import config from '../config'; +import { saveDirect } from '../metric-store'; +import { waitBeforeNextBurst } from '../utils'; + +import { serviceLogger } from '../logger'; + +import { Scenario } from '../types'; + +const allConnectedPeersSoFar = new Set(); + +/** + * A scenario during which the node sends direct messages to random nodes in + * bursts + */ +export async function* directScenario( + node: Awaited>, +): Scenario { + while (true) { + const timeout = yield; + serviceLogger.info(`Running direct scenario for ${timeout}ms`); + const signal = AbortSignal.timeout(timeout); + const peers = (await node.info.getDiscoveredPeers()).filter( + (peer) => + !config.relayMultiaddrs.some((relayMultiaddr) => + relayMultiaddr.includes(peer), + ), + ); + peers.forEach(allConnectedPeersSoFar.add.bind(allConnectedPeersSoFar)); + // eslint-disable-next-line no-constant-condition + while (true) { + if (signal.aborted) { + break; + } + serviceLogger.info( + `Sending ${config.directBurstSize} direct messages to random peers`, + ); + for (let i = 0; i < config.directBurstSize; i++) { + const peer = sample( + config.shouldSendDirectToOldPeers + ? [...allConnectedPeersSoFar] + : peers, + ); + if (!peer) continue; + const message = 'r' + .repeat(random(config.minMessageSize, config.maxMessageSize)) + .concat(Date.now().toString()); + + const roundtripStart = Date.now(); + await node.sendMessage(peer, message, async (error) => { + const roundtripEnd = Date.now(); + const latency = roundtripEnd - roundtripStart; + saveDirect( + 'send', + error ? 'failure' : 'success', + peer, + latency, + message.length, + ); + if (error) { + serviceLogger.warn( + `An error occurred while sending message to peer ${peer.slice(0, 5)}...${peer.slice(-5)}`, + { error }, + ); + } else { + serviceLogger.info( + `Message sent to peer ${peer.slice(0, 5)}...${peer.slice(-5)} successfully`, + { + latency, + messageLength: message.length, + }, + ); + } + }); + } + await waitBeforeNextBurst(); + } + serviceLogger.info('Direct scenario finished'); + } +} diff --git a/tests/global/src/node/scenarios/pubsub.ts b/tests/global/src/node/scenarios/pubsub.ts new file mode 100644 index 0000000..65f41fe --- /dev/null +++ b/tests/global/src/node/scenarios/pubsub.ts @@ -0,0 +1,49 @@ +import { createRoseNetNode } from '@rosen-bridge/rosenet-node'; +import { random } from 'lodash-es'; + +import config from '../config'; +import { savePubsub } from '../metric-store'; +import { waitBeforeNextBurst } from '../utils'; + +import { serviceLogger } from '../logger'; + +import { Scenario } from '../types'; + +/** + * A scenario during which the node sends pubsub messages in bursts + */ +export async function* pubsubScenario( + node: Awaited>, +): Scenario { + while (true) { + const timeout = yield; + serviceLogger.info(`Running pubsub scenario for ${timeout}ms`); + const signal = AbortSignal.timeout(timeout); + // eslint-disable-next-line no-constant-condition + while (true) { + if (signal.aborted) { + break; + } + serviceLogger.info( + `Publishing ${config.pubsubBurstSize} messages`, + ); + for (let i = 0; i < config.pubsubBurstSize; i++) { + const message = 'r' + .repeat(random(config.minMessageSize, config.maxMessageSize)) + .concat(Date.now().toString()); + + await node.publish('rosenet-news', message).catch((error) => { + serviceLogger.warn(`An error occurred while publishing message`, { + error, + }); + }); + savePubsub('send', 0, message.length); + serviceLogger.info(`Message published successfully`, { + messageLength: message.length, + }); + } + await waitBeforeNextBurst(); + } + serviceLogger.info('Pubsub scenario finished'); + } +} diff --git a/tests/global/src/node/types.ts b/tests/global/src/node/types.ts new file mode 100644 index 0000000..3db8b57 --- /dev/null +++ b/tests/global/src/node/types.ts @@ -0,0 +1,5 @@ +/** + * A scenario is an async generator that yields nothing, never returns, and + * accepts scenario duration as parameter to generator's `next` method + */ +export type Scenario = AsyncGenerator; diff --git a/tests/global/src/node/utils.ts b/tests/global/src/node/utils.ts new file mode 100644 index 0000000..c1e7a56 --- /dev/null +++ b/tests/global/src/node/utils.ts @@ -0,0 +1,18 @@ +import { random } from 'lodash-es'; +import config from './config'; + +/** + * Wait for a specific duration + * @param ms + */ +export const waitMs = (ms: number) => + new Promise((resolve) => { + setTimeout(resolve, ms); + }); + +/** + * Wait for a random duration based on config before firing next burst of + * messages + */ +export const waitBeforeNextBurst = () => + waitMs(random(config.minIdleTime, config.maxIdleTime)); diff --git a/tests/global/src/relay/.env.example b/tests/global/src/relay/.env.example new file mode 100644 index 0000000..1847798 --- /dev/null +++ b/tests/global/src/relay/.env.example @@ -0,0 +1,8 @@ +# Required +# comma separated whitelisted peer ids +WHITELIST= + +# Optional +PORT= +MAX_RESERVATIONS= +LOGS_DIRECTORY= diff --git a/tests/global/src/relay/.env.service b/tests/global/src/relay/.env.service new file mode 100644 index 0000000..509cfb8 --- /dev/null +++ b/tests/global/src/relay/.env.service @@ -0,0 +1,2 @@ +WHITELIST=${WHITELIST:?} +MAX_RESERVATIONS=${MAX_RESERVATIONS:-50} diff --git a/tests/global/src/relay/Dockerfile b/tests/global/src/relay/Dockerfile new file mode 100644 index 0000000..5f90d1c --- /dev/null +++ b/tests/global/src/relay/Dockerfile @@ -0,0 +1,24 @@ +FROM node:20-slim AS base +WORKDIR /app +COPY . /app + +FROM base as build +RUN --mount=type=cache,target=/root/.npm npm i +RUN npm run build + +FROM base as prod-deps +RUN --mount=type=cache,target=/root/.npm npm i --omit=dev +RUN mkdir -p /app/packages/rosenet-relay/node_modules +RUN mkdir -p /app/packages/utils/node_modules +RUN mkdir -p /app/tests/global/node_modules + +FROM base +COPY --from=build /app/packages/rosenet-relay /app/packages/rosenet-relay +COPY --from=build /app/packages/utils/dist /app/packages/utils/dist +COPY --from=prod-deps /app/node_modules /app/node_modules +COPY --from=prod-deps /app/packages/rosenet-relay/node_modules /app/packages/rosenet-relay/node_modules +COPY --from=prod-deps /app/packages/utils/node_modules /app/packages/utils/node_modules +COPY --from=prod-deps /app/tests/global/node_modules /app/tests/global/node_modules +WORKDIR /app/tests/global + +CMD npm run start:relay diff --git a/tests/global/src/relay/bootstrap.ts b/tests/global/src/relay/bootstrap.ts new file mode 100644 index 0000000..9a1a687 --- /dev/null +++ b/tests/global/src/relay/bootstrap.ts @@ -0,0 +1,25 @@ +import { DefaultLoggerFactory } from '@rosen-bridge/abstract-logger'; +import WinstonLogger from '@rosen-bridge/winston-logger'; + +const winstonLogger = new WinstonLogger([ + { + type: 'console', + level: 'info', + }, + { + type: 'file', + level: 'info', + maxFiles: '10', + maxSize: '20m', + path: './logs/info/', + }, + { + type: 'file', + level: 'debug', + maxFiles: '100', + maxSize: '20m', + path: './logs/debug/', + }, +]); + +DefaultLoggerFactory.init(winstonLogger); diff --git a/tests/global/src/relay/config.ts b/tests/global/src/relay/config.ts new file mode 100644 index 0000000..bc789cf --- /dev/null +++ b/tests/global/src/relay/config.ts @@ -0,0 +1,4 @@ +export default { + whitelist: process.env.WHITELIST!.split(','), + maxReservations: +process.env.MAX_RESERVATIONS!, +}; diff --git a/tests/global/src/relay/docker-compose.yaml b/tests/global/src/relay/docker-compose.yaml new file mode 100644 index 0000000..81b651b --- /dev/null +++ b/tests/global/src/relay/docker-compose.yaml @@ -0,0 +1,17 @@ +name: 'global-rosenet-test' + +services: + rosenet-relay: + build: + context: ../../../.. + dockerfile: ./tests/global/src/relay/Dockerfile + env_file: + - .env.service + ports: + - ${PORT:-44123}:44123 + volumes: + - rosenet-relay-pk:/app/tests/global/.rosenet + - ${LOGS_DIRECTORY:-./logs}:/app/tests/global/logs + +volumes: + rosenet-relay-pk: diff --git a/tests/global/src/relay/logger.ts b/tests/global/src/relay/logger.ts new file mode 100644 index 0000000..c65b75d --- /dev/null +++ b/tests/global/src/relay/logger.ts @@ -0,0 +1,6 @@ +import { DefaultLoggerFactory } from '@rosen-bridge/abstract-logger'; + +export const serviceLogger = + DefaultLoggerFactory.getInstance().getLogger('service'); +export const rosenetLogger = + DefaultLoggerFactory.getInstance().getLogger('rosenet'); diff --git a/tests/global/src/relay/relay.ts b/tests/global/src/relay/relay.ts new file mode 100644 index 0000000..816f3af --- /dev/null +++ b/tests/global/src/relay/relay.ts @@ -0,0 +1,26 @@ +import './bootstrap'; + +import { createRoseNetRelay } from '@rosen-bridge/rosenet-relay'; +import { readPrivateKeyFromFile } from '@rosen-bridge/rosenet-utils'; + +import config from './config'; + +import { serviceLogger, rosenetLogger } from './logger'; + +const privateKey = await readPrivateKeyFromFile('.rosenet/pk'); + +const node = await createRoseNetRelay({ + privateKey, + listen: { + host: '0.0.0.0', + port: 44123, + }, + whitelist: config.whitelist, + maxReservations: config.maxReservations, + logger: rosenetLogger, +}); + +await node.start(); +node.subscribe('rosenet-news', () => {}); + +serviceLogger.info('RoseNet relay started'); diff --git a/tests/global/ts-node-esm-loader.js b/tests/global/ts-node-esm-loader.js new file mode 100644 index 0000000..6a27e30 --- /dev/null +++ b/tests/global/ts-node-esm-loader.js @@ -0,0 +1,15 @@ +import { resolve as resolveTs } from 'ts-node/esm'; +import * as tsConfigPaths from 'tsconfig-paths'; +import { pathToFileURL } from 'url'; + +const { absoluteBaseUrl, paths } = tsConfigPaths.loadConfig(); +const matchPath = tsConfigPaths.createMatchPath(absoluteBaseUrl, paths); + +export function resolve(specifier, ctx, defaultResolve) { + const match = matchPath(specifier); + return match + ? resolveTs(pathToFileURL(`${match}`).href, ctx, defaultResolve) + : resolveTs(specifier, ctx, defaultResolve); +} + +export { load, transformSource } from 'ts-node/esm'; diff --git a/tests/global/tsconfig.json b/tests/global/tsconfig.json new file mode 100644 index 0000000..e6464bb --- /dev/null +++ b/tests/global/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "baseUrl": ".", + }, + "include": ["src"], + "ts-node": { + "esm": true, + "transpileOnly": true, + }, + "references": [ + { + "path": "../../packages/rosenet-node/tsconfig.build.json", + }, + { + "path": "../../packages/rosenet-relay/tsconfig.build.json", + }, + ], +}