diff --git a/CHANGELOG.md b/CHANGELOG.md
index baa284c..6c7fde9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,11 +11,36 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
- Ronda 2-5: Implementar reglas evolutivas
- Sistema de Judge rotativo
- Shame tokens y penalizaciones
-- UI de administración completa
- Efectos de sonido
- PWA support
- Multi-idioma
+## [0.0.8-alpha] - 2025-07-04
+
+### Added
+- **Admin Dashboard Completo**: UI de administración con información detallada de jugadores
+- **Control de Jugadores**: Expulsar jugadores individuales y todos los jugadores
+- **Control de Rondas Global**: Avanzar y retroceder rondas en todas las salas simultáneamente
+- **Control de Juego**: Pausar y reanudar juegos desde el admin
+- **Notificaciones a Clientes**: Los jugadores reciben notificaciones cuando son expulsados o cuando cambian las rondas
+- **Información Detallada de Jugadores**: Nombre, sala, rol, tipo de productor y tokens actuales
+- **Redirección Automática**: Los clientes expulsados vuelven automáticamente al home
+
+### Changed
+- **API Oficial de Colyseus**: Refactorizado todos los endpoints admin para usar `matchMaker.query()` y `matchMaker.remoteRoomCall()`
+- **Arquitectura sin Variables Globales**: Eliminado el hack de variables globales por implementación oficial
+- **UI Admin Mejorada**: Información más clara y organizada para comentaristas no-técnicos
+
+### Fixed
+- **Notificación de Expulsión**: Los clientes ahora reciben notificación correcta cuando son expulsados
+- **URLs del Admin Service**: Corregido para llamar al servidor Colyseus (puerto 2567) en lugar del admin (puerto 3001)
+- **Expulsión Masiva**: Todos los jugadores reciben notificación apropiada cuando se expulsan todos
+
+### Technical
+- **GameRoom Methods**: Implementado `pauseGame()`, `resumeGame()`, `advanceRound()`, `previousRound()`, `_forceClientDisconnect()`, `_forceDisconnectAllClients()`, `getInspectData()`
+- **Client Notifications**: Manejo de mensajes `adminKicked`, `gamePaused`, `gameResumed`, `roundChanged`
+- **Type Safety**: Mantenida sincronización de tipos TypeScript entre servidor y clientes
+
## [0.0.5-alpha] - 2025-01-04
### Añadido
diff --git a/CLAUDE.md b/CLAUDE.md
index 8ee13b8..31dd977 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -72,16 +72,39 @@ nginx-proxy-manager # Proxy reverso y balanceador
- `/server` → API Servidor Colyseus
## UI de Administración
-**Funcionalidades:**
-- Estadísticas en tiempo real de partidas activas
-- Leaderboard global
-- Monitor de estado de jugadores
+**Arquitectura:**
+- Servidor Express independiente (Puerto 3001)
+- Comunicación SSE con servidor Colyseus
+- Actualización de estado cada 500ms (polling)
+- Una interfaz principal (múltiples conexiones opcionales)
+
+**Funcionalidades principales:**
+- Dashboard con estadísticas en tiempo real:
+ - Cantidad de jugadores conectados
+ - Cantidad de partidas activas
+ - Ronda actual del juego global
+ - Estados: esperando jugadores, pausa, juego terminado
+ - Nombres de las rondas
+- Panel de control:
+ - Expulsar jugadores individuales y todos (con notificaciones)
+ - Control de rondas global (avanzar/retroceder en todas las salas)
+ - Pausar/reanudar juego
+ - Cancelar partidas de grupos específicos
+- Lista de jugadores detallada:
+ - Nombre, sala, rol del juego y tipo de productor
+ - Tokens actuales (🦃 pavos, ☕ café, 🌽 maíz)
+ - Estado de conexión en tiempo real
+- Sistema de notificaciones a clientes:
+ - Expulsión con redirección automática
+ - Cambios de ronda globales
+ - Pausas y reanudaciones
- Panel de debugging para IT profesional
- Transparencia total del estado del servidor
**Usuarios objetivo:**
- Admin no-técnico: Vista simple de estadísticas
- IT profesional: Vista detallada de debugging
+- Comentaristas deportivos: Información clara para narración en vivo
## Comandos Importantes
@@ -175,6 +198,48 @@ client/src/types/
2. **Tipos auxiliares**: Se copian manualmente cuando se añaden/modifican
3. **Consistencia**: Usar nombres idénticos entre server y client
+## API Admin - Arquitectura Técnica
+
+### Endpoints Implementados
+**Servidor Colyseus (Puerto 2567):**
+- `GET /api/admin/stats` - Estadísticas en tiempo real usando `matchMaker.query()`
+- `POST /api/admin/kick-player` - Expulsar jugador específico con notificación
+- `POST /api/admin/kick-all-players` - Expulsar todos los jugadores con notificaciones
+- `POST /api/admin/pause-game` - Pausar todas las partidas activas
+- `POST /api/admin/resume-game` - Reanudar partidas pausadas
+- `POST /api/admin/advance-round` - Avanzar ronda globalmente
+- `POST /api/admin/previous-round` - Retroceder ronda globalmente
+- `POST /api/admin/cancel-game` - Cancelar partidas específicas o todas
+
+### Métodos GameRoom Implementados
+- `getInspectData()` - Datos completos para el admin (compatible con monitor oficial)
+- `pauseGame()` - Pausar juego con broadcast a clientes
+- `resumeGame()` - Reanudar juego con broadcast a clientes
+- `advanceRound()` - Avanzar ronda con límite máximo 10
+- `previousRound()` - Retroceder ronda con límite mínimo 1
+- `_forceClientDisconnect(sessionId)` - Expulsar jugador con notificación
+- `_forceDisconnectAllClients()` - Expulsar todos con notificaciones
+
+### Comunicación Cliente-Servidor
+**Mensajes del servidor a clientes:**
+- `adminKicked` - Notificación de expulsión individual
+- `gamePaused` - Notificación de pausa del juego
+- `gameResumed` - Notificación de reanudación del juego
+- `roundChanged` - Notificación de cambio de ronda global
+
+**Manejo en el cliente:**
+- Auto-redirección a home al recibir `adminKicked`
+- Alerts informativos para cambios de estado
+- Logging detallado de eventos administrativos
+
+### Principios de Diseño
+- **API Oficial Colyseus**: Sin hacks de variables globales
+- **matchMaker.query()**: Acceso seguro a información de salas
+- **matchMaker.remoteRoomCall()**: Ejecución remota de métodos
+- **Type Safety**: Sincronización completa TypeScript
+- **Error Handling**: Try/catch en todos los endpoints
+- **Graceful Notifications**: Delay de 1 segundo para procesar mensajes
+
## Notas Específicas
- **Offline**: Sin dependencias externas de internet
- **Microservicios**: Arquitectura separada por responsabilidades
@@ -184,4 +249,5 @@ client/src/types/
- **Nginx Proxy Manager**: Enrutamiento y balanceo de carga
- **Variables de Entorno**: Configuración por ambiente (.env)
- **Logging**: Detallado para debugging profesional
-- **Tipos TypeScript**: Auto-generación con schema-codegen + copiar tipos auxiliares manualmente
\ No newline at end of file
+- **Tipos TypeScript**: Auto-generación con schema-codegen + copiar tipos auxiliares manualmente
+- **Admin Dashboard**: Completamente funcional con control total del juego
\ No newline at end of file
diff --git a/README.md b/README.md
index 5527bb7..31bd589 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# 🎮 SnatchGame
-[](https://github.com/username/snatchgame)
+[](https://github.com/username/snatchgame)
[](LICENSE)
[](https://nodejs.org/)
[](https://vuejs.org/)
@@ -8,7 +8,7 @@
Un juego multijugador educativo que simula la evolución de instituciones y cooperación, basado en el **"Snatch Game"** de **Elinor Ostrom**. Construido con **Colyseus.io** y **Vue 3** para redes locales.
-> ⚠️ **Proyecto en desarrollo** - Actualmente en fase Alpha (v0.0.5-alpha)
+> ✨ **Admin Dashboard Completo** - Versión Alpha (v0.0.8-alpha) con interfaz de administración profesional
## 🎓 Sobre el Juego
@@ -30,6 +30,8 @@ Un juego multijugador educativo que simula la evolución de instituciones y coop
- **📱 Responsive** - Interfaz optimizada para desktop y móvil
- **🎯 Red local** - Funciona completamente offline
- **📈 Progresión por rondas** - 5 rondas con reglas evolutivas
+- **🎛️ Admin Dashboard** - Interfaz completa de administración y monitoreo
+- **🔔 Notificaciones** - Sistema completo de alertas para jugadores
## 🎮 Cómo Jugar
@@ -92,7 +94,7 @@ cd server && npm install
# Cliente
cd ../client && npm install
-# Admin (próximamente)
+# Admin
cd ../admin && npm install
```
@@ -116,7 +118,7 @@ npm run dev
cd client
npm run dev
-# Terminal 3 - Admin (opcional)
+# Terminal 3 - Admin Dashboard
cd admin
npm run dev
```
@@ -124,7 +126,8 @@ npm run dev
### URLs de desarrollo
- **Cliente**: http://localhost:3000
- **Servidor**: http://localhost:2567
-- **Admin**: http://localhost:3001 (próximamente)
+- **Admin Dashboard**: http://localhost:3001
+- **Monitor Colyseus**: http://localhost:2567/monitor
### Producción
```bash
@@ -155,6 +158,45 @@ docker-compose up -d
- **MakeOfferForm**: Formulario con botones +/- intuitivos
- **OfferModal**: Modal flotante para crear ofertas dirigidas
+## 🎛️ Admin Dashboard
+
+El **Admin Dashboard** proporciona control completo y monitoreo en tiempo real del juego, diseñado tanto para administradores técnicos como para comentaristas no-técnicos.
+
+### 📊 Características Principales
+
+#### **Información en Tiempo Real**
+- **👥 Lista de Jugadores Detallada**: Nombre, sala, rol, tipo de productor y tokens actuales
+- **📈 Estadísticas Globales**: Jugadores conectados, partidas activas, ronda actual
+- **🎯 Estado del Juego**: En progreso, pausado, esperando jugadores
+- **🔄 Actualización Automática**: SSE con polling cada 500ms
+
+#### **Control de Jugadores**
+- **🚫 Expulsar Jugador Individual**: Con notificación al cliente y redirección automática
+- **🚫🚫 Expulsar Todos los Jugadores**: Vaciar todas las salas con notificaciones apropiadas
+- **👤 Información Detallada**: Ver tokens específicos (🦃 pavos, ☕ café, 🌽 maíz)
+
+#### **Control del Juego**
+- **⏸️ Pausar Juego**: Pausar todas las partidas activas
+- **▶️ Reanudar Juego**: Reanudar partidas pausadas
+- **⏮️ Retroceder Ronda**: Cambio global a ronda anterior (mínimo 1)
+- **⏭️ Avanzar Ronda**: Cambio global a ronda siguiente (máximo 10)
+
+#### **Notificaciones a Clientes**
+- **🔔 Expulsión**: Mensaje personalizado y redirección automática
+- **🎯 Cambio de Ronda**: Notificación inmediata de nuevas rondas
+- **⏸️ Estado del Juego**: Alertas de pausa/reanudación
+
+### 🎯 Usuarios Objetivo
+- **👨💼 Administrador No-Técnico**: Vista limpia con estadísticas esenciales
+- **👨💻 IT Profesional**: Información de debugging y estado técnico detallado
+- **🎙️ Comentaristas Deportivos**: Información clara para narración en vivo
+
+### 🏗️ Arquitectura Técnica
+- **API Oficial Colyseus**: Uso de `matchMaker.query()` y `matchMaker.remoteRoomCall()`
+- **Comunicación Bidireccional**: SSE para updates, HTTP para control
+- **Sin Variables Globales**: Implementación limpia y mantenible
+- **Type Safety**: Sincronización completa de tipos TypeScript
+
## ⚙️ Configuración
### Variables de Entorno
@@ -183,7 +225,7 @@ PORT=2567
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client UI │ │ Colyseus │ │ Admin UI │
-│ (Vue 3) │◄──►│ Server │◄──►│ (Vue 3) │
+│ (Vue 3) │◄──►│ Server │◄──►│ (Vue 3 + SSE) │
│ Port 3000 │ │ Port 2567 │ │ Port 3001 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
@@ -195,6 +237,11 @@ PORT=2567
└─────────────────┘
```
+### Comunicación Admin
+- **SSE (Server-Sent Events)**: Servidor → Admin UI
+- **Polling**: Actualización cada 500ms
+- **Control**: Admin → Servidor (HTTP endpoints)
+
### Sincronización de Tipos
```bash
# Los tipos se generan automáticamente del servidor al cliente
@@ -247,7 +294,14 @@ snatchgame/
│ │ └── main.ts
│ ├── server.js # Express server (producción)
│ └── README.md # Documentación del cliente
-├── 📁 admin/ # Admin dashboard (próximamente)
+├── 📁 admin/ # Admin dashboard
+│ ├── src/
+│ │ ├── components/ # Componentes Vue admin
+│ │ ├── services/ # Admin service
+│ │ │ └── adminService.ts
+│ │ └── main.ts
+│ ├── server.js # Express server (producción)
+│ └── README.md # Documentación del admin
├── 🎮 gameRules.md # Reglas del juego detalladas
├── 🐳 docker-compose.yml # Orquestación Docker
├── 📋 CLAUDE.md # Guía de desarrollo
@@ -333,7 +387,15 @@ npm run start
- [ ] 📊 Gráficos y visualizaciones
### Infraestructura
-- [ ] 📈 UI de administración completa
+- [x] 📈 UI de administración completa
+ - [x] Dashboard con estadísticas en tiempo real
+ - [x] Panel de control para administrar partidas
+ - [x] Sistema de expulsión de jugadores
+ - [x] Pausa/reanudación de partidas
+ - [x] Control de rondas globales
+ - [x] Información detallada de jugadores con tokens
+ - [x] Notificaciones automáticas a clientes
+ - [ ] Historial de partidas anteriores
- [ ] 🐳 Docker en producción
- [ ] 📱 PWA support
- [ ] 🌍 Multi-idioma (EN/ES)
diff --git a/TODO.md b/TODO.md
index cbf8659..dad63c1 100644
--- a/TODO.md
+++ b/TODO.md
@@ -22,4 +22,19 @@ Type 'GameClient' is missing the following properties from type 'GameClient': cl
- Posiblemente usar una interface en lugar de clase
- O definir tipos de props más explícitos
-**Prioridad:** Media (funciona pero no es tipo-seguro)
\ No newline at end of file
+**Prioridad:** Media (funciona pero no es tipo-seguro)
+
+### Admin API - Métodos pauseGame y resumeGame
+**Problema:** Los endpoints `/api/admin/pause-game` y `/api/admin/resume-game` usan `matchMaker.remoteRoomCall` para llamar métodos que no existen en GameRoom.
+
+**Archivos afectados:**
+- `server/src/app.config.ts` - Endpoints que llaman a `pauseGame` y `resumeGame`
+- `server/src/rooms/GameRoom.ts` - Falta implementar los métodos
+
+**Solución pendiente:**
+- Implementar método `pauseGame()` en GameRoom.ts
+- Implementar método `resumeGame()` en GameRoom.ts
+- Los métodos deben modificar `gamePhase` en el estado del juego
+- Agregar logs apropiados para debugging
+
+**Prioridad:** Alta (endpoints fallarán hasta que se implemente)
\ No newline at end of file
diff --git a/admin/README.md b/admin/README.md
new file mode 100644
index 0000000..56c137b
--- /dev/null
+++ b/admin/README.md
@@ -0,0 +1,358 @@
+# 🎛️ SnatchGame Admin Dashboard
+
+[](https://github.com/username/snatchgame)
+[](https://vuejs.org/)
+[](https://www.typescriptlang.org/)
+
+**Interfaz de administración completa** para el control y monitoreo en tiempo real del juego **SnatchGame**. Diseñada para administradores técnicos, personal no-técnico y comentaristas deportivos.
+
+## 📊 Características Principales
+
+### **🔄 Monitoreo en Tiempo Real**
+- **👥 Lista de Jugadores Detallada**: Nombre, sala, rol, tipo de productor
+- **🎯 Estado de Tokens**: Cantidad actual de 🦃 pavos, ☕ café, 🌽 maíz por jugador
+- **📈 Estadísticas Globales**: Jugadores conectados, partidas activas, ronda actual
+- **🔗 Estado de Conexión**: Indicador visual de jugadores conectados/desconectados
+- **⚡ Actualización Automática**: SSE con polling cada 500ms
+
+### **🎮 Control del Juego**
+- **⏮️ Retroceder Ronda**: Cambio global a ronda anterior (mínimo 1)
+- **⏭️ Avanzar Ronda**: Cambio global a ronda siguiente (máximo 10)
+- **⏸️ Pausar Juego**: Pausar todas las partidas activas
+- **▶️ Reanudar Juego**: Reanudar partidas pausadas
+
+### **👥 Gestión de Jugadores**
+- **🚫 Expulsar Jugador Individual**: Con notificación automática al cliente
+- **🚫🚫 Expulsar Todos los Jugadores**: Vaciar todas las salas con notificaciones
+- **🏠 Redirección Automática**: Los jugadores expulsados vuelven al home
+- **📱 Notificaciones Inmediatas**: Alerts personalizados para cada acción
+
+### **🎯 Usuarios Objetivo**
+- **👨💼 Administrador No-Técnico**: Vista limpia con estadísticas esenciales
+- **👨💻 IT Profesional**: Información de debugging y estado técnico
+- **🎙️ Comentaristas Deportivos**: Información clara para narración en vivo
+
+## 🏗️ Arquitectura Técnica
+
+### **Stack Tecnológico**
+- **Frontend**: Vue 3 + Composition API + TypeScript
+- **Build Tool**: Vite (desarrollo) + Express (producción)
+- **Comunicación**: HTTP (control) + fetch API
+- **Styling**: CSS vanilla con diseño responsivo
+- **Types**: Auto-generados desde servidor con schema-codegen
+
+### **Comunicación con Servidor**
+```typescript
+// Admin Service comunica con servidor Colyseus
+adminService.kickPlayer(playerId) // → POST /api/admin/kick-player
+adminService.advanceRound() // → POST /api/admin/advance-round
+adminService.pauseGame() // → POST /api/admin/pause-game
+```
+
+### **Arquitectura del Sistema**
+```
+┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
+│ Admin UI │ │ Colyseus │ │ Game Client │
+│ Port 3001 │───▶│ Server │◄──▶│ Port 3000 │
+│ (Vue 3) │ │ Port 2567 │ │ (Vue 3) │
+└─────────────────┘ └─────────────────┘ └─────────────────┘
+ │ │ │
+ └───── HTTP/Fetch ──────┘ │
+ │ │
+ ┌───────────▼───────────┐ │
+ │ Notifications │ │
+ │ (adminKicked, │◄─────────┘
+ │ roundChanged) │
+ └───────────────────────┘
+```
+
+## 🚀 Instalación y Ejecución
+
+### **Prerrequisitos**
+- Node.js >= 18.0.0
+- npm >= 8.0.0
+- Servidor Colyseus ejecutándose en puerto 2567
+
+### **Desarrollo**
+```bash
+# Desde el directorio admin
+cd admin
+
+# Instalar dependencias
+npm install
+
+# Generar tipos desde servidor
+npm run generate-types
+
+# Iniciar desarrollo
+npm run dev
+```
+
+### **Producción**
+```bash
+# Build para producción
+npm run build
+
+# Iniciar servidor Express
+npm start
+```
+
+### **URLs**
+- **Desarrollo**: http://localhost:3001
+- **Producción**: Configurado según variables de entorno
+
+## 📁 Estructura del Proyecto
+
+```
+admin/
+├── src/
+│ ├── components/ # Componentes Vue
+│ ├── services/ # Servicios de comunicación
+│ │ └── adminService.ts # API client para servidor Colyseus
+│ ├── types/ # Tipos auto-generados
+│ │ ├── GameState.ts # Estado del juego
+│ │ ├── Player.ts # Información de jugador
+│ │ ├── TokenInventory.ts # Inventario de tokens
+│ │ └── index.ts # Re-exports y tipos auxiliares
+│ ├── App.vue # Componente principal
+│ └── main.ts # Entry point
+├── server.js # Express server (producción)
+├── package.json # Dependencias y scripts
+├── vite.config.ts # Configuración Vite
+└── README.md # Este archivo
+```
+
+## 🎨 Interfaz de Usuario
+
+### **Dashboard Principal**
+```
+📊 SnatchGame Dashboard 🟢 Conectado
+┌─────────────────────────────────────────────────────────────┐
+│ 👥 Jugadores: 6 🎮 Partidas: 2 🎯 Ronda: 3 │
+│ 📊 Estado: En progreso │
+└─────────────────────────────────────────────────────────────┘
+
+🎛️ Control del Juego
+┌─────────────────────────────────────────────────────────────┐
+│ ⏮️ Retroceder ⏭️ Avanzar ⏸️ Pausar ▶️ Reanudar │
+│ Ronda Ronda Juego Juego │
+│ │
+│ 🚫 Expulsar 🚫🚫 Expulsar │
+│ Jugador Jugadores │
+└─────────────────────────────────────────────────────────────┘
+
+👥 Lista de Jugadores (6)
+┌─────────────────────────────────────────────────────────────┐
+│ Juan Carlos 🟢 Sala: a3f2b1 │
+│ Comerciante 🦃 Productor de Pavos │
+│ 🦃 3 ☕ 2 🌽 1 🚫 Expulsar │
+├─────────────────────────────────────────────────────────────┤
+│ María López 🟢 Sala: a3f2b1 │
+│ Comerciante ☕ Productor de Café │
+│ 🦃 1 ☕ 4 🌽 2 🚫 Expulsar │
+└─────────────────────────────────────────────────────────────┘
+```
+
+### **Responsive Design**
+- **Desktop**: Layout de 2 columnas con información completa
+- **Tablet**: Layout adaptativo con botones optimizados
+- **Mobile**: Layout vertical con información esencial
+
+## ⚙️ Configuración
+
+### **Variables de Entorno**
+```env
+# .env.development
+VITE_ADMIN_PORT=3001
+NODE_ENV=development
+
+# .env.production
+VITE_ADMIN_PORT=3001
+NODE_ENV=production
+```
+
+### **AdminService Configuration**
+```typescript
+// src/services/adminService.ts
+class AdminService {
+ private serverUrl = 'http://localhost:2567' // Colyseus server
+
+ // Todos los métodos apuntan al servidor Colyseus
+ async kickPlayer(playerId: string) { /* ... */ }
+ async advanceRound() { /* ... */ }
+ // ...
+}
+```
+
+## 🔧 API Reference
+
+### **AdminService Methods**
+
+#### **Control de Jugadores**
+```typescript
+// Expulsar jugador específico
+await adminService.kickPlayer('player-session-id')
+
+// Expulsar todos los jugadores
+await adminService.kickAllPlayers()
+```
+
+#### **Control del Juego**
+```typescript
+// Pausar todas las partidas
+await adminService.pauseGame()
+
+// Reanudar partidas pausadas
+await adminService.resumeGame()
+```
+
+#### **Control de Rondas**
+```typescript
+// Avanzar ronda globalmente
+await adminService.advanceRound()
+
+// Retroceder ronda globalmente
+await adminService.previousRound()
+```
+
+#### **Gestión de Partidas**
+```typescript
+// Cancelar partida específica
+await adminService.cancelGame('room-id')
+
+// Cancelar todas las partidas
+await adminService.cancelGame()
+```
+
+### **Endpoints del Servidor**
+Todos los endpoints están en el **servidor Colyseus** (puerto 2567):
+
+- `GET /api/admin/stats` - Estadísticas en tiempo real
+- `POST /api/admin/kick-player` - Expulsar jugador específico
+- `POST /api/admin/kick-all-players` - Expulsar todos los jugadores
+- `POST /api/admin/pause-game` - Pausar juego
+- `POST /api/admin/resume-game` - Reanudar juego
+- `POST /api/admin/advance-round` - Avanzar ronda
+- `POST /api/admin/previous-round` - Retroceder ronda
+- `POST /api/admin/cancel-game` - Cancelar partida
+
+## 🔔 Sistema de Notificaciones
+
+### **Notificaciones a Clientes**
+El admin puede enviar notificaciones automáticas que los clientes reciben:
+
+```typescript
+// El cliente recibe estos mensajes automáticamente
+client.onMessage("adminKicked", (data) => {
+ alert("🚫 Has sido expulsado por el administrador")
+ // Auto-redirección a home screen
+})
+
+client.onMessage("roundChanged", (data) => {
+ alert(`🎯 ${data.message}`) // "Ronda 3 - Cambio realizado por el administrador"
+})
+```
+
+### **Experiencia del Usuario**
+1. **Admin ejecuta acción** (expulsar, cambiar ronda, etc.)
+2. **Servidor procesa** usando API oficial de Colyseus
+3. **Clientes reciben notificación** inmediata y automática
+4. **Redirección automática** cuando corresponde (expulsión)
+
+## 🛠️ Desarrollo
+
+### **Scripts Disponibles**
+```bash
+# Desarrollo con hot reload
+npm run dev
+
+# Generar tipos desde servidor
+npm run generate-types
+
+# Build para producción
+npm run build
+
+# Preview del build
+npm run preview
+
+# Servidor Express (producción)
+npm start
+```
+
+### **Debugging**
+```bash
+# Verificar que el servidor Colyseus esté ejecutándose
+curl http://localhost:2567/
+
+# Verificar endpoint de stats
+curl http://localhost:2567/api/admin/stats
+
+# Ver logs del admin en desarrollo
+npm run dev
+# Abrir DevTools (F12) para logs detallados
+```
+
+### **Type Generation**
+```bash
+# Los tipos se generan automáticamente desde el servidor
+cd admin
+npm run generate-types
+
+# Esto ejecuta:
+# cd ../server && npx schema-codegen src/rooms/GameRoom.ts --ts --output ../admin/src/types/
+```
+
+## 🚀 Deploy
+
+### **Docker (Recomendado)**
+```bash
+# Desde el directorio raíz del proyecto
+docker-compose up -d
+
+# El admin estará disponible en el puerto configurado
+```
+
+### **Manual**
+```bash
+# Build admin
+cd admin
+npm run build
+
+# Start en producción
+npm start
+```
+
+## 🤝 Contribuir
+
+### **Estructura de Contribución**
+1. **Servidor primero**: Implementar nuevos endpoints en `/server/src/app.config.ts`
+2. **GameRoom methods**: Agregar métodos necesarios en `/server/src/rooms/GameRoom.ts`
+3. **AdminService**: Actualizar `/admin/src/services/adminService.ts`
+4. **UI Components**: Modificar `/admin/src/App.vue` según necesidad
+5. **Types**: Regenerar con `npm run generate-types`
+
+### **Convenciones**
+- **Endpoints**: Prefijo `/api/admin/` para todas las rutas admin
+- **Métodos GameRoom**: Prefijo `_` para métodos admin (ej: `_forceClientDisconnect`)
+- **Notificaciones**: Mensajes descriptivos en español para usuarios
+- **Error Handling**: Try/catch en todos los métodos async
+
+## 📄 Licencia
+
+Este microservicio es parte del proyecto **SnatchGame** bajo licencia **MIT**.
+
+## 🙋♂️ Soporte
+
+- **Documentación Principal**: `/README.md` (directorio raíz)
+- **Guía Técnica**: `/CLAUDE.md`
+- **Issues**: [GitHub Issues](https://github.com/username/snatchgame/issues)
+
+---
+
+
+
+**🎛️ Admin Dashboard Completo para SnatchGame**
+
+*Control total • Monitoreo en tiempo real • Notificaciones automáticas*
+
+
\ No newline at end of file
diff --git a/admin/index.html b/admin/index.html
new file mode 100644
index 0000000..e25462f
--- /dev/null
+++ b/admin/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Snatch Game - Admin Dashboard
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/package-lock.json b/admin/package-lock.json
new file mode 100644
index 0000000..ccb28f3
--- /dev/null
+++ b/admin/package-lock.json
@@ -0,0 +1,2917 @@
+{
+ "name": "snatchgame-admin",
+ "version": "0.0.5-alpha",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "snatchgame-admin",
+ "version": "0.0.5-alpha",
+ "license": "ISC",
+ "dependencies": {
+ "@vitejs/plugin-vue": "^6.0.0",
+ "@vue/tsconfig": "^0.7.0",
+ "colyseus.js": "^0.16.19",
+ "dotenv": "^16.0.0",
+ "express": "^4.18.0",
+ "typescript": "^5.8.3",
+ "vite": "^7.0.0",
+ "vue": "^3.5.17"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.0",
+ "@types/node": "^20.0.0",
+ "nodemon": "^3.1.10",
+ "vue-tsc": "^3.0.1"
+ }
+ },
+ "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==",
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
+ "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.0"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz",
+ "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@colyseus/httpie": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@colyseus/httpie/-/httpie-2.0.1.tgz",
+ "integrity": "sha512-JvABMZzPLiyrUsVj3ElXGORRDTu+NKzXHWd1uV1R1SThAKMm06cVW6bOyADARD65bs8JJoHNNbUkW8KoRvRDzA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@colyseus/msgpackr": {
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.11.2.tgz",
+ "integrity": "sha512-MuwPFhizFKC3zmGfy0fpo+kcnZdNdnQHFVjw81v4WXHCelDeCX8yNRVtuEm8kGlHqq7qiASLC0pu0RPqYOhxXg==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "msgpackr-extract": "^3.0.2"
+ }
+ },
+ "node_modules/@colyseus/schema": {
+ "version": "3.0.42",
+ "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.42.tgz",
+ "integrity": "sha512-MNy8wYgvzwPhWWxKXlBqq4cW2iOAx0gMwLdXwy4UYk3oN5AUkHSchPEmo5TeSUlNcvtch/odYIfSMtYlOPO8Aw==",
+ "license": "MIT",
+ "bin": {
+ "schema-codegen": "bin/schema-codegen",
+ "schema-debug": "bin/schema-debug"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
+ "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
+ "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
+ "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
+ "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
+ "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
+ "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
+ "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
+ "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
+ "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
+ "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
+ "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
+ "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
+ "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
+ "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
+ "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
+ "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
+ "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
+ "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
+ "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
+ "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
+ "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
+ "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@isaacs/balanced-match": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
+ "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@isaacs/brace-expansion": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
+ "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@isaacs/balanced-match": "^4.0.1"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
+ "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
+ "license": "MIT"
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
+ "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
+ "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
+ "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
+ "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
+ "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
+ "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.19",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz",
+ "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==",
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.2.tgz",
+ "integrity": "sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.2.tgz",
+ "integrity": "sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.2.tgz",
+ "integrity": "sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.2.tgz",
+ "integrity": "sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.2.tgz",
+ "integrity": "sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.2.tgz",
+ "integrity": "sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.2.tgz",
+ "integrity": "sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.2.tgz",
+ "integrity": "sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.2.tgz",
+ "integrity": "sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.2.tgz",
+ "integrity": "sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.2.tgz",
+ "integrity": "sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.2.tgz",
+ "integrity": "sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.2.tgz",
+ "integrity": "sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.2.tgz",
+ "integrity": "sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.2.tgz",
+ "integrity": "sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.2.tgz",
+ "integrity": "sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.2.tgz",
+ "integrity": "sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.2.tgz",
+ "integrity": "sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.2.tgz",
+ "integrity": "sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.2.tgz",
+ "integrity": "sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.4.tgz",
+ "integrity": "sha512-OP+We5WV8Xnbuvw0zC2m4qfB/BJvjyCwtNjhHdJxV1639SGSKrLmJkc3fMnp2Qy8nJyHp8RO6umxELN/dS1/EA==",
+ "devOptional": true,
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.0.tgz",
+ "integrity": "sha512-iAliE72WsdhjzTOp2DtvKThq1VBC4REhwRcaA+zPAAph6I+OQhUXv+Xu2KS7ElxYtb7Zc/3R30Hwv1DxEo7NXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rolldown/pluginutils": "1.0.0-beta.19"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@volar/language-core": {
+ "version": "2.4.17",
+ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.17.tgz",
+ "integrity": "sha512-chmRZMbKmcGpKMoO7Reb70uiLrzo0KWC2CkFttKUuKvrE+VYgi+fL9vWMJ07Fv5ulX0V1TAyyacN9q3nc5/ecA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/source-map": "2.4.17"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.17",
+ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.17.tgz",
+ "integrity": "sha512-QDybtQyO3Ms/NjFqNHTC5tbDN2oK5VH7ZaKrcubtfHBDj63n2pizHC3wlMQ+iT55kQXZUUAbmBX5L1C8CHFeBw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.17",
+ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.17.tgz",
+ "integrity": "sha512-3paEFNh4P5DkgNUB2YkTRrfUekN4brAXxd3Ow1syMqdIPtCZHbUy4AW99S5RO/7mzyTWPMdDSo3mqTpB/LPObQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.17",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz",
+ "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.27.5",
+ "@vue/shared": "3.5.17",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz",
+ "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz",
+ "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.27.5",
+ "@vue/compiler-core": "3.5.17",
+ "@vue/compiler-dom": "3.5.17",
+ "@vue/compiler-ssr": "3.5.17",
+ "@vue/shared": "3.5.17",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.17",
+ "postcss": "^8.5.6",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz",
+ "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "node_modules/@vue/compiler-vue2": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+ "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/language-core": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.0.1.tgz",
+ "integrity": "sha512-sq+/Mc1IqIexWEQ+Q2XPiDb5SxSvY5JPqHnMOl/PlF5BekslzduX8dglSkpC17VeiAQB6dpS+4aiwNLJRduCNw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.17",
+ "@vue/compiler-dom": "^3.5.0",
+ "@vue/compiler-vue2": "^2.7.16",
+ "@vue/shared": "^3.5.0",
+ "alien-signals": "^2.0.5",
+ "minimatch": "^10.0.1",
+ "muggle-string": "^0.4.1",
+ "path-browserify": "^1.0.1"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/language-core/node_modules/minimatch": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
+ "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@isaacs/brace-expansion": "^5.0.0"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz",
+ "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz",
+ "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz",
+ "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.17",
+ "@vue/runtime-core": "3.5.17",
+ "@vue/shared": "3.5.17",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz",
+ "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.17",
+ "@vue/shared": "3.5.17"
+ },
+ "peerDependencies": {
+ "vue": "3.5.17"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz",
+ "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==",
+ "license": "MIT"
+ },
+ "node_modules/@vue/tsconfig": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz",
+ "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "typescript": "5.x",
+ "vue": "^3.4.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ },
+ "vue": {
+ "optional": true
+ }
+ }
+ },
+ "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/alien-signals": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-2.0.5.tgz",
+ "integrity": "sha512-PdJB6+06nUNAClInE3Dweq7/2xVAYM64vvvS1IHVHSJmgeOtEdrAGyp7Z2oJtYm0B342/Exd2NT0uMJaThcjLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "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/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/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/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/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/colyseus.js": {
+ "version": "0.16.19",
+ "resolved": "https://registry.npmjs.org/colyseus.js/-/colyseus.js-0.16.19.tgz",
+ "integrity": "sha512-48cVPt5+21R79itIHpcJplMFt7HEks5chxPXtM9l+AvmFjfXO8UykIV4j+fYyKaJu6EB14AbBH0AnTvpQqnAEg==",
+ "license": "MIT",
+ "dependencies": {
+ "@colyseus/httpie": "^2.0.0",
+ "@colyseus/msgpackr": "^1.11.2",
+ "@colyseus/schema": "^3.0.0",
+ "tslib": "^2.1.0",
+ "ws": "^8.13.0"
+ },
+ "engines": {
+ "node": ">= 12.x"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/endel"
+ }
+ },
+ "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": {
+ "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/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/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "license": "MIT"
+ },
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/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/detect-libc": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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/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/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "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.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
+ "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.5",
+ "@esbuild/android-arm": "0.25.5",
+ "@esbuild/android-arm64": "0.25.5",
+ "@esbuild/android-x64": "0.25.5",
+ "@esbuild/darwin-arm64": "0.25.5",
+ "@esbuild/darwin-x64": "0.25.5",
+ "@esbuild/freebsd-arm64": "0.25.5",
+ "@esbuild/freebsd-x64": "0.25.5",
+ "@esbuild/linux-arm": "0.25.5",
+ "@esbuild/linux-arm64": "0.25.5",
+ "@esbuild/linux-ia32": "0.25.5",
+ "@esbuild/linux-loong64": "0.25.5",
+ "@esbuild/linux-mips64el": "0.25.5",
+ "@esbuild/linux-ppc64": "0.25.5",
+ "@esbuild/linux-riscv64": "0.25.5",
+ "@esbuild/linux-s390x": "0.25.5",
+ "@esbuild/linux-x64": "0.25.5",
+ "@esbuild/netbsd-arm64": "0.25.5",
+ "@esbuild/netbsd-x64": "0.25.5",
+ "@esbuild/openbsd-arm64": "0.25.5",
+ "@esbuild/openbsd-x64": "0.25.5",
+ "@esbuild/sunos-x64": "0.25.5",
+ "@esbuild/win32-arm64": "0.25.5",
+ "@esbuild/win32-ia32": "0.25.5",
+ "@esbuild/win32-x64": "0.25.5"
+ }
+ },
+ "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/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "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/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/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/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "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/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.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/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-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/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "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-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "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/magic-string": {
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
+ "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/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/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/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": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/msgpackr-extract": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
+ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "node-gyp-build-optional-packages": "5.2.2"
+ },
+ "bin": {
+ "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+ },
+ "optionalDependencies": {
+ "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
+ }
+ },
+ "node_modules/muggle-string": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+ "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==",
+ "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/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/node-gyp-build-optional-packages": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
+ "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^2.0.1"
+ },
+ "bin": {
+ "node-gyp-build-optional-packages": "bin.js",
+ "node-gyp-build-optional-packages-optional": "optional.js",
+ "node-gyp-build-optional-packages-test": "build-test.js"
+ }
+ },
+ "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/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/nodemon/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.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/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-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-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/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "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/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "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/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/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/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/rollup": {
+ "version": "4.44.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.2.tgz",
+ "integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==",
+ "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.44.2",
+ "@rollup/rollup-android-arm64": "4.44.2",
+ "@rollup/rollup-darwin-arm64": "4.44.2",
+ "@rollup/rollup-darwin-x64": "4.44.2",
+ "@rollup/rollup-freebsd-arm64": "4.44.2",
+ "@rollup/rollup-freebsd-x64": "4.44.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.44.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.44.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.44.2",
+ "@rollup/rollup-linux-arm64-musl": "4.44.2",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.44.2",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.44.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.44.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.44.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.44.2",
+ "@rollup/rollup-linux-x64-gnu": "4.44.2",
+ "@rollup/rollup-linux-x64-musl": "4.44.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.44.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.44.2",
+ "@rollup/rollup-win32-x64-msvc": "4.44.2",
+ "fsevents": "~2.3.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==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "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/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/send/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/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/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/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/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==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/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/tinyglobby": {
+ "version": "0.2.14",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
+ "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
+ "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/tinyglobby/node_modules/fdir": {
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+ "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "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/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-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.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "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==",
+ "devOptional": true,
+ "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/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/vite": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.2.tgz",
+ "integrity": "sha512-hxdyZDY1CM6SNpKI4w4lcUc3Mtkd9ej4ECWVHSMrOdSinVc2zYOAppHeGc/hzmRo3pxM5blMzkuWHOJA/3NiFw==",
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.6",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.6",
+ "rollup": "^4.40.0",
+ "tinyglobby": "^0.2.14"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "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/vite/node_modules/fdir": {
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+ "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
+ "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vue": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz",
+ "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.17",
+ "@vue/compiler-sfc": "3.5.17",
+ "@vue/runtime-dom": "3.5.17",
+ "@vue/server-renderer": "3.5.17",
+ "@vue/shared": "3.5.17"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-tsc": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.0.1.tgz",
+ "integrity": "sha512-UvMLQD0hAGL1g/NfEQelnSVB4H5gtf/gz2lJKjMMwWNOUmSNyWkejwJagAxEbSjtV5CPPJYslOtoSuqJ63mhdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/typescript": "2.4.17",
+ "@vue/language-core": "3.0.1"
+ },
+ "bin": {
+ "vue-tsc": "bin/vue-tsc.js"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.0"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/admin/package.json b/admin/package.json
new file mode 100644
index 0000000..057ea41
--- /dev/null
+++ b/admin/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "snatchgame-admin",
+ "version": "0.0.8-alpha",
+ "description": "SnatchGame admin dashboard server",
+ "main": "server.js",
+ "scripts": {
+ "dev": "npm run generate-types && vite",
+ "build": "npm run generate-types && vue-tsc && vite build",
+ "preview": "vite preview",
+ "serve": "PORT=3002 nodemon server.js",
+ "start": "NODE_ENV=production node server.js",
+ "generate-types": "cd ../server && npx schema-codegen src/rooms/GameRoom.ts --ts --output ../admin/src/types/",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [
+ "express",
+ "vue",
+ "admin",
+ "dashboard"
+ ],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "@vitejs/plugin-vue": "^6.0.0",
+ "@vue/tsconfig": "^0.7.0",
+ "colyseus.js": "^0.16.19",
+ "dotenv": "^16.0.0",
+ "express": "^4.18.0",
+ "typescript": "^5.8.3",
+ "vite": "^7.0.0",
+ "vue": "^3.5.17"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.0",
+ "@types/node": "^20.0.0",
+ "nodemon": "^3.1.10",
+ "vue-tsc": "^3.0.1"
+ }
+}
\ No newline at end of file
diff --git a/admin/server.js b/admin/server.js
new file mode 100644
index 0000000..df7a0ab
--- /dev/null
+++ b/admin/server.js
@@ -0,0 +1,172 @@
+const express = require('express');
+const path = require('path');
+const dotenv = require('dotenv');
+
+// Load environment variables
+const ENV = process.env.NODE_ENV || 'development';
+dotenv.config({ path: `.env.${ENV}` });
+
+const app = express();
+const PORT = process.env.PORT || 3002;
+
+// Parse JSON bodies
+app.use(express.json());
+
+// Health check endpoint
+app.get('/health', (req, res) => {
+ console.log('que pedos');
+
+ res.json({
+ status: 'healthy',
+ service: 'snatchgame-admin',
+ environment: ENV,
+ serverUrl: process.env.SERVER_URL
+ });
+});
+
+// API endpoint to get environment config for client
+app.get('/api/config', (req, res) => {
+ res.json({
+ serverUrl: process.env.SERVER_URL,
+ environment: ENV
+ });
+});
+
+// SSE endpoint for real-time updates
+app.get('/api/sse', (req, res) => {
+ res.writeHead(200, {
+ 'Content-Type': 'text/event-stream',
+ 'Cache-Control': 'no-cache',
+ 'Connection': 'keep-alive',
+ 'Access-Control-Allow-Origin': '*',
+ 'Access-Control-Allow-Headers': 'Cache-Control'
+ });
+
+ // Send initial connection message
+ res.write('data: {"type": "connected", "message": "SSE connection established"}\n\n');
+
+ // Set up polling interval for game state updates
+ const pollInterval = setInterval(async () => {
+ try {
+ // Fetch game state from Colyseus server
+ const gameServerUrl = process.env.SERVER_URL || 'http://localhost:2567';
+ const response = await fetch(`${gameServerUrl}/api/admin/stats`);
+
+ if (response.ok) {
+ const gameStats = await response.json();
+ res.write(`data: ${JSON.stringify({
+ type: 'gameStats',
+ timestamp: new Date().toISOString(),
+ data: gameStats
+ })}\n\n`);
+ } else {
+ // Send error status if server is not reachable
+ res.write(`data: ${JSON.stringify({
+ type: 'error',
+ timestamp: new Date().toISOString(),
+ message: 'Cannot connect to game server'
+ })}\n\n`);
+ }
+ } catch (error) {
+ console.error('Error fetching game stats:', error);
+ res.write(`data: ${JSON.stringify({
+ type: 'error',
+ timestamp: new Date().toISOString(),
+ message: 'Error fetching game stats'
+ })}\n\n`);
+ }
+ }, 500); // Poll every 500ms
+
+ // Clean up on client disconnect
+ req.on('close', () => {
+ clearInterval(pollInterval);
+ });
+});
+
+// Admin control endpoints - proxy to Colyseus server
+
+// Kick player endpoint
+app.post('/api/admin/kick-player', async (req, res) => {
+ try {
+ const gameServerUrl = process.env.SERVER_URL || 'http://localhost:2567';
+ const response = await fetch(`${gameServerUrl}/api/admin/kick-player`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(req.body)
+ });
+
+ const result = await response.json();
+ res.json(result);
+ } catch (error) {
+ res.status(500).json({ success: false, message: 'Error communicating with game server' });
+ }
+});
+
+// Pause game endpoint
+app.post('/api/admin/pause-game', async (req, res) => {
+ try {
+ const gameServerUrl = process.env.SERVER_URL || 'http://localhost:2567';
+ const response = await fetch(`${gameServerUrl}/api/admin/pause-game`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(req.body)
+ });
+
+ const result = await response.json();
+ res.json(result);
+ } catch (error) {
+ res.status(500).json({ success: false, message: 'Error communicating with game server' });
+ }
+});
+
+// Resume game endpoint
+app.post('/api/admin/resume-game', async (req, res) => {
+ try {
+ const gameServerUrl = process.env.SERVER_URL || 'http://localhost:2567';
+ const response = await fetch(`${gameServerUrl}/api/admin/resume-game`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(req.body)
+ });
+
+ const result = await response.json();
+ res.json(result);
+ } catch (error) {
+ res.status(500).json({ success: false, message: 'Error communicating with game server' });
+ }
+});
+
+// Cancel game endpoint
+app.post('/api/admin/cancel-game', async (req, res) => {
+ try {
+ const gameServerUrl = process.env.SERVER_URL || 'http://localhost:2567';
+ const response = await fetch(`${gameServerUrl}/api/admin/cancel-game`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(req.body)
+ });
+
+ const result = await response.json();
+ res.json(result);
+ } catch (error) {
+ res.status(500).json({ success: false, message: 'Error communicating with game server' });
+ }
+});
+
+// Serve static files from current directory (AFTER API routes)
+app.use(express.static('.'));
+
+// Serve main HTML file for SPA routes
+app.get('*', (req, res) => {
+ res.sendFile(path.join(__dirname, 'index.html'));
+});
+
+app.listen(PORT, () => {
+ console.log(`
+📊 SnatchGame Admin Dashboard
+📱 Environment: ${ENV}
+🌐 Server URL: http://localhost:${PORT}
+🔗 Game Server: ${process.env.SERVER_URL}
+📡 SSE Endpoint: http://localhost:${PORT}/api/sse
+ `);
+});
\ No newline at end of file
diff --git a/admin/src/App.vue b/admin/src/App.vue
new file mode 100644
index 0000000..3c5b8fb
--- /dev/null
+++ b/admin/src/App.vue
@@ -0,0 +1,553 @@
+
+
+
+
+
+
+
+
+
👥 Jugadores Conectados
+
{{ gameStats.connectedPlayers || 0 }}
+
+
+
+
🎮 Partidas Activas
+
{{ gameStats.activeGames || 0 }}
+
+
+
+
🎯 Ronda Actual
+
{{ gameStats.currentRound || 'N/A' }}
+
+
+
+
📊 Estado del Juego
+
{{ getGameStateText(gameStats.gameState) }}
+
+
+
+
+
+
🎛️ Control del Juego
+
+
+ ⏮️ Retroceder Ronda
+
+
+ ⏭️ Avanzar Ronda
+
+
+ ⏸️ Pausar Juego
+
+
+ ▶️ Reanudar Juego
+
+
+ 🚫 Expulsar Jugador
+
+
+ 🚫🚫 Expulsar Jugadores
+
+
+
+
+
+
+
👥 Lista de Jugadores ({{ gameStats.players?.length || 0 }})
+
+
+
+
+
+
+ Sala: {{ player.roomId?.slice(-6) || 'N/A' }}
+ {{ getRoleText(player.role) }}
+ {{ getProducerText(player.producerRole) }}
+
+
+ 🦃 {{ player.tokens?.turkeys || 0 }}
+ ☕ {{ player.tokens?.coffee || 0 }}
+ 🌽 {{ player.tokens?.corn || 0 }}
+
+
+
+
+ 🚫 Expulsar
+
+
+
+
+
+ Sin jugadores conectados
+
+
+
+
+
+
+
🔧 Debug Info
+
+
Última actualización: {{ lastUpdate }}
+
Conexión SSE: {{ isConnected ? 'Activa' : 'Inactiva' }}
+
Servidor: {{ serverUrl }}
+
+
+ Ver datos completos
+ {{ JSON.stringify(gameStats, null, 2) }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/src/main.ts b/admin/src/main.ts
new file mode 100644
index 0000000..58cdcf4
--- /dev/null
+++ b/admin/src/main.ts
@@ -0,0 +1,4 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+
+createApp(App).mount('#app')
\ No newline at end of file
diff --git a/admin/src/services/adminService.ts b/admin/src/services/adminService.ts
new file mode 100644
index 0000000..6ab0ca7
--- /dev/null
+++ b/admin/src/services/adminService.ts
@@ -0,0 +1,149 @@
+interface AdminStats {
+ connectedPlayers: number
+ activeGames: number
+ currentRound: string
+ gameState: string
+ players?: Array<{
+ id: string
+ name: string
+ role: string
+ }>
+}
+
+interface AdminMessage {
+ type: 'connected' | 'gameStats' | 'error'
+ timestamp?: string
+ data?: AdminStats
+ message?: string
+}
+
+type AdminCallback = (data: AdminMessage) => void
+type ConnectionCallback = (connected: boolean) => void
+
+class AdminService {
+ private eventSource: EventSource | null = null
+ private callback: AdminCallback | null = null
+ private connectionCallback: ConnectionCallback | null = null
+ private isConnected = false
+ private serverUrl: string = 'http://localhost:2567' // Default to Colyseus server
+
+ connect(callback: AdminCallback): void {
+ this.callback = callback
+ this.eventSource = new EventSource('/api/sse')
+
+ this.eventSource.onopen = () => {
+ this.isConnected = true
+ this.connectionCallback?.(true)
+ }
+
+ this.eventSource.onmessage = (event) => {
+ try {
+ const data = JSON.parse(event.data)
+ this.callback?.(data)
+ } catch (error) {
+ console.error('Error parsing SSE message:', error)
+ }
+ }
+
+ this.eventSource.onerror = (error) => {
+ console.error('SSE connection error:', error)
+ this.isConnected = false
+ this.connectionCallback?.(false)
+ }
+ }
+
+ disconnect(): void {
+ if (this.eventSource) {
+ this.eventSource.close()
+ this.eventSource = null
+ }
+ this.isConnected = false
+ this.connectionCallback?.(false)
+ }
+
+ onConnectionChange(callback: ConnectionCallback): void {
+ this.connectionCallback = callback
+ }
+
+ // Admin control methods
+ async kickPlayer(playerId: string): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/kick-player`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ playerId })
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to kick player')
+ }
+ }
+
+ async pauseGame(): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/pause-game`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to pause game')
+ }
+ }
+
+ async resumeGame(): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/resume-game`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to resume game')
+ }
+ }
+
+ async cancelGame(gameId: string): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/cancel-game`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ gameId })
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to cancel game')
+ }
+ }
+
+ async kickAllPlayers(): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/kick-all-players`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to kick all players')
+ }
+ }
+
+ async advanceRound(): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/advance-round`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to advance round')
+ }
+ }
+
+ async previousRound(): Promise {
+ const response = await fetch(`${this.serverUrl}/api/admin/previous-round`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ })
+
+ if (!response.ok) {
+ throw new Error('Failed to go back round')
+ }
+ }
+}
+
+export const adminService = new AdminService()
\ No newline at end of file
diff --git a/admin/src/types/TokenInventory.ts b/admin/src/types/TokenInventory.ts
new file mode 100644
index 0000000..edbc89d
--- /dev/null
+++ b/admin/src/types/TokenInventory.ts
@@ -0,0 +1,15 @@
+//
+// THIS FILE HAS BEEN GENERATED AUTOMATICALLY
+// DO NOT CHANGE IT MANUALLY UNLESS YOU KNOW WHAT YOU'RE DOING
+//
+// GENERATED USING @colyseus/schema 3.0.42
+//
+
+import { Schema, type, ArraySchema, MapSchema, SetSchema, DataChange } from '@colyseus/schema';
+
+
+export class TokenInventory extends Schema {
+ @type("number") public turkey!: number;
+ @type("number") public coffee!: number;
+ @type("number") public corn!: number;
+}
diff --git a/admin/src/types/TradeOffer.ts b/admin/src/types/TradeOffer.ts
new file mode 100644
index 0000000..2bfcab7
--- /dev/null
+++ b/admin/src/types/TradeOffer.ts
@@ -0,0 +1,18 @@
+//
+// THIS FILE HAS BEEN GENERATED AUTOMATICALLY
+// DO NOT CHANGE IT MANUALLY UNLESS YOU KNOW WHAT YOU'RE DOING
+//
+// GENERATED USING @colyseus/schema 3.0.42
+//
+
+import { Schema, type, ArraySchema, MapSchema, SetSchema, DataChange } from '@colyseus/schema';
+import { TokenInventory } from './TokenInventory'
+
+export class TradeOffer extends Schema {
+ @type("string") public id!: string;
+ @type("string") public offererId!: string;
+ @type("string") public targetId!: string;
+ @type(TokenInventory) public offering: TokenInventory = new TokenInventory();
+ @type(TokenInventory) public requesting: TokenInventory = new TokenInventory();
+ @type("string") public status!: string;
+}
diff --git a/admin/src/types/index.ts b/admin/src/types/index.ts
new file mode 100644
index 0000000..ea08175
--- /dev/null
+++ b/admin/src/types/index.ts
@@ -0,0 +1,30 @@
+// Admin-specific types
+export interface AdminStats {
+ connectedPlayers: number
+ activeGames: number
+ currentRound: string
+ gameState: string
+ players?: AdminPlayer[]
+}
+
+export interface AdminPlayer {
+ id: string
+ name: string
+ role: string
+ roomId?: string
+}
+
+export interface AdminMessage {
+ type: 'connected' | 'gameStats' | 'error'
+ timestamp?: string
+ data?: AdminStats
+ message?: string
+}
+
+export interface AdminConfig {
+ serverUrl: string
+ environment: string
+}
+
+// Game-related types will be auto-generated from server using schema-codegen
+// Run: npm run generate-types
\ No newline at end of file
diff --git a/admin/tsconfig.json b/admin/tsconfig.json
new file mode 100644
index 0000000..57382e0
--- /dev/null
+++ b/admin/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": "@vue/tsconfig/tsconfig.dom.json",
+ "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
+ "exclude": ["src/**/__tests__/*"],
+ "compilerOptions": {
+ "composite": true,
+ "baseUrl": ".",
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true,
+ "verbatimModuleSyntax": false,
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ }
+}
\ No newline at end of file
diff --git a/admin/vite.config.ts b/admin/vite.config.ts
new file mode 100644
index 0000000..808c551
--- /dev/null
+++ b/admin/vite.config.ts
@@ -0,0 +1,28 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+ plugins: [vue()],
+ server: {
+ port: 3001,
+ host: true,
+ proxy: {
+ '/health': {
+ target: 'http://localhost:3002',
+ changeOrigin: true
+ },
+ '/api': {
+ target: 'http://localhost:3002',
+ changeOrigin: true
+ }
+ }
+ },
+ build: {
+ outDir: 'dist'
+ },
+ resolve: {
+ alias: {
+ '@': '/src'
+ }
+ }
+})
\ No newline at end of file
diff --git a/client/package.json b/client/package.json
index 4b79cba..ce57c72 100644
--- a/client/package.json
+++ b/client/package.json
@@ -1,6 +1,6 @@
{
"name": "snatchgame-client",
- "version": "0.0.5-alpha",
+ "version": "0.0.8-alpha",
"description": "SnatchGame client UI server",
"main": "server.js",
"scripts": {
diff --git a/client/src/App.vue b/client/src/App.vue
index 7d104d7..ba952de 100644
--- a/client/src/App.vue
+++ b/client/src/App.vue
@@ -28,6 +28,26 @@ const onJoinGame = (client: any) => {
gameClient.value = client
currentScreen.value = 'game'
logger.info('Transitioning to game screen')
+
+ // Handle admin kick notification
+ client.onAdminKicked((data: any) => {
+ // Show alert message
+ alert(`🚫 ${data.message}`)
+
+ // Return to home screen
+ currentScreen.value = 'home'
+ gameClient.value = null
+
+ logger.info('Player kicked by admin, returned to home screen')
+ })
+
+ // Handle round change notification
+ client.onRoundChanged((data: any) => {
+ // Show alert message
+ alert(`🎯 ${data.message}`)
+
+ logger.info('Round changed by admin:', data)
+ })
}
diff --git a/client/src/services/gameClient.ts b/client/src/services/gameClient.ts
index 9efbb42..76ab22e 100644
--- a/client/src/services/gameClient.ts
+++ b/client/src/services/gameClient.ts
@@ -15,6 +15,8 @@ export class GameClient {
// Event callbacks
private onStateChangeCallbacks: ((state: GameState) => void)[] = []
private onGamePhaseChangeCallbacks: ((phase: string) => void)[] = []
+ private onAdminKickedCallbacks: ((data: any) => void)[] = []
+ private onRoundChangedCallbacks: ((data: any) => void)[] = []
constructor() {
const serverUrl = import.meta.env.VITE_SERVER_URL || 'ws://localhost:2567'
@@ -61,12 +63,38 @@ export class GameClient {
this.room.onLeave((code) => {
logger.info('Left room with code:', code)
this.isConnected = false
+
+ // Handle forced disconnect by admin
+ if (code === 4000) {
+ logger.info('Disconnected by admin (code 4000)')
+ }
})
this.room.onError((code, message) => {
logger.error('Room error:', { code, message })
})
+ // Handle admin kick message
+ this.room.onMessage("adminKicked", (data) => {
+ logger.info('Received admin kick message:', data)
+ this.onAdminKickedCallbacks.forEach(callback => callback(data))
+ })
+
+ // Handle game pause/resume messages
+ this.room.onMessage("gamePaused", (data) => {
+ logger.info('Game paused by admin:', data)
+ })
+
+ this.room.onMessage("gameResumed", (data) => {
+ logger.info('Game resumed by admin:', data)
+ })
+
+ // Handle round change messages
+ this.room.onMessage("roundChanged", (data) => {
+ logger.info('Round changed by admin:', data)
+ this.onRoundChangedCallbacks.forEach(callback => callback(data))
+ })
+
return this.room
} catch (error) {
logger.error('Failed to join room:', error)
@@ -122,6 +150,30 @@ export class GameClient {
}
}
+ onAdminKicked(callback: (data: any) => void): () => void {
+ this.onAdminKickedCallbacks.push(callback)
+
+ // Return unsubscribe function
+ return () => {
+ const index = this.onAdminKickedCallbacks.indexOf(callback)
+ if (index > -1) {
+ this.onAdminKickedCallbacks.splice(index, 1)
+ }
+ }
+ }
+
+ onRoundChanged(callback: (data: any) => void): () => void {
+ this.onRoundChangedCallbacks.push(callback)
+
+ // Return unsubscribe function
+ return () => {
+ const index = this.onRoundChangedCallbacks.indexOf(callback)
+ if (index > -1) {
+ this.onRoundChangedCallbacks.splice(index, 1)
+ }
+ }
+ }
+
// Game actions
sendClick(): void {
if (this.room && this.gameState?.gamePhase === 'playing') {
diff --git a/package-lock.json b/package-lock.json
index 07c94d1..2ecda2f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
},
"client": {
"name": "snatchgame-client",
- "version": "0.0.1-alpha",
+ "version": "0.0.5-alpha",
"license": "ISC",
"dependencies": {
"@vitejs/plugin-vue": "^6.0.0",
@@ -86,21 +86,6 @@
"node": ">=10"
}
},
- "client/node_modules/@colyseus/msgpackr": {
- "version": "1.11.2",
- "license": "MIT",
- "optionalDependencies": {
- "msgpackr-extract": "^3.0.2"
- }
- },
- "client/node_modules/@colyseus/schema": {
- "version": "3.0.42",
- "license": "MIT",
- "bin": {
- "schema-codegen": "bin/schema-codegen",
- "schema-debug": "bin/schema-debug"
- }
- },
"client/node_modules/@esbuild/linux-x64": {
"version": "0.25.5",
"cpu": [
@@ -138,17 +123,6 @@
"version": "1.5.4",
"license": "MIT"
},
- "client/node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
- "version": "3.0.3",
- "cpu": [
- "x64"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
"client/node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.19",
"license": "MIT"
@@ -536,38 +510,6 @@
"node": ">=8"
}
},
- "client/node_modules/bytes": {
- "version": "3.1.2",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "client/node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "client/node_modules/call-bound": {
- "version": "1.0.4",
- "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"
- }
- },
"client/node_modules/chokidar": {
"version": "3.6.0",
"dev": true,
@@ -623,13 +565,6 @@
"node": ">= 0.6"
}
},
- "client/node_modules/content-type": {
- "version": "1.0.5",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"client/node_modules/cookie": {
"version": "0.7.1",
"license": "MIT",
@@ -657,13 +592,6 @@
"ms": "2.0.0"
}
},
- "client/node_modules/depd": {
- "version": "2.0.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"client/node_modules/destroy": {
"version": "1.2.0",
"license": "MIT",
@@ -672,14 +600,6 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
- "client/node_modules/detect-libc": {
- "version": "2.0.4",
- "license": "Apache-2.0",
- "optional": true,
- "engines": {
- "node": ">=8"
- }
- },
"client/node_modules/dotenv": {
"version": "16.6.1",
"license": "BSD-2-Clause",
@@ -690,29 +610,6 @@
"url": "https://dotenvx.com"
}
},
- "client/node_modules/dunder-proto": {
- "version": "1.0.1",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "client/node_modules/ee-first": {
- "version": "1.1.1",
- "license": "MIT"
- },
- "client/node_modules/encodeurl": {
- "version": "2.0.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"client/node_modules/entities": {
"version": "4.5.0",
"license": "BSD-2-Clause",
@@ -723,30 +620,6 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
- "client/node_modules/es-define-property": {
- "version": "1.0.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "client/node_modules/es-errors": {
- "version": "1.3.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "client/node_modules/es-object-atoms": {
- "version": "1.1.1",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"client/node_modules/esbuild": {
"version": "0.25.5",
"hasInstallScript": true,
@@ -785,21 +658,10 @@
"@esbuild/win32-x64": "0.25.5"
}
},
- "client/node_modules/escape-html": {
- "version": "1.0.3",
- "license": "MIT"
- },
"client/node_modules/estree-walker": {
"version": "2.0.2",
"license": "MIT"
},
- "client/node_modules/etag": {
- "version": "1.8.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"client/node_modules/express": {
"version": "4.21.2",
"license": "MIT",
@@ -871,13 +733,6 @@
"node": ">= 0.8"
}
},
- "client/node_modules/forwarded": {
- "version": "0.2.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"client/node_modules/fresh": {
"version": "0.5.2",
"license": "MIT",
@@ -885,46 +740,6 @@
"node": ">= 0.6"
}
},
- "client/node_modules/function-bind": {
- "version": "1.1.2",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "client/node_modules/get-intrinsic": {
- "version": "1.3.0",
- "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"
- }
- },
- "client/node_modules/get-proto": {
- "version": "1.0.1",
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"client/node_modules/glob-parent": {
"version": "5.1.2",
"dev": true,
@@ -936,16 +751,6 @@
"node": ">= 6"
}
},
- "client/node_modules/gopd": {
- "version": "1.2.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"client/node_modules/has-flag": {
"version": "3.0.0",
"dev": true,
@@ -954,26 +759,6 @@
"node": ">=4"
}
},
- "client/node_modules/has-symbols": {
- "version": "1.1.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "client/node_modules/hasown": {
- "version": "2.0.2",
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"client/node_modules/he": {
"version": "1.2.0",
"dev": true,
@@ -982,20 +767,6 @@
"he": "bin/he"
}
},
- "client/node_modules/http-errors": {
- "version": "2.0.0",
- "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"
- }
- },
"client/node_modules/iconv-lite": {
"version": "0.4.24",
"license": "MIT",
@@ -1011,17 +782,6 @@
"dev": true,
"license": "ISC"
},
- "client/node_modules/inherits": {
- "version": "2.0.4",
- "license": "ISC"
- },
- "client/node_modules/ipaddr.js": {
- "version": "1.9.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.10"
- }
- },
"client/node_modules/is-binary-path": {
"version": "2.1.0",
"dev": true,
@@ -1067,13 +827,6 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
- "client/node_modules/math-intrinsics": {
- "version": "1.1.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
"client/node_modules/media-typer": {
"version": "0.3.0",
"license": "MIT",
@@ -1137,26 +890,6 @@
"version": "2.0.0",
"license": "MIT"
},
- "client/node_modules/msgpackr-extract": {
- "version": "3.0.3",
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "node-gyp-build-optional-packages": "5.2.2"
- },
- "bin": {
- "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
- },
- "optionalDependencies": {
- "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
- }
- },
"client/node_modules/muggle-string": {
"version": "0.4.1",
"dev": true,
@@ -1185,19 +918,6 @@
"node": ">= 0.6"
}
},
- "client/node_modules/node-gyp-build-optional-packages": {
- "version": "5.2.2",
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "detect-libc": "^2.0.1"
- },
- "bin": {
- "node-gyp-build-optional-packages": "bin.js",
- "node-gyp-build-optional-packages-optional": "optional.js",
- "node-gyp-build-optional-packages-test": "build-test.js"
- }
- },
"client/node_modules/nodemon": {
"version": "3.1.10",
"dev": true,
@@ -1254,33 +974,6 @@
"node": ">=0.10.0"
}
},
- "client/node_modules/object-inspect": {
- "version": "1.13.4",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "client/node_modules/on-finished": {
- "version": "2.4.1",
- "license": "MIT",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "client/node_modules/parseurl": {
- "version": "1.3.3",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"client/node_modules/path-browserify": {
"version": "1.0.1",
"dev": true,
@@ -1331,17 +1024,6 @@
"node": "^10 || ^12 || >=14"
}
},
- "client/node_modules/proxy-addr": {
- "version": "2.0.7",
- "license": "MIT",
- "dependencies": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
"client/node_modules/pstree.remy": {
"version": "1.1.8",
"dev": true,
@@ -1360,13 +1042,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "client/node_modules/range-parser": {
- "version": "1.2.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"client/node_modules/raw-body": {
"version": "2.5.2",
"license": "MIT",
@@ -1428,28 +1103,6 @@
"fsevents": "~2.3.2"
}
},
- "client/node_modules/safe-buffer": {
- "version": "5.2.1",
- "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"
- },
- "client/node_modules/safer-buffer": {
- "version": "2.1.2",
- "license": "MIT"
- },
"client/node_modules/semver": {
"version": "7.7.2",
"dev": true,
@@ -1507,74 +1160,6 @@
"node": ">= 0.8.0"
}
},
- "client/node_modules/setprototypeof": {
- "version": "1.2.0",
- "license": "ISC"
- },
- "client/node_modules/side-channel": {
- "version": "1.1.0",
- "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"
- }
- },
- "client/node_modules/side-channel-list": {
- "version": "1.0.0",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "client/node_modules/side-channel-map": {
- "version": "1.0.1",
- "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"
- }
- },
- "client/node_modules/side-channel-weakmap": {
- "version": "1.0.2",
- "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"
- }
- },
"client/node_modules/simple-update-notifier": {
"version": "2.0.0",
"dev": true,
@@ -1658,13 +1243,6 @@
"node": ">=8.0"
}
},
- "client/node_modules/toidentifier": {
- "version": "1.0.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.6"
- }
- },
"client/node_modules/touch": {
"version": "3.1.1",
"dev": true,
@@ -1684,17 +1262,6 @@
"node": ">= 0.6"
}
},
- "client/node_modules/typescript": {
- "version": "5.8.3",
- "license": "Apache-2.0",
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
"client/node_modules/undefsafe": {
"version": "2.0.5",
"dev": true,
@@ -1705,13 +1272,6 @@
"devOptional": true,
"license": "MIT"
},
- "client/node_modules/unpipe": {
- "version": "1.0.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"client/node_modules/utils-merge": {
"version": "1.0.1",
"license": "MIT",
@@ -1719,13 +1279,6 @@
"node": ">= 0.4.0"
}
},
- "client/node_modules/vary": {
- "version": "1.1.2",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"client/node_modules/vite": {
"version": "7.0.0",
"license": "MIT",
@@ -1888,6 +1441,169 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@colyseus/clock": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@colyseus/clock/-/clock-1.0.0.tgz",
+ "integrity": "sha512-x1un5rFEgilVAA6ukSG8GFgtpX/hsmL5BtrPdxLx0dbPU7zwpTVXez2qoGza7YYS5QTvVD45gbHyX/KaaEWSZQ==",
+ "license": "MIT"
+ },
+ "node_modules/@colyseus/core": {
+ "version": "0.16.19",
+ "resolved": "https://registry.npmjs.org/@colyseus/core/-/core-0.16.19.tgz",
+ "integrity": "sha512-s6PQEED3jjTjnRQsGMSDolbddn5ZdLuuwJElMdTQZwFKfn3vlf4AlpkK5j+c87CaVuUQQ6YvcDnBx9soVIvM0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@colyseus/greeting-banner": "^2.0.6",
+ "@colyseus/msgpackr": "^1.11.2",
+ "@colyseus/timer": "^1.0.1",
+ "debug": "^4.3.4",
+ "nanoid": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 18.x"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/endel"
+ },
+ "peerDependencies": {
+ "@colyseus/schema": "^3.0.0"
+ }
+ },
+ "node_modules/@colyseus/greeting-banner": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@colyseus/greeting-banner/-/greeting-banner-2.0.6.tgz",
+ "integrity": "sha512-65nK7KnJn6g3ArtJqNfVX+Mx7xTlBka04kSwloLP7s24UpCEaK7bMGRLgkzfnysARzlVh1eV4jynBWZN82dYwQ==",
+ "license": "MIT"
+ },
+ "node_modules/@colyseus/monitor": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@colyseus/monitor/-/monitor-0.16.7.tgz",
+ "integrity": "sha512-kkSsEmD38/Rcgy/599Kw1QWfxIwiAdGPHQRfzZF0nsUxWLTNHGfypeEJUeajrnoyYxJFZdKwIma0SSzxmLDCig==",
+ "license": "MIT",
+ "dependencies": {
+ "express": ">=4.16.0",
+ "node-os-utils": "^1.2.0"
+ }
+ },
+ "node_modules/@colyseus/msgpackr": {
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/@colyseus/msgpackr/-/msgpackr-1.11.2.tgz",
+ "integrity": "sha512-MuwPFhizFKC3zmGfy0fpo+kcnZdNdnQHFVjw81v4WXHCelDeCX8yNRVtuEm8kGlHqq7qiASLC0pu0RPqYOhxXg==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "msgpackr-extract": "^3.0.2"
+ }
+ },
+ "node_modules/@colyseus/schema": {
+ "version": "3.0.42",
+ "resolved": "https://registry.npmjs.org/@colyseus/schema/-/schema-3.0.42.tgz",
+ "integrity": "sha512-MNy8wYgvzwPhWWxKXlBqq4cW2iOAx0gMwLdXwy4UYk3oN5AUkHSchPEmo5TeSUlNcvtch/odYIfSMtYlOPO8Aw==",
+ "license": "MIT",
+ "bin": {
+ "schema-codegen": "bin/schema-codegen",
+ "schema-debug": "bin/schema-debug"
+ }
+ },
+ "node_modules/@colyseus/timer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@colyseus/timer/-/timer-1.0.1.tgz",
+ "integrity": "sha512-zsbmytTaSfqOYlnw0PXQCgwumXjn8eM/HMyMTVGjXlczsJ8DFl5OHaWAsJz7kIn92NTAONoIwLTwyVRvpJCVzA==",
+ "license": "MIT",
+ "dependencies": {
+ "@colyseus/clock": "^1.0.0"
+ }
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
+ "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
+ "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
+ "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
+ "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
+ "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
+ "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -1914,6 +1630,64 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "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/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2007,6 +1781,45 @@
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
}
},
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "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": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
"node_modules/date-fns": {
"version": "2.30.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
@@ -2024,6 +1837,62 @@
"url": "https://opencollective.com/date-fns"
}
},
+ "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/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/detect-libc": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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/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/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -2031,6 +1900,45 @@
"dev": true,
"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/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -2041,6 +1949,107 @@
"node": ">=6"
}
},
+ "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/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": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -2051,6 +2060,55 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "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/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/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -2061,6 +2119,82 @@
"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/http-errors/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/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -2071,12 +2205,236 @@
"node": ">=8"
}
},
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"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": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "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/msgpackr-extract": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
+ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "node-gyp-build-optional-packages": "5.2.2"
+ },
+ "bin": {
+ "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+ },
+ "optionalDependencies": {
+ "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz",
+ "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-gyp-build-optional-packages": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
+ "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^2.0.1"
+ },
+ "bin": {
+ "node-gyp-build-optional-packages": "bin.js",
+ "node-gyp-build-optional-packages-optional": "optional.js",
+ "node-gyp-build-optional-packages-test": "build-test.js"
+ }
+ },
+ "node_modules/node-os-utils": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/node-os-utils/-/node-os-utils-1.3.7.tgz",
+ "integrity": "sha512-fvnX9tZbR7WfCG5BAy3yO/nCLyjVWD6MghEq0z5FDfN+ZXpLWNITBdbifxQkQ25ebr16G0N7eRWJisOcMEHG3Q==",
+ "license": "MIT"
+ },
+ "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==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "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-to-regexp": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
+ "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "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/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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": "3.0.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
+ "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.6.3",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -2087,6 +2445,22 @@
"node": ">=0.10.0"
}
},
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
@@ -2097,6 +2471,75 @@
"tslib": "^2.1.0"
}
},
+ "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/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "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/shell-quote": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
@@ -2110,6 +2553,78 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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/snatchgame-client": {
"resolved": "client",
"link": true
@@ -2124,6 +2639,15 @@
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
"dev": true
},
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -2168,6 +2692,15 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "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/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
@@ -2184,6 +2717,51 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "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/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/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -2202,6 +2780,12 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "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==",
+ "license": "ISC"
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -2243,9 +2827,11 @@
},
"server": {
"name": "snatchgame-server",
- "version": "0.0.1-alpha",
+ "version": "0.0.5-alpha",
"license": "ISC",
"dependencies": {
+ "@colyseus/core": "^0.16.19",
+ "@colyseus/monitor": "^0.16.7",
"@colyseus/schema": "^3.0.42",
"@colyseus/tools": "^0.16.0",
"colyseus": "^0.16.0",
@@ -2256,7 +2842,7 @@
"@types/node": "^20.0.0",
"nodemon": "^3.1.10",
"ts-node-dev": "^2.0.0",
- "typescript": "^5.0.0"
+ "typescript": "^5.8.3"
}
},
"server/node_modules/@colyseus/auth": {
@@ -2282,45 +2868,6 @@
"express": ">=4.16.0"
}
},
- "server/node_modules/@colyseus/clock": {
- "version": "1.0.0",
- "license": "MIT",
- "peer": true
- },
- "server/node_modules/@colyseus/core": {
- "version": "0.16.19",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@colyseus/greeting-banner": "^2.0.6",
- "@colyseus/msgpackr": "^1.11.2",
- "@colyseus/timer": "^1.0.1",
- "debug": "^4.3.4",
- "nanoid": "^2.0.0"
- },
- "engines": {
- "node": ">= 18.x"
- },
- "funding": {
- "url": "https://github.com/sponsors/endel"
- },
- "peerDependencies": {
- "@colyseus/schema": "^3.0.0"
- }
- },
- "server/node_modules/@colyseus/greeting-banner": {
- "version": "2.0.6",
- "license": "MIT",
- "peer": true
- },
- "server/node_modules/@colyseus/msgpackr": {
- "version": "1.11.2",
- "license": "MIT",
- "peer": true,
- "optionalDependencies": {
- "msgpackr-extract": "^3.0.2"
- }
- },
"server/node_modules/@colyseus/redis-driver": {
"version": "0.16.1",
"license": "MIT",
@@ -2339,22 +2886,6 @@
"ioredis": "^5.3.2"
}
},
- "server/node_modules/@colyseus/schema": {
- "version": "3.0.42",
- "license": "MIT",
- "bin": {
- "schema-codegen": "bin/schema-codegen",
- "schema-debug": "bin/schema-debug"
- }
- },
- "server/node_modules/@colyseus/timer": {
- "version": "1.0.1",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@colyseus/clock": "^1.0.0"
- }
- },
"server/node_modules/@colyseus/tools": {
"version": "0.16.12",
"license": "MIT",
@@ -2436,18 +2967,6 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
- "server/node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
- "version": "3.0.3",
- "cpu": [
- "x64"
- ],
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true
- },
"server/node_modules/@pm2/io": {
"version": "6.1.0",
"license": "Apache-2",
@@ -2781,38 +3300,6 @@
"dev": true,
"license": "MIT"
},
- "server/node_modules/bytes": {
- "version": "3.1.2",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "server/node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "server/node_modules/call-bound": {
- "version": "1.0.4",
- "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"
- }
- },
"server/node_modules/chokidar": {
"version": "3.6.0",
"dev": true,
@@ -2886,13 +3373,6 @@
"node": ">= 0.6"
}
},
- "server/node_modules/content-type": {
- "version": "1.0.5",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"server/node_modules/cookie": {
"version": "0.7.1",
"license": "MIT",
@@ -2920,21 +3400,6 @@
"dev": true,
"license": "MIT"
},
- "server/node_modules/debug": {
- "version": "4.4.1",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
"server/node_modules/denque": {
"version": "2.1.0",
"license": "Apache-2.0",
@@ -2943,13 +3408,6 @@
"node": ">=0.10"
}
},
- "server/node_modules/depd": {
- "version": "2.0.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"server/node_modules/destroy": {
"version": "1.2.0",
"license": "MIT",
@@ -2958,15 +3416,6 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
- "server/node_modules/detect-libc": {
- "version": "2.0.4",
- "license": "Apache-2.0",
- "optional": true,
- "peer": true,
- "engines": {
- "node": ">=8"
- }
- },
"server/node_modules/diff": {
"version": "4.0.2",
"dev": true,
@@ -2982,18 +3431,6 @@
"node": ">=10"
}
},
- "server/node_modules/dunder-proto": {
- "version": "1.0.1",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"server/node_modules/dynamic-dedupe": {
"version": "0.3.0",
"dev": true,
@@ -3010,10 +3447,6 @@
"safe-buffer": "^5.0.1"
}
},
- "server/node_modules/ee-first": {
- "version": "1.1.1",
- "license": "MIT"
- },
"server/node_modules/elliptic": {
"version": "6.6.1",
"license": "MIT",
@@ -3029,48 +3462,6 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
- "server/node_modules/encodeurl": {
- "version": "2.0.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "server/node_modules/es-define-property": {
- "version": "1.0.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "server/node_modules/es-errors": {
- "version": "1.3.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "server/node_modules/es-object-atoms": {
- "version": "1.1.1",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "server/node_modules/escape-html": {
- "version": "1.0.3",
- "license": "MIT"
- },
- "server/node_modules/etag": {
- "version": "1.8.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"server/node_modules/eventemitter2": {
"version": "6.4.9",
"license": "MIT"
@@ -3230,13 +3621,6 @@
"version": "2.0.0",
"license": "MIT"
},
- "server/node_modules/forwarded": {
- "version": "0.2.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"server/node_modules/fresh": {
"version": "0.5.2",
"license": "MIT",
@@ -3249,46 +3633,6 @@
"dev": true,
"license": "ISC"
},
- "server/node_modules/function-bind": {
- "version": "1.1.2",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "server/node_modules/get-intrinsic": {
- "version": "1.3.0",
- "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"
- }
- },
- "server/node_modules/get-proto": {
- "version": "1.0.1",
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"server/node_modules/glob": {
"version": "7.2.3",
"dev": true,
@@ -3319,16 +3663,6 @@
"node": ">= 6"
}
},
- "server/node_modules/gopd": {
- "version": "1.2.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"server/node_modules/grant": {
"version": "5.4.24",
"license": "MIT",
@@ -3388,16 +3722,6 @@
"node": ">=4"
}
},
- "server/node_modules/has-symbols": {
- "version": "1.1.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"server/node_modules/hash.js": {
"version": "1.1.7",
"license": "MIT",
@@ -3408,16 +3732,6 @@
"minimalistic-assert": "^1.0.1"
}
},
- "server/node_modules/hasown": {
- "version": "2.0.2",
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"server/node_modules/hmac-drbg": {
"version": "1.0.1",
"license": "MIT",
@@ -3429,20 +3743,6 @@
"minimalistic-crypto-utils": "^1.0.1"
}
},
- "server/node_modules/http-errors": {
- "version": "2.0.0",
- "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"
- }
- },
"server/node_modules/http-status-codes": {
"version": "2.3.0",
"license": "MIT",
@@ -3472,10 +3772,6 @@
"wrappy": "1"
}
},
- "server/node_modules/inherits": {
- "version": "2.0.4",
- "license": "ISC"
- },
"server/node_modules/ioredis": {
"version": "5.6.1",
"license": "MIT",
@@ -3499,13 +3795,6 @@
"url": "https://opencollective.com/ioredis"
}
},
- "server/node_modules/ipaddr.js": {
- "version": "1.9.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.10"
- }
- },
"server/node_modules/is-binary-path": {
"version": "2.1.0",
"dev": true,
@@ -3689,13 +3978,6 @@
"dev": true,
"license": "ISC"
},
- "server/node_modules/math-intrinsics": {
- "version": "1.1.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
"server/node_modules/media-typer": {
"version": "0.3.0",
"license": "MIT",
@@ -3790,36 +4072,6 @@
"version": "1.0.4",
"license": "MIT"
},
- "server/node_modules/ms": {
- "version": "2.1.3",
- "license": "MIT"
- },
- "server/node_modules/msgpackr-extract": {
- "version": "3.0.3",
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "node-gyp-build-optional-packages": "5.2.2"
- },
- "bin": {
- "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
- },
- "optionalDependencies": {
- "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
- "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
- }
- },
- "server/node_modules/nanoid": {
- "version": "2.1.11",
- "license": "MIT",
- "peer": true
- },
"server/node_modules/negotiator": {
"version": "0.6.3",
"license": "MIT",
@@ -3827,20 +4079,6 @@
"node": ">= 0.6"
}
},
- "server/node_modules/node-gyp-build-optional-packages": {
- "version": "5.2.2",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "detect-libc": "^2.0.1"
- },
- "bin": {
- "node-gyp-build-optional-packages": "bin.js",
- "node-gyp-build-optional-packages-optional": "optional.js",
- "node-gyp-build-optional-packages-test": "build-test.js"
- }
- },
"server/node_modules/nodemon": {
"version": "3.1.10",
"dev": true,
@@ -3891,26 +4129,6 @@
"node": ">=0.10.0"
}
},
- "server/node_modules/object-inspect": {
- "version": "1.13.4",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "server/node_modules/on-finished": {
- "version": "2.4.1",
- "license": "MIT",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
"server/node_modules/on-headers": {
"version": "1.0.2",
"license": "MIT",
@@ -3919,21 +4137,6 @@
"node": ">= 0.8"
}
},
- "server/node_modules/once": {
- "version": "1.4.0",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "server/node_modules/parseurl": {
- "version": "1.3.3",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"server/node_modules/path-is-absolute": {
"version": "1.0.1",
"dev": true,
@@ -3961,17 +4164,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "server/node_modules/proxy-addr": {
- "version": "2.0.7",
- "license": "MIT",
- "dependencies": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
"server/node_modules/pstree.remy": {
"version": "1.1.8",
"dev": true,
@@ -3998,13 +4190,6 @@
"node": ">= 0.8"
}
},
- "server/node_modules/range-parser": {
- "version": "1.2.1",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
"server/node_modules/raw-body": {
"version": "2.5.2",
"license": "MIT",
@@ -4110,28 +4295,6 @@
"rimraf": "bin.js"
}
},
- "server/node_modules/safe-buffer": {
- "version": "5.2.1",
- "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"
- },
- "server/node_modules/safer-buffer": {
- "version": "2.1.2",
- "license": "MIT"
- },
"server/node_modules/semver": {
"version": "7.5.4",
"license": "ISC",
@@ -4198,78 +4361,10 @@
"node": ">= 0.8.0"
}
},
- "server/node_modules/setprototypeof": {
- "version": "1.2.0",
- "license": "ISC"
- },
"server/node_modules/shimmer": {
"version": "1.2.1",
"license": "BSD-2-Clause"
},
- "server/node_modules/side-channel": {
- "version": "1.1.0",
- "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"
- }
- },
- "server/node_modules/side-channel-list": {
- "version": "1.0.0",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "server/node_modules/side-channel-map": {
- "version": "1.0.1",
- "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"
- }
- },
- "server/node_modules/side-channel-weakmap": {
- "version": "1.0.2",
- "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"
- }
- },
"server/node_modules/signal-exit": {
"version": "3.0.7",
"license": "ISC"
@@ -4362,13 +4457,6 @@
"node": ">=8.0"
}
},
- "server/node_modules/toidentifier": {
- "version": "1.0.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.6"
- }
- },
"server/node_modules/touch": {
"version": "3.1.1",
"dev": true,
@@ -4478,18 +4566,6 @@
"node": ">= 0.6"
}
},
- "server/node_modules/typescript": {
- "version": "5.8.3",
- "dev": true,
- "license": "Apache-2.0",
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
"server/node_modules/uid-safe": {
"version": "2.1.5",
"license": "MIT",
@@ -4510,13 +4586,6 @@
"version": "6.21.0",
"license": "MIT"
},
- "server/node_modules/unpipe": {
- "version": "1.0.0",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
"server/node_modules/utils-merge": {
"version": "1.0.1",
"license": "MIT",
@@ -4564,18 +4633,6 @@
"dev": true,
"license": "MIT"
},
- "server/node_modules/vary": {
- "version": "1.1.2",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "server/node_modules/wrappy": {
- "version": "1.0.2",
- "dev": true,
- "license": "ISC"
- },
"server/node_modules/ws": {
"version": "8.18.3",
"license": "MIT",
diff --git a/package.json b/package.json
index 5daae23..00a000d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "snatchgame",
- "version": "0.0.1-alpha",
+ "version": "0.0.8-alpha",
"description": "Multiplayer real-time click battle game built with Colyseus.io and Vue 3",
"private": true,
"scripts": {
diff --git a/server/.devmode.json b/server/.devmode.json
index d7b4ec2..294db68 100644
--- a/server/.devmode.json
+++ b/server/.devmode.json
@@ -1 +1 @@
-{"data":{"colyseus:nodes":[],"l:game:gameMode:classic":["iys_3ih45","wnh3Dc813","x_N2KoM0r","ZYjw9gCJY"]},"hash":{"roomcount":{},"roomhistory":{"iys_3ih45":"{\"clientOptions\":{\"playerName\":\"Jugador Test\",\"gameMode\":\"classic\"},\"roomName\":\"game\",\"processId\":\"xX4LpKzp8\"}"},"ch:game":{"gameMode:classic":"0"}},"keys":{}}
\ No newline at end of file
+{"data":{"colyseus:nodes":[],"l:game:gameMode:classic":["orqtACqT1","CXsliCwrI","C9VtR3g7Y","5NLMNLp3K","E4GQ95vBo","B8gUy5Ru2","EsWHo9NKW","FfK7pxOt6","clgTgsAZH","O58m3Nc96","07HzAIKHi","-MIdmG17D","SYCmeWB4a","bH9pgtu9q","wOWYHPF2g","lT5vitAWz","DxP0OlLZy","HxsfS-rHq","xoXuKLe8y","Pdth85aBY","OIfp4Z9v1","1stjMQLZG","-oVixmPUu","mGyUM4X_N","Dr2CbrciW","7l-3_W2E6","stIgKYzbR","iys_3ih45","wnh3Dc813","x_N2KoM0r","ZYjw9gCJY"]},"hash":{"roomcount":{},"roomhistory":{},"ch:game":{"gameMode:classic":"0"}},"keys":{}}
\ No newline at end of file
diff --git a/server/package.json b/server/package.json
index de6e9d3..00c5ff8 100644
--- a/server/package.json
+++ b/server/package.json
@@ -1,6 +1,6 @@
{
"name": "snatchgame-server",
- "version": "0.0.5-alpha",
+ "version": "0.0.8-alpha",
"description": "SnatchGame multiplayer server using Colyseus",
"main": "lib/index.js",
"scripts": {
@@ -18,6 +18,8 @@
"author": "",
"license": "ISC",
"dependencies": {
+ "@colyseus/core": "^0.16.19",
+ "@colyseus/monitor": "^0.16.7",
"@colyseus/schema": "^3.0.42",
"@colyseus/tools": "^0.16.0",
"colyseus": "^0.16.0",
@@ -28,6 +30,6 @@
"@types/node": "^20.0.0",
"nodemon": "^3.1.10",
"ts-node-dev": "^2.0.0",
- "typescript": "^5.0.0"
+ "typescript": "^5.8.3"
}
}
diff --git a/server/src/app.config.ts b/server/src/app.config.ts
index 5022aeb..7ffb497 100644
--- a/server/src/app.config.ts
+++ b/server/src/app.config.ts
@@ -1,4 +1,6 @@
import config from "@colyseus/tools";
+import { monitor } from "@colyseus/monitor";
+import { matchMaker } from "@colyseus/core";
import { GameRoom } from "./rooms/GameRoom";
export default config({
@@ -19,12 +21,380 @@ export default config({
res.json({
name: "SnatchGame Server",
status: "running",
- version: "1.0.0"
+ version: "0.0.8-alpha",
+ description: "Multiplayer game server for SnatchGame",
});
});
app.get("/health", (req, res) => {
res.json({ status: "healthy" });
});
+
+ // Colyseus official monitoring panel
+ app.use("/monitor", monitor({
+ columns: [
+ 'roomId',
+ 'name',
+ 'clients',
+ 'maxClients',
+ 'locked',
+ 'elapsedTime'
+ ]
+ }));
+
+ // CORS for admin interface
+ app.use("/api/admin", (req, res, next) => {
+ res.header("Access-Control-Allow-Origin", "*");
+ res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+ res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
+
+ if (req.method === "OPTIONS") {
+ res.sendStatus(200);
+ } else {
+ next();
+ }
+ });
+
+ // Admin endpoints
+ app.use(require('express').json());
+
+ // Get game statistics using official matchMaker API
+ app.get("/api/admin/stats", async (req, res) => {
+ try {
+ const rooms = await matchMaker.query({});
+ let totalPlayers = 0;
+ let activeGames = 0;
+ const gameRooms = [];
+ const allPlayers = [];
+
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ activeGames++;
+ totalPlayers += room.clients;
+
+ // Get detailed room information including players
+ try {
+ const roomData = await matchMaker.remoteRoomCall(room.roomId, "getInspectData");
+
+ gameRooms.push({
+ roomId: room.roomId,
+ players: room.clients,
+ maxPlayers: room.maxClients,
+ locked: room.locked,
+ createdAt: room.createdAt,
+ elapsedTime: Date.now() - new Date(room.createdAt).getTime()
+ });
+
+ // Extract player information with their tokens
+ if (roomData.state && roomData.state.players) {
+ // Use forEach to iterate over MapSchema properly
+ roomData.state.players.forEach((player, playerId) => {
+ // Skip internal MapSchema properties
+ if (playerId.startsWith('$') || playerId === 'deletedItems') {
+ return;
+ }
+
+ allPlayers.push({
+ id: playerId,
+ name: player.name || 'Unknown',
+ roomId: room.roomId,
+ role: player.role || 'player',
+ producerRole: player.producerRole || 'turkey',
+ tokens: {
+ turkeys: player.tokens?.turkey || 0,
+ coffee: player.tokens?.coffee || 0,
+ corn: player.tokens?.corn || 0
+ },
+ isReady: player.isReady || false,
+ isConnected: player.isConnected !== false
+ });
+ });
+ }
+ } catch (roomError) {
+ console.error(`Failed to get room data for ${room.roomId}:`, roomError);
+ // Still add basic room info even if detailed data fails
+ gameRooms.push({
+ roomId: room.roomId,
+ players: room.clients,
+ maxPlayers: room.maxClients,
+ locked: room.locked,
+ createdAt: room.createdAt,
+ elapsedTime: Date.now() - new Date(room.createdAt).getTime()
+ });
+ }
+ }
+ }
+
+ res.json({
+ connectedPlayers: totalPlayers,
+ activeGames,
+ currentRound: activeGames > 0 ? 'Ronda 1' : 'waiting',
+ gameState: activeGames > 0 ? 'in_progress' : 'waiting_for_players',
+ players: allPlayers,
+ rooms: gameRooms
+ });
+ } catch (error) {
+ console.error('Admin stats error:', error);
+ res.status(500).json({
+ error: 'Failed to get stats',
+ connectedPlayers: 0,
+ activeGames: 0,
+ currentRound: 'error',
+ gameState: 'error',
+ players: [],
+ rooms: []
+ });
+ }
+ });
+
+ // Kick player using official matchMaker API
+ app.post("/api/admin/kick-player", async (req, res) => {
+ try {
+ const { playerId } = req.body;
+
+ if (!playerId) {
+ return res.status(400).json({ success: false, message: 'Player ID is required' });
+ }
+
+ // Get all rooms to find the player
+ const rooms = await matchMaker.query({});
+ let playerFound = false;
+
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ // Try to kick the player from this room
+ await matchMaker.remoteRoomCall(room.roomId, "_forceClientDisconnect", [playerId]);
+ console.log(`🚫 Admin kicked player ${playerId} from room ${room.roomId}`);
+ playerFound = true;
+ break;
+ } catch (error) {
+ // Player not in this room, continue searching
+ continue;
+ }
+ }
+ }
+
+ if (playerFound) {
+ res.json({ success: true, message: `Player ${playerId} kicked` });
+ } else {
+ res.status(404).json({ success: false, message: 'Player not found' });
+ }
+ } catch (error) {
+ console.error('Kick player error:', error);
+ res.status(500).json({ success: false, message: 'Failed to kick player' });
+ }
+ });
+
+ // Pause game using official matchMaker API
+ app.post("/api/admin/pause-game", async (req, res) => {
+ try {
+ const rooms = await matchMaker.query({});
+ let pausedGames = 0;
+
+ // Pause all active games
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ await matchMaker.remoteRoomCall(room.roomId, "pauseGame");
+ pausedGames++;
+ console.log(`⏸️ Admin paused game in room ${room.roomId}`);
+ } catch (error) {
+ console.error(`Failed to pause game in room ${room.roomId}:`, error);
+ }
+ }
+ }
+
+ res.json({
+ success: true,
+ message: `${pausedGames} games paused`,
+ pausedGames
+ });
+ } catch (error) {
+ console.error('Pause game error:', error);
+ res.status(500).json({ success: false, message: 'Failed to pause games' });
+ }
+ });
+
+ // Resume game using official matchMaker API
+ app.post("/api/admin/resume-game", async (req, res) => {
+ try {
+ const rooms = await matchMaker.query({});
+ let resumedGames = 0;
+
+ // Resume all paused games
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ await matchMaker.remoteRoomCall(room.roomId, "resumeGame");
+ resumedGames++;
+ console.log(`▶️ Admin resumed game in room ${room.roomId}`);
+ } catch (error) {
+ console.error(`Failed to resume game in room ${room.roomId}:`, error);
+ }
+ }
+ }
+
+ res.json({
+ success: true,
+ message: `${resumedGames} games resumed`,
+ resumedGames
+ });
+ } catch (error) {
+ console.error('Resume game error:', error);
+ res.status(500).json({ success: false, message: 'Failed to resume games' });
+ }
+ });
+
+ // Cancel game using official matchMaker API
+ app.post("/api/admin/cancel-game", async (req, res) => {
+ try {
+ const { gameId } = req.body;
+
+ if (gameId) {
+ // Cancel specific game
+ try {
+ await matchMaker.remoteRoomCall(gameId, "disconnect");
+ console.log(`❌ Admin cancelled game ${gameId}`);
+ res.json({ success: true, message: `Game ${gameId} cancelled` });
+ } catch (error) {
+ console.error(`Failed to cancel game ${gameId}:`, error);
+ res.status(404).json({ success: false, message: 'Game not found' });
+ }
+ } else {
+ // Cancel all games
+ const rooms = await matchMaker.query({});
+ let cancelledGames = 0;
+
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ await matchMaker.remoteRoomCall(room.roomId, "disconnect");
+ cancelledGames++;
+ console.log(`❌ Admin cancelled game ${room.roomId}`);
+ } catch (error) {
+ console.error(`Failed to cancel game ${room.roomId}:`, error);
+ }
+ }
+ }
+
+ res.json({
+ success: true,
+ message: `${cancelledGames} games cancelled`,
+ cancelledGames
+ });
+ }
+ } catch (error) {
+ console.error('Cancel game error:', error);
+ res.status(500).json({ success: false, message: 'Failed to cancel games' });
+ }
+ });
+
+ // Kick all players - empty all rooms
+ app.post("/api/admin/kick-all-players", async (req, res) => {
+ try {
+ const rooms = await matchMaker.query({});
+ let kickedPlayers = 0;
+ let roomsCleared = 0;
+
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ // Get room data to get player information
+ const roomData = await matchMaker.remoteRoomCall(room.roomId, "getInspectData");
+ const playerCount = roomData.clients?.length || 0;
+
+ if (playerCount > 0) {
+ // Kick each player individually to send proper notifications
+ await matchMaker.remoteRoomCall(room.roomId, "_forceDisconnectAllClients");
+ kickedPlayers += playerCount;
+ roomsCleared++;
+ console.log(`🚫🚫 Admin cleared room ${room.roomId} - ${playerCount} players kicked`);
+ }
+ } catch (error) {
+ console.error(`Failed to clear room ${room.roomId}:`, error);
+ }
+ }
+ }
+
+ res.json({
+ success: true,
+ message: `${kickedPlayers} jugadores expulsados de ${roomsCleared} salas`,
+ kickedPlayers,
+ roomsCleared
+ });
+ } catch (error) {
+ console.error('Kick all players error:', error);
+ res.status(500).json({ success: false, message: 'Failed to kick all players' });
+ }
+ });
+
+ // Advance round globally - all active games
+ app.post("/api/admin/advance-round", async (req, res) => {
+ try {
+ const rooms = await matchMaker.query({});
+ let roundsAdvanced = 0;
+ let newRound = 1;
+
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ const result = await matchMaker.remoteRoomCall(room.roomId, "advanceRound");
+ if (result && result.success) {
+ roundsAdvanced++;
+ newRound = result.newRound;
+ console.log(`⏭️ Admin advanced round in ${room.roomId} to round ${newRound}`);
+ }
+ } catch (error) {
+ console.error(`Failed to advance round in room ${room.roomId}:`, error);
+ }
+ }
+ }
+
+ res.json({
+ success: true,
+ message: `Ronda avanzada a ${newRound} en ${roundsAdvanced} salas`,
+ roundsAdvanced,
+ newRound
+ });
+ } catch (error) {
+ console.error('Advance round error:', error);
+ res.status(500).json({ success: false, message: 'Failed to advance round' });
+ }
+ });
+
+ // Go back round globally - all active games
+ app.post("/api/admin/previous-round", async (req, res) => {
+ try {
+ const rooms = await matchMaker.query({});
+ let roundsChanged = 0;
+ let newRound = 1;
+
+ for (const room of rooms) {
+ if (room.name === 'game') {
+ try {
+ const result = await matchMaker.remoteRoomCall(room.roomId, "previousRound");
+ if (result && result.success) {
+ roundsChanged++;
+ newRound = result.newRound;
+ console.log(`⏮️ Admin went back round in ${room.roomId} to round ${newRound}`);
+ }
+ } catch (error) {
+ console.error(`Failed to go back round in room ${room.roomId}:`, error);
+ }
+ }
+ }
+
+ res.json({
+ success: true,
+ message: `Ronda retrocedida a ${newRound} en ${roundsChanged} salas`,
+ roundsChanged,
+ newRound
+ });
+ } catch (error) {
+ console.error('Previous round error:', error);
+ res.status(500).json({ success: false, message: 'Failed to go back round' });
+ }
+ });
}
});
\ No newline at end of file
diff --git a/server/src/rooms/GameRoom.ts b/server/src/rooms/GameRoom.ts
index 7b36bdc..1618295 100644
--- a/server/src/rooms/GameRoom.ts
+++ b/server/src/rooms/GameRoom.ts
@@ -268,4 +268,148 @@ export class GameRoom extends Room {
onDispose() {
console.log(`GameRoom ${this.roomId} disposed`);
}
+
+ // Method for admin monitoring - used by Colyseus monitor and admin API
+ getInspectData() {
+ const stateSize = JSON.stringify(this.state).length;
+ const roomElapsedTime = this.clock.elapsedTime;
+
+ // Gather client information
+ const clients = this.clients.map((client) => ({
+ sessionId: client.sessionId,
+ elapsedTime: roomElapsedTime - (client as any)._joinedAt || 0
+ }));
+
+ // Return comprehensive room data
+ return {
+ roomId: this.roomId,
+ name: 'game',
+ clients: clients.length,
+ maxClients: this.maxClients,
+ locked: this.locked,
+ state: this.state,
+ stateSize,
+ clients: clients,
+ elapsedTime: roomElapsedTime,
+ metadata: {
+ gamePhase: this.state.gamePhase,
+ gameStarted: this.state.gameStarted,
+ round: this.state.round,
+ playerCount: this.state.players.size,
+ activeOffers: this.state.activeTradeOffers.length
+ }
+ };
+ }
+
+ // Admin methods for game control
+ pauseGame() {
+ if (this.state.gameStarted && this.state.gamePhase !== 'paused') {
+ this.state.gamePhase = 'paused';
+ console.log(`⏸️ Game paused in room ${this.roomId} by admin`);
+
+ // Broadcast pause message to all clients
+ this.broadcast("gamePaused", {
+ message: "El juego ha sido pausado por el administrador",
+ timestamp: Date.now()
+ });
+ }
+ }
+
+ resumeGame() {
+ if (this.state.gameStarted && this.state.gamePhase === 'paused') {
+ this.state.gamePhase = 'trading'; // Resume to trading phase
+ console.log(`▶️ Game resumed in room ${this.roomId} by admin`);
+
+ // Broadcast resume message to all clients
+ this.broadcast("gameResumed", {
+ message: "El juego ha sido reanudado por el administrador",
+ timestamp: Date.now()
+ });
+ }
+ }
+
+ _forceClientDisconnect(sessionId: string) {
+ const client = this.clients.find(c => c.sessionId === sessionId);
+ if (client) {
+ console.log(`🚫 Admin force disconnect player ${sessionId} from room ${this.roomId}`);
+
+ // Send notification to the specific client before disconnecting
+ client.send("adminKicked", {
+ message: "Has sido expulsado del juego por el administrador",
+ reason: "admin_kick",
+ timestamp: Date.now()
+ });
+
+ // Give client time to process the message, then disconnect
+ setTimeout(() => {
+ client.leave(4000); // Force disconnect with code 4000
+ }, 1000);
+ } else {
+ throw new Error(`Player ${sessionId} not found in room ${this.roomId}`);
+ }
+ }
+
+ _forceDisconnectAllClients() {
+ console.log(`🚫🚫 Admin force disconnect ALL players from room ${this.roomId}`);
+
+ if (this.clients.length === 0) {
+ return { success: true, kickedPlayers: 0 };
+ }
+
+ // Send notification to all clients first
+ this.broadcast("adminKicked", {
+ message: "Todos los jugadores han sido expulsados por el administrador",
+ reason: "admin_kick_all",
+ timestamp: Date.now()
+ });
+
+ const kickedCount = this.clients.length;
+
+ // Give clients time to process the message, then disconnect all
+ setTimeout(() => {
+ // Create a copy of clients array since it will be modified during iteration
+ const clientsToDisconnect = [...this.clients];
+ clientsToDisconnect.forEach(client => {
+ client.leave(4000); // Force disconnect with code 4000
+ });
+ }, 1000);
+
+ return { success: true, kickedPlayers: kickedCount };
+ }
+
+ advanceRound() {
+ const oldRound = this.state.round;
+ this.state.round = Math.min(oldRound + 1, 10); // Max 10 rounds
+ const newRound = this.state.round;
+
+ console.log(`⏭️ Round advanced from ${oldRound} to ${newRound} in room ${this.roomId}`);
+
+ // Broadcast round change to all clients
+ this.broadcast("roundChanged", {
+ oldRound,
+ newRound,
+ message: `Ronda ${newRound} - Cambio realizado por el administrador`,
+ timestamp: Date.now()
+ });
+
+ return { success: true, newRound, oldRound };
+ }
+
+ previousRound() {
+ const oldRound = this.state.round;
+ this.state.round = Math.max(oldRound - 1, 1); // Min round 1
+ const newRound = this.state.round;
+
+ console.log(`⏮️ Round went back from ${oldRound} to ${newRound} in room ${this.roomId}`);
+
+ // Broadcast round change to all clients
+ this.broadcast("roundChanged", {
+ oldRound,
+ newRound,
+ message: `Ronda ${newRound} - Cambio realizado por el administrador`,
+ timestamp: Date.now()
+ });
+
+ return { success: true, newRound, oldRound };
+ }
}
\ No newline at end of file