diff --git a/.gitignore b/.gitignore index 3d70248ba2..8cf56356dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,22 @@ +# Dependencies node_modules -.DS_Store + +# Environment variables .env .env.local .env.development.local .env.test.local .env.production.local +# Build outputs build +dist +# Logs npm-debug.log* yarn-debug.log* yarn-error.log* -package-lock.json \ No newline at end of file +# System files +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/README.md b/README.md index 31466b54c2..61efd924cd 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,48 @@ -# Final Project +# Banganza -Replace this readme with your own information about your project. +Banganza is a multiplayer quiz game where teams drag and drop cards on a timeline. +Built with **React, TypeScript, and Node.js**. -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +--- -## The problem +## Features +- Intro animation with video +- Category selector with icons +- Drag & drop timeline gameplay +- Admin panel to manage categories and items +- Fully responsive & accessible design -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +--- -## View it live +## Example Data +Example of an item that can be added via the admin panel: -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. \ No newline at end of file +```json +{ + "id": "net-1", + "name": "Dancing Baby", + "label": "Year 1996", + "value": 1996, + "categoryId": "internet.phenomena.year" +} +``` + + +## Tech Stack +**Frontend:** React 18, TypeScript, Tailwind, dnd-kit +**Backend:** Node.js, Express, MongoDB +**Other:** JWT auth, Netlify/Render deployment + + +## Run locally +```bash +git clone https://github.com/username/project-final.git +cd project-final +npm install +npm run dev +``` + + +## Live Demo +👉 Play Banganza [here]([url](https://banganza.netlify.app/)) +https://banganza.netlify.app/ diff --git a/backend/.eslintrc.json b/backend/.eslintrc.json new file mode 100644 index 0000000000..a31a73f74f --- /dev/null +++ b/backend/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "module" + }, + "rules": { + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-explicit-any": "warn", + "prefer-const": "error", + "no-console": "off" + }, + "env": { + "node": true, + "es2022": true + } +} \ No newline at end of file diff --git a/backend/README.md b/backend/README.md index d1438c9108..335fa1620e 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,8 +1,148 @@ -# Backend part of Final Project +# Backend API Server -This project includes the packages and babel setup for an express server, and is just meant to make things a little simpler to get up and running with. +A Node.js/Express/TypeScript backend server for the Banganza quiz application. -## Getting Started +## Architecture -1. Install the required dependencies using `npm install`. -2. Start the development server using `npm run dev`. \ No newline at end of file +The backend follows a clean, layered architecture: + +``` +src/ +├── config/ # Configuration files +├── controllers/ # Request handlers +├── middleware/ # Express middleware +├── models/ # Mongoose models +├── routes/ # API route definitions +├── services/ # Business logic services +├── types/ # TypeScript type definitions +``` + + +## Installation + +1. Install dependencies: +```bash +npm install +``` + +2. Create a `.env` file + +3. Configure environment variables in `.env`: +```env +MONGODB_URI=mongodb://localhost:27017/your_database +PORT=8888 +NODE_ENV=development +FRONTEND_URI=http://127.0.0.1:5173 +JWT_SECRET=your_secure_jwt_secret +ADMIN_USERNAME=admin +ADMIN_PASSWORD=secure_password +ADMIN_EMAIL=admin@example.com +``` + +## Running the Server + +### Development +```bash +npm run dev +``` + +### Production +```bash +npm run build +npm start +``` + +### Database Seeding +```bash +npm run seed +``` + +### Create Admin User +```bash +npm run create-admin +``` + +## 🔧 Available Scripts + +- `npm run dev` - Start development server with hot reload +- `npm run build` - Build TypeScript to JavaScript +- `npm start` - Start production server +- `npm run lint` - Run ESLint +- `npm run lint:fix` - Fix ESLint issues +- `npm run type-check` - Type check without building +- `npm run seed` - Seed database with sample data +- `npm run create-admin` - Create initial admin user + +## API Endpoints + +### Public Endpoints +- `GET /` - Health check +- `GET /health` - Detailed health status +- `GET /api/quiz/categories` - Get all quiz categories +- `GET /api/quiz/category/:categoryId/items` - Get all items for a category +- `POST /api/quiz/check` - Check quiz answers + +### Protected Endpoints (Admin) +- `POST /api/admin/login` - Admin authentication +- `GET /api/admin/profile` - Get admin profile +- `POST /api/admin/logout` - Admin logout +- `GET /api/admin/categories` - Get all categories +- `POST /api/admin/categories` - Create category +- `PUT /api/admin/categories/:id` - Update category +- `DELETE /api/admin/categories/:id` - Delete category +- `GET /api/admin/items` - Get all items +- `POST /api/admin/items` - Create item +- `PUT /api/admin/items/:id` - Update item +- `DELETE /api/admin/items/:id` - Delete item + +## Authentication + +Admin endpoints require JWT authentication. Include the token in the Authorization header: + +``` +Authorization: Bearer +``` + +## Response Format + +All API responses follow a consistent format: + +### Success Response +```json +{ + "success": true, + "data": { ... }, + "meta": { + "timestamp": "2024-01-01T00:00:00.000Z", + "path": "/api/endpoint", + "method": "GET" + } +} +``` + +### Error Response +```json +{ + "success": false, + "error": { + "message": "Error description", + "code": "ERROR_CODE", + "details": { ... } + }, + "meta": { ... } +} +``` + +## Database Models + +### Admin +- Username, password, email +- Active status and last login tracking + +### Category +- ID, name, description, question +- Unit, sort order, source information + +### Item +- ID, name, value, label +- Category reference and source \ No newline at end of file diff --git a/backend/data/categories/animals.json b/backend/data/categories/animals.json new file mode 100644 index 0000000000..09d1f2e5d5 --- /dev/null +++ b/backend/data/categories/animals.json @@ -0,0 +1,14 @@ +{ + "id": "animals.weight", + "name": "Animals", + "description": "Quiz about animal weights in kilograms", + "question": "Which animal weighs the most?", + "unit": "kg", + "unitVisible": true, + "sort": "desc", + "source": { + "name": "Wikipedia (largest animals, species pages)", + "url": "https://en.wikipedia.org/wiki/List_of_largest_organisms" + }, + "version": 1 +} diff --git a/backend/data/categories/celebrities.json b/backend/data/categories/celebrities.json new file mode 100644 index 0000000000..23e2f34a51 --- /dev/null +++ b/backend/data/categories/celebrities.json @@ -0,0 +1,14 @@ +{ + "id": "celebrities.age", + "name": "Celebrities", + "description": "Oldest to Youngest Celebrities", + "question": "What year was the celebrity born in?", + "unit": "year", + "unitVisible": false, + "sort": "desc", + "source": { + "name": "", + "url": "" + }, + "version": 1 +} diff --git a/backend/data/categories/countries.coastline.json b/backend/data/categories/countries.coastline.json new file mode 100644 index 0000000000..0ee5d0d81b --- /dev/null +++ b/backend/data/categories/countries.coastline.json @@ -0,0 +1,14 @@ +{ + "id": "countries.coastline", + "name": "Coastlines", + "description": "Quiz about coastline lengths (km) for sovereign countries (CIA World Factbook methodology)", + "question": "Which country has the longest coastline?", + "unit": "km", + "unitVisible": true, + "sort": "desc", + "source": { + "name": "CIA World Factbook (2023 archive)", + "url": "https://www.cia.gov/the-world-factbook/about/archives/2023/field/coastline" + }, + "version": 1 +} \ No newline at end of file diff --git a/backend/data/categories/elements.json b/backend/data/categories/elements.json new file mode 100644 index 0000000000..4dfe5f600a --- /dev/null +++ b/backend/data/categories/elements.json @@ -0,0 +1,14 @@ +{ + "id": "elements.atomicnumber", + "name": "Elements", + "description": "Quiz about chemical elements and their atomic numbers", + "question": "Which element has the lowest atomic number?", + "unit": "", + "unitVisible": false, + "sort": "asc", + "source": { + "name": "IUPAC, Periodic Table", + "url": "https://en.wikipedia.org/wiki/List_of_chemical_elements" + }, + "version": 1 +} diff --git a/backend/data/categories/games.json b/backend/data/categories/games.json new file mode 100644 index 0000000000..44a959f2c0 --- /dev/null +++ b/backend/data/categories/games.json @@ -0,0 +1,14 @@ +{ + "id": "games.releaseyear", + "name": "Console Games", + "description": "Quiz about release years of popular console games", + "question": "What year was the game released?", + "unit": "year", + "unitVisible": false, + "sort": "desc", + "source": { + "name": "Wikipedia, IGN, GameSpot", + "url": "https://en.wikipedia.org/wiki/List_of_best-selling_video_games" + }, + "version": 1 +} diff --git a/backend/data/categories/internet.json b/backend/data/categories/internet.json new file mode 100644 index 0000000000..709142fe7b --- /dev/null +++ b/backend/data/categories/internet.json @@ -0,0 +1,14 @@ +{ + "id": "internet.phenomena.year", + "name": "Internet Phenomena", + "description": "Quiz about viral internet phenomena and the year they peaked", + "question": "Which internet phenomenon happened first?", + "unit": "year", + "unitVisible": false, + "sort": "asc", + "source": { + "name": "Wikipedia, Know Your Meme", + "url": "https://knowyourmeme.com/" + }, + "version": 1 +} diff --git a/backend/data/items/animals.items.json b/backend/data/items/animals.items.json new file mode 100644 index 0000000000..c9824a5f7f --- /dev/null +++ b/backend/data/items/animals.items.json @@ -0,0 +1,458 @@ +[ + { + "id": "animal-1", + "name": "Blue Whale", + "label": "Weight 150000 kg", + "value": 150000, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-2", + "name": "Sperm Whale", + "label": "Weight 57000 kg", + "value": 57000, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-3", + "name": "Whale Shark", + "label": "Weight 19000 kg", + "value": 19000, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-4", + "name": "Orca", + "label": "Weight 6000 kg", + "value": 6000, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-5", + "name": "African Elephant", + "label": "Weight 6000 kg", + "value": 6000, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-6", + "name": "Hippopotamus", + "label": "Weight 1500 kg", + "value": 1500, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-7", + "name": "Giraffe", + "label": "Weight 1200 kg", + "value": 1200, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-8", + "name": "Great White Shark", + "label": "Weight 1100 kg", + "value": 1100, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-9", + "name": "Bison", + "label": "Weight 900 kg", + "value": 900, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-10", + "name": "Cow", + "label": "Weight 750 kg", + "value": 750, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-11", + "name": "Moose", + "label": "Weight 700 kg", + "value": 700, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-12", + "name": "Polar Bear", + "label": "Weight 650 kg", + "value": 650, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-13", + "name": "Horse", + "label": "Weight 600 kg", + "value": 600, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-14", + "name": "Grizzly Bear", + "label": "Weight 360 kg", + "value": 360, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-15", + "name": "Alligator", + "label": "Weight 230 kg", + "value": 230, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-16", + "name": "Tiger", + "label": "Weight 220 kg", + "value": 220, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-17", + "name": "Sea Lion", + "label": "Weight 200 kg", + "value": 200, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-18", + "name": "Lion", + "label": "Weight 190 kg", + "value": 190, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-19", + "name": "Gorilla", + "label": "Weight 160 kg", + "value": 160, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-20", + "name": "Ostrich", + "label": "Weight 104 kg", + "value": 104, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-21", + "name": "Giant Panda", + "label": "Weight 100 kg", + "value": 100, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-22", + "name": "Human", + "label": "Weight 70 kg", + "value": 70, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-23", + "name": "Kangaroo", + "label": "Weight 60 kg", + "value": 60, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-24", + "name": "Wolf", + "label": "Weight 50 kg", + "value": 50, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-25", + "name": "Cheetah", + "label": "Weight 35 kg", + "value": 35, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-26", + "name": "Swan", + "label": "Weight 12 kg", + "value": 12, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-27", + "name": "Chicken", + "label": "Weight 1 kg", + "value": 1, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-28", + "name": "Komodo Dragon", + "label": "Weight 70 kg", + "value": 70, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-29", + "name": "Emperor Penguin", + "label": "Weight 30 kg", + "value": 30, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-30", + "name": "Golden Eagle", + "label": "Weight 6 kg", + "value": 6, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-31", + "name": "Bald Eagle", + "label": "Weight 5 kg", + "value": 5, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-32", + "name": "Koala", + "label": "Weight 12 kg", + "value": 12, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-33", + "name": "Sloth", + "label": "Weight 6 kg", + "value": 6, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-34", + "name": "Red Fox", + "label": "Weight 8 kg", + "value": 8, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-35", + "name": "Snow Leopard", + "label": "Weight 32 kg", + "value": 32, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-36", + "name": "Puma", + "label": "Weight 70 kg", + "value": 70, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-37", + "name": "Hyena", + "label": "Weight 60 kg", + "value": 60, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-38", + "name": "Crocodile", + "label": "Weight 500 kg", + "value": 500, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-39", + "name": "Anaconda", + "label": "Weight 250 kg", + "value": 250, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-40", + "name": "Komodo Dragon Hatchling", + "label": "Weight 0.1 kg", + "value": 0.1, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-41", + "name": "Albatross", + "label": "Weight 8 kg", + "value": 8, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-42", + "name": "Puffin", + "label": "Weight 0.5 kg", + "value": 0.5, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-43", + "name": "Octopus", + "label": "Weight 15 kg", + "value": 15, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-44", + "name": "Giant Squid", + "label": "Weight 275 kg", + "value": 275, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-45", + "name": "Manta Ray", + "label": "Weight 1350 kg", + "value": 1350, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-46", + "name": "Stingray", + "label": "Weight 300 kg", + "value": 300, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-47", + "name": "Walrus", + "label": "Weight 1000 kg", + "value": 1000, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-48", + "name": "Seal", + "label": "Weight 150 kg", + "value": 150, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-49", + "name": "Lynx", + "label": "Weight 20 kg", + "value": 20, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-50", + "name": "Hedgehog", + "label": "Weight 1 kg", + "value": 1, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-51", + "name": "Rabbit", + "label": "Weight 2 kg", + "value": 2, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-52", + "name": "House Cat", + "label": "Weight 4 kg", + "value": 4, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-53", + "name": "Dog (Labrador)", + "label": "Weight 30 kg", + "value": 30, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-54", + "name": "Guinea Pig", + "label": "Weight 1 kg", + "value": 1, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-55", + "name": "Hamster", + "label": "Weight 0.1 kg", + "value": 0.1, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-56", + "name": "Mouse", + "label": "Weight 0.02 kg", + "value": 0.02, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + }, + { + "id": "animal-57", + "name": "Blue Jay", + "label": "Weight 0.1 kg", + "value": 0.1, + "categoryId": "animals.weight", + "source": { "name": "Wikipedia" } + } +] diff --git a/backend/data/items/celebrities.items.json b/backend/data/items/celebrities.items.json new file mode 100644 index 0000000000..0f28f64328 --- /dev/null +++ b/backend/data/items/celebrities.items.json @@ -0,0 +1,802 @@ +[ + { + "id": "celeb-1", + "name": "Morgan Freeman", + "label": "Born 1937", + "value": 1937, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-2", + "name": "Betty White", + "label": "Born 1922", + "value": 1922, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-3", + "name": "Clint Eastwood", + "label": "Born 1930", + "value": 1930, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-4", + "name": "Judi Dench", + "label": "Born 1934", + "value": 1934, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-5", + "name": "Jack Nicholson", + "label": "Born 1937", + "value": 1937, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-6", + "name": "Sophia Loren", + "label": "Born 1934", + "value": 1934, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-7", + "name": "Robert Redford", + "label": "Born 1936", + "value": 1936, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-8", + "name": "Jane Fonda", + "label": "Born 1937", + "value": 1937, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-9", + "name": "Dustin Hoffman", + "label": "Born 1937", + "value": 1937, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-10", + "name": "Al Pacino", + "label": "Born 1940", + "value": 1940, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-11", + "name": "Harrison Ford", + "label": "Born 1942", + "value": 1942, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-12", + "name": "Michael Caine", + "label": "Born 1933", + "value": 1933, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-13", + "name": "Julie Andrews", + "label": "Born 1935", + "value": 1935, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-14", + "name": "Anthony Hopkins", + "label": "Born 1937", + "value": 1937, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-15", + "name": "Helen Mirren", + "label": "Born 1945", + "value": 1945, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-16", + "name": "Meryl Streep", + "label": "Born 1949", + "value": 1949, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-17", + "name": "Denzel Washington", + "label": "Born 1954", + "value": 1954, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-18", + "name": "Tom Hanks", + "label": "Born 1956", + "value": 1956, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-19", + "name": "George Clooney", + "label": "Born 1961", + "value": 1961, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-20", + "name": "Brad Pitt", + "label": "Born 1963", + "value": 1963, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-21", + "name": "Sandra Bullock", + "label": "Born 1964", + "value": 1964, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-22", + "name": "Johnny Depp", + "label": "Born 1963", + "value": 1963, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-23", + "name": "Leonardo DiCaprio", + "label": "Born 1974", + "value": 1974, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-24", + "name": "Angelina Jolie", + "label": "Born 1975", + "value": 1975, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-25", + "name": "Kate Winslet", + "label": "Born 1975", + "value": 1975, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-26", + "name": "Ryan Reynolds", + "label": "Born 1976", + "value": 1976, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-27", + "name": "Chris Evans", + "label": "Born 1981", + "value": 1981, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-28", + "name": "Anne Hathaway", + "label": "Born 1982", + "value": 1982, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-29", + "name": "Chris Pratt", + "label": "Born 1979", + "value": 1979, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-30", + "name": "Scarlett Johansson", + "label": "Born 1984", + "value": 1984, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-31", + "name": "Bradley Cooper", + "label": "Born 1975", + "value": 1975, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-32", + "name": "Jennifer Lawrence", + "label": "Born 1990", + "value": 1990, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-33", + "name": "Emma Watson", + "label": "Born 1990", + "value": 1990, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-34", + "name": "Tom Holland", + "label": "Born 1996", + "value": 1996, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-35", + "name": "Zendaya", + "label": "Born 1996", + "value": 1996, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-36", + "name": "Michael B. Jordan", + "label": "Born 1987", + "value": 1987, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-37", + "name": "Gal Gadot", + "label": "Born 1985", + "value": 1985, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-38", + "name": "Dwayne Johnson", + "label": "Born 1972", + "value": 1972, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-39", + "name": "Jennifer Aniston", + "label": "Born 1969", + "value": 1969, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-40", + "name": "Tom Cruise", + "label": "Born 1962", + "value": 1962, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-41", + "name": "Julia Roberts", + "label": "Born 1967", + "value": 1967, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-42", + "name": "Will Smith", + "label": "Born 1968", + "value": 1968, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-43", + "name": "Matt Damon", + "label": "Born 1970", + "value": 1970, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-44", + "name": "Ben Affleck", + "label": "Born 1972", + "value": 1972, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-45", + "name": "Cate Blanchett", + "label": "Born 1969", + "value": 1969, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-46", + "name": "Naomi Watts", + "label": "Born 1968", + "value": 1968, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-47", + "name": "Gwyneth Paltrow", + "label": "Born 1972", + "value": 1972, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-48", + "name": "Ryan Gosling", + "label": "Born 1980", + "value": 1980, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-49", + "name": "Emma Stone", + "label": "Born 1988", + "value": 1988, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-50", + "name": "Channing Tatum", + "label": "Born 1980", + "value": 1980, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-51", + "name": "Jennifer Lopez", + "label": "Born 1969", + "value": 1969, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-52", + "name": "Beyoncé", + "label": "Born 1981", + "value": 1981, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-53", + "name": "Taylor Swift", + "label": "Born 1989", + "value": 1989, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-54", + "name": "Adele", + "label": "Born 1988", + "value": 1988, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-55", + "name": "Ed Sheeran", + "label": "Born 1991", + "value": 1991, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-56", + "name": "Rihanna", + "label": "Born 1988", + "value": 1988, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-57", + "name": "Lady Gaga", + "label": "Born 1986", + "value": 1986, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-58", + "name": "Bruno Mars", + "label": "Born 1985", + "value": 1985, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-59", + "name": "Justin Timberlake", + "label": "Born 1981", + "value": 1981, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-60", + "name": "Katy Perry", + "label": "Born 1984", + "value": 1984, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-61", + "name": "Drake", + "label": "Born 1986", + "value": 1986, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-62", + "name": "The Weeknd", + "label": "Born 1990", + "value": 1990, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-63", + "name": "Billie Eilish", + "label": "Born 2001", + "value": 2001, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-64", + "name": "Harry Styles", + "label": "Born 1994", + "value": 1994, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-65", + "name": "Ariana Grande", + "label": "Born 1993", + "value": 1993, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-66", + "name": "Kanye West", + "label": "Born 1977", + "value": 1977, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-67", + "name": "Eminem", + "label": "Born 1972", + "value": 1972, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-68", + "name": "Mariah Carey", + "label": "Born 1969", + "value": 1969, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-69", + "name": "Celine Dion", + "label": "Born 1968", + "value": 1968, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-70", + "name": "Madonna", + "label": "Born 1958", + "value": 1958, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-71", + "name": "Sting", + "label": "Born 1951", + "value": 1951, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-72", + "name": "Elton John", + "label": "Born 1947", + "value": 1947, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-73", + "name": "Paul McCartney", + "label": "Born 1942", + "value": 1942, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-74", + "name": "Bob Dylan", + "label": "Born 1941", + "value": 1941, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-75", + "name": "Stevie Wonder", + "label": "Born 1950", + "value": 1950, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-76", + "name": "Bruce Springsteen", + "label": "Born 1949", + "value": 1949, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-77", + "name": "Will Ferrell", + "label": "Born 1967", + "value": 1967, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-78", + "name": "Adam Sandler", + "label": "Born 1966", + "value": 1966, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-79", + "name": "Jim Carrey", + "label": "Born 1962", + "value": 1962, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-80", + "name": "Steve Martin", + "label": "Born 1945", + "value": 1945, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-81", + "name": "Tina Fey", + "label": "Born 1970", + "value": 1970, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-82", + "name": "Amy Poehler", + "label": "Born 1971", + "value": 1971, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-83", + "name": "Kevin Hart", + "label": "Born 1979", + "value": 1979, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-84", + "name": "Dwayne Johnson", + "label": "Born 1972", + "value": 1972, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-85", + "name": "Jonah Hill", + "label": "Born 1983", + "value": 1983, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-86", + "name": "Seth Rogen", + "label": "Born 1982", + "value": 1982, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-87", + "name": "Ellen DeGeneres", + "label": "Born 1958", + "value": 1958, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-88", + "name": "Oprah Winfrey", + "label": "Born 1954", + "value": 1954, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-89", + "name": "Gordon Ramsay", + "label": "Born 1966", + "value": 1966, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-90", + "name": "Stephen King", + "label": "Born 1947", + "value": 1947, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-91", + "name": "George Lucas", + "label": "Born 1944", + "value": 1944, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-92", + "name": "Steven Spielberg", + "label": "Born 1946", + "value": 1946, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-93", + "name": "Quentin Tarantino", + "label": "Born 1963", + "value": 1963, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-94", + "name": "Martin Scorsese", + "label": "Born 1942", + "value": 1942, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-95", + "name": "Stanley Kubrick", + "label": "Born 1928", + "value": 1928, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-96", + "name": "Alfred Hitchcock", + "label": "Born 1899", + "value": 1899, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-97", + "name": "Jackie Chan", + "label": "Born 1954", + "value": 1954, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-98", + "name": "Jet Li", + "label": "Born 1963", + "value": 1963, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-99", + "name": "Bruce Lee", + "label": "Born 1940", + "value": 1940, + "categoryId": "celebrities.age", + "source": { "name": "" } + }, + { + "id": "celeb-100", + "name": "Chuck Norris", + "label": "Born 1940", + "value": 1940, + "categoryId": "celebrities.age", + "source": { "name": "" } + } + ] \ No newline at end of file diff --git a/backend/data/items/countries.coastline.items.json b/backend/data/items/countries.coastline.items.json new file mode 100644 index 0000000000..ae2f035f9a --- /dev/null +++ b/backend/data/items/countries.coastline.items.json @@ -0,0 +1,2004 @@ +[ + { + "id": "country-afghanistan", + "name": "Afghanistan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-albania", + "name": "Albania", + "label": "Coastline 362 km", + "value": 362.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-algeria", + "name": "Algeria", + "label": "Coastline 998 km", + "value": 998.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-angola", + "name": "Angola", + "label": "Coastline 1600 km", + "value": 1600.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-antigua-and-barbuda", + "name": "Antigua and Barbuda", + "label": "Coastline 153 km", + "value": 153.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-argentina", + "name": "Argentina", + "label": "Coastline 4989 km", + "value": 4989.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-armenia", + "name": "Armenia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-australia", + "name": "Australia", + "label": "Coastline 25760 km", + "value": 25760.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-austria", + "name": "Austria", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-azerbaijan", + "name": "Azerbaijan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bahamas", + "name": "Bahamas", + "label": "Coastline 3542 km", + "value": 3542.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bahrain", + "name": "Bahrain", + "label": "Coastline 161 km", + "value": 161.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bangladesh", + "name": "Bangladesh", + "label": "Coastline 580 km", + "value": 580.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-barbados", + "name": "Barbados", + "label": "Coastline 97 km", + "value": 97.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-belarus", + "name": "Belarus", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-belgium", + "name": "Belgium", + "label": "Coastline 66.5 km", + "value": 66.5, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-belize", + "name": "Belize", + "label": "Coastline 386 km", + "value": 386.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-benin", + "name": "Benin", + "label": "Coastline 121 km", + "value": 121.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bhutan", + "name": "Bhutan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bolivia", + "name": "Bolivia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bosnia-and-herzegovina", + "name": "Bosnia and Herzegovina", + "label": "Coastline 20 km", + "value": 20.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-botswana", + "name": "Botswana", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-brazil", + "name": "Brazil", + "label": "Coastline 7491 km", + "value": 7491.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-brunei", + "name": "Brunei", + "label": "Coastline 161 km", + "value": 161.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-bulgaria", + "name": "Bulgaria", + "label": "Coastline 354 km", + "value": 354.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-burkina-faso", + "name": "Burkina Faso", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-burundi", + "name": "Burundi", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-cabo-verde", + "name": "Cabo Verde", + "label": "Coastline 965 km", + "value": 965.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-cambodia", + "name": "Cambodia", + "label": "Coastline 443 km", + "value": 443.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-cameroon", + "name": "Cameroon", + "label": "Coastline 402 km", + "value": 402.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-canada", + "name": "Canada", + "label": "Coastline 202080 km", + "value": 202080.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-central-african-republic", + "name": "Central African Republic", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-chad", + "name": "Chad", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-chile", + "name": "Chile", + "label": "Coastline 6435 km", + "value": 6435.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-china", + "name": "China", + "label": "Coastline 14500 km", + "value": 14500.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-colombia", + "name": "Colombia", + "label": "Coastline 3208 km", + "value": 3208.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-comoros", + "name": "Comoros", + "label": "Coastline 340 km", + "value": 340.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-congo-democratic-republic-of-the", + "name": "Congo, Democratic Republic of the", + "label": "Coastline 37 km", + "value": 37.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-congo-republic-of-the", + "name": "Congo, Republic of the", + "label": "Coastline 169 km", + "value": 169.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-costa-rica", + "name": "Costa Rica", + "label": "Coastline 1290 km", + "value": 1290.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-cote-d-ivoire", + "name": "Cote d'Ivoire", + "label": "Coastline 515 km", + "value": 515.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-croatia", + "name": "Croatia", + "label": "Coastline 5835 km", + "value": 5835.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-cuba", + "name": "Cuba", + "label": "Coastline 3735 km", + "value": 3735.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-cyprus", + "name": "Cyprus", + "label": "Coastline 648 km", + "value": 648.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-czechia", + "name": "Czechia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-denmark", + "name": "Denmark", + "label": "Coastline 7314 km", + "value": 7314.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-djibouti", + "name": "Djibouti", + "label": "Coastline 314 km", + "value": 314.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-dominica", + "name": "Dominica", + "label": "Coastline 148 km", + "value": 148.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-dominican-republic", + "name": "Dominican Republic", + "label": "Coastline 1288 km", + "value": 1288.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-ecuador", + "name": "Ecuador", + "label": "Coastline 2237 km", + "value": 2237.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-egypt", + "name": "Egypt", + "label": "Coastline 2450 km", + "value": 2450.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-equatorial-guinea", + "name": "Equatorial Guinea", + "label": "Coastline 296 km", + "value": 296.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-eritrea", + "name": "Eritrea", + "label": "Coastline 2234 km", + "value": 2234.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-estonia", + "name": "Estonia", + "label": "Coastline 3794 km", + "value": 3794.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-eswatini", + "name": "Eswatini", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-ethiopia", + "name": "Ethiopia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-germany", + "name": "Germany", + "label": "Coastline 2389 km", + "value": 2389.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-ghana", + "name": "Ghana", + "label": "Coastline 539 km", + "value": 539.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-greece", + "name": "Greece", + "label": "Coastline 13676 km", + "value": 13676.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-grenada", + "name": "Grenada", + "label": "Coastline 121 km", + "value": 121.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-guatemala", + "name": "Guatemala", + "label": "Coastline 400 km", + "value": 400.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-guinea", + "name": "Guinea", + "label": "Coastline 320 km", + "value": 320.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-guinea-bissau", + "name": "Guinea-Bissau", + "label": "Coastline 350 km", + "value": 350.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-guyana", + "name": "Guyana", + "label": "Coastline 459 km", + "value": 459.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-haiti", + "name": "Haiti", + "label": "Coastline 1771 km", + "value": 1771.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-honduras", + "name": "Honduras", + "label": "Coastline 823 km", + "value": 823.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-hungary", + "name": "Hungary", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-iceland", + "name": "Iceland", + "label": "Coastline 4970 km", + "value": 4970.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-india", + "name": "India", + "label": "Coastline 7000 km", + "value": 7000.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-indonesia", + "name": "Indonesia", + "label": "Coastline 54716 km", + "value": 54716.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-iran", + "name": "Iran", + "label": "Coastline 2440 km", + "value": 2440.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-iraq", + "name": "Iraq", + "label": "Coastline 58 km", + "value": 58.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-ireland", + "name": "Ireland", + "label": "Coastline 1448 km", + "value": 1448.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-israel", + "name": "Israel", + "label": "Coastline 273 km", + "value": 273.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-italy", + "name": "Italy", + "label": "Coastline 7600 km", + "value": 7600.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-jamaica", + "name": "Jamaica", + "label": "Coastline 1022 km", + "value": 1022.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-japan", + "name": "Japan", + "label": "Coastline 29751 km", + "value": 29751.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-jordan", + "name": "Jordan", + "label": "Coastline 26 km", + "value": 26.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-kazakhstan", + "name": "Kazakhstan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-kenya", + "name": "Kenya", + "label": "Coastline 536 km", + "value": 536.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-kiribati", + "name": "Kiribati", + "label": "Coastline 1143 km", + "value": 1143.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-korea-north", + "name": "Korea, North", + "label": "Coastline 2495 km", + "value": 2495.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-korea-south", + "name": "Korea, South", + "label": "Coastline 2413 km", + "value": 2413.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-kuwait", + "name": "Kuwait", + "label": "Coastline 499 km", + "value": 499.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-kyrgyzstan", + "name": "Kyrgyzstan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-laos", + "name": "Laos", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-latvia", + "name": "Latvia", + "label": "Coastline 498 km", + "value": 498.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-lebanon", + "name": "Lebanon", + "label": "Coastline 225 km", + "value": 225.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-lesotho", + "name": "Lesotho", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-liberia", + "name": "Liberia", + "label": "Coastline 579 km", + "value": 579.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-libya", + "name": "Libya", + "label": "Coastline 1770 km", + "value": 1770.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-liechtenstein", + "name": "Liechtenstein", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-lithuania", + "name": "Lithuania", + "label": "Coastline 90 km", + "value": 90.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-luxembourg", + "name": "Luxembourg", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-madagascar", + "name": "Madagascar", + "label": "Coastline 4828 km", + "value": 4828.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-malawi", + "name": "Malawi", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-malaysia", + "name": "Malaysia", + "label": "Coastline 4675 km", + "value": 4675.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-maldives", + "name": "Maldives", + "label": "Coastline 644 km", + "value": 644.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-mali", + "name": "Mali", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-malta", + "name": "Malta", + "label": "Coastline 196.8 km", + "value": 196.8, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-marshall-islands", + "name": "Marshall Islands", + "label": "Coastline 370.4 km", + "value": 370.4, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-mauritania", + "name": "Mauritania", + "label": "Coastline 754 km", + "value": 754.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-mauritius", + "name": "Mauritius", + "label": "Coastline 177 km", + "value": 177.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-mexico", + "name": "Mexico", + "label": "Coastline 9330 km", + "value": 9330.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-micronesia-federated-states-of", + "name": "Micronesia, Federated States of", + "label": "Coastline 6112 km", + "value": 6112.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-moldova", + "name": "Moldova", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-monaco", + "name": "Monaco", + "label": "Coastline 4.1 km", + "value": 4.1, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-mongolia", + "name": "Mongolia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-montenegro", + "name": "Montenegro", + "label": "Coastline 293.5 km", + "value": 293.5, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-morocco", + "name": "Morocco", + "label": "Coastline 2945 km", + "value": 2945.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-mozambique", + "name": "Mozambique", + "label": "Coastline 2470 km", + "value": 2470.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-namibia", + "name": "Namibia", + "label": "Coastline 1572 km", + "value": 1572.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-nauru", + "name": "Nauru", + "label": "Coastline 30 km", + "value": 30.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-nepal", + "name": "Nepal", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-netherlands", + "name": "Netherlands", + "label": "Coastline 451 km", + "value": 451.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-new-zealand", + "name": "New Zealand", + "label": "Coastline 15134 km", + "value": 15134.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-nicaragua", + "name": "Nicaragua", + "label": "Coastline 910 km", + "value": 910.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-niger", + "name": "Niger", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-nigeria", + "name": "Nigeria", + "label": "Coastline 853 km", + "value": 853.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-north-macedonia", + "name": "North Macedonia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-norway", + "name": "Norway", + "label": "Coastline 25148 km", + "value": 25148.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-oman", + "name": "Oman", + "label": "Coastline 2092 km", + "value": 2092.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-pakistan", + "name": "Pakistan", + "label": "Coastline 1046 km", + "value": 1046.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-palau", + "name": "Palau", + "label": "Coastline 1519 km", + "value": 1519.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-panama", + "name": "Panama", + "label": "Coastline 2490 km", + "value": 2490.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-papua-new-guinea", + "name": "Papua New Guinea", + "label": "Coastline 5152 km", + "value": 5152.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-paraguay", + "name": "Paraguay", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-peru", + "name": "Peru", + "label": "Coastline 2414 km", + "value": 2414.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-philippines", + "name": "Philippines", + "label": "Coastline 36289 km", + "value": 36289.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-poland", + "name": "Poland", + "label": "Coastline 440 km", + "value": 440.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-portugal", + "name": "Portugal", + "label": "Coastline 1793 km", + "value": 1793.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-qatar", + "name": "Qatar", + "label": "Coastline 563 km", + "value": 563.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-romania", + "name": "Romania", + "label": "Coastline 225 km", + "value": 225.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-russia", + "name": "Russia", + "label": "Coastline 37653 km", + "value": 37653.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-rwanda", + "name": "Rwanda", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-saint-kitts-and-nevis", + "name": "Saint Kitts and Nevis", + "label": "Coastline 135 km", + "value": 135.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-saint-lucia", + "name": "Saint Lucia", + "label": "Coastline 158 km", + "value": 158.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-saint-vincent-and-the-grenadines", + "name": "Saint Vincent and the Grenadines", + "label": "Coastline 84 km", + "value": 84.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-samoa", + "name": "Samoa", + "label": "Coastline 403 km", + "value": 403.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-sao-tome-and-principe", + "name": "Sao Tome and Principe", + "label": "Coastline 209 km", + "value": 209.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-saudi-arabia", + "name": "Saudi Arabia", + "label": "Coastline 2640 km", + "value": 2640.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-senegal", + "name": "Senegal", + "label": "Coastline 531 km", + "value": 531.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-serbia", + "name": "Serbia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-seychelles", + "name": "Seychelles", + "label": "Coastline 491 km", + "value": 491.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-sierra-leone", + "name": "Sierra Leone", + "label": "Coastline 402 km", + "value": 402.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-singapore", + "name": "Singapore", + "label": "Coastline 193 km", + "value": 193.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-slovakia", + "name": "Slovakia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-slovenia", + "name": "Slovenia", + "label": "Coastline 46.6 km", + "value": 46.6, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-solomon-islands", + "name": "Solomon Islands", + "label": "Coastline 5313 km", + "value": 5313.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-somalia", + "name": "Somalia", + "label": "Coastline 3025 km", + "value": 3025.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-south-africa", + "name": "South Africa", + "label": "Coastline 2798 km", + "value": 2798.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-south-sudan", + "name": "South Sudan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-spain", + "name": "Spain", + "label": "Coastline 4964 km", + "value": 4964.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-sri-lanka", + "name": "Sri Lanka", + "label": "Coastline 1340 km", + "value": 1340.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-sudan", + "name": "Sudan", + "label": "Coastline 853 km", + "value": 853.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-suriname", + "name": "Suriname", + "label": "Coastline 386 km", + "value": 386.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-sweden", + "name": "Sweden", + "label": "Coastline 3218 km", + "value": 3218.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-switzerland", + "name": "Switzerland", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-syria", + "name": "Syria", + "label": "Coastline 193 km", + "value": 193.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-taiwan", + "name": "Taiwan", + "label": "Coastline 1566.3 km", + "value": 1566.3, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-tajikistan", + "name": "Tajikistan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-tanzania", + "name": "Tanzania", + "label": "Coastline 1424 km", + "value": 1424.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-thailand", + "name": "Thailand", + "label": "Coastline 3219 km", + "value": 3219.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-timor-leste", + "name": "Timor-Leste", + "label": "Coastline 706 km", + "value": 706.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-togo", + "name": "Togo", + "label": "Coastline 56 km", + "value": 56.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-tonga", + "name": "Tonga", + "label": "Coastline 419 km", + "value": 419.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-trinidad-and-tobago", + "name": "Trinidad and Tobago", + "label": "Coastline 362 km", + "value": 362.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-tunisia", + "name": "Tunisia", + "label": "Coastline 1148 km", + "value": 1148.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-turkey-turkiye", + "name": "Turkey (Turkiye)", + "label": "Coastline 7200 km", + "value": 7200.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-turkmenistan", + "name": "Turkmenistan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-uganda", + "name": "Uganda", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-ukraine", + "name": "Ukraine", + "label": "Coastline 2782 km", + "value": 2782.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-united-arab-emirates", + "name": "United Arab Emirates", + "label": "Coastline 1318 km", + "value": 1318.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-united-kingdom", + "name": "United Kingdom", + "label": "Coastline 12429 km", + "value": 12429.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-united-states", + "name": "United States", + "label": "Coastline 19924 km", + "value": 19924.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-uruguay", + "name": "Uruguay", + "label": "Coastline 660 km", + "value": 660.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-uzbekistan", + "name": "Uzbekistan", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-vanuatu", + "name": "Vanuatu", + "label": "Coastline 2528 km", + "value": 2528.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-venezuela", + "name": "Venezuela", + "label": "Coastline 2800 km", + "value": 2800.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-vietnam", + "name": "Vietnam", + "label": "Coastline 3444 km", + "value": 3444.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-zambia", + "name": "Zambia", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + }, + { + "id": "country-zimbabwe", + "name": "Zimbabwe", + "label": "Coastline 0.0 km", + "value": 0.0, + "unit": "km", + "categoryId": "countries.coastline", + "source": { + "name": "CIA World Factbook" + } + } +] \ No newline at end of file diff --git a/backend/data/items/elements.items.json b/backend/data/items/elements.items.json new file mode 100644 index 0000000000..998cec0a08 --- /dev/null +++ b/backend/data/items/elements.items.json @@ -0,0 +1,352 @@ +[ + { + "id": "element-1", + "name": "Hydrogen", + "label": "Atomic number 1", + "value": 1, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-2", + "name": "Helium", + "label": "Atomic number 2", + "value": 2, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-3", + "name": "Lithium", + "label": "Atomic number 3", + "value": 3, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-4", + "name": "Beryllium", + "label": "Atomic number 4", + "value": 4, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-5", + "name": "Boron", + "label": "Atomic number 5", + "value": 5, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-6", + "name": "Carbon", + "label": "Atomic number 6", + "value": 6, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-7", + "name": "Nitrogen", + "label": "Atomic number 7", + "value": 7, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-8", + "name": "Oxygen", + "label": "Atomic number 8", + "value": 8, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-9", + "name": "Fluorine", + "label": "Atomic number 9", + "value": 9, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-10", + "name": "Neon", + "label": "Atomic number 10", + "value": 10, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-11", + "name": "Sodium", + "label": "Atomic number 11", + "value": 11, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-12", + "name": "Magnesium", + "label": "Atomic number 12", + "value": 12, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-13", + "name": "Aluminium", + "label": "Atomic number 13", + "value": 13, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-14", + "name": "Silicon", + "label": "Atomic number 14", + "value": 14, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-15", + "name": "Phosphorus", + "label": "Atomic number 15", + "value": 15, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-16", + "name": "Sulfur", + "label": "Atomic number 16", + "value": 16, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-17", + "name": "Chlorine", + "label": "Atomic number 17", + "value": 17, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-18", + "name": "Argon", + "label": "Atomic number 18", + "value": 18, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-19", + "name": "Potassium", + "label": "Atomic number 19", + "value": 19, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-20", + "name": "Calcium", + "label": "Atomic number 20", + "value": 20, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-21", + "name": "Scandium", + "label": "Atomic number 21", + "value": 21, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-22", + "name": "Titanium", + "label": "Atomic number 22", + "value": 22, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-23", + "name": "Vanadium", + "label": "Atomic number 23", + "value": 23, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-24", + "name": "Chromium", + "label": "Atomic number 24", + "value": 24, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-25", + "name": "Manganese", + "label": "Atomic number 25", + "value": 25, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-26", + "name": "Iron", + "label": "Atomic number 26", + "value": 26, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-27", + "name": "Cobalt", + "label": "Atomic number 27", + "value": 27, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-28", + "name": "Nickel", + "label": "Atomic number 28", + "value": 28, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-29", + "name": "Copper", + "label": "Atomic number 29", + "value": 29, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-30", + "name": "Zinc", + "label": "Atomic number 30", + "value": 30, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-31", + "name": "Gallium", + "label": "Atomic number 31", + "value": 31, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-32", + "name": "Germanium", + "label": "Atomic number 32", + "value": 32, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-33", + "name": "Arsenic", + "label": "Atomic number 33", + "value": 33, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-34", + "name": "Selenium", + "label": "Atomic number 34", + "value": 34, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-35", + "name": "Bromine", + "label": "Atomic number 35", + "value": 35, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-36", + "name": "Krypton", + "label": "Atomic number 36", + "value": 36, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-37", + "name": "Rubidium", + "label": "Atomic number 37", + "value": 37, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-38", + "name": "Strontium", + "label": "Atomic number 38", + "value": 38, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-39", + "name": "Yttrium", + "label": "Atomic number 39", + "value": 39, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-40", + "name": "Zirconium", + "label": "Atomic number 40", + "value": 40, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-41", + "name": "Niobium", + "label": "Atomic number 41", + "value": 41, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-42", + "name": "Molybdenum", + "label": "Atomic number 42", + "value": 42, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-43", + "name": "Technetium", + "label": "Atomic number 43", + "value": 43, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-44", + "name": "Ruthenium", + "label": "Atomic number 44", + "value": 44, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-45", + "name": "Rhodium", + "label": "Atomic number 45", + "value": 45, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-46", + "name": "Palladium", + "label": "Atomic number 46", + "value": 46, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-47", + "name": "Silver", + "label": "Atomic number 47", + "value": 47, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-48", + "name": "Cadmium", + "label": "Atomic number 48", + "value": 48, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-49", + "name": "Indium", + "label": "Atomic number 49", + "value": 49, + "categoryId": "elements.atomicnumber" + }, + { + "id": "element-50", + "name": "Tin", + "label": "Atomic number 50", + "value": 50, + "categoryId": "elements.atomicnumber" + } +] diff --git a/backend/data/items/games.items.json b/backend/data/items/games.items.json new file mode 100644 index 0000000000..6e514b7cfe --- /dev/null +++ b/backend/data/items/games.items.json @@ -0,0 +1,341 @@ +[ + { + "id": "game-1", + "name": "Super Mario Bros.", + "label": "Released 1985", + "value": 1985, + "categoryId": "games.releaseyear" + }, + { + "id": "game-2", + "name": "The Legend of Zelda", + "label": "Released 1986", + "value": 1986, + "categoryId": "games.releaseyear" + }, + { + "id": "game-3", + "name": "Tetris", + "label": "Released 1984", + "value": 1984, + "categoryId": "games.releaseyear" + }, + { + "id": "game-4", + "name": "Street Fighter II", + "label": "Released 1991", + "value": 1991, + "categoryId": "games.releaseyear" + }, + { + "id": "game-5", + "name": "Sonic the Hedgehog", + "label": "Released 1991", + "value": 1991, + "categoryId": "games.releaseyear" + }, + { + "id": "game-6", + "name": "Mortal Kombat", + "label": "Released 1992", + "value": 1992, + "categoryId": "games.releaseyear" + }, + { + "id": "game-7", + "name": "DOOM", + "label": "Released 1993", + "value": 1993, + "categoryId": "games.releaseyear" + }, + { + "id": "game-8", + "name": "Pokémon Red/Blue", + "label": "Released 1996", + "value": 1996, + "categoryId": "games.releaseyear" + }, + { + "id": "game-9", + "name": "Final Fantasy VII", + "label": "Released 1997", + "value": 1997, + "categoryId": "games.releaseyear" + }, + { + "id": "game-10", + "name": "GoldenEye 007", + "label": "Released 1997", + "value": 1997, + "categoryId": "games.releaseyear" + }, + { + "id": "game-11", + "name": "Half-Life", + "label": "Released 1998", + "value": 1998, + "categoryId": "games.releaseyear" + }, + { + "id": "game-13", + "name": "Super Smash Bros.", + "label": "Released 1999", + "value": 1999, + "categoryId": "games.releaseyear" + }, + { + "id": "game-14", + "name": "The Sims", + "label": "Released 2000", + "value": 2000, + "categoryId": "games.releaseyear" + }, + { + "id": "game-15", + "name": "Grand Theft Auto III", + "label": "Released 2001", + "value": 2001, + "categoryId": "games.releaseyear" + }, + { + "id": "game-16", + "name": "Halo: Combat Evolved", + "label": "Released 2001", + "value": 2001, + "categoryId": "games.releaseyear" + }, + { + "id": "game-17", + "name": "Metroid Prime", + "label": "Released 2002", + "value": 2002, + "categoryId": "games.releaseyear" + }, + + { + "id": "game-19", + "name": "Call of Duty", + "label": "Released 2003", + "value": 2003, + "categoryId": "games.releaseyear" + }, + + { + "id": "game-21", + "name": "World of Warcraft", + "label": "Released 2004", + "value": 2004, + "categoryId": "games.releaseyear" + }, + { + "id": "game-22", + "name": "Half-Life 2", + "label": "Released 2004", + "value": 2004, + "categoryId": "games.releaseyear" + }, + { + "id": "game-23", + "name": "Resident Evil 4", + "label": "Released 2005", + "value": 2005, + "categoryId": "games.releaseyear" + }, + { + "id": "game-24", + "name": "God of War", + "label": "Released 2005", + "value": 2005, + "categoryId": "games.releaseyear" + }, + + { + "id": "game-26", + "name": "Gears of War", + "label": "Released 2006", + "value": 2006, + "categoryId": "games.releaseyear" + }, + { + "id": "game-27", + "name": "BioShock", + "label": "Released 2007", + "value": 2007, + "categoryId": "games.releaseyear" + }, + { + "id": "game-29", + "name": "Super Mario Galaxy", + "label": "Released 2007", + "value": 2007, + "categoryId": "games.releaseyear" + }, + { + "id": "game-30", + "name": "Grand Theft Auto IV", + "label": "Released 2008", + "value": 2008, + "categoryId": "games.releaseyear" + }, + { + "id": "game-31", + "name": "Fallout 3", + "label": "Released 2008", + "value": 2008, + "categoryId": "games.releaseyear" + }, + { + "id": "game-32", + "name": "Uncharted 2: Among Thieves", + "label": "Released 2009", + "value": 2009, + "categoryId": "games.releaseyear" + }, + { + "id": "game-33", + "name": "Minecraft", + "label": "Released 2009", + "value": 2009, + "categoryId": "games.releaseyear" + }, + { + "id": "game-34", + "name": "Red Dead Redemption", + "label": "Released 2010", + "value": 2010, + "categoryId": "games.releaseyear" + }, + { + "id": "game-35", + "name": "Mass Effect 2", + "label": "Released 2010", + "value": 2010, + "categoryId": "games.releaseyear" + }, + { + "id": "game-37", + "name": "Dark Souls", + "label": "Released 2011", + "value": 2011, + "categoryId": "games.releaseyear" + }, + { + "id": "game-38", + "name": "Journey", + "label": "Released 2012", + "value": 2012, + "categoryId": "games.releaseyear" + }, + { + "id": "game-39", + "name": "Borderlands 2", + "label": "Released 2012", + "value": 2012, + "categoryId": "games.releaseyear" + }, + { + "id": "game-40", + "name": "The Last of Us", + "label": "Released 2013", + "value": 2013, + "categoryId": "games.releaseyear" + }, + { + "id": "game-41", + "name": "Grand Theft Auto V", + "label": "Released 2013", + "value": 2013, + "categoryId": "games.releaseyear" + }, + { + "id": "game-42", + "name": "Destiny", + "label": "Released 2014", + "value": 2014, + "categoryId": "games.releaseyear" + }, + { + "id": "game-43", + "name": "Mario Kart 8", + "label": "Released 2014", + "value": 2014, + "categoryId": "games.releaseyear" + }, + { + "id": "game-44", + "name": "The Witcher 3: Wild Hunt", + "label": "Released 2015", + "value": 2015, + "categoryId": "games.releaseyear" + }, + { + "id": "game-45", + "name": "Bloodborne", + "label": "Released 2015", + "value": 2015, + "categoryId": "games.releaseyear" + }, + { + "id": "game-46", + "name": "Overwatch", + "label": "Released 2016", + "value": 2016, + "categoryId": "games.releaseyear" + }, + { + "id": "game-47", + "name": "Uncharted 4: A Thief's End", + "label": "Released 2016", + "value": 2016, + "categoryId": "games.releaseyear" + }, + { + "id": "game-49", + "name": "Horizon Zero Dawn", + "label": "Released 2017", + "value": 2017, + "categoryId": "games.releaseyear" + }, + { + "id": "game-50", + "name": "The Sims 2", + "label": "Released 2004", + "value": 2004, + "categoryId": "games.releaseyear" + }, + { + "id": "game-51", + "name": "Red Dead Redemption 2", + "label": "Released 2018", + "value": 2018, + "categoryId": "games.releaseyear" + }, + { + "id": "game-52", + "name": "Sekiro: Shadows Die Twice", + "label": "Released 2019", + "value": 2019, + "categoryId": "games.releaseyear" + }, + { + "id": "game-53", + "name": "Death Stranding", + "label": "Released 2019", + "value": 2019, + "categoryId": "games.releaseyear" + }, + { + "id": "game-55", + "name": "The Last of Us Part II", + "label": "Released 2020", + "value": 2020, + "categoryId": "games.releaseyear" + }, + { + "id": "game-56", + "name": "Elden Ring", + "label": "Released 2022", + "value": 2022, + "categoryId": "games.releaseyear" + } +] diff --git a/backend/data/items/internet.items.json b/backend/data/items/internet.items.json new file mode 100644 index 0000000000..9de375014d --- /dev/null +++ b/backend/data/items/internet.items.json @@ -0,0 +1,346 @@ +[ + { + "id": "net-1", + "name": "Dancing Baby", + "label": "Year 1996", + "value": 1996, + "categoryId": "internet.phenomena.year", + "source": { "name": "Wikipedia" } + }, + { + "id": "net-2", + "name": "Star Wars Kid", + "label": "Year 2003", + "value": 2003, + "categoryId": "internet.phenomena.year", + "source": { "name": "Wikipedia" } + }, + { + "id": "net-3", + "name": "Numa Numa", + "label": "Year 2004", + "value": 2004, + "categoryId": "internet.phenomena.year", + "source": { "name": "Wikipedia" } + }, + { + "id": "net-4", + "name": "Leeroy Jenkins", + "label": "Year 2005", + "value": 2005, + "categoryId": "internet.phenomena.year", + "source": { "name": "Wikipedia" } + }, + { + "id": "net-5", + "name": "Chuck Norris Facts", + "label": "Year 2005", + "value": 2005, + "categoryId": "internet.phenomena.year", + "source": { "name": "KnowYourMeme" } + }, + { + "id": "net-6", + "name": "OK Go – Treadmills", + "label": "Year 2006", + "value": 2006, + "categoryId": "internet.phenomena.year", + "source": { "name": "Wikipedia" } + }, + { + "id": "net-7", + "name": "Rickrolling", + "label": "Year 2007", + "value": 2007, + "categoryId": "internet.phenomena.year", + "source": { "name": "KnowYourMeme" } + }, + { + "id": "net-9", + "name": "Chocolate Rain", + "label": "Year 2007", + "value": 2007, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-10", + "name": "Dramatic Chipmunk", + "label": "Year 2007", + "value": 2007, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-11", + "name": "Keyboard Cat", + "label": "Year 2009", + "value": 2009, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-12", + "name": "David After Dentist", + "label": "Year 2009", + "value": 2009, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-13", + "name": "Double Rainbow", + "label": "Year 2010", + "value": 2010, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-14", + "name": "Bed Intruder", + "label": "Year 2010", + "value": 2010, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-15", + "name": "Planking", + "label": "Year 2011", + "value": 2011, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-16", + "name": "Nyan Cat", + "label": "Year 2011", + "value": 2011, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-17", + "name": "Rebecca Black – Friday", + "label": "Year 2011", + "value": 2011, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-18", + "name": "Kony 2012", + "label": "Year 2012", + "value": 2012, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-19", + "name": "Gangnam Style", + "label": "Year 2012", + "value": 2012, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-20", + "name": "Overly Attached Girlfriend", + "label": "Year 2012", + "value": 2012, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-21", + "name": "Harlem Shake", + "label": "Year 2013", + "value": 2013, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-22", + "name": "What Does the Fox Say?", + "label": "Year 2013", + "value": 2013, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-23", + "name": "Doge", + "label": "Year 2013", + "value": 2013, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-24", + "name": "Ice Bucket Challenge", + "label": "Year 2014", + "value": 2014, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-25", + "name": "Alex from Target", + "label": "Year 2014", + "value": 2014, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-26", + "name": "The Dress (Blue/Black)", + "label": "Year 2015", + "value": 2015, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-27", + "name": "Left Shark", + "label": "Year 2015", + "value": 2015, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-28", + "name": "Damn, Daniel", + "label": "Year 2016", + "value": 2016, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-29", + "name": "Mannequin Challenge", + "label": "Year 2016", + "value": 2016, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-30", + "name": "Bottle Flip", + "label": "Year 2016", + "value": 2016, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-31", + "name": "Fidget Spinner Craze", + "label": "Year 2017", + "value": 2017, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-32", + "name": "Distracted Boyfriend", + "label": "Year 2017", + "value": 2017, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-33", + "name": "Ugandan Knuckles", + "label": "Year 2018", + "value": 2018, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-34", + "name": "Yanny or Laurel", + "label": "Year 2018", + "value": 2018, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-35", + "name": "Kiki Challenge", + "label": "Year 2018", + "value": 2018, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-36", + "name": "Storm Area 51", + "label": "Year 2019", + "value": 2019, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-37", + "name": "Baby Yoda", + "label": "Year 2019", + "value": 2019, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-38", + "name": "Woman Yelling at a Cat", + "label": "Year 2019", + "value": 2019, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-39", + "name": "Coffin Dance (Astronomia)", + "label": "Year 2020", + "value": 2020, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-40", + "name": "Among Us (Viral Breakout)", + "label": "Year 2020", + "value": 2020, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-41", + "name": "Tiger King Memes", + "label": "Year 2020", + "value": 2020, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-42", + "name": "Bernie Sanders Mittens", + "label": "Year 2021", + "value": 2021, + "categoryId": "internet.phenomena.year" + }, + + { + "id": "net-44", + "name": "Red Flag Emoji Trend", + "label": "Year 2021", + "value": 2021, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-45", + "name": "Wordle", + "label": "Year 2022", + "value": 2022, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-46", + "name": "“It’s Morbin’ Time”", + "label": "Year 2022", + "value": 2022, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-47", + "name": "Little Miss Meme", + "label": "Year 2022", + "value": 2022, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-48", + "name": "Barbenheimer", + "label": "Year 2023", + "value": 2023, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-49", + "name": "Grimace Shake", + "label": "Year 2023", + "value": 2023, + "categoryId": "internet.phenomena.year" + }, + { + "id": "net-50", + "name": "NPC Streaming Trend", + "label": "Year 2023", + "value": 2023, + "categoryId": "internet.phenomena.year" + } +] diff --git a/backend/dist/config/database.js b/backend/dist/config/database.js new file mode 100644 index 0000000000..fd69663f70 --- /dev/null +++ b/backend/dist/config/database.js @@ -0,0 +1,27 @@ +import mongoose from 'mongoose'; +import { config } from './environment.js'; +const connectDB = async () => { + try { + const mongoURI = config.MONGODB_URI; + const conn = await mongoose.connect(mongoURI); + console.log(`[Database] MongoDB Connected: ${conn.connection.host}`); + // Handle connection events + mongoose.connection.on('error', (err) => { + console.error('[Database] MongoDB connection error:', err); + }); + mongoose.connection.on('disconnected', () => { + console.warn('[Database] MongoDB disconnected'); + }); + // Graceful shutdown + process.on('SIGINT', async () => { + await mongoose.connection.close(); + console.log('[Database] MongoDB connection closed through app termination'); + process.exit(0); + }); + } + catch (error) { + console.error('[Database] Error connecting to MongoDB:', error); + process.exit(1); + } +}; +export default connectDB; diff --git a/backend/dist/config/environment.js b/backend/dist/config/environment.js new file mode 100644 index 0000000000..ed7c380628 --- /dev/null +++ b/backend/dist/config/environment.js @@ -0,0 +1,37 @@ +import dotenv from 'dotenv'; +// Load environment variables +dotenv.config(); +const requiredEnvVars = [ + 'MONGODB_URI', + 'FRONTEND_URI', + 'JWT_SECRET', + 'ADMIN_USERNAME', + 'ADMIN_PASSWORD', + 'ADMIN_EMAIL', +]; +const validateEnvironment = () => { + const missingVars = requiredEnvVars.filter(varName => !process.env[varName]); + if (missingVars.length > 0) { + throw new Error(`Missing required environment variables: ${missingVars.join(', ')}\n` + + 'Please check your .env file and ensure all required variables are set.'); + } + if (process.env.NODE_ENV === 'production') { + if (process.env.JWT_SECRET.length < 32) { + throw new Error('JWT_SECRET must be at least 32 characters long in production'); + } + if (!process.env.MONGODB_URI.includes('mongodb.net')) { + console.warn('Warning: Using non-Atlas MongoDB URI in production'); + } + } + return { + NODE_ENV: process.env.NODE_ENV || 'development', + PORT: parseInt(process.env.PORT || '8888', 10), + MONGODB_URI: process.env.MONGODB_URI, + FRONTEND_URI: process.env.FRONTEND_URI, + JWT_SECRET: process.env.JWT_SECRET, + ADMIN_USERNAME: process.env.ADMIN_USERNAME, + ADMIN_PASSWORD: process.env.ADMIN_PASSWORD, + ADMIN_EMAIL: process.env.ADMIN_EMAIL, + }; +}; +export const config = validateEnvironment(); diff --git a/backend/dist/controllers/adminController.js b/backend/dist/controllers/adminController.js new file mode 100644 index 0000000000..e0e911395d --- /dev/null +++ b/backend/dist/controllers/adminController.js @@ -0,0 +1,192 @@ +import jwt from 'jsonwebtoken'; +import { Admin } from '../models/Admin.js'; +import { Category } from '../models/Category.js'; +import { Item } from '../models/Item.js'; +import { config } from '../config/environment.js'; +// Admin Authentication +export const adminLogin = async (req, res) => { + try { + const { username, password } = req.body; + if (!username || !password) { + return res.status(400).json({ success: false, error: 'Username and password are required' }); + } + const admin = await Admin.findOne({ username, isActive: true }); + if (!admin || !(await admin.comparePassword(password))) { + return res.status(401).json({ success: false, error: 'Invalid credentials' }); + } + admin.lastLogin = new Date(); + await admin.save(); + const token = jwt.sign({ adminId: admin._id }, config.JWT_SECRET, { expiresIn: '24h' }); + res.json({ + success: true, + data: { + message: 'Login successful', + admin: { id: admin._id, username: admin.username, email: admin.email, lastLogin: admin.lastLogin }, + token + } + }); + } + catch (error) { + console.error('[AdminController] Admin login error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const adminLogout = (req, res) => { + res.json({ success: true, data: { message: 'Logout successful' } }); +}; +export const getAdminProfile = (req, res) => { + const admin = req.admin; + if (!admin) { + return res.status(401).json({ success: false, error: 'Admin not found' }); + } + res.json({ + success: true, + data: { + admin: { id: admin._id, username: admin.username, email: admin.email, lastLogin: admin.lastLogin } + } + }); +}; +// Category Management +export const getAllCategories = async (req, res) => { + try { + const categories = await Category.find().sort({ name: 1 }); + res.json({ success: true, data: { categories } }); + } + catch (error) { + console.error('[AdminController] Get categories error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const createCategory = async (req, res) => { + try { + const categoryData = req.body; + if (await Category.findOne({ id: categoryData.id })) { + return res.status(409).json({ success: false, error: 'Category with this ID already exists' }); + } + const category = new Category(categoryData); + await category.save(); + res.status(201).json({ + success: true, + data: { + message: 'Category created successfully', + category + } + }); + } + catch (error) { + console.error('[AdminController] Create category error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const updateCategory = async (req, res) => { + try { + const { id } = req.params; + const category = await Category.findOneAndUpdate({ id }, req.body, { new: true, runValidators: true }); + if (!category) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + res.json({ + success: true, + data: { + message: 'Category updated successfully', + category + } + }); + } + catch (error) { + console.error('[AdminController] Update category error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const deleteCategory = async (req, res) => { + try { + const { id } = req.params; + if (!(await Category.findOne({ id }))) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + if (await Item.countDocuments({ categoryId: id }) > 0) { + return res.status(409).json({ success: false, error: 'Cannot delete category with existing items' }); + } + await Category.deleteOne({ id }); + res.json({ success: true, data: { message: 'Category deleted successfully' } }); + } + catch (error) { + console.error('[AdminController] Delete category error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +// Item Management +export const getAllItems = async (req, res) => { + try { + const { categoryId } = req.query; + const query = categoryId ? { categoryId } : {}; + const items = await Item.find(query).sort({ name: 1 }); + res.json({ success: true, data: { items } }); + } + catch (error) { + console.error('[AdminController] Get items error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const createItem = async (req, res) => { + try { + const itemData = req.body; + if (await Item.findOne({ id: itemData.id })) { + return res.status(409).json({ success: false, error: 'Item with this ID already exists' }); + } + if (!(await Category.findOne({ id: itemData.categoryId }))) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + const item = new Item(itemData); + await item.save(); + res.status(201).json({ + success: true, + data: { + message: 'Item created successfully', + item + } + }); + } + catch (error) { + console.error('[AdminController] Create item error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const updateItem = async (req, res) => { + try { + const { id } = req.params; + const updateData = req.body; + if (updateData.categoryId && !(await Category.findOne({ id: updateData.categoryId }))) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + const item = await Item.findOneAndUpdate({ id }, updateData, { new: true, runValidators: true }); + if (!item) { + return res.status(404).json({ success: false, error: 'Item not found' }); + } + res.json({ + success: true, + data: { + message: 'Item updated successfully', + item + } + }); + } + catch (error) { + console.error('[AdminController] Update item error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; +export const deleteItem = async (req, res) => { + try { + const { id } = req.params; + const item = await Item.findOneAndDelete({ id }); + if (!item) { + return res.status(404).json({ success: false, error: 'Item not found' }); + } + res.json({ success: true, data: { message: 'Item deleted successfully' } }); + } + catch (error) { + console.error('[AdminController] Delete item error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; diff --git a/backend/dist/controllers/quizController.js b/backend/dist/controllers/quizController.js new file mode 100644 index 0000000000..3b2d022ca3 --- /dev/null +++ b/backend/dist/controllers/quizController.js @@ -0,0 +1,73 @@ +import { Item } from '../models/Item.js'; +import { Category } from '../models/Category.js'; +export const getCategories = async (req, res) => { + try { + const categories = await Category.find({}); + res.status(200).json({ success: true, data: categories }); + } + catch (error) { + console.error('[QuizController] Error fetching categories:', error); + res.status(500).json({ success: false, error: 'Error fetching categories' }); + } +}; +export const getCategoryItems = async (req, res) => { + try { + const { categoryId } = req.params; + const items = await Item.find({ categoryId }); + if (items.length === 0) { + return res.status(404).json({ success: false, error: 'No items found for this category' }); + } + res.status(200).json({ success: true, data: items }); + } + catch (error) { + console.error('[QuizController] Error fetching category items:', error); + res.status(500).json({ success: false, error: 'Error fetching category items' }); + } +}; +export const checkAnswers = async (req, res) => { + try { + const { categoryId, userAnswers } = req.body; + if (!categoryId || !Array.isArray(userAnswers) || userAnswers.length === 0) { + return res.status(400).json({ + success: false, + error: 'Valid categoryId and userAnswers array are required' + }); + } + // Get the correct order from the database + const items = await Item.find({ categoryId }).sort({ value: 1 }); + if (items.length !== userAnswers.length) { + return res.status(400).json({ + success: false, + error: 'Number of answers does not match number of items' + }); + } + // Check answers + let correctCount = 0; + const results = userAnswers.map((userAnswer, index) => { + const isCorrect = userAnswer === items[index].id; + if (isCorrect) + correctCount++; + return { + userAnswer, + correctAnswer: items[index].id, + isCorrect, + item: { + id: items[index].id, + name: items[index].name, + label: items[index].label, + value: items[index].value + } + }; + }); + const result = { + isCorrect: correctCount === userAnswers.length, + correctOrder: items, + userOrder: results.map(r => r.item) + }; + res.status(200).json({ success: true, data: result }); + } + catch (error) { + console.error('[QuizController] Error checking answers:', error); + res.status(500).json({ success: false, error: 'Error checking answers' }); + } +}; diff --git a/backend/dist/index.js b/backend/dist/index.js new file mode 100644 index 0000000000..8d0002c037 --- /dev/null +++ b/backend/dist/index.js @@ -0,0 +1,71 @@ +// server/src/index.ts +import express from "express"; +import cors from "cors"; +import mongoose from "mongoose"; +import quizRoutes from './routes/quizRoutes.js'; +import adminRoutes from './routes/adminRoutes.js'; +import { errorHandler, notFound } from './middleware/errorHandler.js'; +import connectDB from './config/database.js'; +import { config } from './config/environment.js'; +const app = express(); +const port = config.PORT; +// Middleware +app.use(cors({ + origin: [ + config.FRONTEND_URI, + "https://banganza.netlify.app", + ], + credentials: true, // Allow cookies + methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allowedHeaders: ["Content-Type", "Authorization", "Cookie"], +})); +app.use(express.json()); // For handling JSON request bodies +// Health check endpoint +app.get("/", (req, res) => { + res.json({ + message: "Backend server is running!", + status: "ok", + environment: config.NODE_ENV, + timestamp: new Date().toISOString(), + frontend: config.FRONTEND_URI, + }); +}); +// Additional health check for production monitoring +app.get("/health", (req, res) => { + const health = { + status: "ok", + timestamp: new Date().toISOString(), + uptime: process.uptime(), + environment: config.NODE_ENV, + database: mongoose.connection.readyState === 1 ? "connected" : "disconnected", + }; + if (health.database === "disconnected") { + health.status = "warning"; + } + res.json(health); +}); +// Use the new quiz routes +app.use('/api/quiz', quizRoutes); +// Use admin routes +app.use('/api/admin', adminRoutes); +// 404 handler +app.use(notFound); +// Error handling middleware +app.use(errorHandler); +// Connect to MongoDB +connectDB(); +// Start the server +app + .listen(port, () => { + console.log(`[Server] Backend server is running on port ${port}`); + if (config.NODE_ENV === "production") { + console.log("[Server] Production mode enabled"); + } + else { + console.log(`[Server] Development mode: http://127.0.0.1:${port}`); + } +}) + .on("error", (err) => { + console.error("[Server] Error starting the server:", err); + process.exit(1); +}); diff --git a/backend/dist/middleware/auth.js b/backend/dist/middleware/auth.js new file mode 100644 index 0000000000..8b13430447 --- /dev/null +++ b/backend/dist/middleware/auth.js @@ -0,0 +1,29 @@ +import jwt from 'jsonwebtoken'; +import { Admin } from '../models/Admin.js'; +import { config } from '../config/environment.js'; +export const authenticateToken = async (req, res, next) => { + try { + const authHeader = req.headers.authorization; + const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN + if (!token) { + return res.status(401).json({ success: false, error: 'Access token required' }); + } + const decoded = jwt.verify(token, config.JWT_SECRET); + // Find admin and check if still active + const admin = await Admin.findById(decoded.adminId).select('-password'); + if (!admin || !admin.isActive) { + return res.status(401).json({ success: false, error: 'Invalid or inactive admin account' }); + } + req.admin = admin; + next(); + } + catch (error) { + if (error instanceof jwt.JsonWebTokenError) { + return res.status(403).json({ success: false, error: 'Invalid token' }); + } + if (error instanceof jwt.TokenExpiredError) { + return res.status(401).json({ success: false, error: 'Token expired' }); + } + return res.status(500).json({ success: false, error: 'Authentication error' }); + } +}; diff --git a/backend/dist/middleware/errorHandler.js b/backend/dist/middleware/errorHandler.js new file mode 100644 index 0000000000..5fc9d513ed --- /dev/null +++ b/backend/dist/middleware/errorHandler.js @@ -0,0 +1,28 @@ +export const errorHandler = (err, req, res, +// eslint-disable-next-line @typescript-eslint/no-unused-vars +next) => { + const statusCode = 500; + const message = err.message || 'Internal Server Error'; + // Log error for debugging + console.error(`[ErrorHandler] ${message}:`, { + error: err.message, + statusCode, + path: req.originalUrl, + method: req.method, + userAgent: req.get('User-Agent'), + ip: req.ip, + }); + // Don't leak error details in production + const errorResponse = { + success: false, + error: message, + ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) + }; + res.status(statusCode).json(errorResponse); +}; +export const notFound = (req, res) => { + res.status(404).json({ + success: false, + error: `Route ${req.originalUrl} not found` + }); +}; diff --git a/backend/dist/middleware/validation.js b/backend/dist/middleware/validation.js new file mode 100644 index 0000000000..43c9e13e68 --- /dev/null +++ b/backend/dist/middleware/validation.js @@ -0,0 +1,20 @@ +export const validateCategoryId = (req, res, next) => { + const { categoryId } = req.params; + if (!categoryId || typeof categoryId !== 'string') { + res.status(400).json({ success: false, error: 'Valid categoryId is required' }); + return; + } + next(); +}; +export const validateQuizAnswers = (req, res, next) => { + const { userAnswers } = req.body; + if (!Array.isArray(userAnswers) || userAnswers.length === 0) { + res.status(400).json({ success: false, error: 'userAnswers must be a non-empty array' }); + return; + } + if (!userAnswers.every((id) => typeof id === 'string')) { + res.status(400).json({ success: false, error: 'All userAnswers must be strings' }); + return; + } + next(); +}; diff --git a/backend/dist/models/Admin.js b/backend/dist/models/Admin.js new file mode 100644 index 0000000000..a5286d33d5 --- /dev/null +++ b/backend/dist/models/Admin.js @@ -0,0 +1,51 @@ +import { Schema, model } from 'mongoose'; +import bcrypt from 'bcryptjs'; +const AdminSchema = new Schema({ + username: { + type: String, + required: true, + unique: true, + trim: true, + minlength: 3, + maxlength: 30 + }, + password: { + type: String, + required: true, + minlength: 6 + }, + email: { + type: String, + required: true, + unique: true, + lowercase: true, + trim: true + }, + isActive: { + type: Boolean, + default: true + }, + lastLogin: { + type: Date + } +}, { + timestamps: true +}); +// Hash password before saving +AdminSchema.pre('save', async function (next) { + if (!this.isModified('password')) + return next(); + try { + const salt = await bcrypt.genSalt(12); + this.password = await bcrypt.hash(this.password, salt); + next(); + } + catch (error) { + next(error); + } +}); +// Method to compare passwords +AdminSchema.methods.comparePassword = async function (candidatePassword) { + return bcrypt.compare(candidatePassword, this.password); +}; +export const Admin = model('Admin', AdminSchema); diff --git a/backend/dist/models/Category.js b/backend/dist/models/Category.js new file mode 100644 index 0000000000..4a777a3dc3 --- /dev/null +++ b/backend/dist/models/Category.js @@ -0,0 +1,16 @@ +import { Schema, model } from 'mongoose'; +const CategorySchema = new Schema({ + id: { type: String, required: true, unique: true }, + name: { type: String, required: true }, + description: { type: String, required: false }, + question: { type: String, required: false }, + unit: { type: String, required: true }, + unitVisible: { type: Boolean, required: false }, + sort: { type: String, enum: ['asc', 'desc'], required: false }, + source: { + name: { type: String, required: false }, + url: { type: String, required: false } + }, + version: { type: Number, required: false } +}, { strict: false, timestamps: false }); +export const Category = model('Category', CategorySchema); diff --git a/backend/dist/models/Item.js b/backend/dist/models/Item.js new file mode 100644 index 0000000000..644415c5e3 --- /dev/null +++ b/backend/dist/models/Item.js @@ -0,0 +1,12 @@ +import { Schema, model } from 'mongoose'; +const ItemSchema = new Schema({ + id: { type: String, required: true, unique: true }, + name: { type: String, required: true }, + value: { type: Number, required: true }, + label: { type: String, required: true }, + categoryId: { type: String, required: true }, + source: { + name: { type: String, required: false } + } +}); +export const Item = model('Item', ItemSchema); diff --git a/backend/dist/routes/adminRoutes.js b/backend/dist/routes/adminRoutes.js new file mode 100644 index 0000000000..6b2011e4b1 --- /dev/null +++ b/backend/dist/routes/adminRoutes.js @@ -0,0 +1,22 @@ +import express from 'express'; +import { adminLogin, adminLogout, getAdminProfile, getAllCategories, createCategory, updateCategory, deleteCategory, getAllItems, createItem, updateItem, deleteItem } from '../controllers/adminController.js'; +import { authenticateToken } from '../middleware/auth.js'; +const router = express.Router(); +// Public routes (no authentication required) +router.post('/login', adminLogin); +// Protected routes (authentication required) +router.use(authenticateToken); +// Admin profile +router.get('/profile', getAdminProfile); +router.post('/logout', adminLogout); +// Category management +router.get('/categories', getAllCategories); +router.post('/categories', createCategory); +router.put('/categories/:id', updateCategory); +router.delete('/categories/:id', deleteCategory); +// Item management +router.get('/items', getAllItems); +router.post('/items', createItem); +router.put('/items/:id', updateItem); +router.delete('/items/:id', deleteItem); +export default router; diff --git a/backend/dist/routes/quizRoutes.js b/backend/dist/routes/quizRoutes.js new file mode 100644 index 0000000000..8d1587d254 --- /dev/null +++ b/backend/dist/routes/quizRoutes.js @@ -0,0 +1,8 @@ +import { Router } from 'express'; +import { getCategories, getCategoryItems, checkAnswers } from '../controllers/quizController.js'; +import { validateCategoryId, validateQuizAnswers } from '../middleware/validation.js'; +const router = Router(); +router.get('/categories', getCategories); +router.get('/category/:categoryId/items', validateCategoryId, getCategoryItems); +router.post('/check', validateQuizAnswers, checkAnswers); +export default router; diff --git a/backend/dist/types/quiz.js b/backend/dist/types/quiz.js new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/backend/dist/types/quiz.js @@ -0,0 +1 @@ +export {}; diff --git a/backend/dist/utils/errors.js b/backend/dist/utils/errors.js new file mode 100644 index 0000000000..450d422093 --- /dev/null +++ b/backend/dist/utils/errors.js @@ -0,0 +1,13 @@ +export class AppError extends Error { + statusCode; + isOperational; + constructor(message, statusCode = 500, isOperational = true) { + super(message); + this.statusCode = statusCode; + this.isOperational = isOperational; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, AppError); + } + this.name = this.constructor.name; + } +} diff --git a/backend/dist/utils/logger.js b/backend/dist/utils/logger.js new file mode 100644 index 0000000000..da8f92931c --- /dev/null +++ b/backend/dist/utils/logger.js @@ -0,0 +1,65 @@ +var LogLevel; +(function (LogLevel) { + LogLevel["ERROR"] = "ERROR"; + LogLevel["WARN"] = "WARN"; + LogLevel["INFO"] = "INFO"; + LogLevel["DEBUG"] = "DEBUG"; +})(LogLevel || (LogLevel = {})); +class Logger { + isDevelopment = process.env.NODE_ENV === 'development'; + formatLog(entry) { + const timestamp = entry.timestamp; + const level = entry.level.padEnd(5); + const context = entry.context ? `[${entry.context}]` : ''; + const message = entry.message; + let logString = `${timestamp} ${level} ${context} ${message}`; + if (entry.error && this.isDevelopment) { + logString += `\n${entry.error.stack}`; + } + if (entry.metadata && Object.keys(entry.metadata).length > 0) { + logString += `\n${JSON.stringify(entry.metadata, null, 2)}`; + } + return logString; + } + log(level, message, context, error, metadata) { + const entry = { + timestamp: new Date().toISOString(), + level, + message, + context, + error, + metadata, + }; + const formattedLog = this.formatLog(entry); + switch (level) { + case LogLevel.ERROR: + console.error(formattedLog); + break; + case LogLevel.WARN: + console.warn(formattedLog); + break; + case LogLevel.INFO: + console.info(formattedLog); + break; + case LogLevel.DEBUG: + if (this.isDevelopment) { + console.debug(formattedLog); + } + break; + } + } + error(message, context, error, metadata) { + this.log(LogLevel.ERROR, message, context, error, metadata); + } + warn(message, context, metadata) { + this.log(LogLevel.WARN, message, context, undefined, metadata); + } + info(message, context, metadata) { + this.log(LogLevel.INFO, message, context, undefined, metadata); + } + debug(message, context, metadata) { + this.log(LogLevel.DEBUG, message, context, undefined, metadata); + } +} +export const logger = new Logger(); +export { LogLevel }; diff --git a/backend/dist/utils/response.js b/backend/dist/utils/response.js new file mode 100644 index 0000000000..fb9e0d3cd7 --- /dev/null +++ b/backend/dist/utils/response.js @@ -0,0 +1,49 @@ +export class ResponseBuilder { + static success(data, req) { + const response = { + success: true, + data, + }; + if (req) { + response.meta = { + timestamp: new Date().toISOString(), + path: req.originalUrl || req.url, + method: req.method, + }; + } + return response; + } + static error(message, code, details, req) { + const response = { + success: false, + error: { + message, + code, + details, + }, + }; + if (req) { + response.meta = { + timestamp: new Date().toISOString(), + path: req.originalUrl || req.url, + method: req.method, + }; + } + return response; + } + static notFound(message = 'Resource not found', req) { + return this.error(message, 'NOT_FOUND', undefined, req); + } + static validationError(message, details, req) { + return this.error(message, 'VALIDATION_ERROR', details, req); + } + static unauthorized(message = 'Unauthorized', req) { + return this.error(message, 'UNAUTHORIZED', undefined, req); + } + static forbidden(message = 'Forbidden', req) { + return this.error(message, 'FORBIDDEN', undefined, req); + } + static internalError(message = 'Internal server error', req) { + return this.error(message, 'INTERNAL_ERROR', undefined, req); + } +} diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000000..932fd61da8 --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,3861 @@ +{ + "name": "project-final-backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "project-final-backend", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/cors": "^2.8.19", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.10", + "@types/mongoose": "^5.11.96", + "@types/node": "^20.19.11", + "bcryptjs": "^3.0.2", + "cors": "^2.8.5", + "dotenv": "^16.6.1", + "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.4.1" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^8.39.0", + "@typescript-eslint/parser": "^8.39.0", + "eslint": "^8.57.0", + "nodemon": "^3.1.10", + "tsx": "^4.20.4", + "typescript": "^5.9.2" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/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/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.0.tgz", + "integrity": "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ==", + "license": "MIT", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", + "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", + "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/mongoose": { + "version": "5.11.96", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.96.tgz", + "integrity": "sha512-keiY22ljJtXyM7osgScmZOHV6eL5VFUD5tQumlu+hjS++HND5nM8jNEdj5CSWfKIJpVwQfPuwQ2SfBqUnCAVRw==", + "license": "MIT", + "dependencies": { + "mongoose": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.21.tgz", + "integrity": "sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.0.tgz", + "integrity": "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/type-utils": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.39.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.0.tgz", + "integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.0.tgz", + "integrity": "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.39.0", + "@typescript-eslint/types": "^8.39.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz", + "integrity": "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.0.tgz", + "integrity": "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.0.tgz", + "integrity": "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.0.tgz", + "integrity": "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz", + "integrity": "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.39.0", + "@typescript-eslint/tsconfig-utils": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz", + "integrity": "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "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/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, + "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", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "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/bson": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", + "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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/chokidar/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/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "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", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/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/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/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/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "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", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "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", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/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/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "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/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mongodb": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz", + "integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz", + "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^14.1.0 || ^13.0.0" + } + }, + "node_modules/mongoose": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.17.1.tgz", + "integrity": "sha512-aodS4cacux5caoxB5ErEwRmrafIUsVRJxHnvP7URnSUnTenr32j1qBVV+KjYxryyLSisQkxglAFF69TNLeZTLg==", + "license": "MIT", + "dependencies": { + "bson": "^6.10.4", + "kareem": "2.6.3", + "mongodb": "~6.18.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "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/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/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/nodemon/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/nodemon/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/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-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "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/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "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", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "license": "MIT" + }, + "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/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "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", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "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": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsx": { + "version": "4.20.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.4.tgz", + "integrity": "sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "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-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/backend/package.json b/backend/package.json index 08f29f2448..4f7150e65b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,19 +2,45 @@ "name": "project-final-backend", "version": "1.0.0", "description": "Server part of final project", + "main": "dist/index.js", "scripts": { - "start": "babel-node server.js", - "dev": "nodemon server.js --exec babel-node" + "start": "node dist/index.js", + "dev": "nodemon --exec 'tsx' src/index.ts", + "build": "tsc", + "build:watch": "tsc --watch", + "clean": "rm -rf dist", + "seed": "tsx src/services/seedDb.ts", + "create-admin": "tsx src/services/createAdmin.ts", + "lint": "eslint src/**/*.ts", + "lint:fix": "eslint src/**/*.ts --fix", + "type-check": "tsc --noEmit", + "build:prod": "npm run clean && npm run build", + "start:prod": "NODE_ENV=production node dist/index.js" }, "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.17.9", - "@babel/node": "^7.16.8", - "@babel/preset-env": "^7.16.11", + "bcryptjs": "^3.0.2", "cors": "^2.8.5", - "express": "^4.17.3", - "mongoose": "^8.4.0", - "nodemon": "^3.0.1" + "dotenv": "^16.6.1", + "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.4.1", + "@types/bcryptjs": "^2.4.6", + "@types/cors": "^2.8.19", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.10", + "@types/mongoose": "^5.11.96", + "@types/node": "^20.19.11" + }, + "keywords": [], + "type": "module", + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^8.39.0", + "@typescript-eslint/parser": "^8.39.0", + "eslint": "^8.57.0", + "nodemon": "^3.1.10", + "tsx": "^4.20.4", + "typescript": "^5.9.2" } -} \ No newline at end of file +} diff --git a/backend/server.js b/backend/server.js deleted file mode 100644 index 070c875189..0000000000 --- a/backend/server.js +++ /dev/null @@ -1,22 +0,0 @@ -import express from "express"; -import cors from "cors"; -import mongoose from "mongoose"; - -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/final-project"; -mongoose.connect(mongoUrl); -mongoose.Promise = Promise; - -const port = process.env.PORT || 8080; -const app = express(); - -app.use(cors()); -app.use(express.json()); - -app.get("/", (req, res) => { - res.send("Hello Technigo!"); -}); - -// Start the server -app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`); -}); diff --git a/backend/src/config/database.ts b/backend/src/config/database.ts new file mode 100644 index 0000000000..18f91ce68d --- /dev/null +++ b/backend/src/config/database.ts @@ -0,0 +1,34 @@ +import mongoose from 'mongoose'; +import { config } from './environment.js'; + +const connectDB = async (): Promise => { + try { + const mongoURI = config.MONGODB_URI; + + const conn = await mongoose.connect(mongoURI); + + console.log(`[Database] MongoDB Connected: ${conn.connection.host}`); + + // Handle connection events + mongoose.connection.on('error', (err) => { + console.error('[Database] MongoDB connection error:', err); + }); + + mongoose.connection.on('disconnected', () => { + console.warn('[Database] MongoDB disconnected'); + }); + + // Graceful shutdown + process.on('SIGINT', async () => { + await mongoose.connection.close(); + console.log('[Database] MongoDB connection closed through app termination'); + process.exit(0); + }); + + } catch (error) { + console.error('[Database] Error connecting to MongoDB:', error); + process.exit(1); + } +}; + +export default connectDB; diff --git a/backend/src/config/environment.ts b/backend/src/config/environment.ts new file mode 100644 index 0000000000..620076e3ed --- /dev/null +++ b/backend/src/config/environment.ts @@ -0,0 +1,59 @@ +import dotenv from 'dotenv'; + +// Load environment variables +dotenv.config(); + +interface EnvironmentConfig { + NODE_ENV: string; + PORT: number; + MONGODB_URI: string; + FRONTEND_URI: string; + JWT_SECRET: string; + ADMIN_USERNAME: string; + ADMIN_PASSWORD: string; + ADMIN_EMAIL: string; +} + +const requiredEnvVars = [ + 'MONGODB_URI', + 'FRONTEND_URI', + 'JWT_SECRET', + 'ADMIN_USERNAME', + 'ADMIN_PASSWORD', + 'ADMIN_EMAIL', +] as const; + +const validateEnvironment = (): EnvironmentConfig => { + const missingVars = requiredEnvVars.filter(varName => !process.env[varName]); + + if (missingVars.length > 0) { + throw new Error( + `Missing required environment variables: ${missingVars.join(', ')}\n` + + 'Please check your .env file and ensure all required variables are set.' + ); + } + + + if (process.env.NODE_ENV === 'production') { + if (process.env.JWT_SECRET!.length < 32) { + throw new Error('JWT_SECRET must be at least 32 characters long in production'); + } + + if (!process.env.MONGODB_URI!.includes('mongodb.net')) { + console.warn('Warning: Using non-Atlas MongoDB URI in production'); + } + } + + return { + NODE_ENV: process.env.NODE_ENV || 'development', + PORT: parseInt(process.env.PORT || '8888', 10), + MONGODB_URI: process.env.MONGODB_URI!, + FRONTEND_URI: process.env.FRONTEND_URI!, + JWT_SECRET: process.env.JWT_SECRET!, + ADMIN_USERNAME: process.env.ADMIN_USERNAME!, + ADMIN_PASSWORD: process.env.ADMIN_PASSWORD!, + ADMIN_EMAIL: process.env.ADMIN_EMAIL!, + }; +}; + +export const config = validateEnvironment(); diff --git a/backend/src/controllers/adminController.ts b/backend/src/controllers/adminController.ts new file mode 100644 index 0000000000..e487d11254 --- /dev/null +++ b/backend/src/controllers/adminController.ts @@ -0,0 +1,227 @@ +import { Request, Response } from 'express'; +import jwt from 'jsonwebtoken'; +import { Admin } from '../models/Admin.js'; +import { Category } from '../models/Category.js'; +import { Item } from '../models/Item.js'; +import { config } from '../config/environment.js'; + +// Admin Authentication +export const adminLogin = async (req: Request, res: Response) => { + try { + const { username, password } = req.body; + + if (!username || !password) { + return res.status(400).json({ success: false, error: 'Username and password are required' }); + } + + const admin = await Admin.findOne({ username, isActive: true }); + if (!admin || !(await admin.comparePassword(password))) { + return res.status(401).json({ success: false, error: 'Invalid credentials' }); + } + + admin.lastLogin = new Date(); + await admin.save(); + + const token = jwt.sign({ adminId: admin._id }, config.JWT_SECRET, { expiresIn: '24h' }); + + res.json({ + success: true, + data: { + message: 'Login successful', + admin: { id: admin._id, username: admin.username, email: admin.email, lastLogin: admin.lastLogin }, + token + } + }); + } catch (error) { + console.error('[AdminController] Admin login error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const adminLogout = (req: Request, res: Response) => { + res.json({ success: true, data: { message: 'Logout successful' } }); +}; + +export const getAdminProfile = (req: Request, res: Response) => { + const admin = req.admin; + if (!admin) { + return res.status(401).json({ success: false, error: 'Admin not found' }); + } + + res.json({ + success: true, + data: { + admin: { id: admin._id, username: admin.username, email: admin.email, lastLogin: admin.lastLogin } + } + }); +}; + +// Category Management +export const getAllCategories = async (req: Request, res: Response) => { + try { + const categories = await Category.find().sort({ name: 1 }); + res.json({ success: true, data: { categories } }); + } catch (error) { + console.error('[AdminController] Get categories error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const createCategory = async (req: Request, res: Response) => { + try { + const categoryData = req.body; + + if (await Category.findOne({ id: categoryData.id })) { + return res.status(409).json({ success: false, error: 'Category with this ID already exists' }); + } + + const category = new Category(categoryData); + await category.save(); + + res.status(201).json({ + success: true, + data: { + message: 'Category created successfully', + category + } + }); + } catch (error) { + console.error('[AdminController] Create category error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const updateCategory = async (req: Request, res: Response) => { + try { + const { id } = req.params; + const category = await Category.findOneAndUpdate( + { id }, + req.body, + { new: true, runValidators: true } + ); + + if (!category) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + + res.json({ + success: true, + data: { + message: 'Category updated successfully', + category + } + }); + } catch (error) { + console.error('[AdminController] Update category error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const deleteCategory = async (req: Request, res: Response) => { + try { + const { id } = req.params; + + if (!(await Category.findOne({ id }))) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + + if (await Item.countDocuments({ categoryId: id }) > 0) { + return res.status(409).json({ success: false, error: 'Cannot delete category with existing items' }); + } + + await Category.deleteOne({ id }); + res.json({ success: true, data: { message: 'Category deleted successfully' } }); + } catch (error) { + console.error('[AdminController] Delete category error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +// Item Management +export const getAllItems = async (req: Request, res: Response) => { + try { + const { categoryId } = req.query; + const query = categoryId ? { categoryId } : {}; + const items = await Item.find(query).sort({ name: 1 }); + res.json({ success: true, data: { items } }); + } catch (error) { + console.error('[AdminController] Get items error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const createItem = async (req: Request, res: Response) => { + try { + const itemData = req.body; + + if (await Item.findOne({ id: itemData.id })) { + return res.status(409).json({ success: false, error: 'Item with this ID already exists' }); + } + + if (!(await Category.findOne({ id: itemData.categoryId }))) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + + const item = new Item(itemData); + await item.save(); + + res.status(201).json({ + success: true, + data: { + message: 'Item created successfully', + item + } + }); + } catch (error) { + console.error('[AdminController] Create item error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const updateItem = async (req: Request, res: Response) => { + try { + const { id } = req.params; + const updateData = req.body; + + if (updateData.categoryId && !(await Category.findOne({ id: updateData.categoryId }))) { + return res.status(404).json({ success: false, error: 'Category not found' }); + } + + const item = await Item.findOneAndUpdate( + { id }, + updateData, + { new: true, runValidators: true } + ); + + if (!item) { + return res.status(404).json({ success: false, error: 'Item not found' }); + } + + res.json({ + success: true, + data: { + message: 'Item updated successfully', + item + } + }); + } catch (error) { + console.error('[AdminController] Update item error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; + +export const deleteItem = async (req: Request, res: Response) => { + try { + const { id } = req.params; + const item = await Item.findOneAndDelete({ id }); + + if (!item) { + return res.status(404).json({ success: false, error: 'Item not found' }); + } + + res.json({ success: true, data: { message: 'Item deleted successfully' } }); + } catch (error) { + console.error('[AdminController] Delete item error:', error); + res.status(500).json({ success: false, error: 'Internal server error' }); + } +}; \ No newline at end of file diff --git a/backend/src/controllers/quizController.ts b/backend/src/controllers/quizController.ts new file mode 100644 index 0000000000..2e2c4a2c38 --- /dev/null +++ b/backend/src/controllers/quizController.ts @@ -0,0 +1,83 @@ +import { Request, Response } from 'express'; +import { Item } from '../models/Item.js'; +import { Category } from '../models/Category.js'; + + +export const getCategories = async (req: Request, res: Response) => { + try { + const categories = await Category.find({}); + res.status(200).json({ success: true, data: categories }); + } catch (error) { + console.error('[QuizController] Error fetching categories:', error); + res.status(500).json({ success: false, error: 'Error fetching categories' }); + } +}; + +export const getCategoryItems = async (req: Request, res: Response) => { + try { + const { categoryId } = req.params; + const items = await Item.find({ categoryId }); + + if (items.length === 0) { + return res.status(404).json({ success: false, error: 'No items found for this category' }); + } + + res.status(200).json({ success: true, data: items }); + } catch (error) { + console.error('[QuizController] Error fetching category items:', error); + res.status(500).json({ success: false, error: 'Error fetching category items' }); + } +}; + + +export const checkAnswers = async (req: Request, res: Response) => { + try { + const { categoryId, userAnswers } = req.body; + + if (!categoryId || !Array.isArray(userAnswers) || userAnswers.length === 0) { + return res.status(400).json({ + success: false, + error: 'Valid categoryId and userAnswers array are required' + }); + } + + // Get the correct order from the database + const items = await Item.find({ categoryId }).sort({ value: 1 }); + + if (items.length !== userAnswers.length) { + return res.status(400).json({ + success: false, + error: 'Number of answers does not match number of items' + }); + } + + // Check answers + let correctCount = 0; + const results = userAnswers.map((userAnswer: string, index: number) => { + const isCorrect = userAnswer === items[index].id; + if (isCorrect) correctCount++; + return { + userAnswer, + correctAnswer: items[index].id, + isCorrect, + item: { + id: items[index].id, + name: items[index].name, + label: items[index].label, + value: items[index].value + } + }; + }); + + const result = { + isCorrect: correctCount === userAnswers.length, + correctOrder: items, + userOrder: results.map(r => r.item) + }; + + res.status(200).json({ success: true, data: result }); + } catch (error) { + console.error('[QuizController] Error checking answers:', error); + res.status(500).json({ success: false, error: 'Error checking answers' }); + } +}; \ No newline at end of file diff --git a/backend/src/index.ts b/backend/src/index.ts new file mode 100644 index 0000000000..7b4b57a3c8 --- /dev/null +++ b/backend/src/index.ts @@ -0,0 +1,85 @@ +// server/src/index.ts +import express, { Request, Response } from "express"; +import cors from "cors"; +import mongoose from "mongoose"; +import quizRoutes from './routes/quizRoutes.js'; +import adminRoutes from './routes/adminRoutes.js'; +import { errorHandler, notFound } from './middleware/errorHandler.js'; +import connectDB from './config/database.js'; +import { config } from './config/environment.js'; + +const app = express(); +const port = config.PORT; + +// Middleware +app.use( + cors({ + origin: [ + config.FRONTEND_URI, + "https://banganza.netlify.app", + ], + credentials: true, // Allow cookies + methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allowedHeaders: ["Content-Type", "Authorization", "Cookie"], + }) +); +app.use(express.json()); // For handling JSON request bodies + +// Health check endpoint +app.get("/", (req: Request, res: Response) => { + res.json({ + message: "Backend server is running!", + status: "ok", + environment: config.NODE_ENV, + timestamp: new Date().toISOString(), + frontend: config.FRONTEND_URI, + }); +}); + +// Additional health check for production monitoring +app.get("/health", (req: Request, res: Response) => { + const health = { + status: "ok", + timestamp: new Date().toISOString(), + uptime: process.uptime(), + environment: config.NODE_ENV, + database: + mongoose.connection.readyState === 1 ? "connected" : "disconnected", + }; + + if (health.database === "disconnected") { + health.status = "warning"; + } + + res.json(health); +}); + +// Use the new quiz routes +app.use('/api/quiz', quizRoutes); + +// Use admin routes +app.use('/api/admin', adminRoutes); + +// 404 handler +app.use(notFound); + +// Error handling middleware +app.use(errorHandler); + +// Connect to MongoDB +connectDB(); + +// Start the server +app + .listen(port, () => { + console.log(`[Server] Backend server is running on port ${port}`); + if (config.NODE_ENV === "production") { + console.log("[Server] Production mode enabled"); + } else { + console.log(`[Server] Development mode: http://127.0.0.1:${port}`); + } + }) + .on("error", (err) => { + console.error("[Server] Error starting the server:", err); + process.exit(1); + }); \ No newline at end of file diff --git a/backend/src/middleware/auth.ts b/backend/src/middleware/auth.ts new file mode 100644 index 0000000000..46d1507b69 --- /dev/null +++ b/backend/src/middleware/auth.ts @@ -0,0 +1,41 @@ +import { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import { Admin, IAdmin } from '../models/Admin.js'; +import { config } from '../config/environment.js'; + +// Extend Express Request interface to include admin user +declare module 'express' { + interface Request { + admin?: IAdmin; + } +} + +export const authenticateToken = async (req: Request, res: Response, next: NextFunction): Promise => { + try { + const authHeader = req.headers.authorization; + const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN + + if (!token) { + return res.status(401).json({ success: false, error: 'Access token required' }); + } + + const decoded = jwt.verify(token, config.JWT_SECRET) as { adminId: string }; + + // Find admin and check if still active + const admin = await Admin.findById(decoded.adminId).select('-password'); + if (!admin || !admin.isActive) { + return res.status(401).json({ success: false, error: 'Invalid or inactive admin account' }); + } + + req.admin = admin; + next(); + } catch (error) { + if (error instanceof jwt.JsonWebTokenError) { + return res.status(403).json({ success: false, error: 'Invalid token' }); + } + if (error instanceof jwt.TokenExpiredError) { + return res.status(401).json({ success: false, error: 'Token expired' }); + } + return res.status(500).json({ success: false, error: 'Authentication error' }); + } +}; diff --git a/backend/src/middleware/errorHandler.ts b/backend/src/middleware/errorHandler.ts new file mode 100644 index 0000000000..8757e0cde5 --- /dev/null +++ b/backend/src/middleware/errorHandler.ts @@ -0,0 +1,38 @@ +import { Request, Response, NextFunction } from 'express'; + +export const errorHandler = ( + err: Error, + req: Request, + res: Response, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + next: NextFunction +): void => { + const statusCode = 500; + const message = err.message || 'Internal Server Error'; + + // Log error for debugging + console.error(`[ErrorHandler] ${message}:`, { + error: err.message, + statusCode, + path: req.originalUrl, + method: req.method, + userAgent: req.get('User-Agent'), + ip: req.ip, + }); + + // Don't leak error details in production + const errorResponse = { + success: false, + error: message, + ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) + }; + + res.status(statusCode).json(errorResponse); +}; + +export const notFound = (req: Request, res: Response): void => { + res.status(404).json({ + success: false, + error: `Route ${req.originalUrl} not found` + }); +}; diff --git a/backend/src/middleware/validation.ts b/backend/src/middleware/validation.ts new file mode 100644 index 0000000000..eaa3f0548b --- /dev/null +++ b/backend/src/middleware/validation.ts @@ -0,0 +1,28 @@ +import { Request, Response, NextFunction } from 'express'; + +export const validateCategoryId = (req: Request, res: Response, next: NextFunction): void => { + const { categoryId } = req.params; + + if (!categoryId || typeof categoryId !== 'string') { + res.status(400).json({ success: false, error: 'Valid categoryId is required' }); + return; + } + + next(); +}; + +export const validateQuizAnswers = (req: Request, res: Response, next: NextFunction): void => { + const { userAnswers } = req.body; + + if (!Array.isArray(userAnswers) || userAnswers.length === 0) { + res.status(400).json({ success: false, error: 'userAnswers must be a non-empty array' }); + return; + } + + if (!userAnswers.every((id: unknown) => typeof id === 'string')) { + res.status(400).json({ success: false, error: 'All userAnswers must be strings' }); + return; + } + + next(); +}; diff --git a/backend/src/models/Admin.ts b/backend/src/models/Admin.ts new file mode 100644 index 0000000000..4ddd0aa00b --- /dev/null +++ b/backend/src/models/Admin.ts @@ -0,0 +1,63 @@ +import { Schema, model, Document } from 'mongoose'; +import bcrypt from 'bcryptjs'; + +export interface IAdmin extends Document { + username: string; + password: string; + email: string; + isActive: boolean; + lastLogin?: Date; + comparePassword(candidatePassword: string): Promise; +} + +const AdminSchema = new Schema({ + username: { + type: String, + required: true, + unique: true, + trim: true, + minlength: 3, + maxlength: 30 + }, + password: { + type: String, + required: true, + minlength: 6 + }, + email: { + type: String, + required: true, + unique: true, + lowercase: true, + trim: true + }, + isActive: { + type: Boolean, + default: true + }, + lastLogin: { + type: Date + } +}, { + timestamps: true +}); + +// Hash password before saving +AdminSchema.pre('save', async function(next) { + if (!this.isModified('password')) return next(); + + try { + const salt = await bcrypt.genSalt(12); + this.password = await bcrypt.hash(this.password, salt); + next(); + } catch (error) { + next(error as Error); + } +}); + +// Method to compare passwords +AdminSchema.methods.comparePassword = async function(candidatePassword: string): Promise { + return bcrypt.compare(candidatePassword, this.password); +}; + +export const Admin = model('Admin', AdminSchema); diff --git a/backend/src/models/Category.ts b/backend/src/models/Category.ts new file mode 100644 index 0000000000..7ebceb0cc0 --- /dev/null +++ b/backend/src/models/Category.ts @@ -0,0 +1,33 @@ +import { Schema, model, Document } from 'mongoose'; + +export interface ICategory extends Document { + id: string; + name: string; + description?: string; + question?: string; + unit: string; + unitVisible?: boolean; + sort?: 'asc' | 'desc'; + source?: { + name: string; + url: string; + }; + version?: number; +} + +const CategorySchema = new Schema({ + id: { type: String, required: true, unique: true }, + name: { type: String, required: true }, + description: { type: String, required: false }, + question: { type: String, required: false }, + unit: { type: String, required: true }, + unitVisible: { type: Boolean, required: false }, + sort: { type: String, enum: ['asc', 'desc'], required: false }, + source: { + name: { type: String, required: false }, + url: { type: String, required: false } + }, + version: { type: Number, required: false } +}, { strict: false, timestamps: false }); + +export const Category = model('Category', CategorySchema); \ No newline at end of file diff --git a/backend/src/models/Item.ts b/backend/src/models/Item.ts new file mode 100644 index 0000000000..ba0bf352b3 --- /dev/null +++ b/backend/src/models/Item.ts @@ -0,0 +1,17 @@ +import { Schema, model, Document } from 'mongoose'; +import { QuizItem } from '../types/quiz.js'; + +export interface IItem extends Document, Omit {} + +const ItemSchema = new Schema({ + id: { type: String, required: true, unique: true }, + name: { type: String, required: true }, + value: { type: Number, required: true }, + label: { type: String, required: true }, + categoryId: { type: String, required: true }, + source: { + name: { type: String, required: false } + } +}); + +export const Item = model('Item', ItemSchema); \ No newline at end of file diff --git a/backend/src/routes/adminRoutes.ts b/backend/src/routes/adminRoutes.ts new file mode 100644 index 0000000000..95dd6411f0 --- /dev/null +++ b/backend/src/routes/adminRoutes.ts @@ -0,0 +1,41 @@ +import express from 'express'; +import { + adminLogin, + adminLogout, + getAdminProfile, + getAllCategories, + createCategory, + updateCategory, + deleteCategory, + getAllItems, + createItem, + updateItem, + deleteItem +} from '../controllers/adminController.js'; +import { authenticateToken } from '../middleware/auth.js'; + +const router = express.Router(); + +// Public routes (no authentication required) +router.post('/login', adminLogin); + +// Protected routes (authentication required) +router.use(authenticateToken); + +// Admin profile +router.get('/profile', getAdminProfile); +router.post('/logout', adminLogout); + +// Category management +router.get('/categories', getAllCategories); +router.post('/categories', createCategory); +router.put('/categories/:id', updateCategory); +router.delete('/categories/:id', deleteCategory); + +// Item management +router.get('/items', getAllItems); +router.post('/items', createItem); +router.put('/items/:id', updateItem); +router.delete('/items/:id', deleteItem); + +export default router; diff --git a/backend/src/routes/quizRoutes.ts b/backend/src/routes/quizRoutes.ts new file mode 100644 index 0000000000..e109c7b7e3 --- /dev/null +++ b/backend/src/routes/quizRoutes.ts @@ -0,0 +1,11 @@ +import { Router } from 'express'; +import { getCategories, getCategoryItems, checkAnswers } from '../controllers/quizController.js'; +import { validateCategoryId, validateQuizAnswers } from '../middleware/validation.js'; + +const router = Router(); + +router.get('/categories', getCategories); +router.get('/category/:categoryId/items', validateCategoryId, getCategoryItems); +router.post('/check', validateQuizAnswers, checkAnswers); + +export default router; \ No newline at end of file diff --git a/backend/src/services/createAdmin.ts b/backend/src/services/createAdmin.ts new file mode 100644 index 0000000000..00e1df5fe5 --- /dev/null +++ b/backend/src/services/createAdmin.ts @@ -0,0 +1,34 @@ +import connectDB from '../config/database.js'; +import { Admin } from '../models/Admin.js'; +import { config } from '../config/environment.js'; + +const createInitialAdmin = async () => { + try { + await connectDB(); + + // Check if admin already exists + const existingAdmin = await Admin.findOne({ username: config.ADMIN_USERNAME }); + if (existingAdmin) { + console.log('[CreateAdmin] Admin user already exists'); + process.exit(0); + } + + // Create initial admin user + const admin = new Admin({ + username: config.ADMIN_USERNAME, + password: config.ADMIN_PASSWORD, + email: config.ADMIN_EMAIL, + isActive: true + }); + + await admin.save(); + console.log(`[CreateAdmin] Initial admin user created successfully: ${config.ADMIN_USERNAME} (${config.ADMIN_EMAIL})`); + + process.exit(0); + } catch (error) { + console.error('[CreateAdmin] Error creating admin user', error); + process.exit(1); + } +}; + +createInitialAdmin(); diff --git a/backend/src/services/seedDb.ts b/backend/src/services/seedDb.ts new file mode 100644 index 0000000000..113987e096 --- /dev/null +++ b/backend/src/services/seedDb.ts @@ -0,0 +1,68 @@ +// /backend/src/services/seedDb.ts +import mongoose from 'mongoose'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; +import { Item } from '../models/Item.js'; +import { Category } from '../models/Category.js'; +import { config } from '../config/environment.js'; + +// Get __dirname equivalent for ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Helper function to read and parse a JSON file +const readJsonFile = (filePath: string) => { + try { + const fileContent = fs.readFileSync(filePath, 'utf-8'); + return JSON.parse(fileContent); + } catch (error) { + console.error(`[SeedDB] Error reading or parsing file: ${filePath}`, error); + return null; + } +}; + +const seedData = async () => { + try { + await mongoose.connect(config.MONGODB_URI); + console.log('[SeedDB] Connected to MongoDB'); + + // Clear existing data to prevent duplicates on re-seed + await Item.deleteMany({}); + await Category.deleteMany({}); + console.log('[SeedDB] Existing data cleared'); + + // Step 1: Read and seed Category data from JSON files + const categoriesPath = path.join(__dirname, '../../data/categories'); + const categoryFiles = fs.readdirSync(categoriesPath).filter(file => file.endsWith('.json')); + + for (const file of categoryFiles) { + const categoryData = readJsonFile(path.join(categoriesPath, file)); + if (categoryData) { + await mongoose.connection.collection('categories').insertOne(categoryData); + console.log(`[SeedDB] Category "${categoryData.name}" seeded`); + } + } + + // Step 2: Read and seed Item data from JSON files + const itemsPath = path.join(__dirname, '../../data/items'); + const itemFiles = fs.readdirSync(itemsPath).filter(file => file.endsWith('.json')); + + for (const file of itemFiles) { + const itemsData = readJsonFile(path.join(itemsPath, file)); + if (itemsData && Array.isArray(itemsData)) { + await Item.insertMany(itemsData); + console.log(`[SeedDB] Items from file "${file}" seeded`); + } + } + + console.log('[SeedDB] Database seeding complete!'); + mongoose.connection.close(); + + } catch (error) { + console.error('[SeedDB] Database seeding failed', error); + mongoose.connection.close(); + } +}; + +seedData(); \ No newline at end of file diff --git a/backend/src/types/quiz.ts b/backend/src/types/quiz.ts new file mode 100644 index 0000000000..ece38d8579 --- /dev/null +++ b/backend/src/types/quiz.ts @@ -0,0 +1,27 @@ +export interface QuizItem { + _id: string; + id: string; + name: string; + value: number; + label: string; + categoryId: string; + source: { + name: string; + }; +} + +export interface QuizCategory { + _id: string; + id: string; + name: string; + description?: string; + question?: string; + unit: string; + unitVisible?: boolean; + sort?: 'asc' | 'desc'; + source?: { + name: string; + url: string; + }; + version?: number; +} \ No newline at end of file diff --git a/backend/tsconfig.json b/backend/tsconfig.json new file mode 100644 index 0000000000..3bd349319d --- /dev/null +++ b/backend/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "esnext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": false, + "declarationMap": false, + "sourceMap": false, + "resolveJsonModule": true, + "allowJs": false, + "noEmit": false + }, + "include": ["src/**/*"], + "exclude": ["node_modules", + "dist", + "data", + "src/services/seedDb.ts", + "src/services/createAdmin.ts" +] +} \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md index 5cdb1d9cf3..340009dcb4 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,8 +1,11 @@ -# Frontend part of Final Project +# Install dependencies (if needed) +npm install -This boilerplate is designed to give you a head start in your React projects, with a focus on understanding the structure and components. As a student of Technigo, you'll find this guide helpful in navigating and utilizing the repository. +# Run linting +npm run lint -## Getting Started +# Type check +npm run type-check -1. Install the required dependencies using `npm install`. -2. Start the development server using `npm run dev`. \ No newline at end of file +# Start development server +npm run dev \ No newline at end of file diff --git a/frontend/declaration.d.ts b/frontend/declaration.d.ts new file mode 100644 index 0000000000..fc347d274d --- /dev/null +++ b/frontend/declaration.d.ts @@ -0,0 +1,12 @@ +declare module "*.css"; + +/// + +interface ImportMetaEnv { + readonly VITE_BACKEND_URL: string + readonly VITE_FRONTEND_URL: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/frontend/dist/_redirects b/frontend/dist/_redirects new file mode 100644 index 0000000000..ad37e2c2c9 --- /dev/null +++ b/frontend/dist/_redirects @@ -0,0 +1 @@ +/* /index.html 200 diff --git a/frontend/dist/assets/cygnito-mono-regular-CF-bI0VJ.otf b/frontend/dist/assets/cygnito-mono-regular-CF-bI0VJ.otf new file mode 100644 index 0000000000..0956c58e28 Binary files /dev/null and b/frontend/dist/assets/cygnito-mono-regular-CF-bI0VJ.otf differ diff --git a/frontend/dist/banganzalogo.svg b/frontend/dist/banganzalogo.svg new file mode 100644 index 0000000000..ad3b060a87 --- /dev/null +++ b/frontend/dist/banganzalogo.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/dist/index.html b/frontend/dist/index.html new file mode 100644 index 0000000000..c5ab179064 --- /dev/null +++ b/frontend/dist/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + BANGANZA + + + + +
+ + diff --git a/frontend/dist/intro.mp4 b/frontend/dist/intro.mp4 new file mode 100644 index 0000000000..eab20e4279 Binary files /dev/null and b/frontend/dist/intro.mp4 differ diff --git a/frontend/dist/intropic.png b/frontend/dist/intropic.png new file mode 100644 index 0000000000..8f1445a45e Binary files /dev/null and b/frontend/dist/intropic.png differ diff --git a/frontend/dist/vite.svg b/frontend/dist/vite.svg new file mode 100644 index 0000000000..e7b8dfb1b2 --- /dev/null +++ b/frontend/dist/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000000..f648297c04 --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,64 @@ +import js from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; +import react from "eslint-plugin-react"; +import hooks from "eslint-plugin-react-hooks"; +import unusedImports from "eslint-plugin-unused-imports"; + +export default [ + { ignores: ["dist/**", "node_modules/**", "public/**", "coverage/**"] }, + + js.configs.recommended, + ...tseslint.configs.recommended, + react.configs.flat.recommended, + + { + files: ["**/*.{ts,tsx,js,jsx}"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + globals: { ...globals.browser, ...globals.node }, + parserOptions: { + ecmaFeatures: { jsx: true }, + }, + }, + plugins: { + react, + "react-hooks": hooks, + "unused-imports": unusedImports, + }, + settings: { + react: { version: "detect" }, + }, + rules: { + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + + "react/react-in-jsx-scope": "off", + "react/jsx-uses-react": "off", + + "react/no-unescaped-entities": "off", + + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + vars: "all", + args: "after-used", + varsIgnorePattern: "^_", + argsIgnorePattern: "^_", + }, + ], + + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-unused-vars": [ + "warn", + { argsIgnorePattern: "^_" }, + ], + + "no-console": ["warn", { allow: ["warn", "error"] }], + "no-debugger": "warn", + "react/prop-types": "off", + }, + }, +]; diff --git a/frontend/index.html b/frontend/index.html index 664410b5b9..e2201134e1 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,12 +2,18 @@ - + + + + - Technigo React Vite Boiler Plate + BANGANZA
- + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000000..5bd896a209 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,6462 @@ +{ + "name": "project-final-frontend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "project-final-frontend", + "version": "1.0.0", + "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/modifiers": "^9.0.0", + "clsx": "^2.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^7.7.1", + "tailwind-merge": "^3.3.1", + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.7" + }, + "devDependencies": { + "@eslint/js": "^8.57.1", + "@tailwindcss/vite": "^4.1.11", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.7", + "@vitejs/plugin-react": "^4.7.0", + "eslint": "^8.57.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-unused-imports": "^3.2.0", + "globals": "^15.15.0", + "tailwindcss": "^4.1.11", + "ts-prune": "^0.10.3", + "typescript": "^5.9.2", + "typescript-eslint": "^7.18.0", + "vite": "^6.3.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/modifiers": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@dnd-kit/modifiers/-/modifiers-9.0.0.tgz", + "integrity": "sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==", + "license": "MIT", + "dependencies": { + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@dnd-kit/core": "^6.3.0", + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz", + "integrity": "sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.49.0.tgz", + "integrity": "sha512-cqPpZdKUSQYRtLLr6R4X3sD4jCBO1zUmeo3qrWBCqYIeH8Q3KRL4F3V7XJ2Rm8/RJOQBZuqzQGWPjjvFUcYa/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz", + "integrity": "sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.49.0.tgz", + "integrity": "sha512-y8cXoD3wdWUDpjOLMKLx6l+NFz3NlkWKcBCBfttUn+VGSfgsQ5o/yDUGtzE9HvsodkP0+16N0P4Ty1VuhtRUGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.49.0.tgz", + "integrity": "sha512-3mY5Pr7qv4GS4ZvWoSP8zha8YoiqrU+e0ViPvB549jvliBbdNLrg2ywPGkgLC3cmvN8ya3za+Q2xVyT6z+vZqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.49.0.tgz", + "integrity": "sha512-C9KzzOAQU5gU4kG8DTk+tjdKjpWhVWd5uVkinCwwFub2m7cDYLOdtXoMrExfeBmeRy9kBQMkiyJ+HULyF1yj9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.49.0.tgz", + "integrity": "sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.49.0.tgz", + "integrity": "sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.49.0.tgz", + "integrity": "sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.49.0.tgz", + "integrity": "sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.49.0.tgz", + "integrity": "sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.49.0.tgz", + "integrity": "sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.49.0.tgz", + "integrity": "sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.49.0.tgz", + "integrity": "sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.49.0.tgz", + "integrity": "sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.49.0.tgz", + "integrity": "sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.49.0.tgz", + "integrity": "sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.49.0.tgz", + "integrity": "sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.49.0.tgz", + "integrity": "sha512-gq5aW/SyNpjp71AAzroH37DtINDcX1Qw2iv9Chyz49ZgdOP3NV8QCyKZUrGsYX9Yyggj5soFiRCgsL3HwD8TdA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz", + "integrity": "sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.12.tgz", + "integrity": "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.5.1", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.12.tgz", + "integrity": "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-x64": "4.1.12", + "@tailwindcss/oxide-freebsd-x64": "4.1.12", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-x64-musl": "4.1.12", + "@tailwindcss/oxide-wasm32-wasi": "4.1.12", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.12.tgz", + "integrity": "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.12.tgz", + "integrity": "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz", + "integrity": "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.12.tgz", + "integrity": "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.12.tgz", + "integrity": "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.12.tgz", + "integrity": "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.12.tgz", + "integrity": "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.12.tgz", + "integrity": "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.12.tgz", + "integrity": "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.12.tgz", + "integrity": "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@emnapi/wasi-threads": "^1.0.4", + "@napi-rs/wasm-runtime": "^0.2.12", + "@tybys/wasm-util": "^0.10.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz", + "integrity": "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.12.tgz", + "integrity": "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.12.tgz", + "integrity": "sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.12", + "@tailwindcss/oxide": "4.1.12", + "tailwindcss": "4.1.12" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.12.3.tgz", + "integrity": "sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.7", + "minimatch": "^3.0.4", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.24", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz", + "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "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/browserslist": { + "version": "4.25.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz", + "integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001735", + "electron-to-chromium": "^1.5.204", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001737", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz", + "integrity": "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/code-block-writer": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", + "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "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/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.209", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.209.tgz", + "integrity": "sha512-Xoz0uMrim9ZETCQt8UgM5FxQF9+imA7PBpokoGcZloA1uw2LeHzTlip5cb5KOAsXZLjh/moN2vReN3ZjJmjI9A==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", + "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/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/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "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/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "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", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/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/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/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.2.tgz", + "integrity": "sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.2.tgz", + "integrity": "sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==", + "license": "MIT", + "dependencies": { + "react-router": "7.8.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", + "integrity": "sha512-3IVq0cGJ6H7fKXXEdVt+RcYvRCt8beYY9K1760wGQwSAHZcS9eot1zDG5axUbcp/kWRi5zKIIDX8MoKv/TzvZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.49.0", + "@rollup/rollup-android-arm64": "4.49.0", + "@rollup/rollup-darwin-arm64": "4.49.0", + "@rollup/rollup-darwin-x64": "4.49.0", + "@rollup/rollup-freebsd-arm64": "4.49.0", + "@rollup/rollup-freebsd-x64": "4.49.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.49.0", + "@rollup/rollup-linux-arm-musleabihf": "4.49.0", + "@rollup/rollup-linux-arm64-gnu": "4.49.0", + "@rollup/rollup-linux-arm64-musl": "4.49.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.49.0", + "@rollup/rollup-linux-ppc64-gnu": "4.49.0", + "@rollup/rollup-linux-riscv64-gnu": "4.49.0", + "@rollup/rollup-linux-riscv64-musl": "4.49.0", + "@rollup/rollup-linux-s390x-gnu": "4.49.0", + "@rollup/rollup-linux-x64-gnu": "4.49.0", + "@rollup/rollup-linux-x64-musl": "4.49.0", + "@rollup/rollup-win32-arm64-msvc": "4.49.0", + "@rollup/rollup-win32-ia32-msvc": "4.49.0", + "@rollup/rollup-win32-x64-msvc": "4.49.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", + "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", + "license": "MIT" + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tapable": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", + "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "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/true-myth": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/true-myth/-/true-myth-4.1.1.tgz", + "integrity": "sha512-rqy30BSpxPznbbTcAcci90oZ1YR4DqvKcNXNerG5gQBU2v4jk0cygheiul5J6ExIMrgDVuanv/MkGfqZbKrNNg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "10.* || >= 12.*" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-morph": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-13.0.3.tgz", + "integrity": "sha512-pSOfUMx8Ld/WUreoSzvMFQG5i9uEiWIsBYjpU9+TTASOeUa89j5HykomeqVULm1oqWtBdleI3KEFRLrlA3zGIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.12.3", + "code-block-writer": "^11.0.0" + } + }, + "node_modules/ts-prune": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-prune/-/ts-prune-0.10.3.tgz", + "integrity": "sha512-iS47YTbdIcvN8Nh/1BFyziyUqmjXz7GVzWu02RaZXqb+e/3Qe1B7IQ4860krOeCGUeJmterAlaM2FRH0Ue0hjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^6.2.1", + "cosmiconfig": "^7.0.1", + "json5": "^2.1.3", + "lodash": "^4.17.21", + "true-myth": "^4.1.0", + "ts-morph": "^13.0.1" + }, + "bin": { + "ts-prune": "lib/index.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", + "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.18.0", + "@typescript-eslint/parser": "7.18.0", + "@typescript-eslint/utils": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz", + "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json index 7b2747e949..f44bf13550 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,26 +1,43 @@ { - "name": "project-final-backend", + "name": "project-final-frontend", "description": "Client part of final project", "version": "1.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", - "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "prune": "ts-prune", "preview": "vite preview" }, - "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, "devDependencies": { - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", - "@vitejs/plugin-react": "^4.0.3", - "eslint": "^8.45.0", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", + "@eslint/js": "^8.57.1", + "@tailwindcss/vite": "^4.1.11", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.7", + "@vitejs/plugin-react": "^4.7.0", + "eslint": "^8.57.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-unused-imports": "^3.2.0", + "globals": "^15.15.0", + "tailwindcss": "^4.1.11", + "ts-prune": "^0.10.3", + "typescript": "^5.9.2", + "typescript-eslint": "^7.18.0", "vite": "^6.3.5" + }, + "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/modifiers": "^9.0.0", + "clsx": "^2.1.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^7.7.1", + "tailwind-merge": "^3.3.1", + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.7" } } diff --git a/frontend/public/_redirects b/frontend/public/_redirects new file mode 100644 index 0000000000..ad37e2c2c9 --- /dev/null +++ b/frontend/public/_redirects @@ -0,0 +1 @@ +/* /index.html 200 diff --git a/frontend/public/banganzalogo.svg b/frontend/public/banganzalogo.svg new file mode 100644 index 0000000000..ad3b060a87 --- /dev/null +++ b/frontend/public/banganzalogo.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/intro.mp4 b/frontend/public/intro.mp4 new file mode 100644 index 0000000000..eab20e4279 Binary files /dev/null and b/frontend/public/intro.mp4 differ diff --git a/frontend/public/intropic.png b/frontend/public/intropic.png new file mode 100644 index 0000000000..8f1445a45e Binary files /dev/null and b/frontend/public/intropic.png differ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx deleted file mode 100644 index 0a24275e6e..0000000000 --- a/frontend/src/App.jsx +++ /dev/null @@ -1,8 +0,0 @@ -export const App = () => { - - return ( - <> -

