diff --git a/data/firmware.bin b/data/firmware.bin
new file mode 100644
index 0000000..27ef29f
Binary files /dev/null and b/data/firmware.bin differ
diff --git a/data/index.css b/data/index.css
index 99e32f7..0c4e468 100644
--- a/data/index.css
+++ b/data/index.css
@@ -471,6 +471,13 @@ body {
overflow: visible;
}
+.status.large-status.ready {
+ font-size: clamp(2rem, 8vw, 8rem) !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+}
+
.status.finished {
background-color: rgba(73, 186, 228, 0.3);
border: 2px solid #49bae4;
@@ -479,7 +486,6 @@ body {
.status.ready {
background-color: rgb(0 165 3 / 54%);
border: 2px solid #06ff00;
- animation: pulse 1s infinite;
}
.status.armed {
diff --git a/data/index.html b/data/index.html
index 26b031f..c2f98db 100644
--- a/data/index.html
+++ b/data/index.html
@@ -449,57 +449,80 @@
if (!lane1Connected) {
s1.className = "status standby large-status";
s1.textContent = "Standby: Drücke beide Buttons einmal";
+ time1Element.style.display = "none";
// Position über time-display, aber innerhalb des Containers
if (s1.classList.contains("large-status")) {
- const time1Rect = time1Element.getBoundingClientRect();
const lane1Rect = lane1Element.getBoundingClientRect();
const h2Rect = h2_1.getBoundingClientRect();
- const time1Center = time1Rect.top - lane1Rect.top + time1Rect.height / 2;
const h2Bottom = h2Rect.bottom - lane1Rect.top;
- // Stelle sicher, dass die obere Kante der Status-Box unter h2 beginnt
- // Beginne unter h2 (ohne translate(-50%, -50%) beginnt die Box von oben)
const startTop = h2Bottom + 10;
- // Positioniere so, dass die Box über time-display zentriert ist, aber nicht über h2 hinausragt
- // Berechne die benötigte Höhe, um über time-display zentriert zu sein
- const statusHeight = s1.offsetHeight || 200; // Verwende tatsächliche Höhe oder Schätzwert
- const targetTop = Math.max(startTop, time1Center - statusHeight / 2);
- s1.style.top = targetTop + "px";
+ s1.style.top = startTop + "px";
+ s1.style.left = "50%";
s1.style.transform = "translateX(-50%)";
- // Stelle sicher, dass die Box innerhalb des Containers bleibt
- const maxHeight = lane1Rect.height - targetTop - 30;
- s1.style.maxHeight = maxHeight + "px";
- s1.style.overflow = "auto";
+ s1.style.bottom = "20px";
+ s1.style.width = "calc(100% - 40px)";
+ s1.style.display = "flex";
+ s1.style.alignItems = "center";
+ s1.style.justifyContent = "center";
}
} else {
s1.className = `status ${status1}`;
- // Add large-status class if not running and not finished
- if (status1 !== "running" && status1 !== "finished") {
+ // Wenn status "ready" ist, verstecke Zeit und mache Status groß
+ if (status1 === "ready") {
s1.classList.add("large-status");
- // Position über time-display, aber innerhalb des Containers
- const time1Rect = time1Element.getBoundingClientRect();
+ time1Element.style.display = "none";
const lane1Rect = lane1Element.getBoundingClientRect();
const h2Rect = h2_1.getBoundingClientRect();
- const time1Center = time1Rect.top - lane1Rect.top + time1Rect.height / 2;
const h2Bottom = h2Rect.bottom - lane1Rect.top;
- // Stelle sicher, dass die obere Kante der Status-Box unter h2 beginnt
- // Beginne unter h2 (ohne translate(-50%, -50%) beginnt die Box von oben)
const startTop = h2Bottom + 10;
- // Positioniere so, dass die Box über time-display zentriert ist, aber nicht über h2 hinausragt
- // Berechne die benötigte Höhe, um über time-display zentriert zu sein
- const statusHeight = s1.offsetHeight || 200; // Verwende tatsächliche Höhe oder Schätzwert
- const targetTop = Math.max(startTop, time1Center - statusHeight / 2);
- s1.style.top = targetTop + "px";
+ s1.style.top = startTop + "px";
+ s1.style.left = "50%";
s1.style.transform = "translateX(-50%)";
- // Stelle sicher, dass die Box innerhalb des Containers bleibt
- const maxHeight = lane1Rect.height - targetTop - 30;
- s1.style.maxHeight = maxHeight + "px";
- s1.style.overflow = "auto";
+ s1.style.bottom = "20px";
+ s1.style.width = "calc(100% - 40px)";
+ s1.style.display = "flex";
+ s1.style.alignItems = "center";
+ s1.style.justifyContent = "center";
+ s1.style.fontSize = "clamp(2rem, 8vw, 8rem)";
} else {
- s1.classList.remove("large-status");
- s1.style.top = "";
- s1.style.transform = "";
- s1.style.maxHeight = "";
+ // Bei anderen Status (running, finished, etc.) zeige Zeit wieder an
+ time1Element.style.display = "";
+ if (status1 !== "running" && status1 !== "finished") {
+ s1.classList.add("large-status");
+ const time1Rect = time1Element.getBoundingClientRect();
+ const lane1Rect = lane1Element.getBoundingClientRect();
+ const h2Rect = h2_1.getBoundingClientRect();
+ const time1Center = time1Rect.top - lane1Rect.top + time1Rect.height / 2;
+ const h2Bottom = h2Rect.bottom - lane1Rect.top;
+ const startTop = h2Bottom + 10;
+ const statusHeight = s1.offsetHeight || 200;
+ const targetTop = Math.max(startTop, time1Center - statusHeight / 2);
+ s1.style.top = targetTop + "px";
+ s1.style.transform = "translateX(-50%)";
+ s1.style.height = "";
+ s1.style.width = "";
+ s1.style.display = "";
+ s1.style.alignItems = "";
+ s1.style.justifyContent = "";
+ s1.style.fontSize = "";
+ const maxHeight = lane1Rect.height - targetTop - 30;
+ s1.style.maxHeight = maxHeight + "px";
+ s1.style.overflow = "auto";
+ } else {
+ s1.classList.remove("large-status");
+ s1.style.top = "";
+ s1.style.transform = "";
+ s1.style.maxHeight = "";
+ s1.style.height = "";
+ s1.style.width = "";
+ s1.style.display = "";
+ s1.style.alignItems = "";
+ s1.style.justifyContent = "";
+ s1.style.fontSize = "";
+ s1.style.left = "";
+ s1.style.bottom = "";
+ }
}
switch (status1) {
@@ -529,57 +552,80 @@
if (!lane2Connected) {
s2.className = "status standby large-status";
s2.textContent = "Standby: Drücke beide Buttons einmal";
+ time2Element.style.display = "none";
// Position über time-display, aber innerhalb des Containers
if (s2.classList.contains("large-status")) {
- const time2Rect = time2Element.getBoundingClientRect();
const lane2Rect = lane2Element.getBoundingClientRect();
const h2Rect = h2_2.getBoundingClientRect();
- const time2Center = time2Rect.top - lane2Rect.top + time2Rect.height / 2;
const h2Bottom = h2Rect.bottom - lane2Rect.top;
- // Stelle sicher, dass die obere Kante der Status-Box unter h2 beginnt
- // Beginne unter h2 (ohne translate(-50%, -50%) beginnt die Box von oben)
const startTop = h2Bottom + 10;
- // Positioniere so, dass die Box über time-display zentriert ist, aber nicht über h2 hinausragt
- // Berechne die benötigte Höhe, um über time-display zentriert zu sein
- const statusHeight = s2.offsetHeight || 200; // Verwende tatsächliche Höhe oder Schätzwert
- const targetTop = Math.max(startTop, time2Center - statusHeight / 2);
- s2.style.top = targetTop + "px";
+ s2.style.top = startTop + "px";
+ s2.style.left = "50%";
s2.style.transform = "translateX(-50%)";
- // Stelle sicher, dass die Box innerhalb des Containers bleibt
- const maxHeight = lane2Rect.height - targetTop - 30;
- s2.style.maxHeight = maxHeight + "px";
- s2.style.overflow = "auto";
+ s2.style.bottom = "20px";
+ s2.style.width = "calc(100% - 40px)";
+ s2.style.display = "flex";
+ s2.style.alignItems = "center";
+ s2.style.justifyContent = "center";
}
} else {
s2.className = `status ${status2}`;
- // Add large-status class if not running and not finished
- if (status2 !== "running" && status2 !== "finished") {
+ // Wenn status "ready" ist, verstecke Zeit und mache Status groß
+ if (status2 === "ready") {
s2.classList.add("large-status");
- // Position über time-display, aber innerhalb des Containers
- const time2Rect = time2Element.getBoundingClientRect();
+ time2Element.style.display = "none";
const lane2Rect = lane2Element.getBoundingClientRect();
const h2Rect = h2_2.getBoundingClientRect();
- // Stelle sicher, dass die obere Kante der Status-Box unter h2 beginnt
const h2Bottom = h2Rect.bottom - lane2Rect.top;
- const time2Center = time2Rect.top - lane2Rect.top + time2Rect.height / 2;
- // Beginne unter h2 (ohne translate(-50%, -50%) beginnt die Box von oben)
const startTop = h2Bottom + 10;
- // Positioniere so, dass die Box über time-display zentriert ist, aber nicht über h2 hinausragt
- // Berechne die benötigte Höhe, um über time-display zentriert zu sein
- const statusHeight = s2.offsetHeight || 200; // Verwende tatsächliche Höhe oder Schätzwert
- const targetTop = Math.max(startTop, time2Center - statusHeight / 2);
- s2.style.top = targetTop + "px";
+ s2.style.top = startTop + "px";
+ s2.style.left = "50%";
s2.style.transform = "translateX(-50%)";
- // Stelle sicher, dass die Box innerhalb des Containers bleibt
- const maxHeight = lane2Rect.height - targetTop - 30;
- s2.style.maxHeight = maxHeight + "px";
- s2.style.overflow = "auto";
+ s2.style.bottom = "20px";
+ s2.style.width = "calc(100% - 40px)";
+ s2.style.display = "flex";
+ s2.style.alignItems = "center";
+ s2.style.justifyContent = "center";
+ s2.style.fontSize = "clamp(2rem, 8vw, 8rem)";
} else {
- s2.classList.remove("large-status");
- s2.style.top = "";
- s2.style.transform = "";
- s2.style.maxHeight = "";
+ // Bei anderen Status (running, finished, etc.) zeige Zeit wieder an
+ time2Element.style.display = "";
+ if (status2 !== "running" && status2 !== "finished") {
+ s2.classList.add("large-status");
+ const time2Rect = time2Element.getBoundingClientRect();
+ const lane2Rect = lane2Element.getBoundingClientRect();
+ const h2Rect = h2_2.getBoundingClientRect();
+ const time2Center = time2Rect.top - lane2Rect.top + time2Rect.height / 2;
+ const h2Bottom = h2Rect.bottom - lane2Rect.top;
+ const startTop = h2Bottom + 10;
+ const statusHeight = s2.offsetHeight || 200;
+ const targetTop = Math.max(startTop, time2Center - statusHeight / 2);
+ s2.style.top = targetTop + "px";
+ s2.style.transform = "translateX(-50%)";
+ s2.style.height = "";
+ s2.style.width = "";
+ s2.style.display = "";
+ s2.style.alignItems = "";
+ s2.style.justifyContent = "";
+ s2.style.fontSize = "";
+ const maxHeight = lane2Rect.height - targetTop - 30;
+ s2.style.maxHeight = maxHeight + "px";
+ s2.style.overflow = "auto";
+ } else {
+ s2.classList.remove("large-status");
+ s2.style.top = "";
+ s2.style.transform = "";
+ s2.style.maxHeight = "";
+ s2.style.height = "";
+ s2.style.width = "";
+ s2.style.display = "";
+ s2.style.alignItems = "";
+ s2.style.justifyContent = "";
+ s2.style.fontSize = "";
+ s2.style.left = "";
+ s2.style.bottom = "";
+ }
}
switch (status2) {
diff --git a/mock-server/.gitignore b/mock-server/.gitignore
deleted file mode 100644
index 3f00ede..0000000
--- a/mock-server/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules/
-*.log
-.DS_Store
-.env
diff --git a/mock-server/README.md b/mock-server/README.md
deleted file mode 100644
index 1ad2d98..0000000
--- a/mock-server/README.md
+++ /dev/null
@@ -1,179 +0,0 @@
-# AquaMaster Mock Server
-
-Mock ESP32 Server und MQTT-Broker für lokales Testing ohne Hardware.
-
-## Übersicht
-
-Dieses Projekt simuliert:
-- **MQTT-Broker** (Port 1883 TCP, Port 9001 WebSocket) - Lokaler MQTT-Broker für Kommunikation
-- **Mock ESP32 Server** (Port 80) - Simuliert alle ESP32 API-Endpunkte und WebSocket
-- **Web Debug UI** - Browser-basierte Oberfläche zum Testen von API und MQTT
-
-## Voraussetzungen
-
-- Node.js 16+ (LTS empfohlen)
-- npm
-
-## Installation
-
-```bash
-cd mock-server
-npm install
-```
-
-## Verwendung
-
-### Option 1: Beide Server zusammen starten
-
-```bash
-npm start
-# oder
-node start_all.js
-```
-
-### Option 2: Server einzeln starten
-
-**Terminal 1 - MQTT Broker:**
-```bash
-npm run mqtt
-# oder
-node mqtt_broker.js
-```
-
-**Terminal 2 - Mock ESP32 Server:**
-```bash
-npm run server
-# oder
-node mock_esp32_server.js
-```
-
-### Web Debug UI öffnen
-
-Nach dem Start der Server:
-1. Öffne einen Browser
-2. Navigiere zu: `http://localhost:80`
-3. Die Debug-Oberfläche sollte sichtbar sein
-
-## Features
-
-### MQTT Broker
-- Läuft auf Port 1883 (TCP) und Port 9001 (WebSocket)
-- Unterstützt alle relevanten Topics:
- - `aquacross/button/#`
- - `aquacross/button/rfid/#`
- - `aquacross/battery/#`
- - `heartbeat/alive/#`
- - `aquacross/competition/#`
- - `sync/time`
- - `aquacross/lanes/#`
-- Loggt alle Nachrichten für Debugging
-
-### Mock ESP32 Server
-- Simuliert alle API-Endpunkte aus der ESP32-Firmware
-- WebSocket-Support für Live-Updates
-- MQTT-Client, der sich mit dem Broker verbindet
-- Timer-Logik (Individual/Wettkampf-Modi)
-- Button-Konfigurationen und Learning-Mode
-
-### Web Debug UI
-- **API Testing Tab**: Teste alle API-Endpunkte
-- **MQTT Testing Tab**: Publish/Subscribe MQTT-Nachrichten
-- **Debug Endpoints Tab**: Direkte Timer-Kontrolle
-
-## API-Endpunkte
-
-Alle Endpunkte sind unter `http://localhost:80/api/...` verfügbar:
-
-- `GET /api/data` - Timer-Daten abrufen
-- `POST /api/reset-best` - Beste Zeiten zurücksetzen
-- `POST /api/unlearn-button` - Button-Zuordnungen löschen
-- `GET /api/debug/start1` - Lane 1 starten (Debug)
-- `GET /api/debug/stop1` - Lane 1 stoppen (Debug)
-- `GET /api/debug/start2` - Lane 2 starten (Debug)
-- `GET /api/debug/stop2` - Lane 2 stoppen (Debug)
-- ... und viele mehr (siehe `../API.md`)
-
-## MQTT Topics
-
-### Button Topics
-- `aquacross/button/{MAC}` - Button-Press Nachrichten
- ```json
- {"type": 2, "timestamp": 1234567890}
- ```
- - `type: 2` = Start-Button
- - `type: 1` = Stop-Button
-
-### RFID Topics
-- `aquacross/button/rfid/{MAC}` - RFID-Read Nachrichten
- ```json
- {"uid": "TEST123456"}
- ```
-
-### Battery Topics
-- `aquacross/battery/{MAC}` - Batteriestand
- ```json
- {"voltage": 3600}
- ```
-
-### Heartbeat Topics
-- `heartbeat/alive/{MAC}` - Heartbeat-Nachrichten
- ```json
- {"timestamp": 1234567890}
- ```
-
-### Competition Topics
-- `aquacross/competition/toMaster` - Wettkampf-Start
- ```
- "start"
- ```
-
-### Time Sync
-- `sync/time` - Zeit-Synchronisation (vom Server alle 5 Sekunden)
-
-## Troubleshooting
-
-### Port bereits belegt
-Falls Port 80 oder 1883 bereits belegt sind:
-- Windows: Port 80 benötigt Admin-Rechte, verwende einen anderen Port
-- Linux/Mac: Port 80 benötigt sudo, verwende einen anderen Port
-
-Um Ports zu ändern, editiere:
-- `mqtt_broker.js` - Zeile mit `const port = 1883;`
-- `mock_esp32_server.js` - Zeile mit `const PORT = 80;`
-
-### MQTT-Verbindung fehlgeschlagen
-- Stelle sicher, dass der MQTT-Broker läuft
-- Prüfe, ob Port 1883 (TCP) oder 9001 (WebSocket) erreichbar ist
-- Browser benötigen WebSocket-Verbindung (Port 9001)
-
-### WebSocket-Verbindung fehlgeschlagen
-- Stelle sicher, dass der Mock ESP32 Server läuft
-- Prüfe Browser-Konsole auf Fehler
-- Socket.io sollte automatisch geladen werden
-
-## Projektstruktur
-
-```
-mock-server/
-├── package.json # Node.js Dependencies
-├── README.md # Diese Datei
-├── .gitignore # Git ignore
-├── mqtt_broker.js # MQTT-Broker
-├── mock_esp32_server.js # Mock ESP32 Server
-├── start_all.js # Startet beide Server
-└── debug_server/
- ├── index.html # Web Debug UI
- ├── debug.js # JavaScript-Logik
- └── debug.css # Styling
-```
-
-## Hinweise
-
-- Der Mock-Server speichert keinen persistenten State (alles im Speicher)
-- Nach Neustart sind alle Einstellungen zurückgesetzt
-- Für Produktionstests sollte der echte ESP32 verwendet werden
-- Dieser Mock-Server ist nur für Entwicklung und Testing gedacht
-
-## Lizenz
-
-MIT
diff --git a/mock-server/debug_server/debug.css b/mock-server/debug_server/debug.css
deleted file mode 100644
index 4615ce5..0000000
--- a/mock-server/debug_server/debug.css
+++ /dev/null
@@ -1,273 +0,0 @@
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
- background: #f5f5f5;
- color: #333;
- line-height: 1.6;
-}
-
-.container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 20px;
-}
-
-header {
- background: #2c3e50;
- color: white;
- padding: 20px;
- border-radius: 8px;
- margin-bottom: 20px;
-}
-
-header h1 {
- margin-bottom: 15px;
-}
-
-.status-bar {
- display: flex;
- gap: 20px;
- flex-wrap: wrap;
-}
-
-.status-indicator {
- padding: 5px 10px;
- background: rgba(255, 255, 255, 0.2);
- border-radius: 4px;
- font-size: 0.9em;
-}
-
-.status-indicator.connected {
- background: #27ae60;
-}
-
-.status-indicator.disconnected {
- background: #e74c3c;
-}
-
-.tabs {
- display: flex;
- gap: 10px;
- margin-bottom: 20px;
- border-bottom: 2px solid #ddd;
-}
-
-.tab-button {
- padding: 12px 24px;
- background: transparent;
- border: none;
- border-bottom: 3px solid transparent;
- cursor: pointer;
- font-size: 16px;
- color: #666;
- transition: all 0.3s;
-}
-
-.tab-button:hover {
- color: #2c3e50;
- background: #f0f0f0;
-}
-
-.tab-button.active {
- color: #2c3e50;
- border-bottom-color: #3498db;
- font-weight: bold;
-}
-
-.tab-content {
- display: none;
- background: white;
- padding: 20px;
- border-radius: 8px;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-}
-
-.tab-content.active {
- display: block;
-}
-
-.section {
- margin-bottom: 30px;
-}
-
-.section h2 {
- margin-bottom: 15px;
- color: #2c3e50;
- border-bottom: 2px solid #ecf0f1;
- padding-bottom: 10px;
-}
-
-.section h3 {
- margin-top: 20px;
- margin-bottom: 10px;
- color: #34495e;
-}
-
-.form-group {
- margin-bottom: 15px;
-}
-
-.form-group label {
- display: block;
- margin-bottom: 5px;
- font-weight: 500;
- color: #555;
-}
-
-.form-group input,
-.form-group select,
-.form-group textarea {
- width: 100%;
- padding: 10px;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-size: 14px;
- font-family: inherit;
-}
-
-.form-group textarea {
- resize: vertical;
- font-family: 'Courier New', monospace;
-}
-
-.btn {
- padding: 10px 20px;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.3s;
- margin-right: 10px;
- margin-bottom: 10px;
-}
-
-.btn-primary {
- background: #3498db;
- color: white;
-}
-
-.btn-primary:hover {
- background: #2980b9;
-}
-
-.btn-secondary {
- background: #95a5a6;
- color: white;
-}
-
-.btn-secondary:hover {
- background: #7f8c8d;
-}
-
-.btn-small {
- padding: 5px 10px;
- font-size: 12px;
-}
-
-.button-group {
- display: flex;
- flex-wrap: wrap;
- gap: 10px;
- margin-top: 15px;
-}
-
-.response-section {
- margin-top: 20px;
- padding: 15px;
- background: #f8f9fa;
- border-radius: 4px;
-}
-
-.response-section pre {
- background: #2c3e50;
- color: #ecf0f1;
- padding: 15px;
- border-radius: 4px;
- overflow-x: auto;
- font-size: 13px;
- max-height: 400px;
- overflow-y: auto;
-}
-
-.quick-actions {
- margin-top: 30px;
- padding-top: 20px;
- border-top: 1px solid #ddd;
-}
-
-.messages-section {
- margin-top: 30px;
-}
-
-.messages-controls {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 10px;
-}
-
-.messages-container {
- background: #2c3e50;
- color: #ecf0f1;
- padding: 15px;
- border-radius: 4px;
- max-height: 500px;
- overflow-y: auto;
- font-family: 'Courier New', monospace;
- font-size: 12px;
-}
-
-.message-item {
- padding: 8px;
- margin-bottom: 8px;
- background: rgba(255, 255, 255, 0.1);
- border-radius: 4px;
- border-left: 3px solid #3498db;
-}
-
-.message-item .timestamp {
- color: #95a5a6;
- font-size: 11px;
- margin-bottom: 4px;
-}
-
-.message-item .topic {
- color: #3498db;
- font-weight: bold;
- margin-bottom: 4px;
-}
-
-.message-item .payload {
- color: #ecf0f1;
- word-break: break-all;
-}
-
-@media (max-width: 768px) {
- .container {
- padding: 10px;
- }
-
- .tabs {
- flex-wrap: wrap;
- }
-
- .tab-button {
- flex: 1;
- min-width: 100px;
- }
-
- .button-group {
- flex-direction: column;
- }
-
- .btn {
- width: 100%;
- margin-right: 0;
- }
-}
diff --git a/mock-server/debug_server/debug.js b/mock-server/debug_server/debug.js
deleted file mode 100644
index 4f2e80e..0000000
--- a/mock-server/debug_server/debug.js
+++ /dev/null
@@ -1,378 +0,0 @@
-// Configuration
-const API_BASE_URL = 'http://localhost:80';
-const MQTT_BROKER_URL = 'ws://localhost:9001/mqtt'; // WebSocket port for MQTT
-const WS_URL = 'http://localhost:80';
-
-// State
-let mqttClient = null;
-let wsClient = null;
-let subscribedTopics = new Set();
-
-// Initialize
-document.addEventListener('DOMContentLoaded', init);
-
-function init() {
- setupTabs();
- setupAPI();
- setupMQTT();
- setupWebSocket();
- setupDebug();
- setupQuickActions();
-}
-
-// Tab Management
-function setupTabs() {
- const tabButtons = document.querySelectorAll('.tab-button');
- const tabContents = document.querySelectorAll('.tab-content');
-
- tabButtons.forEach(button => {
- button.addEventListener('click', () => {
- const tabName = button.dataset.tab;
-
- // Remove active class from all
- tabButtons.forEach(btn => btn.classList.remove('active'));
- tabContents.forEach(content => content.classList.remove('active'));
-
- // Add active class to selected
- button.classList.add('active');
- document.getElementById(`${tabName}-tab`).classList.add('active');
- });
- });
-}
-
-// API Setup
-function setupAPI() {
- const endpointSelect = document.getElementById('api-endpoint');
- const paramsTextarea = document.getElementById('api-params');
- const sendBtn = document.getElementById('api-send-btn');
- const responsePre = document.getElementById('api-response');
-
- sendBtn.addEventListener('click', async () => {
- const endpoint = endpointSelect.value;
- const [method, path] = endpoint.split(' ');
- const params = paramsTextarea.value.trim();
-
- try {
- let options = {
- method: method,
- headers: {}
- };
-
- if (method === 'POST' && params) {
- // Try to parse as JSON, otherwise use as form data
- try {
- const jsonData = JSON.parse(params);
- options.headers['Content-Type'] = 'application/json';
- options.body = JSON.stringify(jsonData);
- } catch {
- // Not JSON, use form data
- const formData = new URLSearchParams();
- const pairs = params.split('&');
- pairs.forEach(pair => {
- const [key, value] = pair.split('=');
- if (key && value) {
- formData.append(key, decodeURIComponent(value));
- }
- });
- options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
- options.body = formData.toString();
- }
- }
-
- const response = await fetch(`${API_BASE_URL}${path}`, options);
- const text = await response.text();
-
- let formatted;
- try {
- formatted = JSON.stringify(JSON.parse(text), null, 2);
- } catch {
- formatted = text;
- }
-
- responsePre.textContent = formatted;
-
- } catch (error) {
- responsePre.textContent = `Error: ${error.message}`;
- }
- });
-}
-
-// MQTT Setup
-function setupMQTT() {
- const topicInput = document.getElementById('mqtt-topic');
- const payloadTextarea = document.getElementById('mqtt-payload');
- const publishBtn = document.getElementById('mqtt-publish-btn');
- const subscribeBtn = document.getElementById('mqtt-subscribe-btn');
- const unsubscribeBtn = document.getElementById('mqtt-unsubscribe-btn');
- const subscribeTopicInput = document.getElementById('mqtt-subscribe-topic');
- const messagesContainer = document.getElementById('mqtt-messages');
- const clearMessagesBtn = document.getElementById('clear-messages-btn');
-
- // Connect to MQTT broker
- try {
- mqttClient = mqtt.connect(MQTT_BROKER_URL, {
- clientId: 'debug-ui-' + Math.random().toString(16).substr(2, 8)
- });
-
- mqttClient.on('connect', () => {
- console.log('MQTT connected');
- updateStatus('mqtt-status', 'MQTT: Connected', true);
- });
-
- mqttClient.on('error', (error) => {
- console.error('MQTT error:', error);
- updateStatus('mqtt-status', 'MQTT: Error', false);
- });
-
- mqttClient.on('close', () => {
- console.log('MQTT disconnected');
- updateStatus('mqtt-status', 'MQTT: Disconnected', false);
- });
-
- mqttClient.on('message', (topic, message) => {
- addMessage(topic, message.toString());
- });
- } catch (error) {
- console.error('Failed to connect to MQTT:', error);
- updateStatus('mqtt-status', 'MQTT: Connection Failed', false);
- }
-
- publishBtn.addEventListener('click', () => {
- const topic = topicInput.value.trim();
- let payload = payloadTextarea.value.trim();
-
- if (!topic) {
- alert('Please enter a topic');
- return;
- }
-
- // Try to parse as JSON, otherwise use as-is
- try {
- const jsonData = JSON.parse(payload);
- payload = JSON.stringify(jsonData);
- } catch {
- // Not JSON, use as-is
- }
-
- if (mqttClient && mqttClient.connected) {
- mqttClient.publish(topic, payload, (err) => {
- if (err) {
- console.error('Publish error:', err);
- alert('Failed to publish: ' + err.message);
- } else {
- console.log('Published to', topic);
- }
- });
- } else {
- alert('MQTT not connected');
- }
- });
-
- subscribeBtn.addEventListener('click', () => {
- const topic = subscribeTopicInput.value.trim();
- if (!topic) {
- alert('Please enter a topic pattern');
- return;
- }
-
- if (mqttClient && mqttClient.connected) {
- mqttClient.subscribe(topic, (err) => {
- if (err) {
- console.error('Subscribe error:', err);
- alert('Failed to subscribe: ' + err.message);
- } else {
- subscribedTopics.add(topic);
- console.log('Subscribed to', topic);
- }
- });
- } else {
- alert('MQTT not connected');
- }
- });
-
- unsubscribeBtn.addEventListener('click', () => {
- if (mqttClient && mqttClient.connected) {
- subscribedTopics.forEach(topic => {
- mqttClient.unsubscribe(topic);
- });
- subscribedTopics.clear();
- console.log('Unsubscribed from all topics');
- }
- });
-
- clearMessagesBtn.addEventListener('click', () => {
- messagesContainer.innerHTML = '';
- });
-}
-
-function addMessage(topic, payload) {
- const messagesContainer = document.getElementById('mqtt-messages');
- const messageDiv = document.createElement('div');
- messageDiv.className = 'message-item';
-
- const timestamp = new Date().toLocaleTimeString();
- let formattedPayload = payload;
- try {
- formattedPayload = JSON.stringify(JSON.parse(payload), null, 2);
- } catch {}
-
- messageDiv.innerHTML = `
-
${timestamp}
- ${topic}
- ${formattedPayload}
- `;
-
- messagesContainer.appendChild(messageDiv);
-
- // Auto-scroll
- if (document.getElementById('auto-scroll').checked) {
- messagesContainer.scrollTop = messagesContainer.scrollHeight;
- }
-}
-
-// WebSocket Setup
-function setupWebSocket() {
- if (typeof io !== 'undefined') {
- try {
- wsClient = io(SOCKET_IO_URL);
-
- wsClient.on('connect', () => {
- console.log('WebSocket connected');
- updateStatus('ws-status', 'WebSocket: Connected', true);
- });
-
- wsClient.on('disconnect', () => {
- console.log('WebSocket disconnected');
- updateStatus('ws-status', 'WebSocket: Disconnected', false);
- });
-
- wsClient.on('update', (data) => {
- console.log('WebSocket update:', data);
- // Could display in a separate section
- });
- } catch (error) {
- console.error('Failed to connect WebSocket:', error);
- updateStatus('ws-status', 'WebSocket: Error', false);
- }
- } else {
- console.warn('Socket.io not loaded');
- updateStatus('ws-status', 'WebSocket: Library Not Loaded', false);
- }
-}
-
-// Debug Endpoints Setup
-function setupDebug() {
- const debugButtons = document.querySelectorAll('[data-debug]');
- const responsePre = document.getElementById('debug-response');
-
- debugButtons.forEach(button => {
- button.addEventListener('click', async () => {
- const action = button.dataset.debug;
- const endpoint = `/api/debug/${action}`;
-
- try {
- const response = await fetch(`${API_BASE_URL}${endpoint}`);
- const text = await response.text();
- responsePre.textContent = text;
- } catch (error) {
- responsePre.textContent = `Error: ${error.message}`;
- }
- });
- });
-}
-
-// Quick Actions Setup
-function setupQuickActions() {
- const quickActionButtons = document.querySelectorAll('[data-action]');
-
- quickActionButtons.forEach(button => {
- button.addEventListener('click', () => {
- const action = button.dataset.action;
- const topicInput = document.getElementById('mqtt-topic');
- const payloadTextarea = document.getElementById('mqtt-payload');
-
- switch (action) {
- case 'button-start1':
- topicInput.value = 'aquacross/button/00:00:00:00:00:01';
- payloadTextarea.value = JSON.stringify({
- type: 2,
- timestamp: Date.now()
- }, null, 2);
- break;
- case 'button-stop1':
- topicInput.value = 'aquacross/button/00:00:00:00:00:03';
- payloadTextarea.value = JSON.stringify({
- type: 1,
- timestamp: Date.now()
- }, null, 2);
- break;
- case 'button-start2':
- topicInput.value = 'aquacross/button/00:00:00:00:00:02';
- payloadTextarea.value = JSON.stringify({
- type: 2,
- timestamp: Date.now()
- }, null, 2);
- break;
- case 'button-stop2':
- topicInput.value = 'aquacross/button/00:00:00:00:00:04';
- payloadTextarea.value = JSON.stringify({
- type: 1,
- timestamp: Date.now()
- }, null, 2);
- break;
- case 'rfid-read':
- topicInput.value = 'aquacross/button/rfid/00:00:00:00:00:01';
- payloadTextarea.value = JSON.stringify({
- uid: 'TEST123456'
- }, null, 2);
- break;
- case 'battery-update':
- topicInput.value = 'aquacross/battery/00:00:00:00:00:01';
- payloadTextarea.value = JSON.stringify({
- voltage: 3600
- }, null, 2);
- break;
- case 'heartbeat':
- topicInput.value = 'heartbeat/alive/00:00:00:00:00:01';
- payloadTextarea.value = JSON.stringify({
- timestamp: Date.now()
- }, null, 2);
- break;
- case 'button-available':
- topicInput.value = 'aquacross/button/status/00:00:00:00:00:01';
- payloadTextarea.value = JSON.stringify({
- available: true,
- sleep: false,
- timestamp: Date.now()
- }, null, 2);
- break;
- case 'button-sleep':
- topicInput.value = 'aquacross/button/status/00:00:00:00:00:01';
- payloadTextarea.value = JSON.stringify({
- available: false,
- sleep: true,
- timestamp: Date.now()
- }, null, 2);
- break;
- }
-
- // Auto-publish
- document.getElementById('mqtt-publish-btn').click();
- });
- });
-}
-
-// Helper Functions
-function updateStatus(elementId, text, connected) {
- const element = document.getElementById(elementId);
- element.textContent = text;
- element.classList.remove('connected', 'disconnected');
- element.classList.add(connected ? 'connected' : 'disconnected');
-}
-
-// Initialize on load
-if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', init);
-} else {
- init();
-}
diff --git a/mock-server/debug_server/index.html b/mock-server/debug_server/index.html
deleted file mode 100644
index d33444b..0000000
--- a/mock-server/debug_server/index.html
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
-
- AquaMaster Debug Server
-
-
-
-
-
-
-
-
-
-
-
-
API Endpoint Testing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
MQTT Publish
-
-
-
-
-
-
-
-
-
-
-
-
Quick Actions:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
MQTT Subscribe
-
-
-
-
-
-
-
-
-
Received Messages:
-
-
-
-
-
-
-
-
-
-
-
-
-
Debug Endpoints
-
Direct access to debug endpoints for timer control:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mock-server/mock_esp32_server.js b/mock-server/mock_esp32_server.js
deleted file mode 100644
index 69c8b3b..0000000
--- a/mock-server/mock_esp32_server.js
+++ /dev/null
@@ -1,718 +0,0 @@
-const express = require('express');
-const http = require('http');
-const socketIo = require('socket.io');
-const mqtt = require('mqtt');
-const cors = require('cors');
-const bodyParser = require('body-parser');
-const path = require('path');
-
-const app = express();
-const server = http.createServer(app);
-const io = socketIo(server, {
- cors: {
- origin: "*",
- methods: ["GET", "POST"]
- }
-});
-
-const PORT = 80;
-const MQTT_BROKER = 'mqtt://localhost:1883';
-
-// Middleware
-app.use(cors());
-app.use(bodyParser.urlencoded({ extended: true }));
-app.use(bodyParser.json());
-app.use(express.static(path.join(__dirname, 'debug_server')));
-
-// State - simuliert ESP32 Datenstrukturen
-const state = {
- timerData1: {
- startTime: 0,
- localStartTime: 0,
- finishedSince: 0,
- endTime: 0,
- bestTime: 0,
- isRunning: false,
- isReady: true,
- isArmed: false,
- RFIDUID: ""
- },
- timerData2: {
- startTime: 0,
- localStartTime: 0,
- finishedSince: 0,
- endTime: 0,
- bestTime: 0,
- isRunning: false,
- isReady: true,
- isArmed: false,
- RFIDUID: ""
- },
- buttonConfigs: {
- start1: { mac: [0, 0, 0, 0, 0, 0], isAssigned: false, voltage: 0, lastHeartbeat: 0, heartbeatActive: false },
- stop1: { mac: [0, 0, 0, 0, 0, 0], isAssigned: false, voltage: 0, lastHeartbeat: 0, heartbeatActive: false },
- start2: { mac: [0, 0, 0, 0, 0, 0], isAssigned: false, voltage: 0, lastHeartbeat: 0, heartbeatActive: false },
- stop2: { mac: [0, 0, 0, 0, 0, 0], isAssigned: false, voltage: 0, lastHeartbeat: 0, heartbeatActive: false }
- },
- learningMode: false,
- learningStep: 0,
- maxTimeBeforeReset: 300000,
- maxTimeDisplay: 20000,
- minTimeForLeaderboard: 5000,
- masterlocation: "",
- gamemode: 0, // 0=Individual, 1=Wettkampf
- startCompetition: false,
- laneConfigType: 0,
- lane1DifficultyType: 0,
- lane2DifficultyType: 0,
- localTimes: [],
- wifi: {
- ssid: "",
- password: ""
- },
- start1FoundLocally: false,
- start2FoundLocally: false,
- start1UID: "",
- start2UID: ""
-};
-
-// Helper: millis() - simuliert Arduino millis()
-function millis() {
- return Date.now();
-}
-
-// Helper: getTimerDataJSON() - simuliert getTimerDataJSON()
-function getTimerDataJSON() {
- const currentTime = millis();
- const data = {};
-
- // Lane 1
- if (state.timerData1.isRunning) {
- data.time1 = (currentTime - state.timerData1.localStartTime) / 1000.0;
- data.status1 = "running";
- } else if (state.timerData1.endTime > 0) {
- data.time1 = (state.timerData1.endTime - state.timerData1.startTime) / 1000.0;
- data.status1 = "finished";
- } else if (state.timerData1.isArmed) {
- data.time1 = 0;
- data.status1 = "armed";
- } else {
- data.time1 = 0;
- data.status1 = "ready";
- }
-
- // Lane 2
- if (state.timerData2.isRunning) {
- data.time2 = (currentTime - state.timerData2.localStartTime) / 1000.0;
- data.status2 = "running";
- } else if (state.timerData2.endTime > 0) {
- data.time2 = (state.timerData2.endTime - state.timerData2.startTime) / 1000.0;
- data.status2 = "finished";
- } else if (state.timerData2.isArmed) {
- data.time2 = 0;
- data.status2 = "armed";
- } else {
- data.time2 = 0;
- data.status2 = "ready";
- }
-
- // Best times
- data.best1 = state.timerData1.bestTime / 1000.0;
- data.best2 = state.timerData2.bestTime / 1000.0;
-
- // Learning mode
- data.learningMode = state.learningMode;
- if (state.learningMode) {
- const buttons = ["Start Bahn 1", "Stop Bahn 1", "Start Bahn 2", "Stop Bahn 2"];
- data.learningButton = buttons[state.learningStep];
- }
-
- return JSON.stringify(data);
-}
-
-// Timer-Logik: IndividualMode
-function individualMode(action, press, lane, timestamp = 0) {
- const ts = timestamp > 0 ? timestamp : millis();
-
- if (action === "start" && press === 2 && lane === 1) {
- if (!state.timerData1.isRunning && state.timerData1.isReady) {
- state.timerData1.isReady = false;
- state.timerData1.startTime = ts;
- state.timerData1.localStartTime = millis();
- state.timerData1.isRunning = true;
- state.timerData1.endTime = 0;
- state.timerData1.isArmed = false;
- publishLaneStatus(1, "running");
- console.log("Bahn 1 gestartet");
- }
- }
-
- if (action === "stop" && press === 1 && lane === 1) {
- if (state.timerData1.isRunning) {
- state.timerData1.endTime = ts;
- state.timerData1.finishedSince = millis();
- state.timerData1.isRunning = false;
- const currentTime = state.timerData1.endTime - state.timerData1.startTime;
-
- if (state.timerData1.bestTime === 0 || currentTime < state.timerData1.bestTime) {
- state.timerData1.bestTime = currentTime;
- }
- publishLaneStatus(1, "stopped");
- console.log(`Bahn 1 gestoppt - Zeit: ${(currentTime / 1000.0).toFixed(2)}s`);
- }
- }
-
- if (action === "start" && press === 2 && lane === 2) {
- if (!state.timerData2.isRunning && state.timerData2.isReady) {
- state.timerData2.isReady = false;
- state.timerData2.startTime = ts;
- state.timerData2.localStartTime = millis();
- state.timerData2.isRunning = true;
- state.timerData2.endTime = 0;
- state.timerData2.isArmed = false;
- publishLaneStatus(2, "running");
- console.log("Bahn 2 gestartet");
- }
- }
-
- if (action === "stop" && press === 1 && lane === 2) {
- if (state.timerData2.isRunning) {
- state.timerData2.endTime = ts;
- state.timerData2.finishedSince = millis();
- state.timerData2.isRunning = false;
- const currentTime = state.timerData2.endTime - state.timerData2.startTime;
-
- if (state.timerData2.bestTime === 0 || currentTime < state.timerData2.bestTime) {
- state.timerData2.bestTime = currentTime;
- }
- publishLaneStatus(2, "stopped");
- console.log(`Bahn 2 gestoppt - Zeit: ${(currentTime / 1000.0).toFixed(2)}s`);
- }
- }
-}
-
-// Helper: publishLaneStatus
-function publishLaneStatus(lane, status) {
- if (mqttClient && mqttClient.connected) {
- const topic = `aquacross/lanes/lane${lane}`;
- const message = JSON.stringify({ lane, status });
- mqttClient.publish(topic, message);
- }
-}
-
-// Helper: pushUpdateToFrontend
-function pushUpdateToFrontend(message) {
- io.emit('update', message);
-}
-
-// MQTT Client Setup
-let mqttClient = null;
-let mqttReconnectInterval = null;
-
-function connectMQTT() {
- // Don't reconnect if already connected or connecting
- if (mqttClient && (mqttClient.connected || mqttClient.connecting)) {
- return;
- }
-
- // Clear any existing reconnect interval
- if (mqttReconnectInterval) {
- clearInterval(mqttReconnectInterval);
- mqttReconnectInterval = null;
- }
-
- // Close existing client if any
- if (mqttClient) {
- mqttClient.end(true);
- }
-
- console.log('[MQTT] Attempting to connect to broker at', MQTT_BROKER);
- mqttClient = mqtt.connect(MQTT_BROKER, {
- reconnectPeriod: 5000,
- connectTimeout: 10000,
- clientId: 'mock-esp32-' + Math.random().toString(16).substr(2, 8)
- });
-
- mqttClient.on('connect', () => {
- console.log('[MQTT] Connected to broker');
-
- // Subscribe to all relevant topics
- mqttClient.subscribe('aquacross/button/#', (err) => {
- if (!err) console.log('[MQTT] Subscribed to aquacross/button/#');
- });
- mqttClient.subscribe('aquacross/button/rfid/#', (err) => {
- if (!err) console.log('[MQTT] Subscribed to aquacross/button/rfid/#');
- });
- mqttClient.subscribe('aquacross/battery/#', (err) => {
- if (!err) console.log('[MQTT] Subscribed to aquacross/battery/#');
- });
- mqttClient.subscribe('heartbeat/alive/#', (err) => {
- if (!err) console.log('[MQTT] Subscribed to heartbeat/alive/#');
- });
- mqttClient.subscribe('aquacross/competition/toMaster', (err) => {
- if (!err) console.log('[MQTT] Subscribed to aquacross/competition/toMaster');
- });
- mqttClient.subscribe('aquacross/button/status/#', (err) => {
- if (!err) console.log('[MQTT] Subscribed to aquacross/button/status/#');
- });
- });
-
- mqttClient.on('message', (topic, message) => {
- const payload = message.toString();
- console.log(`[MQTT] Received on ${topic}: ${payload}`);
-
- // Handle different topic types
- if (topic.startsWith('aquacross/button/rfid/')) {
- handleRFIDTopic(topic, payload);
- } else if (topic.startsWith('aquacross/button/status/')) {
- handleButtonStatusTopic(topic, payload);
- } else if (topic.startsWith('aquacross/button/')) {
- handleButtonTopic(topic, payload);
- } else if (topic.startsWith('aquacross/battery/')) {
- handleBatteryTopic(topic, payload);
- } else if (topic.startsWith('heartbeat/alive/')) {
- handleHeartbeatTopic(topic, payload);
- } else if (topic === 'aquacross/competition/toMaster') {
- if (payload === 'start') {
- state.startCompetition = true;
- runCompetition();
- }
- }
- });
-
- mqttClient.on('error', (err) => {
- console.error('[MQTT] Error:', err.message || err);
- if (err.code === 'ECONNREFUSED') {
- console.log('[MQTT] Broker not available at', MQTT_BROKER, '- will retry automatically');
- }
- });
-
- mqttClient.on('close', () => {
- console.log('[MQTT] Connection closed');
- });
-
- mqttClient.on('offline', () => {
- console.log('[MQTT] Client offline, will reconnect automatically...');
- });
-
- mqttClient.on('reconnect', () => {
- console.log('[MQTT] Reconnecting to broker...');
- });
-}
-
-// MQTT Topic Handlers
-function handleButtonTopic(topic, payload) {
- try {
- const buttonId = topic.replace('aquacross/button/', '');
- const data = JSON.parse(payload);
- const pressType = data.type || 0;
- const timestamp = data.timestamp || millis();
-
- console.log(`Button Press: ${buttonId}, Type: ${pressType}, Timestamp: ${timestamp}`);
-
- // Simulate button assignment check (simplified)
- // In real implementation, would check MAC addresses
- if (state.learningMode) {
- // Handle learning mode
- return;
- }
-
- // Trigger action based on button (simplified - would check MAC in real implementation)
- if (pressType === 2) {
- // Start button
- if (buttonId.includes('start1') || buttonId.includes('00:00:00:00:00:01')) {
- individualMode("start", 2, 1, timestamp);
- } else if (buttonId.includes('start2') || buttonId.includes('00:00:00:00:00:02')) {
- individualMode("start", 2, 2, timestamp);
- }
- } else if (pressType === 1) {
- // Stop button
- if (buttonId.includes('stop1') || buttonId.includes('00:00:00:00:00:03')) {
- individualMode("stop", 1, 1, timestamp);
- } else if (buttonId.includes('stop2') || buttonId.includes('00:00:00:00:00:04')) {
- individualMode("stop", 1, 2, timestamp);
- }
- }
- } catch (err) {
- console.error('Error handling button topic:', err);
- }
-}
-
-function handleRFIDTopic(topic, payload) {
- try {
- const buttonId = topic.replace('aquacross/button/rfid/', '');
- const data = JSON.parse(payload);
- const uid = data.uid || '';
-
- console.log(`RFID Read: ${buttonId}, UID: ${uid}`);
-
- // Send to frontend
- const message = JSON.stringify({
- name: uid,
- lane: buttonId.includes('start1') ? 'start1' : 'start2'
- });
- pushUpdateToFrontend(message);
- } catch (err) {
- console.error('Error handling RFID topic:', err);
- }
-}
-
-function handleBatteryTopic(topic, payload) {
- try {
- const buttonId = topic.replace('aquacross/battery/', '');
- const data = JSON.parse(payload);
- const voltage = data.voltage || 0;
-
- console.log(`Battery: ${buttonId}, Voltage: ${voltage}`);
-
- // Update button config if known
- // Send to frontend
- const message = JSON.stringify({
- button: buttonId,
- mac: buttonId,
- batteryLevel: Math.round((voltage - 3200) / 50) // Simple calculation
- });
- pushUpdateToFrontend(message);
- } catch (err) {
- console.error('Error handling battery topic:', err);
- }
-}
-
-function handleHeartbeatTopic(topic, payload) {
- try {
- const buttonId = topic.replace('heartbeat/alive/', '');
- console.log(`Heartbeat: ${buttonId}`);
-
- // Update button heartbeat
- // Send to frontend
- const message = JSON.stringify({
- button: buttonId,
- mac: buttonId,
- active: true
- });
- pushUpdateToFrontend(message);
- } catch (err) {
- console.error('Error handling heartbeat topic:', err);
- }
-}
-
-function handleButtonStatusTopic(topic, payload) {
- try {
- const buttonId = topic.replace('aquacross/button/status/', '');
- const data = JSON.parse(payload);
- const available = data.available !== false;
- const sleep = data.sleep === true;
-
- console.log(`Button Status: ${buttonId}, Available: ${available}, Sleep: ${sleep}`);
-
- // Send to frontend
- const message = JSON.stringify({
- button: buttonId,
- mac: buttonId,
- available: available,
- sleep: sleep,
- timestamp: data.timestamp || Date.now()
- });
- pushUpdateToFrontend(message);
- } catch (err) {
- console.error('Error handling button status topic:', err);
- }
-}
-
-function runCompetition() {
- if (state.timerData1.isArmed && state.timerData2.isArmed && state.startCompetition) {
- const startNow = millis();
-
- state.timerData1.isReady = false;
- state.timerData1.startTime = startNow;
- state.timerData1.localStartTime = millis();
- state.timerData1.isRunning = true;
- state.timerData1.endTime = 0;
- state.timerData1.isArmed = false;
- publishLaneStatus(1, "running");
-
- state.timerData2.isReady = false;
- state.timerData2.startTime = startNow;
- state.timerData2.localStartTime = millis();
- state.timerData2.isRunning = true;
- state.timerData2.endTime = 0;
- state.timerData2.isArmed = false;
- publishLaneStatus(2, "running");
-
- console.log("Competition started");
- }
-}
-
-// API Routes
-app.get('/api/data', (req, res) => {
- res.json(JSON.parse(getTimerDataJSON()));
-});
-
-app.post('/api/reset-best', (req, res) => {
- state.timerData1.bestTime = 0;
- state.timerData2.bestTime = 0;
- state.localTimes = [];
- res.json({ success: true });
-});
-
-app.post('/api/unlearn-button', (req, res) => {
- state.buttonConfigs.start1.isAssigned = false;
- state.buttonConfigs.stop1.isAssigned = false;
- state.buttonConfigs.start2.isAssigned = false;
- state.buttonConfigs.stop2.isAssigned = false;
- res.json({ success: true });
-});
-
-app.post('/api/set-max-time', (req, res) => {
- if (req.body.maxTime) {
- state.maxTimeBeforeReset = parseInt(req.body.maxTime) * 1000;
- }
- if (req.body.maxTimeDisplay) {
- state.maxTimeDisplay = parseInt(req.body.maxTimeDisplay) * 1000;
- }
- if (req.body.minTimeForLeaderboard) {
- state.minTimeForLeaderboard = parseInt(req.body.minTimeForLeaderboard) * 1000;
- }
- res.json({ success: true });
-});
-
-app.get('/api/get-settings', (req, res) => {
- res.json({
- maxTime: state.maxTimeBeforeReset / 1000,
- maxTimeDisplay: state.maxTimeDisplay / 1000,
- minTimeForLeaderboard: state.minTimeForLeaderboard / 1000
- });
-});
-
-app.post('/api/start-learning', (req, res) => {
- state.learningMode = true;
- state.learningStep = 0;
- res.json({ success: true });
-});
-
-app.post('/api/stop-learning', (req, res) => {
- state.learningMode = false;
- state.learningStep = 0;
- res.json({ success: true });
-});
-
-app.get('/api/learn/status', (req, res) => {
- res.json({
- active: state.learningMode,
- step: state.learningStep
- });
-});
-
-app.get('/api/buttons/status', (req, res) => {
- res.json({
- lane1Start: state.buttonConfigs.start1.isAssigned,
- lane1StartVoltage: state.buttonConfigs.start1.voltage,
- lane1Stop: state.buttonConfigs.stop1.isAssigned,
- lane1StopVoltage: state.buttonConfigs.stop1.voltage,
- lane2Start: state.buttonConfigs.start2.isAssigned,
- lane2StartVoltage: state.buttonConfigs.start2.voltage,
- lane2Stop: state.buttonConfigs.stop2.isAssigned,
- lane2StopVoltage: state.buttonConfigs.stop2.voltage
- });
-});
-
-app.get('/api/info', (req, res) => {
- const connected = [
- state.buttonConfigs.start1.isAssigned,
- state.buttonConfigs.stop1.isAssigned,
- state.buttonConfigs.start2.isAssigned,
- state.buttonConfigs.stop2.isAssigned
- ].filter(Boolean).length;
-
- res.json({
- ip: "127.0.0.1",
- ipSTA: "127.0.0.1",
- channel: 1,
- mac: "AA:BB:CC:DD:EE:FF",
- freeMemory: 1024 * 1024,
- connectedButtons: connected,
- isOnline: true,
- valid: "Ja",
- tier: 1
- });
-});
-
-app.post('/api/set-wifi', (req, res) => {
- if (req.body.ssid) {
- state.wifi.ssid = req.body.ssid;
- state.wifi.password = req.body.password || "";
- res.json({ success: true });
- } else {
- res.status(400).json({ success: false, error: "SSID fehlt" });
- }
-});
-
-app.get('/api/get-wifi', (req, res) => {
- res.json({
- ssid: state.wifi.ssid,
- password: state.wifi.password
- });
-});
-
-app.post('/api/set-location', (req, res) => {
- if (req.body.name) {
- state.masterlocation = req.body.name;
- }
- res.json({ success: true });
-});
-
-app.get('/api/get-location', (req, res) => {
- res.json({
- locationid: state.masterlocation
- });
-});
-
-app.get('/api/updateButtons', (req, res) => {
- if (mqttClient && mqttClient.connected) {
- mqttClient.publish('aquacross/update/flag', '1');
- }
- res.json({ success: true });
-});
-
-app.post('/api/set-mode', (req, res) => {
- if (req.body.mode) {
- state.gamemode = req.body.mode === "individual" ? 0 : 1;
- res.json({ success: true });
- } else {
- res.status(400).json({ success: false, error: "Modus fehlt" });
- }
-});
-
-app.get('/api/get-mode', (req, res) => {
- res.json({
- mode: state.gamemode === 0 ? "individual" : "wettkampf"
- });
-});
-
-app.post('/api/set-lane-config', (req, res) => {
- if (req.body.type) {
- state.laneConfigType = req.body.type === "identical" ? 0 : 1;
- if (state.laneConfigType === 1) {
- if (req.body.lane1Difficulty) {
- state.lane1DifficultyType = req.body.lane1Difficulty === "light" ? 0 : 1;
- }
- if (req.body.lane2Difficulty) {
- state.lane2DifficultyType = req.body.lane2Difficulty === "light" ? 0 : 1;
- }
- }
- res.json({ success: true });
- } else {
- res.status(400).json({ success: false, error: "Lane type missing" });
- }
-});
-
-app.get('/api/get-lane-config', (req, res) => {
- const config = {
- type: state.laneConfigType === 0 ? "identical" : "different"
- };
- if (state.laneConfigType === 1) {
- config.lane1Difficulty = state.lane1DifficultyType === 0 ? "light" : "heavy";
- config.lane2Difficulty = state.lane2DifficultyType === 0 ? "light" : "heavy";
- }
- res.json(config);
-});
-
-// Debug Endpoints
-app.get('/api/debug/start1', (req, res) => {
- individualMode("start", 2, 1, millis());
- res.send("handleStart1() called");
-});
-
-app.get('/api/debug/stop1', (req, res) => {
- individualMode("stop", 1, 1, millis());
- res.send("handleStop1() called");
-});
-
-app.get('/api/debug/start2', (req, res) => {
- individualMode("start", 2, 2, millis());
- res.send("handleStart2() called");
-});
-
-app.get('/api/debug/stop2', (req, res) => {
- individualMode("stop", 1, 2, millis());
- res.send("handleStop2() called");
-});
-
-// WebSocket Setup
-io.on('connection', (socket) => {
- console.log(`[WebSocket] Client connected: ${socket.id}`);
-
- socket.on('disconnect', () => {
- console.log(`[WebSocket] Client disconnected: ${socket.id}`);
- });
-});
-
-// Time sync - publish every 5 seconds
-setInterval(() => {
- if (mqttClient && mqttClient.connected) {
- mqttClient.publish('sync/time', millis().toString());
- }
-}, 5000);
-
-// Auto-reset check
-setInterval(() => {
- const currentTime = millis();
-
- if (state.gamemode === 0) {
- // Individual mode
- if (!state.timerData1.isRunning && state.timerData1.endTime > 0 &&
- state.timerData1.finishedSince > 0) {
- if (currentTime - state.timerData1.finishedSince > state.maxTimeDisplay) {
- state.timerData1.startTime = 0;
- state.timerData1.endTime = 0;
- state.timerData1.finishedSince = 0;
- state.timerData1.isReady = true;
- publishLaneStatus(1, "ready");
- }
- }
- if (!state.timerData2.isRunning && state.timerData2.endTime > 0 &&
- state.timerData2.finishedSince > 0) {
- if (currentTime - state.timerData2.finishedSince > state.maxTimeDisplay) {
- state.timerData2.startTime = 0;
- state.timerData2.endTime = 0;
- state.timerData2.finishedSince = 0;
- state.timerData2.isReady = true;
- publishLaneStatus(2, "ready");
- }
- }
- }
-}, 1000);
-
-// Start server
-server.listen(PORT, () => {
- console.log(`[Server] Mock ESP32 Server running on port ${PORT}`);
- console.log(`[Server] Web UI available at http://localhost:${PORT}`);
-
- // Wait a moment before trying to connect to MQTT broker
- // This gives the broker time to start if both are started together
- setTimeout(() => {
- console.log('[MQTT] Attempting initial connection to broker...');
- connectMQTT();
- }, 2000);
-
- // Also set up a periodic check (backup retry mechanism)
- // Note: mqtt.js already has auto-reconnect, this is just a backup
- mqttReconnectInterval = setInterval(() => {
- if (!mqttClient || (!mqttClient.connected && !mqttClient.connecting)) {
- console.log('[MQTT] Connection check: Not connected, attempting reconnect...');
- connectMQTT();
- }
- }, 15000); // Check every 15 seconds if not connected
-});
-
-// Graceful shutdown
-process.on('SIGINT', () => {
- console.log('\n[Server] Shutting down...');
- if (mqttClient) {
- mqttClient.end();
- }
- server.close(() => {
- console.log('[Server] Server closed');
- process.exit(0);
- });
-});
diff --git a/mock-server/mqtt_broker.js b/mock-server/mqtt_broker.js
deleted file mode 100644
index 215e109..0000000
--- a/mock-server/mqtt_broker.js
+++ /dev/null
@@ -1,108 +0,0 @@
-const aedes = require('aedes')();
-const net = require('net');
-const ws = require('ws');
-const http = require('http');
-const port = 1883;
-const wsPort = 9001;
-
-// TCP Server for MQTT
-const server = net.createServer(aedes.handle);
-
-// Logging für alle Nachrichten
-aedes.on('publish', (packet, client) => {
- if (client) {
- console.log(`[MQTT] Client ${client.id} published to topic: ${packet.topic}`);
- console.log(`[MQTT] Payload: ${packet.payload.toString()}`);
- } else {
- console.log(`[MQTT] Published to topic: ${packet.topic}`);
- console.log(`[MQTT] Payload: ${packet.payload.toString()}`);
- }
-});
-
-// Client-Verbindungen
-aedes.on('client', (client) => {
- console.log(`[MQTT] Client connected: ${client.id}`);
-});
-
-aedes.on('clientDisconnect', (client) => {
- console.log(`[MQTT] Client disconnected: ${client.id}`);
-});
-
-// Fehlerbehandlung
-aedes.on('clientError', (client, err) => {
- console.error(`[MQTT] Client error for ${client.id}:`, err);
-});
-
-// WebSocket Server for browser connections
-const httpServer = http.createServer();
-const wsServer = new ws.Server({
- server: httpServer,
- path: '/mqtt'
-});
-
-wsServer.on('connection', (socket, req) => {
- // Create a proper stream adapter for Aedes
- const { Duplex } = require('stream');
-
- const stream = new Duplex({
- write(chunk, encoding, callback) {
- if (socket.readyState === ws.OPEN) {
- socket.send(chunk);
- callback();
- } else {
- callback(new Error('WebSocket is not open'));
- }
- },
- read() {
- // No-op: we push data when we receive it
- }
- });
-
- // Handle incoming WebSocket messages
- socket.on('message', (data) => {
- stream.push(data);
- });
-
- socket.on('error', (err) => {
- console.error('[MQTT] WebSocket error:', err);
- stream.destroy(err);
- });
-
- socket.on('close', () => {
- console.log('[MQTT] WebSocket client disconnected');
- stream.push(null); // End the stream
- });
-
- // Handle stream errors
- stream.on('error', (err) => {
- console.error('[MQTT] Stream error:', err);
- if (socket.readyState === ws.OPEN) {
- socket.close();
- }
- });
-
- // Pass the stream to Aedes
- aedes.handle(stream);
-});
-
-server.listen(port, () => {
- console.log(`[MQTT] TCP Broker started and listening on port ${port}`);
- console.log(`[MQTT] Ready to accept TCP connections`);
-});
-
-httpServer.listen(wsPort, () => {
- console.log(`[MQTT] WebSocket Broker started and listening on port ${wsPort}`);
- console.log(`[MQTT] Ready to accept WebSocket connections at ws://localhost:${wsPort}/mqtt`);
-});
-
-// Graceful shutdown
-process.on('SIGINT', () => {
- console.log('\n[MQTT] Shutting down broker...');
- server.close(() => {
- console.log('[MQTT] TCP server closed');
- });
- httpServer.close(() => {
- console.log('[MQTT] WebSocket server closed');
- process.exit(0);
- });
-});
diff --git a/mock-server/package-lock.json b/mock-server/package-lock.json
deleted file mode 100644
index 4a2e739..0000000
--- a/mock-server/package-lock.json
+++ /dev/null
@@ -1,1922 +0,0 @@
-{
- "name": "aquamaster-mock-server",
- "version": "1.0.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "aquamaster-mock-server",
- "version": "1.0.0",
- "license": "MIT",
- "dependencies": {
- "aedes": "^0.50.0",
- "body-parser": "^1.20.2",
- "cors": "^2.8.5",
- "express": "^4.18.2",
- "mqtt": "^5.3.1",
- "socket.io": "^4.6.1",
- "ws": "^8.14.2"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.28.6",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
- "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
- "license": "MIT",
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@socket.io/component-emitter": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
- "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
- "license": "MIT"
- },
- "node_modules/@types/cors": {
- "version": "2.8.19",
- "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
- "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/node": {
- "version": "25.0.10",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.10.tgz",
- "integrity": "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==",
- "license": "MIT",
- "dependencies": {
- "undici-types": "~7.16.0"
- }
- },
- "node_modules/@types/readable-stream": {
- "version": "4.0.23",
- "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz",
- "integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==",
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/ws": {
- "version": "8.18.1",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
- "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/abort-controller": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
- "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
- "license": "MIT",
- "dependencies": {
- "event-target-shim": "^5.0.0"
- },
- "engines": {
- "node": ">=6.5"
- }
- },
- "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/aedes": {
- "version": "0.50.1",
- "resolved": "https://registry.npmjs.org/aedes/-/aedes-0.50.1.tgz",
- "integrity": "sha512-S1P+COZYSDVYND8G+b7Vy+xoENix57QOJL8pDlwBYvr6GIiaJZFNvOy7GvUxPDxb0EBrsiPSfHHJc6aySK9Wfg==",
- "license": "MIT",
- "dependencies": {
- "aedes-packet": "^3.0.0",
- "aedes-persistence": "^9.1.2",
- "end-of-stream": "^1.4.4",
- "fastfall": "^1.5.1",
- "fastparallel": "^2.4.1",
- "fastseries": "^2.0.0",
- "hyperid": "^3.1.1",
- "mqemitter": "^5.0.0",
- "mqtt-packet": "^9.0.0",
- "retimer": "^3.0.0",
- "reusify": "^1.0.4",
- "uuid": "^9.0.0"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/aedes-packet": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/aedes-packet/-/aedes-packet-3.0.0.tgz",
- "integrity": "sha512-swASey0BxGs4/npZGWoiVDmnEyPvVFIRY6l2LVKL4rbiW8IhcIGDLfnb20Qo8U20itXlitAKPQ3MVTEbOGG5ZA==",
- "license": "MIT",
- "dependencies": {
- "mqtt-packet": "^7.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/aedes-packet/node_modules/bl": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
- "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
- "license": "MIT",
- "dependencies": {
- "buffer": "^5.5.0",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/aedes-packet/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/aedes-packet/node_modules/mqtt-packet": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-7.1.2.tgz",
- "integrity": "sha512-FFZbcZ2omsf4c5TxEQfcX9hI+JzDpDKPT46OmeIBpVA7+t32ey25UNqlqNXTmeZOr5BLsSIERpQQLsFWJS94SQ==",
- "license": "MIT",
- "dependencies": {
- "bl": "^4.0.2",
- "debug": "^4.1.1",
- "process-nextick-args": "^2.0.1"
- }
- },
- "node_modules/aedes-packet/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/aedes-packet/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/aedes-persistence": {
- "version": "9.1.2",
- "resolved": "https://registry.npmjs.org/aedes-persistence/-/aedes-persistence-9.1.2.tgz",
- "integrity": "sha512-2Wlr5pwIK0eQOkiTwb8ZF6C20s8UPUlnsJ4kXYePZ3JlQl0NbBA176mzM8wY294BJ5wybpNc9P5XEQxqadRNcQ==",
- "license": "MIT",
- "dependencies": {
- "aedes-packet": "^3.0.0",
- "qlobber": "^7.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "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/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "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/base64id": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
- "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
- "license": "MIT",
- "engines": {
- "node": "^4.5.0 || >= 5.9"
- }
- },
- "node_modules/bl": {
- "version": "6.1.6",
- "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz",
- "integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==",
- "license": "MIT",
- "dependencies": {
- "@types/readable-stream": "^4.0.0",
- "buffer": "^6.0.3",
- "inherits": "^2.0.4",
- "readable-stream": "^4.2.0"
- }
- },
- "node_modules/bl/node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
- "node_modules/body-parser": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
- "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
- "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.1",
- "iconv-lite": "~0.4.24",
- "on-finished": "~2.4.1",
- "qs": "~6.14.0",
- "raw-body": "~2.5.3",
- "type-is": "~1.6.18",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/broker-factory": {
- "version": "3.1.13",
- "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.13.tgz",
- "integrity": "sha512-H2VALe31mEtO/SRcNp4cUU5BAm1biwhc/JaF77AigUuni/1YT0FLCJfbUxwIEs9y6Kssjk2fmXgf+Y9ALvmKlw==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.28.6",
- "fast-unique-numbers": "^9.0.26",
- "tslib": "^2.8.1",
- "worker-factory": "^7.0.48"
- }
- },
- "node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "node_modules/buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
- "license": "MIT"
- },
- "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/commist": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
- "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==",
- "license": "MIT"
- },
- "node_modules/concat-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
- "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
- "engines": [
- "node >= 6.0"
- ],
- "license": "MIT",
- "dependencies": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^3.0.2",
- "typedarray": "^0.0.6"
- }
- },
- "node_modules/concat-stream/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "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.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.0.7",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
- "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
- "license": "MIT"
- },
- "node_modules/cors": {
- "version": "2.8.6",
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
- "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
- "license": "MIT",
- "dependencies": {
- "object-assign": "^4",
- "vary": "^1"
- },
- "engines": {
- "node": ">= 0.10"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "license": "MIT",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/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/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/end-of-stream": {
- "version": "1.4.5",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
- "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
- "license": "MIT",
- "dependencies": {
- "once": "^1.4.0"
- }
- },
- "node_modules/engine.io": {
- "version": "6.6.5",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz",
- "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==",
- "license": "MIT",
- "dependencies": {
- "@types/cors": "^2.8.12",
- "@types/node": ">=10.0.0",
- "accepts": "~1.3.4",
- "base64id": "2.0.0",
- "cookie": "~0.7.2",
- "cors": "~2.8.5",
- "debug": "~4.4.1",
- "engine.io-parser": "~5.2.1",
- "ws": "~8.18.3"
- },
- "engines": {
- "node": ">=10.2.0"
- }
- },
- "node_modules/engine.io-parser": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
- "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/engine.io/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/engine.io/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/engine.io/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
- }
- }
- },
- "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/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/event-target-shim": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
- "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/events": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "license": "MIT",
- "engines": {
- "node": ">=0.8.x"
- }
- },
- "node_modules/express": {
- "version": "4.22.1",
- "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
- "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
- "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.14.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/fast-unique-numbers": {
- "version": "9.0.26",
- "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.26.tgz",
- "integrity": "sha512-3Mtq8p1zQinjGyWfKeuBunbuFoixG72AUkk4VvzbX4ykCW9Q4FzRaNyIlfQhUjnKw2ARVP+/CKnoyr6wfHftig==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.28.6",
- "tslib": "^2.8.1"
- },
- "engines": {
- "node": ">=18.2.0"
- }
- },
- "node_modules/fastfall": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz",
- "integrity": "sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==",
- "license": "MIT",
- "dependencies": {
- "reusify": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/fastparallel": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.4.1.tgz",
- "integrity": "sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==",
- "license": "ISC",
- "dependencies": {
- "reusify": "^1.0.4",
- "xtend": "^4.0.2"
- }
- },
- "node_modules/fastseries": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-2.0.0.tgz",
- "integrity": "sha512-XBU9RXeoYc2/VnvMhplAxEmZLfIk7cvTBu+xwoBuTI8pL19E03cmca17QQycKIdxgwCeFA/a4u27gv1h3ya5LQ==",
- "license": "ISC"
- },
- "node_modules/finalhandler": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
- "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
- "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.2",
- "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/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/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-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/help-me": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
- "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
- "license": "MIT"
- },
- "node_modules/http-errors": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
- "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
- "license": "MIT",
- "dependencies": {
- "depd": "~2.0.0",
- "inherits": "~2.0.4",
- "setprototypeof": "~1.2.0",
- "statuses": "~2.0.2",
- "toidentifier": "~1.0.1"
- },
- "engines": {
- "node": ">= 0.8"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/hyperid": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-3.3.0.tgz",
- "integrity": "sha512-7qhCVT4MJIoEsNcbhglhdmBKb09QtcmJNiIQGq7js/Khf5FtQQ9bzcAuloeqBeee7XD7JqDeve9KNlQya5tSGQ==",
- "license": "MIT",
- "dependencies": {
- "buffer": "^5.2.1",
- "uuid": "^8.3.2",
- "uuid-parse": "^1.1.0"
- }
- },
- "node_modules/hyperid/node_modules/uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
- "license": "MIT",
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
- "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/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "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": "BSD-3-Clause"
- },
- "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/ip-address": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
- "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
- "license": "MIT",
- "engines": {
- "node": ">= 12"
- }
- },
- "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/js-sdsl": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
- "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/js-sdsl"
- }
- },
- "node_modules/lru-cache": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
- "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
- "license": "ISC"
- },
- "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/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/mqemitter": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/mqemitter/-/mqemitter-5.0.0.tgz",
- "integrity": "sha512-rqNRQhGgl0W/NV+Zrx0rpAUTZcSlAtivCVUmXBUPcFYt+AeDEpoJgy5eKlFWJP6xnatONL59WIFdV0W6niOMhw==",
- "license": "ISC",
- "dependencies": {
- "fastparallel": "^2.3.0",
- "qlobber": "^7.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/mqtt": {
- "version": "5.14.1",
- "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.14.1.tgz",
- "integrity": "sha512-NxkPxE70Uq3Ph7goefQa7ggSsVzHrayCD0OyxlJgITN/EbzlZN+JEPmaAZdxP1LsIT5FamDyILoQTF72W7Nnbw==",
- "license": "MIT",
- "dependencies": {
- "@types/readable-stream": "^4.0.21",
- "@types/ws": "^8.18.1",
- "commist": "^3.2.0",
- "concat-stream": "^2.0.0",
- "debug": "^4.4.1",
- "help-me": "^5.0.0",
- "lru-cache": "^10.4.3",
- "minimist": "^1.2.8",
- "mqtt-packet": "^9.0.2",
- "number-allocator": "^1.0.14",
- "readable-stream": "^4.7.0",
- "rfdc": "^1.4.1",
- "socks": "^2.8.6",
- "split2": "^4.2.0",
- "worker-timers": "^8.0.23",
- "ws": "^8.18.3"
- },
- "bin": {
- "mqtt": "build/bin/mqtt.js",
- "mqtt_pub": "build/bin/pub.js",
- "mqtt_sub": "build/bin/sub.js"
- },
- "engines": {
- "node": ">=16.0.0"
- }
- },
- "node_modules/mqtt-packet": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz",
- "integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==",
- "license": "MIT",
- "dependencies": {
- "bl": "^6.0.8",
- "debug": "^4.3.4",
- "process-nextick-args": "^2.0.1"
- }
- },
- "node_modules/mqtt-packet/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/mqtt-packet/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/mqtt/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/mqtt/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/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "license": "MIT"
- },
- "node_modules/negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/number-allocator": {
- "version": "1.0.14",
- "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
- "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
- "license": "MIT",
- "dependencies": {
- "debug": "^4.3.1",
- "js-sdsl": "4.3.0"
- }
- },
- "node_modules/number-allocator/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/number-allocator/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/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
- "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "license": "MIT",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "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": "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/process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6.0"
- }
- },
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "license": "MIT"
- },
- "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/qlobber": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/qlobber/-/qlobber-7.0.1.tgz",
- "integrity": "sha512-FsFg9lMuMEFNKmTO9nV7tlyPhx8BmskPPjH2akWycuYVTtWaVwhW5yCHLJQ6Q+3mvw5cFX2vMfW2l9z2SiYAbg==",
- "license": "MIT",
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/qs": {
- "version": "6.14.1",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
- "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
- "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": "2.5.3",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
- "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
- "license": "MIT",
- "dependencies": {
- "bytes": "~3.1.2",
- "http-errors": "~2.0.1",
- "iconv-lite": "~0.4.24",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/readable-stream": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
- "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
- "license": "MIT",
- "dependencies": {
- "abort-controller": "^3.0.0",
- "buffer": "^6.0.3",
- "events": "^3.3.0",
- "process": "^0.11.10",
- "string_decoder": "^1.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/readable-stream/node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
- "node_modules/retimer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz",
- "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==",
- "license": "MIT"
- },
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rfdc": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
- "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
- "license": "MIT"
- },
- "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": "0.19.2",
- "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
- "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
- "license": "MIT",
- "dependencies": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "~0.5.2",
- "http-errors": "~2.0.1",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "~2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "~2.0.2"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "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.3",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
- "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
- "license": "MIT",
- "dependencies": {
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "~0.19.1"
- },
- "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/smart-buffer": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
- "license": "MIT",
- "engines": {
- "node": ">= 6.0.0",
- "npm": ">= 3.0.0"
- }
- },
- "node_modules/socket.io": {
- "version": "4.8.3",
- "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz",
- "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==",
- "license": "MIT",
- "dependencies": {
- "accepts": "~1.3.4",
- "base64id": "~2.0.0",
- "cors": "~2.8.5",
- "debug": "~4.4.1",
- "engine.io": "~6.6.0",
- "socket.io-adapter": "~2.5.2",
- "socket.io-parser": "~4.2.4"
- },
- "engines": {
- "node": ">=10.2.0"
- }
- },
- "node_modules/socket.io-adapter": {
- "version": "2.5.6",
- "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz",
- "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==",
- "license": "MIT",
- "dependencies": {
- "debug": "~4.4.1",
- "ws": "~8.18.3"
- }
- },
- "node_modules/socket.io-adapter/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/socket.io-adapter/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/socket.io-adapter/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
- }
- }
- },
- "node_modules/socket.io-parser": {
- "version": "4.2.5",
- "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
- "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==",
- "license": "MIT",
- "dependencies": {
- "@socket.io/component-emitter": "~3.1.0",
- "debug": "~4.4.1"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/socket.io-parser/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/socket.io-parser/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/socket.io/node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/socket.io/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/socks": {
- "version": "2.8.7",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
- "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
- "license": "MIT",
- "dependencies": {
- "ip-address": "^10.0.1",
- "smart-buffer": "^4.2.0"
- },
- "engines": {
- "node": ">= 10.0.0",
- "npm": ">= 3.0.0"
- }
- },
- "node_modules/split2": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
- "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
- "license": "ISC",
- "engines": {
- "node": ">= 10.x"
- }
- },
- "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_decoder": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "license": "MIT",
- "dependencies": {
- "safe-buffer": "~5.2.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/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/typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
- "license": "MIT"
- },
- "node_modules/undici-types": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
- "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
- "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/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "license": "MIT"
- },
- "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/uuid": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
- "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
- "funding": [
- "https://github.com/sponsors/broofa",
- "https://github.com/sponsors/ctavan"
- ],
- "license": "MIT",
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
- "node_modules/uuid-parse": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/uuid-parse/-/uuid-parse-1.1.0.tgz",
- "integrity": "sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==",
- "license": "MIT"
- },
- "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/worker-factory": {
- "version": "7.0.48",
- "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.48.tgz",
- "integrity": "sha512-CGmBy3tJvpBPjUvb0t4PrpKubUsfkI1Ohg0/GGFU2RvA9j/tiVYwKU8O7yu7gH06YtzbeJLzdUR29lmZKn5pag==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.28.6",
- "fast-unique-numbers": "^9.0.26",
- "tslib": "^2.8.1"
- }
- },
- "node_modules/worker-timers": {
- "version": "8.0.29",
- "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.29.tgz",
- "integrity": "sha512-9jk0MWHhWAZ2xlJPXr45oe5UF/opdpfZrY0HtyPizWuJ+ce1M3IYk/4IIdGct3kn9Ncfs+tkZt3w1tU6KW2Fsg==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.28.6",
- "tslib": "^2.8.1",
- "worker-timers-broker": "^8.0.15",
- "worker-timers-worker": "^9.0.13"
- }
- },
- "node_modules/worker-timers-broker": {
- "version": "8.0.15",
- "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.15.tgz",
- "integrity": "sha512-Te+EiVUMzG5TtHdmaBZvBrZSFNauym6ImDaCAnzQUxvjnw+oGjMT2idmAOgDy30vOZMLejd0bcsc90Axu6XPWA==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.28.6",
- "broker-factory": "^3.1.13",
- "fast-unique-numbers": "^9.0.26",
- "tslib": "^2.8.1",
- "worker-timers-worker": "^9.0.13"
- }
- },
- "node_modules/worker-timers-worker": {
- "version": "9.0.13",
- "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.13.tgz",
- "integrity": "sha512-qjn18szGb1kjcmh2traAdki1eiIS5ikFo+L90nfMOvSRpuDw1hAcR1nzkP2+Hkdqz5thIRnfuWx7QSpsEUsA6Q==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.28.6",
- "tslib": "^2.8.1",
- "worker-factory": "^7.0.48"
- }
- },
- "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/ws": {
- "version": "8.19.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
- "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
- "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
- }
- }
- },
- "node_modules/xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.4"
- }
- }
- }
-}
diff --git a/mock-server/package.json b/mock-server/package.json
deleted file mode 100644
index d6bd65a..0000000
--- a/mock-server/package.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "aquamaster-mock-server",
- "version": "1.0.0",
- "description": "Mock ESP32 Server and MQTT Broker for testing AquaMaster without hardware",
- "main": "start_all.js",
- "scripts": {
- "start": "node start_all.js",
- "mqtt": "node mqtt_broker.js",
- "server": "node mock_esp32_server.js"
- },
- "keywords": [
- "mqtt",
- "esp32",
- "mock",
- "testing"
- ],
- "author": "",
- "license": "MIT",
- "dependencies": {
- "aedes": "^0.50.0",
- "express": "^4.18.2",
- "socket.io": "^4.6.1",
- "mqtt": "^5.3.1",
- "cors": "^2.8.5",
- "body-parser": "^1.20.2",
- "ws": "^8.14.2"
- }
-}
diff --git a/mock-server/start_all.js b/mock-server/start_all.js
deleted file mode 100644
index 2dde6d2..0000000
--- a/mock-server/start_all.js
+++ /dev/null
@@ -1,47 +0,0 @@
-const { spawn } = require('child_process');
-const path = require('path');
-
-console.log('Starting AquaMaster Mock Server...\n');
-
-// Start MQTT Broker
-console.log('[1/2] Starting MQTT Broker...');
-const mqttBroker = spawn('node', [path.join(__dirname, 'mqtt_broker.js')], {
- stdio: 'inherit',
- cwd: __dirname
-});
-
-mqttBroker.on('error', (err) => {
- console.error('Failed to start MQTT Broker:', err);
- process.exit(1);
-});
-
-// Wait a bit longer for MQTT broker to fully start
-setTimeout(() => {
- // Start Mock ESP32 Server
- console.log('[2/2] Starting Mock ESP32 Server...');
- const mockServer = spawn('node', [path.join(__dirname, 'mock_esp32_server.js')], {
- stdio: 'inherit',
- cwd: __dirname
- });
-
- mockServer.on('error', (err) => {
- console.error('Failed to start Mock ESP32 Server:', err);
- mqttBroker.kill();
- process.exit(1);
- });
-
- // Handle shutdown
- const shutdown = () => {
- console.log('\nShutting down servers...');
- if (mqttBroker && !mqttBroker.killed) {
- mqttBroker.kill();
- }
- if (mockServer && !mockServer.killed) {
- mockServer.kill();
- }
- process.exit(0);
- };
-
- process.on('SIGINT', shutdown);
- process.on('SIGTERM', shutdown);
-}, 3000); // Increased wait time to 3 seconds