From f6bd4de5b0258a144a306fba9489b00109c4f512 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Tue, 28 Jan 2025 20:07:22 +0900 Subject: [PATCH] [js-legacy-client] Set up CI (#24) * set up ci for js-legacy client * fix deploy path after program build --- .github/workflows/main.yml | 40 +- clients/js-legacy/.eslintignore | 3 + clients/js-legacy/.eslintrc | 34 ++ clients/js-legacy/package.json | 11 +- clients/js-legacy/pnpm-lock.yaml | 835 ++++++++++++++++++++++++++ clients/js-legacy/src/actions.ts | 68 +-- clients/js-legacy/src/instructions.ts | 21 +- clients/js-legacy/src/state.ts | 10 +- clients/js-legacy/test/basic.ts | 50 +- clients/js-legacy/test/longRecord.ts | 16 +- package.json | 9 +- program/Cargo.toml | 3 + scripts/js/format.mjs | 10 + scripts/js/lint.mjs | 10 + scripts/js/test.mjs | 14 + scripts/program/dump.mjs | 105 ++++ scripts/start-validator.mjs | 132 ++++ scripts/stop-validator.mjs | 13 + 18 files changed, 1256 insertions(+), 128 deletions(-) create mode 100644 clients/js-legacy/.eslintignore create mode 100644 clients/js-legacy/.eslintrc create mode 100644 scripts/js/format.mjs create mode 100644 scripts/js/lint.mjs create mode 100644 scripts/js/test.mjs create mode 100644 scripts/program/dump.mjs create mode 100644 scripts/start-validator.mjs create mode 100644 scripts/stop-validator.mjs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 339a612..6e39fcc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,6 +26,22 @@ jobs: - name: Lint Programs run: pnpm programs:lint + format_and_lint_client_js_legacy: + name: Format & Lint Client JS Legacy + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + + - name: Format Client JS Legacy + run: pnpm clients:js-legacy:format + + - name: Lint Client JS Legacy + run: pnpm clients:js-legacy:lint + audit_rust: name: Audit Rust runs-on: ubuntu-latest @@ -113,7 +129,7 @@ jobs: - name: Save Program Builds For Client Jobs uses: actions/cache/save@v4 with: - path: ./**/*.so + path: ./target/deploy/*.so key: ${{ runner.os }}-builds-${{ github.sha }} test_programs: @@ -133,3 +149,25 @@ jobs: - name: Test Programs run: pnpm programs:test + + test_client_js_legacy: + name: Test Client JS Legacy + runs-on: ubuntu-latest + needs: [format_and_lint_client_js_legacy, build_programs] + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + solana: true + + - name: Restore Program Builds + uses: actions/cache/restore@v4 + with: + path: ./target/deploy/*.so + key: ${{ runner.os }}-builds-${{ github.sha }} + + - name: Test Client JS Legacy + run: pnpm clients:js-legacy:test diff --git a/clients/js-legacy/.eslintignore b/clients/js-legacy/.eslintignore new file mode 100644 index 0000000..94bdfb7 --- /dev/null +++ b/clients/js-legacy/.eslintignore @@ -0,0 +1,3 @@ +test-ledger + +package-lock.json diff --git a/clients/js-legacy/.eslintrc b/clients/js-legacy/.eslintrc new file mode 100644 index 0000000..5aef10a --- /dev/null +++ b/clients/js-legacy/.eslintrc @@ -0,0 +1,34 @@ +{ + "root": true, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "plugin:require-extensions/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint", + "prettier", + "require-extensions" + ], + "rules": { + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/consistent-type-imports": "error" + }, + "overrides": [ + { + "files": [ + "examples/**/*", + "test/**/*" + ], + "rules": { + "require-extensions/require-extensions": "off", + "require-extensions/require-index": "off" + } + } + ] +} diff --git a/clients/js-legacy/package.json b/clients/js-legacy/package.json index 45473ac..966522a 100644 --- a/clients/js-legacy/package.json +++ b/clients/js-legacy/package.json @@ -18,7 +18,7 @@ "lint:fix": "eslint --fix .", "format": "prettier --check src test", "format:fix": "prettier --write src test", - "test": "start-server-and-test 'solana-test-validator --bpf-program recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5 ../../target/deploy/spl_record.so --reset --quiet' http://127.0.0.1:8899/health 'mocha test'" + "test": "mocha test/*" }, "peerDependencies": { "@solana/web3.js": "^1.95.5" @@ -27,15 +27,22 @@ "@solana/codecs-numbers": "^2.0.0" }, "devDependencies": { + "@solana/prettier-config-solana": "0.0.5", + "@eslint/js": "^9.19.0", "@types/chai": "^5.0.1", "@types/node": "^22.10.1", "@types/mocha": "^10.0.10", "chai": "^5.1.2", + "eslint": "^8.57.1", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-require-extensions": "^0.1.1", "mocha": "^11.0.1", "prettier": "^3.4.2", "typescript": "^5.7.2", "start-server-and-test": "^2.0.8", - "ts-node": "^10.9.2" + "ts-node": "^10.9.2", + "typescript-eslint": "^8.22.0" }, "prettier": "@solana/prettier-config-solana" } diff --git a/clients/js-legacy/pnpm-lock.yaml b/clients/js-legacy/pnpm-lock.yaml index 93c8b40..48382b9 100644 --- a/clients/js-legacy/pnpm-lock.yaml +++ b/clients/js-legacy/pnpm-lock.yaml @@ -15,6 +15,12 @@ importers: specifier: ^1.95.5 version: 1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) devDependencies: + '@eslint/js': + specifier: ^9.19.0 + version: 9.19.0 + '@solana/prettier-config-solana': + specifier: 0.0.5 + version: 0.0.5(prettier@3.4.2) '@types/chai': specifier: ^5.0.1 version: 5.0.1 @@ -27,6 +33,18 @@ importers: chai: specifier: ^5.1.2 version: 5.1.2 + eslint: + specifier: ^8.57.1 + version: 8.57.1 + eslint-config-prettier: + specifier: ^10.0.1 + version: 10.0.1(eslint@8.57.1) + eslint-plugin-prettier: + specifier: ^5.2.3 + version: 5.2.3(eslint-config-prettier@10.0.1(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2) + eslint-plugin-require-extensions: + specifier: ^0.1.1 + version: 0.1.3(eslint@8.57.1) mocha: specifier: ^11.0.1 version: 11.0.1 @@ -42,6 +60,9 @@ importers: typescript: specifier: ^5.7.2 version: 5.7.3 + typescript-eslint: + specifier: ^8.22.0 + version: 8.22.0(eslint@8.57.1)(typescript@5.7.3) packages: @@ -53,12 +74,47 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@9.19.0': + resolution: {integrity: sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} '@hapi/topo@5.1.0': resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -81,10 +137,26 @@ packages: resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -117,6 +189,11 @@ packages: peerDependencies: typescript: '>=5' + '@solana/prettier-config-solana@0.0.5': + resolution: {integrity: sha512-igtLH1QaX5xzSLlqteexRIg9X1QKA03xKYQc2qY1TrMDDhxKXoRZOStQPWdita2FVJzxTGz/tdMGC1vS0biRcg==} + peerDependencies: + prettier: ^3.2.0 + '@solana/web3.js@1.98.0': resolution: {integrity: sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==} @@ -162,10 +239,65 @@ packages: '@types/ws@8.5.13': resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@typescript-eslint/eslint-plugin@8.22.0': + resolution: {integrity: sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/parser@8.22.0': + resolution: {integrity: sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/scope-manager@8.22.0': + resolution: {integrity: sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.22.0': + resolution: {integrity: sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/types@8.22.0': + resolution: {integrity: sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.22.0': + resolution: {integrity: sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/utils@8.22.0': + resolution: {integrity: sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/visitor-keys@8.22.0': + resolution: {integrity: sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -179,6 +311,9 @@ packages: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -251,6 +386,9 @@ packages: borsh@0.7.0: resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -271,6 +409,10 @@ packages: resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} engines: {node: '>=6.14.2'} + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -320,6 +462,9 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -344,6 +489,9 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + delay@5.0.0: resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} @@ -360,6 +508,10 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -386,6 +538,70 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-config-prettier@10.0.1: + resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-prettier@5.2.3: + resolution: {integrity: sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-require-extensions@0.1.3: + resolution: {integrity: sha512-T3c1PZ9PIdI3hjV8LdunfYI8gj017UQjzAnCrxuo3wAjneDbTPHdE3oNWInOjMA+z/aBkUtlW5vC0YepYMZIug==} + engines: {node: '>=16'} + peerDependencies: + eslint: '*' + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + event-stream@3.3.4: resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} @@ -400,9 +616,32 @@ packages: resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} engines: {node: '> 0.1.90'} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-stable-stringify@1.0.0: resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} @@ -414,10 +653,17 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + follow-redirects@1.15.9: resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} @@ -438,6 +684,9 @@ packages: from@0.1.7: resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -455,10 +704,25 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -477,6 +741,25 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -497,6 +780,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -532,6 +819,15 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -539,14 +835,24 @@ packages: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + lazy-ass@1.6.0: resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} engines: {node: '> 0.8'} + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -569,6 +875,14 @@ packages: merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -581,6 +895,9 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} @@ -604,6 +921,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -625,10 +945,17 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -640,10 +967,18 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -663,6 +998,14 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + prettier@3.4.2: resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} engines: {node: '>=14'} @@ -676,6 +1019,13 @@ packages: engines: {node: '>= 0.10'} hasBin: true + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -690,15 +1040,36 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rpc-websockets@9.0.4: resolution: {integrity: sha512-yWZWN0M+bivtoNLnaDbtny4XchdAIF5Q4g/ZsC5UC61Ckbp0QczwO8fg44rV3uYmY4WHd+EZQbn90W1d8ojzqQ==} + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -764,9 +1135,16 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + text-encoding-utf-8@1.0.2: resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -777,6 +1155,12 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + ts-api-utils@2.0.0: + resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -794,6 +1178,21 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typescript-eslint@8.22.0: + resolution: {integrity: sha512-Y2rj210FW1Wb6TWXzQc5+P+EWI9/zdS57hLEc0gnyuvdzWo8+Y8brKlbj0muejonhMI/xAZCnZZwjbIfv1CkOw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + typescript@5.7.3: resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} @@ -802,6 +1201,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} @@ -829,6 +1231,10 @@ packages: engines: {node: '>= 8'} hasBin: true + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + workerpool@6.5.1: resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} @@ -840,6 +1246,9 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} @@ -898,12 +1307,49 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.0(supports-color@8.1.1) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.1': {} + + '@eslint/js@9.19.0': {} + '@hapi/hoek@9.3.0': {} '@hapi/topo@5.1.0': dependencies: '@hapi/hoek': 9.3.0 + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -928,9 +1374,23 @@ snapshots: '@noble/hashes@1.7.0': {} + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + '@pkgjs/parseargs@0.11.0': optional: true + '@pkgr/core@0.1.1': {} + '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -960,6 +1420,10 @@ snapshots: commander: 12.1.0 typescript: 5.7.3 + '@solana/prettier-config-solana@0.0.5(prettier@3.4.2)': + dependencies: + prettier: 3.4.2 + '@solana/web3.js@1.98.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.26.0 @@ -1022,11 +1486,94 @@ snapshots: dependencies: '@types/node': 22.10.6 + '@typescript-eslint/eslint-plugin@8.22.0(@typescript-eslint/parser@8.22.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.22.0(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.22.0 + '@typescript-eslint/type-utils': 8.22.0(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.22.0(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.22.0 + eslint: 8.57.1 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.22.0(eslint@8.57.1)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.22.0 + '@typescript-eslint/types': 8.22.0 + '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.22.0 + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.22.0': + dependencies: + '@typescript-eslint/types': 8.22.0 + '@typescript-eslint/visitor-keys': 8.22.0 + + '@typescript-eslint/type-utils@8.22.0(eslint@8.57.1)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.22.0(eslint@8.57.1)(typescript@5.7.3) + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.1 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.22.0': {} + + '@typescript-eslint/typescript-estree@8.22.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.22.0 + '@typescript-eslint/visitor-keys': 8.22.0 + debug: 4.4.0(supports-color@8.1.1) + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.22.0(eslint@8.57.1)(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.22.0 + '@typescript-eslint/types': 8.22.0 + '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.7.3) + eslint: 8.57.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.22.0': + dependencies: + '@typescript-eslint/types': 8.22.0 + eslint-visitor-keys: 4.2.0 + + '@ungap/structured-clone@1.3.0': {} + JSONStream@1.3.5: dependencies: jsonparse: 1.3.1 through: 2.3.8 + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn-walk@8.3.4: dependencies: acorn: 8.14.0 @@ -1037,6 +1584,13 @@ snapshots: dependencies: humanize-ms: 1.2.1 + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} @@ -1100,6 +1654,11 @@ snapshots: bs58: 4.0.1 text-encoding-utf-8: 1.0.2 + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -1124,6 +1683,8 @@ snapshots: node-gyp-build: 4.8.4 optional: true + callsites@3.1.0: {} + camelcase@6.3.0: {} chai@5.1.2: @@ -1177,6 +1738,8 @@ snapshots: commander@2.20.3: {} + concat-map@0.0.1: {} + create-require@1.1.1: {} cross-spawn@7.0.6: @@ -1195,6 +1758,8 @@ snapshots: deep-eql@5.0.2: {} + deep-is@0.1.4: {} + delay@5.0.0: {} delayed-stream@1.0.0: {} @@ -1203,6 +1768,10 @@ snapshots: diff@5.2.0: {} + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + duplexer@0.1.2: {} eastasianwidth@0.2.0: {} @@ -1221,6 +1790,93 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-config-prettier@10.0.1(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + + eslint-plugin-prettier@5.2.3(eslint-config-prettier@10.0.1(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2): + dependencies: + eslint: 8.57.1 + prettier: 3.4.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.2 + optionalDependencies: + eslint-config-prettier: 10.0.1(eslint@8.57.1) + + eslint-plugin-require-extensions@0.1.3(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + event-stream@3.3.4: dependencies: duplexer: 0.1.2 @@ -1247,8 +1903,32 @@ snapshots: eyes@0.1.8: {} + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + fast-stable-stringify@1.0.0: {} + fastq@1.18.0: + dependencies: + reusify: 1.0.4 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + file-uri-to-path@1.0.0: {} fill-range@7.1.1: @@ -1260,8 +1940,16 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + flat-cache@3.2.0: + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + rimraf: 3.0.2 + flat@5.0.2: {} + flatted@3.3.2: {} + follow-redirects@1.15.9(debug@4.4.0): optionalDependencies: debug: 4.4.0(supports-color@8.1.1) @@ -1279,6 +1967,8 @@ snapshots: from@0.1.7: {} + fs.realpath@1.0.0: {} + fsevents@2.3.3: optional: true @@ -1290,6 +1980,10 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + glob@10.4.5: dependencies: foreground-child: 3.3.0 @@ -1299,6 +1993,21 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + graphemer@1.4.0: {} + has-flag@4.0.0: {} he@1.2.0: {} @@ -1311,6 +2020,22 @@ snapshots: ieee754@1.2.1: {} + ignore@5.3.2: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -1325,6 +2050,8 @@ snapshots: is-number@7.0.0: {} + is-path-inside@3.0.3: {} + is-plain-obj@2.1.0: {} is-stream@2.0.1: {} @@ -1373,16 +2100,33 @@ snapshots: dependencies: argparse: 2.0.1 + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-safe@5.0.1: {} jsonparse@1.3.1: {} + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + lazy-ass@1.6.0: {} + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash.merge@4.6.2: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -1400,6 +2144,13 @@ snapshots: merge-stream@2.0.0: {} + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + mime-db@1.52.0: {} mime-types@2.1.35: @@ -1408,6 +2159,10 @@ snapshots: mimic-fn@2.1.0: {} + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + minimatch@5.1.6: dependencies: brace-expansion: 2.0.1 @@ -1445,6 +2200,8 @@ snapshots: ms@2.1.3: {} + natural-compare@1.4.0: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -1458,10 +2215,23 @@ snapshots: dependencies: path-key: 3.1.1 + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -1472,8 +2242,14 @@ snapshots: package-json-from-dist@1.0.1: {} + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-scurry@1.11.1: @@ -1489,6 +2265,12 @@ snapshots: picomatch@2.3.1: {} + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + prettier@3.4.2: {} proxy-from-env@1.1.0: {} @@ -1497,6 +2279,10 @@ snapshots: dependencies: event-stream: 3.3.4 + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -1509,6 +2295,14 @@ snapshots: require-directory@2.1.1: {} + resolve-from@4.0.0: {} + + reusify@1.0.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + rpc-websockets@9.0.4: dependencies: '@swc/helpers': 0.5.15 @@ -1522,12 +2316,18 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + rxjs@7.8.1: dependencies: tslib: 2.8.1 safe-buffer@5.2.1: {} + semver@7.6.3: {} + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -1597,8 +2397,15 @@ snapshots: dependencies: has-flag: 4.0.0 + synckit@0.9.2: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.1 + text-encoding-utf-8@1.0.2: {} + text-table@0.2.0: {} + through@2.3.8: {} to-regex-range@5.0.1: @@ -1607,6 +2414,10 @@ snapshots: tr46@0.0.3: {} + ts-api-utils@2.0.0(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + ts-node@10.9.2(@types/node@22.10.6)(typescript@5.7.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -1627,10 +2438,30 @@ snapshots: tslib@2.8.1: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + typescript-eslint@8.22.0(eslint@8.57.1)(typescript@5.7.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.22.0(@typescript-eslint/parser@8.22.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/parser': 8.22.0(eslint@8.57.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.22.0(eslint@8.57.1)(typescript@5.7.3) + eslint: 8.57.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + typescript@5.7.3: {} undici-types@6.20.0: {} + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + utf-8-validate@5.0.10: dependencies: node-gyp-build: 4.8.4 @@ -1661,6 +2492,8 @@ snapshots: dependencies: isexe: 2.0.0 + word-wrap@1.2.5: {} + workerpool@6.5.1: {} wrap-ansi@7.0.0: @@ -1675,6 +2508,8 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrappy@1.0.2: {} + ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 diff --git a/clients/js-legacy/src/actions.ts b/clients/js-legacy/src/actions.ts index d3e8f69..710435a 100644 --- a/clients/js-legacy/src/actions.ts +++ b/clients/js-legacy/src/actions.ts @@ -1,18 +1,18 @@ -import type { ConfirmOptions, Connection, Signer } from '@solana/web3.js'; -import { PublicKey, sendAndConfirmTransaction, SystemProgram, Transaction } from '@solana/web3.js'; +import type { ConfirmOptions, Connection, Signer, PublicKey } from '@solana/web3.js'; +import { sendAndConfirmTransaction, SystemProgram, Transaction } from '@solana/web3.js'; import { RECORD_PROGRAM_ID, RECORD_META_DATA_SIZE, RECORD_CHUNK_SIZE_PRE_INITIALIZE, RECORD_CHUNK_SIZE_POST_INITIALIZE, -} from './constants'; +} from './constants.js'; import { createInitializeInstruction, createWriteInstruction, createSetAuthorityInstruction, createCloseAccountInstruction, createReallocateInstruction, -} from './instructions'; +} from './instructions.js'; /** * Initialize a record account @@ -45,11 +45,7 @@ export async function createRecord( lamports, programId, }), - createInitializeInstruction( - record.publicKey, - authority, - programId, - ) + createInitializeInstruction(record.publicKey, authority, programId), ); return await sendAndConfirmTransaction(connection, transaction, [payer, record], confirmOptions); } @@ -77,13 +73,10 @@ export async function writeRecord( confirmOptions?: ConfirmOptions, programId = RECORD_PROGRAM_ID, ) { - let transactionResults = []; + const transactionResults = []; let bufferOffset = 0; while (bufferOffset < buffer.length) { - const currentChunkBuffer = buffer.subarray( - bufferOffset, - bufferOffset + RECORD_CHUNK_SIZE_POST_INITIALIZE - ); + const currentChunkBuffer = buffer.subarray(bufferOffset, bufferOffset + RECORD_CHUNK_SIZE_POST_INITIALIZE); const transaction = new Transaction().add( createWriteInstruction( record, @@ -91,7 +84,7 @@ export async function writeRecord( offset + BigInt(bufferOffset), currentChunkBuffer, programId, - ) + ), ); transactionResults.push(sendAndConfirmTransaction(connection, transaction, [payer, authority], confirmOptions)); bufferOffset = bufferOffset + RECORD_CHUNK_SIZE_POST_INITIALIZE; @@ -134,24 +127,14 @@ export async function createInitializeWriteRecord( lamports, programId, }), - createInitializeInstruction( - record.publicKey, - authority.publicKey, - programId, - ), - createWriteInstruction( - record.publicKey, - authority.publicKey, - offset, - firstChunkBuffer, - programId, - ) + createInitializeInstruction(record.publicKey, authority.publicKey, programId), + createWriteInstruction(record.publicKey, authority.publicKey, offset, firstChunkBuffer, programId), ); const signature = await sendAndConfirmTransaction( connection, transaction, [payer, authority, record], - confirmOptions + confirmOptions, ); if (buffer.length > RECORD_CHUNK_SIZE_PRE_INITIALIZE) { @@ -194,12 +177,7 @@ export async function setAuthority( programId = RECORD_PROGRAM_ID, ) { const transaction = new Transaction().add( - createSetAuthorityInstruction( - record, - currentAuthority.publicKey, - newAuthority, - programId, - ) + createSetAuthorityInstruction(record, currentAuthority.publicKey, newAuthority, programId), ); return await sendAndConfirmTransaction(connection, transaction, [payer, currentAuthority], confirmOptions); } @@ -226,12 +204,7 @@ export async function closeRecord( programId = RECORD_PROGRAM_ID, ) { const transaction = new Transaction().add( - createCloseAccountInstruction( - record, - authority.publicKey, - receiver, - programId, - ) + createCloseAccountInstruction(record, authority.publicKey, receiver, programId), ); return await sendAndConfirmTransaction(connection, transaction, [payer, authority], confirmOptions); } @@ -259,7 +232,7 @@ export async function reallocateRecord( confirmOptions?: ConfirmOptions, programId = RECORD_PROGRAM_ID, ) { - let transaction = new Transaction(); + const transaction = new Transaction(); if (fundAccount) { const currentLamports = await connection.getBalance(record); const newAccountSize = dataLength + BigInt(RECORD_META_DATA_SIZE); @@ -272,19 +245,12 @@ export async function reallocateRecord( fromPubkey: payer.publicKey, toPubkey: record, lamports: neededLamports, - }) + }), ); } else { - console.log("no additional funds needed for space") + console.log('no additional funds needed for space'); } } - transaction.add( - createReallocateInstruction( - record, - authority.publicKey, - dataLength, - programId, - ) - ); + transaction.add(createReallocateInstruction(record, authority.publicKey, dataLength, programId)); return await sendAndConfirmTransaction(connection, transaction, [payer, authority], confirmOptions); } diff --git a/clients/js-legacy/src/instructions.ts b/clients/js-legacy/src/instructions.ts index c30112a..275773e 100644 --- a/clients/js-legacy/src/instructions.ts +++ b/clients/js-legacy/src/instructions.ts @@ -1,6 +1,7 @@ -import { PublicKey, TransactionInstruction } from '@solana/web3.js'; +import type { PublicKey } from '@solana/web3.js'; +import { TransactionInstruction } from '@solana/web3.js'; import { getU32Codec, getU64Codec } from '@solana/codecs-numbers'; -import { RECORD_PROGRAM_ID } from './constants'; +import { RECORD_PROGRAM_ID } from './constants.js'; export enum RecordInstruction { Initialize = 0, @@ -18,11 +19,7 @@ export enum RecordInstruction { * * @return Instruction to add to a transaction */ -export function createInitializeInstruction( - record: PublicKey, - authority: PublicKey, - programId = RECORD_PROGRAM_ID, -) { +export function createInitializeInstruction(record: PublicKey, authority: PublicKey, programId = RECORD_PROGRAM_ID) { const keys = [ { pubkey: record, isSigner: false, isWritable: true }, { pubkey: authority, isSigner: false, isWritable: false }, @@ -52,12 +49,12 @@ export function createWriteInstruction( const keys = [ { pubkey: record, isSigner: false, isWritable: true }, { pubkey: authority, isSigner: true, isWritable: false }, - ] + ]; const data = Buffer.from([ RecordInstruction.Write, ...getU64Codec().encode(offset), ...getU32Codec().encode(buffer.length), - ...buffer + ...buffer, ]); return new TransactionInstruction({ keys, programId, data }); @@ -82,7 +79,7 @@ export function createSetAuthorityInstruction( { pubkey: record, isSigner: false, isWritable: true }, { pubkey: currentAuthority, isSigner: true, isWritable: false }, { pubkey: newAuthority, isSigner: false, isWritable: false }, - ] + ]; const data = Buffer.from([RecordInstruction.SetAuthority]); return new TransactionInstruction({ keys, programId, data }); @@ -107,7 +104,7 @@ export function createCloseAccountInstruction( { pubkey: record, isSigner: false, isWritable: true }, { pubkey: authority, isSigner: true, isWritable: false }, { pubkey: receiver, isSigner: false, isWritable: true }, - ] + ]; const data = Buffer.from([RecordInstruction.CloseAccount]); return new TransactionInstruction({ keys, programId, data }); @@ -131,7 +128,7 @@ export function createReallocateInstruction( const keys = [ { pubkey: record, isSigner: false, isWritable: true }, { pubkey: authority, isSigner: true, isWritable: false }, - ] + ]; const data = Buffer.from([RecordInstruction.Reallocate, ...getU64Codec().encode(dataLength)]); return new TransactionInstruction({ keys, programId, data }); diff --git a/clients/js-legacy/src/state.ts b/clients/js-legacy/src/state.ts index fca4e3a..041d0c3 100644 --- a/clients/js-legacy/src/state.ts +++ b/clients/js-legacy/src/state.ts @@ -1,6 +1,6 @@ import type { AccountInfo, Commitment, Connection } from '@solana/web3.js'; import { PublicKey } from '@solana/web3.js'; -import { RECORD_META_DATA_SIZE } from './constants'; +import { RECORD_META_DATA_SIZE } from './constants.js'; export interface RecordAccount { version: number; @@ -8,11 +8,7 @@ export interface RecordAccount { recordData: Buffer; } -export async function getRecordAccount( - connection: Connection, - address: PublicKey, - commitment?: Commitment, -) { +export async function getRecordAccount(connection: Connection, address: PublicKey, commitment?: Commitment) { const info = await connection.getAccountInfo(address, commitment); return parseRecordAccount(info); } @@ -21,7 +17,7 @@ export function parseRecordAccount(accountInfo: AccountInfo | null) { if (accountInfo !== null && accountInfo.data.length >= RECORD_META_DATA_SIZE) { const version = accountInfo.data[0]; const authority = new PublicKey(accountInfo.data.subarray(1, RECORD_META_DATA_SIZE)); - const recordData = accountInfo.data.subarray(RECORD_META_DATA_SIZE) + const recordData = accountInfo.data.subarray(RECORD_META_DATA_SIZE); return { version, authority, recordData }; } else { return null; diff --git a/clients/js-legacy/test/basic.ts b/clients/js-legacy/test/basic.ts index 7319d79..114d1ae 100644 --- a/clients/js-legacy/test/basic.ts +++ b/clients/js-legacy/test/basic.ts @@ -33,13 +33,7 @@ describe('basic instructions', () => { }); it('initialize', async () => { - await createRecord( - connection, - payer, - recordAccount, - recordAuthority.publicKey, - initialRecordSize, - ); + await createRecord(connection, payer, recordAccount, recordAuthority.publicKey, initialRecordSize); const recordAccountData = await getRecordAccount(connection, recordAccount.publicKey); expect(recordAccountData).to.not.equal(null); @@ -51,65 +45,39 @@ describe('basic instructions', () => { }); it('reallocate', async () => { - await reallocateRecord( - connection, - payer, - recordAccount.publicKey, - recordAuthority, - newRecordSize, - true, - ); + await reallocateRecord(connection, payer, recordAccount.publicKey, recordAuthority, newRecordSize, true); const recordAccountData = await getRecordAccount(connection, recordAccount.publicKey); expect(recordAccountData).to.not.equal(null); if (recordAccountData !== null) { expect(recordAccountData.recordData).to.eql(Buffer.from([0, 0, 0, 0, 0])); } - }) + }); it('write', async () => { - await writeRecord( - connection, - payer, - recordAccount.publicKey, - recordAuthority, - BigInt(0), - recordData - ); + await writeRecord(connection, payer, recordAccount.publicKey, recordAuthority, BigInt(0), recordData); const recordAccountData = await getRecordAccount(connection, recordAccount.publicKey); if (recordAccountData !== null) { expect(recordAccountData.recordData).to.eql(Buffer.from([0, 1, 2, 3, 4])); } - }) + }); it('set authority', async () => { - await setAuthority( - connection, - payer, - recordAccount.publicKey, - recordAuthority, - newRecordAuthority.publicKey, - ); + await setAuthority(connection, payer, recordAccount.publicKey, recordAuthority, newRecordAuthority.publicKey); const recordAccountData = await getRecordAccount(connection, recordAccount.publicKey); if (recordAccountData !== null) { expect(recordAccountData.authority).to.eql(newRecordAuthority.publicKey); } - }) + }); it('close', async () => { const destination = Keypair.generate(); const recordAccountSize = BigInt(RECORD_META_DATA_SIZE) + newRecordSize; const recordAccountLamports = await connection.getMinimumBalanceForRentExemption(Number(recordAccountSize)); - await closeRecord( - connection, - payer, - recordAccount.publicKey, - newRecordAuthority, - destination.publicKey, - ) + await closeRecord(connection, payer, recordAccount.publicKey, newRecordAuthority, destination.publicKey); const closedRecordInfo = await connection.getAccountInfo(recordAccount.publicKey); expect(closedRecordInfo).to.equal(null); @@ -120,4 +88,4 @@ describe('basic instructions', () => { expect(destinationInfo.lamports).to.eql(recordAccountLamports); } }); -}) +}); diff --git a/clients/js-legacy/test/longRecord.ts b/clients/js-legacy/test/longRecord.ts index 9156302..66d7c19 100644 --- a/clients/js-legacy/test/longRecord.ts +++ b/clients/js-legacy/test/longRecord.ts @@ -2,10 +2,7 @@ import { expect } from 'chai'; import type { Connection, Signer } from '@solana/web3.js'; import { Keypair } from '@solana/web3.js'; import { newAccountWithLamports, getConnection } from './common'; -import { - createInitializeWriteRecord, - getRecordAccount, -} from '../src'; +import { createInitializeWriteRecord, getRecordAccount } from '../src'; describe('long record data', () => { let connection: Connection; @@ -22,14 +19,7 @@ describe('long record data', () => { }); it('initialize and write', async () => { - await createInitializeWriteRecord( - connection, - payer, - recordAccount, - recordAuthority, - BigInt(0), - recordData, - ); + await createInitializeWriteRecord(connection, payer, recordAccount, recordAuthority, BigInt(0), recordData); const recordAccountData = await getRecordAccount(connection, recordAccount.publicKey); expect(recordAccountData).to.not.equal(null); @@ -39,4 +29,4 @@ describe('long record data', () => { expect(recordAccountData.recordData).to.eql(recordData); } }); -}) +}); diff --git a/package.json b/package.json index 88fcae0..bb0fb7f 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,19 @@ "programs:test": "zx ./scripts/program/test.mjs", "programs:format": "zx ./scripts/program/format.mjs", "programs:lint": "zx ./scripts/program/lint.mjs", + "programs:dump": "zx ./scripts/program/dump.mjs", "solana:check": "zx ./scripts/check-solana-version.mjs", "solana:link": "zx ./scripts/link-solana-version.mjs", + "validator:start": "zx ./scripts/start-validator.mjs", + "validator:restart": "pnpm validator:start --restart", + "validator:stop": "zx ./scripts/stop-validator.mjs", "template:upgrade": "zx ./scripts/upgrade-template.mjs", "rust:spellcheck": "cargo spellcheck --code 1", "rust:audit": "zx ./scripts/audit-rust.mjs", - "rust:semver": "cargo semver-checks" + "rust:semver": "cargo semver-checks", + "clients:js-legacy:format": "zx ./scripts/js/format.mjs clients/js-legacy", + "clients:js-legacy:lint": "zx ./scripts/js/lint.mjs clients/js-legacy", + "clients:js-legacy:test": "zx ./scripts/js/test.mjs clients/js-legacy" }, "devDependencies": { "@iarna/toml": "^2.2.5", diff --git a/program/Cargo.toml b/program/Cargo.toml index f6aed8e..c9fab44 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -38,3 +38,6 @@ targets = ["x86_64-unknown-linux-gnu"] [lints] workspace = true + +[package.metadata.solana] +program-id = "recr1L3PCGKLbckBqMNcJhuuyU1zgo8nBhfLVsJNwr5" diff --git a/scripts/js/format.mjs b/scripts/js/format.mjs new file mode 100644 index 0000000..e6978dc --- /dev/null +++ b/scripts/js/format.mjs @@ -0,0 +1,10 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); + +// Format the client using Prettier. +cd(path.join(workingDirectory, folder)); +await $`pnpm install`; +await $`pnpm format ${args}`; diff --git a/scripts/js/lint.mjs b/scripts/js/lint.mjs new file mode 100644 index 0000000..a4f25a7 --- /dev/null +++ b/scripts/js/lint.mjs @@ -0,0 +1,10 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); + +// Check the client using ESLint. +cd(path.join(workingDirectory, folder)); +await $`pnpm install`; +await $`pnpm lint ${args}`; diff --git a/scripts/js/test.mjs b/scripts/js/test.mjs new file mode 100644 index 0000000..b39d60e --- /dev/null +++ b/scripts/js/test.mjs @@ -0,0 +1,14 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +const [folder, ...args] = cliArguments(); + +// Start the local validator, or restart it if it is already running. +await $`pnpm validator:restart`; + +// Build the client and run the tests. +cd(path.join(workingDirectory, folder)); +await $`pnpm install`; +await $`pnpm build`; +await $`pnpm test ${args}`; diff --git a/scripts/program/dump.mjs b/scripts/program/dump.mjs new file mode 100644 index 0000000..7e7db12 --- /dev/null +++ b/scripts/program/dump.mjs @@ -0,0 +1,105 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { + getExternalAccountAddresses, + getExternalProgramAddresses, + getExternalProgramOutputDir, +} from '../utils.mjs'; + +// Get input from environment variables. +const rpc = process.env.RPC ?? 'https://api.mainnet-beta.solana.com'; +const outputDir = getExternalProgramOutputDir(); +await dump(); + +/** Dump external programs binaries and accounts if needed. */ +async function dump() { + // Ensure we have some external accounts to dump. + const programs = getExternalProgramAddresses(); + const accounts = getExternalAccountAddresses(); + const external = [ + ...programs.map((program) => [program, 'so']), + ...accounts.map((account) => [account, 'json']), + ]; + + if (external.length === 0) return; + echo(`Dumping external accounts to '${outputDir}':`); + + // Create the output directory if needed. + $`mkdir -p ${outputDir}`.quiet(); + + // Copy the binaries from the chain or warn if they are different. + await Promise.all( + external.map(async ([address, extension]) => { + const binary = `${address}.${extension}`; + const hasBinary = await fs.exists(`${outputDir}/${binary}`); + + if (!hasBinary) { + await copyFromChain(address, extension); + echo(`Wrote account data to ${outputDir}/${binary}`); + return; + } + + let sha = 'sha256sum'; + let options = []; + let hasShaChecksum = await which('sha256sum', { nothrow: true }); + + // We might not have sha256sum on some systems, so we try shasum as well. + if (!hasShaChecksum) { + hasShaChecksum = await which('shasum', { nothrow: true }); + + if (hasShaChecksum) { + sha = 'shasum'; + options = ['-a', '256']; + } + } + + if (hasShaChecksum) { + try { + await copyFromChain(address, extension, 'onchain-'); + const [onChainHash, localHash] = await Promise.all([ + $`${sha} ${options} -b ${outputDir}/onchain-${binary} | cut -d ' ' -f 1`.quiet(), + $`${sha} ${options} -b ${outputDir}/${binary} | cut -d ' ' -f 1`.quiet(), + ]); + + if (onChainHash.toString() !== localHash.toString()) { + echo( + chalk.yellow('[ WARNING ]'), + `on-chain and local binaries are different for '${address}'` + ); + } else { + echo( + chalk.green('[ SKIPPED ]'), + `on-chain and local binaries are the same for '${address}'` + ); + } + + await $`rm ${outputDir}/onchain-${binary}`.quiet(); + } catch (error) { + echo( + chalk.yellow('[ WARNING ]'), + `skipped check for '${address}' (error copying data from '${rpc}')` + ); + } + } else { + echo( + chalk.yellow('[ WARNING ]'), + `skipped check for '${address}' (missing 'sha256sum' command)` + ); + } + }) + ); +} + +/** Helper function to copy external programs or accounts binaries from the chain. */ +async function copyFromChain(address, extension, prefix = '') { + const binary = `${prefix}${address}.${extension}`; + switch (extension) { + case 'json': + return $`solana account -u ${rpc} ${address} -o ${outputDir}/${binary} --output json >/dev/null`.quiet(); + case 'so': + return $`solana program dump -u ${rpc} ${address} ${outputDir}/${binary} >/dev/null`.quiet(); + default: + echo(chalk.red(`[ ERROR ] unknown account type for '${binary}'`)); + await $`exit 1`; + } +} diff --git a/scripts/start-validator.mjs b/scripts/start-validator.mjs new file mode 100644 index 0000000..ffdfe4f --- /dev/null +++ b/scripts/start-validator.mjs @@ -0,0 +1,132 @@ +#!/usr/bin/env zx +import { spawn } from 'node:child_process'; +import fs from 'node:fs'; +import 'zx/globals'; +import { + getCargo, + getExternalAccountAddresses, + getExternalProgramAddresses, + getExternalProgramOutputDir, + getProgramFolders, +} from './utils.mjs'; + +// Check Solana version. +await $`pnpm solana:check`; + +// Options and arguments. +const restart = argv['restart']; + +// Keep the validator running when not using the restart flag. +const isValidatorRunning = (await $`lsof -t -i:8899`.quiet().exitCode) === 0; +if (!restart && isValidatorRunning) { + echo(chalk.yellow('Local validator is already running.')); + process.exit(); +} + +// Dump external programs and accounts. +await $`pnpm programs:dump`; + +// Initial message. +const verb = isValidatorRunning ? 'Restarting' : 'Starting'; + +// Get programs and accounts. +const programs = [...getPrograms(), ...getExternalPrograms(), ...getFixturePrograms()]; +const programPluralized = programs.length === 1 ? 'program' : 'programs'; +const accounts = [...getExternalAccounts()]; +const accountsPluralized = accounts.length === 1 ? 'account' : 'accounts'; + +echo( + `${verb} local validator with ${programs.length} custom ${programPluralized}` + + (accounts.length > 0 + ? ` and ${accounts.length} external ${accountsPluralized}...` + : `...`) +); + +// Kill the validator if it's already running. +if (isValidatorRunning) { + await $`pkill -f solana-test-validator`.quiet(); + await sleep(1000); +} + +// Global validator arguments. +const args = [/* Reset ledger */ '-r']; + +// Load programs. +programs.forEach(({ programId, deployPath }) => { + args.push(/* Load BPF program */ '--bpf-program', programId, deployPath); +}); + +// Load accounts. +accounts.forEach(({ account, deployPath }) => { + args.push(/* Load account */ '--account', account, deployPath); +}); + +// Start the validator in detached mode. +const cliLogs = path.join(os.tmpdir(), 'validator-cli.log'); +fs.writeFileSync(cliLogs, '', () => { }); +const out = fs.openSync(cliLogs, 'a'); +const err = fs.openSync(cliLogs, 'a'); +const validator = spawn('solana-test-validator', args, { + detached: true, + stdio: ['ignore', out, err], +}); +validator.unref(); + +// Wait for the validator to stabilize. +const waitForValidator = spinner( + 'Waiting for local validator to stabilize...', + () => + new Promise((resolve, reject) => { + setInterval(() => { + const logs = fs.readFileSync(cliLogs, 'utf8'); + if (validator.exitCode !== null) { + reject(logs); + } else if (logs.includes('Confirmed Slot: 1')) { + resolve(); + } + }, 1000); + }) +); + +try { + await waitForValidator; + echo(chalk.green('Local validator is up and running!')); +} catch (error) { + echo(error); + echo(chalk.red('Could not start local validator.')); +} finally { + fs.rmSync(cliLogs); + process.exit(); +} + +function getPrograms() { + const binaryDir = path.join(__dirname, '..', 'target', 'deploy'); + return getProgramFolders().map((folder) => { + const cargo = getCargo(folder); + const name = cargo.package.name.replace(/-/g, '_'); + return { + programId: cargo.package.metadata.solana['program-id'], + deployPath: path.join(binaryDir, `${name}.so`), + }; + }); +} + +function getExternalPrograms() { + const binaryDir = getExternalProgramOutputDir(); + return getExternalProgramAddresses().map((address) => ({ + programId: address, + deployPath: path.join(binaryDir, `${address}.so`), + })); +} + +function getFixturePrograms() { + return []; +} + +function getExternalAccounts() { + const binaryDir = getExternalProgramOutputDir(); + return getExternalAccountAddresses().map((address) => ({ + account: address, + deployPath: path.join(binaryDir, `${address}.json`), + })); +} diff --git a/scripts/stop-validator.mjs b/scripts/stop-validator.mjs new file mode 100644 index 0000000..b1f3100 --- /dev/null +++ b/scripts/stop-validator.mjs @@ -0,0 +1,13 @@ +#!/usr/bin/env zx +import 'zx/globals'; + +const isValidatorRunning = (await $`lsof -t -i:8899`.quiet().exitCode) === 0; + +if (isValidatorRunning) { + // Kill the validator if it's already running. + await $`pkill -f solana-test-validator`.quiet(); + await sleep(1000); + echo(chalk.green('Local validator terminated!')); +} else { + echo(chalk.yellow('Local validator is not running.')); +}