diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 5ba30ed..2251716 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -13,6 +13,9 @@ on: jobs: test: runs-on: ubuntu-latest + defaults: + run: + working-directory: ./backend steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index b87c51e..d25f88e 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -3,7 +3,7 @@ name: Contracts CI on: push: paths: - - 'contracts/**' # Only trigger when contracts change + - 'contracts/**' branches: [main, develop] pull_request: paths: @@ -13,33 +13,33 @@ on: jobs: test: runs-on: ubuntu-latest + defaults: + run: + working-directory: ./contracts steps: - - uses: actions/checkout@v4 # Updated to v4 (latest) + - uses: actions/checkout@v4 - # Install Scarb (Cairo package manager) - uses: software-mansion/setup-scarb@v1 with: - scarb-version: "2.11.3" # Pinned version - - # Install Starknet Foundry (snforge) + scarb-version: "2.11.3" + - uses: foundry-rs/setup-snfoundry@v3 with: - starknet-foundry-version: "0.39.0" # Pinned version + starknet-foundry-version: "0.39.0" + - # Verify installations - name: Check Versions run: | scarb --version snforge -V - # Format check (similar to Rust's `cargo fmt`) + - name: Format Check run: scarb fmt --check - # Run Starknet tests + - name: Run Tests run: snforge test - # Build the project (compile Cairo code) - name: Build Project run: scarb build \ No newline at end of file diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 2fb45d1..5239296 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -30,6 +30,7 @@ jobs: with: node-version: '20' cache: 'pnpm' + cache-dependency-path: frontend/pnpm-lock.yaml - name: Install dependencies run: pnpm install diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json new file mode 100644 index 0000000..7f73765 --- /dev/null +++ b/frontend/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "extends": [ + "next/core-web-vitals", + "next/typescript" + ], + "overrides": [ + { + "files": ["**/*.ts", "**/*.tsx"], + "rules": { + "@typescript-eslint/no-unused-vars": "off" + } + } + ] +} diff --git a/frontend/package.json b/frontend/package.json index 1593ac8..8b04a41 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,9 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,md}'", + "format:check": "prettier --check 'src/**/*.{js,jsx,ts,tsx,json,css,md}'" }, "dependencies": { "@headlessui/react": "^2.2.0", @@ -14,7 +16,6 @@ "@radix-ui/react-dropdown-menu": "^2.1.12", "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-tabs": "^1.1.3", - "@starknet-react/chains": "^3.1.3", "@starknet-react/core": "^3.7.4", "@starknet-react/typescript-config": "^0.0.1", @@ -39,14 +40,18 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", + "@next/eslint-plugin-next": "^15.3.1", "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", + "@types/node": "^20.17.32", + "@types/react": "^19.1.2", "@types/react-dom": "^19", - "eslint": "^9", + "eslint": "^8.57.0", "eslint-config-next": "15.3.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "prettier": "^3.5.3", "tailwindcss": "^4", "tw-animate-css": "^1.2.8", - "typescript": "^5" + "typescript": "^5.8.3" } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 588cfe7..408f54a 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -90,24 +90,36 @@ importers: '@eslint/eslintrc': specifier: ^3 version: 3.3.1 + '@next/eslint-plugin-next': + specifier: ^15.3.1 + version: 15.3.1 '@tailwindcss/postcss': specifier: ^4 version: 4.1.5 '@types/node': - specifier: ^20 + specifier: ^20.17.32 version: 20.17.32 '@types/react': - specifier: ^19 + specifier: ^19.1.2 version: 19.1.2 '@types/react-dom': specifier: ^19 version: 19.1.3(@types/react@19.1.2) eslint: - specifier: ^9 - version: 9.26.0(jiti@2.4.2) + specifier: ^8.57.0 + version: 8.57.0 eslint-config-next: specifier: 15.3.1 - version: 15.3.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + version: 15.3.1(eslint@8.57.0)(typescript@5.8.3) + eslint-plugin-react: + specifier: ^7.37.5 + version: 7.37.5(eslint@8.57.0) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@8.57.0) + prettier: + specifier: ^3.5.3 + version: 3.5.3 tailwindcss: specifier: ^4 version: 4.1.5 @@ -115,7 +127,7 @@ importers: specifier: ^1.2.8 version: 1.2.9 typescript: - specifier: ^5 + specifier: ^5.8.3 version: 5.8.3 packages: @@ -146,33 +158,17 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.20.0': - resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.2.2': - resolution: {integrity: sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.13.0': - resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.26.0': - resolution: {integrity: sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.2.8': - resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} '@floating-ui/core@1.7.0': resolution: {integrity: sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==} @@ -208,25 +204,18 @@ packages: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} - engines: {node: '>=18.18.0'} + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + 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/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} - - '@humanwhocodes/retry@0.4.2': - resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} - engines: {node: '>=18.18'} + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} @@ -333,10 +322,6 @@ packages: cpu: [x64] os: [win32] - '@modelcontextprotocol/sdk@1.11.0': - resolution: {integrity: sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==} - engines: {node: '>=18'} - '@napi-rs/wasm-runtime@0.2.9': resolution: {integrity: sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==} @@ -1057,12 +1042,6 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -1136,6 +1115,9 @@ packages: resolution: {integrity: sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@unrs/resolver-binding-darwin-arm64@1.7.2': resolution: {integrity: sha512-vxtBno4xvowwNmO/ASL0Y45TpHqmNkAaDtz4Jqb+clmcVSSl8XCG/PNFFkGsXXXS6AMjP+ja/TtNCFFa1QwLRg==} cpu: [arm64] @@ -1236,10 +1218,6 @@ packages: zod: optional: true - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1329,10 +1307,6 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} - engines: {node: '>=18'} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1347,10 +1321,6 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1409,26 +1379,6 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - content-disposition@1.0.0: - resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -1485,10 +1435,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} @@ -1500,23 +1446,20 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - enhanced-resolve@5.18.1: resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} engines: {node: '>=10.13.0'} @@ -1561,9 +1504,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1642,9 +1582,9 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + 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==} @@ -1654,20 +1594,20 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.26.0: - resolution: {integrity: sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + 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 - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true espree@10.3.0: resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -1689,31 +1629,9 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - eventsource-parser@3.0.1: - resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.6: - resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} - engines: {node: '>=18.0.0'} - - express-rate-limit@7.5.0: - resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} - engines: {node: '>= 16'} - peerDependencies: - express: ^4.11 || 5 || ^5.0.0-beta.1 - - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} - engines: {node: '>= 18'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1745,25 +1663,21 @@ packages: fetch-cookie@3.0.1: resolution: {integrity: sha512-ZGXe8Y5Z/1FWqQ9q/CrJhkUD73DyBU9VF0hBQmEO/wPHe4A9PKTjplFDLeFX8aOsYypZUcX5Ji/eByn3VCVO3Q==} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} @@ -1772,10 +1686,6 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - framer-motion@12.9.4: resolution: {integrity: sha512-yaeGDmGQ3eCQEwZ95/pRQMaSh/Q4E2CK6JYOclG/PdjyQad0MULJ+JFVV8911Fl5a6tF6o0wgW8Dpl5Qx4Adjg==} peerDependencies: @@ -1790,14 +1700,13 @@ packages: react-dom: optional: true - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -1843,6 +1752,14 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + 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'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -1893,14 +1810,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1913,6 +1822,10 @@ packages: 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==} @@ -1920,10 +1833,6 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -1994,8 +1903,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} @@ -2196,14 +2106,6 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2212,14 +2114,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2252,10 +2146,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - next@14.2.28: resolution: {integrity: sha512-QLEIP/kYXynIxtcKB6vNjtWLVs3Y4Sb+EClTC/CSVzdLD1gIuItccpu/n1lhmduffI32iPGEK2cLLxxt28qgYA==} engines: {node: '>=18.17.0'} @@ -2315,10 +2205,6 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2356,14 +2242,14 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - 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'} @@ -2371,10 +2257,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-to-regexp@8.2.0: - resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} - engines: {node: '>=16'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2386,10 +2268,6 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} - engines: {node: '>=16.20.0'} - possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -2406,6 +2284,11 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -2467,10 +2350,6 @@ packages: prosemirror-view@1.39.2: resolution: {integrity: sha512-BmOkml0QWNob165gyUxXi5K5CVUgVPpqMEAAml/qzgKn9boLUWVPzQ6LtzXw8Cn1GtRQX4ELumPxqtLTDaAKtg==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} @@ -2482,24 +2361,12 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.0: - resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} - engines: {node: '>= 0.8'} - react-datepicker@8.3.0: resolution: {integrity: sha512-DhfrIJnTPJTUVRtXU7c7zooug40rD6q+Fc8UTCt19dYEotLpDQgTN98MfocY6Rc4S99oOFFEoxyanOM/TKauuw==} peerDependencies: @@ -2598,13 +2465,14 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 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 + rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2612,9 +2480,6 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -2623,9 +2488,6 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -2638,14 +2500,6 @@ packages: engines: {node: '>=10'} hasBin: true - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} - - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} - engines: {node: '>= 18'} - set-cookie-parser@2.7.1: resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} @@ -2661,9 +2515,6 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.33.5: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -2705,10 +2556,6 @@ packages: starknet@6.24.1: resolution: {integrity: sha512-g7tiCt73berhcNi41otlN3T3kxZnIvZhMi8WdC21Y6GC6zoQgbI2z1t7JAZF9c4xZiomlanwVnurcpyfEdyMpg==} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -2791,6 +2638,9 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -2802,10 +2652,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - tough-cookie@4.1.4: resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} @@ -2835,9 +2681,9 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} @@ -2878,10 +2724,6 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - unrs-resolver@1.7.2: resolution: {integrity: sha512-BBKpaylOW8KbHsu378Zky/dGh4ckT/4NW/0SHRABdqRLcQJ2dAOjDo9g97p04sWflm0kqPqpUatxReNV/dqI5A==} @@ -2916,10 +2758,6 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - viem@2.28.3: resolution: {integrity: sha512-kGYmSHNmzXqg7uZlaV6OEL1p68Z45BYTRPsUM0jYLmOn2zWy6DRA+YxntKnt6jBiCPjiWbVrbFm5QS6TWnfAXQ==} peerDependencies: @@ -3000,11 +2838,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod-to-json-schema@3.24.5: - resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} - peerDependencies: - zod: ^3.24.1 - zod@3.24.3: resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} @@ -3030,27 +2863,27 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@9.26.0(jiti@2.4.2))': + '@eslint-community/eslint-utils@4.7.0(eslint@8.57.0)': dependencies: - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.20.0': + '@eslint/eslintrc@2.1.4': dependencies: - '@eslint/object-schema': 2.1.6 + ajv: 6.12.6 debug: 4.4.0 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 minimatch: 3.1.2 + strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.2.2': {} - - '@eslint/core@0.13.0': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -3065,14 +2898,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.26.0': {} - - '@eslint/object-schema@2.1.6': {} - - '@eslint/plugin-kit@0.2.8': - dependencies: - '@eslint/core': 0.13.0 - levn: 0.4.1 + '@eslint/js@8.57.0': {} '@floating-ui/core@1.7.0': dependencies: @@ -3117,18 +2943,17 @@ snapshots: react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.5.0(react@18.3.1) - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.6': + '@humanwhocodes/config-array@0.11.14': dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/retry@0.3.1': {} - - '@humanwhocodes/retry@0.4.2': {} + '@humanwhocodes/object-schema@2.0.3': {} '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: @@ -3205,21 +3030,6 @@ snapshots: '@img/sharp-win32-x64@0.33.5': optional: true - '@modelcontextprotocol/sdk@1.11.0': - dependencies: - content-type: 1.0.5 - cors: 2.8.5 - cross-spawn: 7.0.6 - eventsource: 3.0.6 - express: 5.1.0 - express-rate-limit: 7.5.0(express@5.1.0) - pkce-challenge: 5.0.0 - raw-body: 3.0.0 - zod: 3.24.3 - zod-to-json-schema: 3.24.5(zod@3.24.3) - transitivePeerDependencies: - - supports-color - '@napi-rs/wasm-runtime@0.2.9': dependencies: '@emnapi/core': 1.4.3 @@ -3919,10 +3729,6 @@ snapshots: tslib: 2.8.1 optional: true - '@types/estree@1.0.7': {} - - '@types/json-schema@7.0.15': {} - '@types/json5@0.0.29': {} '@types/linkify-it@5.0.0': {} @@ -3948,15 +3754,15 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@typescript-eslint/eslint-plugin@8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.31.1(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0)(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.31.1(eslint@8.57.0)(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.31.1 - '@typescript-eslint/type-utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.31.1(eslint@8.57.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.31.1(eslint@8.57.0)(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.31.1 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -3965,14 +3771,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.31.1 '@typescript-eslint/types': 8.31.1 '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.31.1 debug: 4.4.0 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -3982,12 +3788,12 @@ snapshots: '@typescript-eslint/types': 8.31.1 '@typescript-eslint/visitor-keys': 8.31.1 - '@typescript-eslint/type-utils@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.31.1(eslint@8.57.0)(typescript@5.8.3)': dependencies: '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/utils': 8.31.1(eslint@8.57.0)(typescript@5.8.3) debug: 4.4.0 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -4009,13 +3815,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3)': + '@typescript-eslint/utils@8.31.1(eslint@8.57.0)(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) '@typescript-eslint/scope-manager': 8.31.1 '@typescript-eslint/types': 8.31.1 '@typescript-eslint/typescript-estree': 8.31.1(typescript@5.8.3) - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -4025,6 +3831,8 @@ snapshots: '@typescript-eslint/types': 8.31.1 eslint-visitor-keys: 4.2.0 + '@ungap/structured-clone@1.3.0': {} + '@unrs/resolver-binding-darwin-arm64@1.7.2': optional: true @@ -4090,11 +3898,6 @@ snapshots: typescript: 5.8.3 zod: 3.24.3 - accepts@2.0.0: - dependencies: - mime-types: 3.0.1 - negotiator: 1.0.0 - acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -4203,20 +4006,6 @@ snapshots: balanced-match@1.0.2: {} - body-parser@2.2.0: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.0 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 3.0.0 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -4234,8 +4023,6 @@ snapshots: dependencies: streamsearch: 1.1.0 - bytes@3.1.2: {} - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -4299,21 +4086,6 @@ snapshots: concat-map@0.0.1: {} - content-disposition@1.0.0: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - crelt@1.0.6: {} cross-spawn@7.0.6: @@ -4368,8 +4140,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - depd@2.0.0: {} - detect-libc@2.0.4: {} detect-node-es@1.1.0: {} @@ -4378,20 +4148,20 @@ snapshots: dependencies: esutils: 2.0.3 + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 - ee-first@1.1.1: {} - emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} - encodeurl@2.0.0: {} - enhanced-resolve@5.18.1: dependencies: graceful-fs: 4.2.11 @@ -4499,23 +4269,21 @@ snapshots: escalade@3.2.0: {} - escape-html@1.0.3: {} - escape-string-regexp@4.0.0: {} - eslint-config-next@15.3.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3): + eslint-config-next@15.3.1(eslint@8.57.0)(typescript@5.8.3): dependencies: '@next/eslint-plugin-next': 15.3.1 '@rushstack/eslint-patch': 1.11.0 - '@typescript-eslint/eslint-plugin': 8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - '@typescript-eslint/parser': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - eslint: 9.26.0(jiti@2.4.2) + '@typescript-eslint/eslint-plugin': 8.31.1(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.31.1(eslint@8.57.0)(typescript@5.8.3) + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0(jiti@2.4.2)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.4.2)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.26.0(jiti@2.4.2)) - eslint-plugin-react: 7.37.5(eslint@9.26.0(jiti@2.4.2)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.26.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) + eslint-plugin-react: 7.37.5(eslint@8.57.0) + eslint-plugin-react-hooks: 5.2.0(eslint@8.57.0) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -4531,33 +4299,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0(jiti@2.4.2)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 get-tsconfig: 4.10.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.13 unrs-resolver: 1.7.2 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.4.2)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) - eslint: 9.26.0(jiti@2.4.2) + '@typescript-eslint/parser': 8.31.1(eslint@8.57.0)(typescript@5.8.3) + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@9.26.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.4.2)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -4566,9 +4334,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.31.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4580,13 +4348,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.31.1(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) + '@typescript-eslint/parser': 8.31.1(eslint@8.57.0)(typescript@5.8.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.26.0(jiti@2.4.2)): + eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -4596,7 +4364,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -4605,11 +4373,11 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.26.0(jiti@2.4.2)): + eslint-plugin-react-hooks@5.2.0(eslint@8.57.0): dependencies: - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 - eslint-plugin-react@7.37.5(eslint@9.26.0(jiti@2.4.2)): + eslint-plugin-react@7.37.5(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -4617,7 +4385,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.26.0(jiti@2.4.2) + eslint: 8.57.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -4631,7 +4399,7 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-scope@8.3.0: + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 @@ -4640,47 +4408,46 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.26.0(jiti@2.4.2): + eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0(jiti@2.4.2)) + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.20.0 - '@eslint/config-helpers': 0.2.2 - '@eslint/core': 0.13.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.26.0 - '@eslint/plugin-kit': 0.2.8 - '@humanfs/node': 0.16.6 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.2 - '@modelcontextprotocol/sdk': 1.11.0 - '@types/estree': 1.0.7 - '@types/json-schema': 7.0.15 + '@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 + doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 8.3.0 - eslint-visitor-keys: 4.2.0 - espree: 10.3.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: 8.0.0 + 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 - zod: 3.24.3 - optionalDependencies: - jiti: 2.4.2 + strip-ansi: 6.0.1 + text-table: 0.2.0 transitivePeerDependencies: - supports-color @@ -4690,6 +4457,12 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 4.2.0 + espree@9.6.1: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 3.4.3 + esprima@4.0.1: {} esquery@1.6.0: @@ -4704,52 +4477,8 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} - eventemitter3@5.0.1: {} - eventsource-parser@3.0.1: {} - - eventsource@3.0.6: - dependencies: - eventsource-parser: 3.0.1 - - express-rate-limit@7.5.0(express@5.1.0): - dependencies: - express: 5.1.0 - - express@5.1.0: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.0 - content-disposition: 1.0.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.0 - fresh: 2.0.0 - http-errors: 2.0.0 - merge-descriptors: 2.0.0 - mime-types: 3.0.1 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 - statuses: 2.0.1 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - fast-deep-equal@3.1.3: {} fast-glob@3.3.1: @@ -4785,34 +4514,24 @@ snapshots: set-cookie-parser: 2.7.1 tough-cookie: 4.1.4 - file-entry-cache@8.0.0: + file-entry-cache@6.0.1: dependencies: - flat-cache: 4.0.1 + flat-cache: 3.2.0 fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.0: - dependencies: - debug: 4.4.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@4.0.1: + flat-cache@3.2.0: dependencies: flatted: 3.3.3 keyv: 4.5.4 + rimraf: 3.0.2 flatted@3.3.3: {} @@ -4820,8 +4539,6 @@ snapshots: dependencies: is-callable: 1.2.7 - forwarded@0.2.0: {} - framer-motion@12.9.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: motion-dom: 12.9.4 @@ -4831,14 +4548,14 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - fresh@2.0.0: {} - fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 + fs.realpath@1.0.0: {} + function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -4896,6 +4613,19 @@ snapshots: dependencies: is-glob: 4.0.3 + 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 + globals@14.0.0: {} globalthis@1.0.4: @@ -4935,18 +4665,6 @@ snapshots: dependencies: function-bind: 1.1.2 - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - ignore@5.3.2: {} import-fresh@3.3.1: @@ -4956,6 +4674,11 @@ snapshots: imurmurhash@0.1.4: {} + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + inherits@2.0.4: {} internal-slot@1.1.0: @@ -4964,8 +4687,6 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 - ipaddr.js@1.9.1: {} - is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -5040,7 +4761,7 @@ snapshots: is-number@7.0.0: {} - is-promise@4.0.0: {} + is-path-inside@3.0.3: {} is-regex@1.2.1: dependencies: @@ -5231,10 +4952,6 @@ snapshots: mdurl@2.0.0: {} - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - merge2@1.4.1: {} micromatch@4.0.8: @@ -5242,12 +4959,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.54.0: {} - - mime-types@3.0.1: - dependencies: - mime-db: 1.54.0 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -5272,8 +4983,6 @@ snapshots: natural-compare@1.4.0: {} - negotiator@1.0.0: {} - next@14.2.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 14.2.28 @@ -5345,10 +5054,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -5398,24 +5103,20 @@ snapshots: dependencies: callsites: 3.1.0 - parseurl@1.3.3: {} - path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-parse@1.0.7: {} - path-to-regexp@8.2.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.2: {} - pkce-challenge@5.0.0: {} - possible-typed-array-names@1.1.0: {} postcss@8.4.31: @@ -5432,6 +5133,8 @@ snapshots: prelude-ls@1.2.1: {} + prettier@3.5.3: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -5541,11 +5244,6 @@ snapshots: prosemirror-state: 1.4.3 prosemirror-transform: 1.10.4 - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - psl@1.15.0: dependencies: punycode: 2.3.1 @@ -5554,23 +5252,10 @@ snapshots: punycode@2.3.1: {} - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - querystringify@2.2.0: {} queue-microtask@1.2.3: {} - range-parser@1.2.1: {} - - raw-body@3.0.0: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - unpipe: 1.0.0 - react-datepicker@8.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@floating-ui/react': 0.27.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -5675,17 +5360,11 @@ snapshots: reusify@1.1.0: {} - rope-sequence@1.3.4: {} - - router@2.2.0: + rimraf@3.0.2: dependencies: - debug: 4.4.0 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.2.0 - transitivePeerDependencies: - - supports-color + glob: 7.2.3 + + rope-sequence@1.3.4: {} run-parallel@1.2.0: dependencies: @@ -5699,8 +5378,6 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 - safe-buffer@5.2.1: {} - safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -5712,8 +5389,6 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - safer-buffer@2.1.2: {} - scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -5722,31 +5397,6 @@ snapshots: semver@7.7.1: {} - send@1.2.0: - dependencies: - debug: 4.4.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.0: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.0 - transitivePeerDependencies: - - supports-color - set-cookie-parser@2.7.1: {} set-function-length@1.2.2: @@ -5771,8 +5421,6 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 - setprototypeof@1.2.0: {} - sharp@0.33.5: dependencies: color: 4.2.3 @@ -5857,8 +5505,6 @@ snapshots: transitivePeerDependencies: - encoding - statuses@2.0.1: {} - streamsearch@1.1.0: {} string-width@4.2.3: @@ -5948,6 +5594,8 @@ snapshots: tapable@2.2.1: {} + text-table@0.2.0: {} + tinyglobby@0.2.13: dependencies: fdir: 6.4.4(picomatch@4.0.2) @@ -5961,8 +5609,6 @@ snapshots: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - tough-cookie@4.1.4: dependencies: psl: 1.15.0 @@ -5993,11 +5639,7 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.1 + type-fest@0.20.2: {} typed-array-buffer@1.0.3: dependencies: @@ -6049,8 +5691,6 @@ snapshots: universalify@2.0.1: {} - unpipe@1.0.0: {} - unrs-resolver@1.7.2: dependencies: napi-postinstall: 0.2.3 @@ -6101,8 +5741,6 @@ snapshots: dependencies: react: 18.3.1 - vary@1.1.2: {} - viem@2.28.3(typescript@5.8.3)(zod@3.24.3): dependencies: '@noble/curves': 1.8.2 @@ -6204,8 +5842,4 @@ snapshots: yocto-queue@0.1.0: {} - zod-to-json-schema@3.24.5(zod@3.24.3): - dependencies: - zod: 3.24.3 - zod@3.24.3: {} diff --git a/frontend/src/app/betting/page.tsx b/frontend/src/app/betting/page.tsx index fb6f047..854d4cb 100644 --- a/frontend/src/app/betting/page.tsx +++ b/frontend/src/app/betting/page.tsx @@ -1,11 +1,11 @@ -import BettingInterface from "../../components/betting-interface"; - -export default function Home() { - return ( -
-
- -
-
- ); -} +import BettingInterface from "../../components/betting-interface"; + +export default function Home() { + return ( +
+
+ +
+
+ ); +} diff --git a/frontend/src/components/betting-interface.tsx b/frontend/src/components/betting-interface.tsx index d302628..34f470d 100644 --- a/frontend/src/components/betting-interface.tsx +++ b/frontend/src/components/betting-interface.tsx @@ -1,259 +1,259 @@ -"use client"; - -import { useState, useEffect } from "react"; -import { useAccount } from "@starknet-react/core"; -import { WalletConnectButton } from "@/components/wallet-connect-button"; -import { Loader2, CheckCircle, XCircle } from "lucide-react"; -import type { Agent } from "@/types/betting"; -import { useBetting } from "@/hooks/use-betting"; -import { getAgents } from "@/lib/starknet"; -import Image from "next/image"; - -export default function BettingInterface() { - const { address, isConnected } = useAccount(); - const [agents, setAgents] = useState([]); - const [selectedAgent, setSelectedAgent] = useState(null); - const [betAmount, setBetAmount] = useState("0.01"); - const { placeBet, transactions, isLoading } = useBetting(); - - useEffect(() => { - const loadAgents = async () => { - try { - const agentData = await getAgents(); - setAgents(agentData); - } catch (error) { - console.error("Failed to load agents:", error); - } - }; - - if (isConnected) { - loadAgents(); - } - }, [isConnected]); - - const handleBetSubmit = async () => { - if (!selectedAgent) { - alert("Please select an agent to place your bet."); - return; - } - - if (!betAmount || Number.parseFloat(betAmount) <= 0) { - alert("Please enter a valid bet amount."); - return; - } - - try { - await placeBet(selectedAgent.id, betAmount); - setBetAmount("0.01"); - } catch (error) { - console.error("Failed to place bet:", error); - } - }; - - return ( -
-
-

- BOTBATTLES ARENA -

- -
- - {!isConnected ? ( -
-

- Connect Your Wallet -

-

- Connect your StarkNet wallet to start placing bets on AI agents. -

- -
- ) : ( -
-
-
-

- Place Your Bets -

-
- {agents.map((agent) => ( -
setSelectedAgent(agent)} - > -
-
- {agent.name} -
-

- {agent.name} -

-
-
66 - ? "bg-green-400" - : agent.performance > 33 - ? "bg-yellow-400" - : "bg-red-400" - } rounded-full`} - style={{ width: `${agent.performance}%` }} - /> -
-
-
- ))} -
- - {selectedAgent && ( -
-

- Betting on: {selectedAgent.name} -

- -
- -
- setBetAmount(e.target.value)} - min="0.001" - step="0.001" - className={` - bg-gray-700 border-2 border-gray-500 - font-pixel text-white px-3 py-2 rounded - focus:border-green-400 focus:ring-1 focus:ring-green-400 - focus:outline-none - hover:border-gray-400 - shadow-[0_2px_4px_rgba(0,0,0,0.25)] - transition-all - w-full - `} - /> - -
-
-
- )} -
-
- -
-
-

- Transaction History -

-
- {transactions.length > 0 ? ( - transactions.map((tx) => ( -
-
- {tx.status === "confirmed" ? ( - - ) : tx.status === "failed" ? ( - - ) : ( - - )} - -
-

- {tx.message} -

-
-

- {tx.status === "pending" - ? "Processing..." - : tx.status === "confirmed" - ? "Confirmed" - : "Failed"} -

-

- {new Date(tx.timestamp).toLocaleTimeString()} -

-
- {tx.status === "confirmed" && ( -

- Tx: {tx.hash.substring(0, 10)}... - {tx.hash.substring(tx.hash.length - 6)} -

- )} -
-
-
- )) - ) : ( -

- No transactions yet. Place a bet to get started! -

- )} -
-
- -
-

- Wallet Info -

-
-

- Address:{" "} - {address} -

-

- Network: StarkNet -

-
-
-
-
- )} -
- ); -} +"use client"; + +import { useState, useEffect } from "react"; +import { useAccount } from "@starknet-react/core"; +import { WalletConnectButton } from "@/components/wallet-connect-button"; +import { Loader2, CheckCircle, XCircle } from "lucide-react"; +import type { Agent } from "@/types/betting"; +import { useBetting } from "@/hooks/use-betting"; +import { getAgents } from "@/lib/starknet"; +import Image from "next/image"; + +export default function BettingInterface() { + const { address, isConnected } = useAccount(); + const [agents, setAgents] = useState([]); + const [selectedAgent, setSelectedAgent] = useState(null); + const [betAmount, setBetAmount] = useState("0.01"); + const { placeBet, transactions, isLoading } = useBetting(); + + useEffect(() => { + const loadAgents = async () => { + try { + const agentData = await getAgents(); + setAgents(agentData); + } catch (error) { + console.error("Failed to load agents:", error); + } + }; + + if (isConnected) { + loadAgents(); + } + }, [isConnected]); + + const handleBetSubmit = async () => { + if (!selectedAgent) { + alert("Please select an agent to place your bet."); + return; + } + + if (!betAmount || Number.parseFloat(betAmount) <= 0) { + alert("Please enter a valid bet amount."); + return; + } + + try { + await placeBet(selectedAgent.id, betAmount); + setBetAmount("0.01"); + } catch (error) { + console.error("Failed to place bet:", error); + } + }; + + return ( +
+
+

+ BOTBATTLES ARENA +

+ +
+ + {!isConnected ? ( +
+

+ Connect Your Wallet +

+

+ Connect your StarkNet wallet to start placing bets on AI agents. +

+ +
+ ) : ( +
+
+
+

+ Place Your Bets +

+
+ {agents.map((agent) => ( +
setSelectedAgent(agent)} + > +
+
+ {agent.name} +
+

+ {agent.name} +

+
+
66 + ? "bg-green-400" + : agent.performance > 33 + ? "bg-yellow-400" + : "bg-red-400" + } rounded-full`} + style={{ width: `${agent.performance}%` }} + /> +
+
+
+ ))} +
+ + {selectedAgent && ( +
+

+ Betting on: {selectedAgent.name} +

+ +
+ +
+ setBetAmount(e.target.value)} + min="0.001" + step="0.001" + className={` + bg-gray-700 border-2 border-gray-500 + font-pixel text-white px-3 py-2 rounded + focus:border-green-400 focus:ring-1 focus:ring-green-400 + focus:outline-none + hover:border-gray-400 + shadow-[0_2px_4px_rgba(0,0,0,0.25)] + transition-all + w-full + `} + /> + +
+
+
+ )} +
+
+ +
+
+

