├── test
└── .gitkeep
├── src
├── vite-env.d.ts
├── types
│ ├── global.d.ts
│ └── index.ts
├── assets
│ ├── Queen.png
│ ├── Rook.png
│ ├── Bishop.png
│ └── pngegg.png
├── main.tsx
├── index.css
├── config
│ ├── constants.ts
│ └── ChessGame.json
├── components
│ ├── Input.tsx
│ ├── Dialog.tsx
│ ├── ErrorMessage.tsx
│ ├── Button.tsx
│ ├── GameStatus.tsx
│ ├── WalletConnect.tsx
│ ├── Footer.tsx
│ ├── Navbar.tsx
│ └── Chessboard.tsx
├── store
│ ├── useGameStore.ts
│ └── useWalletStore.ts
├── App.tsx
├── services
│ └── socketService.ts
└── pages
│ ├── Leaderboard.tsx
│ ├── FreeMode.tsx
│ ├── Home.tsx
│ ├── OnlineMode.tsx
│ └── BotMode.tsx
├── netlify.toml
├── MockDown images
├── clone.png
├── Botmode.png
├── Chess-home.png
├── local_run.png
├── game created.png
├── whitescreen.png
├── Contract report.png
├── local_install.png
└── Chessgame report.png
├── postcss.config.js
├── server-
├── vercel.json
├── package.json
├── index.js
└── package-lock.json
├── tsconfig.json
├── tailwind.config.js
├── vite.config.ts
├── Contract
├── tsconfig.json
├── data.txt
├── README.md
├── .gitignore
└── ChessGame.sol
├── index.html
├── tsconfig.node.json
├── truffle-config.cjs
├── tsconfig.app.json
├── eslint.config.js
├── LICENSE
├── GetPoints.md
├── package.json
├── .gitignore
├── CONTRIBUTING.md
└── README.md
/test/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [[redirects]]
2 | from = "/*"
3 | to = "/index.html"
4 | status = 200
--------------------------------------------------------------------------------
/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | interface Window {
2 | ethereum: any;
3 | Stockfish: any;
4 | }
--------------------------------------------------------------------------------
/src/assets/Queen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/src/assets/Queen.png
--------------------------------------------------------------------------------
/src/assets/Rook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/src/assets/Rook.png
--------------------------------------------------------------------------------
/src/assets/Bishop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/src/assets/Bishop.png
--------------------------------------------------------------------------------
/src/assets/pngegg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/src/assets/pngegg.png
--------------------------------------------------------------------------------
/MockDown images/clone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/clone.png
--------------------------------------------------------------------------------
/MockDown images/Botmode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/Botmode.png
--------------------------------------------------------------------------------
/MockDown images/Chess-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/Chess-home.png
--------------------------------------------------------------------------------
/MockDown images/local_run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/local_run.png
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/MockDown images/game created.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/game created.png
--------------------------------------------------------------------------------
/MockDown images/whitescreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/whitescreen.png
--------------------------------------------------------------------------------
/MockDown images/Contract report.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/Contract report.png
--------------------------------------------------------------------------------
/MockDown images/local_install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/local_install.png
--------------------------------------------------------------------------------
/MockDown images/Chessgame report.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Navneet1206/Ether-Chess-OTC/HEAD/MockDown images/Chessgame report.png
--------------------------------------------------------------------------------
/server-/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "version":2,
3 | "builds":[{"src":"./index.js","use":"@vercel/node"}],
4 | "routes": [{"src":"/(.*)","dest":"/"}]
5 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { createRoot } from 'react-dom/client';
3 | import App from './App.tsx';
4 | import './index.css';
5 |
6 | createRoot(document.getElementById('root')!).render(
7 |
8 | );
9 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | };
9 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss/base";
2 | @import "tailwindcss/components";
3 | @import "tailwindcss/utilities";
4 | .highlight-check {
5 | background-color: rgba(255, 0, 0, 0.5); /* Red translucent background */
6 | }
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import react from '@vitejs/plugin-react';
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | optimizeDeps: {
8 | exclude: ['lucide-react'],
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/Contract/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2020",
4 | "module": "commonjs",
5 | "esModuleInterop": true,
6 | "forceConsistentCasingInFileNames": true,
7 | "strict": true,
8 | "skipLibCheck": true,
9 | "resolveJsonModule": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/config/constants.ts:
--------------------------------------------------------------------------------
1 | export const CONTRACT_ADDRESS = '0x5E88992fC85ab96bb184269C8E5cBd77BF933147'; // Replace with actual deployed contract address
2 |
3 | export const MINIMUM_STAKE = '0.00001';
4 | export const MAXIMUM_STAKE = '0.1';
5 |
6 | export const BOT_DIFFICULTY_LEVELS = {
7 | EASY: 5,
8 | MEDIUM: 10,
9 | HARD: 15,
10 | } as const;
--------------------------------------------------------------------------------
/src/components/Input.tsx:
--------------------------------------------------------------------------------
1 | export const Input = ({ label, ...props }) => (
2 |
3 | {label && {label} }
4 |
5 |
6 | );
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | web3-chess-platform
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Contract/data.txt:
--------------------------------------------------------------------------------
1 | import { HardhatUserConfig } from 'hardhat/config';
2 | import '@nomicfoundation/hardhat-toolbox';
3 | const config: HardhatUserConfig = {
4 | solidity: '0.8.20',
5 | networks: {
6 | sepolia: {
7 | url: `https://eth-ropsten.alchemyapi.io/v2/z4WpA8UKgqnwbTYmrZu15yCOiijBKaRv`,
8 | accounts: '2f99db8cdb04655028eee1dc98230925202f6b3e010e43fad2883b4bea90a1a3',
9 | },
10 | },
11 | };
12 |
13 | export default config;
--------------------------------------------------------------------------------
/Contract/README.md:
--------------------------------------------------------------------------------
1 | # Sample Hardhat Project
2 |
3 | This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a Hardhat Ignition module that deploys that contract.
4 |
5 | Try running some of the following tasks:
6 |
7 | ```shell
8 | npx hardhat help
9 | npx hardhat test
10 | REPORT_GAS=true npx hardhat test
11 | npx hardhat node
12 | npx hardhat ignition deploy ./ignition/modules/Lock.ts
13 | ```
14 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export interface Player {
2 | address: string;
3 | username: string;
4 | rating: number;
5 | earnings: number;
6 | }
7 |
8 | export interface GameState {
9 | gameId?: string | null;
10 | players?: {
11 | white: Player | null;
12 | black: Player | null;
13 | };
14 | stake?: string | number;
15 | status?: 'waiting' | 'active' | 'completed';
16 | winner?: string | null;
17 | moves?: string[];
18 | position?: string;
19 | checkedKing?: 'white' | 'black' | null; //Check if the king is in checked
20 | }
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "lib": ["ES2023"],
5 | "module": "ESNext",
6 | "skipLibCheck": true,
7 |
8 | /* Bundler mode */
9 | "moduleResolution": "bundler",
10 | "allowImportingTsExtensions": true,
11 | "isolatedModules": true,
12 | "moduleDetection": "force",
13 | "noEmit": true,
14 |
15 | /* Linting */
16 | "strict": true,
17 | "noUnusedLocals": true,
18 | "noUnusedParameters": true,
19 | "noFallthroughCasesInSwitch": true
20 | },
21 | "include": ["vite.config.ts"]
22 | }
23 |
--------------------------------------------------------------------------------
/truffle-config.cjs:
--------------------------------------------------------------------------------
1 | // truffle-config.cjs
2 | const { config: dotenvConfig } = require("dotenv");
3 | const { HardhatUserConfig } = require("hardhat/config");
4 | require("@nomiclabs/hardhat-ethers");
5 |
6 | dotenvConfig(); // Loads .env variables
7 |
8 | const SEPOLIA_URL = process.env.SEPOLIA_URL || "";
9 | const PRIVATE_KEY = process.env.PRIVATE_KEY || "";
10 |
11 | const config = {
12 | solidity: "0.8.20",
13 | networks: {
14 | sepolia: {
15 | url: SEPOLIA_URL,
16 | accounts: PRIVATE_KEY !== "" ? [PRIVATE_KEY] : [],
17 | },
18 | },
19 | };
20 |
21 | module.exports = config;
22 |
--------------------------------------------------------------------------------
/src/components/Dialog.tsx:
--------------------------------------------------------------------------------
1 | export const Dialog = ({ open, onClose, title, description, children }) => {
2 | if (!open) return null;
3 |
4 | return (
5 |
6 |
7 |
8 | {title &&
{title} }
9 | {description &&
{description}
}
10 | {children}
11 |
12 |
13 | );
14 | };
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "isolatedModules": true,
13 | "moduleDetection": "force",
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"]
24 | }
25 |
--------------------------------------------------------------------------------
/server-/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "start": "nodemon index.js"
7 | },
8 | "keywords": [],
9 | "author": "",
10 | "license": "ISC",
11 | "description": "",
12 | "dependencies": {
13 | "@jackstenglein/chess": "^2.2.8",
14 | "body-parser": "^1.20.3",
15 | "chess.js": "^1.0.0-beta.8",
16 | "chessground": "^9.1.1",
17 | "cors": "^2.8.5",
18 | "ethers": "^6.13.5",
19 | "express": "^4.21.2",
20 | "http": "^0.0.1-security",
21 | "socket.io": "^4.8.1",
22 | "ws": "^8.18.0"
23 | },
24 | "devDependencies": {
25 | "nodemon": "^3.1.7"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/ErrorMessage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AlertCircle } from 'lucide-react';
3 |
4 | interface ErrorMessageProps {
5 | message: string;
6 | onClose?: () => void;
7 | }
8 |
9 | export const ErrorMessage: React.FC = ({ message, onClose }) => {
10 | return (
11 |
12 |
13 |
14 |
{message}
15 | {onClose && (
16 |
20 | ×
21 |
22 | )}
23 |
24 |
25 | );
26 | };
--------------------------------------------------------------------------------
/src/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import { Loader2 } from 'lucide-react';
2 |
3 | export const Button = ({ children, onClick, disabled, variant = 'primary', className = '', loading = false }) => {
4 | const baseStyles = "px-4 py-2 rounded-lg font-medium transition-colors disabled:opacity-50 flex items-center justify-center gap-2";
5 | const variants = {
6 | primary: "bg-indigo-600 hover:bg-indigo-500 text-white disabled:hover:bg-indigo-600",
7 | secondary: "bg-gray-700 hover:bg-gray-600 text-white",
8 | outline: "border border-white/10 bg-gray-800 hover:bg-gray-700 text-white"
9 | };
10 |
11 | return (
12 |
13 | {loading && }
14 | {children}
15 |
16 | );
17 | };
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import globals from 'globals';
3 | import reactHooks from 'eslint-plugin-react-hooks';
4 | import reactRefresh from 'eslint-plugin-react-refresh';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | { ignores: ['dist'] },
9 | {
10 | extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 | files: ['**/*.{ts,tsx}'],
12 | languageOptions: {
13 | ecmaVersion: 2020,
14 | globals: globals.browser,
15 | },
16 | plugins: {
17 | 'react-hooks': reactHooks,
18 | 'react-refresh': reactRefresh,
19 | },
20 | rules: {
21 | ...reactHooks.configs.recommended.rules,
22 | 'react-refresh/only-export-components': [
23 | 'warn',
24 | { allowConstantExport: true },
25 | ],
26 | },
27 | }
28 | );
29 |
--------------------------------------------------------------------------------
/src/store/useGameStore.ts:
--------------------------------------------------------------------------------
1 | import { create } from 'zustand';
2 | import { GameState } from '../types';
3 |
4 | interface GameStore {
5 | gameState: GameState;
6 | setGameState: (state: GameState) => void;
7 | resetGame: () => void;
8 | checkedKing: 'white' | 'black' | null;
9 | setCheckedKing: (king: 'white' | 'black' | null) => void;
10 | }
11 |
12 | const initialGameState: GameState = {
13 | position: 'start',
14 | players: {
15 | white: null,
16 | black: null
17 | },
18 | status: 'waiting',
19 | moves: [],
20 | stake: 0,
21 | gameId: null,
22 | checkedKing: null,
23 | };
24 |
25 | export const useGameStore = create((set) => ({
26 | checkedKing: null,
27 | setCheckedKing: (king) => set({ checkedKing: king }),
28 | gameState: initialGameState,
29 | setGameState: (state) => set({ gameState: { ...initialGameState, ...state } }),
30 | resetGame: () => set({ gameState: initialGameState }),
31 | }));
32 |
--------------------------------------------------------------------------------
/Contract/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
3 |
4 | # Hardhat files
5 | /cache
6 | /artifacts
7 |
8 | # TypeChain files
9 | /typechain
10 | /typechain-types
11 |
12 | # solidity-coverage files
13 | /coverage
14 | /coverage.json
15 |
16 | # Hardhat Ignition default folder for deployments against a local node
17 | ignition/deployments/chain-31337
18 |
19 | node_modules
20 | .env
21 |
22 | # Hardhat files
23 | /cache
24 | /artifacts
25 |
26 | # TypeChain files
27 | /typechain
28 | /typechain-types
29 |
30 | # solidity-coverage files
31 | /coverage
32 | /coverage.json
33 |
34 | # Hardhat Ignition default folder for deployments against a local node
35 | ignition/deployments/chain-31337
36 |
37 | node_modules
38 | .env
39 |
40 | # Hardhat files
41 | /cache
42 | /artifacts
43 |
44 | # TypeChain files
45 | /typechain
46 | /typechain-types
47 |
48 | # solidity-coverage files
49 | /coverage
50 | /coverage.json
51 |
52 | # Hardhat Ignition default folder for deployments against a local node
53 | ignition/deployments/chain-31337
54 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
3 | import { Navbar } from './components/Navbar';
4 | import { Home } from './pages/Home';
5 | import { FreeMode } from './pages/FreeMode';
6 | import { BotMode } from './pages/BotMode';
7 | import { OnlineMode } from './pages/OnlineMode';
8 | import { Leaderboard } from './pages/Leaderboard';
9 | import { Footer } from './components/Footer';
10 |
11 | function App() {
12 | return (
13 |
14 |
15 |
16 |
17 | } />
18 | } />
19 | } />
20 | } />
21 | } />
22 |
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | export default App;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Navneet Vishwakarma
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/GetPoints.md:
--------------------------------------------------------------------------------
1 |
2 | # Thank you for contributing to this project! To streamline the process and ensure smooth collaboration, please follow the guidelines below when submitting your pull requests.
3 |
4 | ## **How to Submit Pull Request Information**
5 |
6 | ### Step 1: Visit the Portfolio
7 | - Go to Portfolio :- https://navneet-resume.netlify.app/
8 |
9 | ### Step 2: Fill Out the Contact Form
10 | provide the following details in the form:
11 |
12 | 1. **Name:**
13 | - Format: Your Full Name (GitHub Username)
14 | - Example: John Doe (johndoe123)
15 |
16 | 2. **Mail:**
17 | - Use your working email address.
18 |
19 | 3. **Project:**
20 | - Include the URL of your pull request.
21 |
22 | 4. **Message:**
23 | - Provide additional details about your contribution type(s).
24 | - If you have multiple pull requests, list them in the message using the format below:
25 |
26 | ### Example Format for the Message Section:
27 | ```plaintext
28 | Pull Request 1: [URL]
29 | Contribution Type: Bug Fix / Feature Addition / Documentation Update, etc.
30 |
31 | Pull Request 2: [URL]
32 | Contribution Type: Code Optimization / Testing, etc.
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web3-chess-platform",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@jackstenglein/chess": "^2.2.8",
14 | "@openzeppelin/contracts": "^5.0.1",
15 | "chess.js": "^1.0.0-beta.7",
16 | "chessground": "^9.1.1",
17 | "ethers": "^6.11.1",
18 | "express": "^4.18.3",
19 | "hardhat": "^2.22.17",
20 | "lucide-react": "^0.344.0",
21 | "react": "^18.3.1",
22 | "react-chessboard": "^4.4.0",
23 | "react-dom": "^18.3.1",
24 | "react-router-dom": "^6.22.2",
25 | "socket.io": "^4.7.4",
26 | "socket.io-client": "^4.7.4",
27 | "stockfish.js": "^10.0.2",
28 | "zustand": "^4.5.2"
29 | },
30 | "devDependencies": {
31 | "@eslint/js": "^9.9.1",
32 | "@types/concat-stream": "^2.0.3",
33 | "@types/react": "^18.3.5",
34 | "@types/react-dom": "^18.3.0",
35 | "@vitejs/plugin-react": "^4.3.1",
36 | "autoprefixer": "^10.4.18",
37 | "eslint": "^9.9.1",
38 | "eslint-plugin-react-hooks": "^5.1.0-rc.0",
39 | "eslint-plugin-react-refresh": "^0.4.11",
40 | "globals": "^15.9.0",
41 | "postcss": "^8.4.35",
42 | "tailwindcss": "^3.4.1",
43 | "typescript": "^5.5.3",
44 | "typescript-eslint": "^8.3.0",
45 | "vite": "^5.4.2"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/GameStatus.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Clock } from 'lucide-react';
3 |
4 | interface GameStatusProps {
5 | status: 'waiting' | 'active' | 'completed';
6 | timeLeft?: number;
7 | currentPlayer?: 'white' | 'black';
8 | }
9 |
10 | export const GameStatus: React.FC = ({ status, timeLeft, currentPlayer }) => {
11 | return (
12 |
13 |
14 |
22 | {timeLeft && (
23 |
24 |
25 | {Math.floor(timeLeft / 60)}:{(timeLeft % 60).toString().padStart(2, '0')}
26 |
27 | )}
28 |
29 | {currentPlayer && status === 'active' && (
30 |
31 | Current turn: {currentPlayer}
32 |
33 | )}
34 |
35 | );
36 | };
37 |
--------------------------------------------------------------------------------
/src/store/useWalletStore.ts:
--------------------------------------------------------------------------------
1 | import { create } from 'zustand';
2 | import { ethers } from 'ethers';
3 |
4 | interface WalletState {
5 | address: string | null;
6 | balance: string | null;
7 | provider: ethers.BrowserProvider | null;
8 | signer: ethers.JsonRpcSigner | null;
9 | isConnecting: boolean;
10 | error: string | null;
11 | connectWallet: () => Promise;
12 | disconnectWallet: () => void;
13 | }
14 |
15 | export const useWalletStore = create((set) => ({
16 | address: null,
17 | balance: null,
18 | provider: null,
19 | signer: null,
20 | isConnecting: false,
21 | error: null,
22 |
23 | connectWallet: async () => {
24 | try {
25 | set({ isConnecting: true, error: null });
26 |
27 | if (!window.ethereum) {
28 | throw new Error('MetaMask is not installed');
29 | }
30 |
31 | const provider = new ethers.BrowserProvider(window.ethereum);
32 | const signer = await provider.getSigner();
33 | const address = await signer.getAddress();
34 | const balance = ethers.formatEther(await provider.getBalance(address));
35 |
36 | set({ provider, signer, address, balance, isConnecting: false });
37 | } catch (error) {
38 | set({ error: (error as Error).message, isConnecting: false });
39 | }
40 | },
41 |
42 | disconnectWallet: () => {
43 | set({
44 | address: null,
45 | balance: null,
46 | provider: null,
47 | signer: null,
48 | error: null,
49 | });
50 | },
51 | }));
--------------------------------------------------------------------------------
/src/components/WalletConnect.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useWalletStore } from '../store/useWalletStore';
3 | import { Wallet } from 'lucide-react';
4 |
5 | export const WalletConnect: React.FC = () => {
6 | const { address, balance, connectWallet, disconnectWallet, isConnecting, error } = useWalletStore();
7 |
8 | return (
9 |
10 | {address ? (
11 |
12 |
13 |
14 | {address.slice(0, 6)}...{address.slice(-4)}
15 |
16 |
{balance?.slice(0, 8)} ETH
17 |
18 |
22 | Disconnect
23 |
24 |
25 | ) : (
26 |
31 |
32 | {isConnecting ? 'Connecting...' : 'Connect Wallet'}
33 |
34 | )}
35 | {error &&
{error}
}
36 |
37 | );
38 | };
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 | .pnpm-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Snowpack dependency directory (https://snowpack.dev/)
46 | web_modules/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Optional stylelint cache
58 | .stylelintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variable files
76 | .env
77 | .env.development.local
78 | .env.test.local
79 | .env.production.local
80 | .env.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 | out
89 |
90 | # Nuxt.js build / generate output
91 | .nuxt
92 | dist
93 |
94 | # Gatsby files
95 | .cache/
96 | # Comment in the public line in if your project uses Gatsby and not Next.js
97 | # https://nextjs.org/blog/next-9-1#public-directory-support
98 | # public
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # vuepress v2.x temp and cache directory
104 | .temp
105 | .cache
106 |
107 | # Docusaurus cache and generated files
108 | .docusaurus
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # yarn v2
126 | .yarn/cache
127 | .yarn/unplugged
128 | .yarn/build-state.yml
129 | .yarn/install-state.gz
130 | .pnp.*
131 |
--------------------------------------------------------------------------------
/server-/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const { ethers } = require('ethers');
3 | const cors = require('cors');
4 | const { Chess } = require('chess.js');
5 | const { createServer } = require('http');
6 | const { Server } = require('socket.io');
7 |
8 | const app = express();
9 | const server = createServer(app);
10 | const io = new Server(server, {
11 | cors: {
12 | origin: '*', // Allow all origins (update in production)
13 | },
14 | });
15 |
16 | app.use(cors());
17 | app.use(express.json());
18 |
19 | // Ethereum contract setup
20 | const provider = new ethers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'); // Replace with your Infura or Alchemy URL
21 | const contractAddress = '0xA12E9052EDbffCA633eBe3Fc9B3F477E516d4D43'; // Replace with your contract address
22 | const contractABI = [
23 | // Paste your contract ABI here
24 | ];
25 |
26 | const contract = new ethers.Contract(contractAddress, contractABI, provider);
27 |
28 | // In-memory game state storage
29 | const games = new Map(); // gameId -> { position: 'start', players: { white: address, black: address } }
30 |
31 | // Socket.io connection handler
32 | io.on('connection', (socket) => {
33 | console.log('A user connected:', socket.id);
34 |
35 | // Handle game creation
36 | socket.on('createGame', async ({ gameId, stake, address }) => {
37 | try {
38 | const game = new Chess();
39 | games.set(gameId, { position: game.fen(), players: { white: address, black: null } });
40 | socket.join(gameId);
41 | io.to(gameId).emit('gameState', { position: game.fen(), players: { white: address, black: null } });
42 | } catch (error) {
43 | console.error('Error creating game:', error);
44 | socket.emit('error', 'Failed to create game');
45 | }
46 | });
47 |
48 | // Handle game joining
49 | socket.on('joinGame', async ({ gameId, address }) => {
50 | try {
51 | const gameState = games.get(gameId);
52 | if (!gameState) {
53 | throw new Error('Game does not exist');
54 | }
55 | if (gameState.players.black) {
56 | throw new Error('Game is already full');
57 | }
58 |
59 | gameState.players.black = address;
60 | games.set(gameId, gameState);
61 | socket.join(gameId);
62 | io.to(gameId).emit('gameState', gameState);
63 | } catch (error) {
64 | console.error('Error joining game:', error);
65 | socket.emit('error', error.message);
66 | }
67 | });
68 |
69 | // Handle moves
70 | socket.on('makeMove', ({ gameId, move }) => {
71 | try {
72 | const gameState = games.get(gameId);
73 | if (!gameState) {
74 | throw new Error('Game does not exist');
75 | }
76 |
77 | const game = new Chess(gameState.position);
78 | const result = game.move(move);
79 | if (!result) {
80 | throw new Error('Invalid move');
81 | }
82 |
83 | gameState.position = game.fen();
84 | games.set(gameId, gameState);
85 | io.to(gameId).emit('gameState', gameState);
86 |
87 | // Check for game over
88 | if (game.isGameOver()) {
89 | io.to(gameId).emit('gameOver', { winner: game.turn() === 'w' ? gameState.players.black : gameState.players.white });
90 | }
91 | } catch (error) {
92 | console.error('Error making move:', error);
93 | socket.emit('error', error.message);
94 | }
95 | });
96 |
97 | // Handle disconnection
98 | socket.on('disconnect', () => {
99 | console.log('A user disconnected:', socket.id);
100 | });
101 | });
102 |
103 | // Start the server
104 | const PORT = process.env.PORT || 5000;
105 | server.listen(PORT, () => {
106 | console.log(`Server running on port ${PORT}`);
107 | });
--------------------------------------------------------------------------------
/Contract/ChessGame.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.20;
3 | import "@openzeppelin/contracts/access/Ownable.sol";
4 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
5 |
6 | contract ChessGame is Ownable, ReentrancyGuard {
7 | struct Game {
8 | address white;
9 | address black;
10 | uint256 stake;
11 | bool isActive;
12 | address winner;
13 | uint256 startTime;
14 | uint256 joinTimeout; // Timeout for joining the game
15 | }
16 |
17 | mapping(bytes32 => Game) public games;
18 | mapping(address => uint256) public playerEarnings;
19 |
20 | uint256 public ownerFeePercentage = 5; // 5% fee
21 | uint256 public joinTimeoutDuration = 1 hours; // Default timeout duration
22 |
23 | event GameCreated(bytes32 gameId, address indexed white, uint256 stake, uint256 startTime);
24 | event GameJoined(bytes32 gameId, address indexed black);
25 | event GameEnded(bytes32 gameId, address indexed winner, uint256 prize);
26 | event GameCanceled(bytes32 gameId, address indexed canceledBy);
27 | event StakeRefunded(bytes32 gameId, address indexed player, uint256 amount);
28 |
29 | constructor() {}
30 |
31 | /// @notice Creates a new chess game with a given gameId and stake.
32 | /// @param gameId The unique identifier for the game (as bytes32).
33 | function createGame(bytes32 gameId) external payable {
34 | require(msg.value > 0, "Stake must be greater than 0");
35 | require(games[gameId].white == address(0), "Game already exists");
36 |
37 | games[gameId] = Game({
38 | white: msg.sender,
39 | black: address(0),
40 | stake: msg.value,
41 | isActive: true,
42 | winner: address(0),
43 | startTime: block.timestamp,
44 | joinTimeout: block.timestamp + joinTimeoutDuration
45 | });
46 |
47 | emit GameCreated(gameId, msg.sender, msg.value, block.timestamp);
48 | }
49 |
50 | /// @notice Joins an existing game by providing the correct stake.
51 | /// @param gameId The unique identifier for the game to join.
52 | function joinGame(bytes32 gameId) external payable {
53 | Game storage game = games[gameId];
54 | require(game.white != address(0), "Game does not exist");
55 | require(game.black == address(0), "Game already full");
56 | require(msg.value == game.stake, "Incorrect stake amount");
57 | require(block.timestamp <= game.joinTimeout, "Join timeout expired");
58 |
59 | game.black = msg.sender;
60 | emit GameJoined(gameId, msg.sender);
61 | }
62 |
63 | /// @notice Ends a game and declares the winner. Only the owner can call this.
64 | /// @param gameId The unique identifier for the game to end.
65 | /// @param winner The address of the winner.
66 | function endGame(bytes32 gameId, address winner) external onlyOwner {
67 | Game storage game = games[gameId];
68 | require(game.isActive, "Game not active");
69 | require(winner == game.white || winner == game.black, "Invalid winner");
70 |
71 | game.isActive = false;
72 | game.winner = winner;
73 |
74 | uint256 totalPrize = game.stake * 2;
75 | uint256 ownerFee = (totalPrize * ownerFeePercentage) / 100;
76 | uint256 winnerPrize = totalPrize - ownerFee;
77 |
78 | playerEarnings[winner] += winnerPrize;
79 |
80 | emit GameEnded(gameId, winner, winnerPrize);
81 | }
82 |
83 | /// @notice Cancels a game and refunds stakes. Only the owner can call this.
84 | /// @param gameId The unique identifier for the game to cancel.
85 | function cancelGame(bytes32 gameId) external onlyOwner {
86 | Game storage game = games[gameId];
87 | require(game.isActive, "Game not active");
88 |
89 | game.isActive = false;
90 |
91 | // Refund stakes
92 | payable(game.white).transfer(game.stake);
93 | if (game.black != address(0)) {
94 | payable(game.black).transfer(game.stake);
95 | }
96 |
97 | emit GameCanceled(gameId, msg.sender);
98 | }
99 |
100 | /// @notice Withdraw earnings for the caller.
101 | function withdrawEarnings() external nonReentrant {
102 | uint256 amount = playerEarnings[msg.sender];
103 | require(amount > 0, "No earnings to withdraw");
104 |
105 | playerEarnings[msg.sender] = 0;
106 | payable(msg.sender).transfer(amount);
107 | }
108 |
109 | /// @notice Withdraw accumulated fees by the owner.
110 | function withdrawOwnerFees() external onlyOwner {
111 | uint256 balance = address(this).balance;
112 | require(balance > 0, "No fees to withdraw");
113 | payable(owner()).transfer(balance);
114 | }
115 | }
--------------------------------------------------------------------------------
/src/services/socketService.ts:
--------------------------------------------------------------------------------
1 | import { io, Socket } from 'socket.io-client';
2 | import { GameState } from '../types';
3 | import { useGameStore } from '../store/useGameStore';
4 |
5 | class SocketService {
6 | private socket: Socket | null = null;
7 | private gameStateCallback: ((state: GameState) => void) | null = null;
8 | private reconnectAttempts = 0;
9 | private maxReconnectAttempts = 3;
10 | private currentGameId: string | null = null;
11 |
12 | connect(address: string, username: string) {
13 | this.disconnect();
14 |
15 | if (!address || !username) {
16 | console.error('Invalid connection parameters');
17 | return;
18 | }
19 |
20 | this.attemptConnection(address, username);
21 | }
22 |
23 | private attemptConnection(address: string, username: string) {
24 | this.reconnectAttempts = 0;
25 | this.createSocketConnection(address, username);
26 | }
27 |
28 | private createSocketConnection(address: string, username: string) {
29 | try {
30 | this.socket = io('http://localhost:8080', {
31 | query: {
32 | address: address.toLowerCase(),
33 | username: username.trim()
34 | },
35 | transports: ['websocket', 'polling'],
36 | reconnection: true,
37 | reconnectionAttempts: this.maxReconnectAttempts,
38 | reconnectionDelay: 1000
39 | });
40 |
41 | this.setupSocketListeners(address, username);
42 | } catch (error) {
43 | console.error('Socket connection initialization error:', error);
44 | this.handleConnectionError(address, username);
45 | }
46 | }
47 |
48 | private setupSocketListeners(address: string, username: string) {
49 | if (!this.socket) return;
50 |
51 | this.socket.on('connect', () => {
52 | console.log('Socket connected successfully');
53 | this.reconnectAttempts = 0;
54 |
55 | // Request initial game state if a game is in progress
56 | if (this.currentGameId && this.socket) {
57 | this.socket.emit('requestInitialGameState', { gameId: this.currentGameId });
58 | }
59 | });
60 |
61 | this.socket.on('connect_error', (error) => {
62 | console.error('Connection error:', error);
63 | this.handleConnectionError(address, username);
64 | });
65 |
66 | this.socket.on('disconnect', (reason) => {
67 | console.log('Socket disconnected:', reason);
68 | if (reason === 'io server disconnect') {
69 | this.createSocketConnection(address, username);
70 | }
71 | });
72 |
73 | this.socket.on('gameCreated', ({ gameId }) => {
74 | console.log('Game created with ID:', gameId);
75 | this.currentGameId = gameId;
76 | });
77 |
78 | this.socket.on('gameState', (state: GameState) => {
79 | console.log('Received game state:', state);
80 | if (this.gameStateCallback) {
81 | this.gameStateCallback(state);
82 | }
83 | });
84 |
85 | this.socket.on('initialGameState', (state: GameState) => {
86 | console.log('Received initial game state:', state);
87 | if (this.gameStateCallback) {
88 | this.gameStateCallback(state);
89 | }
90 | });
91 |
92 | // Check if the king is in check
93 | this.socket.on('kingInCheck', ({ kingColor }) => {
94 | console.log('King in check:', kingColor);
95 | useGameStore.getState().setCheckedKing(kingColor);
96 | });
97 |
98 | this.socket.on('gameOver', ({ winner }) => {
99 | console.log('Game over, winner:', winner);
100 | useGameStore.getState().setGameState({ status: 'finished', winner });
101 | });
102 | }
103 |
104 | private handleConnectionError(address: string, username: string) {
105 | this.reconnectAttempts++;
106 |
107 | if (this.reconnectAttempts < this.maxReconnectAttempts) {
108 | console.log(`Reconnection attempt ${this.reconnectAttempts}`);
109 |
110 | setTimeout(() => {
111 | this.createSocketConnection(address, username);
112 | }, 1000 * this.reconnectAttempts);
113 | } else {
114 | console.error('Maximum reconnection attempts reached');
115 | }
116 | }
117 |
118 | createGame(stake: string) {
119 | if (!this.socket) return;
120 | this.socket.emit('createGame', { stake });
121 | }
122 |
123 | joinGame(gameId: string) {
124 | if (!this.socket) return;
125 | this.currentGameId = gameId;
126 | this.socket.emit('joinGame', { gameId });
127 | }
128 |
129 | makeMove(gameId: string, move: { from: string; to: string }) {
130 | if (!this.socket) return;
131 | this.socket.emit('makeMove', { gameId, move });
132 | }
133 |
134 | onGameState(callback: (state: GameState) => void) {
135 | this.gameStateCallback = callback;
136 | }
137 |
138 | disconnect() {
139 | if (this.socket) {
140 | this.socket.disconnect();
141 | this.socket = null;
142 | this.currentGameId = null;
143 | }
144 | }
145 | }
146 |
147 | export const socketService = new SocketService();
--------------------------------------------------------------------------------
/src/components/Footer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | export const Footer: React.FC = () => {
5 | return (
6 |
7 | {/* Subtle animated chess pattern */}
8 |
9 |
10 | {[...Array(16)].map((_, i) => (
11 |
17 | ))}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ♔
26 |
Web3 Chess
27 |
28 |
29 | The future of chess meets blockchain technology. Play, compete, and earn in the most innovative chess platform.
30 |
31 |
32 |
33 |
34 |
Play
35 |
36 |
37 | console.log('Navigate to practice')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
38 | Practice Mode
39 |
40 |
41 |
42 | console.log('Navigate to tournaments')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
43 | Tournaments
44 |
45 |
46 |
47 | console.log('Navigate to AI')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
48 | AI Challenge
49 |
50 |
51 |
52 |
53 |
54 |
55 |
Resources
56 |
57 |
58 | console.log('Navigate to learn')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
59 | Learn Chess
60 |
61 |
62 |
63 | console.log('Navigate to rules')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
64 | Game Rules
65 |
66 |
67 |
68 | console.log('Navigate to FAQ')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
69 | FAQ
70 |
71 |
72 |
73 |
74 |
75 |
76 |
Legal
77 |
78 |
79 | console.log('Navigate to privacy')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
80 | Privacy Policy
81 |
82 |
83 |
84 | console.log('Navigate to terms')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
85 | Terms of Service
86 |
87 |
88 |
89 | console.log('Navigate to contact')} className="text-blue-200/70 hover:text-blue-400 text-sm transition-colors">
90 | Contact Us
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | © {new Date().getFullYear()} Web3 Chess. All rights reserved.
100 |
101 |
102 | console.log('Navigate to twitter')} className="text-blue-200/70 hover:text-blue-400 transition-colors">
103 | 𝕏
104 |
105 | console.log('Navigate to discord')} className="text-blue-200/70 hover:text-blue-400 transition-colors">
106 | Discord
107 |
108 | console.log('Navigate to telegram')} className="text-blue-200/70 hover:text-blue-400 transition-colors">
109 | Telegram
110 |
111 |
112 |
113 |
114 |
115 | );
116 | };
--------------------------------------------------------------------------------
/src/pages/Leaderboard.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Trophy, Crown, Award, Medal } from 'lucide-react';
3 |
4 | interface LeaderboardEntry {
5 | address: string;
6 | username: string;
7 | earnings: number;
8 | gamesPlayed: number;
9 | winRate: number;
10 | }
11 |
12 | const mockLeaderboard: LeaderboardEntry[] = [
13 | {
14 | address: '0x1234...5678',
15 | username: 'GrandMaster1',
16 | earnings: 3.5,
17 | gamesPlayed: 145,
18 | winRate: 0.82,
19 | },
20 | {
21 | address: '0x8765...4321',
22 | username: 'CryptoKing',
23 | earnings: 2.8,
24 | gamesPlayed: 98,
25 | winRate: 0.75,
26 | },
27 | {
28 | address: '0x9876...1234',
29 | username: 'ChessWhiz',
30 | earnings: 2.1,
31 | gamesPlayed: 112,
32 | winRate: 0.71,
33 | },
34 | {
35 | address: '0x4567...8901',
36 | username: 'BlockchainKnight',
37 | earnings: 1.9,
38 | gamesPlayed: 87,
39 | winRate: 0.68,
40 | },
41 | {
42 | address: '0x3456...7890',
43 | username: 'Web3Bishop',
44 | earnings: 1.5,
45 | gamesPlayed: 76,
46 | winRate: 0.65,
47 | },
48 | ];
49 |
50 | export const Leaderboard: React.FC = () => {
51 | const getRankIcon = (index: number) => {
52 | switch (index) {
53 | case 0:
54 | return ;
55 | case 1:
56 | return ;
57 | case 2:
58 | return ;
59 | default:
60 | return {index + 1}
;
61 | }
62 | };
63 |
64 | return (
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
Masters of the Board
73 |
Top players by earnings and performance
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | Rank
84 |
85 |
86 | Player
87 |
88 |
89 | Earnings (ETH)
90 |
91 |
92 | Games
93 |
94 |
95 | Win Rate
96 |
97 |
98 |
99 |
100 | {mockLeaderboard.map((entry, index) => (
101 |
105 |
106 |
107 | {getRankIcon(index)}
108 |
109 |
110 |
111 | {entry.username}
112 | {entry.address}
113 |
114 |
115 |
116 | {entry.earnings.toFixed(2)} ETH
117 |
118 |
119 |
120 |
121 | {entry.gamesPlayed}
122 |
123 |
124 |
125 |
126 | {(entry.winRate * 100).toFixed(1)}%
127 |
128 |
129 |
130 | ))}
131 |
132 |
133 |
134 |
135 |
136 |
137 | );
138 | };
139 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute to the Online Chess Game Project
2 |
3 | Thank you for your interest in contributing to the Online Chess Game project! Below is a detailed guide on the current issues and how you can help improve the project.
4 |
5 | ---
6 |
7 | ## Project Overview
8 | This is an online chess platform built using React, Ethereum, and Web3.js. Players can connect their wallets, make payments in ETH, and start chess games. While the core functionality is in place, there are some bugs and areas for improvement.
9 |
10 | ---
11 |
12 | ## Current Issues
13 |
14 | ### 1. **Drag-and-Drop Chess Piece Movement (High Priority)**
15 | - **Description**: Currently, players must hold and drag a chess piece to its desired position. This behavior is unintuitive and disrupts gameplay.
16 | - **Improvement**: Implement a smoother drag-and-drop functionality or enable single-click selection and movement for a better user experience.
17 |
18 | ---
19 |
20 | ### 2. **Pawn Promotion Bug**
21 | - **Description**: When a pawn reaches the last rank for promotion, the game gets stuck, and no promotion options are shown.
22 | - **Improvement**:
23 | 1. Fix the logic to detect when a pawn reaches the promotion rank.
24 | 2. Display a modal or dropdown to select the desired piece (Queen, Rook, Bishop, Knight).
25 | 3. Ensure the game resumes seamlessly after promotion.
26 |
27 | ---
28 |
29 | ### 3. **Chess Game Loading Issue**
30 | - **Description**: After connecting the wallet and making a payment, the chess game occasionally fails to load, resulting in a white screen.
31 | - **Improvement**: Debug the chessboard component's state and props to ensure they initialize correctly. Verify dependencies and WebSocket connections.
32 |
33 | **Error Preview**:
34 | 
35 |
36 | ```error
37 | socketService.ts:21 WebSocket connection to 'ws://localhost:3001/socket.io/?address=0xbf786287609d1e4bfa96794893fc899ae957f484&username=Player&EIO=4&transport=websocket' failed: WebSocket is closed before the connection is established.
38 | setTimeoutconnect@socketService.ts:21handleCreateGame@OnlineMode.tsx:75
39 | socketService.ts:39 Socket connected successfully
40 | socketService.ts:47 Game created with ID: 3gik7tpb
41 | ```
42 |
43 | ---
44 |
45 | ### 4. **Alerts Instead of Popups**
46 | - **Location**: Multiple files, primarily `src/components/OnlineMode.jsx`
47 | - **Description**: The application currently uses `alert()` for notifications, which is disruptive and not user-friendly.
48 | - **Improvement**: Replace `alert()` with a modal-based popup component for better UX.
49 |
50 | ---
51 |
52 | ### 5. **Missing Loaders**
53 | - **Location**: `src/components/OnlineMode.jsx`
54 | - **Description**: There is no indication of ongoing processes such as connecting to the wallet, making a payment, or loading the game.
55 | - **Improvement**: Add loaders to show progress for the following actions:
56 | - Wallet connection
57 | - Payment processing
58 | - Chess game initialization
59 |
60 | ---
61 |
62 | ### 6. **Add Input Validation**
63 | - **Location**: `src/components/OnlineMode.jsx`
64 | - **Description**: The input fields (e.g., stake amount) do not have proper validation, leading to potential errors or misuse.
65 | - **Improvement**: Add validations to ensure:
66 | - Stake amounts are positive integers.
67 | - All required fields are filled before proceeding.
68 |
69 | ---
70 |
71 | ### 7. **Suggested Features**
72 | - **Enhance User Interface**: Improve the layout and aesthetics of the chess game and wallet integration screens.
73 | - **Add Sound Effects**: Provide sound feedback for actions like moves, payments, and connection success.
74 | - **Game History**: Display a log of moves made during the chess game.
75 | - **Dynamic Theme**: Allow users to switch between light and dark themes.
76 |
77 | ---
78 |
79 | ## How to Contribute
80 |
81 | ### Step 1: Fork and Clone the Repository
82 | ```bash
83 | # Clone the repository
84 | git clone https://github.com/your-repo/online-chess-game.git
85 | cd online-chess-game
86 | ```
87 |
88 | ### Step 2: Set Up the Development Environment
89 | Follow the instructions in the `README.md` file to set up your local environment.
90 |
91 | ### Step 3: Address Specific Issues
92 |
93 | #### For **Drag-and-Drop Movement**:
94 | - Review the chessboard component handling piece movement.
95 | - Use libraries like `react-dnd` for implementing robust drag-and-drop functionality.
96 |
97 | #### For **Pawn Promotion**:
98 | - Add logic to detect pawn promotion conditions.
99 | - Use a modal to display promotion options and update the game state accordingly.
100 |
101 | #### For **Alerts Instead of Popups**:
102 | - Replace existing `alert()` calls with a custom modal component using libraries like `react-modal` or `Material-UI`.
103 | - Ensure the modal design aligns with the app’s UI and offers dismissible options.
104 |
105 | ### Step 4: Test Your Changes
106 | 1. Run the application locally:
107 | ```bash
108 | npm start
109 | ```
110 | 2. Test various scenarios, such as moving pieces, pawn promotion, and responsive navigation.
111 | 3. Ensure no regressions are introduced.
112 |
113 | ### 4. Local Installation
114 | 
115 |
116 | ### 5. Local Run
117 | 
118 |
119 | ### Step 5: Submit a Pull Request
120 | 1. Push your changes to your forked repository.
121 | 2. Open a pull request with a clear description of your changes and reference the issue numbers you are addressing.
122 |
123 | ---
124 |
125 | ## Contact
126 | If you have any questions or need guidance, feel free to open an issue or reach out to the project maintainer.
127 |
128 | Happy Coding!
--------------------------------------------------------------------------------
/src/pages/FreeMode.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Chessboard } from '../components/Chessboard';
3 | import { GameStatus } from '../components/GameStatus';
4 | import { Chess } from 'chess.js';
5 | import { useGameStore } from '../store/useGameStore';
6 | import { Trophy } from 'lucide-react';
7 |
8 | // Toast component for error feedback (example implementation)
9 | const Toast = ({ message }: { message: string }) => (
10 |
11 | {message}
12 |
13 | );
14 |
15 | export const FreeMode: React.FC = () => {
16 | const [game] = useState(() => new Chess()); // Optimized initialization
17 | const [position, setPosition] = useState(game.fen());
18 | const [error, setError] = useState(null); // State for error feedback
19 | const [gameOver, setGameOver] = useState(false);
20 | const [winner, setWinner] = useState<'white' | 'black' | 'draw' | null>(null);
21 | const [showWinnerPopup, setShowWinnerPopup] = useState(false);
22 | const [timeLeft, setTimeLeft] = useState(20);
23 | const setCheckedKing = useGameStore((state) => state.setCheckedKing);
24 | let checkedKing = useGameStore((state) => state.checkedKing); // Retrieve checkedKing from store
25 |
26 | const handleMove = (move: { from: string; to: string; promotion?: string }) => {
27 | try {
28 | const moveResult = game.move(move);
29 | if (!moveResult) throw new Error('Invalid move');
30 | setPosition(game.fen());
31 | setError(null); // Clear error on successful move
32 |
33 | // Determine if the king is in check
34 | checkedKing = game.inCheck()
35 | ? game.turn() === 'w' ? 'white' : 'black'
36 | : null;
37 | setCheckedKing(checkedKing);
38 |
39 | // Check for game over conditions
40 | if (game.isGameOver()) {
41 | determineGameOutcome();
42 | }
43 | } catch (error) {
44 | console.error('Invalid move:', error);
45 | setError('Invalid move! Please try again.'); // User feedback
46 | }
47 | };
48 |
49 | const determineGameOutcome = () => {
50 | let gameWinner: 'white' | 'black' | 'draw' | null = null;
51 |
52 | if (game.isCheckmate()) {
53 | // If it's checkmate, the winner is the opposite of the current player
54 | gameWinner = game.turn() === 'w' ? 'black' : 'white';
55 | } else if (game.isDraw()) {
56 | // If it's a draw, set the winner to 'draw'
57 | gameWinner = 'draw';
58 | }
59 |
60 | // Update the state with the game outcome
61 | setGameOver(true);
62 | setWinner(gameWinner);
63 | setShowWinnerPopup(true);
64 | setTimeLeft(20);
65 | };
66 |
67 | useEffect(() => {
68 | let timer: NodeJS.Timeout;
69 |
70 | if (showWinnerPopup && timeLeft > 0) {
71 | timer = setInterval(() => {
72 | setTimeLeft(prev => prev - 1);
73 | }, 1000);
74 | } else if (timeLeft === 0) {
75 | setShowWinnerPopup(false);
76 | restartGame();
77 | }
78 |
79 | return () => {
80 | if (timer) {
81 | clearInterval(timer);
82 | }
83 | };
84 | }, [showWinnerPopup, timeLeft]);
85 |
86 | const restartGame = () => {
87 | const newGame = new Chess();
88 | setGame(newGame);
89 | setPosition(newGame.fen());
90 | setGameOver(false);
91 | setWinner(null);
92 | setCheckedKing(null);
93 | setError(null);
94 | };
95 |
96 | const winnerAnnouncement = showWinnerPopup && (
97 |
98 |
99 |
100 |
101 | {winner === 'draw'
102 | ? 'Game is a Draw!'
103 | : `${winner === 'white' ? 'White' : 'Black'} Wins!`}
104 |
105 |
Restarting in {timeLeft} seconds
106 | {/*
110 | OK
111 | */}
112 |
113 |
114 | );
115 |
116 | return (
117 |
118 | {/* Background Chessboard Pattern */}
119 |
{/* Accessibility improvement */}
120 |
121 | {Array.from({ length: 64 }).map((_, i) => ( // Optimized background grid
122 |
128 | ))}
129 |
130 |
131 |
132 |
133 |
134 |
135 |
Free Mode
136 |
137 | {winnerAnnouncement}
138 |
139 |
140 |
144 |
145 |
Game Info
146 |
147 | Practice mode - no stakes, no time limit. Perfect for learning and experimenting with different strategies.
148 |
149 |
150 |
151 |
152 |
153 |
154 | {/* Render error message if move is invalid */}
155 | {error &&
}
156 |
157 | );
158 | };
--------------------------------------------------------------------------------
/src/components/Navbar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Sword } from 'lucide-react';
3 | import { useNavigate } from 'react-router-dom';
4 | import { WalletConnect } from './WalletConnect';
5 |
6 | export const Navbar: React.FC = () => {
7 | const [isOpen, setIsOpen] = useState(false);
8 | const navigate = useNavigate();
9 | const toggleNavbar = () => {
10 | setIsOpen(!isOpen);
11 | };
12 |
13 | const handleNavigation = (path: string) => {
14 | navigate(path); // Navigate to the specified path
15 | };
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
handleNavigation('/')}
24 | className="flex items-center gap-2 group"
25 | >
26 |
27 |
28 | ♔
29 |
30 | Web3 Chess
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
handleNavigation('/play/free')}
48 | className="text-blue-200/70 hover:text-blue-400 px-3 py-2 text-sm font-medium transition-colors"
49 | >
50 | Practice Mode
51 |
52 |
handleNavigation('/play/bot')}
54 | className="text-blue-200/70 hover:text-blue-400 px-3 py-2 text-sm font-medium transition-colors"
55 | >
56 | Bot Challenge
57 |
58 |
handleNavigation('/play/online')}
60 | className="text-blue-200/70 hover:text-blue-400 px-3 py-2 text-sm font-medium transition-colors"
61 | >
62 | Tournament Mode
63 |
64 |
handleNavigation('/leaderboard')}
66 | className="text-blue-200/70 hover:text-blue-400 px-3 py-2 text-sm font-medium transition-colors"
67 | >
68 | Leaderboard
69 |
70 |
71 | console.log('Connect wallet')}
73 | className="bg-blue-500/20 hover:bg-blue-500/30 text-blue-400 hover:text-blue-300 px-4 py-2 rounded-lg border border-blue-500/30 hover:border-blue-400/50 transition-all duration-300"
74 | >
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | {/* Mobile Menu Overlay */}
83 | {isOpen && (
84 |
85 |
86 |
87 |
handleNavigation('/')}
89 | className="flex items-center gap-2"
90 | >
91 |
92 |
93 | ♔
94 |
95 | Web3 Chess
96 |
97 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | handleNavigation('/play/free')}
109 | className="text-blue-200/70 hover:text-blue-400 py-2 text-lg font-medium transition-colors"
110 | >
111 | Practice Mode
112 |
113 | handleNavigation('/play/bot')}
115 | className="text-blue-200/70 hover:text-blue-400 py-2 text-lg font-medium transition-colors"
116 | >
117 | AI Challenge
118 |
119 | handleNavigation('/play/online')}
121 | className="text-blue-200/70 hover:text-blue-400 py-2 text-lg font-medium transition-colors"
122 | >
123 | Tournament Mode
124 |
125 | handleNavigation('/leaderboard')}
127 | className="text-blue-200/70 hover:text-blue-400 py-2 text-lg font-medium transition-colors"
128 | >
129 | Leaderboard
130 |
131 | console.log('Connect wallet')}
133 | className="bg-blue-500/20 hover:bg-blue-500/30 text-blue-400 hover:text-blue-300 px-4 py-2 rounded-lg border border-blue-500/30 hover:border-blue-400/50 transition-all duration-300 mt-4"
134 | >
135 |
136 |
137 |
138 |
139 |
140 | )}
141 |
142 | );
143 | };
144 |
--------------------------------------------------------------------------------
/src/components/Chessboard.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef } from 'react';
2 | import { Chessboard as ReactChessboard } from 'react-chessboard';
3 | import { Chess } from 'chess.js';
4 |
5 | interface ChessboardProps {
6 | position?: string;
7 | onMove?: (move: { from: string; to: string; promotion?: string }) => void;
8 | orientation?: 'white' | 'black';
9 | disabled?: boolean;
10 | gameState: { checkedKing: 'white' | 'black' | null };
11 | }
12 |
13 | export function Chessboard({
14 | position = 'start',
15 | onMove,
16 | orientation = 'white',
17 | disabled = false,
18 | gameState,
19 | }: ChessboardProps) {
20 | const [chess] = useState(() => new Chess(position));
21 | const [selectedSquare, setSelectedSquare] = useState(null);
22 | const [promotionMove, setPromotionMove] = useState<{ from: string; to: string } | null>(null);
23 | const [isPromotionInProgress, setIsPromotionInProgress] = useState(false); // New flag
24 |
25 | const currentPositionRef = useRef(position);
26 | if (position !== currentPositionRef.current) {
27 | chess.load(position);
28 | currentPositionRef.current = position;
29 | }
30 |
31 | const getLegalMovesForSquare = (square: string) => {
32 | const moves = chess.moves({ square, verbose: true });
33 | return moves.map(move => move.to);
34 | };
35 |
36 | const onSquareClick = (square: string) => {
37 | if (disabled || isPromotionInProgress) return; // Check flag
38 |
39 | const piece = chess.get(square);
40 |
41 | if (piece && piece.color === chess.turn()) {
42 | setSelectedSquare(square);
43 | return;
44 | }
45 |
46 | if (selectedSquare) {
47 | const move = { from: selectedSquare, to: square };
48 |
49 | const promotionPiece = chess.get(selectedSquare);
50 | if (promotionPiece?.type === 'p' && (square[1] === '1' || square[1] === '8')) {
51 | setPromotionMove(move);
52 | setIsPromotionInProgress(true); // Set flag
53 | return;
54 | }
55 |
56 | try {
57 | const moveAttempt = chess.move({ ...move, promotion: 'q' });
58 |
59 | if (moveAttempt !== null && onMove) {
60 | onMove(move);
61 | }
62 | } catch {
63 | // Invalid move
64 | }
65 | setSelectedSquare(null);
66 | }
67 | };
68 |
69 | const onDrop = (sourceSquare: string, targetSquare: string) => {
70 | if (disabled || isPromotionInProgress) return false; // Check flag
71 |
72 | const move = { from: sourceSquare, to: targetSquare };
73 |
74 | const promotionPiece = chess.get(sourceSquare);
75 | if (promotionPiece?.type === 'p' && (targetSquare[1] === '1' || targetSquare[1] === '8')) {
76 | setPromotionMove(move);
77 | setIsPromotionInProgress(true); // Set flag
78 | return false;
79 | }
80 |
81 | try {
82 | const moveAttempt = chess.move({ ...move, promotion: 'q' });
83 |
84 | if (moveAttempt === null) return false;
85 |
86 | if (onMove) {
87 | onMove(move);
88 | }
89 |
90 | return true;
91 | } catch {
92 | return false;
93 | }
94 | };
95 |
96 | const handlePromotion = (promotion: 'q' | 'r' | 'b' | 'n') => {
97 | if (!promotionMove) return;
98 |
99 | try {
100 | const moveAttempt = chess.move({
101 | ...promotionMove,
102 | promotion,
103 | });
104 |
105 | if (moveAttempt !== null && onMove) {
106 | onMove({ ...promotionMove, promotion });
107 | }
108 | } catch {
109 | // Invalid move
110 | }
111 |
112 | setPromotionMove(null);
113 | setSelectedSquare(null);
114 | setIsPromotionInProgress(false); // Reset flag
115 | };
116 |
117 | const getCustomSquareStyles = () => {
118 | const styles: Record = {};
119 |
120 | if (selectedSquare) {
121 | styles[selectedSquare] = { backgroundColor: 'rgba(255, 255, 0, 0.4)' };
122 | const legalMoves = getLegalMovesForSquare(selectedSquare);
123 | legalMoves.forEach(square => {
124 | styles[square] = {
125 | backgroundColor: 'rgba(0, 255, 0, 0.2)',
126 | borderRadius: '50%',
127 | };
128 | });
129 | }
130 |
131 | if (gameState.checkedKing) {
132 | const kingSquare = chess.board().flat().find(
133 | piece =>
134 | piece &&
135 | piece.type === 'k' &&
136 | ((gameState.checkedKing === 'white' && piece.color === 'w') ||
137 | (gameState.checkedKing === 'black' && piece.color === 'b'))
138 | )?.square;
139 |
140 | if (kingSquare) {
141 | styles[kingSquare] = {
142 | backgroundColor: 'rgba(255, 0, 0, 0.4)',
143 | border: '2px solid red',
144 | };
145 | }
146 | }
147 |
148 | return styles;
149 | };
150 |
151 | return (
152 |
153 |
164 | {promotionMove && (
165 |
166 |
167 |
Promote Pawn
168 |
169 |
handlePromotion('q')}
171 | className="bg-gray-100 hover:bg-gray-200 p-4 rounded-lg transition duration-200"
172 | >
173 |
174 |
175 |
handlePromotion('r')}
177 | className="bg-gray-100 hover:bg-gray-200 p-4 rounded-lg transition duration-200"
178 | >
179 |
180 |
181 |
handlePromotion('b')}
183 | className="bg-gray-100 hover:bg-gray-200 p-4 rounded-lg transition duration-200"
184 | >
185 |
186 |
187 |
handlePromotion('n')}
189 | className="bg-gray-100 hover:bg-gray-200 p-4 rounded-lg transition duration-200"
190 | >
191 |
192 |
193 |
194 |
195 |
196 | )}
197 |
198 | );
199 | }
200 |
--------------------------------------------------------------------------------
/src/pages/Home.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ChevronRight } from 'lucide-react';
3 | import { useNavigate } from 'react-router-dom';
4 |
5 | export const Home: React.FC = () => {
6 | const navigate = useNavigate(); // React Router's navigate function
7 |
8 | const handleNavigation = (path: string) => {
9 | navigate(path); // Navigate to the specified path
10 | };
11 |
12 | return (
13 |
14 | {/* Animated chess board pattern */}
15 |
16 |
17 | {[...Array(64)].map((_, i) => (
18 |
24 | ))}
25 |
26 |
27 |
28 |
29 |
30 |
31 | ♔
32 | ♕
33 | ♗
34 | ♘
35 | ♖
36 |
37 |
38 | Crypto Chess Arena
39 |
40 |
41 | Where Grandmasters Meet the Blockchain
42 |
43 |
44 |
45 |
46 |
handleNavigation('/play/free')}
48 | className="group bg-gradient-to-br from-gray-900/90 to-indigo-900/90 p-8 rounded-xl border border-white/10 hover:border-blue-400/40 transition-all duration-300 w-full text-left relative overflow-hidden backdrop-blur-lg hover:scale-[1.02] hover:shadow-2xl hover:shadow-blue-500/20"
49 | >
50 |
51 |
52 | ♟
53 |
Practice Mode
54 |
55 |
56 | Master your openings and tactics in a risk-free environment.
57 |
58 |
59 |
60 |
61 |
handleNavigation('/play/bot')}
63 | className="group bg-gradient-to-br from-gray-900/90 to-indigo-900/90 p-8 rounded-xl border border-white/10 hover:border-blue-400/40 transition-all duration-300 w-full text-left relative overflow-hidden backdrop-blur-lg hover:scale-[1.02] hover:shadow-2xl hover:shadow-blue-500/20"
64 | >
65 |
66 |
67 | ♝
68 |
Bot Challenge
69 |
70 |
71 | Test your skills against our neural network chess engine.
72 |
73 |
74 |
75 |
76 |
handleNavigation('/play/online')}
78 | className="group bg-gradient-to-br from-gray-900/90 to-indigo-900/90 p-8 rounded-xl border border-white/10 hover:border-blue-400/40 transition-all duration-300 w-full text-left relative overflow-hidden backdrop-blur-lg hover:scale-[1.02] hover:shadow-2xl hover:shadow-blue-500/20"
79 | >
80 |
81 |
82 | ♚
83 |
Tournament Mode
84 |
85 |
86 | Compete in ETH-staked tournaments against global players.
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | ♕ Your Path to Mastery
95 |
96 |
97 |
98 |
99 |
100 | ♟
101 |
102 |
Connect Wallet
103 |
104 |
105 | Link your MetaMask to enter tournaments and earn rewards.
106 |
107 |
108 |
109 |
110 |
111 | ♞
112 |
113 |
Select Format
114 |
115 |
116 | Choose from Blitz, Rapid, or Classical time controls.
117 |
118 |
119 |
120 |
121 |
122 | ♔
123 |
124 |
Compete & Earn
125 |
126 |
127 | Win matches to climb the leaderboard and earn ETH rewards.
128 |
129 |
130 |
131 |
132 |
133 |
134 | );
135 | };
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 🎮 Welcome to Web3 Based Chess Game 🎮
2 | A decentralized platform where blockchain meets chess!🕹️
3 |
4 |
5 |
6 |
7 |
8 | 
9 | ---
10 |
11 | 🔧 Tech Stack 🔧
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 | ---
25 |
26 | 🚀 Features 🚀
27 |
28 | - **🏠 Home Screen**: Sleek interface for easy navigation between game modes.
29 | - **🤖 Bot Mode**: Challenge a computer bot with various difficulty levels.
30 | - **🌐 Online Mode**: Connect with players worldwide and stake ETH in games.
31 | - **🔔 Game Alerts**: Real-time notifications for in-game actions.
32 | - **🔐 Wallet Integration**: Connect and manage your Ethereum wallet effortlessly.
33 | - **✅ Secure Transactions**: Ensure transparency and security with smart contracts.
34 | - **👤 User Profiles**: Track your performance with personalized profiles.
35 |
36 | ---
37 |
38 | 👤 Contributors 👤
39 |
40 | 🌟 Core Functional Contributors 🌟
41 |
71 |
72 | 🛠️ Moderate Contributors 🛠️
73 |
111 |
112 | 🛠️ Documentation Contributors 🛠️
113 |
127 |
128 | ---
129 |
130 | 💡 How It Works 💡
131 |
132 | #### 🌐 Online Mode:
133 | 1. Connect your Ethereum wallet.
134 | 2. Set a stake amount (in ETH).
135 | 3. Create or join a game.
136 | 4. Play chess and win ETH!
137 |
138 | #### 🤖 Bot Mode:
139 | 1. Choose your difficulty level.
140 | 2. Play against the AI bot.
141 | 3. Improve your chess skills.
142 |
143 | ---
144 |
145 | 🎓 Installation & Setup 🎓
146 |
147 | 1. Clone the repository:
148 | ```bash
149 | git clone https://github.com/Navneet1206/Ether-Chess-OTC
150 | ```
151 | 2. Install dependencies in main folder:
152 | ```bash
153 | npm install
154 | ```
155 |
156 | 3. Start the Application :
157 | ```bash
158 | npm run dev
159 | ```
160 |
161 | 4. Install dependencies in server folder :
162 | ```bash
163 | npm install
164 | ```
165 | 5. Start the server :
166 | ```bash
167 | npm run dev
168 | ```
169 |
170 | 6. Deploy Smart Contracts:
171 | ```bash
172 | truffle migrate --network sepolia
173 | ```
174 | 7. Configure the environment variables in the `.env` file.
175 |
176 | ---
177 |
178 | 🔧 Testing 🔧
179 |
180 | 1. Run the application locally:
181 | ```bash
182 | npm run dev
183 | ```
184 |
185 | 2. Test features:
186 | - Wallet connection
187 | - Game creation and notifications
188 | - Chess gameplay
189 |
190 | 3. Run linting and tests:
191 | ```bash
192 | npm run lint
193 | npm test
194 | ```
195 |
196 | ---
197 |
198 | 🖼 Preview 🖼
199 |
200 |
201 |
202 | 🖥️Home Screen🖥️
203 | 🤖Bot Mode🤖
204 |
205 |
206 |
207 |
208 | Play Chess, Earn Crypto: Explore various modes
209 |
210 |
211 |
212 | Challenge our AI bot and improve your skills
213 |
214 |
215 |
216 |
217 |
218 | 🎯Game Created Alert🎯
219 | 🛠️Local Installation and Run🛠️
220 |
221 |
222 |
223 |
224 | Get alerted whenever the game is created
225 |
226 |
227 |
228 |
229 | This is how you can install and run the game
230 |
231 |
232 |
233 |
234 |
235 |
236 | ---
237 | ⚠️ Important Note: ⚠️
238 |
239 | **Off Anti-Tracking**
240 | For a seamless user experience, ensure that anti-tracking features are disabled in the browser settings, as this might cause issues with game state tracking and wallet interactions. You can disable these features in your browser preferences to avoid potential problems.
241 |
242 | ---
243 |
244 | 📂 Issues and Contributions 📂
245 | Check the 📜 CONTRIBUTING.md 📜 file for detailed information on known issues and how you can contribute.
246 |
247 | ---
248 |
249 | 📧 Contact 📧
250 | For queries or support, feel free to open an issue on GitHub or contact the project maintainer.
251 |
252 | ---
253 |
254 |
255 |
256 |
257 |
--------------------------------------------------------------------------------
/src/pages/OnlineMode.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { useWalletStore } from '../store/useWalletStore';
3 | import { socketService } from '../services/socketService';
4 | import { Chessboard } from '../components/Chessboard';
5 | import { ethers } from 'ethers';
6 | import { useGameStore } from '../store/useGameStore';
7 | import { AlertCircle, Check, Loader2, ArrowUp, ArrowDown } from 'lucide-react';
8 | import { Chess } from 'chess.js';
9 | import { Button } from '../components/Button'; // Import extracted components
10 | import { Input } from '../components/Input'; // Import extracted components
11 | import { Dialog } from '../components/Dialog'; // Import extracted components
12 |
13 | const MIN_STAKE = 0.0001;
14 | const MAX_STAKE = 0.1;
15 | const STAKE_INCREMENT = 0.0001;
16 |
17 | const chessGameABI = [
18 | "function createGame(string calldata gameId) external payable",
19 | "function joinGame(string calldata gameId) external payable",
20 | "function games(string calldata) external view returns (address white, address black, uint256 stake, bool isActive, address winner, uint256 startTime)"
21 | ];
22 |
23 | export const OnlineMode = () => {
24 | const { address, signer, provider } = useWalletStore();
25 | const { gameState, setGameState } = useGameStore();
26 | const [gameId, setGameId] = useState(null);
27 | const [stake, setStake] = useState(MIN_STAKE);
28 | const [error, setError] = useState(null);
29 | const [contractAddress] = useState('0xA12E9052EDbffCA633eBe3Fc9B3F477E516d4D43');
30 | const [isJoinGameDialogOpen, setIsJoinGameDialogOpen] = useState(false);
31 | const [joinGameId, setJoinGameId] = useState('');
32 | const [showSuccessToast, setShowSuccessToast] = useState(false);
33 | const [successMessage, setSuccessMessage] = useState('');
34 | const [isCreatingGame, setIsCreatingGame] = useState(false);
35 | const [isJoiningGame, setIsJoiningGame] = useState(false);
36 | const [isVerifyingGame, setIsVerifyingGame] = useState(false);
37 | const [game] = useState(new Chess());
38 |
39 | useEffect(() => {
40 | if (gameState?.gameId) {
41 | setGameId(gameState.gameId);
42 | }
43 | }, [gameState]);
44 |
45 | useEffect(() => {
46 | socketService.onGameState((state) => {
47 | setGameState(state);
48 | game.load(state.position);
49 | });
50 | return () => {
51 | socketService.disconnect();
52 | };
53 | }, [setGameState, game]);
54 |
55 | const handleStakeChange = (increment) => {
56 | setStake(prevStake => {
57 | const newStake = parseFloat((prevStake + increment).toFixed(4));
58 | return newStake >= MIN_STAKE && newStake <= MAX_STAKE ? newStake : prevStake;
59 | });
60 | };
61 |
62 | const handleStakeInput = (event) => {
63 | const value = event.target.value;
64 | if (value === '') {
65 | setStake(MIN_STAKE);
66 | return;
67 | }
68 |
69 | const numValue = parseFloat(value);
70 | if (!isNaN(numValue)) {
71 | const roundedValue = parseFloat(numValue.toFixed(4));
72 | if (roundedValue >= MIN_STAKE && roundedValue <= MAX_STAKE) {
73 | setStake(roundedValue);
74 | } else if (roundedValue < MIN_STAKE) {
75 | setStake(MIN_STAKE);
76 | } else if (roundedValue > MAX_STAKE) {
77 | setStake(MAX_STAKE);
78 | }
79 | }
80 | };
81 |
82 | const showToast = (message) => {
83 | setSuccessMessage(message);
84 | setShowSuccessToast(true);
85 | setTimeout(() => setShowSuccessToast(false), 5000);
86 | };
87 |
88 | const verifyGameExists = async (gameId) => {
89 | if (!provider) return false;
90 | setIsVerifyingGame(true);
91 | try {
92 | const contract = new ethers.Contract(contractAddress, chessGameABI, provider);
93 | const gameDetails = await contract.games(gameId);
94 | return gameDetails.white !== ethers.ZeroAddress;
95 | } catch (error) {
96 | console.error('Error verifying game:', error);
97 | return false;
98 | } finally {
99 | setIsVerifyingGame(false);
100 | }
101 | };
102 |
103 | const handleCreateGame = async () => {
104 | if (!address || !signer || !provider) {
105 | setError('Please connect your wallet first');
106 | return;
107 | }
108 |
109 | if (stake < MIN_STAKE || stake > MAX_STAKE) {
110 | setError(`Stake must be between ${MIN_STAKE} and ${MAX_STAKE} ETH`);
111 | return;
112 | }
113 |
114 | setIsCreatingGame(true);
115 | setError(null);
116 |
117 | try {
118 | const stakeInWei = ethers.parseEther(stake.toString());
119 | const contract = new ethers.Contract(contractAddress, chessGameABI, signer);
120 | const generatedGameId = Math.random().toString(36).substring(7);
121 |
122 | const tx = await contract.createGame(generatedGameId, { value: stakeInWei });
123 | showToast('Transaction submitted. Waiting for confirmation...');
124 | await tx.wait();
125 |
126 | const gameExists = await verifyGameExists(generatedGameId);
127 | if (!gameExists) {
128 | throw new Error('Game creation failed on blockchain');
129 | }
130 |
131 | await socketService.connect(address, 'Player');
132 | await socketService.createGame(stake);
133 |
134 | setGameId(generatedGameId);
135 | showToast(`Game created successfully! Game ID: ${generatedGameId}`);
136 | } catch (error) {
137 | console.error('Error creating game:', error);
138 | setError(error.reason || error.message || 'Failed to create game');
139 | } finally {
140 | setIsCreatingGame(false);
141 | }
142 | };
143 |
144 | const handleJoinGame = async () => {
145 | if (!address || !signer || !provider) {
146 | setError('Please connect your wallet first');
147 | return;
148 | }
149 |
150 | if (!joinGameId.trim()) {
151 | setError('Please enter a valid Game ID');
152 | return;
153 | }
154 |
155 | setIsJoiningGame(true);
156 | setError(null);
157 |
158 | try {
159 | const contract = new ethers.Contract(contractAddress, chessGameABI, provider);
160 | const gameDetails = await contract.games(joinGameId);
161 |
162 | if (gameDetails.white === ethers.ZeroAddress) {
163 | throw new Error('Game does not exist');
164 | }
165 |
166 | if (gameDetails.black !== ethers.ZeroAddress) {
167 | throw new Error('Game is already full');
168 | }
169 |
170 | const contractWithSigner = new ethers.Contract(contractAddress, chessGameABI, signer);
171 | const tx = await contractWithSigner.joinGame(joinGameId, { value: gameDetails.stake });
172 | showToast('Transaction submitted. Waiting for confirmation...');
173 | await tx.wait();
174 |
175 | await socketService.connect(address, 'Player');
176 | await socketService.joinGame(joinGameId);
177 |
178 | setGameId(joinGameId);
179 | setIsJoinGameDialogOpen(false);
180 | showToast('Successfully joined the game!');
181 | } catch (error) {
182 | console.error('Error joining game:', error);
183 | setError(error.reason || error.message || 'Failed to join game');
184 | } finally {
185 | setIsJoiningGame(false);
186 | }
187 | };
188 |
189 | const handleMove = (move) => {
190 | if (gameId) {
191 | socketService.makeMove(gameId, move);
192 | }
193 | };
194 |
195 | return (
196 |
197 |
198 |
Online Chess Game
199 |
200 | {error && (
201 |
202 |
203 |
{error}
204 |
205 | )}
206 |
207 | {showSuccessToast && (
208 |
209 |
210 | {successMessage}
211 |
212 | )}
213 |
214 | {!gameId ? (
215 |
216 |
217 |
Select Stake (ETH)
218 |
219 |
handleStakeChange(-STAKE_INCREMENT)} className="p-3 bg-gray-800 text-white rounded-lg hover:bg-gray-700 transition-colors disabled:opacity-50" disabled={stake <= MIN_STAKE}>
220 |
221 |
222 |
223 |
224 | ETH
225 |
226 |
handleStakeChange(STAKE_INCREMENT)} className="p-3 bg-gray-800 text-white rounded-lg hover:bg-gray-700 transition-colors disabled:opacity-50" disabled={stake >= MAX_STAKE}>
227 |
228 |
229 |
230 |
Min: {MIN_STAKE} ETH - Max: {MAX_STAKE} ETH
231 |
232 |
233 |
234 | MAX_STAKE} loading={isCreatingGame} className="flex-1 py-4 text-lg">
235 | {isCreatingGame ? 'Creating Game...' : 'Create Game'}
236 |
237 | setIsJoinGameDialogOpen(true)} disabled={!address} variant="secondary" className="flex-1 py-4 text-lg">
238 | Join Game
239 |
240 |
241 |
242 | ) : (
243 |
244 |
245 |
246 | Game ID: {gameId}
247 |
248 |
249 |
250 |
251 |
252 |
253 | )}
254 |
255 |
setIsJoinGameDialogOpen(false)} title="Join Game" description="Enter the Game ID to join an existing game">
256 |
257 |
setJoinGameId(e.target.value)} />
258 |
259 | setIsJoinGameDialogOpen(false)}>Cancel
260 |
261 | {isJoiningGame ? 'Joining...' : 'Join Game'}
262 |
263 |
264 |
265 |
266 |
267 |
268 | );
269 | };
270 |
271 | export default OnlineMode;
--------------------------------------------------------------------------------
/src/pages/BotMode.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback } from 'react';
2 | import { Chessboard as ReactChessboard } from 'react-chessboard';
3 | import { Chess } from 'chess.js';
4 | import { Bot, Trophy } from 'lucide-react';
5 |
6 | type Difficulty = 'EASY' | 'MEDIUM' | 'HARD';
7 |
8 | interface PieceValues {
9 | p: number;
10 | n: number;
11 | b: number;
12 | r: number;
13 | q: number;
14 | k: number;
15 | }
16 |
17 | const PIECE_VALUES: PieceValues = {
18 | p: 1,
19 | n: 3,
20 | b: 3,
21 | r: 5,
22 | q: 9,
23 | k: 0
24 | };
25 |
26 | export const BotMode: React.FC = () => {
27 | const [game, setGame] = useState(new Chess());
28 | const [position, setPosition] = useState(game.fen());
29 | const [difficulty, setDifficulty] = useState('MEDIUM');
30 | const [gameOver, setGameOver] = useState(false);
31 | const [winner, setWinner] = useState<'white' | 'black' | 'draw' | null>(null);
32 | const [thinking, setThinking] = useState(false);
33 | const [selectedSquare, setSelectedSquare] = useState(null);
34 | const [promotionSquare, setPromotionSquare] = useState(null);
35 | const [checkedKing, setCheckedKing] = useState<'white' | 'black' | null>(null);
36 | const [showWinnerPopup, setShowWinnerPopup] = useState(false);
37 | const [timeLeft, setTimeLeft] = useState(20);
38 |
39 | // Evaluate board position for bot
40 | const evaluatePosition = (chess: Chess): number => {
41 | let score = 0;
42 |
43 | chess.board().forEach(row => {
44 | row.forEach(piece => {
45 | if (piece) {
46 | const value = PIECE_VALUES[piece.type as keyof PieceValues];
47 | score += piece.color === 'w' ? value : -value;
48 | }
49 | });
50 | });
51 |
52 | const moves = chess.moves({ verbose: true });
53 | score += (moves.length * 0.1) * (chess.turn() === 'w' ? 1 : -1);
54 |
55 | const centerSquares = ['d4', 'd5', 'e4', 'e5'];
56 | centerSquares.forEach(square => {
57 | const piece = chess.get(square);
58 | if (piece) {
59 | score += piece.color === 'w' ? 0.5 : -0.5;
60 | }
61 | });
62 |
63 | return score;
64 | };
65 |
66 | const minimax = (
67 | chess: Chess,
68 | depth: number,
69 | alpha: number,
70 | beta: number,
71 | isMaximizing: boolean
72 | ): { score: number; move?: string } => {
73 | if (depth === 0 || chess.isGameOver()) {
74 | return { score: evaluatePosition(chess) };
75 | }
76 |
77 | const moves = chess.moves({ verbose: true });
78 | let bestMove: string | undefined;
79 |
80 | if (isMaximizing) {
81 | let maxScore = -Infinity;
82 | for (const move of moves) {
83 | chess.move(move);
84 | const evaluation = minimax(chess, depth - 1, alpha, beta, false).score;
85 | chess.undo();
86 |
87 | if (evaluation > maxScore) {
88 | maxScore = evaluation;
89 | bestMove = move.san;
90 | }
91 | alpha = Math.max(alpha, maxScore);
92 | if (beta <= alpha) break;
93 | }
94 | return { score: maxScore, move: bestMove };
95 | } else {
96 | let minScore = Infinity;
97 | for (const move of moves) {
98 | chess.move(move);
99 | const evaluation = minimax(chess, depth - 1, alpha, beta, true).score;
100 | chess.undo();
101 |
102 | if (evaluation < minScore) {
103 | minScore = evaluation;
104 | bestMove = move.san;
105 | }
106 | beta = Math.min(beta, minScore);
107 | if (beta <= alpha) break;
108 | }
109 | return { score: minScore, move: bestMove };
110 | }
111 | };
112 |
113 | const makeBotMove = useCallback(() => {
114 | if (game.isGameOver()) {
115 | determineGameOutcome();
116 | return;
117 | }
118 |
119 | setThinking(true);
120 | const gameCopy = new Chess(game.fen());
121 |
122 | // Check for immediate winning moves (checkmate)
123 | const moves = gameCopy.moves({ verbose: true });
124 | for (const move of moves) {
125 | gameCopy.move(move);
126 | if (gameCopy.isCheckmate()) {
127 | setGame(gameCopy);
128 | setPosition(gameCopy.fen());
129 | updateCheckedKing(gameCopy);
130 | setThinking(false);
131 | determineGameOutcome();
132 | return;
133 | }
134 | gameCopy.undo();
135 | }
136 |
137 | let moveToMake;
138 |
139 | switch (difficulty) {
140 | case 'EASY':
141 | // Random move, but avoid losing moves
142 | const safeMoves = moves.filter(move => {
143 | gameCopy.move(move);
144 | const isSafe = !gameCopy.isCheckmate() && !gameCopy.isDraw();
145 | gameCopy.undo();
146 | return isSafe;
147 | });
148 | moveToMake = safeMoves[Math.floor(Math.random() * safeMoves.length)];
149 | break;
150 |
151 | case 'MEDIUM':
152 | const { move } = minimax(gameCopy, 2, -Infinity, Infinity, false);
153 | moveToMake = move ? gameCopy.moves({ verbose: true }).find(m => m.san === move) : null;
154 | break;
155 |
156 | case 'HARD':
157 | const result = minimax(gameCopy, 3, -Infinity, Infinity, false);
158 | moveToMake = result.move ? gameCopy.moves({ verbose: true }).find(m => m.san === result.move) : null;
159 | break;
160 | }
161 |
162 | if (moveToMake) {
163 | gameCopy.move(moveToMake);
164 | setGame(gameCopy);
165 | setPosition(gameCopy.fen());
166 | updateCheckedKing(gameCopy);
167 | }
168 |
169 | setThinking(false);
170 | }, [game, difficulty]);
171 |
172 | const updateCheckedKing = (currentGame: Chess) => {
173 | if (currentGame.inCheck()) {
174 | setCheckedKing(currentGame.turn() === 'w' ? 'white' : 'black');
175 | } else {
176 | setCheckedKing(null);
177 | }
178 | };
179 |
180 | const determineGameOutcome = () => {
181 | let gameWinner: 'white' | 'black' | 'draw' | null = null;
182 |
183 | if (game.isCheckmate()) {
184 | gameWinner = game.turn() === 'w' ? 'black' : 'white';
185 | } else if (game.isDraw()) {
186 | gameWinner = 'draw';
187 | }
188 |
189 | setGameOver(true);
190 | setWinner(gameWinner);
191 | setShowWinnerPopup(true);
192 | setTimeLeft(20);
193 | };
194 |
195 | useEffect(() => {
196 | let timer: NodeJS.Timeout;
197 |
198 | if (showWinnerPopup && timeLeft > 0) {
199 | timer = setInterval(() => {
200 | setTimeLeft(prev => prev - 1);
201 | }, 1000);
202 | } else if (timeLeft === 0) {
203 | setShowWinnerPopup(false);
204 | restartGame();
205 | }
206 |
207 | return () => {
208 | if (timer) {
209 | clearInterval(timer);
210 | }
211 | };
212 | }, [showWinnerPopup, timeLeft]);
213 |
214 | const restartGame = () => {
215 | const newGame = new Chess();
216 | setGame(newGame);
217 | setPosition(newGame.fen());
218 | setGameOver(false);
219 | setWinner(null);
220 | setCheckedKing(null);
221 | setSelectedSquare(null);
222 | setPromotionSquare(null);
223 | setThinking(false);
224 | };
225 |
226 | const getLegalMovesForSquare = (square: string) => {
227 | return game.moves({ square, verbose: true }).map(move => move.to);
228 | };
229 |
230 | const handleSquareClick = (square: string) => {
231 | if (thinking || gameOver || game.turn() === 'b') return;
232 |
233 | const piece = game.get(square);
234 |
235 | if (promotionSquare) {
236 | const promotionMove = {
237 | from: selectedSquare!,
238 | to: promotionSquare,
239 | promotion: square[0] as 'q' | 'r' | 'b' | 'n'
240 | };
241 |
242 | try {
243 | game.move(promotionMove);
244 | setPosition(game.fen());
245 | setSelectedSquare(null);
246 | setPromotionSquare(null);
247 | updateCheckedKing(game);
248 | setTimeout(makeBotMove, 500);
249 | } catch (error) {
250 | console.error('Invalid promotion move:', error);
251 | }
252 | return;
253 | }
254 |
255 | if (piece && piece.color === game.turn()) {
256 | setSelectedSquare(square);
257 | return;
258 | }
259 |
260 | if (selectedSquare) {
261 | const moveAttempt = {
262 | from: selectedSquare,
263 | to: square,
264 | };
265 |
266 | const piece = game.get(selectedSquare);
267 | if (
268 | piece &&
269 | piece.type === 'p' &&
270 | ((piece.color === 'w' && square[1] === '8') ||
271 | (piece.color === 'b' && square[1] === '1'))
272 | ) {
273 | setPromotionSquare(square);
274 | return;
275 | }
276 |
277 | try {
278 | game.move(moveAttempt);
279 | setPosition(game.fen());
280 | setSelectedSquare(null);
281 | updateCheckedKing(game);
282 | setTimeout(makeBotMove, 500);
283 | } catch (error) {
284 | console.error('Invalid move:', error);
285 | }
286 | }
287 | };
288 |
289 | const customSquareStyles = () => {
290 | const styles: Record = {};
291 |
292 | if (selectedSquare) {
293 | styles[selectedSquare] = {
294 | backgroundColor: 'rgba(255, 255, 0, 0.4)',
295 | };
296 |
297 | const legalMoves = getLegalMovesForSquare(selectedSquare);
298 | legalMoves.forEach(square => {
299 | styles[square] = {
300 | backgroundColor: 'rgba(0, 255, 0, 0.2)',
301 | borderRadius: '50%',
302 | };
303 | });
304 | }
305 |
306 | if (checkedKing) {
307 | const kingSquare = game.board().flat().find(
308 | piece => piece && piece.type === 'k' &&
309 | ((checkedKing === 'white' && piece.color === 'w') ||
310 | (checkedKing === 'black' && piece.color === 'b'))
311 | )?.square;
312 |
313 | if (kingSquare) {
314 | styles[kingSquare] = {
315 | backgroundColor: 'rgba(255, 0, 0, 0.4)',
316 | border: '2px solid red',
317 | };
318 | }
319 | }
320 |
321 | return styles;
322 | };
323 |
324 | const promotionPieces = promotionSquare && (
325 |
327 | {['q', 'r', 'b', 'n'].map((piece) => (
328 | handleSquareClick(piece)}
332 | >
333 | {piece.toUpperCase()}
334 |
335 | ))}
336 |
337 | );
338 |
339 | const winnerAnnouncement = showWinnerPopup && (
340 |
341 |
342 |
343 |
344 | {winner === 'draw'
345 | ? 'Game is a Draw!'
346 | : `${winner === 'white' ? 'White' : 'Black'} Wins!`}
347 |
348 |
Restarting in {timeLeft} seconds
349 | {/*
353 | OK
354 | */}
355 |
356 |
357 | );
358 |
359 | return (
360 |
361 |
362 |
363 |
364 |
365 | Bot Mode
366 |
367 |
368 |
369 |
375 | {promotionPieces}
376 | {winnerAnnouncement}
377 |
378 |
379 |
380 |
381 |
382 |
Game Status
383 |
384 |
Current Turn: {game.turn() === 'w' ? 'White' : 'Black'}
385 |
Status: {gameOver ? 'Game Over' : 'Active'}
386 |
387 |
388 |
389 |
390 |
Bot Settings
391 | setDifficulty(e.target.value as Difficulty)}
394 | className="mt-1 block w-full rounded-md bg-gray-800 text-white shadow-sm p-2"
395 | disabled={gameOver}
396 | >
397 | Easy
398 | Medium
399 | Hard
400 |
401 |
402 |
403 |
404 |
405 |
406 | );
407 | };
--------------------------------------------------------------------------------
/src/config/ChessGame.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "ChessGame",
4 | "sourceName": "contracts/ChessGame.sol",
5 | "abi": [
6 | {
7 | "inputs": [],
8 | "stateMutability": "nonpayable",
9 | "type": "constructor"
10 | },
11 | {
12 | "anonymous": false,
13 | "inputs": [
14 | {
15 | "indexed": false,
16 | "internalType": "string",
17 | "name": "gameId",
18 | "type": "string"
19 | },
20 | {
21 | "indexed": false,
22 | "internalType": "address",
23 | "name": "white",
24 | "type": "address"
25 | },
26 | {
27 | "indexed": false,
28 | "internalType": "uint256",
29 | "name": "stake",
30 | "type": "uint256"
31 | }
32 | ],
33 | "name": "GameCreated",
34 | "type": "event"
35 | },
36 | {
37 | "anonymous": false,
38 | "inputs": [
39 | {
40 | "indexed": false,
41 | "internalType": "string",
42 | "name": "gameId",
43 | "type": "string"
44 | },
45 | {
46 | "indexed": false,
47 | "internalType": "address",
48 | "name": "winner",
49 | "type": "address"
50 | },
51 | {
52 | "indexed": false,
53 | "internalType": "uint256",
54 | "name": "prize",
55 | "type": "uint256"
56 | }
57 | ],
58 | "name": "GameEnded",
59 | "type": "event"
60 | },
61 | {
62 | "anonymous": false,
63 | "inputs": [
64 | {
65 | "indexed": false,
66 | "internalType": "string",
67 | "name": "gameId",
68 | "type": "string"
69 | },
70 | {
71 | "indexed": false,
72 | "internalType": "address",
73 | "name": "black",
74 | "type": "address"
75 | }
76 | ],
77 | "name": "GameJoined",
78 | "type": "event"
79 | },
80 | {
81 | "anonymous": false,
82 | "inputs": [
83 | {
84 | "indexed": true,
85 | "internalType": "address",
86 | "name": "previousOwner",
87 | "type": "address"
88 | },
89 | {
90 | "indexed": true,
91 | "internalType": "address",
92 | "name": "newOwner",
93 | "type": "address"
94 | }
95 | ],
96 | "name": "OwnershipTransferred",
97 | "type": "event"
98 | },
99 | {
100 | "inputs": [
101 | {
102 | "internalType": "string",
103 | "name": "gameId",
104 | "type": "string"
105 | }
106 | ],
107 | "name": "createGame",
108 | "outputs": [],
109 | "stateMutability": "payable",
110 | "type": "function"
111 | },
112 | {
113 | "inputs": [
114 | {
115 | "internalType": "string",
116 | "name": "gameId",
117 | "type": "string"
118 | },
119 | {
120 | "internalType": "address",
121 | "name": "winner",
122 | "type": "address"
123 | }
124 | ],
125 | "name": "endGame",
126 | "outputs": [],
127 | "stateMutability": "nonpayable",
128 | "type": "function"
129 | },
130 | {
131 | "inputs": [
132 | {
133 | "internalType": "string",
134 | "name": "",
135 | "type": "string"
136 | }
137 | ],
138 | "name": "games",
139 | "outputs": [
140 | {
141 | "internalType": "address",
142 | "name": "white",
143 | "type": "address"
144 | },
145 | {
146 | "internalType": "address",
147 | "name": "black",
148 | "type": "address"
149 | },
150 | {
151 | "internalType": "uint256",
152 | "name": "stake",
153 | "type": "uint256"
154 | },
155 | {
156 | "internalType": "bool",
157 | "name": "isActive",
158 | "type": "bool"
159 | },
160 | {
161 | "internalType": "address",
162 | "name": "winner",
163 | "type": "address"
164 | },
165 | {
166 | "internalType": "uint256",
167 | "name": "startTime",
168 | "type": "uint256"
169 | }
170 | ],
171 | "stateMutability": "view",
172 | "type": "function"
173 | },
174 | {
175 | "inputs": [
176 | {
177 | "internalType": "string",
178 | "name": "gameId",
179 | "type": "string"
180 | }
181 | ],
182 | "name": "joinGame",
183 | "outputs": [],
184 | "stateMutability": "payable",
185 | "type": "function"
186 | },
187 | {
188 | "inputs": [],
189 | "name": "owner",
190 | "outputs": [
191 | {
192 | "internalType": "address",
193 | "name": "",
194 | "type": "address"
195 | }
196 | ],
197 | "stateMutability": "view",
198 | "type": "function"
199 | },
200 | {
201 | "inputs": [],
202 | "name": "ownerFeePercentage",
203 | "outputs": [
204 | {
205 | "internalType": "uint256",
206 | "name": "",
207 | "type": "uint256"
208 | }
209 | ],
210 | "stateMutability": "view",
211 | "type": "function"
212 | },
213 | {
214 | "inputs": [
215 | {
216 | "internalType": "address",
217 | "name": "",
218 | "type": "address"
219 | }
220 | ],
221 | "name": "playerEarnings",
222 | "outputs": [
223 | {
224 | "internalType": "uint256",
225 | "name": "",
226 | "type": "uint256"
227 | }
228 | ],
229 | "stateMutability": "view",
230 | "type": "function"
231 | },
232 | {
233 | "inputs": [],
234 | "name": "renounceOwnership",
235 | "outputs": [],
236 | "stateMutability": "nonpayable",
237 | "type": "function"
238 | },
239 | {
240 | "inputs": [
241 | {
242 | "internalType": "address",
243 | "name": "newOwner",
244 | "type": "address"
245 | }
246 | ],
247 | "name": "transferOwnership",
248 | "outputs": [],
249 | "stateMutability": "nonpayable",
250 | "type": "function"
251 | },
252 | {
253 | "inputs": [],
254 | "name": "withdrawEarnings",
255 | "outputs": [],
256 | "stateMutability": "nonpayable",
257 | "type": "function"
258 | },
259 | {
260 | "inputs": [],
261 | "name": "withdrawOwnerFees",
262 | "outputs": [],
263 | "stateMutability": "nonpayable",
264 | "type": "function"
265 | }
266 | ],
267 | "bytecode": "0x6080604052600560045534801561001557600080fd5b5061003261002761003e60201b60201c565b61004660201b60201c565b6001808190555061010a565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b611bcd806101196000396000f3fe60806040526004361061009c5760003560e01c80636d20931a116100645780636d20931a14610158578063715018a61461019a5780637753af3e146101b15780638da5cb5b146101da578063b73c6ce914610205578063f2fde38b1461021c5761009c565b80630a9ef34c146100a15780631cb398c2146100b85780632ebc0504146100e35780633d536a2e146100ff57806369f927731461011b575b600080fd5b3480156100ad57600080fd5b506100b6610245565b005b3480156100c457600080fd5b506100cd61035a565b6040516100da9190611033565b60405180910390f35b6100fd60048036038101906100f891906110c7565b610360565b005b610119600480360381019061011491906110c7565b610636565b005b34801561012757600080fd5b50610142600480360381019061013d9190611172565b610849565b60405161014f9190611033565b60405180910390f35b34801561016457600080fd5b5061017f600480360381019061017a91906112e0565b610861565b60405161019196959493929190611353565b60405180910390f35b3480156101a657600080fd5b506101af610920565b005b3480156101bd57600080fd5b506101d860048036038101906101d391906113b4565b6109a8565b005b3480156101e657600080fd5b506101ef610cc4565b6040516101fc9190611414565b60405180910390f35b34801561021157600080fd5b5061021a610ced565b005b34801561022857600080fd5b50610243600480360381019061023e9190611172565b610e57565b005b61024d610f4e565b73ffffffffffffffffffffffffffffffffffffffff1661026b610cc4565b73ffffffffffffffffffffffffffffffffffffffff16146102c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b89061148c565b60405180910390fd5b600047905060008111610309576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610300906114f8565b60405180910390fd5b610311610cc4565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610356573d6000803e3d6000fd5b5050565b60045481565b600034116103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161039a90611564565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600283836040516103cd9291906115b4565b908152602001604051809103902060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044c90611619565b60405180910390fd5b6040518060c001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001348152602001600115158152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200142815250600283836040516104db9291906115b4565b908152602001604051809103902060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040820151816002015560608201518160030160006101000a81548160ff02191690831515021790555060808201518160030160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a082015181600401559050507f132c99221e3a8bd54ab4759163b62794bddb60ad4f2dc5f1e3604a5fe03bae578282333460405161062a9493929190611666565b60405180910390a15050565b60006002838360405161064a9291906115b4565b90815260200160405180910390209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036106ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e4906116f2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610780576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107779061175e565b60405180910390fd5b806002015434146107c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107bd906117ca565b60405180910390fd5b338160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f69b91453edfa045ed34feb2b032d08b6c3333ec2404f18b285c7ce7ffe69ba5183833360405161083c939291906117ea565b60405180910390a1505050565b60036020528060005260406000206000915090505481565b6002818051602081018201805184825260208301602085012081835280955050505050506000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030160009054906101000a900460ff16908060030160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060040154905086565b610928610f4e565b73ffffffffffffffffffffffffffffffffffffffff16610946610cc4565b73ffffffffffffffffffffffffffffffffffffffff161461099c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109939061148c565b60405180910390fd5b6109a66000610f56565b565b6109b0610f4e565b73ffffffffffffffffffffffffffffffffffffffff166109ce610cc4565b73ffffffffffffffffffffffffffffffffffffffff1614610a24576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1b9061148c565b60405180910390fd5b600060028484604051610a389291906115b4565b908152602001604051809103902090508060030160009054906101000a900460ff16610a99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9090611868565b60405180910390fd5b8060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610b4657508060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b610b85576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c906118d4565b60405180910390fd5b60008160030160006101000a81548160ff021916908315150217905550818160030160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060028260020154610bf89190611923565b90506000606460045483610c0c9190611923565b610c169190611994565b905060008183610c2691906119c5565b905080600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610c7791906119f9565b925050819055507ffe19dffae58b26bebdf0f9362f64c6e305eda567dd06dec08adc7457f65c00ea87878784604051610cb39493929190611666565b60405180910390a150505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600260015403610d32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2990611a79565b60405180910390fd5b60026001819055506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008111610dc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db890611ae5565b60405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610e4c573d6000803e3d6000fd5b505060018081905550565b610e5f610f4e565b73ffffffffffffffffffffffffffffffffffffffff16610e7d610cc4565b73ffffffffffffffffffffffffffffffffffffffff1614610ed3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eca9061148c565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610f42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f3990611b77565b60405180910390fd5b610f4b81610f56565b50565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000819050919050565b61102d8161101a565b82525050565b60006020820190506110486000830184611024565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261108757611086611062565b5b8235905067ffffffffffffffff8111156110a4576110a3611067565b5b6020830191508360018202830111156110c0576110bf61106c565b5b9250929050565b600080602083850312156110de576110dd611058565b5b600083013567ffffffffffffffff8111156110fc576110fb61105d565b5b61110885828601611071565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061113f82611114565b9050919050565b61114f81611134565b811461115a57600080fd5b50565b60008135905061116c81611146565b92915050565b60006020828403121561118857611187611058565b5b60006111968482850161115d565b91505092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6111ed826111a4565b810181811067ffffffffffffffff8211171561120c5761120b6111b5565b5b80604052505050565b600061121f61104e565b905061122b82826111e4565b919050565b600067ffffffffffffffff82111561124b5761124a6111b5565b5b611254826111a4565b9050602081019050919050565b82818337600083830152505050565b600061128361127e84611230565b611215565b90508281526020810184848401111561129f5761129e61119f565b5b6112aa848285611261565b509392505050565b600082601f8301126112c7576112c6611062565b5b81356112d7848260208601611270565b91505092915050565b6000602082840312156112f6576112f5611058565b5b600082013567ffffffffffffffff8111156113145761131361105d565b5b611320848285016112b2565b91505092915050565b61133281611134565b82525050565b60008115159050919050565b61134d81611338565b82525050565b600060c0820190506113686000830189611329565b6113756020830188611329565b6113826040830187611024565b61138f6060830186611344565b61139c6080830185611329565b6113a960a0830184611024565b979650505050505050565b6000806000604084860312156113cd576113cc611058565b5b600084013567ffffffffffffffff8111156113eb576113ea61105d565b5b6113f786828701611071565b9350935050602061140a8682870161115d565b9150509250925092565b60006020820190506114296000830184611329565b92915050565b600082825260208201905092915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b600061147660208361142f565b915061148182611440565b602082019050919050565b600060208201905081810360008301526114a581611469565b9050919050565b7f4e6f206665657320746f20776974686472617700000000000000000000000000600082015250565b60006114e260138361142f565b91506114ed826114ac565b602082019050919050565b60006020820190508181036000830152611511816114d5565b9050919050565b7f5374616b65206d7573742062652067726561746572207468616e203000000000600082015250565b600061154e601c8361142f565b915061155982611518565b602082019050919050565b6000602082019050818103600083015261157d81611541565b9050919050565b600081905092915050565b600061159b8385611584565b93506115a8838584611261565b82840190509392505050565b60006115c182848661158f565b91508190509392505050565b7f47616d6520616c72656164792065786973747300000000000000000000000000600082015250565b600061160360138361142f565b915061160e826115cd565b602082019050919050565b60006020820190508181036000830152611632816115f6565b9050919050565b6000611645838561142f565b9350611652838584611261565b61165b836111a4565b840190509392505050565b60006060820190508181036000830152611681818688611639565b90506116906020830185611329565b61169d6040830184611024565b95945050505050565b7f47616d6520646f6573206e6f7420657869737400000000000000000000000000600082015250565b60006116dc60138361142f565b91506116e7826116a6565b602082019050919050565b6000602082019050818103600083015261170b816116cf565b9050919050565b7f47616d6520616c72656164792066756c6c000000000000000000000000000000600082015250565b600061174860118361142f565b915061175382611712565b602082019050919050565b600060208201905081810360008301526117778161173b565b9050919050565b7f496e636f7272656374207374616b6520616d6f756e7400000000000000000000600082015250565b60006117b460168361142f565b91506117bf8261177e565b602082019050919050565b600060208201905081810360008301526117e3816117a7565b9050919050565b60006040820190508181036000830152611805818587611639565b90506118146020830184611329565b949350505050565b7f47616d65206e6f74206163746976650000000000000000000000000000000000600082015250565b6000611852600f8361142f565b915061185d8261181c565b602082019050919050565b6000602082019050818103600083015261188181611845565b9050919050565b7f496e76616c69642077696e6e6572000000000000000000000000000000000000600082015250565b60006118be600e8361142f565b91506118c982611888565b602082019050919050565b600060208201905081810360008301526118ed816118b1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061192e8261101a565b91506119398361101a565b92508282026119478161101a565b9150828204841483151761195e5761195d6118f4565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061199f8261101a565b91506119aa8361101a565b9250826119ba576119b9611965565b5b828204905092915050565b60006119d08261101a565b91506119db8361101a565b92508282039050818111156119f3576119f26118f4565b5b92915050565b6000611a048261101a565b9150611a0f8361101a565b9250828201905080821115611a2757611a266118f4565b5b92915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000611a63601f8361142f565b9150611a6e82611a2d565b602082019050919050565b60006020820190508181036000830152611a9281611a56565b9050919050565b7f4e6f206561726e696e677320746f207769746864726177000000000000000000600082015250565b6000611acf60178361142f565b9150611ada82611a99565b602082019050919050565b60006020820190508181036000830152611afe81611ac2565b9050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000611b6160268361142f565b9150611b6c82611b05565b604082019050919050565b60006020820190508181036000830152611b9081611b54565b905091905056fea2646970667358221220da42bab4deed86f9aaf14bc08f2ee2a16e3019b4ad3f3b9c6b2ef44700c024c064736f6c63430008140033",
268 | "deployedBytecode": "0x60806040526004361061009c5760003560e01c80636d20931a116100645780636d20931a14610158578063715018a61461019a5780637753af3e146101b15780638da5cb5b146101da578063b73c6ce914610205578063f2fde38b1461021c5761009c565b80630a9ef34c146100a15780631cb398c2146100b85780632ebc0504146100e35780633d536a2e146100ff57806369f927731461011b575b600080fd5b3480156100ad57600080fd5b506100b6610245565b005b3480156100c457600080fd5b506100cd61035a565b6040516100da9190611033565b60405180910390f35b6100fd60048036038101906100f891906110c7565b610360565b005b610119600480360381019061011491906110c7565b610636565b005b34801561012757600080fd5b50610142600480360381019061013d9190611172565b610849565b60405161014f9190611033565b60405180910390f35b34801561016457600080fd5b5061017f600480360381019061017a91906112e0565b610861565b60405161019196959493929190611353565b60405180910390f35b3480156101a657600080fd5b506101af610920565b005b3480156101bd57600080fd5b506101d860048036038101906101d391906113b4565b6109a8565b005b3480156101e657600080fd5b506101ef610cc4565b6040516101fc9190611414565b60405180910390f35b34801561021157600080fd5b5061021a610ced565b005b34801561022857600080fd5b50610243600480360381019061023e9190611172565b610e57565b005b61024d610f4e565b73ffffffffffffffffffffffffffffffffffffffff1661026b610cc4565b73ffffffffffffffffffffffffffffffffffffffff16146102c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102b89061148c565b60405180910390fd5b600047905060008111610309576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610300906114f8565b60405180910390fd5b610311610cc4565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610356573d6000803e3d6000fd5b5050565b60045481565b600034116103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161039a90611564565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600283836040516103cd9291906115b4565b908152602001604051809103902060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044c90611619565b60405180910390fd5b6040518060c001604052803373ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001348152602001600115158152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200142815250600283836040516104db9291906115b4565b908152602001604051809103902060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040820151816002015560608201518160030160006101000a81548160ff02191690831515021790555060808201518160030160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a082015181600401559050507f132c99221e3a8bd54ab4759163b62794bddb60ad4f2dc5f1e3604a5fe03bae578282333460405161062a9493929190611666565b60405180910390a15050565b60006002838360405161064a9291906115b4565b90815260200160405180910390209050600073ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036106ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e4906116f2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610780576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107779061175e565b60405180910390fd5b806002015434146107c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107bd906117ca565b60405180910390fd5b338160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f69b91453edfa045ed34feb2b032d08b6c3333ec2404f18b285c7ce7ffe69ba5183833360405161083c939291906117ea565b60405180910390a1505050565b60036020528060005260406000206000915090505481565b6002818051602081018201805184825260208301602085012081835280955050505050506000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060020154908060030160009054906101000a900460ff16908060030160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060040154905086565b610928610f4e565b73ffffffffffffffffffffffffffffffffffffffff16610946610cc4565b73ffffffffffffffffffffffffffffffffffffffff161461099c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109939061148c565b60405180910390fd5b6109a66000610f56565b565b6109b0610f4e565b73ffffffffffffffffffffffffffffffffffffffff166109ce610cc4565b73ffffffffffffffffffffffffffffffffffffffff1614610a24576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1b9061148c565b60405180910390fd5b600060028484604051610a389291906115b4565b908152602001604051809103902090508060030160009054906101000a900460ff16610a99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9090611868565b60405180910390fd5b8060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480610b4657508060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b610b85576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7c906118d4565b60405180910390fd5b60008160030160006101000a81548160ff021916908315150217905550818160030160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600060028260020154610bf89190611923565b90506000606460045483610c0c9190611923565b610c169190611994565b905060008183610c2691906119c5565b905080600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610c7791906119f9565b925050819055507ffe19dffae58b26bebdf0f9362f64c6e305eda567dd06dec08adc7457f65c00ea87878784604051610cb39493929190611666565b60405180910390a150505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600260015403610d32576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d2990611a79565b60405180910390fd5b60026001819055506000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905060008111610dc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db890611ae5565b60405180910390fd5b6000600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610e4c573d6000803e3d6000fd5b505060018081905550565b610e5f610f4e565b73ffffffffffffffffffffffffffffffffffffffff16610e7d610cc4565b73ffffffffffffffffffffffffffffffffffffffff1614610ed3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eca9061148c565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610f42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f3990611b77565b60405180910390fd5b610f4b81610f56565b50565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000819050919050565b61102d8161101a565b82525050565b60006020820190506110486000830184611024565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f84011261108757611086611062565b5b8235905067ffffffffffffffff8111156110a4576110a3611067565b5b6020830191508360018202830111156110c0576110bf61106c565b5b9250929050565b600080602083850312156110de576110dd611058565b5b600083013567ffffffffffffffff8111156110fc576110fb61105d565b5b61110885828601611071565b92509250509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061113f82611114565b9050919050565b61114f81611134565b811461115a57600080fd5b50565b60008135905061116c81611146565b92915050565b60006020828403121561118857611187611058565b5b60006111968482850161115d565b91505092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6111ed826111a4565b810181811067ffffffffffffffff8211171561120c5761120b6111b5565b5b80604052505050565b600061121f61104e565b905061122b82826111e4565b919050565b600067ffffffffffffffff82111561124b5761124a6111b5565b5b611254826111a4565b9050602081019050919050565b82818337600083830152505050565b600061128361127e84611230565b611215565b90508281526020810184848401111561129f5761129e61119f565b5b6112aa848285611261565b509392505050565b600082601f8301126112c7576112c6611062565b5b81356112d7848260208601611270565b91505092915050565b6000602082840312156112f6576112f5611058565b5b600082013567ffffffffffffffff8111156113145761131361105d565b5b611320848285016112b2565b91505092915050565b61133281611134565b82525050565b60008115159050919050565b61134d81611338565b82525050565b600060c0820190506113686000830189611329565b6113756020830188611329565b6113826040830187611024565b61138f6060830186611344565b61139c6080830185611329565b6113a960a0830184611024565b979650505050505050565b6000806000604084860312156113cd576113cc611058565b5b600084013567ffffffffffffffff8111156113eb576113ea61105d565b5b6113f786828701611071565b9350935050602061140a8682870161115d565b9150509250925092565b60006020820190506114296000830184611329565b92915050565b600082825260208201905092915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b600061147660208361142f565b915061148182611440565b602082019050919050565b600060208201905081810360008301526114a581611469565b9050919050565b7f4e6f206665657320746f20776974686472617700000000000000000000000000600082015250565b60006114e260138361142f565b91506114ed826114ac565b602082019050919050565b60006020820190508181036000830152611511816114d5565b9050919050565b7f5374616b65206d7573742062652067726561746572207468616e203000000000600082015250565b600061154e601c8361142f565b915061155982611518565b602082019050919050565b6000602082019050818103600083015261157d81611541565b9050919050565b600081905092915050565b600061159b8385611584565b93506115a8838584611261565b82840190509392505050565b60006115c182848661158f565b91508190509392505050565b7f47616d6520616c72656164792065786973747300000000000000000000000000600082015250565b600061160360138361142f565b915061160e826115cd565b602082019050919050565b60006020820190508181036000830152611632816115f6565b9050919050565b6000611645838561142f565b9350611652838584611261565b61165b836111a4565b840190509392505050565b60006060820190508181036000830152611681818688611639565b90506116906020830185611329565b61169d6040830184611024565b95945050505050565b7f47616d6520646f6573206e6f7420657869737400000000000000000000000000600082015250565b60006116dc60138361142f565b91506116e7826116a6565b602082019050919050565b6000602082019050818103600083015261170b816116cf565b9050919050565b7f47616d6520616c72656164792066756c6c000000000000000000000000000000600082015250565b600061174860118361142f565b915061175382611712565b602082019050919050565b600060208201905081810360008301526117778161173b565b9050919050565b7f496e636f7272656374207374616b6520616d6f756e7400000000000000000000600082015250565b60006117b460168361142f565b91506117bf8261177e565b602082019050919050565b600060208201905081810360008301526117e3816117a7565b9050919050565b60006040820190508181036000830152611805818587611639565b90506118146020830184611329565b949350505050565b7f47616d65206e6f74206163746976650000000000000000000000000000000000600082015250565b6000611852600f8361142f565b915061185d8261181c565b602082019050919050565b6000602082019050818103600083015261188181611845565b9050919050565b7f496e76616c69642077696e6e6572000000000000000000000000000000000000600082015250565b60006118be600e8361142f565b91506118c982611888565b602082019050919050565b600060208201905081810360008301526118ed816118b1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061192e8261101a565b91506119398361101a565b92508282026119478161101a565b9150828204841483151761195e5761195d6118f4565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061199f8261101a565b91506119aa8361101a565b9250826119ba576119b9611965565b5b828204905092915050565b60006119d08261101a565b91506119db8361101a565b92508282039050818111156119f3576119f26118f4565b5b92915050565b6000611a048261101a565b9150611a0f8361101a565b9250828201905080821115611a2757611a266118f4565b5b92915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000611a63601f8361142f565b9150611a6e82611a2d565b602082019050919050565b60006020820190508181036000830152611a9281611a56565b9050919050565b7f4e6f206561726e696e677320746f207769746864726177000000000000000000600082015250565b6000611acf60178361142f565b9150611ada82611a99565b602082019050919050565b60006020820190508181036000830152611afe81611ac2565b9050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000611b6160268361142f565b9150611b6c82611b05565b604082019050919050565b60006020820190508181036000830152611b9081611b54565b905091905056fea2646970667358221220da42bab4deed86f9aaf14bc08f2ee2a16e3019b4ad3f3b9c6b2ef44700c024c064736f6c63430008140033",
269 | "linkReferences": {},
270 | "deployedLinkReferences": {}
271 | }
272 |
--------------------------------------------------------------------------------
/server-/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "server",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@jackstenglein/chess": "^2.2.8",
13 | "body-parser": "^1.20.3",
14 | "chess.js": "^1.0.0-beta.8",
15 | "chessground": "^9.1.1",
16 | "cors": "^2.8.5",
17 | "ethers": "^6.13.5",
18 | "express": "^4.21.2",
19 | "http": "^0.0.1-security",
20 | "socket.io": "^4.8.1",
21 | "ws": "^8.18.0"
22 | },
23 | "devDependencies": {
24 | "nodemon": "^3.1.7"
25 | }
26 | },
27 | "node_modules/@adraffy/ens-normalize": {
28 | "version": "1.10.1",
29 | "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
30 | "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
31 | "license": "MIT"
32 | },
33 | "node_modules/@jackstenglein/chess": {
34 | "version": "2.2.8",
35 | "resolved": "https://registry.npmjs.org/@jackstenglein/chess/-/chess-2.2.8.tgz",
36 | "integrity": "sha512-NpDBNXuOlkrbb3cSIM/XLDhEigqFKBQUkJWDhhmi5GeDSqio1qTmZ924D5KhIHd550p732p7B/nfsJwxtkrw+A==",
37 | "license": "MIT",
38 | "dependencies": {
39 | "@jackstenglein/pgn-parser": "^2.0.7",
40 | "chess.js": "^1.0.0-beta.7"
41 | }
42 | },
43 | "node_modules/@jackstenglein/pgn-parser": {
44 | "version": "2.0.8",
45 | "resolved": "https://registry.npmjs.org/@jackstenglein/pgn-parser/-/pgn-parser-2.0.8.tgz",
46 | "integrity": "sha512-4qmK+GdiY3bAGHKtzxMXQhLJUOdZ9l16hY5h7S/T35G3xPVcsmeb1x0cFlrJ7adeJHm09aLnaKkCd1SC+7bAUw==",
47 | "license": "Apache-2.0",
48 | "bin": {
49 | "pgn-parser": "bin/pgn-to-json.js"
50 | }
51 | },
52 | "node_modules/@noble/curves": {
53 | "version": "1.2.0",
54 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
55 | "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
56 | "license": "MIT",
57 | "dependencies": {
58 | "@noble/hashes": "1.3.2"
59 | },
60 | "funding": {
61 | "url": "https://paulmillr.com/funding/"
62 | }
63 | },
64 | "node_modules/@noble/hashes": {
65 | "version": "1.3.2",
66 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
67 | "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
68 | "license": "MIT",
69 | "engines": {
70 | "node": ">= 16"
71 | },
72 | "funding": {
73 | "url": "https://paulmillr.com/funding/"
74 | }
75 | },
76 | "node_modules/@socket.io/component-emitter": {
77 | "version": "3.1.2",
78 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
79 | "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
80 | "license": "MIT"
81 | },
82 | "node_modules/@types/cookie": {
83 | "version": "0.4.1",
84 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
85 | "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
86 | "license": "MIT"
87 | },
88 | "node_modules/@types/cors": {
89 | "version": "2.8.17",
90 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
91 | "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
92 | "license": "MIT",
93 | "dependencies": {
94 | "@types/node": "*"
95 | }
96 | },
97 | "node_modules/@types/node": {
98 | "version": "22.10.1",
99 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz",
100 | "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==",
101 | "license": "MIT",
102 | "dependencies": {
103 | "undici-types": "~6.20.0"
104 | }
105 | },
106 | "node_modules/accepts": {
107 | "version": "1.3.8",
108 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
109 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
110 | "license": "MIT",
111 | "dependencies": {
112 | "mime-types": "~2.1.34",
113 | "negotiator": "0.6.3"
114 | },
115 | "engines": {
116 | "node": ">= 0.6"
117 | }
118 | },
119 | "node_modules/aes-js": {
120 | "version": "4.0.0-beta.5",
121 | "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
122 | "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
123 | "license": "MIT"
124 | },
125 | "node_modules/anymatch": {
126 | "version": "3.1.3",
127 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
128 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
129 | "dev": true,
130 | "license": "ISC",
131 | "dependencies": {
132 | "normalize-path": "^3.0.0",
133 | "picomatch": "^2.0.4"
134 | },
135 | "engines": {
136 | "node": ">= 8"
137 | }
138 | },
139 | "node_modules/array-flatten": {
140 | "version": "1.1.1",
141 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
142 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
143 | "license": "MIT"
144 | },
145 | "node_modules/balanced-match": {
146 | "version": "1.0.2",
147 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
148 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
149 | "dev": true,
150 | "license": "MIT"
151 | },
152 | "node_modules/base64id": {
153 | "version": "2.0.0",
154 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
155 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
156 | "license": "MIT",
157 | "engines": {
158 | "node": "^4.5.0 || >= 5.9"
159 | }
160 | },
161 | "node_modules/binary-extensions": {
162 | "version": "2.3.0",
163 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
164 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
165 | "dev": true,
166 | "license": "MIT",
167 | "engines": {
168 | "node": ">=8"
169 | },
170 | "funding": {
171 | "url": "https://github.com/sponsors/sindresorhus"
172 | }
173 | },
174 | "node_modules/body-parser": {
175 | "version": "1.20.3",
176 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
177 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
178 | "license": "MIT",
179 | "dependencies": {
180 | "bytes": "3.1.2",
181 | "content-type": "~1.0.5",
182 | "debug": "2.6.9",
183 | "depd": "2.0.0",
184 | "destroy": "1.2.0",
185 | "http-errors": "2.0.0",
186 | "iconv-lite": "0.4.24",
187 | "on-finished": "2.4.1",
188 | "qs": "6.13.0",
189 | "raw-body": "2.5.2",
190 | "type-is": "~1.6.18",
191 | "unpipe": "1.0.0"
192 | },
193 | "engines": {
194 | "node": ">= 0.8",
195 | "npm": "1.2.8000 || >= 1.4.16"
196 | }
197 | },
198 | "node_modules/brace-expansion": {
199 | "version": "1.1.11",
200 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
201 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
202 | "dev": true,
203 | "license": "MIT",
204 | "dependencies": {
205 | "balanced-match": "^1.0.0",
206 | "concat-map": "0.0.1"
207 | }
208 | },
209 | "node_modules/braces": {
210 | "version": "3.0.3",
211 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
212 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
213 | "dev": true,
214 | "license": "MIT",
215 | "dependencies": {
216 | "fill-range": "^7.1.1"
217 | },
218 | "engines": {
219 | "node": ">=8"
220 | }
221 | },
222 | "node_modules/bytes": {
223 | "version": "3.1.2",
224 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
225 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
226 | "license": "MIT",
227 | "engines": {
228 | "node": ">= 0.8"
229 | }
230 | },
231 | "node_modules/call-bind": {
232 | "version": "1.0.7",
233 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
234 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
235 | "license": "MIT",
236 | "dependencies": {
237 | "es-define-property": "^1.0.0",
238 | "es-errors": "^1.3.0",
239 | "function-bind": "^1.1.2",
240 | "get-intrinsic": "^1.2.4",
241 | "set-function-length": "^1.2.1"
242 | },
243 | "engines": {
244 | "node": ">= 0.4"
245 | },
246 | "funding": {
247 | "url": "https://github.com/sponsors/ljharb"
248 | }
249 | },
250 | "node_modules/chess.js": {
251 | "version": "1.0.0-beta.8",
252 | "resolved": "https://registry.npmjs.org/chess.js/-/chess.js-1.0.0-beta.8.tgz",
253 | "integrity": "sha512-UngzUMXmexcQaQA/UEJuJj5vatEy34awYMD5YMOp/FW3HM7lqspp7ymYs5JAmquDq0WROtURRfSffoa/vrCCyw==",
254 | "license": "BSD-2-Clause"
255 | },
256 | "node_modules/chessground": {
257 | "version": "9.1.1",
258 | "resolved": "https://registry.npmjs.org/chessground/-/chessground-9.1.1.tgz",
259 | "integrity": "sha512-X4xrBICrixaLATCn+jGEzk58UXcas+9QqJnwVq9nT7AaX2M1CJLMA0vC7noG0s6Tr2zoAHZ1FOviE5b05MgduQ==",
260 | "license": "GPL-3.0-or-later",
261 | "funding": {
262 | "url": "https://lichess.org/patron"
263 | }
264 | },
265 | "node_modules/chokidar": {
266 | "version": "3.6.0",
267 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
268 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
269 | "dev": true,
270 | "license": "MIT",
271 | "dependencies": {
272 | "anymatch": "~3.1.2",
273 | "braces": "~3.0.2",
274 | "glob-parent": "~5.1.2",
275 | "is-binary-path": "~2.1.0",
276 | "is-glob": "~4.0.1",
277 | "normalize-path": "~3.0.0",
278 | "readdirp": "~3.6.0"
279 | },
280 | "engines": {
281 | "node": ">= 8.10.0"
282 | },
283 | "funding": {
284 | "url": "https://paulmillr.com/funding/"
285 | },
286 | "optionalDependencies": {
287 | "fsevents": "~2.3.2"
288 | }
289 | },
290 | "node_modules/concat-map": {
291 | "version": "0.0.1",
292 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
293 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
294 | "dev": true,
295 | "license": "MIT"
296 | },
297 | "node_modules/content-disposition": {
298 | "version": "0.5.4",
299 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
300 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
301 | "license": "MIT",
302 | "dependencies": {
303 | "safe-buffer": "5.2.1"
304 | },
305 | "engines": {
306 | "node": ">= 0.6"
307 | }
308 | },
309 | "node_modules/content-type": {
310 | "version": "1.0.5",
311 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
312 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
313 | "license": "MIT",
314 | "engines": {
315 | "node": ">= 0.6"
316 | }
317 | },
318 | "node_modules/cookie": {
319 | "version": "0.7.1",
320 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
321 | "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
322 | "license": "MIT",
323 | "engines": {
324 | "node": ">= 0.6"
325 | }
326 | },
327 | "node_modules/cookie-signature": {
328 | "version": "1.0.6",
329 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
330 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
331 | "license": "MIT"
332 | },
333 | "node_modules/cors": {
334 | "version": "2.8.5",
335 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
336 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
337 | "license": "MIT",
338 | "dependencies": {
339 | "object-assign": "^4",
340 | "vary": "^1"
341 | },
342 | "engines": {
343 | "node": ">= 0.10"
344 | }
345 | },
346 | "node_modules/debug": {
347 | "version": "2.6.9",
348 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
349 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
350 | "license": "MIT",
351 | "dependencies": {
352 | "ms": "2.0.0"
353 | }
354 | },
355 | "node_modules/define-data-property": {
356 | "version": "1.1.4",
357 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
358 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
359 | "license": "MIT",
360 | "dependencies": {
361 | "es-define-property": "^1.0.0",
362 | "es-errors": "^1.3.0",
363 | "gopd": "^1.0.1"
364 | },
365 | "engines": {
366 | "node": ">= 0.4"
367 | },
368 | "funding": {
369 | "url": "https://github.com/sponsors/ljharb"
370 | }
371 | },
372 | "node_modules/depd": {
373 | "version": "2.0.0",
374 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
375 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
376 | "license": "MIT",
377 | "engines": {
378 | "node": ">= 0.8"
379 | }
380 | },
381 | "node_modules/destroy": {
382 | "version": "1.2.0",
383 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
384 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
385 | "license": "MIT",
386 | "engines": {
387 | "node": ">= 0.8",
388 | "npm": "1.2.8000 || >= 1.4.16"
389 | }
390 | },
391 | "node_modules/ee-first": {
392 | "version": "1.1.1",
393 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
394 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
395 | "license": "MIT"
396 | },
397 | "node_modules/encodeurl": {
398 | "version": "2.0.0",
399 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
400 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
401 | "license": "MIT",
402 | "engines": {
403 | "node": ">= 0.8"
404 | }
405 | },
406 | "node_modules/engine.io": {
407 | "version": "6.6.2",
408 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
409 | "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
410 | "license": "MIT",
411 | "dependencies": {
412 | "@types/cookie": "^0.4.1",
413 | "@types/cors": "^2.8.12",
414 | "@types/node": ">=10.0.0",
415 | "accepts": "~1.3.4",
416 | "base64id": "2.0.0",
417 | "cookie": "~0.7.2",
418 | "cors": "~2.8.5",
419 | "debug": "~4.3.1",
420 | "engine.io-parser": "~5.2.1",
421 | "ws": "~8.17.1"
422 | },
423 | "engines": {
424 | "node": ">=10.2.0"
425 | }
426 | },
427 | "node_modules/engine.io-parser": {
428 | "version": "5.2.3",
429 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
430 | "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
431 | "license": "MIT",
432 | "engines": {
433 | "node": ">=10.0.0"
434 | }
435 | },
436 | "node_modules/engine.io/node_modules/cookie": {
437 | "version": "0.7.2",
438 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
439 | "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
440 | "license": "MIT",
441 | "engines": {
442 | "node": ">= 0.6"
443 | }
444 | },
445 | "node_modules/engine.io/node_modules/debug": {
446 | "version": "4.3.7",
447 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
448 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
449 | "license": "MIT",
450 | "dependencies": {
451 | "ms": "^2.1.3"
452 | },
453 | "engines": {
454 | "node": ">=6.0"
455 | },
456 | "peerDependenciesMeta": {
457 | "supports-color": {
458 | "optional": true
459 | }
460 | }
461 | },
462 | "node_modules/engine.io/node_modules/ms": {
463 | "version": "2.1.3",
464 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
465 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
466 | "license": "MIT"
467 | },
468 | "node_modules/engine.io/node_modules/ws": {
469 | "version": "8.17.1",
470 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
471 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
472 | "license": "MIT",
473 | "engines": {
474 | "node": ">=10.0.0"
475 | },
476 | "peerDependencies": {
477 | "bufferutil": "^4.0.1",
478 | "utf-8-validate": ">=5.0.2"
479 | },
480 | "peerDependenciesMeta": {
481 | "bufferutil": {
482 | "optional": true
483 | },
484 | "utf-8-validate": {
485 | "optional": true
486 | }
487 | }
488 | },
489 | "node_modules/es-define-property": {
490 | "version": "1.0.0",
491 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
492 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
493 | "license": "MIT",
494 | "dependencies": {
495 | "get-intrinsic": "^1.2.4"
496 | },
497 | "engines": {
498 | "node": ">= 0.4"
499 | }
500 | },
501 | "node_modules/es-errors": {
502 | "version": "1.3.0",
503 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
504 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
505 | "license": "MIT",
506 | "engines": {
507 | "node": ">= 0.4"
508 | }
509 | },
510 | "node_modules/escape-html": {
511 | "version": "1.0.3",
512 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
513 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
514 | "license": "MIT"
515 | },
516 | "node_modules/etag": {
517 | "version": "1.8.1",
518 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
519 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
520 | "license": "MIT",
521 | "engines": {
522 | "node": ">= 0.6"
523 | }
524 | },
525 | "node_modules/ethers": {
526 | "version": "6.13.5",
527 | "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz",
528 | "integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==",
529 | "funding": [
530 | {
531 | "type": "individual",
532 | "url": "https://github.com/sponsors/ethers-io/"
533 | },
534 | {
535 | "type": "individual",
536 | "url": "https://www.buymeacoffee.com/ricmoo"
537 | }
538 | ],
539 | "license": "MIT",
540 | "dependencies": {
541 | "@adraffy/ens-normalize": "1.10.1",
542 | "@noble/curves": "1.2.0",
543 | "@noble/hashes": "1.3.2",
544 | "@types/node": "22.7.5",
545 | "aes-js": "4.0.0-beta.5",
546 | "tslib": "2.7.0",
547 | "ws": "8.17.1"
548 | },
549 | "engines": {
550 | "node": ">=14.0.0"
551 | }
552 | },
553 | "node_modules/ethers/node_modules/@types/node": {
554 | "version": "22.7.5",
555 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
556 | "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
557 | "license": "MIT",
558 | "dependencies": {
559 | "undici-types": "~6.19.2"
560 | }
561 | },
562 | "node_modules/ethers/node_modules/undici-types": {
563 | "version": "6.19.8",
564 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
565 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
566 | "license": "MIT"
567 | },
568 | "node_modules/ethers/node_modules/ws": {
569 | "version": "8.17.1",
570 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
571 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
572 | "license": "MIT",
573 | "engines": {
574 | "node": ">=10.0.0"
575 | },
576 | "peerDependencies": {
577 | "bufferutil": "^4.0.1",
578 | "utf-8-validate": ">=5.0.2"
579 | },
580 | "peerDependenciesMeta": {
581 | "bufferutil": {
582 | "optional": true
583 | },
584 | "utf-8-validate": {
585 | "optional": true
586 | }
587 | }
588 | },
589 | "node_modules/express": {
590 | "version": "4.21.2",
591 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
592 | "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
593 | "license": "MIT",
594 | "dependencies": {
595 | "accepts": "~1.3.8",
596 | "array-flatten": "1.1.1",
597 | "body-parser": "1.20.3",
598 | "content-disposition": "0.5.4",
599 | "content-type": "~1.0.4",
600 | "cookie": "0.7.1",
601 | "cookie-signature": "1.0.6",
602 | "debug": "2.6.9",
603 | "depd": "2.0.0",
604 | "encodeurl": "~2.0.0",
605 | "escape-html": "~1.0.3",
606 | "etag": "~1.8.1",
607 | "finalhandler": "1.3.1",
608 | "fresh": "0.5.2",
609 | "http-errors": "2.0.0",
610 | "merge-descriptors": "1.0.3",
611 | "methods": "~1.1.2",
612 | "on-finished": "2.4.1",
613 | "parseurl": "~1.3.3",
614 | "path-to-regexp": "0.1.12",
615 | "proxy-addr": "~2.0.7",
616 | "qs": "6.13.0",
617 | "range-parser": "~1.2.1",
618 | "safe-buffer": "5.2.1",
619 | "send": "0.19.0",
620 | "serve-static": "1.16.2",
621 | "setprototypeof": "1.2.0",
622 | "statuses": "2.0.1",
623 | "type-is": "~1.6.18",
624 | "utils-merge": "1.0.1",
625 | "vary": "~1.1.2"
626 | },
627 | "engines": {
628 | "node": ">= 0.10.0"
629 | },
630 | "funding": {
631 | "type": "opencollective",
632 | "url": "https://opencollective.com/express"
633 | }
634 | },
635 | "node_modules/fill-range": {
636 | "version": "7.1.1",
637 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
638 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
639 | "dev": true,
640 | "license": "MIT",
641 | "dependencies": {
642 | "to-regex-range": "^5.0.1"
643 | },
644 | "engines": {
645 | "node": ">=8"
646 | }
647 | },
648 | "node_modules/finalhandler": {
649 | "version": "1.3.1",
650 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
651 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
652 | "license": "MIT",
653 | "dependencies": {
654 | "debug": "2.6.9",
655 | "encodeurl": "~2.0.0",
656 | "escape-html": "~1.0.3",
657 | "on-finished": "2.4.1",
658 | "parseurl": "~1.3.3",
659 | "statuses": "2.0.1",
660 | "unpipe": "~1.0.0"
661 | },
662 | "engines": {
663 | "node": ">= 0.8"
664 | }
665 | },
666 | "node_modules/forwarded": {
667 | "version": "0.2.0",
668 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
669 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
670 | "license": "MIT",
671 | "engines": {
672 | "node": ">= 0.6"
673 | }
674 | },
675 | "node_modules/fresh": {
676 | "version": "0.5.2",
677 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
678 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
679 | "license": "MIT",
680 | "engines": {
681 | "node": ">= 0.6"
682 | }
683 | },
684 | "node_modules/fsevents": {
685 | "version": "2.3.3",
686 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
687 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
688 | "dev": true,
689 | "hasInstallScript": true,
690 | "license": "MIT",
691 | "optional": true,
692 | "os": [
693 | "darwin"
694 | ],
695 | "engines": {
696 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
697 | }
698 | },
699 | "node_modules/function-bind": {
700 | "version": "1.1.2",
701 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
702 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
703 | "license": "MIT",
704 | "funding": {
705 | "url": "https://github.com/sponsors/ljharb"
706 | }
707 | },
708 | "node_modules/get-intrinsic": {
709 | "version": "1.2.4",
710 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
711 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
712 | "license": "MIT",
713 | "dependencies": {
714 | "es-errors": "^1.3.0",
715 | "function-bind": "^1.1.2",
716 | "has-proto": "^1.0.1",
717 | "has-symbols": "^1.0.3",
718 | "hasown": "^2.0.0"
719 | },
720 | "engines": {
721 | "node": ">= 0.4"
722 | },
723 | "funding": {
724 | "url": "https://github.com/sponsors/ljharb"
725 | }
726 | },
727 | "node_modules/glob-parent": {
728 | "version": "5.1.2",
729 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
730 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
731 | "dev": true,
732 | "license": "ISC",
733 | "dependencies": {
734 | "is-glob": "^4.0.1"
735 | },
736 | "engines": {
737 | "node": ">= 6"
738 | }
739 | },
740 | "node_modules/gopd": {
741 | "version": "1.1.0",
742 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz",
743 | "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==",
744 | "license": "MIT",
745 | "dependencies": {
746 | "get-intrinsic": "^1.2.4"
747 | },
748 | "engines": {
749 | "node": ">= 0.4"
750 | },
751 | "funding": {
752 | "url": "https://github.com/sponsors/ljharb"
753 | }
754 | },
755 | "node_modules/has-flag": {
756 | "version": "3.0.0",
757 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
758 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
759 | "dev": true,
760 | "license": "MIT",
761 | "engines": {
762 | "node": ">=4"
763 | }
764 | },
765 | "node_modules/has-property-descriptors": {
766 | "version": "1.0.2",
767 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
768 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
769 | "license": "MIT",
770 | "dependencies": {
771 | "es-define-property": "^1.0.0"
772 | },
773 | "funding": {
774 | "url": "https://github.com/sponsors/ljharb"
775 | }
776 | },
777 | "node_modules/has-proto": {
778 | "version": "1.0.3",
779 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
780 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
781 | "license": "MIT",
782 | "engines": {
783 | "node": ">= 0.4"
784 | },
785 | "funding": {
786 | "url": "https://github.com/sponsors/ljharb"
787 | }
788 | },
789 | "node_modules/has-symbols": {
790 | "version": "1.0.3",
791 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
792 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
793 | "license": "MIT",
794 | "engines": {
795 | "node": ">= 0.4"
796 | },
797 | "funding": {
798 | "url": "https://github.com/sponsors/ljharb"
799 | }
800 | },
801 | "node_modules/hasown": {
802 | "version": "2.0.2",
803 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
804 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
805 | "license": "MIT",
806 | "dependencies": {
807 | "function-bind": "^1.1.2"
808 | },
809 | "engines": {
810 | "node": ">= 0.4"
811 | }
812 | },
813 | "node_modules/http": {
814 | "version": "0.0.1-security",
815 | "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz",
816 | "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g=="
817 | },
818 | "node_modules/http-errors": {
819 | "version": "2.0.0",
820 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
821 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
822 | "license": "MIT",
823 | "dependencies": {
824 | "depd": "2.0.0",
825 | "inherits": "2.0.4",
826 | "setprototypeof": "1.2.0",
827 | "statuses": "2.0.1",
828 | "toidentifier": "1.0.1"
829 | },
830 | "engines": {
831 | "node": ">= 0.8"
832 | }
833 | },
834 | "node_modules/iconv-lite": {
835 | "version": "0.4.24",
836 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
837 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
838 | "license": "MIT",
839 | "dependencies": {
840 | "safer-buffer": ">= 2.1.2 < 3"
841 | },
842 | "engines": {
843 | "node": ">=0.10.0"
844 | }
845 | },
846 | "node_modules/ignore-by-default": {
847 | "version": "1.0.1",
848 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
849 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
850 | "dev": true,
851 | "license": "ISC"
852 | },
853 | "node_modules/inherits": {
854 | "version": "2.0.4",
855 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
856 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
857 | "license": "ISC"
858 | },
859 | "node_modules/ipaddr.js": {
860 | "version": "1.9.1",
861 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
862 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
863 | "license": "MIT",
864 | "engines": {
865 | "node": ">= 0.10"
866 | }
867 | },
868 | "node_modules/is-binary-path": {
869 | "version": "2.1.0",
870 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
871 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
872 | "dev": true,
873 | "license": "MIT",
874 | "dependencies": {
875 | "binary-extensions": "^2.0.0"
876 | },
877 | "engines": {
878 | "node": ">=8"
879 | }
880 | },
881 | "node_modules/is-extglob": {
882 | "version": "2.1.1",
883 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
884 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
885 | "dev": true,
886 | "license": "MIT",
887 | "engines": {
888 | "node": ">=0.10.0"
889 | }
890 | },
891 | "node_modules/is-glob": {
892 | "version": "4.0.3",
893 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
894 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
895 | "dev": true,
896 | "license": "MIT",
897 | "dependencies": {
898 | "is-extglob": "^2.1.1"
899 | },
900 | "engines": {
901 | "node": ">=0.10.0"
902 | }
903 | },
904 | "node_modules/is-number": {
905 | "version": "7.0.0",
906 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
907 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
908 | "dev": true,
909 | "license": "MIT",
910 | "engines": {
911 | "node": ">=0.12.0"
912 | }
913 | },
914 | "node_modules/media-typer": {
915 | "version": "0.3.0",
916 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
917 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
918 | "license": "MIT",
919 | "engines": {
920 | "node": ">= 0.6"
921 | }
922 | },
923 | "node_modules/merge-descriptors": {
924 | "version": "1.0.3",
925 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
926 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
927 | "license": "MIT",
928 | "funding": {
929 | "url": "https://github.com/sponsors/sindresorhus"
930 | }
931 | },
932 | "node_modules/methods": {
933 | "version": "1.1.2",
934 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
935 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
936 | "license": "MIT",
937 | "engines": {
938 | "node": ">= 0.6"
939 | }
940 | },
941 | "node_modules/mime": {
942 | "version": "1.6.0",
943 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
944 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
945 | "license": "MIT",
946 | "bin": {
947 | "mime": "cli.js"
948 | },
949 | "engines": {
950 | "node": ">=4"
951 | }
952 | },
953 | "node_modules/mime-db": {
954 | "version": "1.52.0",
955 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
956 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
957 | "license": "MIT",
958 | "engines": {
959 | "node": ">= 0.6"
960 | }
961 | },
962 | "node_modules/mime-types": {
963 | "version": "2.1.35",
964 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
965 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
966 | "license": "MIT",
967 | "dependencies": {
968 | "mime-db": "1.52.0"
969 | },
970 | "engines": {
971 | "node": ">= 0.6"
972 | }
973 | },
974 | "node_modules/minimatch": {
975 | "version": "3.1.2",
976 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
977 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
978 | "dev": true,
979 | "license": "ISC",
980 | "dependencies": {
981 | "brace-expansion": "^1.1.7"
982 | },
983 | "engines": {
984 | "node": "*"
985 | }
986 | },
987 | "node_modules/ms": {
988 | "version": "2.0.0",
989 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
990 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
991 | "license": "MIT"
992 | },
993 | "node_modules/negotiator": {
994 | "version": "0.6.3",
995 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
996 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
997 | "license": "MIT",
998 | "engines": {
999 | "node": ">= 0.6"
1000 | }
1001 | },
1002 | "node_modules/nodemon": {
1003 | "version": "3.1.7",
1004 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
1005 | "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
1006 | "dev": true,
1007 | "license": "MIT",
1008 | "dependencies": {
1009 | "chokidar": "^3.5.2",
1010 | "debug": "^4",
1011 | "ignore-by-default": "^1.0.1",
1012 | "minimatch": "^3.1.2",
1013 | "pstree.remy": "^1.1.8",
1014 | "semver": "^7.5.3",
1015 | "simple-update-notifier": "^2.0.0",
1016 | "supports-color": "^5.5.0",
1017 | "touch": "^3.1.0",
1018 | "undefsafe": "^2.0.5"
1019 | },
1020 | "bin": {
1021 | "nodemon": "bin/nodemon.js"
1022 | },
1023 | "engines": {
1024 | "node": ">=10"
1025 | },
1026 | "funding": {
1027 | "type": "opencollective",
1028 | "url": "https://opencollective.com/nodemon"
1029 | }
1030 | },
1031 | "node_modules/nodemon/node_modules/debug": {
1032 | "version": "4.3.7",
1033 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1034 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1035 | "dev": true,
1036 | "license": "MIT",
1037 | "dependencies": {
1038 | "ms": "^2.1.3"
1039 | },
1040 | "engines": {
1041 | "node": ">=6.0"
1042 | },
1043 | "peerDependenciesMeta": {
1044 | "supports-color": {
1045 | "optional": true
1046 | }
1047 | }
1048 | },
1049 | "node_modules/nodemon/node_modules/ms": {
1050 | "version": "2.1.3",
1051 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1052 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1053 | "dev": true,
1054 | "license": "MIT"
1055 | },
1056 | "node_modules/normalize-path": {
1057 | "version": "3.0.0",
1058 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1059 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1060 | "dev": true,
1061 | "license": "MIT",
1062 | "engines": {
1063 | "node": ">=0.10.0"
1064 | }
1065 | },
1066 | "node_modules/object-assign": {
1067 | "version": "4.1.1",
1068 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1069 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1070 | "license": "MIT",
1071 | "engines": {
1072 | "node": ">=0.10.0"
1073 | }
1074 | },
1075 | "node_modules/object-inspect": {
1076 | "version": "1.13.3",
1077 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
1078 | "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
1079 | "license": "MIT",
1080 | "engines": {
1081 | "node": ">= 0.4"
1082 | },
1083 | "funding": {
1084 | "url": "https://github.com/sponsors/ljharb"
1085 | }
1086 | },
1087 | "node_modules/on-finished": {
1088 | "version": "2.4.1",
1089 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1090 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1091 | "license": "MIT",
1092 | "dependencies": {
1093 | "ee-first": "1.1.1"
1094 | },
1095 | "engines": {
1096 | "node": ">= 0.8"
1097 | }
1098 | },
1099 | "node_modules/parseurl": {
1100 | "version": "1.3.3",
1101 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1102 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1103 | "license": "MIT",
1104 | "engines": {
1105 | "node": ">= 0.8"
1106 | }
1107 | },
1108 | "node_modules/path-to-regexp": {
1109 | "version": "0.1.12",
1110 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
1111 | "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
1112 | "license": "MIT"
1113 | },
1114 | "node_modules/picomatch": {
1115 | "version": "2.3.1",
1116 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1117 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1118 | "dev": true,
1119 | "license": "MIT",
1120 | "engines": {
1121 | "node": ">=8.6"
1122 | },
1123 | "funding": {
1124 | "url": "https://github.com/sponsors/jonschlinkert"
1125 | }
1126 | },
1127 | "node_modules/proxy-addr": {
1128 | "version": "2.0.7",
1129 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1130 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1131 | "license": "MIT",
1132 | "dependencies": {
1133 | "forwarded": "0.2.0",
1134 | "ipaddr.js": "1.9.1"
1135 | },
1136 | "engines": {
1137 | "node": ">= 0.10"
1138 | }
1139 | },
1140 | "node_modules/pstree.remy": {
1141 | "version": "1.1.8",
1142 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1143 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1144 | "dev": true,
1145 | "license": "MIT"
1146 | },
1147 | "node_modules/qs": {
1148 | "version": "6.13.0",
1149 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
1150 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
1151 | "license": "BSD-3-Clause",
1152 | "dependencies": {
1153 | "side-channel": "^1.0.6"
1154 | },
1155 | "engines": {
1156 | "node": ">=0.6"
1157 | },
1158 | "funding": {
1159 | "url": "https://github.com/sponsors/ljharb"
1160 | }
1161 | },
1162 | "node_modules/range-parser": {
1163 | "version": "1.2.1",
1164 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1165 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1166 | "license": "MIT",
1167 | "engines": {
1168 | "node": ">= 0.6"
1169 | }
1170 | },
1171 | "node_modules/raw-body": {
1172 | "version": "2.5.2",
1173 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
1174 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
1175 | "license": "MIT",
1176 | "dependencies": {
1177 | "bytes": "3.1.2",
1178 | "http-errors": "2.0.0",
1179 | "iconv-lite": "0.4.24",
1180 | "unpipe": "1.0.0"
1181 | },
1182 | "engines": {
1183 | "node": ">= 0.8"
1184 | }
1185 | },
1186 | "node_modules/readdirp": {
1187 | "version": "3.6.0",
1188 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1189 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1190 | "dev": true,
1191 | "license": "MIT",
1192 | "dependencies": {
1193 | "picomatch": "^2.2.1"
1194 | },
1195 | "engines": {
1196 | "node": ">=8.10.0"
1197 | }
1198 | },
1199 | "node_modules/safe-buffer": {
1200 | "version": "5.2.1",
1201 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1202 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1203 | "funding": [
1204 | {
1205 | "type": "github",
1206 | "url": "https://github.com/sponsors/feross"
1207 | },
1208 | {
1209 | "type": "patreon",
1210 | "url": "https://www.patreon.com/feross"
1211 | },
1212 | {
1213 | "type": "consulting",
1214 | "url": "https://feross.org/support"
1215 | }
1216 | ],
1217 | "license": "MIT"
1218 | },
1219 | "node_modules/safer-buffer": {
1220 | "version": "2.1.2",
1221 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1222 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1223 | "license": "MIT"
1224 | },
1225 | "node_modules/semver": {
1226 | "version": "7.6.3",
1227 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
1228 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
1229 | "dev": true,
1230 | "license": "ISC",
1231 | "bin": {
1232 | "semver": "bin/semver.js"
1233 | },
1234 | "engines": {
1235 | "node": ">=10"
1236 | }
1237 | },
1238 | "node_modules/send": {
1239 | "version": "0.19.0",
1240 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
1241 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
1242 | "license": "MIT",
1243 | "dependencies": {
1244 | "debug": "2.6.9",
1245 | "depd": "2.0.0",
1246 | "destroy": "1.2.0",
1247 | "encodeurl": "~1.0.2",
1248 | "escape-html": "~1.0.3",
1249 | "etag": "~1.8.1",
1250 | "fresh": "0.5.2",
1251 | "http-errors": "2.0.0",
1252 | "mime": "1.6.0",
1253 | "ms": "2.1.3",
1254 | "on-finished": "2.4.1",
1255 | "range-parser": "~1.2.1",
1256 | "statuses": "2.0.1"
1257 | },
1258 | "engines": {
1259 | "node": ">= 0.8.0"
1260 | }
1261 | },
1262 | "node_modules/send/node_modules/encodeurl": {
1263 | "version": "1.0.2",
1264 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1265 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
1266 | "license": "MIT",
1267 | "engines": {
1268 | "node": ">= 0.8"
1269 | }
1270 | },
1271 | "node_modules/send/node_modules/ms": {
1272 | "version": "2.1.3",
1273 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1274 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1275 | "license": "MIT"
1276 | },
1277 | "node_modules/serve-static": {
1278 | "version": "1.16.2",
1279 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
1280 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
1281 | "license": "MIT",
1282 | "dependencies": {
1283 | "encodeurl": "~2.0.0",
1284 | "escape-html": "~1.0.3",
1285 | "parseurl": "~1.3.3",
1286 | "send": "0.19.0"
1287 | },
1288 | "engines": {
1289 | "node": ">= 0.8.0"
1290 | }
1291 | },
1292 | "node_modules/set-function-length": {
1293 | "version": "1.2.2",
1294 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
1295 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
1296 | "license": "MIT",
1297 | "dependencies": {
1298 | "define-data-property": "^1.1.4",
1299 | "es-errors": "^1.3.0",
1300 | "function-bind": "^1.1.2",
1301 | "get-intrinsic": "^1.2.4",
1302 | "gopd": "^1.0.1",
1303 | "has-property-descriptors": "^1.0.2"
1304 | },
1305 | "engines": {
1306 | "node": ">= 0.4"
1307 | }
1308 | },
1309 | "node_modules/setprototypeof": {
1310 | "version": "1.2.0",
1311 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1312 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
1313 | "license": "ISC"
1314 | },
1315 | "node_modules/side-channel": {
1316 | "version": "1.0.6",
1317 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
1318 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
1319 | "license": "MIT",
1320 | "dependencies": {
1321 | "call-bind": "^1.0.7",
1322 | "es-errors": "^1.3.0",
1323 | "get-intrinsic": "^1.2.4",
1324 | "object-inspect": "^1.13.1"
1325 | },
1326 | "engines": {
1327 | "node": ">= 0.4"
1328 | },
1329 | "funding": {
1330 | "url": "https://github.com/sponsors/ljharb"
1331 | }
1332 | },
1333 | "node_modules/simple-update-notifier": {
1334 | "version": "2.0.0",
1335 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
1336 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
1337 | "dev": true,
1338 | "license": "MIT",
1339 | "dependencies": {
1340 | "semver": "^7.5.3"
1341 | },
1342 | "engines": {
1343 | "node": ">=10"
1344 | }
1345 | },
1346 | "node_modules/socket.io": {
1347 | "version": "4.8.1",
1348 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
1349 | "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
1350 | "license": "MIT",
1351 | "dependencies": {
1352 | "accepts": "~1.3.4",
1353 | "base64id": "~2.0.0",
1354 | "cors": "~2.8.5",
1355 | "debug": "~4.3.2",
1356 | "engine.io": "~6.6.0",
1357 | "socket.io-adapter": "~2.5.2",
1358 | "socket.io-parser": "~4.2.4"
1359 | },
1360 | "engines": {
1361 | "node": ">=10.2.0"
1362 | }
1363 | },
1364 | "node_modules/socket.io-adapter": {
1365 | "version": "2.5.5",
1366 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
1367 | "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
1368 | "license": "MIT",
1369 | "dependencies": {
1370 | "debug": "~4.3.4",
1371 | "ws": "~8.17.1"
1372 | }
1373 | },
1374 | "node_modules/socket.io-adapter/node_modules/debug": {
1375 | "version": "4.3.7",
1376 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1377 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1378 | "license": "MIT",
1379 | "dependencies": {
1380 | "ms": "^2.1.3"
1381 | },
1382 | "engines": {
1383 | "node": ">=6.0"
1384 | },
1385 | "peerDependenciesMeta": {
1386 | "supports-color": {
1387 | "optional": true
1388 | }
1389 | }
1390 | },
1391 | "node_modules/socket.io-adapter/node_modules/ms": {
1392 | "version": "2.1.3",
1393 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1394 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1395 | "license": "MIT"
1396 | },
1397 | "node_modules/socket.io-adapter/node_modules/ws": {
1398 | "version": "8.17.1",
1399 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
1400 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
1401 | "license": "MIT",
1402 | "engines": {
1403 | "node": ">=10.0.0"
1404 | },
1405 | "peerDependencies": {
1406 | "bufferutil": "^4.0.1",
1407 | "utf-8-validate": ">=5.0.2"
1408 | },
1409 | "peerDependenciesMeta": {
1410 | "bufferutil": {
1411 | "optional": true
1412 | },
1413 | "utf-8-validate": {
1414 | "optional": true
1415 | }
1416 | }
1417 | },
1418 | "node_modules/socket.io-parser": {
1419 | "version": "4.2.4",
1420 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
1421 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
1422 | "license": "MIT",
1423 | "dependencies": {
1424 | "@socket.io/component-emitter": "~3.1.0",
1425 | "debug": "~4.3.1"
1426 | },
1427 | "engines": {
1428 | "node": ">=10.0.0"
1429 | }
1430 | },
1431 | "node_modules/socket.io-parser/node_modules/debug": {
1432 | "version": "4.3.7",
1433 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1434 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1435 | "license": "MIT",
1436 | "dependencies": {
1437 | "ms": "^2.1.3"
1438 | },
1439 | "engines": {
1440 | "node": ">=6.0"
1441 | },
1442 | "peerDependenciesMeta": {
1443 | "supports-color": {
1444 | "optional": true
1445 | }
1446 | }
1447 | },
1448 | "node_modules/socket.io-parser/node_modules/ms": {
1449 | "version": "2.1.3",
1450 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1451 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1452 | "license": "MIT"
1453 | },
1454 | "node_modules/socket.io/node_modules/debug": {
1455 | "version": "4.3.7",
1456 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1457 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1458 | "license": "MIT",
1459 | "dependencies": {
1460 | "ms": "^2.1.3"
1461 | },
1462 | "engines": {
1463 | "node": ">=6.0"
1464 | },
1465 | "peerDependenciesMeta": {
1466 | "supports-color": {
1467 | "optional": true
1468 | }
1469 | }
1470 | },
1471 | "node_modules/socket.io/node_modules/ms": {
1472 | "version": "2.1.3",
1473 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1474 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1475 | "license": "MIT"
1476 | },
1477 | "node_modules/statuses": {
1478 | "version": "2.0.1",
1479 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1480 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
1481 | "license": "MIT",
1482 | "engines": {
1483 | "node": ">= 0.8"
1484 | }
1485 | },
1486 | "node_modules/supports-color": {
1487 | "version": "5.5.0",
1488 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1489 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1490 | "dev": true,
1491 | "license": "MIT",
1492 | "dependencies": {
1493 | "has-flag": "^3.0.0"
1494 | },
1495 | "engines": {
1496 | "node": ">=4"
1497 | }
1498 | },
1499 | "node_modules/to-regex-range": {
1500 | "version": "5.0.1",
1501 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1502 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1503 | "dev": true,
1504 | "license": "MIT",
1505 | "dependencies": {
1506 | "is-number": "^7.0.0"
1507 | },
1508 | "engines": {
1509 | "node": ">=8.0"
1510 | }
1511 | },
1512 | "node_modules/toidentifier": {
1513 | "version": "1.0.1",
1514 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1515 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1516 | "license": "MIT",
1517 | "engines": {
1518 | "node": ">=0.6"
1519 | }
1520 | },
1521 | "node_modules/touch": {
1522 | "version": "3.1.1",
1523 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
1524 | "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
1525 | "dev": true,
1526 | "license": "ISC",
1527 | "bin": {
1528 | "nodetouch": "bin/nodetouch.js"
1529 | }
1530 | },
1531 | "node_modules/tslib": {
1532 | "version": "2.7.0",
1533 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
1534 | "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
1535 | "license": "0BSD"
1536 | },
1537 | "node_modules/type-is": {
1538 | "version": "1.6.18",
1539 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1540 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1541 | "license": "MIT",
1542 | "dependencies": {
1543 | "media-typer": "0.3.0",
1544 | "mime-types": "~2.1.24"
1545 | },
1546 | "engines": {
1547 | "node": ">= 0.6"
1548 | }
1549 | },
1550 | "node_modules/undefsafe": {
1551 | "version": "2.0.5",
1552 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1553 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1554 | "dev": true,
1555 | "license": "MIT"
1556 | },
1557 | "node_modules/undici-types": {
1558 | "version": "6.20.0",
1559 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
1560 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
1561 | "license": "MIT"
1562 | },
1563 | "node_modules/unpipe": {
1564 | "version": "1.0.0",
1565 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1566 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1567 | "license": "MIT",
1568 | "engines": {
1569 | "node": ">= 0.8"
1570 | }
1571 | },
1572 | "node_modules/utils-merge": {
1573 | "version": "1.0.1",
1574 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1575 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
1576 | "license": "MIT",
1577 | "engines": {
1578 | "node": ">= 0.4.0"
1579 | }
1580 | },
1581 | "node_modules/vary": {
1582 | "version": "1.1.2",
1583 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1584 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1585 | "license": "MIT",
1586 | "engines": {
1587 | "node": ">= 0.8"
1588 | }
1589 | },
1590 | "node_modules/ws": {
1591 | "version": "8.18.0",
1592 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
1593 | "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
1594 | "license": "MIT",
1595 | "engines": {
1596 | "node": ">=10.0.0"
1597 | },
1598 | "peerDependencies": {
1599 | "bufferutil": "^4.0.1",
1600 | "utf-8-validate": ">=5.0.2"
1601 | },
1602 | "peerDependenciesMeta": {
1603 | "bufferutil": {
1604 | "optional": true
1605 | },
1606 | "utf-8-validate": {
1607 | "optional": true
1608 | }
1609 | }
1610 | }
1611 | }
1612 | }
1613 |
--------------------------------------------------------------------------------