Jan 2025 Update
Team Search Improvements: Added required game selection before team name input Added VR Battles image as the main embed image Removed buttons for cleaner display Added sorting by game mode (Squads > Duo > Solo) Made team display more compact with icons and shortened stats Added SQL injection protection and input sanitization User Search Improvements: Made game selection required before username input Added VR Battles image as the main embed image Added better user status messages: played Security Enhancements: Added input validation and sanitization at multiple levels Limited input lengths to prevent buffer overflow Added proper error handling and logging Implemented safe API calls with timeouts and validation Added protection against SQL injection Code Organization: Improved error messages for better user feedback Added comprehensive logging for monitoring Made responses visible to everyone in the channel Cleaned up code structure and removed redundant parts Development Environment: Set up proper development configuration Added environment variable management Improved command deployment process
This commit is contained in:
16
.env.example
Normal file
16
.env.example
Normal file
@@ -0,0 +1,16 @@
|
||||
# Discord Bot Configuration
|
||||
DISCORD_TOKEN=your_dev_bot_token
|
||||
CLIENT_ID=your_dev_client_id
|
||||
|
||||
# Supabase Configuration
|
||||
SUPABASE_URL=your_dev_supabase_url
|
||||
SUPABASE_KEY=your_dev_supabase_key
|
||||
|
||||
# Webhook Configuration (for match notifications)
|
||||
WEBHOOK_SECRET=your_webhook_secret
|
||||
|
||||
# Channel Configuration
|
||||
NOTIFICATION_CHANNEL_ID=your_notification_channel_id
|
||||
|
||||
# Environment
|
||||
NODE_ENV=development
|
||||
37
.gitignore
vendored
37
.gitignore
vendored
@@ -1,4 +1,35 @@
|
||||
node_modules/
|
||||
.env
|
||||
# Environment variables
|
||||
.env
|
||||
/node_modules
|
||||
.env.local
|
||||
.env.*.local
|
||||
.env.development
|
||||
.env.production
|
||||
.env.test
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
88
README.md
Normal file
88
README.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# VRBattles Discord Bot (Development)
|
||||
|
||||
This is the development version of the VRBattles Discord Bot. It connects to the VRBattles API and provides various commands for users to interact with VRBattles data through Discord.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd discord-bot
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Create a `.env` file based on `.env.example`:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
4. Set up your development environment:
|
||||
|
||||
- Create a new Discord Application at https://discord.com/developers/applications
|
||||
- Create a new bot for your application
|
||||
- Get your bot token and client ID
|
||||
- Create a new Supabase project at https://supabase.com
|
||||
- Get your Supabase URL and anon key
|
||||
|
||||
5. Update your `.env` file with the development credentials:
|
||||
```env
|
||||
DISCORD_TOKEN=your_dev_bot_token
|
||||
CLIENT_ID=your_dev_client_id
|
||||
SUPABASE_URL=your_dev_supabase_url
|
||||
SUPABASE_KEY=your_dev_supabase_key
|
||||
NODE_ENV=development
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Start the bot in development mode:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Deploy slash commands to your development Discord server:
|
||||
```bash
|
||||
npm run deploy-commands:dev
|
||||
```
|
||||
|
||||
## Available Commands
|
||||
|
||||
- `/ping` - Test bot connectivity
|
||||
- `/finduser` - Find a user by username
|
||||
- `/matchhistory` - View match history
|
||||
- `/findteam` - Find a team by name
|
||||
- `/subscribe` - Subscribe to game notifications (Admin only)
|
||||
- `/unsubscribe` - Unsubscribe from game notifications (Admin only)
|
||||
- `/register_server` - Register Discord server with BattleBot (Admin only)
|
||||
- `/list_subscriptions` - List all game subscriptions (Admin only)
|
||||
|
||||
## API Integration
|
||||
|
||||
The bot connects to the following APIs:
|
||||
- VRBattles API (`https://www.vrbattles.gg/api/`)
|
||||
- Discord API (via discord.js)
|
||||
- Supabase Database
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Create a new branch for your feature:
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
2. Make your changes and commit them:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Description of your changes"
|
||||
```
|
||||
|
||||
3. Push to your branch:
|
||||
```bash
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
|
||||
4. Create a Pull Request to merge into the dev branch
|
||||
@@ -10,15 +10,25 @@ const commands = [
|
||||
.setDescription("Find a user by username")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("username")
|
||||
.setDescription("The username to search for")
|
||||
.setName("game")
|
||||
.setDescription("Select the game")
|
||||
.setRequired(true)
|
||||
.addChoices(
|
||||
{ name: "Big Ballers VR", value: "Big Ballers VR" },
|
||||
{ name: "Blacktop Hoops", value: "Blacktop Hoops" },
|
||||
{ name: "Breachers", value: "Breachers" },
|
||||
{ name: "Echo Arena", value: "Echo Arena" },
|
||||
{ name: "Echo Combat", value: "Echo Combat" },
|
||||
{ name: "Gun Raiders", value: "Gun Raiders" },
|
||||
{ name: "Nock", value: "Nock" },
|
||||
{ name: "VAIL", value: "VAIL" }
|
||||
)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("game")
|
||||
.setDescription("Specify a game to view stats for")
|
||||
.setRequired(false)
|
||||
.setName("username")
|
||||
.setDescription("The username to search for")
|
||||
.setRequired(true)
|
||||
),
|
||||
new SlashCommandBuilder()
|
||||
.setName("matchhistory")
|
||||
@@ -89,17 +99,11 @@ const commands = [
|
||||
new SlashCommandBuilder()
|
||||
.setName("findteam")
|
||||
.setDescription("Find a team by name")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("teamname")
|
||||
.setDescription("The team name to search for")
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("game")
|
||||
.setDescription("Filter by game")
|
||||
.setRequired(false)
|
||||
.setDescription("Select the game")
|
||||
.setRequired(true)
|
||||
.addChoices(
|
||||
{ name: "Big Ballers VR", value: "Big Ballers VR" },
|
||||
{ name: "Blacktop Hoops", value: "Blacktop Hoops" },
|
||||
@@ -110,6 +114,12 @@ const commands = [
|
||||
{ name: "Nock", value: "Nock" },
|
||||
{ name: "VAIL", value: "VAIL" }
|
||||
)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("teamname")
|
||||
.setDescription("The team name to search for")
|
||||
.setRequired(true)
|
||||
),
|
||||
];
|
||||
|
||||
|
||||
358
node_modules/.package-lock.json
generated
vendored
358
node_modules/.package-lock.json
generated
vendored
@@ -317,6 +317,20 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
@@ -346,6 +360,26 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
@@ -370,6 +404,30 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@@ -398,6 +456,31 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
@@ -455,6 +538,13 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@@ -700,6 +790,19 @@
|
||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
@@ -804,6 +907,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
@@ -816,6 +932,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
@@ -892,6 +1018,13 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@@ -913,6 +1046,52 @@
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
@@ -1032,6 +1211,19 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -1047,6 +1239,70 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
|
||||
"integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/debug": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
@@ -1095,6 +1351,19 @@
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -1114,6 +1383,13 @@
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
@@ -1167,6 +1443,19 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -1202,6 +1491,19 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
@@ -1306,6 +1608,19 @@
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
@@ -1333,12 +1648,38 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@@ -1348,6 +1689,16 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
@@ -1388,6 +1739,13 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
|
||||
|
||||
376
package-lock.json
generated
376
package-lock.json
generated
@@ -16,6 +16,9 @@
|
||||
"express": "^4.21.1",
|
||||
"undici": "^6.19.8",
|
||||
"winston": "^3.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
@@ -331,6 +334,20 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
@@ -360,6 +377,26 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
@@ -384,6 +421,30 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@@ -412,6 +473,31 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
@@ -469,6 +555,13 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@@ -714,6 +807,19 @@
|
||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
@@ -790,6 +896,21 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -818,6 +939,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
@@ -830,6 +964,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
@@ -906,6 +1050,13 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@@ -927,6 +1078,52 @@
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
@@ -1046,6 +1243,19 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@@ -1061,6 +1271,70 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
|
||||
"integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/debug": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
@@ -1109,6 +1383,19 @@
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -1128,6 +1415,13 @@
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
@@ -1181,6 +1475,19 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -1216,6 +1523,19 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
@@ -1320,6 +1640,19 @@
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
@@ -1347,12 +1680,38 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@@ -1362,6 +1721,16 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
@@ -1402,6 +1771,13 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
|
||||
|
||||
10
package.json
10
package.json
@@ -3,8 +3,11 @@
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test:webhook": "NODE_ENV=test node src/test/testWebhook.js"
|
||||
"start": "node -r dotenv/config index.js dotenv_config_path=.env.production",
|
||||
"dev": "nodemon -r dotenv/config index.js dotenv_config_path=.env.development",
|
||||
"deploy-commands": "node -r dotenv/config deploy-commands.js dotenv_config_path=.env.production",
|
||||
"deploy-commands:dev": "node -r dotenv/config deploy-commands.js dotenv_config_path=.env.development",
|
||||
"test:webhook": "node -r dotenv/config src/test/testWebhook.js dotenv_config_path=.env.test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@@ -18,5 +21,8 @@
|
||||
"express": "^4.21.1",
|
||||
"undici": "^6.19.8",
|
||||
"winston": "^3.17.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,10 +151,40 @@ class CommandHandler {
|
||||
const username = interaction.options.getString('username');
|
||||
const gameFilter = interaction.options.getString('game');
|
||||
|
||||
const userData = await this.playerService.findUserByUsername(username);
|
||||
// Input validation
|
||||
if (!username || typeof username !== 'string') {
|
||||
await interaction.editReply({
|
||||
content: '❌ Invalid username provided.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Enhanced sanitization
|
||||
const sanitizedUsername = username
|
||||
.replace(/[^a-zA-Z0-9\s\-_.]/g, '')
|
||||
.trim()
|
||||
.slice(0, 100);
|
||||
|
||||
if (!sanitizedUsername) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Username must contain valid characters (letters, numbers, spaces, hyphens, underscores, or periods).'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Log sanitized input for monitoring
|
||||
this.logger.debug('User search input:', {
|
||||
original: username,
|
||||
sanitized: sanitizedUsername,
|
||||
game: gameFilter,
|
||||
userId: interaction.user.id,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
const userData = await this.playerService.findUserByUsername(sanitizedUsername);
|
||||
if (!userData || !userData.success) {
|
||||
await interaction.editReply({
|
||||
content: '❌ User not found or an error occurred while fetching data.',
|
||||
content: '❌ User not found or an error occurred while fetching data.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -163,20 +193,43 @@ class CommandHandler {
|
||||
? JSON.parse(userData.player_data)
|
||||
: userData.player_data;
|
||||
|
||||
// Check if the user is on a team for the specified game
|
||||
const isOnTeam = playerData.teams && Object.values(playerData.teams)
|
||||
.some(team => team.game_name === gameFilter);
|
||||
|
||||
// Check if the user has played the specified game
|
||||
const hasPlayedGame = playerData.stats?.games &&
|
||||
Object.keys(playerData.stats.games)
|
||||
.some(game => game.toLowerCase() === gameFilter.toLowerCase());
|
||||
|
||||
if (!hasPlayedGame) {
|
||||
const teamMessage = isOnTeam ?
|
||||
`\nThey are on a team for ${gameFilter} but haven't played any matches yet.` :
|
||||
'';
|
||||
await interaction.editReply({
|
||||
content: `✅ User found, but they haven't played ${gameFilter} yet.${teamMessage}`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = EmbedBuilders.createUserEmbed(playerData, gameFilter, this.playerService);
|
||||
const row = this.createActionRow(playerData.username);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [embed],
|
||||
components: [row],
|
||||
components: [row]
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error('Error in handleFindUser:', {
|
||||
error: error.message,
|
||||
username: interaction.options.getString('username'),
|
||||
game: interaction.options.getString('game'),
|
||||
userId: interaction.user.id,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
throw error;
|
||||
await interaction.editReply({
|
||||
content: '❌ An error occurred while searching for the user.'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,47 +278,64 @@ class CommandHandler {
|
||||
const teamName = interaction.options.getString('teamname');
|
||||
const gameFilter = interaction.options.getString('game');
|
||||
|
||||
const teamData = await this.playerService.findTeamByName(teamName, gameFilter);
|
||||
if (!teamData || !teamData.success || !teamData.teams || teamData.teams.length === 0) {
|
||||
// Input validation
|
||||
if (!teamName || typeof teamName !== 'string') {
|
||||
await interaction.editReply({
|
||||
content: '❌ No teams found matching your search criteria.',
|
||||
content: '❌ Invalid team name provided.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const embed = EmbedBuilders.createTeamEmbed(teamData.teams);
|
||||
// Enhanced sanitization - only allow alphanumeric characters, spaces, and specific symbols
|
||||
// Limit the length to prevent buffer overflow attacks
|
||||
const sanitizedTeamName = teamName
|
||||
.replace(/[^a-zA-Z0-9\s\-_.]/g, '') // Remove any characters that aren't alphanumeric, space, hyphen, underscore, or period
|
||||
.trim()
|
||||
.slice(0, 100); // Limit length to 100 characters
|
||||
|
||||
// Create buttons for each team
|
||||
const rows = teamData.teams.slice(0, 5).map(team => {
|
||||
return new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel(`🔵 View ${team.name} (${team.game_mode})`)
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL(`${this.playerService.baseUrl}/teams/${team.id}`),
|
||||
);
|
||||
if (!sanitizedTeamName) {
|
||||
await interaction.editReply({
|
||||
content: '❌ Team name must contain valid characters (letters, numbers, spaces, hyphens, underscores, or periods).'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Log sanitized input for monitoring
|
||||
this.logger.debug('Team search input:', {
|
||||
original: teamName,
|
||||
sanitized: sanitizedTeamName,
|
||||
game: gameFilter,
|
||||
userId: interaction.user.id,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Add Discord join button in a separate row
|
||||
rows.push(
|
||||
new ActionRowBuilder().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('🟡 Join Discord')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL('https://discord.gg/j3DKVATPGQ')
|
||||
)
|
||||
);
|
||||
// Game filter is pre-validated by Discord's slash command choices
|
||||
const teamData = await this.playerService.findTeamByName(sanitizedTeamName, gameFilter);
|
||||
|
||||
if (!teamData || !teamData.success || !teamData.teams || teamData.teams.length === 0) {
|
||||
await interaction.editReply({
|
||||
content: '❌ No teams found matching your search criteria.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const embeds = EmbedBuilders.createTeamEmbed(teamData.teams);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [embed],
|
||||
components: rows,
|
||||
embeds: embeds,
|
||||
components: []
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error('Error in handleFindTeam:', {
|
||||
error: error.message,
|
||||
teamname: interaction.options.getString('teamname'),
|
||||
teamName: interaction.options.getString('teamname'),
|
||||
game: interaction.options.getString('game'),
|
||||
userId: interaction.user.id,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
throw error;
|
||||
await interaction.editReply({
|
||||
content: '❌ An error occurred while searching for teams.'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,35 +70,59 @@ class PlayerService {
|
||||
return `${this.baseUrl}/profile/${username}/stats`;
|
||||
}
|
||||
|
||||
async findTeamByName(teamName, gameFilter = null) {
|
||||
async findTeamByName(teamName, gameFilter) {
|
||||
try {
|
||||
console.log(`Fetching team data for: ${teamName}${gameFilter ? ` in ${gameFilter}` : ''}`);
|
||||
const url = `${this.baseUrl}/api/get_team_data_by_name/${encodeURIComponent(teamName)}`;
|
||||
console.log(`API URL: ${url}`);
|
||||
|
||||
const response = await axios.get(url, {
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
console.log('API Response:', JSON.stringify(response.data, null, 2));
|
||||
|
||||
if (response.data && response.data.success) {
|
||||
// Filter teams by game if gameFilter is provided
|
||||
if (gameFilter && response.data.teams) {
|
||||
response.data.teams = response.data.teams.filter(
|
||||
team => team.game_name.toLowerCase() === gameFilter.toLowerCase()
|
||||
);
|
||||
}
|
||||
// Double-check sanitization here as well for defense in depth
|
||||
if (!teamName || typeof teamName !== 'string') {
|
||||
throw new Error('Invalid team name provided');
|
||||
}
|
||||
|
||||
|
||||
// Additional sanitization at the service level
|
||||
const sanitizedTeamName = teamName
|
||||
.replace(/[^a-zA-Z0-9\s\-_.]/g, '')
|
||||
.trim()
|
||||
.slice(0, 100);
|
||||
|
||||
if (!sanitizedTeamName) {
|
||||
throw new Error('Invalid team name after sanitization');
|
||||
}
|
||||
|
||||
// Use URL encoding for the query parameters
|
||||
const encodedTeamName = encodeURIComponent(sanitizedTeamName);
|
||||
const url = `${this.baseUrl}/api/get_team_data_by_name/${encodedTeamName}`;
|
||||
|
||||
const response = await axios.get(url, {
|
||||
timeout: 5000, // 5 second timeout
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
validateStatus: function (status) {
|
||||
return status >= 200 && status < 300; // Only accept success status codes
|
||||
}
|
||||
});
|
||||
|
||||
// Validate response structure
|
||||
if (!response.data || typeof response.data !== 'object') {
|
||||
throw new Error('Invalid response format from API');
|
||||
}
|
||||
|
||||
// If game filter is provided, filter the teams
|
||||
if (gameFilter && response.data.teams) {
|
||||
response.data.teams = response.data.teams.filter(
|
||||
team => team.game_name === gameFilter
|
||||
);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching team data:', {
|
||||
message: error.message,
|
||||
response: error.response?.data,
|
||||
status: error.response?.status
|
||||
this.logger.error('Error in findTeamByName:', {
|
||||
error: error.message,
|
||||
teamName,
|
||||
gameFilter,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
return null;
|
||||
return { success: false, error: 'Failed to fetch team data' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ class EmbedBuilders {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(`User: ${playerData.username || 'Unknown'}`)
|
||||
.setDescription(profile.bio || 'No bio available')
|
||||
.setColor('#0099ff');
|
||||
.setColor('#0099ff')
|
||||
.setImage('https://www.vrbattles.gg/assets/images/Qubi/vrwearcubesatad.png');
|
||||
|
||||
// Add thumbnail (avatar)
|
||||
if (profile.avatar) {
|
||||
@@ -15,12 +16,6 @@ class EmbedBuilders {
|
||||
);
|
||||
}
|
||||
|
||||
// Add badge image using PlayerService
|
||||
if (profile.current_level_badge) {
|
||||
const badgeImageUrl = playerService.getBadgeImageUrl(profile.current_level_badge);
|
||||
embed.setImage(badgeImageUrl);
|
||||
}
|
||||
|
||||
// Add profile fields
|
||||
const profileFields = [];
|
||||
if (profile.country) profileFields.push({ name: 'Country', value: profile.country, inline: true });
|
||||
@@ -210,73 +205,71 @@ class EmbedBuilders {
|
||||
}
|
||||
|
||||
static createTeamEmbed(teams) {
|
||||
const embed = new EmbedBuilder()
|
||||
const embeds = [];
|
||||
const infoEmbed = new EmbedBuilder()
|
||||
.setTitle(`Teams Found`)
|
||||
.setColor('#0099ff');
|
||||
.setColor('#0099ff')
|
||||
.setImage('https://www.vrbattles.gg/assets/images/Qubi/vrwearcubesatad.png');
|
||||
|
||||
if (!teams || teams.length === 0) {
|
||||
embed.setDescription('No teams found');
|
||||
return embed;
|
||||
infoEmbed.setDescription('No teams found');
|
||||
return [infoEmbed];
|
||||
}
|
||||
|
||||
// Sort teams by date created (newest first)
|
||||
teams.sort((a, b) => new Date(b.date_created) - new Date(a.date_created));
|
||||
// Sort teams by game mode priority and date
|
||||
const gameModeOrder = {
|
||||
'Squads': 1,
|
||||
'Duo': 2,
|
||||
'Solo': 3
|
||||
};
|
||||
|
||||
teams.sort((a, b) => {
|
||||
const modeA = gameModeOrder[a.game_mode] || 999;
|
||||
const modeB = gameModeOrder[b.game_mode] || 999;
|
||||
if (modeA !== modeB) return modeA - modeB;
|
||||
return new Date(b.date_created) - new Date(a.date_created);
|
||||
});
|
||||
|
||||
teams.forEach((team, index) => {
|
||||
// Add team header
|
||||
embed.addFields({
|
||||
name: `${index + 1}. ${team.name} - ${team.game_name} (${team.game_mode})`,
|
||||
value: '\u200B'
|
||||
const modeIcon = team.game_mode === 'Squads' ? '🎮' :
|
||||
team.game_mode === 'Duo' ? '🎯' : '⚔️';
|
||||
|
||||
// Combine stats into a single line
|
||||
const stats = [];
|
||||
if (team.matches) stats.push(`M:${team.matches}`);
|
||||
if (team.wins) stats.push(`W:${team.wins}`);
|
||||
if (team.losses) stats.push(`L:${team.losses}`);
|
||||
const winRate = team.matches > 0 ?
|
||||
((parseInt(team.wins) / parseInt(team.matches)) * 100).toFixed(1) : 0;
|
||||
stats.push(`WR:${winRate}%`);
|
||||
|
||||
// Create team header with stats
|
||||
let teamInfo = `${modeIcon} **${team.name}** (${team.game_name} ${team.game_mode})\n`;
|
||||
teamInfo += `📊 ${stats.join(' | ')}`;
|
||||
|
||||
// Add players if available
|
||||
if (team.players?.length > 0) {
|
||||
teamInfo += `\n👥 ${team.players.map(p => p.username).join(', ')}`;
|
||||
}
|
||||
|
||||
// Add logo link if available
|
||||
if (team.logo) {
|
||||
teamInfo += `\n🎨 [View Logo](${team.logo})`;
|
||||
}
|
||||
|
||||
infoEmbed.addFields({
|
||||
name: `Team ${index + 1}`,
|
||||
value: teamInfo
|
||||
});
|
||||
|
||||
// Add team stats
|
||||
const statsFields = [];
|
||||
if (team.matches) statsFields.push(`Matches: ${team.matches}`);
|
||||
if (team.wins) statsFields.push(`Wins: ${team.wins}`);
|
||||
if (team.losses) statsFields.push(`Losses: ${team.losses}`);
|
||||
if (team.forfeits) statsFields.push(`Forfeits: ${team.forfeits}`);
|
||||
|
||||
const winRate = team.matches > 0
|
||||
? ((parseInt(team.wins) / parseInt(team.matches)) * 100).toFixed(1)
|
||||
: 0;
|
||||
|
||||
if (statsFields.length > 0) {
|
||||
embed.addFields({
|
||||
name: 'Stats',
|
||||
value: `${statsFields.join(' | ')} | Win Rate: ${winRate}%`,
|
||||
inline: false
|
||||
});
|
||||
}
|
||||
|
||||
// Add team members
|
||||
if (team.players && team.players.length > 0) {
|
||||
const playerList = team.players
|
||||
.map(player => `- ${player.username} (${player.position})`)
|
||||
.join('\n');
|
||||
|
||||
embed.addFields({
|
||||
name: 'Players',
|
||||
value: playerList,
|
||||
inline: false
|
||||
});
|
||||
}
|
||||
|
||||
// Add team creation date
|
||||
if (team.date_created) {
|
||||
embed.addFields({
|
||||
name: 'Created',
|
||||
value: new Date(team.date_created).toLocaleDateString(),
|
||||
inline: true
|
||||
});
|
||||
}
|
||||
|
||||
// Add separator between teams
|
||||
// Add small separator if not the last team
|
||||
if (index < teams.length - 1) {
|
||||
embed.addFields({ name: '\u200B', value: '\u200B' });
|
||||
infoEmbed.addFields({ name: '\u200B', value: '▬▬▬▬▬▬▬▬▬▬', inline: false });
|
||||
}
|
||||
});
|
||||
|
||||
return embed;
|
||||
embeds.push(infoEmbed);
|
||||
return embeds;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user