+ Transaction History +

+
+ {transactions.length > 0 ? ( + transactions.map((tx) => ( +
+
+ {tx.status === "confirmed" ? ( + + ) : tx.status === "failed" ? ( + + ) : ( + + )} + +
+

+ {tx.message} +

+
+

+ {tx.status === "pending" + ? "Processing..." + : tx.status === "confirmed" + ? "Confirmed" + : "Failed"} +

+

+ {new Date(tx.timestamp).toLocaleTimeString()} +

+
+ {tx.status === "confirmed" && ( +

+ Tx: {tx.hash.substring(0, 10)}... + {tx.hash.substring(tx.hash.length - 6)} +

+ )} +
+
+
+ )) + ) : ( +

+ No transactions yet. Place a bet to get started! +

+ )} +
+
+ +
+

+ Wallet Info +

+
+

+ Address:{" "} + {address} +

+

+ Network: StarkNet +

+
+
+
+
+ )} +
+ ); +} diff --git a/frontend/src/components/starknet-provider.tsx b/frontend/src/components/starknet-provider.tsx index 108b46c..4c42ffa 100644 --- a/frontend/src/components/starknet-provider.tsx +++ b/frontend/src/components/starknet-provider.tsx @@ -1,7 +1,7 @@ "use client"; import React from "react"; -import { sepolia} from "@starknet-react/chains"; +import { sepolia } from "@starknet-react/chains"; import { StarknetConfig, argent, diff --git a/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx index a2df8dc..2adaf00 100644 --- a/frontend/src/components/ui/button.tsx +++ b/frontend/src/components/ui/button.tsx @@ -1,8 +1,8 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", @@ -32,8 +32,8 @@ const buttonVariants = cva( variant: "default", size: "default", }, - } -) + }, +); function Button({ className, @@ -43,9 +43,9 @@ function Button({ ...props }: React.ComponentProps<"button"> & VariantProps & { - asChild?: boolean + asChild?: boolean; }) { - const Comp = asChild ? Slot : "button" + const Comp = asChild ? Slot : "button"; return ( - ) + ); } -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx index 7d7a9d3..7d7783f 100644 --- a/frontend/src/components/ui/dialog.tsx +++ b/frontend/src/components/ui/dialog.tsx @@ -1,33 +1,33 @@ -"use client" +"use client"; -import * as React from "react" -import * as DialogPrimitive from "@radix-ui/react-dialog" -import { XIcon } from "lucide-react" +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { XIcon } from "lucide-react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Dialog({ ...props }: React.ComponentProps) { - return + return ; } function DialogTrigger({ ...props }: React.ComponentProps) { - return + return ; } function DialogPortal({ ...props }: React.ComponentProps) { - return + return ; } function DialogClose({ ...props }: React.ComponentProps) { - return + return ; } function DialogOverlay({ @@ -39,11 +39,11 @@ function DialogOverlay({ data-slot="dialog-overlay" className={cn( "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", - className + className, )} {...props} /> - ) + ); } function DialogContent({ @@ -58,7 +58,7 @@ function DialogContent({ data-slot="dialog-content" className={cn( "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg", - className + className, )} {...props} > @@ -69,7 +69,7 @@ function DialogContent({ - ) + ); } function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -79,7 +79,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { className={cn("flex flex-col gap-2 text-center sm:text-left", className)} {...props} /> - ) + ); } function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -88,11 +88,11 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { data-slot="dialog-footer" className={cn( "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", - className + className, )} {...props} /> - ) + ); } function DialogTitle({ @@ -105,7 +105,7 @@ function DialogTitle({ className={cn("text-lg leading-none font-semibold", className)} {...props} /> - ) + ); } function DialogDescription({ @@ -118,7 +118,7 @@ function DialogDescription({ className={cn("text-muted-foreground text-sm", className)} {...props} /> - ) + ); } export { @@ -132,4 +132,4 @@ export { DialogPortal, DialogTitle, DialogTrigger, -} +}; diff --git a/frontend/src/components/ui/dropdown-menu.tsx b/frontend/src/components/ui/dropdown-menu.tsx index ec51e9c..1fc1f4e 100644 --- a/frontend/src/components/ui/dropdown-menu.tsx +++ b/frontend/src/components/ui/dropdown-menu.tsx @@ -1,15 +1,15 @@ -"use client" +"use client"; -import * as React from "react" -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" +import * as React from "react"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function DropdownMenu({ ...props }: React.ComponentProps) { - return + return ; } function DropdownMenuPortal({ @@ -17,7 +17,7 @@ function DropdownMenuPortal({ }: React.ComponentProps) { return ( - ) + ); } function DropdownMenuTrigger({ @@ -28,7 +28,7 @@ function DropdownMenuTrigger({ data-slot="dropdown-menu-trigger" {...props} /> - ) + ); } function DropdownMenuContent({ @@ -43,12 +43,12 @@ function DropdownMenuContent({ sideOffset={sideOffset} className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md", - className + className, )} {...props} /> - ) + ); } function DropdownMenuGroup({ @@ -56,7 +56,7 @@ function DropdownMenuGroup({ }: React.ComponentProps) { return ( - ) + ); } function DropdownMenuItem({ @@ -65,8 +65,8 @@ function DropdownMenuItem({ variant = "default", ...props }: React.ComponentProps & { - inset?: boolean - variant?: "default" | "destructive" + inset?: boolean; + variant?: "default" | "destructive"; }) { return ( - ) + ); } function DropdownMenuCheckboxItem({ @@ -93,7 +93,7 @@ function DropdownMenuCheckboxItem({ data-slot="dropdown-menu-checkbox-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", - className + className, )} checked={checked} {...props} @@ -105,7 +105,7 @@ function DropdownMenuCheckboxItem({ {children} - ) + ); } function DropdownMenuRadioGroup({ @@ -116,7 +116,7 @@ function DropdownMenuRadioGroup({ data-slot="dropdown-menu-radio-group" {...props} /> - ) + ); } function DropdownMenuRadioItem({ @@ -129,7 +129,7 @@ function DropdownMenuRadioItem({ data-slot="dropdown-menu-radio-item" className={cn( "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", - className + className, )} {...props} > @@ -140,7 +140,7 @@ function DropdownMenuRadioItem({ {children} - ) + ); } function DropdownMenuLabel({ @@ -148,7 +148,7 @@ function DropdownMenuLabel({ inset, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( - ) + ); } function DropdownMenuSeparator({ @@ -173,7 +173,7 @@ function DropdownMenuSeparator({ className={cn("bg-border -mx-1 my-1 h-px", className)} {...props} /> - ) + ); } function DropdownMenuShortcut({ @@ -185,17 +185,17 @@ function DropdownMenuShortcut({ data-slot="dropdown-menu-shortcut" className={cn( "text-muted-foreground ml-auto text-xs tracking-widest", - className + className, )} {...props} /> - ) + ); } function DropdownMenuSub({ ...props }: React.ComponentProps) { - return + return ; } function DropdownMenuSubTrigger({ @@ -204,7 +204,7 @@ function DropdownMenuSubTrigger({ children, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( {children} - ) + ); } function DropdownMenuSubContent({ @@ -231,11 +231,11 @@ function DropdownMenuSubContent({ data-slot="dropdown-menu-sub-content" className={cn( "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", - className + className, )} {...props} /> - ) + ); } export { @@ -254,4 +254,4 @@ export { DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, -} +}; diff --git a/frontend/src/components/wallet-connect-button.tsx b/frontend/src/components/wallet-connect-button.tsx index 4d8a3e8..55450ea 100644 --- a/frontend/src/components/wallet-connect-button.tsx +++ b/frontend/src/components/wallet-connect-button.tsx @@ -1,151 +1,151 @@ -"use client"; - -import { useState, useEffect, useRef } from "react"; -import { - useAccount, - useConnect, - useDisconnect, - type Connector, -} from "@starknet-react/core"; -import { Wallet } from "lucide-react"; -// import { Button } from "@/components/ui/button"; -import { WalletDropdown } from "./wallet-dropdown"; -import { truncateAddress } from "@/utils/wallet"; -import WalletConnectModal from "./wallet-connect-modal"; - -export function WalletConnectButton() { - const [isModalOpen, setIsModalOpen] = useState(false); - const [isDropdownOpen, setIsDropdownOpen] = useState(false); - const [isConnecting, setIsConnecting] = useState(false); - const [connectionError, setConnectionError] = useState(null); - const dropdownTimeoutRef = useRef(null); - - const { address, isConnected } = useAccount(); - const { connect, connectors } = useConnect(); - const { disconnect } = useDisconnect(); - - const handleConnect = () => { - if (isConnected) { - setIsDropdownOpen(!isDropdownOpen); - } else { - setIsModalOpen(true); - setConnectionError(null); - } - }; - - const handleDisconnect = () => { - disconnect(); - setIsDropdownOpen(false); - localStorage.removeItem("lastUsedConnector"); - }; - - const handleConnectorSelect = async (connector: Connector) => { - if (!connector) return; - - setIsConnecting(true); - setConnectionError(null); - - try { - await connect({ connector }); - - if (connector.id) { - localStorage.setItem("lastUsedConnector", connector.id); - } - - // Only close modal after successful connection - setIsModalOpen(false); - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : "Failed to connect wallet"; - console.error("Wallet connection error:", errorMessage); - setConnectionError(errorMessage); - } finally { - setIsConnecting(false); - } - }; - - // Handle dropdown hover behavior - const handleMouseEnter = () => { - if (isConnected) { - if (dropdownTimeoutRef.current) { - clearTimeout(dropdownTimeoutRef.current); - dropdownTimeoutRef.current = null; - } - setIsDropdownOpen(true); - } - }; - - const handleMouseLeave = () => { - if (dropdownTimeoutRef.current) { - clearTimeout(dropdownTimeoutRef.current); - } - - dropdownTimeoutRef.current = setTimeout(() => { - setIsDropdownOpen(false); - }, 300); - }; - - // Listen for wallet_disconnected events - useEffect(() => { - const handleWalletDisconnected = () => { - setIsDropdownOpen(false); - }; - - window.addEventListener("wallet_disconnected", handleWalletDisconnected); - - return () => { - window.removeEventListener( - "wallet_disconnected", - handleWalletDisconnected - ); - - if (dropdownTimeoutRef.current) { - clearTimeout(dropdownTimeoutRef.current); - } - }; - }, []); - - return ( -
- {/* Connect Button */} - - - {/* Wallet Connect Modal */} - { - if (!isConnecting) { - setIsModalOpen(false); - setConnectionError(null); - } - }} - onSelect={async (walletId) => { - const connector = connectors.find((c) => c.id === walletId); - if (connector) { - await handleConnectorSelect(connector); - } - }} - /> - - {/* Wallet Dropdown */} - {isConnected && address && ( - setIsDropdownOpen(false)} - address={address} - onDisconnect={handleDisconnect} - /> - )} -
- ); -} +"use client"; + +import { useState, useEffect, useRef } from "react"; +import { + useAccount, + useConnect, + useDisconnect, + type Connector, +} from "@starknet-react/core"; +import { Wallet } from "lucide-react"; +// import { Button } from "@/components/ui/button"; +import { WalletDropdown } from "./wallet-dropdown"; +import { truncateAddress } from "@/utils/wallet"; +import WalletConnectModal from "./wallet-connect-modal"; + +export function WalletConnectButton() { + const [isModalOpen, setIsModalOpen] = useState(false); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const [isConnecting, setIsConnecting] = useState(false); + const [connectionError, setConnectionError] = useState(null); + const dropdownTimeoutRef = useRef(null); + + const { address, isConnected } = useAccount(); + const { connect, connectors } = useConnect(); + const { disconnect } = useDisconnect(); + + const handleConnect = () => { + if (isConnected) { + setIsDropdownOpen(!isDropdownOpen); + } else { + setIsModalOpen(true); + setConnectionError(null); + } + }; + + const handleDisconnect = () => { + disconnect(); + setIsDropdownOpen(false); + localStorage.removeItem("lastUsedConnector"); + }; + + const handleConnectorSelect = async (connector: Connector) => { + if (!connector) return; + + setIsConnecting(true); + setConnectionError(null); + + try { + await connect({ connector }); + + if (connector.id) { + localStorage.setItem("lastUsedConnector", connector.id); + } + + // Only close modal after successful connection + setIsModalOpen(false); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : "Failed to connect wallet"; + console.error("Wallet connection error:", errorMessage); + setConnectionError(errorMessage); + } finally { + setIsConnecting(false); + } + }; + + // Handle dropdown hover behavior + const handleMouseEnter = () => { + if (isConnected) { + if (dropdownTimeoutRef.current) { + clearTimeout(dropdownTimeoutRef.current); + dropdownTimeoutRef.current = null; + } + setIsDropdownOpen(true); + } + }; + + const handleMouseLeave = () => { + if (dropdownTimeoutRef.current) { + clearTimeout(dropdownTimeoutRef.current); + } + + dropdownTimeoutRef.current = setTimeout(() => { + setIsDropdownOpen(false); + }, 300); + }; + + // Listen for wallet_disconnected events + useEffect(() => { + const handleWalletDisconnected = () => { + setIsDropdownOpen(false); + }; + + window.addEventListener("wallet_disconnected", handleWalletDisconnected); + + return () => { + window.removeEventListener( + "wallet_disconnected", + handleWalletDisconnected, + ); + + if (dropdownTimeoutRef.current) { + clearTimeout(dropdownTimeoutRef.current); + } + }; + }, []); + + return ( +
+ {/* Connect Button */} + + + {/* Wallet Connect Modal */} + { + if (!isConnecting) { + setIsModalOpen(false); + setConnectionError(null); + } + }} + onSelect={async (walletId) => { + const connector = connectors.find((c) => c.id === walletId); + if (connector) { + await handleConnectorSelect(connector); + } + }} + /> + + {/* Wallet Dropdown */} + {isConnected && address && ( + setIsDropdownOpen(false)} + address={address} + onDisconnect={handleDisconnect} + /> + )} +
+ ); +} diff --git a/frontend/src/components/wallet-connect-modal.tsx b/frontend/src/components/wallet-connect-modal.tsx index e215fc3..878824e 100644 --- a/frontend/src/components/wallet-connect-modal.tsx +++ b/frontend/src/components/wallet-connect-modal.tsx @@ -24,16 +24,15 @@ export default function WalletConnectModal({ onSelect, // Added this prop }: WalletConnectModalProps) { const [selectedWallet, setSelectedWallet] = useState(null); - const { connectors } = useWalletContext(); + const { connectors } = useWalletContext(); const handleSelect = (walletId: string) => { setSelectedWallet(walletId); }; - // helper to get icon source function getIconSource( - icon: string | { dark: string; light: string } + icon: string | { dark: string; light: string }, ): string { if (typeof icon === "string") { return icon; diff --git a/frontend/src/components/wallet-dropdown.tsx b/frontend/src/components/wallet-dropdown.tsx index 84bff46..2d333cd 100644 --- a/frontend/src/components/wallet-dropdown.tsx +++ b/frontend/src/components/wallet-dropdown.tsx @@ -1,101 +1,101 @@ -"use client"; - -import { useRef, useEffect } from "react"; -import { LogOut, ExternalLink, Copy, CheckCircle2 } from "lucide-react"; -import { useState } from "react"; -import Link from "next/link"; -import { truncateAddress } from "@/utils/wallet"; - -interface WalletDropdownProps { - isOpen: boolean; - onClose: () => void; - address: string; - onDisconnect: () => void; -} - -export function WalletDropdown({ - isOpen, - onClose, - address, - onDisconnect, -}: WalletDropdownProps) { - const dropdownRef = useRef(null); - const [copied, setCopied] = useState(false); - - // Close dropdown when clicking outside - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - onClose(); - } - }; - - if (isOpen) { - document.addEventListener("mousedown", handleClickOutside); - } - - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [isOpen, onClose]); - - const copyToClipboard = () => { - navigator.clipboard.writeText(address); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }; - - if (!isOpen) return null; - - const explorerUrl = `https://voyager.online/contract/${address}`; - - return ( -
-
-
- Connected Wallet -
-
- - {truncateAddress(address)} - - -
-
-
- - - View on Explorer - - -
-
- ); -} +"use client"; + +import { useRef, useEffect } from "react"; +import { LogOut, ExternalLink, Copy, CheckCircle2 } from "lucide-react"; +import { useState } from "react"; +import Link from "next/link"; +import { truncateAddress } from "@/utils/wallet"; + +interface WalletDropdownProps { + isOpen: boolean; + onClose: () => void; + address: string; + onDisconnect: () => void; +} + +export function WalletDropdown({ + isOpen, + onClose, + address, + onDisconnect, +}: WalletDropdownProps) { + const dropdownRef = useRef(null); + const [copied, setCopied] = useState(false); + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + onClose(); + } + }; + + if (isOpen) { + document.addEventListener("mousedown", handleClickOutside); + } + + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [isOpen, onClose]); + + const copyToClipboard = () => { + navigator.clipboard.writeText(address); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + if (!isOpen) return null; + + const explorerUrl = `https://voyager.online/contract/${address}`; + + return ( +
+
+
+ Connected Wallet +
+
+ + {truncateAddress(address)} + + +
+
+
+ + + View on Explorer + + +
+
+ ); +} diff --git a/frontend/src/components/wallet-provider.tsx b/frontend/src/components/wallet-provider.tsx index f6df863..4a68095 100644 --- a/frontend/src/components/wallet-provider.tsx +++ b/frontend/src/components/wallet-provider.tsx @@ -12,7 +12,7 @@ import { useAccount, useDisconnect, Connector, - ConnectVariables + ConnectVariables, } from "@starknet-react/core"; interface WalletContextProps { @@ -44,7 +44,7 @@ export const WalletProvider: React.FC<{ children: ReactNode }> = ({ (connector: Connector) => { connect({ connector }); }, - [connect] + [connect], ); // Save wallet address to localStorage when connected @@ -71,7 +71,6 @@ export const WalletProvider: React.FC<{ children: ReactNode }> = ({ ); }; - export const useWalletContext = () => { const ctx = useContext(WalletContext); if (!ctx) { diff --git a/frontend/src/hooks/use-betting.tsx b/frontend/src/hooks/use-betting.tsx index a81537e..25c90c5 100644 --- a/frontend/src/hooks/use-betting.tsx +++ b/frontend/src/hooks/use-betting.tsx @@ -1,82 +1,82 @@ -"use client"; - -import { useState, useCallback } from "react"; -import { useAccount } from "@starknet-react/core"; -import { Transaction } from "../types/betting"; -import { placeBet as placeBetOnChain } from "../lib/starknet"; - -export function useBetting() { - const { address } = useAccount(); - const [transactions, setTransactions] = useState([]); - const [isLoading, setIsLoading] = useState(false); - - const placeBet = useCallback( - async (agentId: number, amount: string) => { - if (!address) { - throw new Error("Wallet not connected"); - } - - setIsLoading(true); - - try { - // Create a pending transaction record - const pendingTx: Transaction = { - hash: "pending-" + Date.now(), - status: "pending", - message: `Placing bet of ${amount} STRK on agent #${agentId}...`, - timestamp: Date.now(), - }; - - setTransactions((prev) => [pendingTx, ...prev]); - - // Call the StarkNet contract - const result = await placeBetOnChain(agentId, amount); - - // Update the transaction status - setTransactions((prev) => - prev.map((tx) => - tx.hash === pendingTx.hash - ? { - hash: result.transactionHash, - status: "confirmed", - message: `Successfully placed bet of ${amount} STRK on agent #${agentId}`, - timestamp: Date.now(), - } - : tx - ) - ); - - return result; - } catch (error) { - console.error("Transaction failed:", error); - - // Update the transaction status to failed - setTransactions((prev) => - prev.map((tx) => - tx.hash === "pending-" + Date.now().toString().slice(0, -3) - ? { - hash: "failed-" + Date.now(), - status: "failed", - message: `Failed to place bet: ${ - error instanceof Error ? error.message : "Unknown error" - }`, - timestamp: Date.now(), - } - : tx - ) - ); - - throw error; - } finally { - setIsLoading(false); - } - }, - [address] - ); - - return { - transactions, - isLoading, - placeBet, - }; -} +"use client"; + +import { useState, useCallback } from "react"; +import { useAccount } from "@starknet-react/core"; +import { Transaction } from "../types/betting"; +import { placeBet as placeBetOnChain } from "../lib/starknet"; + +export function useBetting() { + const { address } = useAccount(); + const [transactions, setTransactions] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + const placeBet = useCallback( + async (agentId: number, amount: string) => { + if (!address) { + throw new Error("Wallet not connected"); + } + + setIsLoading(true); + + try { + // Create a pending transaction record + const pendingTx: Transaction = { + hash: "pending-" + Date.now(), + status: "pending", + message: `Placing bet of ${amount} STRK on agent #${agentId}...`, + timestamp: Date.now(), + }; + + setTransactions((prev) => [pendingTx, ...prev]); + + // Call the StarkNet contract + const result = await placeBetOnChain(agentId, amount); + + // Update the transaction status + setTransactions((prev) => + prev.map((tx) => + tx.hash === pendingTx.hash + ? { + hash: result.transactionHash, + status: "confirmed", + message: `Successfully placed bet of ${amount} STRK on agent #${agentId}`, + timestamp: Date.now(), + } + : tx, + ), + ); + + return result; + } catch (error) { + console.error("Transaction failed:", error); + + // Update the transaction status to failed + setTransactions((prev) => + prev.map((tx) => + tx.hash === "pending-" + Date.now().toString().slice(0, -3) + ? { + hash: "failed-" + Date.now(), + status: "failed", + message: `Failed to place bet: ${ + error instanceof Error ? error.message : "Unknown error" + }`, + timestamp: Date.now(), + } + : tx, + ), + ); + + throw error; + } finally { + setIsLoading(false); + } + }, + [address], + ); + + return { + transactions, + isLoading, + placeBet, + }; +} diff --git a/frontend/src/hooks/use-starknet-connect.tsx b/frontend/src/hooks/use-starknet-connect.tsx index 81c7bd3..84c1550 100644 --- a/frontend/src/hooks/use-starknet-connect.tsx +++ b/frontend/src/hooks/use-starknet-connect.tsx @@ -1,51 +1,51 @@ -"use client"; - -import { useCallback, useMemo } from "react"; -import { - argent, - braavos, - useInjectedConnectors, - voyager, - publicProvider, -} from "@starknet-react/core"; -import { mainnet, sepolia } from "@starknet-react/chains"; - -/** - * Hook to get Starknet connectors - */ -export function useStarknetConnectors() { - return useInjectedConnectors({ - recommended: [argent(), braavos()], - includeRecommended: "onlyIfNoConnectors", - order: "random", - }); -} - -/** - * Hook to get the complete Starknet configuration - * Includes error handling for disconnection events - */ -export function useStarknetConfig() { - const { connectors } = useStarknetConnectors(); - - // Handle wallet disconnection errors - const handleDisconnectError = useCallback((error: Error) => { - console.warn("Starknet disconnect error:", error); - // Dispatch a custom event that our components can listen for - window.dispatchEvent(new CustomEvent("wallet_disconnected")); - // Return true to indicate the error was handled - return true; - }, []); - - return useMemo( - () => ({ - chains: [mainnet, sepolia], - provider: publicProvider(), - connectors, - explorer: voyager, - autoConnect: true, - onDisconnectError: handleDisconnectError, - }), - [connectors, handleDisconnectError] - ); -} +"use client"; + +import { useCallback, useMemo } from "react"; +import { + argent, + braavos, + useInjectedConnectors, + voyager, + publicProvider, +} from "@starknet-react/core"; +import { mainnet, sepolia } from "@starknet-react/chains"; + +/** + * Hook to get Starknet connectors + */ +export function useStarknetConnectors() { + return useInjectedConnectors({ + recommended: [argent(), braavos()], + includeRecommended: "onlyIfNoConnectors", + order: "random", + }); +} + +/** + * Hook to get the complete Starknet configuration + * Includes error handling for disconnection events + */ +export function useStarknetConfig() { + const { connectors } = useStarknetConnectors(); + + // Handle wallet disconnection errors + const handleDisconnectError = useCallback((error: Error) => { + console.warn("Starknet disconnect error:", error); + // Dispatch a custom event that our components can listen for + window.dispatchEvent(new CustomEvent("wallet_disconnected")); + // Return true to indicate the error was handled + return true; + }, []); + + return useMemo( + () => ({ + chains: [mainnet, sepolia], + provider: publicProvider(), + connectors, + explorer: voyager, + autoConnect: true, + onDisconnectError: handleDisconnectError, + }), + [connectors, handleDisconnectError], + ); +} diff --git a/frontend/src/hooks/use-wallet-connection.tsx b/frontend/src/hooks/use-wallet-connection.tsx index b609cb3..978194b 100644 --- a/frontend/src/hooks/use-wallet-connection.tsx +++ b/frontend/src/hooks/use-wallet-connection.tsx @@ -1,109 +1,109 @@ -"use client"; - -import { useState, useCallback, useEffect } from "react"; -import { - useAccount, - useConnect, - useDisconnect, - type Connector, -} from "@starknet-react/core"; - -/** - * Custom hook for managing wallet connection state and operations - */ -export function useWalletConnection() { - const [isConnecting, setIsConnecting] = useState(false); - const [connectionError, setConnectionError] = useState(null); - const { address, isConnected, isConnecting: isReconnecting } = useAccount(); - const { connect, connectors } = useConnect(); - const { disconnect } = useDisconnect(); - - // Connect to wallet with error handling - const connectWallet = useCallback( - async (connector: Connector) => { - if (!connector) return Promise.reject(new Error("No connector provided")); - - setIsConnecting(true); - setConnectionError(null); - - try { - await connect({ connector }); - - // Save the last used connector for auto-connect - if (connector.id) { - localStorage.setItem("lastUsedConnector", connector.id); - } - return Promise.resolve(); - } catch (error) { - const errorMessage = - error instanceof Error ? error.message : "Failed to connect wallet"; - console.error("Wallet connection error:", errorMessage); - setConnectionError(errorMessage); - return Promise.reject(error); - } finally { - setIsConnecting(false); - } - }, - [connect] - ); - - // Disconnect wallet - const disconnectWallet = useCallback(() => { - disconnect(); - localStorage.removeItem("lastUsedConnector"); - }, [disconnect]); - - // Auto-connect on component mount - const autoConnect = useCallback(() => { - if ( - !isConnected && - !isReconnecting && - connectors && - connectors.length > 0 - ) { - const lastConnector = localStorage.getItem("lastUsedConnector"); - - if (lastConnector) { - const connector = connectors.find((c) => c.id === lastConnector); - if (connector) { - connectWallet(connector).catch(() => { - // Silent fail for auto-connect - }); - } - } - } - }, [connectWallet, connectors, isConnected, isReconnecting]); - - // Listen for wallet_disconnected events - useEffect(() => { - const handleWalletDisconnected = () => { - // Clear any connection state - localStorage.removeItem("lastUsedConnector"); - }; - - window.addEventListener("wallet_disconnected", handleWalletDisconnected); - - return () => { - window.removeEventListener( - "wallet_disconnected", - handleWalletDisconnected - ); - }; - }, []); - - // Run auto-connect on component mount - useEffect(() => { - autoConnect(); - }, [autoConnect]); - - return { - address, - isConnected, - isConnecting, - connectionError, - connectors, - connectWallet, - disconnectWallet, - autoConnect, - }; -} +"use client"; + +import { useState, useCallback, useEffect } from "react"; +import { + useAccount, + useConnect, + useDisconnect, + type Connector, +} from "@starknet-react/core"; + +/** + * Custom hook for managing wallet connection state and operations + */ +export function useWalletConnection() { + const [isConnecting, setIsConnecting] = useState(false); + const [connectionError, setConnectionError] = useState(null); + const { address, isConnected, isConnecting: isReconnecting } = useAccount(); + const { connect, connectors } = useConnect(); + const { disconnect } = useDisconnect(); + + // Connect to wallet with error handling + const connectWallet = useCallback( + async (connector: Connector) => { + if (!connector) return Promise.reject(new Error("No connector provided")); + + setIsConnecting(true); + setConnectionError(null); + + try { + await connect({ connector }); + + // Save the last used connector for auto-connect + if (connector.id) { + localStorage.setItem("lastUsedConnector", connector.id); + } + return Promise.resolve(); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : "Failed to connect wallet"; + console.error("Wallet connection error:", errorMessage); + setConnectionError(errorMessage); + return Promise.reject(error); + } finally { + setIsConnecting(false); + } + }, + [connect], + ); + + // Disconnect wallet + const disconnectWallet = useCallback(() => { + disconnect(); + localStorage.removeItem("lastUsedConnector"); + }, [disconnect]); + + // Auto-connect on component mount + const autoConnect = useCallback(() => { + if ( + !isConnected && + !isReconnecting && + connectors && + connectors.length > 0 + ) { + const lastConnector = localStorage.getItem("lastUsedConnector"); + + if (lastConnector) { + const connector = connectors.find((c) => c.id === lastConnector); + if (connector) { + connectWallet(connector).catch(() => { + // Silent fail for auto-connect + }); + } + } + } + }, [connectWallet, connectors, isConnected, isReconnecting]); + + // Listen for wallet_disconnected events + useEffect(() => { + const handleWalletDisconnected = () => { + // Clear any connection state + localStorage.removeItem("lastUsedConnector"); + }; + + window.addEventListener("wallet_disconnected", handleWalletDisconnected); + + return () => { + window.removeEventListener( + "wallet_disconnected", + handleWalletDisconnected, + ); + }; + }, []); + + // Run auto-connect on component mount + useEffect(() => { + autoConnect(); + }, [autoConnect]); + + return { + address, + isConnected, + isConnecting, + connectionError, + connectors, + connectWallet, + disconnectWallet, + autoConnect, + }; +} diff --git a/frontend/src/lib/starknet.ts b/frontend/src/lib/starknet.ts index d898e04..4a979de 100644 --- a/frontend/src/lib/starknet.ts +++ b/frontend/src/lib/starknet.ts @@ -1,82 +1,82 @@ -import { Agent } from "../types/betting"; - -// Mock agents data -const mockAgents: Agent[] = [ - { - id: 1, - name: "Mark Cuban", - image: "/bet-image1.jpg", - performance: 75, - }, - { - id: 2, - name: "Batman", - image: "/bet-image3.jpg", - performance: 45, - }, - { - id: 3, - name: "Literally a fish", - image: "/bet-image2.jpg", - performance: 90, - }, -]; - -// Get list of available agents -export async function getAgents(): Promise { - // In a real implementation, this would fetch agents from a backend or smart contract - return new Promise((resolve) => { - setTimeout(() => { - resolve(mockAgents); - }, 800); - }); -} - -// Place a bet on an agent -export async function placeBet( - agentId: number, - amount: string -): Promise<{ transactionHash: string }> { - // In a real implementation, this would call the StarkNet contract - - // This is where you would implement the actual StarkNet contract call - // Example implementation (commented out as it requires actual contract): - /* - const contractAddress = "0x123..."; // Your contract address - const contract = new Contract(abi, contractAddress, provider); - - // Convert amount to uint256 - const amountUint256 = uint256.bnToUint256(ethers.utils.parseEther(amount)); - - // Prepare calldata - const calldata = CallData.compile({ - agentId: agentId, - amount: amountUint256 - }); - - // Execute transaction - const tx = await contract.invoke("placeBet", calldata); - - return { - transactionHash: tx.transaction_hash - }; - */ - - // For now, we'll simulate a transaction with a delay - return new Promise((resolve, reject) => { - // Simulate transaction delay - setTimeout(() => { - // 90% chance of success - if (Math.random() > 0.1) { - resolve({ - transactionHash: - "0x" + - Math.random().toString(16).substring(2) + - Math.random().toString(16).substring(2), - }); - } else { - reject(new Error("Transaction rejected by the network")); - } - }, 2000); - }); -} +import { Agent } from "../types/betting"; + +// Mock agents data +const mockAgents: Agent[] = [ + { + id: 1, + name: "Mark Cuban", + image: "/bet-image1.jpg", + performance: 75, + }, + { + id: 2, + name: "Batman", + image: "/bet-image3.jpg", + performance: 45, + }, + { + id: 3, + name: "Literally a fish", + image: "/bet-image2.jpg", + performance: 90, + }, +]; + +// Get list of available agents +export async function getAgents(): Promise { + // In a real implementation, this would fetch agents from a backend or smart contract + return new Promise((resolve) => { + setTimeout(() => { + resolve(mockAgents); + }, 800); + }); +} + +// Place a bet on an agent +export async function placeBet( + agentId: number, + amount: string, +): Promise<{ transactionHash: string }> { + // In a real implementation, this would call the StarkNet contract + + // This is where you would implement the actual StarkNet contract call + // Example implementation (commented out as it requires actual contract): + /* + const contractAddress = "0x123..."; // Your contract address + const contract = new Contract(abi, contractAddress, provider); + + // Convert amount to uint256 + const amountUint256 = uint256.bnToUint256(ethers.utils.parseEther(amount)); + + // Prepare calldata + const calldata = CallData.compile({ + agentId: agentId, + amount: amountUint256 + }); + + // Execute transaction + const tx = await contract.invoke("placeBet", calldata); + + return { + transactionHash: tx.transaction_hash + }; + */ + + // For now, we'll simulate a transaction with a delay + return new Promise((resolve, reject) => { + // Simulate transaction delay + setTimeout(() => { + // 90% chance of success + if (Math.random() > 0.1) { + resolve({ + transactionHash: + "0x" + + Math.random().toString(16).substring(2) + + Math.random().toString(16).substring(2), + }); + } else { + reject(new Error("Transaction rejected by the network")); + } + }, 2000); + }); +} diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index bd0c391..a5ef193 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,6 +1,6 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); } diff --git a/frontend/src/motion/background-particles.tsx b/frontend/src/motion/background-particles.tsx index 83700af..9f34c88 100644 --- a/frontend/src/motion/background-particles.tsx +++ b/frontend/src/motion/background-particles.tsx @@ -19,4 +19,3 @@ const AnimatedBackground = () => { ); }; export default AnimatedBackground; - diff --git a/frontend/src/motion/floating-particle.tsx b/frontend/src/motion/floating-particle.tsx index 1b94c3c..715249d 100644 --- a/frontend/src/motion/floating-particle.tsx +++ b/frontend/src/motion/floating-particle.tsx @@ -16,4 +16,4 @@ export function FloatingParticles({ count = 50 }: { count?: number }) { ))}
); -} \ No newline at end of file +} diff --git a/frontend/src/types/betting.ts b/frontend/src/types/betting.ts index ceef481..924a199 100644 --- a/frontend/src/types/betting.ts +++ b/frontend/src/types/betting.ts @@ -1,13 +1,13 @@ -export type Agent = { - id: number; - name: string; - image: string; - performance: number; // 0-100 scale for the colored bar -}; - -export type Transaction = { - hash: string; - status: "pending" | "confirmed" | "failed"; - message: string; - timestamp: number; -}; +export type Agent = { + id: number; + name: string; + image: string; + performance: number; +}; + +export type Transaction = { + hash: string; + status: "pending" | "confirmed" | "failed"; + message: string; + timestamp: number; +}; diff --git a/frontend/src/utils/wallet.ts b/frontend/src/utils/wallet.ts index bbbdf7d..bcbec9d 100644 --- a/frontend/src/utils/wallet.ts +++ b/frontend/src/utils/wallet.ts @@ -1,13 +1,13 @@ -/** - * Truncates an address for display purposes - * @param address The full address to truncate - * @returns The truncated address (e.g. 0x1234...5678) - */ -export function truncateAddress(address: string): string { - if (!address) return ""; - if (address.length <= 10) return address; - - return `${address.substring(0, 6)}...${address.substring( - address.length - 4 - )}`; -} +/** + * Truncates an address for display purposes + * @param address The full address to truncate + * @returns The truncated address (e.g. 0x1234...5678) + */ +export function truncateAddress(address: string): string { + if (!address) return ""; + if (address.length <= 10) return address; + + return `${address.substring(0, 6)}...${address.substring( + address.length - 4, + )}`; +}