Welcome to Final Project!

- - ); -}; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000000..e6f2c573f7 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { + BrowserRouter as Router, + Routes, + Route, +} from "react-router-dom"; +import { Home } from "./pages/Home"; +import GameMode from "./pages/GameMode"; +import AdminPage from "./pages/AdminPage"; + +export const App = () => { + return ( + + + } /> + } /> + } /> + + + ); +}; diff --git a/frontend/src/assets/banana.png b/frontend/src/assets/banana.png new file mode 100644 index 0000000000..d7f46bd573 Binary files /dev/null and b/frontend/src/assets/banana.png differ diff --git a/frontend/src/assets/banganzalogo.png b/frontend/src/assets/banganzalogo.png new file mode 100644 index 0000000000..0d70f97a04 Binary files /dev/null and b/frontend/src/assets/banganzalogo.png differ diff --git a/frontend/src/assets/cygnito-mono-regular.otf b/frontend/src/assets/cygnito-mono-regular.otf new file mode 100755 index 0000000000..0956c58e28 Binary files /dev/null and b/frontend/src/assets/cygnito-mono-regular.otf differ diff --git a/frontend/src/components/BanganzaIntro.tsx b/frontend/src/components/BanganzaIntro.tsx new file mode 100644 index 0000000000..6aa1eb1e6f --- /dev/null +++ b/frontend/src/components/BanganzaIntro.tsx @@ -0,0 +1,47 @@ +import { useRef, useState } from "react"; + +type Props = { onFinish?: () => void }; + +export default function BanganzaIntro({ onFinish }: Props) { + const [exiting, setExiting] = useState(false); + const doneRef = useRef(false); + + function endWithFade() { + if (doneRef.current) return; + doneRef.current = true; + setExiting(true); + setTimeout(() => onFinish?.(), 100); + } + + return ( +
+ + + {/* dark overlay fading in on exit → prevents bright flash */} +
+
+ ); +} diff --git a/frontend/src/components/CategorySelector.tsx b/frontend/src/components/CategorySelector.tsx new file mode 100644 index 0000000000..84907b9ed3 --- /dev/null +++ b/frontend/src/components/CategorySelector.tsx @@ -0,0 +1,205 @@ +import React, { useEffect } from "react"; +import { useGame } from "../store/game"; +import { Spinner } from "../ui/Spinner"; +import { useNavigate } from "react-router-dom"; + +const AnimalIcon = () => ( + + + + + + + +); + +const PersonIcon = () => ( + + + + + + + + + + +); + +const GlobeIcon = () => ( + + + + + + + + +); + +const GameIcon = () => ( + + + + + + + +); + +const ElementIcon = () => ( + + + + + + +); + +const InternetIcon = () => ( + + + + + + + +); + +export const CategorySelector: React.FC = () => { + const { + categories, + loading, + error, + loadCategories, + selectCategory, + selectedCategory, + } = useGame(); + const navigate = useNavigate(); + + useEffect(() => { + loadCategories(); + }, [loadCategories]); + + if (loading) + return ( +
+ +
+ ); + + if (error) + return ( +
+
Error: {error}
+
+ ); + + const iconFor = (id: string) => { + if (id.startsWith("animals")) return ; + if (id.startsWith("celebrities")) return ; + if (id.startsWith("games")) return ; + if (id.startsWith("element")) return ; + if (id.startsWith("internet")) return ; + return ; + }; + + return ( +
+
+

+ THE CATEGORIES +

+

+ Pick one to start playing +

+
+
+ {categories.map((c) => { + const active = selectedCategory?.id === c.id; + return ( + + ); + })} +
+
+ ); +}; diff --git a/frontend/src/components/ConfirmModal.tsx b/frontend/src/components/ConfirmModal.tsx new file mode 100644 index 0000000000..280a7ebd8f --- /dev/null +++ b/frontend/src/components/ConfirmModal.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import { Button } from "../ui"; + +interface ConfirmModalProps { + isOpen: boolean; + onClose: () => void; + onConfirm: () => void; + title: string; + message: string; + confirmText?: string; + cancelText?: string; +} + +export const ConfirmModal: React.FC = ({ + isOpen, + onClose, + onConfirm, + title, + message, + confirmText = "Confirm", + cancelText = "Cancel", +}) => { + const handleConfirm = React.useCallback(() => { + onConfirm(); + onClose(); + }, [onConfirm, onClose]); + + const handleCancel = React.useCallback(() => { + onClose(); + }, [onClose]); + + React.useEffect(() => { + const handleEscape = (e: KeyboardEvent) => { + if (e.key === "Escape") { + onClose(); + } + }; + + if (isOpen) { + document.addEventListener("keydown", handleEscape); + return () => document.removeEventListener("keydown", handleEscape); + } + }, [isOpen, onClose]); + + React.useEffect(() => { + if (isOpen) { + document.body.style.overflow = "hidden"; + return () => { + document.body.style.overflow = "unset"; + }; + } + }, [isOpen]); + + if (!isOpen) { + return null; + } + + return ( +
+ + ); +}; diff --git a/frontend/src/components/CurrentCard.tsx b/frontend/src/components/CurrentCard.tsx new file mode 100644 index 0000000000..c69af8d4b8 --- /dev/null +++ b/frontend/src/components/CurrentCard.tsx @@ -0,0 +1,65 @@ +import React from "react"; +import { useDraggable } from "@dnd-kit/core"; +import { Card, CardHeader, CardContent } from "../ui"; +import type { GameItem } from "../types/game"; + +export const CurrentCard: React.FC<{ card: GameItem; dragging?: boolean }> = ({ + card, + dragging, +}) => { + const { attributes, listeners, setNodeRef, transform } = useDraggable({ + id: "current-card", + }); + + const style: React.CSSProperties | undefined = transform + ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)` } + : undefined; + + return ( +
+ + +
+ Place in timeline +
+
+ +
+ {card.name} +
+
+ ? +
+
+
+
+ ); +}; + +export const CurrentCardPreview: React.FC<{ card: GameItem }> = ({ card }) => ( +
+ + +
+ Place in timeline +
+
+ +
+ {card.name} +
+
+ ? +
+
+
+
+); diff --git a/frontend/src/components/GameBoard.tsx b/frontend/src/components/GameBoard.tsx new file mode 100644 index 0000000000..ffb01cbe16 --- /dev/null +++ b/frontend/src/components/GameBoard.tsx @@ -0,0 +1,533 @@ +import React from "react"; +import { + DndContext, + MouseSensor, + TouchSensor, + useSensor, + useSensors, + DragStartEvent, + DragEndEvent, + DragOverlay, + useDroppable, + closestCenter, +} from "@dnd-kit/core"; +import { useNavigate } from "react-router-dom"; + +import { useGame } from "../store/game"; +import { Button } from "../ui"; +import { ErrorMessage } from "../ui/ErrorMessage"; +import { TimeLineCard } from "./TimeLineCard"; +import { CurrentCard, CurrentCardPreview } from "./CurrentCard"; + +const DropSlot: React.FC<{ id: string; show: boolean }> = ({ id, show }) => { + const { setNodeRef, isOver } = useDroppable({ id }); + if (!show) return null; + + return ( +
+ ); +}; + +export const GameBoard: React.FC<{ className?: string }> = ({ className }) => { + const teams = useGame((s) => s.teams); + const currentTeamIndex = useGame((s) => s.currentTeamIndex); + const phase = useGame((s) => s.phase); + const currentCard = useGame((s) => s.currentCard); + + const startGame = useGame((s) => s.startGame); + const startTurn = useGame((s) => s.startTurn); + const placeAt = useGame((s) => s.placeAt); + const drawAnother = useGame((s) => s.drawAnother); + const lockIn = useGame((s) => s.lockIn); + const confirmPlacement = useGame((s) => s.confirmPlacement); + const nextTeam = useGame((s) => s.nextTeam); + + const loading = useGame((s) => s.loading); + const error = useGame((s) => s.error); + const clearError = useGame((s) => s.clearError); + + const pendingIndex = useGame((s) => s.pendingIndex); + const lastPlacementCorrect = useGame((s) => s.lastPlacementCorrect); + const selectedCategory = useGame((s) => s.selectedCategory); + const lastTurnFeedback = useGame((s) => s.lastTurnFeedback); + const turnTimeline = useGame((s) => s.turnTimeline); + const timer = useGame((s) => s.timer); + const settings = useGame((s) => s.settings); + const wrongAnswerCard = useGame((s) => s.wrongAnswerCard); + + const team = teams[currentTeamIndex]; + + const navigate = useNavigate(); + + const winner = useGame((s) => (s as any).winner); + + const sensors = useSensors( + useSensor(MouseSensor), + useSensor(TouchSensor, { activationConstraint: { delay: 250, tolerance: 5 } }) + ); + const [isDragging, setIsDragging] = React.useState(false); + + const onDragStart = (e: DragStartEvent) => { + if ( + e.active.id === "current-card" && + lastPlacementCorrect !== false && + phase !== "PLACED_WRONG" + ) { + setIsDragging(true); + } + }; + + const onDragEnd = (e: DragEndEvent) => { + setIsDragging(false); + if (lastPlacementCorrect === false || phase === "PLACED_WRONG") return; + + const overId = e.over?.id as string | undefined; + if (!overId || !overId.startsWith("slot-")) return; + const n = Number(overId.slice(5)); + if (!Number.isFinite(n)) return; + if (!currentCard) return; + placeAt(n); + }; + + const [showWinner, setShowWinner] = React.useState(true); + React.useEffect(() => { + setShowWinner(true); + const onKey = (e: KeyboardEvent) => { + if (e.key === "Escape") setShowWinner(false); + }; + window.addEventListener("keydown", onKey); + return () => window.removeEventListener("keydown", onKey); + }, [winner]); + + const winnerName = React.useMemo(() => { + if (!winner) return null; + if (typeof winner === "number") return teams[winner]?.name ?? "Team"; + if (typeof winner === "string") return winner; + if (typeof winner === "object") { + if ("teamIndex" in winner) + return teams[(winner as any).teamIndex]?.name ?? "Team"; + if ("index" in winner) + return teams[(winner as any).index]?.name ?? "Team"; + if ("name" in winner) return (winner as any).name ?? "Team"; + } + const bestIdx = teams.reduce( + (best, _, i, arr) => + (arr[i].timeline?.length ?? 0) > (arr[best].timeline?.length ?? 0) + ? i + : best, + 0 + ); + return teams[bestIdx]?.name ?? "Team"; + }, [winner, teams]); + + + const renderTimeline = () => { + const teamTimeline = team?.timeline ?? []; + const base = + phase === "DRAWN" || + phase === "PLACED_PENDING" || + phase === "CHOICE_AFTER_CORRECT" + ? turnTimeline + : teamTimeline; + + const showSlots = phase === "DRAWN" || phase === "PLACED_PENDING"; + + + if (lastTurnFeedback?.timeUp && lastTurnFeedback.correct == null) { + return ( +
+
+
+
+ TIME’S UP! +
+
+ + Your turn is over, it's time for the next team. + +
+
+
+
+ ); + } + + if ( + lastPlacementCorrect === false || + phase === "PLACED_WRONG" || + (lastTurnFeedback?.timeUp && lastTurnFeedback.correct === false) + ) { + const heading = lastTurnFeedback?.timeUp ? "TIME'S UP!" : "OH NO!"; + return ( +
+
+
+
+ OH NO! +
+
+ + Wrong answer. Your turn is over. + +
+ {wrongAnswerCard && ( +
+
+ +
+
+ )} +
+
+
+ ); + } + + if (lastTurnFeedback?.timeUp && lastTurnFeedback.correct === null) { + return ( +
+
+
+
+ TIME'S UP! +
+
+ + Your turn is over, it's time for the next team. + +
+
+
+
+ ); + } + + const children: React.ReactNode[] = []; + children.push(); + + for (let i = 0; i < base.length; i++) { + if (phase === "PLACED_PENDING" && pendingIndex === i && currentCard) { + children.push( +
+
+ +
+
+ ); + } + + const c = base[i] as any; + const isLastPlaced = + lastPlacementCorrect !== null && + pendingIndex !== null && + i === pendingIndex; + + children.push( +
+
+ +
+
+ ); + + children.push( + + ); + } + + if ( + phase === "PLACED_PENDING" && + pendingIndex === base.length && + currentCard + ) { + children.splice( + children.length - 1, + 0, +
+
+ +
+
+ ); + } + + return ( +
+
+ {children} +
+ + {lastPlacementCorrect === true && ( +
+ + + + + {lastTurnFeedback?.timeUp && lastTurnFeedback.correct === true + ? "Time’s up. Correct!" + : "CORRECT!"} + +
+ )} + + {phase === "PLACED_PENDING" && ( +
+ +
+ )} +
+ ); + }; + + const renderTimelineCounter = () => { + const isActiveTurn = phase === "DRAWN" || phase === "PLACED_PENDING" || phase === "CHOICE_AFTER_CORRECT"; + const currentTimeline = isActiveTurn ? turnTimeline : (team?.timeline ?? []); + const cardCount = currentTimeline.length; + + return ( +
+
+ + Card{cardCount !== 1 ? 's' : ''}: {cardCount} + +
+
+ ); + }; + + const renderTimer = () => { + if (phase !== "DRAWN" && phase !== "PLACED_PENDING" && phase !== "CHOICE_AFTER_CORRECT") { + return null; + } + + const total = settings.turnSeconds; + const left = timer.secondsLeft; + const elapsed = total - left; + const pct = Math.max(0, Math.min(100, Math.round((elapsed / total) * 100))); + + return ( +
+
+ {String(Math.floor(left / 60)).padStart(2, "0")}: + {String(left % 60).padStart(2, "0")} +
+
+
+
+
+ ); + }; + + return ( +
+ {loading && ( +
Loading items…
+ )} + {error && ( +
+ + +
+ )} + + {phase === "SETUP" && ( +
+ +
+ )} + + {phase !== "SETUP" && ( + <> + + +
+ +
+ {renderTimer()} +
+ +
+ {renderTimelineCounter()} + {renderTimeline()} +
+ + {phase === "DRAWN" && currentCard && lastPlacementCorrect !== false && !(lastTurnFeedback?.timeUp && lastTurnFeedback.correct === null) && ( +
+ Drag the card and drop it between two cards. +
+ )} + + {phase === "DRAWN" && currentCard && lastPlacementCorrect !== false && !(lastTurnFeedback?.timeUp && lastTurnFeedback.correct === null) && ( +
+
+ +
+
+ )} +
+ + + {isDragging && + currentCard && + lastPlacementCorrect !== false && + phase !== "PLACED_WRONG" && + !lastTurnFeedback?.timeUp ? ( + + ) : null} + +
+ + +
+ {phase === "TURN_START" && lastPlacementCorrect !== false && ( + + )} + + {phase === "CHOICE_AFTER_CORRECT" && ( + <> + + + + )} + + + {(lastPlacementCorrect === false || phase === "PLACED_WRONG" || (lastTurnFeedback?.timeUp && lastTurnFeedback.correct === null)) && ( + + )} +
+ + )} + + {winner && showWinner && ( +
setShowWinner(false)} + > +
+
e.stopPropagation()} + > + + +
+ Congratulations! +
+
+ {winnerName ? `${winnerName} wins` : `Winner!`} +
+ +
+ + +
+
+
+ )} +
+ ); +}; diff --git a/frontend/src/components/GameSettings.tsx b/frontend/src/components/GameSettings.tsx new file mode 100644 index 0000000000..fb767e2684 --- /dev/null +++ b/frontend/src/components/GameSettings.tsx @@ -0,0 +1,91 @@ +import React from "react"; +import { Card, Button } from "../ui"; +import { useGame } from "../store/game"; + +type Props = { onClose?: () => void; onContinue?: () => void }; + +export const GameSettings: React.FC = ({ onClose, onContinue }) => { + const { + selectedCategory, + settings, + setTeamCount, + setTeamName, + setTurnSeconds, + setRevealMode, + applySettings, + } = useGame(); + + const handleContinue = () => { + applySettings(); + onContinue?.(); + }; + + return ( +
+
+
+ {settings.teamNames.length} teams • {settings.turnSeconds}s per turn +
+
+ + +
Teams
+ +
+ + +
+ +
+ {settings.teamNames.map((name, i) => ( + setTeamName(i, e.target.value)} + className="w-full rounded-md border border-border bg-card px-3 py-2" + placeholder={`Team ${i + 1} name`} + /> + ))} +
+
+ + +
Turn time
+ +
+ +
+ {onClose && ( + + )} + + +
+
+ ); +}; diff --git a/frontend/src/components/OrientationGuard.tsx b/frontend/src/components/OrientationGuard.tsx new file mode 100644 index 0000000000..267f5e3b36 --- /dev/null +++ b/frontend/src/components/OrientationGuard.tsx @@ -0,0 +1,63 @@ +import React from "react" + +type Props = { + minWidth?: number + allowDismiss?: boolean +} + +export const OrientationGuard: React.FC = ({ minWidth = 600, allowDismiss = true }) => { + const [show, setShow] = React.useState(false) + const [dismissed, setDismissed] = React.useState(false) + + React.useEffect(() => { + const mqPortrait = window.matchMedia("(orientation: portrait)") + const check = () => { + const isPortrait = mqPortrait.matches + const isNarrow = window.innerWidth < minWidth + setShow(isPortrait && isNarrow && !dismissed) + } + check() + const onResize = () => check() + mqPortrait.addEventListener?.("change", check) + window.addEventListener("resize", onResize) + return () => { + mqPortrait.removeEventListener?.("change", check) + window.removeEventListener("resize", onResize) + } + }, [minWidth, dismissed]) + + if (!show) return null + + return ( +
+
+
+
+
+

Rotate your screen

+

+See the whole timeline and stay ahead in the game – rotate your screen to landscape mode. +

+ +
+ {allowDismiss && ( + + )} + +
+
+
+ ) +} diff --git a/frontend/src/components/StartCard.tsx b/frontend/src/components/StartCard.tsx new file mode 100644 index 0000000000..2c373dcdcd --- /dev/null +++ b/frontend/src/components/StartCard.tsx @@ -0,0 +1,75 @@ +import React from "react"; +import { Card, CardHeader, CardContent } from "../ui"; +import type { GameItem } from "../types/game"; + +interface StartCardProps { + item: GameItem; + playerName?: string; + className?: string; +} + +const formatValue = (value: number, unit?: string, revealed = true) => + revealed + ? unit + ? `${value} ${unit}` + : String(value) + : unit + ? `?? ${unit}` + : "??"; + +export const StartCard: React.FC = ({ + item, + playerName, + className = "", +}) => ( + +
+
+
+
+
+
+
+
+ +
+ + Start + +
+ + +
+ {formatValue(item.value)} +
+
+ + + +
+
+ {item.name} +
+
+ {playerName} +
+
+ {playerName && ( +
+ {playerName} +
+ )} +
+ +
+
+
+ +); diff --git a/frontend/src/components/TimeLineCard.tsx b/frontend/src/components/TimeLineCard.tsx new file mode 100644 index 0000000000..9f5ea772eb --- /dev/null +++ b/frontend/src/components/TimeLineCard.tsx @@ -0,0 +1,129 @@ +import React from "react"; +import { Card, CardContent } from "../ui"; +import { cn } from "../lib/utils"; + +import type { GameItem, GameCategory } from "../types/game"; + +type CardSize = "xs" | "sm" | "md"; + +const TOKENS: Record< + CardSize, + { + wrapper: string; + value: string; + name: string; + label: string; + badge: string; + padHeader: string; + padContent: string; + vspace: string; + } +> = { + xs: { + wrapper: "w-[90px] h-[127px]", + value: "text-xl", + name: "text-sm font-semibold", + label: "text-[9px]", + badge: "w-4 h-4 text-[9px]", + padHeader: "pt-1.5 pb-0.5 px-1.5", + padContent: "px-1.5 pb-1.5", + vspace: "space-y-0.5", + }, + sm: { + wrapper: "w-[90px] h-[127px] lg:w-[164px] lg:h-[217px]", + value: "text-xl lg:text-3xl", + name: "text-sm lg:text-lg font-semibold", + label: "text-[9px] lg:text-xs", + badge: "w-4 h-4 lg:w-6 lg:h-6 text-[9px] lg:text-xs", + padHeader: "pt-1.5 pb-0.5 px-1.5 lg:pt-3 lg:pb-2 lg:px-3", + padContent: "px-1.5 pb-1.5 lg:px-3 lg:pb-3", + vspace: "space-y-0.5 lg:space-y-2", + }, + md: { + wrapper: "w-[290px] h-[387px]", + value: "text-6xl", + name: "text-6xl font-semibold", + label: "text-3xl font-medium", + badge: "w-8 h-8 text-lg", + padHeader: "pt-6 pb-4 px-6", + padContent: "px-6 pb-6", + vspace: "space-y-4", + }, +}; + +interface TimeLineCardProps { + item: GameItem; + category?: GameCategory; + isCorrect?: boolean; + isRevealed?: boolean; + className?: string; + size?: CardSize; +} + +const formatValue = (value: number, unit?: string) => { + if (!unit) return String(value); + return `${value} ${unit}`; +}; + +export const TimeLineCard: React.FC = ({ + item, + category, + isCorrect, + isRevealed, + className, + size = "sm", +}) => { + const t = TOKENS[size]; + const unit = category?.unit; + const unitVisible = category?.unitVisible ?? true; + const displayUnit = unitVisible ? unit : undefined; + + const responsiveWrapper = + size === "sm" ? "w-[90px] h-[127px] lg:w-[164px] lg:h-[217px]" : t.wrapper; + + return ( + + +
+
+ {isRevealed ? formatValue(item.value, displayUnit) : "??"} +
+ +
+ {item.name} +
+
+
+ + {isCorrect !== undefined && ( +
+ + {isCorrect ? "✓" : "✗"} + +
+ )} + +
+ ); +}; diff --git a/frontend/src/components/Timeline.tsx b/frontend/src/components/Timeline.tsx new file mode 100644 index 0000000000..1ecd768ea0 --- /dev/null +++ b/frontend/src/components/Timeline.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { useDroppable } from "@dnd-kit/core"; +import { TimeLineCard } from "./TimeLineCard"; +import type { GameItem, GameCategory } from "../types/game"; + +type Size = "xs" | "sm" | "md"; +const SIZES: Record< + Size, + { card: string; slot: string; gap: string; cardSize: Size } +> = { + xs: { + card: "w-[100px] h-[140px]", + slot: "w-1 h-[140px]", + gap: "gap-0.5", + cardSize: "xs", + }, + sm: { + card: "w-[136px] h-[180px]", + slot: "w-2 h-[180px]", + gap: "gap-1", + cardSize: "sm", + }, + md: { + card: "w-60 h-80", + slot: "w-3 h-80", + gap: "gap-1.5", + cardSize: "md" }, +}; + +type TimelineProps = { + timeline: GameItem[]; + category?: GameCategory; + showSlots?: boolean; + size?: Size; + className?: string; +}; + +const Slot: React.FC<{ id: string; className: string }> = ({ + id, + className, +}) => { + const { isOver, setNodeRef } = useDroppable({ id }); + return ( +
+ ); +}; + +export const Timeline: React.FC = ({ + timeline, + category, + showSlots = true, + size = "md", + className, +}) => { + const sz = SIZES[size]; + const slots = Array.from({ length: timeline.length + 1 }); + + return ( +
+ {slots.map((_, i) => ( + + {showSlots && } + {i < timeline.length && ( +
+ +
+ )} +
+ ))} +
+ ); +}; diff --git a/frontend/src/components/admin/CategoriesTab.tsx b/frontend/src/components/admin/CategoriesTab.tsx new file mode 100644 index 0000000000..829ae88ebc --- /dev/null +++ b/frontend/src/components/admin/CategoriesTab.tsx @@ -0,0 +1,198 @@ +import React, { useState, useMemo } from 'react'; +import { Button, Card, Input, Label } from '../../ui'; +import { Category } from '../../types/admin'; + +interface CategoriesTabProps { + categories: Category[]; + onEdit: (category: Category) => void; + onDelete: (id: string) => Promise; + onCreate: () => void; + editingCategory: Category | null; + showCreateForm: boolean; + onSave: (data: Partial) => Promise; + onUpdate: (id: string, data: Partial) => Promise; + onCancel: () => void; +} + +const CategoriesTab: React.FC = ({ + categories, + onEdit, + onDelete, + onCreate, + editingCategory, + showCreateForm, + onSave, + onUpdate, + onCancel +}) => { + const [formData, setFormData] = useState>({ + id: '', + name: '', + description: '', + question: '', + unit: '', + unitVisible: false, + sort: 'asc' + }); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + let success = false; + + if (editingCategory) { + success = await onUpdate(editingCategory.id, formData); + } else { + success = await onSave(formData); + } + + if (success) { + setFormData({ id: '', name: '', description: '', question: '', unit: '', unitVisible: false, sort: 'asc' }); + } + }; + + const handleEdit = (category: Category) => { + setFormData(category); + onEdit(category); + }; + + const handleCancel = () => { + setFormData({ id: '', name: '', description: '', question: '', unit: '', unitVisible: false, sort: 'asc' }); + onCancel(); + }; + + // Sort categories alphabetically + const sortedCategories = useMemo(() => { + return [...categories].sort((a, b) => a.name.localeCompare(b.name)); + }, [categories]); + + return ( +
+
+

Categories

+ +
+ + {/* Create/Edit Form */} + {(showCreateForm || editingCategory) && ( + +

+ {editingCategory ? 'Edit Category' : 'Create Category'} +

+
+
+
+ + setFormData({ ...formData, id: e.target.value })} + required + disabled={!!editingCategory} + /> +
+
+ + setFormData({ ...formData, name: e.target.value })} + required + /> +
+
+ + setFormData({ ...formData, unit: e.target.value })} + required + /> +
+
+ + +
+
+
+ + setFormData({ ...formData, description: e.target.value })} + /> +
+
+ + setFormData({ ...formData, question: e.target.value })} + /> +
+
+ setFormData({ ...formData, unitVisible: e.target.checked })} + className="rounded border-border" + /> + +
+
+ + +
+
+
+ )} + + {/* Categories List */} +
+ {sortedCategories.map((category) => ( + +
+
+

{category.name}

+

ID: {category.id}

+ {category.description && ( +

{category.description}

+ )} + {category.question && ( +

Q: {category.question}

+ )} +
+ Unit: {category.unit} + Sort: {category.sort} + Unit Visible: {category.unitVisible ? 'Yes' : 'No'} +
+
+
+ + +
+
+
+ ))} +
+
+ ); +}; + +export default CategoriesTab; diff --git a/frontend/src/components/admin/ItemsTab.tsx b/frontend/src/components/admin/ItemsTab.tsx new file mode 100644 index 0000000000..99dfdd9e0d --- /dev/null +++ b/frontend/src/components/admin/ItemsTab.tsx @@ -0,0 +1,239 @@ +import React, { useState, useMemo } from 'react'; +import { Button, Card, Input, Label } from '../../ui'; +import { Item, Category } from '../../types/admin'; + +interface ItemsTabProps { + items: Record; + categories: Category[]; + onEdit: (item: Item) => void; + onDelete: (id: string) => Promise; + onCreate: () => void; + editingItem: Item | null; + showCreateForm: boolean; + onSave: (data: Partial) => Promise; + onUpdate: (id: string, data: Partial) => Promise; + onCancel: () => void; + selectedCategoryFilter: string; + setSelectedCategoryFilter: (filter: string) => void; +} + +const ItemsTab: React.FC = ({ + items, + categories, + onEdit, + onDelete, + onCreate, + editingItem, + showCreateForm, + onSave, + onUpdate, + onCancel, + selectedCategoryFilter, + setSelectedCategoryFilter +}) => { + const [formData, setFormData] = useState>({ + id: '', + name: '', + value: 0, + label: '', + categoryId: '' + }); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + let success = false; + + if (editingItem) { + success = await onUpdate(editingItem.id, formData); + } else { + success = await onSave(formData); + } + + if (success) { + setFormData({ id: '', name: '', value: 0, label: '', categoryId: '' }); + } + }; + + const handleEdit = (item: Item) => { + setFormData(item); + onEdit(item); + }; + + const handleCancel = () => { + setFormData({ id: '', name: '', value: 0, label: '', categoryId: '' }); + onCancel(); + }; + + // Sort and group items by category, then alphabetically within each category + const sortedAndGroupedItems = useMemo(() => { + const filteredItems = selectedCategoryFilter === 'all' + ? Object.values(items).flat() + : items[selectedCategoryFilter] || []; + + // Group by category + const grouped = filteredItems.reduce((acc, item) => { + const categoryId = item.categoryId; + if (!acc[categoryId]) { + acc[categoryId] = []; + } + acc[categoryId].push(item); + return acc; + }, {} as Record); + + // Sort items within each category alphabetically + Object.keys(grouped).forEach(categoryId => { + grouped[categoryId].sort((a, b) => a.name.localeCompare(b.name)); + }); + + return grouped; + }, [items, selectedCategoryFilter]); + + return ( +
+
+

Items

+ +
+ + {/* Create/Edit Form */} + {(showCreateForm || editingItem) && ( + +

+ {editingItem ? 'Edit Item' : 'Create Item'} +

+
+
+
+ + setFormData({ ...formData, id: e.target.value })} + required + disabled={!!editingItem} + /> +
+
+ + setFormData({ ...formData, name: e.target.value })} + required + /> +
+
+ + setFormData({ ...formData, value: Number(e.target.value) })} + required + /> +
+
+ + setFormData({ ...formData, label: e.target.value })} + required + /> +
+
+
+ + +
+
+ + +
+
+
+ )} + + {/* Items List */} +
+ {/* Category Filter */} +
+ + {Object.keys(items).map((categoryId) => { + const category = categories.find(c => c.id === categoryId); + return ( + + ); + })} +
+ + {Object.entries(sortedAndGroupedItems).map(([categoryId, categoryItems]) => ( +
+

+ {categories.find(c => c.id === categoryId)?.name || 'Unknown Category'} +

+
+ {categoryItems.map((item) => ( + +
+
+

{item.name}

+

ID: {item.id}

+
+ Value: {item.value} + Label: {item.label} + + Category: {categories.find(c => c.id === categoryId)?.name || 'Unknown'} + +
+
+
+ + +
+
+
+ ))} +
+
+ ))} +
+
+ ); +}; + +export default ItemsTab; diff --git a/frontend/src/components/admin/LoginForm.tsx b/frontend/src/components/admin/LoginForm.tsx new file mode 100644 index 0000000000..ffba2bc44f --- /dev/null +++ b/frontend/src/components/admin/LoginForm.tsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import { Heading, Button, Card, Input, Label, ErrorMessage } from '../../ui'; + +interface LoginFormProps { + onLogin: (username: string, password: string) => Promise<{ success: boolean; error?: string }>; + loading: boolean; + error: string; +} + +const LoginForm: React.FC = ({ onLogin, loading, error }) => { + const [formData, setFormData] = useState({ username: '', password: '' }); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + const result = await onLogin(formData.username, formData.password); + if (result.success) { + setFormData({ username: '', password: '' }); + } + }; + + return ( +
+
+
+
+
+ Admin Access +
+ + Admin Login + +

+ Enter your credentials to access the admin panel. +

+
+ +
+ +
+ {error && } + +
+ + setFormData({ ...formData, username: e.target.value })} + required + disabled={loading} + /> +
+ +
+ + setFormData({ ...formData, password: e.target.value })} + required + disabled={loading} + /> +
+ + + +
+
+
+
+
+ ); +}; + +export default LoginForm; diff --git a/frontend/src/config/environment.ts b/frontend/src/config/environment.ts new file mode 100644 index 0000000000..dc755bf2a6 --- /dev/null +++ b/frontend/src/config/environment.ts @@ -0,0 +1,8 @@ +export const config = { + backendUrl: import.meta.env.VITE_BACKEND_URL || "https://project-final-pfy9.onrender.com", + + frontendUrl: import.meta.env.VITE_FRONTEND_URL || "http://127.0.0.1:5173", + + appName: "Banganza", + +}; diff --git a/frontend/src/hooks/useApi.ts b/frontend/src/hooks/useApi.ts new file mode 100644 index 0000000000..87961b0e48 --- /dev/null +++ b/frontend/src/hooks/useApi.ts @@ -0,0 +1,166 @@ +import { useState, useEffect } from 'react'; +import { config } from '../config/environment'; + +interface ApiState { + data: T[]; + loading: boolean; + error: string; +} + +interface ApiActions { + fetch: () => Promise; + create: (item: Partial) => Promise; + update: (id: string, item: Partial) => Promise; + delete: (id: string) => Promise; + clearError: () => void; +} + +export function useApi( + endpoint: string, + token: string | null, + confirmMessage?: string +): ApiState & ApiActions { + const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + + const fetchData = async () => { + if (!token) return; + + try { + setLoading(true); + const response = await fetch(`${config.backendUrl}/api/admin/${endpoint}`, { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }); + + if (response.ok) { + const result = await response.json(); + if (result.success && result.data) { + setData(result.data[endpoint] || result.data); + } else { + setError(result.error?.message || `Failed to fetch ${endpoint}`); + } + } else { + const result = await response.json(); + setError(result.error?.message || result.message || `Failed to fetch ${endpoint}`); + } + } catch (error) { + setError('Network error occurred'); + } finally { + setLoading(false); + } + }; + + const create = async (itemData: Partial) => { + if (!token) return false; + + try { + setLoading(true); + const response = await fetch(`${config.backendUrl}/api/admin/${endpoint}`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(itemData) + }); + + if (response.ok) { + await fetchData(); + return true; + } else { + const result = await response.json(); + setError(result.error?.message || result.message || `Failed to create ${endpoint.slice(0, -1)}`); + return false; + } + } catch (error) { + setError('Network error occurred'); + return false; + } finally { + setLoading(false); + } + }; + + const update = async (id: string, itemData: Partial) => { + if (!token) return false; + + try { + setLoading(true); + const response = await fetch(`${config.backendUrl}/api/admin/${endpoint}/${id}`, { + method: 'PUT', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify(itemData) + }); + + if (response.ok) { + await fetchData(); + return true; + } else { + const result = await response.json(); + setError(result.error?.message || result.message || `Failed to update ${endpoint.slice(0, -1)}`); + return false; + } + } catch (error) { + setError('Network error occurred'); + return false; + } finally { + setLoading(false); + } + }; + + const deleteItem = async (id: string) => { + if (!token) return false; + + if (confirmMessage && !confirm(confirmMessage)) return false; + + try { + setLoading(true); + const response = await fetch(`${config.backendUrl}/api/admin/${endpoint}/${id}`, { + method: 'DELETE', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }); + + if (response.ok) { + await fetchData(); + return true; + } else { + const result = await response.json(); + setError(result.error?.message || result.message || `Failed to delete ${endpoint.slice(0, -1)}`); + return false; + } + } catch (error) { + setError('Network error occurred'); + return false; + } finally { + setLoading(false); + } + }; + + const clearError = () => setError(''); + + useEffect(() => { + if (token) { + fetchData(); + } + }, [token]); + + return { + data, + loading, + error, + fetch: fetchData, + create, + update, + delete: deleteItem, + clearError + }; +} diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts new file mode 100644 index 0000000000..bb21f65bf2 --- /dev/null +++ b/frontend/src/hooks/useAuth.ts @@ -0,0 +1,111 @@ +import { useState, useEffect } from 'react'; +import { config } from '../config/environment'; +import { Admin } from '../types/admin'; + +export const useAuth = () => { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [admin, setAdmin] = useState(null); + const [token, setToken] = useState(localStorage.getItem('adminToken')); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); + + useEffect(() => { + if (token) { + checkAuth(); + } + }, [token]); + + const checkAuth = async () => { + try { + const response = await fetch(`${config.backendUrl}/api/admin/profile`, { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }); + + if (response.ok) { + const data = await response.json(); + if (data.success && data.data) { + setAdmin(data.data.admin); + setIsAuthenticated(true); + } else { + logout(); + } + } else { + logout(); + } + } catch (error) { + console.error('Auth check failed:', error); + logout(); + } + }; + + const login = async (username: string, password: string) => { + setError(''); + setLoading(true); + + try { + const response = await fetch(`${config.backendUrl}/api/admin/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ username, password }) + }); + + const data = await response.json(); + + if (response.ok && data.success && data.data) { + localStorage.setItem('adminToken', data.data.token); + setToken(data.data.token); + setAdmin(data.data.admin); + setIsAuthenticated(true); + return { success: true }; + } else { + const errorMessage = data.error?.message || data.message || 'Login failed'; + setError(errorMessage); + return { success: false, error: errorMessage }; + } + } catch (error) { + setError('Network error occurred'); + return { success: false, error: 'Network error occurred' }; + } finally { + setLoading(false); + } + }; + + const logout = async () => { + try { + if (token) { + await fetch(`${config.backendUrl}/api/admin/logout`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }); + } + } catch (error) { + console.error('Logout error:', error); + } finally { + localStorage.removeItem('adminToken'); + setToken(null); + setAdmin(null); + setIsAuthenticated(false); + } + }; + + const clearError = () => setError(''); + + return { + isAuthenticated, + admin, + token, + loading, + error, + login, + logout, + clearError + }; +}; diff --git a/frontend/src/hooks/useCategories.ts b/frontend/src/hooks/useCategories.ts new file mode 100644 index 0000000000..e8c7d85a46 --- /dev/null +++ b/frontend/src/hooks/useCategories.ts @@ -0,0 +1,16 @@ +import { useApi } from './useApi'; +import { Category } from '../types/admin'; + +export const useCategories = (token: string | null) => { + const api = useApi('categories', token, 'Are you sure you want to delete this category?'); + + return { + categories: api.data, + loading: api.loading, + error: api.error, + createCategory: api.create, + updateCategory: api.update, + deleteCategory: api.delete, + clearError: api.clearError + }; +}; diff --git a/frontend/src/hooks/useItems.ts b/frontend/src/hooks/useItems.ts new file mode 100644 index 0000000000..3043f6a2e9 --- /dev/null +++ b/frontend/src/hooks/useItems.ts @@ -0,0 +1,16 @@ +import { useApi } from './useApi'; +import { Item } from '../types/admin'; + +export const useItems = (token: string | null) => { + const api = useApi('items', token, 'Are you sure you want to delete this item?'); + + return { + items: api.data, + loading: api.loading, + error: api.error, + createItem: api.create, + updateItem: api.update, + deleteItem: api.delete, + clearError: api.clearError + }; +}; diff --git a/frontend/src/index.css b/frontend/src/index.css index e69de29bb2..6955000bbb 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -0,0 +1,366 @@ +@import "tailwindcss"; +@import url("https://fonts.googleapis.com/css2?family=Zen+Kaku+Gothic+Antique:wght@400;500;700&display=swap"); + +@font-face { + font-family: "Cygnito Mono"; + src: url("/src/assets/cygnito-mono-regular.otf") format("opentype"); + font-weight: 400; + font-style: normal; +} + +@theme { + --font-family-sans: "Zen Kaku Gothic Antique", system-ui, sans-serif; + --font-family-mono: "Cygnito Mono", ui-monospace, SFMono-Regular, Menlo, + Monaco, Consolas, monospace; + + --color-base-100: #fefcfa; + --color-base-200: #fdf8f3; + --color-base-300: #fbf4ec; + --color-base-400: #f9ecdf; + --color-base-500: #f5e4d2; + --color-base-600: #f0dbc5; + --color-base-700: #ebd2b8; + --color-base-800: #e6c9ab; + --color-base-900: #e1c09e; + + --color-accent-100: #934d56; + --color-accent-200: #86464e; + --color-accent-300: #783f46; + --color-accent-400: #6b383e; + --color-accent-500: #5d3136; + --color-accent-600: #502a2f; + --color-accent-700: #432327; + --color-accent-800: #351c1f; + --color-accent-900: #281517; + --color-accent-950: #1b0e0f; + + --color-primary: #5d3136; + --color-primary-hover: #4a272b; + --color-primary-focus: #6b3a40; + --color-background: #f9ecdf; + --color-surface: #fefcfa; + --color-card: #fdf8f3; + --color-muted: #f0dbc5; + --color-muted-foreground: #946971; + --color-foreground: #5d3136; + --color-border: #ebd2b8; + --color-border-muted: #f5e4d2; + + --shadow-soft: 0 2px 8px 0 rgba(93, 49, 54, 0.08); + --shadow-medium: 0 4px 16px 0 rgba(93, 49, 54, 0.12); + --shadow-strong: 0 8px 32px 0 rgba(93, 49, 54, 0.16); + + --radius-sm: 0.25rem; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --radius-2xl: 1rem; + --radius-3xl: 1.5rem; + + --spacing-18: 4.5rem; + --spacing-22: 5.5rem; + --spacing-26: 6.5rem; + --spacing-30: 7.5rem; + + --font-size-xs: 0.75rem; + --leading-xs: 1rem; + --font-size-sm: 0.875rem; + --leading-sm: 1.25rem; + --font-size-base: 1rem; + --leading-base: 1.5rem; + --font-size-lg: 1.125rem; + --leading-lg: 1.75rem; + --font-size-xl: 1.25rem; + --leading-xl: 1.75rem; + --font-size-2xl: 1.5rem; + --leading-2xl: 2rem; + --font-size-3xl: 1.875rem; + --leading-3xl: 2.25rem; + --font-size-4xl: 2.25rem; + --leading-4xl: 2.5rem; + --font-size-5xl: 3rem; + --leading-5xl: 1; + --font-size-6xl: 3.75rem; + --leading-6xl: 1; + --font-size-7xl: 4.5rem; + --leading-7xl: 1; + --font-size-8xl: 6rem; + --leading-8xl: 1; + --font-size-9xl: 8rem; + --leading-9xl: 1; +} + +html { + scroll-behavior: smooth; +} + +.mono-spinner { + position: relative; + width: 3.25rem; + height: 3.25rem; + filter: contrast(110%) saturate(80%); +} + +.mono-spinner::before { + content: ""; + position: absolute; + inset: 0; + border: 1px solid var(--color-border); + border-radius: 0.5rem; + box-shadow: 0 0 0 1px var(--color-border-muted) inset, var(--shadow-soft); +} + +.mono-spinner .disc { + position: absolute; + inset: 6px; + border-radius: 9999px; + background: radial-gradient( + circle at center, + var(--color-surface) 60%, + transparent 61% + ), + conic-gradient( + from 0deg, + var(--color-foreground) 0 120deg, + transparent 120deg 360deg + ); + animation: spin 1.1s linear infinite; +} + +.mono-spinner .scan { + content: ""; + position: absolute; + inset: 0; + border-radius: 0.5rem; + background: repeating-linear-gradient( + 0deg, + rgba(40, 21, 23, 0.08), + rgba(40, 21, 23, 0.08) 2px, + transparent 2px, + transparent 4px + ); + mix-blend-mode: multiply; + pointer-events: none; + animation: crt-flicker 1.8s ease-in-out infinite; +} + +.border-\[\#f9ecdf\] { + border-color: #e1c09e; +} + + +.report-card { + position: relative; + display: flex; + aspect-ratio: 16 / 7; + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: 1rem; + box-shadow: var(--shadow-soft); + transition: transform 200ms ease, box-shadow 200ms ease, + border-color 200ms ease, background-color 200ms ease; + overflow: hidden; +} + +.report-card::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + box-shadow: 0 0 0 1px var(--color-border-muted) inset; + pointer-events: none; +} + +.report-card::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + background-image: radial-gradient( + rgba(40, 21, 23, 0.05) 1px, + transparent 1.2px + ); + background-size: 3px 3px; + opacity: 0.6; + mix-blend-mode: multiply; + pointer-events: none; + transition: opacity 200ms ease; +} + +.report-card:hover, +.report-card:focus-visible { + transform: translateY(-2px); + box-shadow: var(--shadow-medium); + border-color: var(--color-foreground); + background-color: color-mix( + in srgb, + var(--color-accent-100) 10%, + var(--color-surface) + ); +} + +.report-card--active { + border-color: var(--color-primary); + background-color: color-mix( + in srgb, + var(--color-primary) 12%, + var(--color-surface) + ); + box-shadow: var(--shadow-medium); +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@media (max-width: 640px) { + html { + font-size: 14px; + } +} + +@keyframes logo-in { + 0% { + opacity: 0; + transform: scale(0.96); + filter: blur(3px); + } + 60% { + opacity: 1; + transform: scale(1.01); + filter: blur(0); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + +@keyframes seed-sweep { + 0% { + transform: translateX(-20vw) rotate(-10deg) scale(0.9); + } + 50% { + transform: translateX(15vw) rotate(6deg) scale(1.08); + } + 100% { + transform: translateX(50vw) rotate(0deg) scale(1); + } +} + +@keyframes tagline-in { + 0% { + opacity: 0; + transform: translateY(0.75rem); + letter-spacing: 0.12em; + } + 100% { + opacity: 1; + transform: translateY(0); + letter-spacing: 0; + } +} + +@keyframes particle-float { + 0% { + transform: translateX(0) translateY(0) rotate(0deg); + opacity: 0.65; + } + 70% { + opacity: 0.9; + } + 100% { + transform: translateX(-120vw) translateY(-10vh) rotate(14deg); + opacity: 0; + } +} + +@keyframes letter-in { + 0% { + opacity: 0; + transform: translateY(1.6rem) scale(0.98); + filter: blur(2px); + } + 55% { + opacity: 1; + transform: translateY(0) scale(1.02); + filter: blur(0); + } + 100% { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +@keyframes tagline-in { + 0% { + opacity: 0; + transform: translateY(0.8rem); + letter-spacing: 0.14em; + } + 100% { + opacity: 1; + transform: translateY(0); + letter-spacing: 0; + } +} + +@keyframes crt-flicker { + 0% { + opacity: 1; + } + 50% { + opacity: 0.92; + } + 100% { + opacity: 1; + } +} + +@keyframes typewriter { + 0% { + width: 0; + overflow: hidden; + white-space: nowrap; + } + 100% { + width: 100%; + overflow: visible; + white-space: normal; + } +} + +@keyframes typewriter-smooth { + 0% { + clip-path: inset(0 100% 0 0); + } + 100% { + clip-path: inset(0 0% 0 0); + } +} + +@keyframes pulsate { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } + 100% { + transform: scale(1); + } +} + +.animate-pulsate { + animation: pulsate 2s ease-in-out infinite; +} + +@media (prefers-reduced-motion: reduce) { + * { + animation: none !important; + transition: none !important; + } +} + diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts new file mode 100644 index 0000000000..72508922d0 --- /dev/null +++ b/frontend/src/lib/utils.ts @@ -0,0 +1,15 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} + +export const shuffle = (arr: T[]): T[] => { + const shuffled = [...arr]; + for (let i = shuffled.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; + } + return shuffled; +}; diff --git a/frontend/src/main.jsx b/frontend/src/main.tsx similarity index 61% rename from frontend/src/main.jsx rename to frontend/src/main.tsx index 51294f3998..fd7970f796 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.tsx @@ -1,9 +1,9 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import { App } from "./App.jsx"; +import { App } from "./App"; import "./index.css"; -ReactDOM.createRoot(document.getElementById("root")).render( +ReactDOM.createRoot(document.getElementById("root")!).render( diff --git a/frontend/src/pages/AdminPage.tsx b/frontend/src/pages/AdminPage.tsx new file mode 100644 index 0000000000..c39542df74 --- /dev/null +++ b/frontend/src/pages/AdminPage.tsx @@ -0,0 +1,163 @@ +import React, { useState, useMemo } from 'react'; +import { Heading, Button, ErrorMessage } from '../ui'; +import { useAuth } from '../hooks/useAuth'; +import { useCategories } from '../hooks/useCategories'; +import { useItems } from '../hooks/useItems'; +import LoginForm from '../components/admin/LoginForm'; +import CategoriesTab from '../components/admin/CategoriesTab'; +import ItemsTab from '../components/admin/ItemsTab'; + +const AdminPage: React.FC = () => { + const { isAuthenticated, admin, token, login, logout, error: authError, loading: authLoading } = useAuth(); + const { + categories, + createCategory, + updateCategory, + deleteCategory, + error: categoriesError + } = useCategories(token); + const { + items, + createItem, + updateItem, + deleteItem, + error: itemsError + } = useItems(token); + + const [activeTab, setActiveTab] = useState<'categories' | 'items'>('categories'); + const [editingCategory, setEditingCategory] = useState(null); + const [editingItem, setEditingItem] = useState(null); + const [showCreateForm, setShowCreateForm] = useState(false); + const [selectedCategoryFilter, setSelectedCategoryFilter] = useState('all'); + + const sortedAndGroupedItems = useMemo(() => { + const filteredItems = selectedCategoryFilter === 'all' + ? items + : items.filter(item => item.categoryId === selectedCategoryFilter); + + const grouped = filteredItems.reduce((acc, item) => { + const categoryId = item.categoryId; + if (!acc[categoryId]) { + acc[categoryId] = []; + } + acc[categoryId].push(item); + return acc; + }, {} as Record); + + Object.keys(grouped).forEach(categoryId => { + grouped[categoryId].sort((a, b) => a.name.localeCompare(b.name)); + }); + + return grouped; + }, [items, selectedCategoryFilter]); + + const handleLogin = async (username: string, password: string) => { + return await login(username, password); + }; + + const handleLogout = () => { + logout(); + }; + + if (!isAuthenticated) { + return ( + + ); + } + + return ( +
+
+ +
+ +
+
+
+
+
+ Admin Panel +
+ + Quiz Management + +

+ Welcome back, {admin?.username} +

+
+
+ + {(authError || categoriesError || itemsError) && ( +
+ +
+ )} + +
+ + +
+ + {activeTab === 'categories' ? ( + setShowCreateForm(true)} + editingCategory={editingCategory} + showCreateForm={showCreateForm} + onSave={createCategory} + onUpdate={updateCategory} + onCancel={() => { + setEditingCategory(null); + setShowCreateForm(false); + }} + /> + ) : ( + setShowCreateForm(true)} + editingItem={editingItem} + showCreateForm={showCreateForm} + onSave={createItem} + onUpdate={updateItem} + onCancel={() => { + setEditingItem(null); + setShowCreateForm(false); + }} + selectedCategoryFilter={selectedCategoryFilter} + setSelectedCategoryFilter={setSelectedCategoryFilter} + /> + )} +
+
+
+ ); +}; + +export default AdminPage; diff --git a/frontend/src/pages/GameMode.tsx b/frontend/src/pages/GameMode.tsx new file mode 100644 index 0000000000..eb8ec2e871 --- /dev/null +++ b/frontend/src/pages/GameMode.tsx @@ -0,0 +1,423 @@ +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { OrientationGuard } from "../components/OrientationGuard"; +import { GameBoard } from "../components/GameBoard"; +import { CategorySelector } from "../components/CategorySelector"; +import { Heading } from "../ui"; +import { ConfirmModal } from "../components/ConfirmModal"; +import { useGame } from "../store/game"; +import { GameSettings } from "../components/GameSettings"; + +export default function GameMode() { + const navigate = useNavigate(); + const { + teams, + currentTeamIndex, + selectedCategory, + phase, + startGame, + resetGame, + } = useGame(); + const [showConfirmModal, setShowConfirmModal] = React.useState(false); + const [showInfo, setShowInfo] = React.useState(false); + const infoTitleId = React.useId(); + const infoDescriptionId = `${infoTitleId}-desc`; + + const categoryLabel = "Category"; + const categoryValue = selectedCategory?.name || "Select Category"; + + const scoreA = teams[0]?.timeline.length ?? 0; + const scoreB = teams[1]?.timeline.length ?? 0; + + + + const chip = + "px-2 py-1 rounded-full bg-primary/10 border border-[#f9ecdf] text-xs tracking-wider uppercase text-[#f9ecdf]"; + + const handleHomeClick = (e: React.MouseEvent) => { + e.preventDefault(); + setShowConfirmModal(true); + }; + + const handleConfirmHome = () => { + resetGame(); + navigate("/"); + }; + + React.useEffect(() => { + if (!showInfo) return; + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") setShowInfo(false); + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [showInfo]); + + +if (!selectedCategory) { + return ( +
+ + +
+ + +
+ + + +
+
+
+ +
+
+
+ + {showInfo && ( +
+
setShowInfo(false)} + aria-hidden="true" + /> +
+
+
+

+ Game info +

+

+ The goal of the game is to place 10 cards correctly according + to the rule for the chosen category. +

+
+ +
+ +
+
+

+ Setup +

+
    +
  • + Choose a category.{" "} + The category decides what you are comparing, for example earlier vs later in time, lighter vs heavier, + shorter vs longer, or smaller vs larger values. +
  • +
  • + Form your teams.{" "} + 2–4 teams, any number of players. Each team gets one starting card that begins their line. +
  • +
  • + Pick turn time.{" "} + Decide whether each turn should be 30, 60, or 90 seconds. +
  • +
+
+ +
+

+ Your turn +

+
    +
  1. Draw the next card.
  2. +
  3. Decide where it belongs on your team’s line based on the category rule.
  4. +
  5. Place the card and confirm your choice.
  6. +
+

+ Correct: The card stays on the line.{" "} + Incorrect: The card is discarded. +

+
+ +
+

+ End of round +

+

+ The first team with 10 correct cards on their line + wins the round. +

+
+
+
+
+ )} + + setShowConfirmModal(false)} + onConfirm={handleConfirmHome} + title="Back to Home?" + message="Are you sure you want to return to the home page?" + confirmText="Yes, go Home" + cancelText="Stay here" + /> +
+ ); +} + + + + return ( +
+ + + {phase !== "SETUP" && ( +
+ + +
+ )} + + {phase !== "SETUP" && ( + + )} + + {phase !== "SETUP" && ( +
+
+ {teams[currentTeamIndex]?.name} is playing +
+
+ {teams.map((t, i) => { + const active = currentTeamIndex === i; + return ( +
+ {t.name}{" "} + + {t.timeline?.length ?? 0} + +
+ ); + })} +
+ +
+ )} + + {phase !== "SETUP" && ( +
+
+ {categoryLabel}:{" "} + {categoryValue} +
+ +
+ )} + +
+
+ {phase === "SETUP" ? ( + <> +
+
+

+ GAME SETTINGS +

+

+ Configure your match +

+
+
+ +
+ + navigate("/", { state: { scrollTo: "categories" } }) + } + onContinue={() => startGame()} + /> +
+ + ) : ( + <> + +
+
+ Game Question +
+ + {selectedCategory.question} + +
+ +
+ +
+ + )} +
+
+ + setShowConfirmModal(false)} + onConfirm={handleConfirmHome} + title="End Game?" + message="Are you sure you want to end the current game and return to the home page? All progress will be lost." + confirmText="Yes, End Game" + cancelText="Continue Playing" + /> + + {showInfo && ( +
+
setShowInfo(false)} + aria-hidden="true" + /> +
+
+
+

+ Game info +

+

+The goal of the game is to be the first team to place 10 cards in the correct order on your line, based on the rule for the chosen category. + +

+
+ +
+ +
+ +
+

+ Your turn +

+
    +
  1. Draw the next card.
  2. +
  3. Decide where it belongs on your team’s line based on the category rule.
  4. +
  5. On the line, the lowest value goes on the left and the highest on the right.
  6. +
  7. Place the card and confirm your choice.
  8. +
+

+ Correct: The card stays on the line.{" "} + Incorrect: The card is discarded. +

+
+ +
+

+ End of round +

+

+ The first team with 10 correct cards on their line wins + the round. +

+
+
+
+
+ )} +
+ ); +} diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx new file mode 100644 index 0000000000..17cce8e9e9 --- /dev/null +++ b/frontend/src/pages/Home.tsx @@ -0,0 +1,262 @@ +import { useEffect, useState, useRef, useId } from "react"; +import { useLocation } from "react-router-dom"; +import BanganzaIntro from "../components/BanganzaIntro"; +import { CategorySelector } from "../components/CategorySelector"; + +export const Home = () => { + const [introDone, setIntroDone] = useState( + () => sessionStorage.getItem("introDone") === "1" + ); + const [showIntro, setShowIntro] = useState( + () => sessionStorage.getItem("introDone") !== "1" + ); + const FADE_MS = 100; + const [ready, setReady] = useState(false); + const catsRef = useRef(null); + const location = useLocation(); + const [showInfo, setShowInfo] = useState(false); + const infoTitleId = useId(); + const infoDescriptionId = `${infoTitleId}-desc`; + + useEffect(() => { + const t = setTimeout(() => setReady(true), 250); + return () => clearTimeout(t); + }, []); + + useEffect(() => { + const s = (location.state as any) || {}; + if (s.scrollTo === "categories") { + if (!introDone) { + setIntroDone(true); + sessionStorage.setItem("introDone", "1"); + } + catsRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); + window.history.replaceState({}, ""); + } + }, [location.state, introDone]); + + useEffect(() => { + if (!showInfo) return; + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") setShowInfo(false); + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [showInfo]); + +const InfoIcon = () => ( + +); + + + return ( +
+ {showIntro && ( + { + setIntroDone(true); + sessionStorage.setItem("introDone", "1"); + setTimeout(() => setShowIntro(false), FADE_MS); + }} + /> + )} + +{!showIntro && ( + +)} + +
+
+
+
+
+
+ +
+
+

+ BEYOND THE ANSWERS… THERE IS +

+ +

Banganza

+ + +
+
+
+ +
+
+ +
+
+
+ + {showInfo && ( +
+
setShowInfo(false)} + aria-hidden="true" + /> +
+
+
+

+ Game info +

+

+ The goal of the game is to place 10 cards correctly according + to the rule for the chosen category. +

+
+ +
+ +
+
+

+ Setup +

+
    +
  • + + Choose a category. + {" "} + The category decides what you are comparing, for example + earlier vs later in time, lighter vs heavier, shorter vs + longer, or smaller vs larger values. +
  • +
  • + + Form your teams. + {" "} + 2–4 teams, any number of players. Each team gets one + starting card that begins their line. +
  • +
  • + + Pick turn time. + {" "} + Decide whether each turn should be 30, 60, or 90 seconds. +
  • +
+
+ +
+

+ Your turn +

+
    +
  1. Draw the next card.
  2. +
  3. + Decide where it belongs on your team’s line based on the + category rule. +
  4. +
  5. Place the card and confirm your choice.
  6. +
+

+ Correct:{" "} + The card stays on the line.{" "} + + Incorrect: + {" "} + The card is discarded. +

+
+ +
+

+ End of round +

+

+ The first team with{" "} + + 10 correct cards + {" "} + on their line wins the round. +

+
+ +
+
+
+ )} +
+ ); +}; diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts new file mode 100644 index 0000000000..40f7a3d4ed --- /dev/null +++ b/frontend/src/services/api.ts @@ -0,0 +1,73 @@ +import { config } from '../config/environment'; +import type { GameItem, GameCategory } from '../types/game'; + +class ApiService { + private baseUrl: string; + + constructor() { + this.baseUrl = config.backendUrl; + } + + private async request(endpoint: string, options?: RequestInit): Promise { + const url = `${this.baseUrl}/api/quiz${endpoint}`; + + try { + const response = await fetch(url, { + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + ...options, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + if (!data.success) { + throw new Error(data.error?.message || 'API request failed'); + } + + return data.data; + } catch (error) { + console.error('API request failed:', error); + throw error; + } + } + + async getCategories(): Promise { + const categories = await this.request('/categories'); + return categories.map(cat => ({ + _id: cat._id, + id: cat.id, + name: cat.name, + description: cat.description, + question: cat.question || cat.description || `Which ${cat.name} is the most?`, + unit: cat.unit, + unitVisible: cat.unitVisible ?? true, + sort: cat.sort, + source: cat.source, + version: cat.version, + })); + } + + async getItems(categoryId: string, withValues = false): Promise { + const endpoint = withValues ? `/category/${categoryId}/items` : `/items/${categoryId}`; + const response = await this.request(endpoint); + const items = response.items || response; + + return items.map((item: any) => ({ + _id: item._id, + id: item.id, + name: item.name, + label: item.label, + value: withValues ? item.value : 0, + categoryId: categoryId, + source: response.source || item.source, + })); + } +} + +export const apiService = new ApiService(); diff --git a/frontend/src/store/game.ts b/frontend/src/store/game.ts new file mode 100644 index 0000000000..03f98d7df4 --- /dev/null +++ b/frontend/src/store/game.ts @@ -0,0 +1,512 @@ +import { create } from "zustand"; +import type { + GameItem, + GameState, + GameCategory, + GameSettings, + RevealMode, +} from "../types/game"; +import { apiService } from "../services/api"; +import { shuffle } from "../lib/utils"; + +const WIN_TARGET = 10; + +const insertAt = (arr: GameItem[], item: GameItem, idx: number) => { + const copy = arr.slice(); + copy.splice(idx, 0, item); + return copy; +}; +const Y = (c: GameItem | undefined) => c?.value; +const isPlacementCorrect = ( + timeline: GameItem[], + card: GameItem, + i: number +) => { + const y = Y(card); + if (y === undefined) return false; + + const left = i - 1 >= 0 ? Y(timeline[i - 1]) : undefined; + const right = i < timeline.length ? Y(timeline[i]) : undefined; + return ( + (left === undefined || y >= left) && (right === undefined || y <= right) + ); +}; +const drawOne = (pool: GameItem[]) => { + const i = Math.floor(Math.random() * pool.length); + return pool.splice(i, 1)[0]; +}; + +type TimerState = { + turnDeadline: number | null; + secondsLeft: number; + timerId: number | null; +}; + +type UIState = { + loading: boolean; + error: string | null; + lastPlacementCorrect: boolean | null; + pendingIndex: number | null; + roundBaselineTimeline: GameItem[]; + turnTimeline: GameItem[]; + categories: GameCategory[]; + selectedCategory: GameCategory | null; + settings: GameSettings; + timer: TimerState; + lastTurnFeedback: { timeUp?: boolean; correct?: boolean | null } | null; + winner: { teamIndex: number; teamName: string } | null; + wrongAnswerCard: GameItem | null; +}; + +type Actions = { + clearError: () => void; + loadCategories: () => Promise; + selectCategory: (category: GameCategory) => void; + startGame: () => Promise; + startTurn: () => Promise; + placeAt: (slotIndex: number) => void; + confirmPlacement: () => void; + drawAnother: () => Promise; + lockIn: () => void; + nextTeam: () => void; + setTeamCount: (count: number) => void; + setTeamName: (index: number, name: string) => void; + setTurnSeconds: (sec: 30 | 60 | 90) => void; + setRevealMode: (mode: RevealMode) => void; + applySettings: () => void; + startTimer: () => void; + stopTimer: () => void; + timeUp: () => void; + resetGame: () => void; + resetGameAndCategory: () => void; +}; + +const initialSettings: GameSettings = { + teamNames: ["Team Bang", "Team Ganza", "Team Anga", "Team Zaba"], + turnSeconds: 60, + revealMode: "hidden", +}; + +const initialTimer: TimerState = { + turnDeadline: null, + secondsLeft: initialSettings.turnSeconds, + timerId: null, +}; + +export const useGame = create()((set, get) => { + const declareWinner = (staged: GameItem[]) => { + const s = get(); + const tIdx = s.currentTeamIndex; + + get().stopTimer(); + + set({ + teams: s.teams.map((t, i) => + i === tIdx ? { ...t, timeline: staged } : t + ) as GameState["teams"], + currentCard: undefined, + pendingIndex: null, + lastPlacementCorrect: true, + phase: "TURN_START", + winner: { teamIndex: tIdx, teamName: s.teams[tIdx].name }, + }); + }; + + return { + deck: [], + discard: [], + teams: [ + { id: "A", name: "Team Bang", timeline: [], score: 0 }, + { id: "B", name: "Team Ganza", timeline: [], score: 0 }, + ], + currentTeamIndex: 0, + currentCard: undefined, + phase: "SETUP", + + loading: false, + error: null, + lastPlacementCorrect: null, + pendingIndex: null, + roundBaselineTimeline: [], + turnTimeline: [], + categories: [], + selectedCategory: null, + settings: initialSettings, + timer: initialTimer, + winner: null, + + lastTurnFeedback: null, + wrongAnswerCard: null, + + clearError: () => set({ error: null }), + + loadCategories: async () => { + set({ loading: true, error: null }); + try { + const categories = await apiService.getCategories(); + set({ categories, loading: false }); + } catch (error: any) { + set({ + error: error?.message ?? "Failed to load categories", + loading: false, + }); + } + }, + + selectCategory: (category: GameCategory) => { + set({ selectedCategory: category }); + }, + + startGame: async () => { + const state = get(); + if (!state.selectedCategory) { + set({ error: "Please select a category first" }); + return; + } + + set({ loading: true, error: null }); + try { + const deck = await apiService.getItems( + state.selectedCategory.id, + true + ); + if (!deck || deck.length < 2) throw new Error("Not enough items"); + + const shuffledDeck = shuffle(deck); + const pool = shuffledDeck.slice(); + + const names = get().settings.teamNames; + const teams = names.map((name, i) => { + const start = drawOne(pool); + return { id: String(i), name, timeline: [start], score: 0 }; + }); + + set({ + deck: pool, + discard: [], + teams, + currentTeamIndex: 0, + currentCard: undefined, + roundBaselineTimeline: [], + turnTimeline: [], + pendingIndex: null, + lastPlacementCorrect: null, + phase: "TURN_START", + winner: null, + }); + } catch (e: any) { + set({ error: e?.message ?? "Failed to load items" }); + } finally { + set({ loading: false }); + } + }, + + startTurn: async () => { + const s = get(); + if (s.winner) return; + if (!s.deck.length) { + await get().startGame(); + } + const s2 = get(); + if (!s2.deck.length) return; + + const [card, ...rest] = s2.deck; + const startingNewRound = s2.phase === "TURN_START"; + + set({ + deck: rest, + currentCard: card, + roundBaselineTimeline: startingNewRound + ? s2.teams[s2.currentTeamIndex].timeline.slice() + : s2.roundBaselineTimeline, + turnTimeline: startingNewRound + ? s2.teams[s2.currentTeamIndex].timeline.slice() + : s2.turnTimeline, + pendingIndex: null, + lastPlacementCorrect: null, + lastTurnFeedback: null, + wrongAnswerCard: null, + phase: "DRAWN", + }); + get().startTimer(); + }, + + placeAt: (slotIndex: number) => { + const s = get(); + if (!s.currentCard) return; + set({ + pendingIndex: slotIndex, + phase: "PLACED_PENDING", + }); + }, + + confirmPlacement: () => { + const s = get(); + const card = s.currentCard; + const i = s.pendingIndex; + if (!card || i == null) return; + + const base = s.turnTimeline; + const correct = isPlacementCorrect(base, card, i); + + if (correct) { + const staged = insertAt(base, card, i); + if (staged.length >= WIN_TARGET) { + declareWinner(staged); + return; + } + + get().stopTimer(); + + set({ + turnTimeline: staged, + currentCard: undefined, + pendingIndex: null, + lastPlacementCorrect: true, + phase: "CHOICE_AFTER_CORRECT", + }); + } else { + set({ + turnTimeline: s.roundBaselineTimeline.slice(), + currentCard: undefined, + pendingIndex: null, + lastPlacementCorrect: false, + phase: "PLACED_WRONG", + wrongAnswerCard: card, + }); + get().stopTimer(); + } + }, + + drawAnother: async () => { + await get().startTurn(); + }, + + lockIn: () => { + const s = get(); + if (s.winner) return; + + const tIdx = s.currentTeamIndex; + const committed = s.turnTimeline; + + get().stopTimer(); + + const full = get().settings.turnSeconds; + set((state) => ({ timer: { ...state.timer, secondsLeft: full } })); + + if (committed.length >= WIN_TARGET) { + declareWinner(committed); + return; + } + + set({ + teams: s.teams.map((t, i) => + i === tIdx ? { ...t, timeline: committed } : t + ) as GameState["teams"], + phase: "TURN_START", + lastPlacementCorrect: null, + wrongAnswerCard: null, + }); + + if (s.lastPlacementCorrect !== false) { + get().nextTeam(); + } + }, + + nextTeam: () => { + const s = get(); + const currentTeamIdx = s.currentTeamIndex; + const next = (currentTeamIdx + 1) % s.teams.length; + const nextTeam = s.teams[next]; + + const committed = s.turnTimeline; + set({ + teams: s.teams.map((t, i) => + i === currentTeamIdx ? { ...t, timeline: committed } : t + ) as GameState["teams"], + currentTeamIndex: next, + currentCard: undefined, + pendingIndex: null, + phase: "TURN_START", + lastPlacementCorrect: null, + lastTurnFeedback: null, + wrongAnswerCard: null, + turnTimeline: nextTeam?.timeline?.slice() || [], + }); + }, + + setTeamCount: (count) => { + const s = get().settings; + const names = s.teamNames.slice(0, count); + while (names.length < count) names.push(`Team ${names.length + 1}`); + set({ settings: { ...s, teamNames: names } }); + }, + + setTeamName: (index, name) => { + const s = get().settings; + const names = s.teamNames.slice(); + names[index] = name; + set({ settings: { ...s, teamNames: names } }); + }, + + setTurnSeconds: (sec) => { + const s = get().settings; + set({ + settings: { ...s, turnSeconds: sec }, + timer: { ...get().timer, secondsLeft: sec }, + }); + }, + + setRevealMode: (mode) => { + const s = get().settings; + set({ settings: { ...s, revealMode: mode } }); + }, + + applySettings: () => { + const { settings, timer } = get(); + set({ timer: { ...timer, secondsLeft: settings.turnSeconds } }); + }, + + timeUp: () => { + const s = get(); + + if (s.pendingIndex != null && s.currentCard) { + const ok = isPlacementCorrect( + s.turnTimeline, + s.currentCard, + s.pendingIndex + ); + + if (ok) { + const staged = insertAt( + s.turnTimeline, + s.currentCard, + s.pendingIndex + ); + if (staged.length >= WIN_TARGET) { + set({ + currentCard: undefined, + pendingIndex: null, + lastPlacementCorrect: true, + lastTurnFeedback: { timeUp: true, correct: true }, + }); + declareWinner(staged); + return; + } + + set({ + turnTimeline: staged, + currentCard: undefined, + pendingIndex: null, + lastPlacementCorrect: true, + lastTurnFeedback: { timeUp: true, correct: true }, + }); + get().stopTimer(); + set({ phase: "CHOICE_AFTER_CORRECT" }); + return; + } else { + set({ + turnTimeline: s.roundBaselineTimeline.slice(), + currentCard: undefined, + pendingIndex: null, + lastPlacementCorrect: false, + lastTurnFeedback: { timeUp: true, correct: false }, + wrongAnswerCard: s.currentCard, + }); + get().stopTimer(); + return; + } + } + + set({ + lastPlacementCorrect: null, + lastTurnFeedback: { timeUp: true, correct: null }, + }); + get().stopTimer(); + return; + }, + + startTimer: () => { + const prev = get().timer.timerId; + if (prev) window.clearInterval(prev); + + const { turnSeconds } = get().settings; + const deadline = Date.now() + turnSeconds * 1000; + + const id = window.setInterval(() => { + const left = Math.max(0, Math.ceil((deadline - Date.now()) / 1000)); + set({ + timer: { + ...get().timer, + secondsLeft: left, + turnDeadline: deadline, + timerId: id, + }, + }); + if (left <= 0) { + get().timeUp(); + } + }, 250); + + set({ + timer: { + ...get().timer, + secondsLeft: turnSeconds, + turnDeadline: deadline, + timerId: id, + }, + }); + }, + + stopTimer: () => { + const { timerId } = get().timer; + if (timerId) window.clearInterval(timerId); + const full = get().settings.turnSeconds; + set({ + timer: { + ...get().timer, + timerId: null, + turnDeadline: null, + secondsLeft: full, + }, + }); + }, + + resetGame: () => { + const { timerId } = get().timer; + if (timerId) window.clearInterval(timerId); + + set({ + deck: [], + discard: [], + teams: [ + { id: "A", name: "Team A", timeline: [], score: 0 }, + { id: "B", name: "Team B", timeline: [], score: 0 }, + ], + currentTeamIndex: 0, + currentCard: undefined, + phase: "SETUP", + loading: false, + error: null, + lastPlacementCorrect: null, + pendingIndex: null, + roundBaselineTimeline: [], + turnTimeline: [], + selectedCategory: null, + winner: null, + lastTurnFeedback: null, + wrongAnswerCard: null, + timer: { + turnDeadline: null, + secondsLeft: initialSettings.turnSeconds, + timerId: null, + }, + }); + }, + + resetGameAndCategory: () => { + get().resetGame(); + set({ selectedCategory: null }); + }, + }; +}); diff --git a/frontend/src/types/admin.ts b/frontend/src/types/admin.ts new file mode 100644 index 0000000000..8daef925c6 --- /dev/null +++ b/frontend/src/types/admin.ts @@ -0,0 +1,11 @@ +import type { GameCategory, GameItem } from './game'; + +export interface Admin { + id: string; + username: string; + email: string; + lastLogin?: string; +} + +export type Category = GameCategory; +export type Item = GameItem; diff --git a/frontend/src/types/game.ts b/frontend/src/types/game.ts new file mode 100644 index 0000000000..fb24d6875d --- /dev/null +++ b/frontend/src/types/game.ts @@ -0,0 +1,60 @@ +export type GameItem = { + _id?: string; + id: string; + name: string; + label?: string; + value: number; + categoryId: string; + source?: { name: string; url?: string }; + meta?: Record; +}; + +export type GameCategory = { + _id?: string; + id: string; + name: string; + description?: string; + question: string; + unit: string; + unitVisible?: boolean; + sort?: "asc" | "desc"; + source?: { name: string; url?: string }; + version?: number; +}; + +export type Team = { + id: string; + name: string; + timeline: GameItem[]; + score: number; +}; + +export type Phase = + | "SETUP" + | "TURN_START" + | "DRAWN" + | "PLACED_PENDING" + | "WAITING_PLACEMENT" + | "CHOICE_AFTER_CORRECT" + | "PLACED_WRONG"; + +export type RevealMode = "hidden" | "shown"; + +export type GameSettings = { + teamNames: string[]; + turnSeconds: 30 | 60 | 90; + revealMode: RevealMode; +}; + +export type GameState = { + deck: GameItem[]; + discard: GameItem[]; + teams: Team[]; + currentTeamIndex: number; + currentCard?: GameItem; + roundBaselineTimeline: GameItem[]; + pendingIndex: number | null; + lastPlacementCorrect: boolean | null; + + phase: Phase; +}; diff --git a/frontend/src/ui/Button.tsx b/frontend/src/ui/Button.tsx new file mode 100644 index 0000000000..bc96bf82b4 --- /dev/null +++ b/frontend/src/ui/Button.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { cn } from "../lib/utils"; + +interface ButtonProps extends React.ButtonHTMLAttributes { + variant?: "primary" | "secondary" | "outline" | "ghost"; + size?: "xs" | "sm" | "md" | "lg"; + children: React.ReactNode; +} + +export const Button = React.forwardRef( + ( + { className, variant = "primary", size = "md", children, ...props }, + ref + ) => { + const baseStyles = + "inline-flex items-center justify-center rounded-xl font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-focus disabled:pointer-events-none disabled:opacity-50"; + + const variants = { + primary: "bg-primary text-background hover:bg-primary-hover shadow-soft", + secondary: + "bg-surface text-foreground hover:bg-card border border-border shadow-soft", + outline: + "border border-primary text-primary hover:bg-primary hover:text-background", + ghost: "text-foreground hover:bg-muted hover:text-foreground", + }; + + const sizes = { + xs: "h-8 px-2 text-xs", + sm: "h-9 px-3 text-sm", + md: "h-11 px-6 text-base", + lg: "h-12 px-8 text-lg", + }; + + return ( + + ); + } +); + +Button.displayName = "Button"; diff --git a/frontend/src/ui/Card.tsx b/frontend/src/ui/Card.tsx new file mode 100644 index 0000000000..0102c1d643 --- /dev/null +++ b/frontend/src/ui/Card.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { cn } from "../lib/utils"; + +type CardVariant = "surface" | "accent"; + +interface CardProps extends React.HTMLAttributes { + children: React.ReactNode; + variant?: CardVariant; + hoverable?: boolean; + clickable?: boolean +} + +export const Card = React.forwardRef( + ({ className, children, variant = "surface", hoverable = false, clickable = false, ...props }, ref) => { + const hoverClasses = hoverable + ? "hover:shadow-medium hover:border-primary/30 hover:bg-card hover:-translate-y-1" + : ""; + const clickClasses = clickable ? "cursor-pointer" : ""; + + const variantClasses = + variant === "accent" + ? "bg-accent-300 border-accent-400 text-base-100 hover:bg-accent-200" + : "bg-surface border-border text-foreground"; + + return ( +
+ {children} +
+ ); + } +); + +Card.displayName = "Card"; + +interface CardHeaderProps extends React.HTMLAttributes { + children: React.ReactNode; +} + +export const CardHeader = React.forwardRef( + ({ className, children, ...props }, ref) => { + return ( +
+ {children} +
+ ); + } +); + +CardHeader.displayName = "CardHeader"; + +interface CardContentProps extends React.HTMLAttributes { + children: React.ReactNode; +} + +export const CardContent = React.forwardRef( + ({ className, children, ...props }, ref) => { + return ( +
+ {children} +
+ ); + } +); + +CardContent.displayName = "CardContent"; diff --git a/frontend/src/ui/ErrorMessage.tsx b/frontend/src/ui/ErrorMessage.tsx new file mode 100644 index 0000000000..983b34feb9 --- /dev/null +++ b/frontend/src/ui/ErrorMessage.tsx @@ -0,0 +1,76 @@ +"use client" + +import type React from "react" +import { cn } from "../lib/utils" + +type ErrorVariant = "error" | "warning" | "info" + +interface ErrorMessageProps { + message: string + variant?: ErrorVariant + dismissible?: boolean + onDismiss?: () => void + className?: string +} + +export const ErrorMessage: React.FC = ({ + message, + variant = "error", + dismissible = false, + onDismiss, + className, +}) => { + const variantClasses = { + error: "bg-red-50 border-red-200 text-red-800", + warning: "bg-amber-50 border-amber-200 text-amber-800", + info: "bg-blue-50 border-blue-200 text-blue-800", + } + + const iconClasses = { + error: "text-red-500", + warning: "text-amber-500", + info: "text-blue-500", + } + + return ( +
+ {/* CSS Alert Icon */} +
+
+
+
+
+
+ +
+

{message}

+
+ + {dismissible && onDismiss && ( + + )} +
+ ) +} diff --git a/frontend/src/ui/Heading.tsx b/frontend/src/ui/Heading.tsx new file mode 100644 index 0000000000..32c2b47984 --- /dev/null +++ b/frontend/src/ui/Heading.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import { cn } from "../lib/utils"; + +interface HeadingProps extends React.HTMLAttributes { + level?: 1 | 2 | 3 | 4 | 5 | 6; + children: React.ReactNode; +} + +export const Heading = React.forwardRef( + ({ className, level = 1, children, ...props }, ref) => { + const Tag = `h${level}` as keyof JSX.IntrinsicElements; + + const styles = { + 1: "text-6xl font-bold text-primary tracking-tight", + 2: "text-4xl font-bold text-primary tracking-tight", + 3: "text-2xl font-semibold text-primary tracking-tight", + 4: "text-xl font-semibold text-foreground", + 5: "text-lg font-medium text-foreground", + 6: "text-base font-medium text-muted-foreground", + }; + + return React.createElement( + Tag, + { + ref, + className: cn(styles[level], className), + ...props, + }, + children + ); + } +); + +Heading.displayName = "Heading"; diff --git a/frontend/src/ui/Input.tsx b/frontend/src/ui/Input.tsx new file mode 100644 index 0000000000..32822db92b --- /dev/null +++ b/frontend/src/ui/Input.tsx @@ -0,0 +1,35 @@ +import React from "react" +import { cn } from "../lib/utils" + +interface InputProps extends React.InputHTMLAttributes { + error?: boolean + helperText?: string +} + +export const Input = React.forwardRef( + ({ className, error, helperText, ...props }, ref) => { + return ( +
+ + {helperText && ( +

{helperText}

+ )} +
+ ) + }, +) + +Input.displayName = "Input" diff --git a/frontend/src/ui/Label.tsx b/frontend/src/ui/Label.tsx new file mode 100644 index 0000000000..c784675b42 --- /dev/null +++ b/frontend/src/ui/Label.tsx @@ -0,0 +1,28 @@ +import React from "react" +import { cn } from "../lib/utils" + +interface LabelProps extends React.LabelHTMLAttributes { + children: React.ReactNode + required?: boolean +} + +export const Label = React.forwardRef( + ({ className, children, required, ...props }, ref) => { + return ( + + ) + }, +) + +Label.displayName = "Label" diff --git a/frontend/src/ui/Spinner.tsx b/frontend/src/ui/Spinner.tsx new file mode 100644 index 0000000000..84339b53b8 --- /dev/null +++ b/frontend/src/ui/Spinner.tsx @@ -0,0 +1,30 @@ +import React from "react"; + +type SpinnerProps = { label?: string; size?: "sm" | "md" | "lg" }; + +const S = { + sm: "h-6 w-6 border-2", + md: "h-10 w-10 border-[3px]", + lg: "h-14 w-14 border-[4px]", +}; + +export const Spinner: React.FC = ({ label, size = "md" }) => { + const ring = S[size]; + return ( +
+
+ {label ? ( +
+ {label} +
+ ) : null} +
+ ); +}; diff --git a/frontend/src/ui/index.ts b/frontend/src/ui/index.ts new file mode 100644 index 0000000000..7808b11a0e --- /dev/null +++ b/frontend/src/ui/index.ts @@ -0,0 +1,7 @@ +export { Button } from './Button'; +export { Card, CardHeader, CardContent } from './Card'; +export { Heading } from './Heading'; +export { ErrorMessage } from './ErrorMessage'; +export { Input } from './Input'; +export { Label } from './Label'; +export { Spinner } from './Spinner'; \ No newline at end of file diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000000..3fa6063088 --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,10 @@ +/// + +interface ImportMetaEnv { + readonly VITE_BACKEND_URL: string; + readonly VITE_FRONTEND_URL: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/frontend/tailwind.config.ts b/frontend/tailwind.config.ts new file mode 100644 index 0000000000..1f10460203 --- /dev/null +++ b/frontend/tailwind.config.ts @@ -0,0 +1,22 @@ +import type { Config } from "tailwindcss"; +import animate from "tailwindcss-animate"; + +const config: Config = { + darkMode: "class", + content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + theme: { + extend: { + screens: { + 'xs': '320px', + 'sm': '640px', + 'md': '768px', + 'lg': '1024px', + 'xl': '1280px', + '2xl': '1536px', + }, + }, + }, + plugins: [animate], +}; + +export default config; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000000..5485dce0c0 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "jsx": "react-jsx", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src", "vite.config.ts", "tailwind.config.ts", "declaration.d.ts"] +} diff --git a/frontend/vite.config.js b/frontend/vite.config.js deleted file mode 100644 index 5a33944a9b..0000000000 --- a/frontend/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], -}) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000000..e79cad931b --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; + + +export default defineConfig({ + plugins: [react(), tailwindcss()], + server: { + host: '127.0.0.1', + port: 5173, + }, +}); diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000000..fba8de4b3a --- /dev/null +++ b/netlify.toml @@ -0,0 +1,9 @@ +[build] + base = "frontend" + publish = "dist" + command = "npm run build" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..e5c892cb4a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "project-final-parent", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "project-final-parent", + "version": "1.0.0", + "hasInstallScript": true + } + } +} diff --git a/package.json b/package.json index 680d190772..549039a2fd 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,9 @@ "name": "project-final-parent", "version": "1.0.0", "scripts": { - "postinstall": "npm install --prefix backend" + "postinstall": "npm install --prefix backend", + "lint": "npm --prefix frontend run lint", + "lint:fix": "npm --prefix frontend run lint:fix", + "prune": "npm --prefix frontend run prune" } -} \ No newline at end of file +}