diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..704fc45 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,107 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +NiLai-Clock is a worker attendance management system with role-based dashboards for workers and managers. It's built as a Vue.js SPA with an Express.js backend, featuring QR code attendance tracking, geofencing, and comprehensive reporting capabilities. + +## Commands + +### Development +- `npm run dev` - Start frontend development server (Vite on port 5173) +- `npm run backend` - Start backend server (Express on port 3000) +- `npm run dev:all` - Run both frontend and backend concurrently +- `npm install` - Install dependencies + +### Production +- `npm run build` - Build for production using Vite +- `npm run preview` - Preview production build locally + +### Code Quality +- `npm run lint` - Run ESLint with auto-fix +- `npm run format` - Format code using Prettier + +## Architecture + +### Frontend (Vue.js) +- **Framework**: Vue 3 with Composition API +- **Build Tool**: Vite with Vue plugin and TailwindCSS +- **Routing**: Vue Router with hash-based routing and role-based guards +- **State**: Session storage for authentication (userId, userRole, token) +- **Styling**: TailwindCSS v4 with responsive design +- **Internationalization**: Vue I18n with English (en) and Malay (ms) locales + +### Backend (Express.js) +- **Server**: Express with CORS, supports both HTTP and HTTPS +- **Database**: MySQL with connection pooling (mysql2) +- **Authentication**: JWT tokens with bcrypt for password hashing +- **Routes**: Separated into manager (`/api/managers/*`) and worker (`/api/*`) routes + +### Key Components Structure + +#### Views (Role-Based) +- **Worker**: `WorkerDashboard`, `WorkerHistory`, `WorkerSettings`, `WorkerChangePassword` +- **Manager**: `ManagerDashboard`, `ManagerAttendanceRecord` +- **Auth**: `Login` (supports both roles) + +#### Components +- **Management**: `PersonnelManagement`, `GeofenceManagement`, `QrCodeManagement`, `KillSwitchManagement` +- **UI**: `Toast` notifications with `useToast` composable +- **Reporting**: `WarningReporting` with CSV export capabilities + +### Authentication Flow +- Role-based routing with `meta: { requiresAuth: true, role: 'worker|manager' }` +- Navigation guards redirect users to appropriate dashboards +- Session storage manages authentication state +- API requests include JWT tokens via Authorization header + +### Key Libraries +- **Maps**: Leaflet with drawing capabilities for geofencing +- **QR Codes**: html5-qrcode for scanning, qrcode for generation +- **Geospatial**: @turf/turf for geographical calculations +- **Data Export**: json2csv for attendance reports +- **UUID**: For device identification and worker login tracking + +## Environment Configuration + +Create `.env` file with: +``` +DB_HOST=your_database_host +DB_USER=your_database_user +DB_PASSWORD=your_database_password +DB_NAME=your_database_name +DB_PORT=your_database_port +VITE_API_BASE_URL=your_api_base_url +``` + +Optional SSL configuration: +- `SSL_ENABLED=true` +- `HTTP_PORT=3000` +- `HTTPS_PORT=3443` + +## Development Notes + +- Frontend uses hash-based routing for better deployment compatibility +- Backend supports both HTTP and HTTPS with configurable ports +- CORS configured for multiple origins including mobile app protocols +- Database connection is tested on server startup with proper error handling +- All API calls go through centralized `apiFetch` utility with error handling +- ESLint configured to ignore unused variables/parameters prefixed with underscore +- Prettier integrated with Vue ESLint config for consistent formatting + +## Database Schema + +The application manages worker attendance with these core entities: +- **Workers**: Authentication, device UUID tracking, role assignment +- **Managers**: Administrative access and permissions +- **Attendance Records**: Clock in/out with location and timestamp data +- **Geofences**: Location boundaries for valid attendance tracking +- **QR Codes**: Dynamic codes for attendance verification + +## Docker Support + +Includes Docker configuration: +- `Dockerfile` - Node.js Alpine-based container +- `docker-compose.yml` - Multi-service setup with nginx reverse proxy +- Production deployment on port 18080 (nginx) and 18081 (app) \ No newline at end of file diff --git a/backend/cert.pem b/backend/cert.pem new file mode 100644 index 0000000..b3ebdd9 --- /dev/null +++ b/backend/cert.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEajCCAtKgAwIBAgIQCidY0lKaDwojBgr6MpeBzzANBgkqhkiG9w0BAQsFADCB +kTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTMwMQYDVQQLDCpNQUlM +XG1hc29uZ3lhbkBERVNLVE9QLUlRVThEREQgKG1hc29uZ3lhbikxOjA4BgNVBAMM +MW1rY2VydCBNQUlMXG1hc29uZ3lhbkBERVNLVE9QLUlRVThEREQgKG1hc29uZ3lh +bikwHhcNMjUwNzA0MDc0NjExWhcNMjcxMDA0MDc0NjExWjBeMScwJQYDVQQKEx5t +a2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxMzAxBgNVBAsMKk1BSUxcbWFz +b25neWFuQERFU0tUT1AtSVFVOERERCAobWFzb25neWFuKTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANl8SofEGCDGYv2J22Qanu6LgxvvKd9wKB1Lf2x6 +eBD84tHmVZXKuQElo9ZkEbljKA9M8dNCTrxNFzGL6dB2b3fRHBnEYhiANKnMohgb +oul+Tiq2/Pye4SHWglvsM6DboImARRW58L8FyA3mnS9VgS7TUb3W2tRQhLHU1s/R +QjZulIQvpe+k0dW+S1zd7wBg790K5GNs9va/8KEM1v3esBNOpCbKeWzeRT/Si9ZA +Dfm72SSWslHQEXtuz8AQVtfk0qJMUB0URmyadir0aJwuDC6m5iQSKtLTvQp+n0/Z +lundQQbsnm71FnCAD9PSz+IaB3euEOwUGbGnDW9+10kGTekCAwEAAaNwMG4wDgYD +VR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFElR +m5C15845O14vXvSvwjxwtiJEMCYGA1UdEQQfMB2CCWxvY2FsaG9zdIcECgACAocE +fwAAAYcEwKgkNjANBgkqhkiG9w0BAQsFAAOCAYEAsOdvadeTxsAT0Le63PPEYPiZ +drkEJdTyu9Thv9nFhLCD4vUYIZrlE3brFXD1iVTR1muJsalfnmW9azIwGBHw52bZ +B2XdA6HNZEklSRtqNMEAGJsdnbGuCTPa1lLNuzCQodSnmbvu6Y5K13Pq/asl3DVW +h/hczwX5NrQvlvyDwI0kVSDRmEb5AYnEic5h64gEyILTVWopT8RzA+B8AtW3oP3d +pfoCErwQvxfkNd3UGWk+rDlQWwApzh+N4P+3vAjhAra7Yoj+JtT0SnXeAjXhbB0E +WmDcMNQwxUg1FN5ATR5pAMoSSNviLaf/jYb93naZ6YZKgSfSIKNgUJz+ppgHNBFr +326JOYH0yzyhWXUXchzsn1ytMkhddNVZhRbGceOkyZEkaSynZR4om8ZGxPJYfCBB +m9sH27eCeJBy9DXk0ZUkJg+y3C+jizenHiPnED92Z1EZ0ke7fNufiVZs0yQl2uxg +V5mgoQSLxu4LHXQnTm/NQugY9S8rfbz510WutGKi +-----END CERTIFICATE----- diff --git a/backend/key.pem b/backend/key.pem new file mode 100644 index 0000000..f667e5f --- /dev/null +++ b/backend/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZfEqHxBggxmL9 +idtkGp7ui4Mb7ynfcCgdS39sengQ/OLR5lWVyrkBJaPWZBG5YygPTPHTQk68TRcx +i+nQdm930RwZxGIYgDSpzKIYG6Lpfk4qtvz8nuEh1oJb7DOg26CJgEUVufC/BcgN +5p0vVYEu01G91trUUISx1NbP0UI2bpSEL6XvpNHVvktc3e8AYO/dCuRjbPb2v/Ch +DNb93rATTqQmynls3kU/0ovWQA35u9kklrJR0BF7bs/AEFbX5NKiTFAdFEZsmnYq +9GicLgwupuYkEirS070Kfp9P2Zbp3UEG7J5u9RZwgA/T0s/iGgd3rhDsFBmxpw1v +ftdJBk3pAgMBAAECggEAIeDztzx7ybc9umMcMvbWpTBEZziVXEIbbZzSJ7LYO0U5 +jBsGYAQpV51mbUI/ZJKmreN9lDwzCbA0mbpC3P9mE9MWPolSAqEOExlWcszzTs4n +HQ5OUIfraBsDSZB85mTwGBtMJ7tEXm1nIYs4FySJsCKpDBqJEiPM1+rg35SobNP5 +aOvuLgXe3V6wVuihakoGj8nUtCgKsPr/14ybcF6Fcv5ULI6Tls0G8HOY92Kesb/o +NZL1YmMVevY+RKYzrZKca6mRanMIjnjrnYGX5V404mh6GQKpGdgrcMEONMbJje2H +44MjyJYhQ67/ItOKOuC1JG1LuRq/5SXTAS2WW7g+1QKBgQDiWefUn2v3pYd4CIFd +Bz43TpHuQZiqX5UOvPFOrk5LT+EhYHTpSCThrc5piqk+XsnV3G1dyDnbBK8k4FPa +yyrUuNOSvQlspSr0u++5i7cRLwq7C6kRtTzW8nr6Az8bE6u1prvXKFIWKP/doWeg +U7jPMCVKN+oxvNN6Fi0meecLxwKBgQD1+RkfrUCg7xpr+gn2R2LxryL2u/oxVRmo +4TZqBQoXcQJBx+UrTcIL8XENohYYI/7HCZfD/cBxpFGNqclD3DjzjH2NZ43MBlbN +up3wD+Ks2LVOilyOrxK3be/cnvPyQJantd/NBnHOTsQoBUPdhbrqdyrjYW0o4WZQ +5c36f934zwKBgQCRiTEQeviWoG279ewHfpK4SOJ3iOG6Gf7jHQUii9x3fALKzRQe +sm5UVMZ1AdzT52prAXGobQcWFarvUPVZpmwBnl0a6kTXAFPgS75VVMn+WHrTzSmF +4zwdEIeVnOTEah9riqsYKiqtaOsq+45/fZVEUjaHw+/mzvxCcWPSa2rtHQKBgEUe +amDsXmzaw6Hz8TizdqpTfI+44uVZ9IvwPUotgFh1+Rxi/5LbltukTRB3q528/6sO +lwcMFzfX5NLaEyRujdJieCV0I/RhE6Nb/WWoERphCxG276topunEitKEGCjK3Yrj +ILCMTw6aM6TLVfa5zXx1YCflCLekHww8h1UM+WMhAoGAH6U1XzkW3ozty7sQ5vxZ +jzri0xUpp06EA/EtfhkCRPgaYCkL5aXan+jNAZPfTG6mGudULWjTIfEEQrMJ54CN +sItMoPP2S4EDuj4xdQWe8eTeMqtGG/lAmG2Yr9QajWofNLwaBtsXANYCDGadNUxa +2pog6+BDaFEC64IwkoBYgZ8= +-----END PRIVATE KEY----- diff --git a/backend/managerRoutes.js b/backend/managerRoutes.js index bd331be..9a91c94 100644 --- a/backend/managerRoutes.js +++ b/backend/managerRoutes.js @@ -16,17 +16,39 @@ export default function(db) { if (err || user.role !== 'manager') { return res.status(403).json({ message: 'Forbidden' }); } - req.user = user; + req.user = { ...user, id: user.userId }; // Correctly map userId to id next(); }); } else { res.status(401).json({ message: 'Unauthorized' }); } }; + + // Middleware to check for specific permissions + const checkPermission = (requiredPermission) => { + return async (req, res, next) => { + try { + const managerId = req.user.id; + const [rows] = await db.execute( + 'SELECT * FROM manager_permissions WHERE manager_id = ?', + [managerId] + ); + + if (rows.length === 0 || !rows[0][requiredPermission]) { + return res.status(403).json({ message: 'Forbidden: Insufficient permissions.' }); + } + next(); + } catch (error) { + console.error('Permission check error:', error); + res.status(500).json({ message: 'Database error during permission check.' }); + } + }; + }; + router.use(authenticateJWT); // --- START: Date Management Routes --- - router.get('/enabled-dates', async (req, res) => { + router.get('/enabled-dates', checkPermission('view_all'), async (req, res) => { try { const [rows] = await db.execute('SELECT YEAR(enabled_date) as year, MONTH(enabled_date) as month, DAY(enabled_date) as day FROM enabled_dates'); // Format date safely using components from the database to avoid timezone shifts @@ -39,7 +61,7 @@ export default function(db) { }); // Definitive version using a dedicated database connection - router.post('/enabled-dates/update', async (req, res) => { + router.post('/enabled-dates/update', checkPermission('manage_resources'), async (req, res) => { let connection; // Define connection here to ensure it's accessible in the 'finally' block try { const { datesToEnable, datesToDisable } = req.body; @@ -77,7 +99,7 @@ export default function(db) { // --- ATTENDANCE & REPORTING --- - router.get('/failed-records', async (req, res) => { + router.get('/failed-records', checkPermission('view_all'), async (req, res) => { try { const { search = '', startDate, endDate } = req.query; if (!startDate || !endDate) { @@ -112,7 +134,7 @@ export default function(db) { } }); - router.get('/failed-records/details', async (req, res) => { + router.get('/failed-records/details', checkPermission('view_all'), async (req, res) => { try { const { workerId, startDate, endDate } = req.query; if (!workerId || !startDate || !endDate) { @@ -139,7 +161,7 @@ export default function(db) { }); // GET attendance records with a modified query to avoid the MySQL 5.7 bug - router.get('/attendance-records/export-raw', async (req, res) => { + router.get('/attendance-records/export-raw', checkPermission('view_all'), async (req, res) => { try { const { workerIds, startDate, endDate } = req.query; if (!startDate || !endDate) { @@ -177,7 +199,7 @@ export default function(db) { } }); - router.post('/add-record', authenticateJWT, async (req, res) => { + router.post('/add-record', checkPermission('edit_workers'), async (req, res) => { try { const { workerId, eventType, timestamp, notes } = req.body @@ -212,7 +234,7 @@ export default function(db) { } }) - router.get('/attendance-records/export', async (req, res) => { + router.get('/attendance-records/export', checkPermission('view_all'), async (req, res) => { try { const { workerIds, startDate, endDate } = req.query; if (!startDate || !endDate) { @@ -295,7 +317,7 @@ export default function(db) { } }); - router.get('/attendance-records', async (req, res) => { + router.get('/attendance-records', checkPermission('view_all'), async (req, res) => { try { const { workerIds, startDate, endDate, format } = req.query; if (!workerIds) { @@ -351,22 +373,107 @@ export default function(db) { // --- All other manager routes remain the same --- + // GET a specific manager's permissions + router.get('/permissions/:id', async (req, res) => { + try { + const requesterId = req.user.id; + const targetId = parseInt(req.params.id, 10); + + // Check if the user is trying to access their own permissions + if (requesterId !== targetId) { + // If not, check if they have permission to manage permissions + const [permissionRows] = await db.execute( + 'SELECT can_manage_permissions FROM manager_permissions WHERE manager_id = ?', + [requesterId] + ); + + if (permissionRows.length === 0 || !permissionRows[0].can_manage_permissions) { + return res.status(403).json({ message: 'Forbidden: Insufficient permissions to view others\' permissions.' }); + } + } + + // If they are accessing their own, or have permission, fetch the target's permissions + const [rows] = await db.execute( + 'SELECT * FROM manager_permissions WHERE manager_id = ?', + [targetId] + ); + + if (rows.length === 0) { + // If no permissions are set, return a default set of all false + const [fields] = await db.execute('DESCRIBE manager_permissions'); + const defaultPermissions = fields.reduce((acc, field) => { + if (field.Field !== 'manager_id') { + acc[field.Field] = 0; // Use 0 for false + } + return acc; + }, {}); + return res.json(defaultPermissions); + } + + // Convert buffer values to booleans + const permissions = Object.entries(rows[0]).reduce((acc, [key, value]) => { + if (key !== 'manager_id') { + acc[key] = Boolean(value); + } + return acc; + }, {}); + + res.json(permissions); + } catch (error) { + console.error('Get manager permissions error:', error); + res.status(500).json({ message: 'Database error fetching manager permissions.', details: error.message }); + } + }); + + // PUT (update) a manager's permissions + router.put('/permissions/:id', checkPermission('manager_permissions'), async (req, res) => { + try { + const { id } = req.params; + const permissions = req.body; + + const fields = [ + 'view_all', 'edit_workers', 'manage_resources', 'manager_permissions' + ]; + const values = fields.map(field => permissions[field] || false); + + // Convert to new simplified permissions schema + const query = ` + INSERT INTO manager_permissions (manager_id, view_all, edit_workers, manage_resources, manager_permissions) + VALUES (?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + view_all = VALUES(view_all), + edit_workers = VALUES(edit_workers), + manage_resources = VALUES(manage_resources), + manager_permissions = VALUES(manager_permissions) + `; + + const queryParams = [id, ...values]; + + await db.execute(query, queryParams); + + res.status(200).json({ message: 'Permissions updated successfully.' }); + } catch (error) { + console.error('Update manager permissions error:', error); + res.status(500).json({ message: 'Database error updating manager permissions.', details: error.message }); + } + }); + // GET all workers with filtering and pagination - router.get('/workers', async (req, res) => { + router.get('/workers', checkPermission('view_all'), async (req, res) => { try { const { search = '', page = 1, limit = 20 } = req.query; const offset = (parseInt(page) - 1) * parseInt(limit); const searchTerm = `%${search}%`; let baseQuery = ` - SELECT w.id, w.username, w.full_name, w.department, w.position, w.created_at + SELECT w.id, w.username, w.full_name, w.department, w.position, w.created_at, w.status FROM workers w `; let countQuery = `SELECT COUNT(w.id) as totalCount FROM workers w`; const params = []; const countParams = []; - let whereClauses = ["w.role = 'worker'"]; + let whereClauses = ["w.role = 'worker'", "w.status != 'deleted'"]; // Filter out soft-deleted workers if (search) { whereClauses.push(`(w.full_name LIKE ? OR w.department LIKE ?)`); @@ -393,8 +500,91 @@ export default function(db) { } }); + // GET all managers with their permissions + router.get('/managers', checkPermission('manager_permissions'), async (req, res) => { + try { + const { search = '', page = 1, limit = 20 } = req.query; + const offset = (parseInt(page) - 1) * parseInt(limit); + const searchTerm = `%${search}%`; + + let baseQuery = ` + SELECT + w.id, w.username, w.full_name, w.department, w.position, w.created_at, w.status, + mp.* + FROM workers w + LEFT JOIN manager_permissions mp ON w.id = mp.manager_id + `; + let countQuery = `SELECT COUNT(w.id) as totalCount FROM workers w`; + + const params = []; + const countParams = []; + let whereClauses = ["w.role = 'manager'", "w.status != 'deleted'"]; + + if (search) { + whereClauses.push(`(w.full_name LIKE ? OR w.department LIKE ?)`); + params.push(searchTerm, searchTerm); + countParams.push(searchTerm, searchTerm); + } + + if (whereClauses.length > 0) { + const whereString = ` WHERE ${whereClauses.join(' AND ')}`; + baseQuery += whereString; + countQuery += whereString; + } + + baseQuery += ` ORDER BY w.created_at DESC LIMIT ? OFFSET ?`; + params.push(parseInt(limit), offset); + + const [managers] = await db.execute(baseQuery, params); + const [[{ totalCount }]] = await db.execute(countQuery, countParams); + + res.json({ managers, totalCount }); + } catch (error) { + console.error('Get managers error:', error); + res.status(500).json({ message: 'Database error fetching managers.', details: error.message }); + } + }); + + // POST (add) a new manager + router.post('/managers', checkPermission('manager_permissions'), async (req, res) => { + try { + const { username, password, fullName, department, position } = req.body; + if (!username || !password || !fullName) { + return res.status(400).json({ message: 'Username, password, and full name are required.' }); + } + const hashedPassword = await bcrypt.hash(password, 10); + const [result] = await db.execute( + 'INSERT INTO workers (username, password_hash, full_name, role, department, position, status) VALUES (?, ?, ?, ?, ?, ?, ?)', + [username, hashedPassword, fullName, 'manager', department, position, 'active'] + ); + + // Set default view_all permission + await db.execute( + 'INSERT INTO manager_permissions (manager_id, view_all) VALUES (?, ?)', + [result.insertId, true] + ); + + res.status(201).json({ + id: result.insertId, + username, + fullName, + role: 'manager', + department, + position, + status: 'active', + view_all: true + }); + } catch (error) { + console.error('Add manager error:', error); + if (error.code === 'ER_DUP_ENTRY') { + return res.status(409).json({ message: 'Username already exists.' }); + } + res.status(500).json({ message: 'Database error adding manager.', details: error.message }); + } + }); + // POST (add) a new worker - router.post('/workers', async (req, res) => { + router.post('/workers', checkPermission('edit_workers'), async (req, res) => { try { const { username, password, fullName, department, position, role = 'worker' } = req.body; if (!username || !password || !fullName) { @@ -402,10 +592,10 @@ export default function(db) { } const hashedPassword = await bcrypt.hash(password, 10); const [result] = await db.execute( - 'INSERT INTO workers (username, password_hash, full_name, role, department, position) VALUES (?, ?, ?, ?, ?, ?)', - [username, hashedPassword, fullName, role, department, position] + 'INSERT INTO workers (username, password_hash, full_name, role, department, position, status) VALUES (?, ?, ?, ?, ?, ?, ?)', + [username, hashedPassword, fullName, role, department, position, 'active'] // Default status to 'active' ); - res.status(201).json({ id: result.insertId, username, fullName, role, department, position }); + res.status(201).json({ id: result.insertId, username, fullName, role, department, position, status: 'active' }); } catch (error) { console.error('Add worker error:', error); if (error.code === 'ER_DUP_ENTRY') { @@ -415,23 +605,132 @@ export default function(db) { } }); - // DELETE a worker - router.delete('/workers/:id', async (req, res) => { + // Soft DELETE a worker (update status to 'deleted') + router.delete('/workers/:id', checkPermission('edit_workers'), async (req, res) => { try { const { id } = req.params; - const [result] = await db.execute("DELETE FROM workers WHERE id = ? AND role = 'worker'", [id]); + const [result] = await db.execute("UPDATE workers SET status = 'deleted' WHERE id = ? AND role = 'worker'", [id]); if (result.affectedRows === 0) { - return res.status(404).json({ message: 'Worker not found.' }); + return res.status(404).json({ message: 'Worker not found or already deleted.' }); + } + res.status(204).send(); // Maintain existing response for client compatibility + } catch (error) { + console.error('Soft delete worker error:', error); + res.status(500).json({ message: 'Database error soft deleting worker.', details: error.message }); + } + }); + + // Soft DELETE a manager (update status to 'deleted') + router.delete('/managers/:id', checkPermission('manager_permissions'), async (req, res) => { + try { + const { id } = req.params; + const [result] = await db.execute("UPDATE workers SET status = 'deleted' WHERE id = ? AND role = 'manager'", [id]); + if (result.affectedRows === 0) { + return res.status(404).json({ message: 'Manager not found or already deleted.' }); } res.status(204).send(); } catch (error) { - console.error('Delete worker error:', error); - res.status(500).json({ message: 'Database error deleting worker.', details: error.message }); + console.error('Soft delete manager error:', error); + res.status(500).json({ message: 'Database error soft deleting manager.', details: error.message }); + } + }); + + // PUT (update) a worker's details (department, position, status) + router.put('/workers/:id', checkPermission('edit_workers'), async (req, res) => { + try { + const { id } = req.params; + const { department, position, status } = req.body; + + // Basic validation + if (!department && !position && !status) { + return res.status(400).json({ message: 'No update information provided.' }); + } + if (status && !['active', 'inactive'].includes(status)) { + return res.status(400).json({ message: 'Invalid status value.' }); + } + + let updateQuery = 'UPDATE workers SET'; + const params = []; + const fieldsToUpdate = []; + + if (department) { + fieldsToUpdate.push('department = ?'); + params.push(department); + } + if (position) { + fieldsToUpdate.push('position = ?'); + params.push(position); + } + if (status) { + fieldsToUpdate.push('status = ?'); + params.push(status); + } + + updateQuery += ` ${fieldsToUpdate.join(', ')} WHERE id = ? AND role = 'worker'`; + params.push(id); + + const [result] = await db.execute(updateQuery, params); + + if (result.affectedRows === 0) { + return res.status(404).json({ message: 'Worker not found.' }); + } + + res.status(200).json({ message: 'Worker details updated successfully.' }); + } catch (error) { + console.error('Update worker details error:', error); + res.status(500).json({ message: 'Database error updating worker details.', details: error.message }); + } + }); + + // PUT (update) a manager's details (department, position, status) + router.put('/managers/:id', checkPermission('manager_permissions'), async (req, res) => { + try { + const { id } = req.params; + const { department, position, status } = req.body; + + // Basic validation + if (!department && !position && !status) { + return res.status(400).json({ message: 'No update information provided.' }); + } + if (status && !['active', 'inactive'].includes(status)) { + return res.status(400).json({ message: 'Invalid status value.' }); + } + + let updateQuery = 'UPDATE workers SET'; + const params = []; + const fieldsToUpdate = []; + + if (department) { + fieldsToUpdate.push('department = ?'); + params.push(department); + } + if (position) { + fieldsToUpdate.push('position = ?'); + params.push(position); + } + if (status) { + fieldsToUpdate.push('status = ?'); + params.push(status); + } + + updateQuery += ` ${fieldsToUpdate.join(', ')} WHERE id = ? AND role = 'manager'`; + params.push(id); + + const [result] = await db.execute(updateQuery, params); + + if (result.affectedRows === 0) { + return res.status(404).json({ message: 'Manager not found.' }); + } + + res.status(200).json({ message: 'Manager details updated successfully.' }); + } catch (error) { + console.error('Update manager details error:', error); + res.status(500).json({ message: 'Database error updating manager details.', details: error.message }); } }); // PUT (update) a worker's password - router.put('/workers/:workerId/password', async (req, res) => { + router.put('/workers/:workerId/password', checkPermission('edit_workers'), async (req, res) => { try { const { workerId } = req.params; const { newPassword } = req.body; @@ -450,24 +749,57 @@ export default function(db) { } }); - // PUT (clear) a worker's device UUID - router.put('/workers/:workerId/reset-device', async (req, res) => { + // PUT (update) a manager's password + router.put('/managers/:managerId/password', checkPermission('manager_permissions'), async (req, res) => { + try { + const { managerId } = req.params; + const { newPassword } = req.body; + if (!newPassword || newPassword.length < 6) { + return res.status(400).json({ message: 'Password must be at least 6 characters long.' }); + } + const hashedPassword = await bcrypt.hash(newPassword, 10); + const [result] = await db.execute("UPDATE workers SET password_hash = ? WHERE id = ? AND role = 'manager'", [hashedPassword, managerId]); + if (result.affectedRows === 0) { + return res.status(404).json({ message: 'Manager not found.' }); + } + res.status(200).json({ message: 'Password updated successfully.' }); + } catch (error) { + console.error('Update manager password error:', error); + res.status(500).json({ message: 'Database error updating manager password.', details: error.message }); + } + }); + + // PUT (clear) a worker's device UUID and/or update status + router.put('/workers/:workerId/reset-device', checkPermission('edit_workers'), async (req, res) => { try { const { workerId } = req.params; - const [result] = await db.execute("UPDATE workers SET device_uuid = NULL WHERE id = ?", [workerId]); + const { status } = req.body; // Optional status field + + let updateQuery = "UPDATE workers SET device_uuid = NULL"; + const params = [workerId]; + + if (status && ['active', 'inactive', 'deleted'].includes(status)) { + updateQuery += ", status = ?"; + params.unshift(status); // Add status to the beginning of params for correct order + } + + updateQuery += " WHERE id = ?"; + + const [result] = await db.execute(updateQuery, params); + if (result.affectedRows === 0) { return res.status(404).json({ message: 'Worker not found.' }); } - res.status(200).json({ message: 'Device registration cleared.' }); + res.status(200).json({ message: 'Device registration cleared and/or status updated.' }); } catch (error) { - console.error('Reset device error:', error); - res.status(500).json({ message: 'Database error resetting device.', details: error.message }); + console.error('Reset device/update status error:', error); + res.status(500).json({ message: 'Database error resetting device or updating status.', details: error.message }); } }); // Geofence Management Routes - router.get('/geofences', async (req, res) => { + router.get('/geofences', checkPermission('view_all'), async (req, res) => { try { const [rows] = await db.execute( 'SELECT id, name, coordinates, is_active, created_at FROM geofences ORDER BY created_at DESC' @@ -483,7 +815,7 @@ export default function(db) { } }); - router.post('/geofences', async (req, res) => { + router.post('/geofences', checkPermission('manage_resources'), async (req, res) => { try { const { name, coordinates } = req.body; if (!name || !coordinates) { @@ -508,7 +840,7 @@ export default function(db) { } }); - router.put('/geofences/:id', async (req, res) => { + router.put('/geofences/:id', checkPermission('manage_resources'), async (req, res) => { try { const { id } = req.params; const { is_active } = req.body; @@ -533,7 +865,7 @@ export default function(db) { } }); - router.delete('/geofences/:id', async (req, res) => { + router.delete('/geofences/:id', checkPermission('manage_resources'), async (req, res) => { try { const { id } = req.params; const [result] = await db.execute('DELETE FROM geofences WHERE id = ?', [id]); @@ -551,7 +883,7 @@ export default function(db) { // QR Code Management Routes - router.get('/qr-codes', authenticateJWT, async (req, res) => { + router.get('/qr-codes', checkPermission('view_all'), async (req, res) => { try { const [rows] = await db.execute( 'SELECT id, name, is_active, created_at FROM qr_codes ORDER BY created_at DESC' @@ -563,7 +895,7 @@ export default function(db) { } }); - router.post('/qr-codes', authenticateJWT, async (req, res) => { + router.post('/qr-codes', checkPermission('manage_resources'), async (req, res) => { try { const { name } = req.body; if (!name) return res.status(400).json({ message: 'QR Code name is required.' }); @@ -586,7 +918,7 @@ export default function(db) { } }); - router.put('/qr-codes/:id', authenticateJWT, async (req, res) => { + router.put('/qr-codes/:id', checkPermission('manage_resources'), async (req, res) => { try { const { id } = req.params; // Handle both isActive (camelCase) and is_active (snake_case) @@ -612,7 +944,7 @@ export default function(db) { } }); - router.delete('/qr-codes/:id', authenticateJWT, async (req, res) => { + router.delete('/qr-codes/:id', checkPermission('manage_resources'), async (req, res) => { try { const { id } = req.params; const [result] = await db.execute( diff --git a/backend/rootCA.pem b/backend/rootCA.pem new file mode 100644 index 0000000..f8213ef --- /dev/null +++ b/backend/rootCA.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE8zCCA1ugAwIBAgIQGdkeqkj233eI/7av8ih4aTANBgkqhkiG9w0BAQsFADCB +kTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTMwMQYDVQQLDCpNQUlM +XG1hc29uZ3lhbkBERVNLVE9QLUlRVThEREQgKG1hc29uZ3lhbikxOjA4BgNVBAMM +MW1rY2VydCBNQUlMXG1hc29uZ3lhbkBERVNLVE9QLUlRVThEREQgKG1hc29uZ3lh +bikwHhcNMjUwNzAzMDg1NDI2WhcNMzUwNzAzMDg1NDI2WjCBkTEeMBwGA1UEChMV +bWtjZXJ0IGRldmVsb3BtZW50IENBMTMwMQYDVQQLDCpNQUlMXG1hc29uZ3lhbkBE +RVNLVE9QLUlRVThEREQgKG1hc29uZ3lhbikxOjA4BgNVBAMMMW1rY2VydCBNQUlM +XG1hc29uZ3lhbkBERVNLVE9QLUlRVThEREQgKG1hc29uZ3lhbikwggGiMA0GCSqG +SIb3DQEBAQUAA4IBjwAwggGKAoIBgQC5YL+VRL/bDBg0SP78IZTCemeLr7Q4Zxtg +8MiaWrDnh6ssVFzmAY3PEnfTdSL/j0JV2I0cSZhmMkUAzoo7136paLA3aGD4QP0B +fDEt6xQZF30U3bRhTglEY8a1zhy6fJGTYOcl2/OTbS0q90fEaLx8wkVa0lf/2wA7 +fYG65BSu9CgTdob6NBWbI3Jpsesxd+36WZCqa6ZPSk07nXozqjMFsG8CThr1Wmei +mZJZF6+ji0mI6RqiqgdWrKBp2FZbPERQS+QfYfKD5/N0cWpwUAxejSLlPxU886Ns +Tcld9vxHQjzcE0afJe7rO4IrzzIeL1oLsz3xhEBgn8JCUeWbU12pk+9j1z+/M0+U +LUt/g+cwHk8fKl7qoL1ydR7afDdFBR8ns+g5l40ZE/uwhgQA8uTsi2E18B5agAtQ +C6+dJC4bMiVn9iyCeQmPKS+xw4YOVmn0yfrkqRLRgSZDjQEd4pUAep4J/8WbI1BY +lNqRwmqBcLuuyQLpExlMBYPMWiWYBakCAwEAAaNFMEMwDgYDVR0PAQH/BAQDAgIE +MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFElRm5C15845O14vXvSvwjxw +tiJEMA0GCSqGSIb3DQEBCwUAA4IBgQAIjI0pKdY1/NKIaCg0WuQcWh8/noTjqYdl +7RDJ+JQZB1W0SkN7XvSLiRcEroWalbq9BMwE/bwV9jcgW1NvQ+00VzUWKh0r9z3B +xjEnKnK+1pEXRdBfkG6bVi2XehNs7KOvqR07xv7o9GdB41R7TSo1Vr228ot82FNO +6B2iDumfIr9RESsx8nVntHvRuFTee/DlhVUEgJPWmw0Kwcewmd2p5XNijdA2V2nI +zwhUxQuuu0LtV8RXmBi5vDanrJHwZZ1kFvGG9SGiVNx6aEtGBjTMIFRpQyLFzeq9 +TPbVLsEGjvi8wLqO8U/aj56BEkFNKAx0idohgyfF2qohRMXoL0MRtEQIpJdL2kMP +Gqg1aY7MWooEM9swji1hHuoDwLriVNS6W3LvT9qXWlI3e/J7f5aLT/QyP4VUW+4N +1oGUL54aXCMYymVXooU3QomakxCildlGbH0jdcf8uX8JVnI0Zeo3ftCmtf46Q+Lu +7Mhu4NO8kQGHH/m0wQwwahh+mBfwYwk= +-----END CERTIFICATE----- diff --git a/backend/workerRoutes.js b/backend/workerRoutes.js index f64320f..9eb3239 100644 --- a/backend/workerRoutes.js +++ b/backend/workerRoutes.js @@ -24,23 +24,55 @@ async function isClockingEnabled(db) { export default function(db) { const router = express.Router(); + // Set DEVICE_UUID_ENABLED to false to completely disable device UUID checking + const DEVICE_UUID_ENABLED = false; + const REQUIRE_DEVICE_FOR_WORKERS = true; + const AUTO_REGISTER_NEW_DEVICES = true; + router.post('/auth/login', async (req, res) => { const { username, password, deviceUuid } = req.body; - const [rows] = await db.execute('SELECT id, role, password_hash FROM workers WHERE username = ?', [username]); + const [rows] = await db.execute('SELECT id, role, password_hash, status FROM workers WHERE username = ?', [username]); if (rows.length === 0) { return res.status(401).json({ message: 'Invalid credentials' }); } const user = rows[0]; + + // Check if the user's status is 'active' + if (user.status !== 'active') { + return res.status(401).json({ message: 'Invalid credentials' }); + } + const passwordMatch = await bcrypt.compare(password, user.password_hash); if (!passwordMatch) { return res.status(401).json({ message: 'Invalid credentials' }); } - if (deviceUuid && user.role !== 'manager') { - const deviceValidation = await validateDeviceForUser(user.id, deviceUuid, db); - if (!deviceValidation.valid) { - return res.status(403).json({ message: deviceValidation.message }); + + // Device UUID handling - controlled by configuration flags above + if (DEVICE_UUID_ENABLED && user.role === 'worker') { + const [deviceRows] = await db.execute('SELECT device_uuid FROM workers WHERE id = ?', [user.id]); + const existingDeviceUuid = deviceRows[0].device_uuid; + + if (existingDeviceUuid) { + if (deviceUuid && deviceUuid !== existingDeviceUuid) { + return res.status(403).json({ message: 'deviceMismatch' }); + } else if (!deviceUuid) { + return res.status(403).json({ message: 'useMobileApp' }); + } + } else { + // User has no registered device + if (deviceUuid && AUTO_REGISTER_NEW_DEVICES) { + const deviceResult = await validateDeviceForUser(user.id, deviceUuid, db); + if (!deviceResult.valid) { + return res.status(500).json({ message: 'deviceRegistrationFailed' }); + } + // console.log(`Device UUID registered for worker ${user.id}: ${deviceUuid}`); + } else if (!deviceUuid && REQUIRE_DEVICE_FOR_WORKERS) { + return res.status(403).json({ message: 'deviceRequired' }); + } } } + + // Managers can always login, workers without device_uuid can login const token = jwt.sign({ userId: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1h' }); res.json({ token }); }); @@ -53,7 +85,7 @@ export default function(db) { if (err) { return res.status(403).json({ message: 'Invalid or expired token' }); } - req.user = user; + req.user = { ...user, id: user.userId }; // Correctly map userId to id next(); }); } else { diff --git a/dev.sql b/dev.sql deleted file mode 100644 index 05787a8..0000000 --- a/dev.sql +++ /dev/null @@ -1,207 +0,0 @@ -# Host: localhost (Version: 5.7.26) -# Date: 2025-07-16 13:39:50 -# Generator: MySQL-Front 5.3 (Build 4.234) - -/*!40101 SET NAMES utf8 */; - -# -# Structure for table "app_blacklist" -# - -CREATE TABLE `app_blacklist` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `package_name` varchar(255) NOT NULL, - `reason` varchar(255) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `package_name` (`package_name`) -) ENGINE=MyISAM AUTO_INCREMENT=50 DEFAULT CHARSET=utf8; - -# -# Data for table "app_blacklist" -# - -INSERT INTO `app_blacklist` VALUES (4,'com.lexa.fakegps','GPS Spoofing App','2025-07-09 11:59:55'),(5,'com.incorporateapps.fakegps.fre','GPS Spoofing App','2025-07-09 11:59:55'),(6,'com.blogspot.newapphorizons.fakegps','GPS Spoofing App','2025-07-09 11:59:55'),(7,'com.theappninjas.gpsjoystick','GPS Spoofing App','2025-07-09 11:59:55'),(8,'com.fakegps.mock','GPS Spoofing App','2025-07-09 11:59:55'),(9,'com.mock.location.app','GPS Spoofing App','2025-07-09 11:59:55'),(10,'com.fakegps.location','GPS Spoofing App','2025-07-09 11:59:55'),(11,'com.gpsemulator','GPS Spoofing App','2025-07-09 11:59:55'),(12,'com.locationspoofer','GPS Spoofing App','2025-07-09 11:59:55'),(13,'com.fakegps.pro','GPS Spoofing App','2025-07-09 11:59:55'),(14,'com.mock.gps.location','GPS Spoofing App','2025-07-09 11:59:55'),(15,'com.gps.mock.location','GPS Spoofing App','2025-07-09 11:59:55'),(16,'com.fake.location.spoofer','GPS Spoofing App','2025-07-09 11:59:55'),(17,'com.location.faker','GPS Spoofing App','2025-07-09 11:59:55'),(18,'com.gps.faker','GPS Spoofing App','2025-07-09 11:59:55'),(19,'com.mock.location.faker','GPS Spoofing App','2025-07-09 11:59:55'),(20,'com.location.mock.gps','GPS Spoofing App','2025-07-09 11:59:55'),(21,'com.gps.location.faker','GPS Spoofing App','2025-07-09 11:59:55'),(22,'com.fake.gps.location.spoofer','GPS Spoofing App','2025-07-09 11:59:55'),(23,'com.location.spoofer.gps','GPS Spoofing App','2025-07-09 11:59:55'),(24,'com.hola.mocklocation','Location Simulation App','2025-07-09 12:00:50'),(25,'com.lexa.fakegps.route','Location Simulation App','2025-07-09 12:00:50'),(26,'com.fakegps.mock.location.app','Location Simulation App','2025-07-09 12:00:50'),(27,'com.mock.location.app.free','Location Simulation App','2025-07-09 12:00:50'),(28,'com.location.mock.free','Location Simulation App','2025-07-09 12:00:50'),(29,'com.gps.mock.free','Location Simulation App','2025-07-09 12:00:50'),(33,'com.topjohnwu.magisk','Root Management/Evasion Tool','2025-07-09 12:01:02'),(34,'com.noshufou.android.su','Root Management/Evasion Tool','2025-07-09 12:01:02'),(35,'com.koushikdutta.superuser','Root Management/Evasion Tool','2025-07-09 12:01:02'),(36,'com.zachspong.temprootremovejb','Root Management/Evasion Tool','2025-07-09 12:01:02'),(37,'com.ramdroid.appquarantine','Root Management/Evasion Tool','2025-07-09 12:01:02'),(38,'com.devadvance.rootcloak','Root Management/Evasion Tool','2025-07-09 12:01:02'),(39,'com.devadvance.rootcloakplus','Root Management/Evasion Tool','2025-07-09 12:01:02'),(40,'de.robv.android.xposed.installer','Root Management/Evasion Tool','2025-07-09 12:01:02'),(41,'com.saurik.substrate','Root Management/Evasion Tool','2025-07-09 12:01:02'),(42,'com.amphoras.hidemyroot','Root Management/Evasion Tool','2025-07-09 12:01:02'),(43,'com.amphoras.hidemyrootadfree','Root Management/Evasion Tool','2025-07-09 12:01:02'),(44,'com.formyhm.hiderootPremium','Root Management/Evasion Tool','2025-07-09 12:01:02'),(45,'me.phh.superuser','Root Management/Evasion Tool','2025-07-09 12:01:02'),(46,'eu.chainfire.supersu','Root Management/Evasion Tool','2025-07-09 12:01:02'),(47,'com.kingouser.com','Root Management/Evasion Tool','2025-07-09 12:01:02'),(48,'com.android.vending.billing.InAppBillingService.LOCK','App Cracking/Patching Tool','2025-07-09 12:01:02'),(49,'com.android.vending.billing.InAppBillingService.LACK','App Cracking/Patching Tool','2025-07-09 12:01:02'); - -# -# Structure for table "clock_records" -# - -CREATE TABLE `clock_records` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `worker_id` int(11) NOT NULL, - `event_type` enum('clock_in','clock_out','failed') NOT NULL, - `timestamp` datetime NOT NULL, - `qr_code_id` varchar(255) DEFAULT NULL, - `latitude` decimal(10,8) DEFAULT NULL, - `longitude` decimal(11,8) DEFAULT NULL, - `notes` text, - PRIMARY KEY (`id`), - KEY `worker_id` (`worker_id`), - KEY `qr_code_id` (`qr_code_id`) -) ENGINE=MyISAM AUTO_INCREMENT=106 DEFAULT CHARSET=utf8 COMMENT='Logs every clock-in and clock-out event for all workers.'; - -# -# Data for table "clock_records" -# - -INSERT INTO `clock_records` VALUES (50,6,'clock_in','2025-07-08 14:09:24','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13490670,113.32259360,NULL),(51,6,'clock_out','2025-07-08 15:45:43','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13486030,113.32251780,NULL),(52,6,'clock_in','2025-07-08 15:46:05','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13486030,113.32251780,NULL),(53,4,'failed','2025-07-09 09:50:28','9f72afba-ebb6-445d-a7fc-58df9902777b',37.42199830,-122.08400000,'Clock-in outside of the zone: 11134377.47 meters.'),(54,4,'failed','2025-07-09 09:52:56','9f72afba-ebb6-445d-a7fc-58df9902777b',37.42199830,-122.08400000,'Clock-in outside of the zone: 11134377.47 meters.'),(55,4,'failed','2025-07-09 09:54:43','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,'Clock-in outside of the zone: 392.58 meters.'),(56,4,'failed','2025-07-09 09:57:11','9f72afba-ebb6-445d-a7fc-58df9902777b',23.12999830,113.31499830,'Clock-in outside of the zone: 376.27 meters.'),(57,4,'failed','2025-07-09 09:57:37','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13086670,113.32691330,'Clock-in outside of the zone: 455.18 meters.'),(58,4,'failed','2025-07-09 09:58:01','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13244650,113.32775730,'Clock-in outside of the zone: 399.79 meters.'),(59,4,'failed','2025-07-09 09:58:23','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13244670,113.32784160,'Clock-in outside of the zone: 406.12 meters.'),(60,4,'failed','2025-07-09 09:58:51','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13312330,113.32783670,'Clock-in outside of the zone: 354.82 meters.'),(61,4,'failed','2025-07-09 10:05:28','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13312670,113.32783670,'Clock-in outside of the zone: 354.57 meters.'),(62,4,'failed','2025-07-09 10:13:54','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13312670,113.32783670,'Clock-in outside of the zone: 354.57 meters.'),(63,4,'clock_in','2025-07-09 10:16:51','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13312670,113.32783670,NULL),(64,4,'clock_out','2025-07-09 15:01:53','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13312670,113.32783670,NULL),(65,4,'clock_in','2025-07-09 15:06:55','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13312670,113.32783670,NULL),(66,4,'clock_out','2025-07-09 18:02:51','FORCE_CLOCK_OUT',0.00000000,0.00000000,'Blacklisted App Detected'),(67,4,'failed','2025-07-09 18:08:08','FORCE_CLOCK_OUT',0.00000000,0.00000000,'Forced clock-out failed: User already clocked out.'),(68,4,'clock_out','2025-07-09 18:16:54','FORCE_CLOCK_OUT',0.00000000,0.00000000,'Blacklisted App Detected'),(69,4,'failed','2025-07-09 18:22:09','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(70,4,'failed','2025-07-09 18:23:58','9f72afba-ebb6-445d-a7fc-58df9902777b',37.42198810,-122.08399140,'Clock-in outside of the zone: 11134378.78 meters.'),(71,4,'failed','2025-07-09 18:24:58','9f72afba-ebb6-445d-a7fc-58df9902777b',37.42198810,-122.08399140,'Clock-in outside of the zone: 11134378.78 meters.'),(72,4,'failed','2025-07-09 18:29:30','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,'Clock-in outside of the zone: 392.58 meters.'),(73,4,'failed','2025-07-10 10:13:12','9f72afba-ebb6-445d-a7fc-58df9902777b',37.42199830,-122.08400000,'Clock-in outside of the zone: 11134237.56 meters.'),(74,4,'failed','2025-07-10 10:13:43','9f72afba-ebb6-445d-a7fc-58df9902777b',37.42199830,-122.08400000,'Clock-in outside of the zone: 11134237.56 meters.'),(75,4,'failed','2025-07-10 10:14:45','9f72afba-ebb6-445d-a7fc-58df9902777b',25.21599040,141.62428650,'Clock-in outside of the zone: 2871482.21 meters.'),(76,4,'failed','2025-07-10 10:14:48','9f72afba-ebb6-445d-a7fc-58df9902777b',23.92816100,124.13230650,'Clock-in outside of the zone: 1101840.15 meters.'),(77,4,'clock_in','2025-07-10 10:18:00','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(78,4,'clock_out','2025-07-10 10:38:50','FORCE_CLOCK_OUT',NULL,NULL,'Blacklisted App Detected'),(79,4,'failed','2025-07-10 10:59:12','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(80,4,'clock_out','2025-07-10 11:05:34','FORCE_CLOCK_OUT',NULL,NULL,'Blacklisted App Detected'),(81,6,'clock_out','2025-07-10 11:11:04','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13362700,113.32298620,NULL),(82,6,'clock_in','2025-07-10 11:11:44','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13362700,113.32298620,NULL),(83,6,'clock_out','2025-07-10 11:25:20','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(84,6,'clock_in','2025-07-10 11:29:30','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(85,6,'clock_out','2025-07-10 11:29:34','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(86,6,'clock_in','2025-07-10 11:29:53','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(87,6,'clock_out','2025-07-10 11:29:58','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(88,6,'clock_in','2025-07-10 11:48:36','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(89,6,'clock_out','2025-07-10 11:48:40','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13370560,113.32305440,NULL),(90,4,'failed','2025-07-10 13:29:58','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(91,10,'clock_out','2025-07-10 13:31:07','FORCE_CLOCK_OUT',NULL,NULL,'Blacklisted App Detected'),(92,10,'failed','2025-07-10 13:32:06','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(93,10,'clock_out','2025-07-10 13:33:38','FORCE_CLOCK_OUT',NULL,NULL,'Blacklisted App Detected'),(94,10,'failed','2025-07-10 13:40:42','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(95,10,'clock_out','2025-07-10 13:41:01','FORCE_CLOCK_OUT',NULL,NULL,'Blacklisted App Detected'),(96,10,'failed','2025-07-10 13:47:44','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(97,10,'failed','2025-07-10 13:48:00','FORCE_CLOCK_OUT',0.00000000,0.00000000,'FAKE GPS APP Detected.'),(98,10,'clock_in','2025-07-10 14:04:48','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(99,4,'clock_in','2025-07-10 14:17:24','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(100,4,'clock_out','2025-07-10 14:18:00','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(101,4,'clock_in','2025-07-15 08:41:40','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(102,4,'clock_out','2025-07-15 08:48:43','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(103,4,'clock_in','2025-07-15 08:52:03','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(104,4,'clock_out','2025-07-15 08:52:09','9f72afba-ebb6-445d-a7fc-58df9902777b',23.13269830,113.32791330,NULL),(105,10,'clock_out','2025-07-16 09:44:00',NULL,NULL,NULL,'test'); - -# -# Structure for table "geofences" -# - -CREATE TABLE `geofences` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL, - `coordinates` text NOT NULL, - `is_active` tinyint(1) DEFAULT '1', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; - -# -# Data for table "geofences" -# - -INSERT INTO `geofences` VALUES (1,'Main Work Area','[[113.35311466293217,23.161344441258407],[113.28591534444001,23.161344441258407],[113.28591534444001,23.091366234233973],[113.35311466293217,23.091366234233973],[113.35311466293217,23.161344441258407]]',1,'2025-07-14 16:07:32'); - -# -# Structure for table "location_updates" -# - -CREATE TABLE `location_updates` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` int(11) NOT NULL, - `longitude` decimal(11,8) NOT NULL COMMENT 'Longitude first for geographic convention', - `latitude` decimal(10,8) NOT NULL COMMENT 'Latitude second for geographic convention', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Single timestamp field', - PRIMARY KEY (`id`), - KEY `idx_user_id` (`user_id`), - KEY `idx_created_at` (`created_at`), - KEY `idx_user_created` (`user_id`,`created_at`) COMMENT 'Composite index for user location history' -) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='Optimized for 30-minute updates - essential fields only (longitude, latitude, created_at)'; - -# -# Data for table "location_updates" -# - -INSERT INTO `location_updates` VALUES (1,4,113.32791330,23.13269830,'2025-07-15 16:41:41'),(2,4,113.32791330,23.13269830,'2025-07-15 16:52:04'); - -# -# Structure for table "qr_codes" -# - -CREATE TABLE `qr_codes` ( - `id` varchar(255) NOT NULL COMMENT 'Using the UUID string as the primary key', - `name` varchar(255) NOT NULL, - `is_active` tinyint(1) NOT NULL DEFAULT '1', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Stores all physical QR code locations and their status.'; - -# -# Data for table "qr_codes" -# - -INSERT INTO `qr_codes` VALUES ('19e8f029-2e61-4b34-af3a-ee985f2cff74','Gate A -2',1,'2025-06-20 14:42:29'),('4afb2111-cff8-4706-bc87-44518492d5f6','test',1,'2025-07-02 11:41:21'),('9f72afba-ebb6-445d-a7fc-58df9902777b','GATE A',1,'2025-06-26 15:56:14'),('ASSEMBLY-LINE-1','Assembly Line 1',1,'2025-06-13 13:39:51'),('d654a6bf-2b48-49e9-95c8-4fe9af6c3e44','Gate B',1,'2025-06-13 14:00:31'),('d7ac9594-ad9f-48dc-b984-5a9e7ea7e995','weast',1,'2025-06-20 14:55:09'),('FACTORY-MAIN-ENTRANCE','Factory Main Entrance',1,'2025-06-13 13:39:51'),('WAREHOUSE-SECTION-A','Warehouse Section A',1,'2025-06-13 13:39:51'); - -# -# Structure for table "security_alerts" -# - -CREATE TABLE `security_alerts` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` int(11) NOT NULL, - `alert_type` varchar(100) NOT NULL, - `alert_data` json DEFAULT NULL, - `severity` enum('low','medium','high','critical') DEFAULT 'medium', - `is_resolved` tinyint(1) DEFAULT '0', - `resolved_at` timestamp NULL DEFAULT NULL, - `resolved_by` int(11) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - KEY `resolved_by` (`resolved_by`), - KEY `idx_user_id` (`user_id`), - KEY `idx_alert_type` (`alert_type`), - KEY `idx_severity` (`severity`), - KEY `idx_is_resolved` (`is_resolved`), - KEY `idx_created_at` (`created_at`) -) ENGINE=MyISAM AUTO_INCREMENT=272 DEFAULT CHARSET=utf8; - -# -# Data for table "security_alerts" -# - - -# -# Structure for table "security_checks" -# - -CREATE TABLE `security_checks` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` int(11) NOT NULL, - `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `device_info` json DEFAULT NULL, - `security_data` json DEFAULT NULL, - `risk_level` enum('low','medium','high') DEFAULT 'low', - `risk_score` int(11) DEFAULT '0', - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - KEY `idx_user_id` (`user_id`), - KEY `idx_risk_level` (`risk_level`), - KEY `idx_timestamp` (`timestamp`), - KEY `idx_created_at` (`created_at`) -) ENGINE=MyISAM AUTO_INCREMENT=107 DEFAULT CHARSET=utf8; - -# -# Data for table "security_checks" -# - - -# -# Structure for table "workers" -# - -CREATE TABLE `workers` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `password_hash` varchar(255) NOT NULL COMMENT 'Store hashed passwords, not plain text!', - `full_name` varchar(255) NOT NULL, - `role` enum('worker','manager') NOT NULL, - `device_uuid` varchar(255) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `department` varchar(50) DEFAULT NULL, - `position` varchar(100) DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `username` (`username`), - KEY `idx_device_uuid` (`device_uuid`) -) ENGINE=MyISAM AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='Stores user account information for both workers and managers.'; - -# -# Data for table "workers" -# - -INSERT INTO `workers` VALUES (1,'worker','$2b$10$ej9XEoBLd6Gl0OJvQbScdeACzdHt98VJVsxs7PqV6XSyhfsVCGfNe','John Doe','worker',NULL,'2025-06-13 13:39:51','test','test'),(2,'worker2','$2b$10$SxjhV19fhO1ILISNxxVJXeJ23Z3p/Dclt47c0j7SfuliROKDpANQC','Jane Smith','worker','7cf298e6-7cf2-4cf2-f306-5365d6d7','2025-06-13 13:39:51','test','test'),(3,'manager','$2b$10$GkPmwkSIxv0d6z/R6S/PCe5NLwgKtAOP7/FDCUwR1vCFZ7ex3FeNi','Manager Bob','manager',NULL,'2025-06-13 13:39:51','test','test'),(4,'ryanlee','$2b$10$jsYy.2SzpJ9A0LWu6CpoK.mZ3GZWZoIp8g81sRfKt2G4Dipjp8Sa6','Ryan Lee','worker','557fd11d-557f-457f-f214-14df7cf1','2025-06-13 14:48:06','testb','test'),(6,'modewang','$2b$10$4gb.m2IgY9iJoVjyVUQ9IuUmiKNuR6TlxUsXmiaSpf8XFrnko8bcG','Ryan Qi','worker',NULL,'2025-06-13 15:53:08','testb','test'),(8,'bwilliams','$2b$10$MsJ1baJE.g4tAm1HOhTFD.cz1vd80BRPQE//hNVuikdLf2QOhdLi6','Bob Williams','worker',NULL,'2025-06-13 15:57:30','testb','test'),(10,'dmiller','$2b$10$e0cpp2JcfExeB9APu2Hbf.H21rn8XBcCsJOCuVUjltlBqTOOQJuDm','Diana Miller','worker','3a2641b6-3a26-4a26-ee92-0d1ea028','2025-06-13 15:57:30','testb','test'); - -# -# Structure for table "active_user_devices" -# - -CREATE VIEW `active_user_devices` AS - select `w`.`id` AS `id`,`w`.`id` AS `user_id`,`w`.`device_uuid` AS `device_uuid`,NULL AS `device_info`,NULL AS `registered_at`,NULL AS `last_seen`,(case when (`w`.`device_uuid` is not null) then 1 else 0 end) AS `is_online`,`w`.`created_at` AS `created_at`,`w`.`created_at` AS `updated_at`,`w`.`username` AS `username`,`w`.`full_name` AS `full_name`,`w`.`role` AS `role`,NULL AS `minutes_since_last_seen` from `workers` `w` where ((`w`.`device_uuid` is not null) and (`w`.`role` = 'worker')); - -# -# Structure for table "recent_location_updates" -# - -CREATE VIEW `recent_location_updates` AS - select `lu`.`id` AS `id`,`lu`.`user_id` AS `user_id`,`lu`.`longitude` AS `longitude`,`lu`.`latitude` AS `latitude`,`lu`.`created_at` AS `created_at`,`w`.`username` AS `username`,`w`.`full_name` AS `full_name`,timestampdiff(MINUTE,`lu`.`created_at`,now()) AS `minutes_ago` from (`location_updates` `lu` join `workers` `w` on((`lu`.`user_id` = `w`.`id`))) where (`lu`.`created_at` > (now() - interval 24 hour)) order by `lu`.`created_at` desc; - -# -# Structure for table "security_summary" -# - -CREATE VIEW `security_summary` AS - select `w`.`id` AS `user_id`,`w`.`username` AS `username`,`w`.`full_name` AS `full_name`,`sc`.`risk_level` AS `latest_risk_level`,`sc`.`risk_score` AS `latest_risk_score`,`sc`.`created_at` AS `last_security_check`,count(`sa`.`id`) AS `active_alerts`,`w`.`device_uuid` AS `current_device`,NULL AS `device_last_seen` from ((`workers` `w` left join `security_checks` `sc` on(((`w`.`id` = `sc`.`user_id`) and (`sc`.`id` = (select max(`security_checks`.`id`) from `security_checks` where (`security_checks`.`user_id` = `w`.`id`)))))) left join `security_alerts` `sa` on(((`w`.`id` = `sa`.`user_id`) and (`sa`.`is_resolved` = FALSE)))) where (`w`.`role` = 'worker') group by `w`.`id`,`w`.`username`,`w`.`full_name`,`sc`.`risk_level`,`sc`.`risk_score`,`sc`.`created_at`,`w`.`device_uuid`; diff --git a/geofence_simple.sql b/geofence_simple.sql deleted file mode 100644 index 238ffa8..0000000 --- a/geofence_simple.sql +++ /dev/null @@ -1,13 +0,0 @@ --- Simple geofence management table -CREATE TABLE IF NOT EXISTS `geofences` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL, - `coordinates` text NOT NULL, - `is_active` tinyint(1) DEFAULT 1, - `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- Insert current geofence as default -INSERT INTO `geofences` (`name`, `coordinates`) VALUES -('Main Work Area', '[[113.35311466293217,23.161344441258407],[113.28591534444001,23.161344441258407],[113.28591534444001,23.091366234233973],[113.35311466293217,23.091366234233973],[113.35311466293217,23.161344441258407]]'); diff --git a/index.html b/index.html index 7652f40..88d4904 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> - Vite App + Ouji Kehadiran
diff --git a/package-lock.json b/package-lock.json index 3c42697..b7a8256 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,7 @@ "name": "nilai-clock", "version": "0.0.0", "dependencies": { - "@capacitor/cli": "^7.4.0", - "@capacitor/core": "^7.4.0", - "@primeuix/themes": "^1.1.2", + "@heroicons/vue": "^2.2.0", "@turf/turf": "^7.2.0", "bcrypt": "^6.0.0", "body-parser": "^2.2.0", @@ -21,7 +19,6 @@ "json2csv": "^6.0.0-alpha.2", "jsonwebtoken": "^9.0.2", "mysql2": "^3.14.2", - "primevue": "^4.3.5", "qrcode": "^1.5.4", "uuid": "^11.1.0", "vue": "^3.5.13", @@ -575,47 +572,6 @@ "node": ">=6.9.0" } }, - "node_modules/@capacitor/cli": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@capacitor/cli/-/cli-7.4.0.tgz", - "integrity": "sha512-RXmsW067r9sz7K1qtXGNB12w2aJtt86J3Jc4vOvmvpA+GyVYkVY1UhAMRnuVrXHjGZEVlwBORHunwrmv30HoZg==", - "license": "MIT", - "dependencies": { - "@ionic/cli-framework-output": "^2.2.8", - "@ionic/utils-subprocess": "^3.0.1", - "@ionic/utils-terminal": "^2.3.5", - "commander": "^12.1.0", - "debug": "^4.4.0", - "env-paths": "^2.2.0", - "fs-extra": "^11.2.0", - "kleur": "^4.1.5", - "native-run": "^2.0.1", - "open": "^8.4.0", - "plist": "^3.1.0", - "prompts": "^2.4.2", - "rimraf": "^6.0.1", - "semver": "^7.6.3", - "tar": "^6.1.11", - "tslib": "^2.8.1", - "xml2js": "^0.6.2" - }, - "bin": { - "cap": "bin/capacitor", - "capacitor": "bin/capacitor" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@capacitor/core": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-7.4.0.tgz", - "integrity": "sha512-P6NnjoHyobZgTjynlZSn27d0SUj6j38inlNxFnKZr9qwU7/r6+0Sg2nWkGkIH/pMmXHsvGD8zVe6KUq1UncIjA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", @@ -1208,6 +1164,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@heroicons/vue": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@heroicons/vue/-/vue-2.2.0.tgz", + "integrity": "sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw==", + "license": "MIT", + "peerDependencies": { + "vue": ">= 3" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1318,262 +1283,6 @@ "url": "https://github.com/sponsors/kazupon" } }, - "node_modules/@ionic/cli-framework-output": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@ionic/cli-framework-output/-/cli-framework-output-2.2.8.tgz", - "integrity": "sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==", - "license": "MIT", - "dependencies": { - "@ionic/utils-terminal": "2.3.5", - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-array": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.6.tgz", - "integrity": "sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==", - "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-fs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz", - "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==", - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.0", - "debug": "^4.0.0", - "fs-extra": "^9.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-fs/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@ionic/utils-object": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz", - "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==", - "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-process": { - "version": "2.1.12", - "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.12.tgz", - "integrity": "sha512-Jqkgyq7zBs/v/J3YvKtQQiIcxfJyplPgECMWgdO0E1fKrrH8EF0QGHNJ9mJCn6PYe2UtHNS8JJf5G21e09DfYg==", - "license": "MIT", - "dependencies": { - "@ionic/utils-object": "2.1.6", - "@ionic/utils-terminal": "2.3.5", - "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "tree-kill": "^1.2.2", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.7.tgz", - "integrity": "sha512-eSELBE7NWNFIHTbTC2jiMvh1ABKGIpGdUIvARsNPMNQhxJB3wpwdiVnoBoTYp+5a6UUIww4Kpg7v6S7iTctH1w==", - "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-subprocess": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-3.0.1.tgz", - "integrity": "sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==", - "license": "MIT", - "dependencies": { - "@ionic/utils-array": "2.1.6", - "@ionic/utils-fs": "3.1.7", - "@ionic/utils-process": "2.1.12", - "@ionic/utils-stream": "3.1.7", - "@ionic/utils-terminal": "2.3.5", - "cross-spawn": "^7.0.3", - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-terminal": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.5.tgz", - "integrity": "sha512-3cKScz9Jx2/Pr9ijj1OzGlBDfcmx7OMVBt4+P1uRR0SSW4cm1/y3Mo4OY3lfkuaYifMNBW8Wz6lQHbs1bihr7A==", - "license": "MIT", - "dependencies": { - "@types/slice-ansi": "^4.0.0", - "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "slice-ansi": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "tslib": "^2.0.1", - "untildify": "^4.0.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -1659,74 +1368,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@primeuix/styled": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.6.4.tgz", - "integrity": "sha512-7ePLwqazLV0x269YlPMeE4wtQKT0NScY2/gEin0/96krTiGiElmlzKMMbH69bVApm/sfen5DZGuCEEwPiBJJ5g==", - "license": "MIT", - "dependencies": { - "@primeuix/utils": "^0.5.3" - }, - "engines": { - "node": ">=12.11.0" - } - }, - "node_modules/@primeuix/styles": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-1.1.2.tgz", - "integrity": "sha512-KSwyuxNhl2bVv9eBr6SQHyRUtg93mCL7xqfQPoEzr7tgKfvIHJdGcMSSFxYyEXQv4EmSF6JxVkCWprKFAfnR5Q==", - "license": "MIT", - "dependencies": { - "@primeuix/styled": "^0.6.4" - } - }, - "node_modules/@primeuix/themes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@primeuix/themes/-/themes-1.1.2.tgz", - "integrity": "sha512-yxnmMqMct6RYWX6m9gS9AIG8QArjnROQzBqQf8UDQggAedX3My1fxr9FKEpvZMoY39WD494kG0pU9zIa1k2XyA==", - "license": "MIT", - "dependencies": { - "@primeuix/styled": "^0.6.4" - } - }, - "node_modules/@primeuix/utils": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.5.4.tgz", - "integrity": "sha512-8LggV3Jz59pymHQD10e/u63z/GemQ22RBeu2Gb1eJgBYVwn1iOb82LR+daeAc/LxrXCC5pHnftnCmnZO6vInLA==", - "license": "MIT", - "engines": { - "node": ">=12.11.0" - } - }, - "node_modules/@primevue/core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.3.5.tgz", - "integrity": "sha512-YBlSr/EbXsnsTOyfgqmbrJQ7AI5EThaeGZvfDFjPIIEpokEK+Q32++9xPn3MH8rcM8zPsfMeBOWi4/OJkOqG4w==", - "license": "MIT", - "dependencies": { - "@primeuix/styled": "^0.6.4", - "@primeuix/utils": "^0.5.3" - }, - "engines": { - "node": ">=12.11.0" - }, - "peerDependencies": { - "vue": "^3.5.0" - } - }, - "node_modules/@primevue/icons": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.3.5.tgz", - "integrity": "sha512-+V8XG6MEvczw3Ufz7+ABSSCaVdFCYKRHvVDmXpS65AUeQTDEqmJz3xx2UiYYdASA6Gb2yIKdVztTcRjHFtiAnw==", - "license": "MIT", - "dependencies": { - "@primeuix/utils": "^0.5.3", - "@primevue/core": "4.3.5" - }, - "engines": { - "node": ">=12.11.0" - } - }, "node_modules/@rollup/pluginutils": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", @@ -4440,15 +4081,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/fs-extra": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", - "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", @@ -4486,17 +4118,14 @@ "version": "24.0.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.4.tgz", "integrity": "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA==", + "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "undici-types": "~7.8.0" } }, - "node_modules/@types/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==", - "license": "MIT" - }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", @@ -4748,15 +4377,6 @@ "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==", "license": "MIT" }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -4841,24 +4461,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/autoprefixer": { "version": "10.4.21", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", @@ -4913,26 +4515,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/bcrypt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", @@ -4947,15 +4529,6 @@ "node": ">= 18" } }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, "node_modules/bignumber.js": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", @@ -5002,18 +4575,6 @@ "dev": true, "license": "ISC" }, - "node_modules/bplist-parser": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.2.tgz", - "integrity": "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==", - "license": "MIT", - "dependencies": { - "big-integer": "1.6.x" - }, - "engines": { - "node": ">= 5.10.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -5058,15 +4619,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -5197,15 +4749,6 @@ "node": ">=8" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -5239,15 +4782,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5372,6 +4906,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5485,15 +5020,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -5560,12 +5086,6 @@ "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", "license": "ISC" }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -5588,18 +5108,6 @@ "dev": true, "license": "ISC" }, - "node_modules/elementtree": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz", - "integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==", - "license": "Apache-2.0", - "dependencies": { - "sax": "1.1.4" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5641,15 +5149,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/error-stack-parser-es": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", @@ -6108,15 +5607,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fdir": { "version": "6.4.6", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", @@ -6216,34 +5706,6 @@ "dev": true, "license": "ISC" }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -6280,6 +5742,7 @@ "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -6290,30 +5753,6 @@ "node": ">=14.14" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -6453,29 +5892,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", - "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.0.3", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6489,21 +5905,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", @@ -6533,6 +5934,7 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "node_modules/has-flag": { @@ -6672,15 +6074,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -6690,21 +6083,6 @@ "node": ">= 0.10" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6836,39 +6214,13 @@ "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, - "node_modules/jackspeak": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", - "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -6977,6 +6329,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -7047,15 +6400,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/kolorist": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", @@ -7522,36 +6866,12 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -7559,18 +6879,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -7637,31 +6945,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/native-run": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/native-run/-/native-run-2.0.1.tgz", - "integrity": "sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==", - "license": "MIT", - "dependencies": { - "@ionic/utils-fs": "^3.1.7", - "@ionic/utils-terminal": "^2.3.4", - "bplist-parser": "^0.3.2", - "debug": "^4.3.4", - "elementtree": "^0.1.7", - "ini": "^4.1.1", - "plist": "^3.1.0", - "split2": "^4.2.0", - "through2": "^4.0.2", - "tslib": "^2.6.2", - "yauzl": "^2.10.0" - }, - "bin": { - "native-run": "bin/native-run" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7800,23 +7083,6 @@ "wrappy": "1" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -7876,12 +7142,6 @@ "node": ">=6" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7930,36 +7190,12 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/path-to-regexp": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", @@ -7976,12 +7212,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -8008,20 +7238,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/plist": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", - "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, "node_modules/pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -8166,44 +7382,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/primevue": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.3.5.tgz", - "integrity": "sha512-KYjLrf7W96qVOFdX2nyap5IrJIEF8qEfLaHpMPw+H3SCd7zV6uiIrOYBNvovk677rhjBGpSjEbxTFY/K+i/DMA==", - "license": "MIT", - "dependencies": { - "@primeuix/styled": "^0.6.4", - "@primeuix/styles": "^1.1.1", - "@primeuix/utils": "^0.5.3", - "@primevue/core": "4.3.5", - "@primevue/icons": "4.3.5" - }, - "engines": { - "node": ">=12.11.0" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prompts/node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8416,20 +7594,6 @@ "quickselect": "^2.0.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8462,25 +7626,6 @@ "dev": true, "license": "MIT" }, - "node_modules/rimraf": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", - "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", - "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/robust-predicates": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz", @@ -8592,12 +7737,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/sax": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz", - "integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==", - "license": "ISC" - }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -8668,6 +7807,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -8680,6 +7820,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8770,12 +7911,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, "node_modules/sirv": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", @@ -8791,35 +7926,12 @@ "node": ">=18" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "license": "MIT" - }, "node_modules/skmeans": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz", "integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg==", "license": "MIT" }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8845,15 +7957,6 @@ "integrity": "sha512-0kGecIZNIReCSiznK3uheYB8sbstLjCZLiwcQwbmLhgHJj2gz6OnSPkVzJQCMnmEz1BQ4gPK59ylhBoEWOhGNA==", "license": "BDS-3-Clause" }, - "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/sqlstring": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", @@ -8872,15 +7975,6 @@ "node": ">= 0.8" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8895,21 +7989,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8922,19 +8001,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-final-newline": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", @@ -9032,41 +8098,6 @@ "node": ">=6" } }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "license": "MIT", - "dependencies": { - "readable-stream": "3" - } - }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -9151,6 +8182,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, "license": "MIT", "bin": { "tree-kill": "cli.js" @@ -9193,7 +8225,10 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "license": "MIT" + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/unicorn-magic": { "version": "0.3.0", @@ -9212,6 +8247,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -9226,15 +8262,6 @@ "node": ">= 0.8" } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -9280,6 +8307,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, "license": "MIT" }, "node_modules/uuid": { @@ -9601,6 +8629,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9632,24 +8661,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -9679,37 +8691,6 @@ "node": ">=12" } }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xml2js/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -9720,12 +8701,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -9755,16 +8730,6 @@ "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 2232213..c53649f 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,7 @@ "format": "prettier --write src/" }, "dependencies": { - "@capacitor/cli": "^7.4.0", - "@capacitor/core": "^7.4.0", - "@primeuix/themes": "^1.1.2", + "@heroicons/vue": "^2.2.0", "@turf/turf": "^7.2.0", "bcrypt": "^6.0.0", "body-parser": "^2.2.0", @@ -26,7 +24,6 @@ "json2csv": "^6.0.0-alpha.2", "jsonwebtoken": "^9.0.2", "mysql2": "^3.14.2", - "primevue": "^4.3.5", "qrcode": "^1.5.4", "uuid": "^11.1.0", "vue": "^3.5.13", diff --git a/public/favicon.ico b/public/favicon.ico index df36fcf..ae330ff 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/App.vue b/src/App.vue index 6451f9b..aa4cb34 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,23 +1,27 @@