From 0894a9c21e1c9c7e6e2d882478e67021a87bf107 Mon Sep 17 00:00:00 2001 From: Mohan K Date: Tue, 28 Jul 2026 12:50:28 +0530 Subject: [PATCH] Initial commit of SOP Monitoring Dashboard --- .gitignore | 8 + Consolidated_report.xlsx | Bin 0 -> 23815 bytes ...lidated_report_v2_with_feed-names (1).xlsx | Bin 0 -> 22734 bytes api/.dockerignore | 3 + api/Dockerfile | 7 + api/ecosystem.config.js | 14 + api/index.js | 178 ++ api/package-lock.json | 1963 +++++++++++++++++ api/package.json | 19 + db/schema.sql | 12 + docker-compose.yaml | 39 + ingestion/explore.js | 16 + ingestion/package-lock.json | 279 +++ ingestion/package.json | 17 + ingestion/parse.js | 137 ++ ingestion/test.js | 4 + nginx/nginx.conf | 18 + package-lock.json | 119 + package.json | 15 + ui/.dockerignore | 3 + ui/.gitignore | 24 + ui/.oxlintrc.json | 8 + ui/Dockerfile | 13 + ui/README.md | 16 + ui/index.html | 13 + ui/package-lock.json | 1798 +++++++++++++++ ui/package.json | 26 + ui/public/favicon.svg | 1 + ui/public/icons.svg | 24 + ui/src/App.css | 184 ++ ui/src/App.jsx | 22 + ui/src/assets/hero.png | Bin 0 -> 13057 bytes ui/src/assets/react.svg | 1 + ui/src/assets/vite.svg | 1 + ui/src/components/ChangeoverDetail.jsx | 283 +++ ui/src/components/ConsolidatedHome.jsx | 84 + ui/src/components/EventTimeline.jsx | 133 ++ ui/src/index.css | 177 ++ ui/src/main.jsx | 10 + ui/vite.config.js | 7 + 40 files changed, 5676 insertions(+) create mode 100644 .gitignore create mode 100644 Consolidated_report.xlsx create mode 100644 Consolidated_report_v2_with_feed-names (1).xlsx create mode 100644 api/.dockerignore create mode 100644 api/Dockerfile create mode 100644 api/ecosystem.config.js create mode 100644 api/index.js create mode 100644 api/package-lock.json create mode 100644 api/package.json create mode 100644 db/schema.sql create mode 100644 docker-compose.yaml create mode 100644 ingestion/explore.js create mode 100644 ingestion/package-lock.json create mode 100644 ingestion/package.json create mode 100644 ingestion/parse.js create mode 100644 ingestion/test.js create mode 100644 nginx/nginx.conf create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 ui/.dockerignore create mode 100644 ui/.gitignore create mode 100644 ui/.oxlintrc.json create mode 100644 ui/Dockerfile create mode 100644 ui/README.md create mode 100644 ui/index.html create mode 100644 ui/package-lock.json create mode 100644 ui/package.json create mode 100644 ui/public/favicon.svg create mode 100644 ui/public/icons.svg create mode 100644 ui/src/App.css create mode 100644 ui/src/App.jsx create mode 100644 ui/src/assets/hero.png create mode 100644 ui/src/assets/react.svg create mode 100644 ui/src/assets/vite.svg create mode 100644 ui/src/components/ChangeoverDetail.jsx create mode 100644 ui/src/components/ConsolidatedHome.jsx create mode 100644 ui/src/components/EventTimeline.jsx create mode 100644 ui/src/index.css create mode 100644 ui/src/main.jsx create mode 100644 ui/vite.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f316ea5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +dist/ +.env +.DS_Store +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/Consolidated_report.xlsx b/Consolidated_report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b9b5fb7d1c0557fc6df9f7363eeab9a9c9bd4b08 GIT binary patch literal 23815 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 G)&Bw1*>-IJ literal 0 HcmV?d00001 diff --git a/Consolidated_report_v2_with_feed-names (1).xlsx b/Consolidated_report_v2_with_feed-names (1).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0dd491988e7fc4c2e531b656e21cb21e627747a3 GIT binary patch literal 22734 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 literal 0 HcmV?d00001 diff --git a/api/.dockerignore b/api/.dockerignore new file mode 100644 index 0000000..9c97bbd --- /dev/null +++ b/api/.dockerignore @@ -0,0 +1,3 @@ +node_modules +dist +.env diff --git a/api/Dockerfile b/api/Dockerfile new file mode 100644 index 0000000..e709cc2 --- /dev/null +++ b/api/Dockerfile @@ -0,0 +1,7 @@ +FROM node:20-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm install +RUN npm install -g pm2 +COPY . . +CMD ["pm2-runtime", "ecosystem.config.js"] diff --git a/api/ecosystem.config.js b/api/ecosystem.config.js new file mode 100644 index 0000000..874669c --- /dev/null +++ b/api/ecosystem.config.js @@ -0,0 +1,14 @@ +module.exports = { + apps: [{ + name: "sop-api", + script: "./index.js", + instances: "max", + exec_mode: "cluster", + env: { + NODE_ENV: "development", + }, + env_production: { + NODE_ENV: "production", + } + }] +} diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..3b9b976 --- /dev/null +++ b/api/index.js @@ -0,0 +1,178 @@ +const express = require('express'); +const { Pool } = require('pg'); +const cors = require('cors'); +require('dotenv').config(); + +const app = express(); +app.use(cors()); +app.use(express.json()); + +const pool = new Pool({ + user: process.env.DB_USER || 'admin', + host: process.env.DB_HOST || 'localhost', + database: process.env.DB_NAME || 'sop_monitoring', + password: process.env.DB_PASS || 'password', + port: process.env.DB_PORT || 5432, +}); + +app.get('/api/changeovers', async (req, res) => { + try { + const result = await pool.query('SELECT DISTINCT changeover_id, changeover_date FROM events ORDER BY changeover_date DESC'); + res.json(result.rows); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +app.get('/api/events', async (req, res) => { + try { + const { camera_zone, state, changeover_id } = req.query; + let query = 'SELECT * FROM events WHERE 1=1'; + let values = []; + + if (camera_zone) { + values.push(camera_zone); + query += ` AND camera_zone = $${values.length}`; + } + if (state) { + values.push(state); + query += ` AND state = $${values.length}`; + } + if (changeover_id) { + values.push(changeover_id); + query += ` AND changeover_id = $${values.length}`; + } + query += ' ORDER BY start_time ASC'; + + const result = await pool.query(query, values); + res.json(result.rows); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +app.get('/api/analytics/idle-time', async (req, res) => { + try { + const { changeover_id } = req.query; + let filter = changeover_id ? `AND changeover_id = $1` : ''; + let params = changeover_id ? [changeover_id] : []; + + // 1. CO Idle Time: Sum of all events marked Waste in CO + const coResult = await pool.query(` + SELECT SUM(state_duration_seconds) as total_idle + FROM events + WHERE camera_zone = 'CO' AND state = 'Waste' ${filter} + `, params); + const coIdle = parseInt(coResult.rows[0].total_idle || 0); + + // 2. Mill Idle Time: Sum of Waste in Mill + specific Mill gap/idle + const millResult = await pool.query(` + SELECT SUM(state_duration_seconds) as total_idle + FROM events + WHERE camera_zone = 'Mill' AND (state = 'Waste' OR state = 'Idle') ${filter} + `, params); + const millIdle = parseInt(millResult.rows[0].total_idle || 0); + + // 3. Conveyor Idle Time: Sum of No Load (Waste) + Load waiting before start + const conveyorResult = await pool.query(` + SELECT SUM(state_duration_seconds) as total_idle + FROM events + WHERE camera_zone = 'Conveyor' AND (state = 'Waste' OR state = 'Load waiting') ${filter} + `, params); + const conveyorIdle = parseInt(conveyorResult.rows[0].total_idle || 0); + + res.json({ + CO: coIdle, + Mill: millIdle, + Conveyor: conveyorIdle + }); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +app.get('/api/analytics/bottlenecks', async (req, res) => { + try { + const { changeover_id } = req.query; + let filter = changeover_id ? `AND changeover_id = $1` : ''; + let params = changeover_id ? [changeover_id] : []; + + const result = await pool.query(` + SELECT event_description, camera_zone, SUM(state_duration_seconds) as total_duration, COUNT(*) as occurrences + FROM events + WHERE state IN ('Waste', 'Idle', 'Load waiting') ${filter} + GROUP BY event_description, camera_zone + ORDER BY total_duration DESC + LIMIT 10 + `, params); + res.json(result.rows); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +app.get('/api/analytics/sop-compliance', async (req, res) => { + try { + const { changeover_id } = req.query; + let filter = changeover_id ? `AND changeover_id = $1` : ''; + let params = changeover_id ? [changeover_id] : []; + + // 1. Conveyor must be started 15 mins before changeover + const coStartResult = await pool.query(`SELECT start_time FROM events WHERE camera_zone = 'CO' ${filter} ORDER BY start_time ASC LIMIT 1`, params); + const convStartResult = await pool.query(`SELECT start_time FROM events WHERE camera_zone = 'Conveyor' AND (event_description ILIKE '%Started%' OR event_description ILIKE '%Active%') ${filter} ORDER BY start_time ASC LIMIT 1`, params); + + let conveyorCompliance = { rule: "Conveyor started 15 min before CO", status: "Unknown", detail: "" }; + if (coStartResult.rows.length > 0 && convStartResult.rows.length > 0) { + const coTime = coStartResult.rows[0].start_time; + const convTime = convStartResult.rows[0].start_time; + // Compare times (assuming same day) + const coDate = new Date(`1970-01-01T${coTime}Z`); + const convDate = new Date(`1970-01-01T${convTime}Z`); + const diffMins = (coDate - convDate) / 60000; + + if (diffMins >= 15) { + conveyorCompliance.status = "Pass"; + conveyorCompliance.detail = `Started ${diffMins.toFixed(1)} mins before CO`; + } else { + conveyorCompliance.status = "Fail"; + if (diffMins > 0) conveyorCompliance.detail = `Started only ${diffMins.toFixed(1)} mins before CO`; + else conveyorCompliance.detail = `Started ${Math.abs(diffMins).toFixed(1)} mins AFTER CO`; + } + } + + // 2. Mill should be completed within 15 mins after pushout rubber collection + const pushoutResult = await pool.query(`SELECT end_time FROM events WHERE event_description ILIKE '%Pushout of Rubber - 4%' ${filter} ORDER BY end_time DESC LIMIT 1`, params); + const millCompleteResult = await pool.query(`SELECT end_time FROM events WHERE camera_zone = 'Mill' AND event_description ILIKE '%Sheeting Out - 3%' ${filter} ORDER BY end_time DESC LIMIT 1`, params); + + let millCompliance = { rule: "Mill completed within 15 min of Pushout", status: "Unknown", detail: "" }; + if (pushoutResult.rows.length > 0 && millCompleteResult.rows.length > 0) { + const pushoutTime = pushoutResult.rows[0].end_time; + const millTime = millCompleteResult.rows[0].end_time; + const pushoutDate = new Date(`1970-01-01T${pushoutTime}Z`); + const millDate = new Date(`1970-01-01T${millTime}Z`); + const diffMins = (millDate - pushoutDate) / 60000; + + if (diffMins <= 15 && diffMins >= 0) { + millCompliance.status = "Pass"; + millCompliance.detail = `Completed in ${diffMins.toFixed(1)} mins`; + } else { + millCompliance.status = "Fail"; + millCompliance.detail = `Completed in ${diffMins.toFixed(1)} mins (limit 15)`; + } + } + + res.json([conveyorCompliance, millCompliance]); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); +}); diff --git a/api/package-lock.json b/api/package-lock.json new file mode 100644 index 0000000..91b3959 --- /dev/null +++ b/api/package-lock.json @@ -0,0 +1,1963 @@ +{ + "name": "api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "api", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "cors": "^2.8.6", + "dotenv": "^17.4.2", + "express": "^5.2.1", + "pg": "^8.22.0", + "pm2": "^7.0.3" + } + }, + "node_modules/@pm2/blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@pm2/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha512-ZcNHqQjMuNRcQ7Z1zJbFIQZO/BDKV3KbiTckWdfbUaYhj7uNmUwb+FbdDWSCkvxNr9dBJQwvV17o6QBkAvgO0g==", + "license": "MIT", + "bin": { + "blessed": "bin/tput.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@pm2/js-api": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.8.1.tgz", + "integrity": "sha512-n9tDOz1ojyDOs05XthEXrLFVQYbbh2oAN19UakLPyEZDrUyEq05h8wIZU8+dNXBQY/KeFlWMLVA76nnX52ofRg==", + "license": "Apache-2", + "dependencies": { + "async": "^2.6.3", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "extrareqp2": "^1.0.0", + "ws": "^8.21.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@pm2/js-api/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/js-api/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@pm2/pm2-version-check": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", + "integrity": "sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.1" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/amp": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", + "integrity": "sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==", + "license": "MIT" + }, + "node_modules/amp-message": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", + "integrity": "sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==", + "license": "MIT", + "dependencies": { + "amp": "0.3.1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.0.0-node10", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.0.0-node10.tgz", + "integrity": "sha512-BRrU0Bo1X9dFGw6KgGz6hWrqQuOlVEDOzkb0QSLZY9sXHqA7pNj7yHPVJRz7y/rj4EOJ3d/D5uxH+ee9leYgsg==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cli-tableau": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", + "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", + "dependencies": { + "chalk": "3.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/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/croner": { + "version": "4.1.97", + "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", + "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/dayjs": { + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.15.tgz", + "integrity": "sha512-MC+DfnSWiM9APs7fpiurHGCoeIx0Gdl6QZBy+5lu8MbYKN5FZEXqOgrundfibdfhGZ15o9hzmZ2xJjZnbvgKXQ==", + "license": "MIT" + }, + "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/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "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/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "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/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", + "license": "MIT" + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extrareqp2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extrareqp2/-/extrareqp2-1.0.0.tgz", + "integrity": "sha512-Gum0g1QYb6wpPJCVypWP3bbIuaibcFiJcpuPM10YSXp/tzqi84x9PJageob+eN4xVRIOto4wjSGNLyMD54D2xA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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.3.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.3.1.tgz", + "integrity": "sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==", + "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/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pg": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz", + "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.14.0", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.15.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz", + "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz", + "integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz", + "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz", + "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidusage": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-4.0.1.tgz", + "integrity": "sha512-yCH2dtLHfEBnzlHUJymR/Z1nN2ePG3m392Mv8TFlTP1B0xkpMQNHAnfkY0n2tAi6ceKO6YWhxYfZ96V4vVkh/g==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/pm2": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-7.0.3.tgz", + "integrity": "sha512-zRJOdburpb9OEPB0uqoNT8C1Gp7hPJPVy4Kr67XJNuT9UlMQcOt1WXrYQUmwqKPHk8FyauvP1CPhqoCrCaPw0Q==", + "license": "AGPL-3.0", + "dependencies": { + "@pm2/blessed": "0.1.81", + "@pm2/js-api": "0.8.1", + "@pm2/pm2-version-check": "1.0.4", + "amp": "0.3.1", + "amp-message": "0.1.2", + "ansis": "4.0.0-node10", + "async": "3.2.6", + "chokidar": "3.6.0", + "cli-tableau": "2.0.1", + "commander": "2.15.1", + "croner": "4.1.97", + "dayjs": "1.11.15", + "debug": "4.4.3", + "eventemitter2": "6.4.9", + "fast-json-patch": "3.1.1", + "js-yaml": "4.3.0", + "pidusage": "4.0.1", + "pm2-deploy": "1.0.2", + "proxy-agent": "6.5.0", + "semver": "7.7.2", + "tx2": "1.0.5", + "ws": "8.21.0" + }, + "bin": { + "pm2": "bin/pm2", + "pm2-dev": "bin/pm2-dev", + "pm2-docker": "bin/pm2-docker", + "pm2-runtime": "bin/pm2-runtime" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/pm2-deploy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-1.0.2.tgz", + "integrity": "sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==", + "license": "MIT", + "dependencies": { + "run-series": "^1.1.8", + "tv4": "^1.3.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "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/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "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.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "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/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.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/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/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/tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==", + "license": [ + { + "type": "Public Domain", + "url": "http://geraintluff.github.io/tv4/LICENSE.txt" + }, + { + "type": "MIT", + "url": "http://jsonary.com/LICENSE.txt" + } + ], + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tx2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", + "integrity": "sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==", + "license": "MIT", + "dependencies": { + "json-stringify-safe": "^5.0.1" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "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/api/package.json b/api/package.json new file mode 100644 index 0000000..b2455c3 --- /dev/null +++ b/api/package.json @@ -0,0 +1,19 @@ +{ + "name": "api", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "cors": "^2.8.6", + "dotenv": "^17.4.2", + "express": "^5.2.1", + "pg": "^8.22.0", + "pm2": "^7.0.3" + } +} diff --git a/db/schema.sql b/db/schema.sql new file mode 100644 index 0000000..6a76c96 --- /dev/null +++ b/db/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS events ( + id SERIAL PRIMARY KEY, + changeover_id VARCHAR(100), + changeover_date DATE, + start_time TIME, + end_time TIME, + duration_seconds INTEGER, + camera_zone VARCHAR(50), + event_description TEXT, + state VARCHAR(50), + state_duration_seconds INTEGER +); diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..a83ac83 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,39 @@ +version: '3.8' +services: + db: + image: postgres:15 + environment: + POSTGRES_USER: admin + POSTGRES_PASSWORD: password + POSTGRES_DB: sop_monitoring + ports: + - "5432:5432" + volumes: + - ./db:/docker-entrypoint-initdb.d + - pgdata:/var/lib/postgresql/data + + api: + build: ./api + environment: + - DB_HOST=db + - DB_USER=admin + - DB_PASS=password + - DB_NAME=sop_monitoring + - DB_PORT=5432 + - PORT=3000 + depends_on: + - db + restart: always + + ui: + build: ./ui + ports: + - "8080:80" + volumes: + - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf + depends_on: + - api + restart: always + +volumes: + pgdata: diff --git a/ingestion/explore.js b/ingestion/explore.js new file mode 100644 index 0000000..2aed9ca --- /dev/null +++ b/ingestion/explore.js @@ -0,0 +1,16 @@ +const xlsx = require('xlsx'); +const fs = require('fs'); +const filePath = 'd:\\Projects\\AI SOP Monitoring\\Consolidated_report_v2_with_feed-names (1).xlsx'; +const workbook = xlsx.readFile(filePath); + +console.log("Sheets found:", workbook.SheetNames); + +const timeMatrixSheet = workbook.SheetNames.find(s => s.toLowerCase() === 'time matrix'); +if (timeMatrixSheet) { + console.log("First 10 rows of Time Matrix:"); + const sheet = workbook.Sheets[timeMatrixSheet]; + const data = xlsx.utils.sheet_to_json(sheet, { header: 1 }); + console.log(data.slice(0, 10)); +} else { + console.log("Time Matrix sheet not found."); +} diff --git a/ingestion/package-lock.json b/ingestion/package-lock.json new file mode 100644 index 0000000..41f3c6f --- /dev/null +++ b/ingestion/package-lock.json @@ -0,0 +1,279 @@ +{ + "name": "ingestion", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ingestion", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^17.4.2", + "pg": "^8.22.0", + "xlsx": "^0.18.5" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/pg": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz", + "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.14.0", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.15.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz", + "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz", + "integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz", + "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz", + "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.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/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "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/ingestion/package.json b/ingestion/package.json new file mode 100644 index 0000000..d8b715c --- /dev/null +++ b/ingestion/package.json @@ -0,0 +1,17 @@ +{ + "name": "ingestion", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "dotenv": "^17.4.2", + "pg": "^8.22.0", + "xlsx": "^0.18.5" + } +} diff --git a/ingestion/parse.js b/ingestion/parse.js new file mode 100644 index 0000000..c6fa833 --- /dev/null +++ b/ingestion/parse.js @@ -0,0 +1,137 @@ +const xlsx = require('xlsx'); +const { Client } = require('pg'); +const path = require('path'); + +const filePath = path.join(__dirname, '..', 'Consolidated_report_v2_with_feed-names (1).xlsx'); + +const client = new Client({ + user: 'admin', + host: 'localhost', + database: 'sop_monitoring', + password: 'password', + port: 5432, +}); + +function parseDuration(durationStr) { + if (!durationStr) return 0; + const hMatch = durationStr.match(/(\d+)h/); + const mMatch = durationStr.match(/(\d+)m/); + const sMatch = durationStr.match(/(\d+)s/); + + let seconds = 0; + if (hMatch) seconds += parseInt(hMatch[1]) * 3600; + if (mMatch) seconds += parseInt(mMatch[1]) * 60; + if (sMatch) seconds += parseInt(sMatch[1]); + return seconds; +} + +function parseCellEvents(cellText, cameraZone, startTime, endTime, totalDuration) { + if (!cellText) return []; + const events = []; + const blocks = cellText.split(/\r?\n---\r?\n/); + + for (const block of blocks) { + const lines = block.split(/\r?\n/); + if (lines.length === 0) continue; + + let eventDesc = lines[0]; + let state = 'Active'; + let stateDuration = totalDuration; + + if (lines.length > 1) { + const stateMatch = lines[1].match(/(Active|Waste|Idle|Load waiting|Start point):\s*(.*)/i); + if (stateMatch) { + let stateText = stateMatch[1]; + if (stateText.toLowerCase() === 'load waiting') state = 'Load waiting'; + else if (stateText.toLowerCase() === 'waste') state = 'Waste'; + else if (stateText.toLowerCase() === 'idle') state = 'Idle'; + else if (stateText.toLowerCase() === 'start point') state = 'Active'; + else state = 'Active'; + + if (stateText.toLowerCase() !== 'start point') { + stateDuration = parseDuration(stateMatch[2]); + } + } + } + + events.push({ + start_time: startTime, + end_time: endTime, + duration_seconds: totalDuration, + camera_zone: cameraZone, + event_description: eventDesc.trim(), + state, + state_duration_seconds: stateDuration + }); + } + return events; +} + +async function run() { + await client.connect(); + + // Create table if not exists (in case it wasn't created yet) + await client.query('DROP TABLE IF EXISTS events;'); + await client.query(` + CREATE TABLE IF NOT EXISTS events ( + id SERIAL PRIMARY KEY, + changeover_id VARCHAR(100), + changeover_date DATE, + start_time TIME, + end_time TIME, + duration_seconds INTEGER, + camera_zone VARCHAR(50), + event_description TEXT, + state VARCHAR(50), + state_duration_seconds INTEGER + ); + `); + await client.query('TRUNCATE TABLE events RESTART IDENTITY;'); + + const wb = xlsx.readFile(filePath); + const sheet = wb.Sheets['Time Matrix']; + const data = xlsx.utils.sheet_to_json(sheet, { header: 1, raw: false, dateNF: 'yyyy-mm-dd hh:mm:ss' }); + + // Start from row index 8 (skipping headers in the new file format) + let allEvents = []; + + for (let i = 8; i < data.length; i++) { + const row = data[i]; + + let startTime = row[1]; + let endTime = row[2]; + let durationStr = row[4]; + + if (!startTime || !endTime) continue; // Skip empty rows + + // Handle "0s / start marker" + let totalDuration = row[3] ? parseInt(row[3]) : parseDuration(durationStr); + + // CO + if (row[5]) allEvents.push(...parseCellEvents(row[5], 'CO', startTime, endTime, totalDuration)); + // Mill + if (row[6]) allEvents.push(...parseCellEvents(row[6], 'Mill', startTime, endTime, totalDuration)); + // Conveyor + if (row[7]) allEvents.push(...parseCellEvents(row[7], 'Conveyor', startTime, endTime, totalDuration)); + } + + const changeoverId = 'CO-DEMO-1'; + const changeoverDate = '2026-07-28'; + + for (const ev of allEvents) { + try { + await client.query( + `INSERT INTO events (changeover_id, changeover_date, start_time, end_time, duration_seconds, camera_zone, event_description, state, state_duration_seconds) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, + [changeoverId, changeoverDate, ev.start_time, ev.end_time, ev.duration_seconds, ev.camera_zone, ev.event_description, ev.state, ev.state_duration_seconds] + ); + } catch(err) { + console.error("Error inserting:", ev, err); + } + } + + console.log(`Inserted ${allEvents.length} events into the database.`); + await client.end(); +} + +run().catch(console.error); diff --git a/ingestion/test.js b/ingestion/test.js new file mode 100644 index 0000000..aa033b7 --- /dev/null +++ b/ingestion/test.js @@ -0,0 +1,4 @@ +const { Client } = require('pg'); +const client = new Client({ user: 'admin', host: 'localhost', database: 'sop_monitoring', password: 'password', port: 5432 }); +client.connect().then(() => client.query("SELECT * FROM events WHERE camera_zone = 'Conveyor' ORDER BY start_time ASC")) +.then(res => { console.log(res.rows); client.end(); }).catch(console.error); diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..bf7ce46 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,18 @@ +server { + listen 80; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://api:3000/api/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..bb55be7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,119 @@ +{ + "name": "ai-sop-monitoring", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ai-sop-monitoring", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "xlsx": "^0.18.5" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6dde5d6 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "ai-sop-monitoring", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "xlsx": "^0.18.5" + } +} diff --git a/ui/.dockerignore b/ui/.dockerignore new file mode 100644 index 0000000..9c97bbd --- /dev/null +++ b/ui/.dockerignore @@ -0,0 +1,3 @@ +node_modules +dist +.env diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/ui/.oxlintrc.json b/ui/.oxlintrc.json new file mode 100644 index 0000000..1255078 --- /dev/null +++ b/ui/.oxlintrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["react", "oxc"], + "rules": { + "react/rules-of-hooks": "error", + "react/only-export-components": ["warn", { "allowConstantExport": true }] + } +} diff --git a/ui/Dockerfile b/ui/Dockerfile new file mode 100644 index 0000000..42a3def --- /dev/null +++ b/ui/Dockerfile @@ -0,0 +1,13 @@ +# Build stage +FROM node:20-alpine as build +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +# Serve stage +FROM nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 0000000..d937833 --- /dev/null +++ b/ui/README.md @@ -0,0 +1,16 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the Oxlint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and Oxlint's TypeScript related rules in your project. diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 0000000..830671e --- /dev/null +++ b/ui/index.html @@ -0,0 +1,13 @@ + + + + + + + ui + + +
+ + + diff --git a/ui/package-lock.json b/ui/package-lock.json new file mode 100644 index 0000000..d72867b --- /dev/null +++ b/ui/package-lock.json @@ -0,0 +1,1798 @@ +{ + "name": "ui", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ui", + "version": "0.0.0", + "dependencies": { + "lucide-react": "^1.27.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.1", + "recharts": "^3.10.1" + }, + "devDependencies": { + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.3", + "oxlint": "^1.71.0", + "vite": "^8.1.1" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.76.0.tgz", + "integrity": "sha512-ZHIE5Zt9AsPDcY4nOlofXt0YfneEeo+QrKMPcPzLf2Z6Q8VtV2W73d7SFJ920WUwyik783u/doKCs3KXdwG+7w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.76.0.tgz", + "integrity": "sha512-shm/ngQilHK6bs+ElJWa4oHfNj5vL1Gl/iVEJldTQjpr0/67oSgr0KUpbmcnLig5Fo0v/l6j2567A7TOL89ONA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.76.0.tgz", + "integrity": "sha512-rvJmrAPKSQ9aWJ6wIS6CK2tJjwzfW0ApQH9qokq6sfDvmHwoyIHxHFMq7z7i7GiV6fdE6s8qvBqWKPTu8RmT6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.76.0.tgz", + "integrity": "sha512-U/zYdb7VYKGY6pA9Vd2rYl9O/HlCylcOlb5PGPvVLtg+oLGsk6H3XGKEMHKyqD3nmmtmlmwb/8SwU2vfSAtvMw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.76.0.tgz", + "integrity": "sha512-WvKG9CAriuo0XNiFzpXjDngUZcRGFNpaK2kLyMUsnJlShxkT96u+BpJQ3KqdQwGOrvI14L6V8bAwXwAYNNY6Jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.76.0.tgz", + "integrity": "sha512-qJ5+RH99TqFRq3UCDxkW0zJJu9c+OAHFY72vGlxZLEpuO+MpKo3POgqb8sYipL9KYm8XY6ofb0HsOuvY6hQNqQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.76.0.tgz", + "integrity": "sha512-PvPCVptkgVARsucgIqFQQcSmJ6xc6GtnVB5bRBekRahTc9eObMtjHfMjy5M+C2tHt5UCMttWM9RuSk/H9NqYeg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.76.0.tgz", + "integrity": "sha512-3KeFDx8Bu4HPAXbuHZOr/oHvN+QT+JQhMw/NYPz7Z071xLSsG27Jfh9PIQVEY7hk1I+jr43ExqRIeJ6VKk2yLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.76.0.tgz", + "integrity": "sha512-oPFkkKTgl0K/EIg9fQ8oA3IGcI05/Mq1en04iFa41mmNPT+6KEiByVazTOZZJiHMBBrbsns1YJ2e1Scqwzesjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.76.0.tgz", + "integrity": "sha512-gN7yZ0eqflA5Fhf1wvHxGUltIV3FsvmB1zhNMDEK9vSHhc7E6qg9CuPeBgPZab66Tjzq6w6kHAtNEvnTHf4cyw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.76.0.tgz", + "integrity": "sha512-S/HqMbn22mQrjtErUxEoS/a55u8kIeXvreIxiJu5G7Le3UecEd6SQZxrDIpuhtgaFnsY/nVra3ytP+pRljDilA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.76.0.tgz", + "integrity": "sha512-ZIga3097VJZolGZk6SrIAUokIGfRkxRlhiHDUznZptGBfwrhD7pNfD1rzEzsCwvk/1DX0A1bLz+liuNh5QKIVQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.76.0.tgz", + "integrity": "sha512-ZGiiA7pFzMJSyMWYZTVlPgbTsx+Vl8ihLGMIujPwaslUF7kIPPWAbVmAlTc+9lWDV+DCiB8Ikixu+lSHeOIIWQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.76.0.tgz", + "integrity": "sha512-JLiy5WuvEBFTT6ErIFV35SLzi0R7Iri6MKU6dZbTxfIx8pndbbPs3Mj780nMipBFcPkti+okAPOJ9POKkHFEgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.76.0.tgz", + "integrity": "sha512-z7lgKQtbo/I1NIe8G5NHLesxJDv0tRSUWTpXKb9Pm3E9nKFKfO4IOSDtFroKgXtOYb0jQbcdH+0wzTyMXVes+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.76.0.tgz", + "integrity": "sha512-JOjKymIpb9QcYfEhZsN6h4V9Ivd474W38cNIBRv6bg2TbIvogbMTH0Mg6YWW9TiRDqfcX+/Hyfsbo5vcSE5guQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.76.0.tgz", + "integrity": "sha512-pqDWZiwcmByWUEm1NFUBNiT6aentCcaoMWJv0HbXEmuYermJ4sg8ppVrshubYP2MZ6SHccJJcpr6x469PuDFIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.76.0.tgz", + "integrity": "sha512-Ba0O659kgMv6pwO3z9PdO+K3aMxQRaw9HnG+e6AtOfgwcKFvYilciQYBoUBmxfQvOCKZe1SwjMkuB542NkuDMQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.76.0.tgz", + "integrity": "sha512-5qcirPHO8nKfkoowEVWtpAoVTcYDy6g0UT0NGic450Qv8J2NrOqg4uQ8QppRP4MDTC7Xx47lbZnmadTH03CGGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", + "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.4.tgz", + "integrity": "sha512-XcCQz0TBpBgljhj0gMuuDj49i6Ytqh5q1osT/Gp5uAVJUCTWxyskk/l1jwYYiu2xcNHHipdMz40EGfM1VdamVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/es-toolkit": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", + "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types" + ] + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/immer": { + "version": "11.1.15", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.15.tgz", + "integrity": "sha512-VrNANlmnWQnh5COXIIOQXM9oOJw7naGKlBT74ZOOR6lpVXc3gFEu9FJLDFcpCJ2j+NWr8TIwtWD//T6ZX6TKiQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lucide-react": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.27.0.tgz", + "integrity": "sha512-rJicGl/3Fly/E0rOH1YmPZ6e49JCnKknh1ox1vpHnkfjujAkKA6sqUZvH3MTAaXXjgexyUwgNwTJzTtYuAFYJw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/oxlint": { + "version": "1.76.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.76.0.tgz", + "integrity": "sha512-6QoFioEU4fNdiUx/2Eo6TRd6NG7H7njnRCz8rhB66cZmMHDTqcm1Rjvl8Wry+ZTQMBAmyb4Mlf62Mk5X+eHSOw==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.76.0", + "@oxlint/binding-android-arm64": "1.76.0", + "@oxlint/binding-darwin-arm64": "1.76.0", + "@oxlint/binding-darwin-x64": "1.76.0", + "@oxlint/binding-freebsd-x64": "1.76.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.76.0", + "@oxlint/binding-linux-arm-musleabihf": "1.76.0", + "@oxlint/binding-linux-arm64-gnu": "1.76.0", + "@oxlint/binding-linux-arm64-musl": "1.76.0", + "@oxlint/binding-linux-ppc64-gnu": "1.76.0", + "@oxlint/binding-linux-riscv64-gnu": "1.76.0", + "@oxlint/binding-linux-riscv64-musl": "1.76.0", + "@oxlint/binding-linux-s390x-gnu": "1.76.0", + "@oxlint/binding-linux-x64-gnu": "1.76.0", + "@oxlint/binding-linux-x64-musl": "1.76.0", + "@oxlint/binding-openharmony-arm64": "1.76.0", + "@oxlint/binding-win32-arm64-msvc": "1.76.0", + "@oxlint/binding-win32-ia32-msvc": "1.76.0", + "@oxlint/binding-win32-x64-msvc": "1.76.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=7.0.2001", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", + "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", + "license": "MIT", + "peer": true + }, + "node_modules/react-redux": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", + "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz", + "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.1.tgz", + "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==", + "license": "MIT", + "dependencies": { + "react-router": "7.18.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/recharts": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.10.1.tgz", + "integrity": "sha512-QXFrvt6IVcw7eeZCoyXTwkIJAX3Dv1nyVhMicXJ47GsGDDpcN8z6o644DibE9XjpBTThtsomLKnTV6lc+cVFUA==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^11.1.8", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.2.0", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reselect": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "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==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 0000000..e2a59cb --- /dev/null +++ b/ui/package.json @@ -0,0 +1,26 @@ +{ + "name": "ui", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "oxlint", + "preview": "vite preview" + }, + "dependencies": { + "lucide-react": "^1.27.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.1", + "recharts": "^3.10.1" + }, + "devDependencies": { + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.3", + "oxlint": "^1.71.0", + "vite": "^8.1.1" + } +} diff --git a/ui/public/favicon.svg b/ui/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/ui/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/icons.svg b/ui/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/ui/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/src/App.css b/ui/src/App.css new file mode 100644 index 0000000..f90339d --- /dev/null +++ b/ui/src/App.css @@ -0,0 +1,184 @@ +.counter { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--accent); + background: var(--accent-bg); + border: 2px solid transparent; + transition: border-color 0.3s; + margin-bottom: 24px; + + &:hover { + border-color: var(--accent-border); + } + &:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) + scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) + scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + & > div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/ui/src/App.jsx b/ui/src/App.jsx new file mode 100644 index 0000000..5103693 --- /dev/null +++ b/ui/src/App.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import ConsolidatedHome from './components/ConsolidatedHome'; +import ChangeoverDetail from './components/ChangeoverDetail'; +import EventTimeline from './components/EventTimeline'; +import './index.css'; + +function App() { + return ( + +
+ + } /> + } /> + } /> + +
+
+ ); +} + +export default App; diff --git a/ui/src/assets/hero.png b/ui/src/assets/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..02251f4b956c55af2d76fd0788124d7eee2b45eb GIT binary patch literal 13057 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 P00000NkvXXu0mjft=yBf literal 0 HcmV?d00001 diff --git a/ui/src/assets/react.svg b/ui/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/ui/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/assets/vite.svg b/ui/src/assets/vite.svg new file mode 100644 index 0000000..5101b67 --- /dev/null +++ b/ui/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/ui/src/components/ChangeoverDetail.jsx b/ui/src/components/ChangeoverDetail.jsx new file mode 100644 index 0000000..86d3936 --- /dev/null +++ b/ui/src/components/ChangeoverDetail.jsx @@ -0,0 +1,283 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import { useParams, useNavigate, Link } from 'react-router-dom'; +import { Activity, Clock, AlertTriangle, Monitor, ArrowLeft, Calendar } from 'lucide-react'; +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip as RechartsTooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'; + +export default function ChangeoverDetail() { + const { id } = useParams(); + const navigate = useNavigate(); + const [idleTimes, setIdleTimes] = useState({ CO: 0, Mill: 0, Conveyor: 0 }); + const [events, setEvents] = useState([]); + const [bottlenecks, setBottlenecks] = useState([]); + const [compliance, setCompliance] = useState([]); + const [loading, setLoading] = useState(true); + + // We assume the API runs on the same host but port 3000 during dev, or proxied via nginx + // Using relative path for Nginx reverse proxy compatibility + const API_BASE = '/api'; + + useEffect(() => { + async function fetchData() { + try { + const query = id ? `?changeover_id=${id}` : ''; + const [idleRes, eventsRes, bottleRes, compRes] = await Promise.all([ + fetch(`${API_BASE}/analytics/idle-time${query}`), + fetch(`${API_BASE}/events${query}`), + fetch(`${API_BASE}/analytics/bottlenecks${query}`), + fetch(`${API_BASE}/analytics/sop-compliance${query}`) + ]); + + if (idleRes.ok) setIdleTimes(await idleRes.json()); + if (eventsRes.ok) setEvents(await eventsRes.json()); + if (bottleRes.ok) setBottlenecks(await bottleRes.json()); + if (compRes.ok) setCompliance(await compRes.json()); + } catch (err) { + console.error("Error fetching data", err); + } finally { + setLoading(false); + } + } + fetchData(); + }, []); + + const formatDuration = (seconds) => { + if (!seconds) return '0s'; + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = seconds % 60; + + let res = []; + if (h > 0) res.push(`${h}h`); + if (m > 0) res.push(`${m}m`); + if (s > 0) res.push(`${s}s`); + return res.join(' ') || '0s'; + }; + + const getStateBadge = (state) => { + const s = state?.toLowerCase() || ''; + if (s === 'active') return Active; + if (s === 'waste') return Waste; + if (s === 'idle') return Idle; + if (s === 'load waiting') return Load Wait; + return {state}; + }; + + const zoneData = useMemo(() => { + const data = { + CO: { name: 'CO', Active: 0, Idle: 0, Waste: 0, 'Load wait': 0 }, + Mill: { name: 'Mill', Active: 0, Idle: 0, Waste: 0, 'Load wait': 0 }, + Conveyor: { name: 'Conveyor', Active: 0, Idle: 0, Waste: 0, 'Load wait': 0 } + }; + events.forEach(ev => { + const z = ev.camera_zone; + const s = ev.state?.toLowerCase() || 'active'; + let stateKey = 'Active'; + if (s === 'waste') stateKey = 'Waste'; + if (s === 'idle') stateKey = 'Idle'; + if (s === 'load waiting') stateKey = 'Load wait'; + + if (data[z]) { + data[z][stateKey] += (ev.state_duration_seconds || 0); + } + }); + return Object.values(data); + }, [events]); + + const bottleneckData = useMemo(() => { + return bottlenecks.map(b => ({ + name: b.event_description.length > 25 ? b.event_description.substring(0, 25) + '...' : b.event_description, + value: parseInt(b.total_duration || 0) + })); + }, [bottlenecks]); + + const COLORS = ['#e74c3c', '#f39c12', '#3498db', '#9b59b6', '#1abc9c', '#34495e']; + + const CustomTooltip = ({ active, payload, label }) => { + if (active && payload && payload.length) { + return ( +
+

{label || payload[0].name}

+ {payload.map((entry, index) => ( +

+ {entry.name}: {formatDuration(entry.value)} +

+ ))} +
+ ); + } + return null; + }; + + if (loading) { + return ( +
+

Loading Analytics...

+
+ ); + } + + return ( +
+
+
+ + Back to Home + +

Changeover Session: {id}

+

Detailed Analytics and SOP Monitoring

+
+
+ + +
+
+ +
+
+
+ CO Idle / Waste + +
+ {formatDuration(idleTimes.CO)} +
+
+
+ Mill Gaps / Idle + +
+ {formatDuration(idleTimes.Mill)} +
+
+
+ Conveyor Transport Delay + +
+ {formatDuration(idleTimes.Conveyor)} +
+
+ +
+

SOP Compliance Checks

+
+ + + + + + + + + + {compliance.map((c, idx) => ( + + + + + + ))} + {compliance.length === 0 && ( + + + + )} + +
RuleStatusDetails
{c.rule} + + {c.status} + + {c.detail}
No compliance checks available.
+
+
+ +
+
+

Zone Efficiency Breakdown

+
+ + + + + Math.floor(val/60) + 'm'} /> + } /> + + + + + + + +
+
+ +
+

