diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccc0817..1632535 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '18' + node-version: "18" - name: Install dependencies run: npm install @@ -34,7 +34,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '18' + node-version: "18" - name: Install dependencies run: npm install @@ -52,7 +52,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '18.19.0' + node-version: "18.19.0" - name: Cache node_modules uses: actions/cache@v3 @@ -69,8 +69,9 @@ jobs: - name: Checkout Barge uses: actions/checkout@v3 with: - repository: 'oceanprotocol/barge' - path: 'barge' + repository: "oceanprotocol/barge" + path: "barge" + ref: "feature/barge_with_node" - name: Login to Docker Hub if: ${{ env.DOCKERHUB_PASSWORD && env.DOCKERHUB_USERNAME }} @@ -81,10 +82,11 @@ jobs: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} - - name: Run Barge + - name: Run Barge (Ocean Node enabled) working-directory: ${{ github.workspace }}/barge run: | - bash -x start_ocean.sh --no-aquarius --no-provider --no-dashboard --with-c2d --with-typesense 2>&1 > start_ocean.log & + bash -x start_ocean.sh --no-aquarius --no-provider --no-dashboard --with-typesense 2>&1 > start_ocean.log & + - run: npm ci - run: npm run build - run: docker image ls @@ -101,64 +103,76 @@ jobs: docker image rm -f moby/buildkit:latest rm -rf /usr/share/swift/ - - name: Wait for contracts deployment and C2D cluster to be ready + - name: Wait for services with detailed logging working-directory: ${{ github.workspace }}/barge run: | - for i in $(seq 1 250); do - sleep 10 - [ -f "$HOME/.ocean/ocean-contracts/artifacts/ready" -a -f "$HOME/.ocean/ocean-c2d/ready" ] && break - done - - - name: docker logs - run: docker logs ocean_ocean-contracts_1 && docker logs ocean_kindcluster_1 && docker logs ocean_computetodata_1 && docker logs ocean_typesense_1 - if: ${{ failure() }} - - - name: Checkout Ocean Node - uses: actions/checkout@v3 - with: - repository: 'oceanprotocol/ocean-node' - path: 'ocean-node' - ref: 'main' + # Start log tail in background + tail -f start_ocean.log & + TAIL_PID=$! + + # Wait for services with status reporting + for i in {1..50}; do + echo "=== Check attempt $i/50 ===" + + # Check contract deployment + CONTRACTS_READY=$([ -f "$HOME/.ocean/ocean-contracts/artifacts/ready" ] && echo "yes" || echo "no") + + # Check Node container status + NODE_CONTAINER=$(docker ps -q --filter "name=ocean_node") + NODE_RUNNING=$([ -n "$NODE_CONTAINER" ] && echo "yes" || echo "no") + + # Check Node health endpoint + NODE_HEALTH=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8001/health || true) + + echo "Contracts ready: $CONTRACTS_READY" + echo "Node container running: $NODE_RUNNING" + echo "Node health status: $NODE_HEALTH" + + # If container exists but isn't healthy, show logs immediately + if [ "$NODE_RUNNING" = "yes" ] && [ "$NODE_HEALTH" != "200" ]; then + echo "Node container found but unhealthy. Current logs:" + docker logs ocean_node_1 --tail 50 || true + exit 1 + fi - - name: Start Ocean Node - working-directory: ${{ github.workspace }}/ocean-node - run: | - npm ci - npm run build - npm run start & - env: - PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - IPFS_GATEWAY: http://172.15.0.16:8080/ - ARWEAVE_GATEWAY: https://arweave.net/ - P2P_ipV4BindTcpPort: 8000 - HTTP_API_PORT: 8001 - RPCS: '{ "8996": {"rpc": "http://127.0.0.1:8545", "chainId": 8996, "network": "development", "chunkSize": 100} }' - DB_URL: 'http://localhost:9200' - DB_TYPE: 'elasticsearch' - FEE_TOKENS: '{ "1": "0x967da4048cD07aB37855c090aAF366e4ce1b9F48", "137": "0x282d8efCe846A88B159800bd4130ad77443Fa1A1", "80001": "0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8", "56": "0xDCe07662CA8EbC241316a15B611c89711414Dd1a" }' - FEE_AMOUNT: '{ "amount": 1, "unit": "MB" }' - AUTHORIZED_DECRYPTERS: '["0xe2DD09d719Da89e5a3D0F2549c7E24566e947260","0x529043886F21D9bc1AE0feDb751e34265a246e47"]' - AUTHORIZED_PUBLISHERS: '["0xe2DD09d719Da89e5a3D0F2549c7E24566e947260","0x529043886F21D9bc1AE0feDb751e34265a246e47"]' - ALLOWED_ADMINS: '["0xe2DD09d719Da89e5a3D0F2549c7E24566e947260"]' - MAX_REQ_PER_MINUTE: 320 - MAX_CONNECTIONS_PER_MINUTE: 500 - DOCKER_COMPUTE_ENVIRONMENTS: '[{"socketPath":"/var/run/docker.sock","resources":[{"id":"disk","total":1000000000}],"storageExpiry":604800,"maxJobDuration":3600,"fees":{"1":[{"feeToken":"0x123","prices":[{"id":"cpu","price":1}]}]},"free":{"maxJobDuration":60,"maxJobs":3,"resources":[{"id":"cpu","max":1},{"id":"ram","max":1000000000},{"id":"disk","max":1000000000}]}}]' - - name: Check Ocean Node is running - run: | - for i in $(seq 1 30); do - if curl --output /dev/null --silent --head --fail "http://localhost:8001"; then - echo "Ocean Node is up" + # Exit condition + if [ "$CONTRACTS_READY" = "yes" ] && [ "$NODE_RUNNING" = "yes" ] && [ "$NODE_HEALTH" = "200" ]; then + echo "All services operational!" + kill $TAIL_PID exit 0 fi + sleep 10 done - echo "Ocean Node did not start in time" + + # Timeout handling + echo "!!! Service startup timed out !!!" + echo "=== Barge startup log ===" + cat start_ocean.log + echo "\n=== Node container logs ===" + docker logs ocean_node_1 --tail 1000 || echo "No node container found" + echo "\n=== Docker compose status ===" + docker compose -f docker-compose.yml ps exit 1 - - name: Run system tests + + - name: Capture failure logs + if: ${{ failure() }} + run: | + echo "=== Full Docker Container List ===" + docker ps -a + echo "\n=== Barge Docker Compose Logs ===" + docker compose -f ${{ github.workspace }}/barge/docker-compose.yml logs --no-color --tail=1000 + echo "\n=== Node Container Logs ===" + docker logs ocean_node_1 --tail 1000 2>&1 || echo "No node container logs available" + echo "\n=== Contracts Container Logs ===" + docker logs ocean_ocean-contracts_1 --tail 1000 2>&1 || echo "No contracts container logs available" + echo "\n=== C2D Container Logs ===" + docker logs ocean_computetodata_1 --tail 1000 2>&1 || echo "No C2D container logs available" + + - name: Run system tests run: npm run test:system env: INDEXING_RETRY_INTERVAL: 4000 INDEXING_MAX_RETRIES: 120 - NODE_URL: 'http://127.0.0.1:8001' + NODE_URL: "http://127.0.0.1:8001" AVOID_LOOP_RUN: true - diff --git a/package-lock.json b/package-lock.json index 3cc78e7..bc7d9bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "ocean-cli", "version": "2.0.0", "license": "Apache-2.0", "dependencies": { @@ -41,6 +40,7 @@ "mocha": "^10.2.0", "prettier": "^2.8.8", "pretty-quick": "^3.1.3", + "strip-ansi": "^6.0.1", "tsx": "^4.19.2", "typescript": "^5.0.4", "typescript-eslint": "^7.12.0" @@ -2002,7 +2002,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2019,7 +2018,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2036,7 +2034,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2053,7 +2050,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2070,7 +2066,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2087,7 +2082,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2104,7 +2098,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2121,7 +2114,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2138,7 +2130,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2155,7 +2146,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2172,7 +2162,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2189,7 +2178,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2206,7 +2194,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2223,7 +2210,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2240,7 +2226,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2257,7 +2242,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2274,7 +2258,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2291,7 +2274,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2308,7 +2290,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2325,7 +2306,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2342,7 +2322,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2359,7 +2338,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2376,7 +2354,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2393,7 +2370,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2410,7 +2386,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7594,7 +7569,6 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", - "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -9144,7 +9118,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -9295,7 +9268,6 @@ "version": "4.10.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", - "dev": true, "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -13798,7 +13770,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" @@ -15189,9 +15160,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "engines": { "node": ">=16" @@ -15285,7 +15256,6 @@ "version": "4.19.3", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "~0.25.0", @@ -15465,14 +15435,14 @@ } }, "node_modules/typescript-eslint": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.14.1.tgz", - "integrity": "sha512-Eo1X+Y0JgGPspcANKjeR6nIqXl4VL5ldXLc15k4m9upq+eY5fhU2IueiEZL6jmHrKH8aCfbIvM/v3IrX5Hg99w==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", + "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.14.1", - "@typescript-eslint/parser": "7.14.1", - "@typescript-eslint/utils": "7.14.1" + "@typescript-eslint/eslint-plugin": "7.18.0", + "@typescript-eslint/parser": "7.18.0", + "@typescript-eslint/utils": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -15491,16 +15461,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz", - "integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/type-utils": "7.14.1", - "@typescript-eslint/utils": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -15524,15 +15494,15 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", - "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "engines": { @@ -15552,13 +15522,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -15569,13 +15539,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz", - "integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.14.1", - "@typescript-eslint/utils": "7.14.1", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -15596,9 +15566,9 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -15609,13 +15579,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -15637,15 +15607,15 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -15659,12 +15629,12 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -15685,12 +15655,12 @@ } }, "node_modules/typescript-eslint/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -15717,9 +15687,9 @@ } }, "node_modules/typescript-eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/uint32": { @@ -17952,175 +17922,150 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", - "dev": true, "optional": true }, "@esbuild/android-arm": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", - "dev": true, "optional": true }, "@esbuild/android-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", - "dev": true, "optional": true }, "@esbuild/android-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", - "dev": true, "optional": true }, "@esbuild/darwin-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", - "dev": true, "optional": true }, "@esbuild/darwin-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", - "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", - "dev": true, "optional": true }, "@esbuild/freebsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", - "dev": true, "optional": true }, "@esbuild/linux-arm": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", - "dev": true, "optional": true }, "@esbuild/linux-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", - "dev": true, "optional": true }, "@esbuild/linux-ia32": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", - "dev": true, "optional": true }, "@esbuild/linux-loong64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", - "dev": true, "optional": true }, "@esbuild/linux-mips64el": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", - "dev": true, "optional": true }, "@esbuild/linux-ppc64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", - "dev": true, "optional": true }, "@esbuild/linux-riscv64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", - "dev": true, "optional": true }, "@esbuild/linux-s390x": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", - "dev": true, "optional": true }, "@esbuild/linux-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", - "dev": true, "optional": true }, "@esbuild/netbsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", - "dev": true, "optional": true }, "@esbuild/netbsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", - "dev": true, "optional": true }, "@esbuild/openbsd-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", - "dev": true, "optional": true }, "@esbuild/openbsd-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", - "dev": true, "optional": true }, "@esbuild/sunos-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", - "dev": true, "optional": true }, "@esbuild/win32-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", - "dev": true, "optional": true }, "@esbuild/win32-ia32": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", - "dev": true, "optional": true }, "@esbuild/win32-x64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", - "dev": true, "optional": true }, "@eslint-community/eslint-utils": { @@ -21885,7 +21830,6 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", - "dev": true, "requires": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", @@ -23052,7 +22996,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "optional": true }, "function-bind": { @@ -23152,7 +23095,6 @@ "version": "4.10.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", - "dev": true, "requires": { "resolve-pkg-maps": "^1.0.0" } @@ -26308,8 +26250,7 @@ "resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" }, "responselike": { "version": "2.0.1", @@ -27321,9 +27262,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "requires": {} }, @@ -27386,7 +27327,6 @@ "version": "4.19.3", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", - "dev": true, "requires": { "esbuild": "~0.25.0", "fsevents": "~2.3.3", @@ -27511,27 +27451,27 @@ "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==" }, "typescript-eslint": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.14.1.tgz", - "integrity": "sha512-Eo1X+Y0JgGPspcANKjeR6nIqXl4VL5ldXLc15k4m9upq+eY5fhU2IueiEZL6jmHrKH8aCfbIvM/v3IrX5Hg99w==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", + "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", "dev": true, "requires": { - "@typescript-eslint/eslint-plugin": "7.14.1", - "@typescript-eslint/parser": "7.14.1", - "@typescript-eslint/utils": "7.14.1" + "@typescript-eslint/eslint-plugin": "7.18.0", + "@typescript-eslint/parser": "7.18.0", + "@typescript-eslint/utils": "7.18.0" }, "dependencies": { "@typescript-eslint/eslint-plugin": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz", - "integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/type-utils": "7.14.1", - "@typescript-eslint/utils": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -27539,54 +27479,54 @@ } }, "@typescript-eslint/parser": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", - "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", - "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, "requires": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" } }, "@typescript-eslint/type-utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz", - "integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.14.1", - "@typescript-eslint/utils": "7.14.1", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", - "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", - "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, "requires": { - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/visitor-keys": "7.14.1", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -27596,24 +27536,24 @@ } }, "@typescript-eslint/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.14.1", - "@typescript-eslint/types": "7.14.1", - "@typescript-eslint/typescript-estree": "7.14.1" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" } }, "@typescript-eslint/visitor-keys": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", - "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, "requires": { - "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" } }, @@ -27627,12 +27567,12 @@ } }, "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "minimatch": { @@ -27645,9 +27585,9 @@ } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } diff --git a/package.json b/package.json index 13f6eff..9b1715c 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "mocha": "^10.2.0", "prettier": "^2.8.8", "pretty-quick": "^3.1.3", + "strip-ansi": "^6.0.1", "tsx": "^4.19.2", "typescript": "^5.0.4", "typescript-eslint": "^7.12.0" diff --git a/test/compute.test.ts b/test/compute.test.ts new file mode 100644 index 0000000..43c88f0 --- /dev/null +++ b/test/compute.test.ts @@ -0,0 +1,233 @@ +import { expect } from "chai"; +import { exec } from "child_process"; +import path from "path"; +import fs from "fs"; +import util from "util"; +import stripAnsi from "strip-ansi"; + +import { dirname } from "path"; +import { fileURLToPath } from "url"; + +const execPromise = util.promisify(exec); + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +describe("Ocean CLI Free Compute Flow", function () { + this.timeout(300000); + + const projectRoot = path.resolve(__dirname, ".."); + + let computeDatasetDid: string; + let algoDid: string; + let computeEnvId: string; + let jobId: string; + + const runCommand = async (command: string): Promise => { + console.log(`\n[CMD]: ${command}`); + try { + const { stdout } = await execPromise(command, { cwd: projectRoot }); + console.log(`[OUTPUT]:\n${stdout}`); + return stdout; + } catch (error: any) { + console.error(`[ERROR]:\n${error.stderr || error.message}`); + throw error; + } + }; + + before(async () => { + process.env.PRIVATE_KEY = + "0x1d751ded5a32226054cd2e71261039b65afb9ee1c746d055dd699b1150a5befc"; + process.env.RPC = "http://127.0.0.1:8545"; + // process.env.AQUARIUS_URL = "http://127.0.0.1:5000"; + // process.env.PROVIDER_URL = "http://127.0.0.1:8030"; + process.env.ADDRESS_FILE = path.join( + process.env.HOME || "", + ".ocean/ocean-contracts/artifacts/address.json" + ); + console.log("Starting compute tests ... "); + }); + + it("should publish a compute dataset", async () => { + const metadataFile = path.resolve( + projectRoot, + "metadata/simpleComputeDataset.json" + ); + + if (!fs.existsSync(metadataFile)) { + throw new Error(`Metadata file not found: ${metadataFile}`); + } + + const output = await runCommand(`npm run cli publish ${metadataFile}`); + + const didMatch = output.match(/did:op:[a-f0-9]{64}/); + expect(didMatch, "No DID found in output").to.not.be.null; + + computeDatasetDid = didMatch![0]; + console.log(`Published Compute Dataset DID: ${computeDatasetDid}`); + }); + + it("should publish an algorithm", async () => { + const algoFile = path.resolve(projectRoot, "metadata/jsAlgo.json"); + + if (!fs.existsSync(algoFile)) { + throw new Error(`Algorithm metadata file not found: ${algoFile}`); + } + + const output = await runCommand(`npm run cli publishAlgo ${algoFile}`); + + const didMatch = output.match(/did:op:[a-f0-9]{64}/); + expect(didMatch, "No DID found in output").to.not.be.null; + + algoDid = didMatch![0]; + console.log(`Published Algorithm DID: ${algoDid}`); + }); + + it("should get compute environments", async () => { + const output = await runCommand(`npm run cli getComputeEnvironments`); + + const jsonMatch = output.match(/Exiting compute environments:\s*([\s\S]*)/); + if (!jsonMatch) { + console.error("Raw output:", output); + throw new Error("Could not find compute environments in the output"); + } + + let environments; + try { + environments = eval(`(${jsonMatch[1]})`); + } catch (error) { + console.error("Extracted output:", jsonMatch[1]); + throw new Error("Failed to parse the extracted output:\n" + error); + } + + expect(environments).to.be.an("array").that.is.not.empty; + + const firstEnv = environments[0]; + + expect(firstEnv).to.have.property("id").that.is.a("string"); + expect(firstEnv).to.have.property("consumerAddress").that.is.a("string"); + expect(firstEnv).to.have.property("resources").that.is.an("array"); + + computeEnvId = firstEnv.id; + console.log(`Fetched Compute Env ID: ${computeEnvId}`); + }); + + it("should start a free compute job", async () => { + const output = await runCommand( + `npm run cli startFreeCompute --datasets ${computeDatasetDid} --algo ${algoDid} --env ${computeEnvId}` + ); + console.log("Start Free Compute output:", output); + + const jobIdMatch = output.match( + /Compute started\.\s+JobID:\s+(0x[a-f0-9-]+)/i + ); + expect(jobIdMatch, "No Job ID found in output").to.not.be.null; + + jobId = jobIdMatch![1]; + console.log(`Started Free Compute Job ID: ${jobId}`); + }); + + it("should get job status", async () => { + const output = await runCommand( + `npm run cli getJobStatus --dataset ${computeDatasetDid} --job ${jobId}` + ); + + expect(output).to.contain(jobId); + expect(output.toLowerCase()).to.match(/status/); + console.log(`Job status retrieved for jobId: ${jobId}`); + }); + + const waitForJobCompletion = async ( + datasetDid: string, + jobId: string, + maxWaitMs = 120000, + pollIntervalMs = 5000 + ): Promise => { + const start = Date.now(); + + function extractFullJsonArray(output: string): string | null { + const startIndex = output.indexOf("["); + if (startIndex === -1) return null; + + let bracketCount = 0; + for (let i = startIndex; i < output.length; i++) { + if (output[i] === "[") bracketCount++; + if (output[i] === "]") bracketCount--; + + if (bracketCount === 0) return output.slice(startIndex, i + 1); + } + + return null; + } + + while (Date.now() - start < maxWaitMs) { + const output = await runCommand( + `npm run cli getJobStatus --dataset ${datasetDid} --job ${jobId}` + ); + console.log("[CMD]: getJobStatus"); + console.log("[OUTPUT]:\n", output); + + const cleanOutput = stripAnsi(output); + const jsonStr = extractFullJsonArray(cleanOutput); + + if (!jsonStr) { + console.warn("❌ Could not locate full JSON in output, retrying..."); + await new Promise((res) => setTimeout(res, pollIntervalMs)); + continue; + } + + try { + const cleanedJson = jsonStr + .replace(/([{,]\s*)'([^']+?)'\s*:/g, '$1"$2":') + .replace(/:\s*'([^']*?)'/g, ': "$1"') + .replace(/'/g, '"'); + + console.log("🕵️ Cleaned JSON string:\n", cleanedJson); + + const jobs = JSON.parse(cleanedJson); + console.log("✅ Parsed job status JSON:", jobs); + + if (Array.isArray(jobs) && jobs.length > 0) { + const job = jobs[0]; + if (job.status === 70) { + console.log("🎉 Job is finished!"); + return job; + } + } else { + console.warn("⚠️ No jobs found in the parsed JSON, will retry..."); + } + } catch (e) { + console.error("❌ Still failed to parse JSON, will retry...", e); + } + + await new Promise((res) => setTimeout(res, pollIntervalMs)); + } + + throw new Error( + `Job ${jobId} did not finish within ${maxWaitMs / 1000} seconds` + ); + }; + + it("should download compute job results", async () => { + const job = await waitForJobCompletion( + computeDatasetDid, + jobId, + 180000, + 7000 + ); + console.log("Job details:", job); + + const destFolder = path.join(projectRoot, "test-results", jobId); + fs.mkdirSync(destFolder, { recursive: true }); + + const output = await runCommand( + `npm run cli downloadJobResults ${jobId} 1 ${destFolder}` + ); + + expect(output.toLowerCase()).to.match(/download(ed)?/); + + // const files = fs.readdirSync(destFolder); + // expect(files.length).to.be.greaterThan(0, "No result files downloaded"); + // console.log(`Downloaded results to: ${destFolder}`); + }); +});