Bottleneck Impact Distribution

+
+ + + + {bottleneckData.map((entry, index) => ( + + ))} + + } /> + + + +
+
+
+ +
+
+

Top Bottlenecks

+
+ + + + + + + + + + + {bottlenecks.map((b, idx) => ( + + + + + + + ))} + {bottlenecks.length === 0 && ( + + + + )} + +
Fault / EventZoneLost TimeOccurrences
{b.event_description}{b.camera_zone}{formatDuration(b.total_duration)}{b.occurrences}
No bottlenecks recorded.
+
+
+
+
+ ); +} diff --git a/ui/src/components/ConsolidatedHome.jsx b/ui/src/components/ConsolidatedHome.jsx new file mode 100644 index 0000000..361bc87 --- /dev/null +++ b/ui/src/components/ConsolidatedHome.jsx @@ -0,0 +1,84 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Activity, Calendar, Play } from 'lucide-react'; + +export default function ConsolidatedHome() { + const [changeovers, setChangeovers] = useState([]); + const [loading, setLoading] = useState(true); + const navigate = useNavigate(); + + const API_BASE = '/api'; + + useEffect(() => { + async function fetchData() { + try { + const res = await fetch(`${API_BASE}/changeovers`); + if (res.ok) { + setChangeovers(await res.json()); + } + } catch (err) { + console.error("Error fetching changeovers", err); + } finally { + setLoading(false); + } + } + fetchData(); + }, []); + + if (loading) { + return ( +
+

Loading Changeover Sessions...

+
+ ); + } + + return ( +
+
+
+

SOP Monitoring Analytics

+

Consolidated Factory Changeover History

+
+ +
+ +
+

Recorded Changeover Sessions

+
+ + + + + + + + + + {changeovers.map((co) => ( + + + + + + ))} + {changeovers.length === 0 && ( + + + + )} + +
Session IDDateAction
{co.changeover_id}{new Date(co.changeover_date).toLocaleDateString()} + +
No changeover sessions found.
+
+
+
+ ); +} diff --git a/ui/src/components/EventTimeline.jsx b/ui/src/components/EventTimeline.jsx new file mode 100644 index 0000000..0a5d96b --- /dev/null +++ b/ui/src/components/EventTimeline.jsx @@ -0,0 +1,133 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import { useParams, Link } from 'react-router-dom'; +import { ArrowLeft, Video } from 'lucide-react'; + +export default function EventTimeline() { + const { id } = useParams(); + const [events, setEvents] = useState([]); + const [loading, setLoading] = useState(true); + + const API_BASE = '/api'; + + useEffect(() => { + async function fetchData() { + try { + const query = id ? `?changeover_id=${id}` : ''; + const res = await fetch(`${API_BASE}/events${query}`); + if (res.ok) { + setEvents(await res.json()); + } + } catch (err) { + console.error("Error fetching events", err); + } finally { + setLoading(false); + } + } + fetchData(); + }, [id]); + + const formatDuration = (seconds) => { + if (!seconds) return '0s'; + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = seconds % 60; + let res = []; + if (h > 0) res.push(`${h}h`); + if (m > 0) res.push(`${m}m`); + if (s > 0) res.push(`${s}s`); + return res.join(' ') || '0s'; + }; + + const getStateBadge = (state) => { + const s = state?.toLowerCase() || ''; + if (s === 'active') return Active; + if (s === 'waste') return Waste; + if (s === 'idle') return Idle; + if (s === 'load waiting') return Load Wait; + return {state}; + }; + + const groupedEvents = useMemo(() => { + return { + CO: events.filter(e => e.camera_zone === 'CO'), + Mill: events.filter(e => e.camera_zone === 'Mill'), + Conveyor: events.filter(e => e.camera_zone === 'Conveyor') + }; + }, [events]); + + const renderTimeline = (zone, zoneEvents) => ( +
+

+ {zone} Timeline +

+
+ {zoneEvents.length === 0 ? ( +

No events recorded.

+ ) : ( + zoneEvents.map((ev, i) => ( +
+
+ + {ev.start_time.substring(0, 5)} - {ev.end_time.substring(0, 5)} + + {getStateBadge(ev.state)} +
+

{ev.event_description}

+
+ Duration: {formatDuration(ev.state_duration_seconds)} + +
+
+
+ Std Cycle: + N/A +
+
+ Manpower: + Nil +
+
+
+ )) + )} +
+
+ ); + + if (loading) { + return ( +
+

Loading Timeline...

+
+ ); + } + + return ( +
+
+ + Back to Changeover Analytics + +

Event Timeline: {id}

+

Location-wise sequential breakdown of events

+
+ +
+ {renderTimeline('CO', groupedEvents.CO)} + {renderTimeline('Mill', groupedEvents.Mill)} + {renderTimeline('Conveyor', groupedEvents.Conveyor)} +
+
+ ); +} diff --git a/ui/src/index.css b/ui/src/index.css new file mode 100644 index 0000000..6a91394 --- /dev/null +++ b/ui/src/index.css @@ -0,0 +1,177 @@ +:root { + --bg-color: #0f1115; + --bg-gradient: radial-gradient(circle at 10% 20%, rgb(20, 24, 33) 0%, rgb(15, 17, 21) 90.2%); + --panel-bg: rgba(25, 29, 41, 0.6); + --panel-border: rgba(255, 255, 255, 0.08); + --text-primary: #f8fafc; + --text-secondary: #94a3b8; + --accent: #3b82f6; + --accent-glow: rgba(59, 130, 246, 0.5); + --danger: #ef4444; + --warning: #f59e0b; + --success: #10b981; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + background: var(--bg-gradient); + background-color: var(--bg-color); + color: var(--text-primary); + min-height: 100vh; + -webkit-font-smoothing: antialiased; +} + +/* Typography */ +h1 { + font-size: 2rem; + font-weight: 700; + letter-spacing: -0.02em; + margin-bottom: 0.5rem; +} + +h2 { + font-size: 1.25rem; + font-weight: 600; + color: var(--text-primary); + margin-bottom: 1rem; +} + +p { + color: var(--text-secondary); + font-size: 0.95rem; + line-height: 1.5; +} + +/* Glassmorphism Panel */ +.glass-panel { + background: var(--panel-bg); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border: 1px solid var(--panel-border); + border-radius: 16px; + padding: 1.5rem; + box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.glass-panel:hover { + transform: translateY(-2px); + box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.4), 0 0 12px 0 var(--accent-glow); +} + +/* Layout */ +.container { + max-width: 1400px; + margin: 0 auto; + padding: 2rem; +} + +.header { + margin-bottom: 2rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.kpi-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 1.5rem; + margin-bottom: 2rem; +} + +/* KPI Cards */ +.kpi-card { + display: flex; + flex-direction: column; +} + +.kpi-title { + color: var(--text-secondary); + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.kpi-value { + font-size: 2.5rem; + font-weight: 700; + color: var(--text-primary); + margin-bottom: 0.25rem; +} + +.kpi-value.danger { color: var(--danger); } +.kpi-value.warning { color: var(--warning); } +.kpi-value.success { color: var(--success); } + +/* Table */ +.data-table-container { + overflow-x: auto; +} + +table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + text-align: left; +} + +th { + color: var(--text-secondary); + font-weight: 500; + font-size: 0.875rem; + padding: 1rem; + border-bottom: 1px solid var(--panel-border); +} + +td { + padding: 1rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.04); + font-size: 0.95rem; +} + +tbody tr { + transition: background-color 0.2s ease; +} + +tbody tr:hover { + background-color: rgba(255, 255, 255, 0.03); +} + +tbody tr:last-child td { + border-bottom: none; +} + +/* Badges */ +.badge { + display: inline-block; + padding: 0.25rem 0.75rem; + border-radius: 999px; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.025em; +} + +.badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); } +.badge.waste { background: rgba(239, 68, 68, 0.2); color: var(--danger); } +.badge.idle { background: rgba(245, 158, 11, 0.2); color: var(--warning); } +.badge.load { background: rgba(59, 130, 246, 0.2); color: var(--accent); } + +/* Animations */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +.animate-fade-in { + animation: fadeIn 0.4s ease forwards; +} diff --git a/ui/src/main.jsx b/ui/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/ui/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/ui/vite.config.js b/ui/vite.config.js new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/ui/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +})