From 11c52b3c48e45644c3765bf989e1add7c171024c Mon Sep 17 00:00:00 2001 From: Vindya Kodithuwakku Date: Tue, 28 Oct 2025 00:16:04 +0530 Subject: [PATCH 1/4] feat: add Statuses table migration --- .../20251027183315-create-statuses-table.js | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/database/migrations/20251027183315-create-statuses-table.js diff --git a/src/database/migrations/20251027183315-create-statuses-table.js b/src/database/migrations/20251027183315-create-statuses-table.js new file mode 100644 index 0000000..d37a3fb --- /dev/null +++ b/src/database/migrations/20251027183315-create-statuses-table.js @@ -0,0 +1,65 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +export default { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Statuses', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + issue_id: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'Issues', // name of your Issues table + key: 'id' + }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE' + }, + user_id: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'Users', // name of your Users table + key: 'id' + }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE' + }, + description: { + type: Sequelize.TEXT, + allowNull: false + }, + image_url: { + type: Sequelize.STRING, + allowNull: true + }, + status_type: { + type: Sequelize.ENUM('Open', 'Assigned', 'In Progress', 'Resolved', 'Closed'), + allowNull: false, + defaultValue: 'Open' + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.fn('NOW') + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.fn('NOW') + } + }); + + await queryInterface.addIndex('Statuses', ['issue_id'], { name: 'idx_status_issue_id' }); + await queryInterface.addIndex('Statuses', ['user_id'], { name: 'idx_status_user_id' }); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Statuses'); + } +}; From 183f4f62d6704de16d945a4966c3f5fa2d2d57c7 Mon Sep 17 00:00:00 2001 From: Naveen Sanjula <82176749+naveensanjula975@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:16:51 +0530 Subject: [PATCH 2/4] feat: add outside party request management and forms --- server.js | 2 + src/controllers/issueController.js | 52 +++-- .../outsidePartyRequestController.js | 90 ++++++++ src/controllers/statusController.js | 96 +++++++++ ...20251028120000-add-pending-status-enum.cjs | 27 +++ ...01-create-outside-party-requests-table.cjs | 68 ++++++ ...002-fix-outside-party-requests-indexes.cjs | 42 ++++ ...000000-update-status-image-url-to-text.cjs | 21 ++ src/models/index.js | 52 +++++ src/models/issue.js | 54 ++--- src/models/outsidePartyRequest.js | 113 ++++++++++ src/models/status.js | 97 +++++++++ src/routes/issues.js | 9 +- src/routes/outsidePartyRequests.js | 24 +++ src/services/issueService.js | 200 ++++++++---------- src/services/outsidePartyRequestService.js | 59 ++++++ src/services/statusService.js | 103 +++++++++ src/socket/socket.js | 129 ++++++++++- 18 files changed, 1072 insertions(+), 166 deletions(-) create mode 100644 src/controllers/outsidePartyRequestController.js create mode 100644 src/controllers/statusController.js create mode 100644 src/database/migrations/20251028120000-add-pending-status-enum.cjs create mode 100644 src/database/migrations/20260302000001-create-outside-party-requests-table.cjs create mode 100644 src/database/migrations/20260302000002-fix-outside-party-requests-indexes.cjs create mode 100644 src/database/migrations/20260303000000-update-status-image-url-to-text.cjs create mode 100644 src/models/outsidePartyRequest.js create mode 100644 src/models/status.js create mode 100644 src/routes/outsidePartyRequests.js create mode 100644 src/services/outsidePartyRequestService.js create mode 100644 src/services/statusService.js diff --git a/server.js b/server.js index 426a195..6071cd3 100644 --- a/server.js +++ b/server.js @@ -13,6 +13,7 @@ import thirdPartiesRoutes from './src/routes/thirdparties.js'; import cashRequestRoutes from './src/routes/cashRequestRoutes.js'; import ahpRoutes from './src/routes/ahpRoutes.js'; import authRoutes from './src/routes/auth.js'; +import outsidePartyRequestRoutes from './src/routes/outsidePartyRequests.js'; const app = express(); const server = http.createServer(app); @@ -34,6 +35,7 @@ app.use('/api/v1/messages', messageRoutes); app.use('/api/v1/branches', branchRoutes); app.use('/api/v1/thirdparties', thirdPartiesRoutes); app.use('/api/v1/ahp', ahpRoutes); +app.use('/api/v1/outside-party-requests', outsidePartyRequestRoutes); // Basic route app.get('/api/', (req, res) => { diff --git a/src/controllers/issueController.js b/src/controllers/issueController.js index a64a57e..6f21226 100644 --- a/src/controllers/issueController.js +++ b/src/controllers/issueController.js @@ -5,32 +5,38 @@ class IssueController { // POST /api/issues - Create new issue async createIssue(req, res) { try { - const { - branch_id, - title, - manager_id, - description, - maintenance_executive_id, - technician_id, + const { + branch_id, + title, + manager_id, + description, + maintenance_executive_id, + technician_id, status, - third_party_id + third_party_id } = req.body; // Validation - if (!branch_id || !title || !manager_id) { + if (!branch_id || !title) { return res.status(400).json({ success: false, - message: 'Branch ID, title, and manager ID are required' + message: 'Branch ID and title are required' }); } const issueData = { branch_id: parseInt(branch_id), title, - manager_id: parseInt(manager_id), description }; + // Include manager_id only if it is a valid non-zero integer + // When it's 0 or absent, issueService will auto-assign a branch manager + const parsedManagerId = manager_id ? parseInt(manager_id) : 0; + if (parsedManagerId > 0) { + issueData.manager_id = parsedManagerId; + } + // Add optional fields if provided if (maintenance_executive_id) { issueData.maintenance_executive_id = parseInt(maintenance_executive_id); @@ -49,7 +55,7 @@ class IssueController { if (result.success) { // Notify all Maintenance Executives about the new issue(real-time) - try { notifyNewIssue(result); } catch (e) { console.error(e);} + try { notifyNewIssue(result); } catch (e) { console.error(e); } try { // Create dynamic namespaces for real-time communication @@ -74,17 +80,17 @@ class IssueController { // GET /api/issues - Get all issues async getAllIssues(req, res) { try { - const { - branch_id, - manager_id, - technician_id, + const { + branch_id, + manager_id, + technician_id, maintenance_executive_id, third_party_id, status, - search, - limit, + search, + limit, offset, - include_relations + include_relations } = req.query; const filters = {}; @@ -299,7 +305,7 @@ class IssueController { } // Notify all Maintenance Executives about the new issue(real-time) update with assigned ME - try { notifyNewIssue(result); } catch (e) { console.error(e);} + try { notifyNewIssue(result); } catch (e) { console.error(e); } return res.status(200).json(result); } else { @@ -377,7 +383,7 @@ class IssueController { }); } - const validStatuses = ['Open', 'In Progress', 'Done', 'Closed']; + const validStatuses = ['Open', 'In Progress', 'Pending Resolution', 'Pending Close', 'Done', 'Closed']; if (!validStatuses.includes(status)) { return res.status(400).json({ success: false, @@ -396,10 +402,10 @@ class IssueController { } // Notify Maintenance Executives about the issue status update(real-time in home dashboard) - try { notifyNewIssue(result); } catch (e) { console.error(e);} + try { notifyNewIssue(result); } catch (e) { console.error(e); } // Notify assigned technician about the issue status update(real-time in home dashboard) - try { notifyAssign(result.data.technician_id, result); } catch (e) { console.error(e);} + try { notifyAssign(result.data.technician_id, result); } catch (e) { console.error(e); } // Remove all connections and delete the namespace for the issue if (result.data.status === 'Closed' || result.data.status === 'Done') { diff --git a/src/controllers/outsidePartyRequestController.js b/src/controllers/outsidePartyRequestController.js new file mode 100644 index 0000000..b53218b --- /dev/null +++ b/src/controllers/outsidePartyRequestController.js @@ -0,0 +1,90 @@ +import * as OutsidePartyRequestService from '../services/outsidePartyRequestService.js'; +import { issueRealtimeUpdate } from '../socket/socket.js'; + +/** GET /api/v1/outside-party-requests */ +export const getAll = async (req, res) => { + try { + const filters = {}; + if (req.query.issue_id) filters.issue_id = req.query.issue_id; + if (req.query.status) filters.status = req.query.status; + if (req.query.suggested_by) filters.suggested_by = req.query.suggested_by; + const data = await OutsidePartyRequestService.getAll(filters); + res.json({ success: true, count: data.length, data }); + } catch (e) { + res.status(500).json({ success: false, message: e.message }); + } +}; + +/** GET /api/v1/outside-party-requests/:id */ +export const getOne = async (req, res) => { + try { + const data = await OutsidePartyRequestService.getById(req.params.id); + if (!data) return res.status(404).json({ success: false, message: 'Not found' }); + res.json({ success: true, data }); + } catch (e) { + res.status(500).json({ success: false, message: e.message }); + } +}; + +/** POST /api/v1/outside-party-requests */ +export const create = async (req, res) => { + try { + const data = await OutsidePartyRequestService.create(req.body); + try { issueRealtimeUpdate(data.issue_id, data); } catch (_) { } + res.status(201).json({ success: true, data }); + } catch (e) { + res.status(400).json({ success: false, message: e.message }); + } +}; + +/** PATCH /api/v1/outside-party-requests/:id/approve */ +export const approve = async (req, res) => { + try { + const approverId = req.body.approved_by || req.body.user_id; + const comment = req.body.comment || null; + + // Role check — only branch_manager / maintenance_executive + const userRole = req.body.user_role; + if (userRole && !['branch_manager', 'maintenance_executive'].includes(userRole)) { + return res.status(403).json({ success: false, message: 'Permission denied' }); + } + + const data = await OutsidePartyRequestService.approve(req.params.id, approverId, comment); + if (!data) return res.status(404).json({ success: false, message: 'Not found' }); + try { issueRealtimeUpdate(data.issue_id, { ...data, event_type: 'outside_party_approved' }); } catch (_) { } + res.json({ success: true, data }); + } catch (e) { + res.status(400).json({ success: false, message: e.message }); + } +}; + +/** PATCH /api/v1/outside-party-requests/:id/reject */ +export const reject = async (req, res) => { + try { + const approverId = req.body.approved_by || req.body.user_id; + const comment = req.body.comment || null; + + const userRole = req.body.user_role; + if (userRole && !['branch_manager', 'maintenance_executive'].includes(userRole)) { + return res.status(403).json({ success: false, message: 'Permission denied' }); + } + + const data = await OutsidePartyRequestService.reject(req.params.id, approverId, comment); + if (!data) return res.status(404).json({ success: false, message: 'Not found' }); + try { issueRealtimeUpdate(data.issue_id, { ...data, event_type: 'outside_party_rejected' }); } catch (_) { } + res.json({ success: true, data }); + } catch (e) { + res.status(400).json({ success: false, message: e.message }); + } +}; + +/** DELETE /api/v1/outside-party-requests/:id */ +export const remove = async (req, res) => { + try { + const deleted = await OutsidePartyRequestService.remove(req.params.id); + if (!deleted) return res.status(404).json({ success: false, message: 'Not found' }); + res.json({ success: true, message: 'Deleted' }); + } catch (e) { + res.status(500).json({ success: false, message: e.message }); + } +}; diff --git a/src/controllers/statusController.js b/src/controllers/statusController.js new file mode 100644 index 0000000..ed48054 --- /dev/null +++ b/src/controllers/statusController.js @@ -0,0 +1,96 @@ +import statusService from '../services/statusService.js'; +import { statusUpdateLogCreated } from '../socket/socket.js'; + +class StatusController { + /** + * POST /api/v1/issues/:id/statuses + * Create a status update log for an issue. + */ + async createStatusUpdate(req, res) { + try { + const { id } = req.params; + const { user_id, description, image_url, image_urls, status_type } = req.body; + + if (!id || isNaN(id)) { + return res.status(400).json({ success: false, message: 'Valid issue ID is required' }); + } + if (!user_id) { + return res.status(400).json({ success: false, message: 'User ID is required' }); + } + if (!description || description.trim() === '') { + return res.status(400).json({ success: false, message: 'Description is required' }); + } + + // Validate image_urls if provided + if (image_urls && !Array.isArray(image_urls)) { + return res.status(400).json({ success: false, message: 'image_urls must be an array' }); + } + + const validTypes = ['Open', 'Assigned', 'In Progress', 'Resolved', 'Closed']; + if (status_type && !validTypes.includes(status_type)) { + return res.status(400).json({ + success: false, + message: `status_type must be one of: ${validTypes.join(', ')}` + }); + } + + const result = await statusService.createStatusUpdate({ + issue_id: parseInt(id), + user_id: parseInt(user_id), + description: description.trim(), + image_url: image_url || null, + image_urls: image_urls || null, + status_type: status_type || 'Open' + }); + + if (result.success) { + // Emit socket event for real-time status log update + try { + statusUpdateLogCreated(parseInt(id), result.data); + } catch (socketErr) { + console.error('Socket emit failed for status update:', socketErr); + } + + return res.status(201).json(result); + } else { + return res.status(400).json(result); + } + } catch (error) { + return res.status(500).json({ + success: false, + message: 'Internal server error', + error: error.message + }); + } + } + + /** + * GET /api/v1/issues/:id/statuses + * Get all status updates for an issue. + */ + async getStatusUpdates(req, res) { + try { + const { id } = req.params; + + if (!id || isNaN(id)) { + return res.status(400).json({ success: false, message: 'Valid issue ID is required' }); + } + + const result = await statusService.getStatusUpdatesByIssue(parseInt(id)); + + if (result.success) { + return res.status(200).json(result); + } else { + return res.status(400).json(result); + } + } catch (error) { + return res.status(500).json({ + success: false, + message: 'Internal server error', + error: error.message + }); + } + } +} + +export default new StatusController(); diff --git a/src/database/migrations/20251028120000-add-pending-status-enum.cjs b/src/database/migrations/20251028120000-add-pending-status-enum.cjs new file mode 100644 index 0000000..64d7531 --- /dev/null +++ b/src/database/migrations/20251028120000-add-pending-status-enum.cjs @@ -0,0 +1,27 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + // Add new status values to Issues status ENUM + try { + await queryInterface.sequelize.query(`ALTER TYPE "enum_Issues_status" ADD VALUE IF NOT EXISTS 'Pending Resolution';`); + } catch (e) { console.warn(e.message); } + + try { + await queryInterface.sequelize.query(`ALTER TYPE "enum_Issues_status" ADD VALUE IF NOT EXISTS 'Pending Close';`); + } catch (e) { console.warn(e.message); } + + // Add new status values to Statuses status_type ENUM + try { + await queryInterface.sequelize.query(`ALTER TYPE "enum_Statuses_status_type" ADD VALUE IF NOT EXISTS 'Pending Resolution';`); + } catch (e) { console.warn(e.message); } + + try { + await queryInterface.sequelize.query(`ALTER TYPE "enum_Statuses_status_type" ADD VALUE IF NOT EXISTS 'Pending Close';`); + } catch (e) { console.warn(e.message); } + }, + + down: async (queryInterface, Sequelize) => { + // PostgreSQL does not support easily dropping ENUM values. + } +}; diff --git a/src/database/migrations/20260302000001-create-outside-party-requests-table.cjs b/src/database/migrations/20260302000001-create-outside-party-requests-table.cjs new file mode 100644 index 0000000..3cdf735 --- /dev/null +++ b/src/database/migrations/20260302000001-create-outside-party-requests-table.cjs @@ -0,0 +1,68 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + // Create ENUM if not exists + await queryInterface.sequelize.query(` + DO $$ BEGIN + CREATE TYPE outside_party_request_status AS ENUM ('pending', 'approved', 'rejected'); + EXCEPTION + WHEN duplicate_object THEN null; + END $$; + `); + + // Create table if not exists (safe) + await queryInterface.sequelize.query(` + CREATE TABLE IF NOT EXISTS outside_party_requests ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + issue_id INTEGER NOT NULL, + suggested_by INTEGER NOT NULL, + vendor_name VARCHAR(255) NOT NULL, + description TEXT NOT NULL, + status outside_party_request_status NOT NULL DEFAULT 'pending', + approved_by INTEGER, + approval_comment TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP + ); + `); + + // Indexes with IF NOT EXISTS + await queryInterface.sequelize.query(` + CREATE INDEX IF NOT EXISTS "idx_outside_party_requests_issue_id" + ON outside_party_requests (issue_id); + `); + await queryInterface.sequelize.query(` + CREATE INDEX IF NOT EXISTS "idx_outside_party_requests_suggested_by" + ON outside_party_requests (suggested_by); + `); + await queryInterface.sequelize.query(` + CREATE INDEX IF NOT EXISTS "idx_outside_party_requests_status" + ON outside_party_requests (status); + `); + + // Trigger safely + await queryInterface.sequelize.query(` + DO $$ BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_trigger + WHERE tgname = 'update_outside_party_requests_updated_at' + ) THEN + CREATE TRIGGER update_outside_party_requests_updated_at + BEFORE UPDATE ON outside_party_requests + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + END IF; + END $$; + `); + }, + + async down(queryInterface) { + await queryInterface.sequelize.query(` + DROP TRIGGER IF EXISTS update_outside_party_requests_updated_at ON outside_party_requests; + `); + await queryInterface.dropTable('outside_party_requests'); + await queryInterface.sequelize.query(`DROP TYPE IF EXISTS outside_party_request_status;`); + } +}; diff --git a/src/database/migrations/20260302000002-fix-outside-party-requests-indexes.cjs b/src/database/migrations/20260302000002-fix-outside-party-requests-indexes.cjs new file mode 100644 index 0000000..3cd27e1 --- /dev/null +++ b/src/database/migrations/20260302000002-fix-outside-party-requests-indexes.cjs @@ -0,0 +1,42 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface) { + // Add indexes safely using IF NOT EXISTS (raw SQL) + await queryInterface.sequelize.query(` + CREATE INDEX IF NOT EXISTS "idx_outside_party_requests_issue_id" + ON outside_party_requests (issue_id); + `); + await queryInterface.sequelize.query(` + CREATE INDEX IF NOT EXISTS "idx_outside_party_requests_suggested_by" + ON outside_party_requests (suggested_by); + `); + await queryInterface.sequelize.query(` + CREATE INDEX IF NOT EXISTS "idx_outside_party_requests_status" + ON outside_party_requests (status); + `); + // Add trigger if not already there + await queryInterface.sequelize.query(` + DO $$ BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_trigger + WHERE tgname = 'update_outside_party_requests_updated_at' + ) THEN + CREATE TRIGGER update_outside_party_requests_updated_at + BEFORE UPDATE ON outside_party_requests + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + END IF; + END $$; + `); + }, + + async down(queryInterface) { + await queryInterface.sequelize.query(` + DROP INDEX IF EXISTS "idx_outside_party_requests_issue_id"; + DROP INDEX IF EXISTS "idx_outside_party_requests_suggested_by"; + DROP INDEX IF EXISTS "idx_outside_party_requests_status"; + `); + } +}; diff --git a/src/database/migrations/20260303000000-update-status-image-url-to-text.cjs b/src/database/migrations/20260303000000-update-status-image-url-to-text.cjs new file mode 100644 index 0000000..98c11b3 --- /dev/null +++ b/src/database/migrations/20260303000000-update-status-image-url-to-text.cjs @@ -0,0 +1,21 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + // Change image_url from VARCHAR to TEXT to support JSON array of multiple image URLs + await queryInterface.changeColumn('Statuses', 'image_url', { + type: Sequelize.TEXT, + allowNull: true, + comment: 'Can store a single URL or JSON array of URLs' + }); + }, + + async down(queryInterface, Sequelize) { + // Revert back to VARCHAR + await queryInterface.changeColumn('Statuses', 'image_url', { + type: Sequelize.STRING(1000), + allowNull: true + }); + } +}; diff --git a/src/models/index.js b/src/models/index.js index 2230cd0..d44edf0 100644 --- a/src/models/index.js +++ b/src/models/index.js @@ -8,6 +8,8 @@ import Technician from './technician.js'; import BranchManager from './branchManager.js'; import MaintenanceExecutive from './maintenanceExecutive.js'; import ThirdParty from './thirdParty.js'; +import Status from './status.js'; +import OutsidePartyRequest from './outsidePartyRequest.js'; const sequelize = getSequelizeInstance(); @@ -172,6 +174,31 @@ Issue.belongsTo(ThirdParty, { as: 'thirdParty' }); +// Issue <-> Status (status update log) +Issue.hasMany(Status, { + foreignKey: 'issue_id', + as: 'statuses', + onDelete: 'CASCADE' +}); + +Status.belongsTo(Issue, { + foreignKey: 'issue_id', + as: 'issue', + onDelete: 'CASCADE' +}); + +Status.belongsTo(User, { + foreignKey: 'user_id', + as: 'user', + onDelete: 'CASCADE' +}); + +User.hasMany(Status, { + foreignKey: 'user_id', + as: 'statusUpdates', + onDelete: 'CASCADE' +}); + // One-to-many relationship: Technician with PettyCashRequests Technician.hasMany(PettyCashRequest, { foreignKey: 'technician_id', @@ -184,6 +211,29 @@ PettyCashRequest.belongsTo(Technician, { as: 'technician' }); +// One-to-many relationship: Issue with OutsidePartyRequests +Issue.hasMany(OutsidePartyRequest, { + foreignKey: 'issue_id', + as: 'outsidePartyRequests', + onDelete: 'CASCADE' +}); + +OutsidePartyRequest.belongsTo(Issue, { + foreignKey: 'issue_id', + as: 'issue' +}); + +User.hasMany(OutsidePartyRequest, { + foreignKey: 'suggested_by', + as: 'outsidePartySuggestions', + onDelete: 'CASCADE' +}); + +OutsidePartyRequest.belongsTo(User, { + foreignKey: 'suggested_by', + as: 'suggester' +}); + // Initialize all models const models = { Issue, @@ -191,10 +241,12 @@ const models = { Branch, Message, PettyCashRequest, + OutsidePartyRequest, Technician, BranchManager, MaintenanceExecutive, ThirdParty, + Status, sequelize }; diff --git a/src/models/issue.js b/src/models/issue.js index f7cdbf3..9d06540 100644 --- a/src/models/issue.js +++ b/src/models/issue.js @@ -99,13 +99,13 @@ const Issue = sequelize.define('Issue', { } }, status: { - type: DataTypes.ENUM('Open', 'In Progress', 'Done', 'Closed'), + type: DataTypes.ENUM('Open', 'In Progress', 'Pending Resolution', 'Pending Close', 'Done', 'Closed'), allowNull: false, defaultValue: 'Open', validate: { isIn: { - args: [['Open', 'In Progress', 'Done', 'Closed']], - msg: 'Status must be one of: Open, In Progress, Done, Closed' + args: [['Open', 'In Progress', 'Pending Resolution', 'Pending Close', 'Done', 'Closed']], + msg: 'Status must be one of: Open, In Progress, Pending Resolution, Pending Close, Done, Closed' } } }, @@ -137,29 +137,29 @@ const Issue = sequelize.define('Issue', { allowNull: true } }, -{ - tableName: 'Issues', - timestamps: true, // This will automatically add createdAt and updatedAt - indexes: [ - { - fields: ['branch_id'] - }, - { - fields: ['manager_id'] - }, - { - fields: ['maintenance_executive_id'] - }, - { - fields: ['technician_id'] - }, - { - fields: ['status'] - }, - { - fields: ['third_party_id'] - } - ] -}); + { + tableName: 'Issues', + timestamps: true, // This will automatically add createdAt and updatedAt + indexes: [ + { + fields: ['branch_id'] + }, + { + fields: ['manager_id'] + }, + { + fields: ['maintenance_executive_id'] + }, + { + fields: ['technician_id'] + }, + { + fields: ['status'] + }, + { + fields: ['third_party_id'] + } + ] + }); export default Issue; \ No newline at end of file diff --git a/src/models/outsidePartyRequest.js b/src/models/outsidePartyRequest.js new file mode 100644 index 0000000..0d76477 --- /dev/null +++ b/src/models/outsidePartyRequest.js @@ -0,0 +1,113 @@ +import { DataTypes } from 'sequelize'; +import { getSequelizeInstance } from '../services/connectionService.js'; + +const sequelize = getSequelizeInstance(); + +const OutsidePartyRequest = sequelize.define( + 'OutsidePartyRequest', + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + allowNull: false + }, + issue_id: { + type: DataTypes.INTEGER, + allowNull: false, + references: { model: 'Issues', key: 'id' }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE' + }, + suggested_by: { + type: DataTypes.INTEGER, + allowNull: false, + references: { model: 'Users', key: 'id' }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE' + }, + vendor_name: { + type: DataTypes.STRING(255), + allowNull: false, + validate: { + notNull: { msg: 'Vendor name is required' }, + notEmpty: { msg: 'Vendor name cannot be empty' } + } + }, + description: { + type: DataTypes.TEXT, + allowNull: false, + validate: { + notNull: { msg: 'Description is required' }, + notEmpty: { msg: 'Description cannot be empty' } + } + }, + status: { + type: DataTypes.ENUM('pending', 'approved', 'rejected'), + allowNull: false, + defaultValue: 'pending', + validate: { + isIn: { + args: [['pending', 'approved', 'rejected']], + msg: 'Status must be pending, approved, or rejected' + } + } + }, + approved_by: { + type: DataTypes.INTEGER, + allowNull: true + }, + approval_comment: { + type: DataTypes.TEXT, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + field: 'created_at' + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + field: 'updated_at' + } + }, + { + tableName: 'outside_party_requests', + timestamps: true, + underscored: true, + indexes: [ + { name: 'idx_outside_party_requests_issue_id', fields: ['issue_id'] }, + { name: 'idx_outside_party_requests_suggested_by', fields: ['suggested_by'] }, + { name: 'idx_outside_party_requests_status', fields: ['status'] } + ] + } +); + +/** + * Get all outside party requests with optional filtering + */ +OutsidePartyRequest.getAllWithFilters = async function (filters = {}) { + const where = {}; + if (filters.issue_id) where.issue_id = filters.issue_id; + if (filters.status) where.status = filters.status; + if (filters.suggested_by) where.suggested_by = filters.suggested_by; + return await this.findAll({ where, order: [['created_at', 'DESC']] }); +}; + +/** + * Update request status + */ +OutsidePartyRequest.updateStatus = async function (id, status, approvedBy = null, comment = null) { + const record = await this.findByPk(id); + if (!record) return null; + record.status = status; + if (approvedBy) record.approved_by = approvedBy; + if (comment !== null) record.approval_comment = comment; + await record.save(); + return record; +}; + +export default OutsidePartyRequest; diff --git a/src/models/status.js b/src/models/status.js new file mode 100644 index 0000000..2e76cd9 --- /dev/null +++ b/src/models/status.js @@ -0,0 +1,97 @@ +import { DataTypes } from 'sequelize'; +import { getSequelizeInstance } from '../services/connectionService.js'; + +const sequelize = getSequelizeInstance(); + +const Status = sequelize.define('Status', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, + issue_id: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'Issues', + key: 'id' + }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE', + validate: { + notNull: { msg: 'Issue ID is required' }, + isInt: { msg: 'Issue ID must be an integer' } + } + }, + user_id: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'Users', + key: 'id' + }, + onUpdate: 'CASCADE', + onDelete: 'CASCADE', + validate: { + notNull: { msg: 'User ID is required' }, + isInt: { msg: 'User ID must be an integer' } + } + }, + description: { + type: DataTypes.TEXT, + allowNull: false, + validate: { + notNull: { msg: 'Description is required' }, + notEmpty: { msg: 'Description cannot be empty' } + } + }, + image_url: { + type: DataTypes.TEXT, + allowNull: true, + get() { + const rawValue = this.getDataValue('image_url'); + if (!rawValue) return null; + + // Try to parse as JSON array + try { + const parsed = JSON.parse(rawValue); + return Array.isArray(parsed) ? parsed : [rawValue]; + } catch { + // If not JSON, treat as single URL + return [rawValue]; + } + }, + set(value) { + if (!value) { + this.setDataValue('image_url', null); + } else if (Array.isArray(value)) { + // Store array as JSON string + this.setDataValue('image_url', JSON.stringify(value)); + } else { + // Store single value as-is + this.setDataValue('image_url', value); + } + } + }, + status_type: { + type: DataTypes.ENUM('Open', 'Assigned', 'In Progress', 'Pending Resolution', 'Pending Close', 'Resolved', 'Closed'), + allowNull: false, + defaultValue: 'Open', + validate: { + isIn: { + args: [['Open', 'Assigned', 'In Progress', 'Pending Resolution', 'Pending Close', 'Resolved', 'Closed']], + msg: 'Status type must be one of: Open, Assigned, In Progress, Pending Resolution, Pending Close, Resolved, Closed' + } + } + } +}, { + tableName: 'Statuses', + timestamps: true, + indexes: [ + { fields: ['issue_id'], name: 'idx_status_issue_id' }, + { fields: ['user_id'], name: 'idx_status_user_id' } + ] +}); + +export default Status; diff --git a/src/routes/issues.js b/src/routes/issues.js index 985f669..70d5e60 100644 --- a/src/routes/issues.js +++ b/src/routes/issues.js @@ -1,5 +1,6 @@ import { Router } from 'express'; import issueController from '../controllers/issueController.js'; +import statusController from '../controllers/statusController.js'; const router = Router(); @@ -30,4 +31,10 @@ router.post('/:id/assign-third-party', issueController.assignThirdParty); // PUT /api/v1/issues/:id/status - Update issue status router.put('/:id/status', issueController.updateStatus); -export default router; \ No newline at end of file +// GET /api/v1/issues/:id/statuses - Get all status update logs for an issue +router.get('/:id/statuses', statusController.getStatusUpdates); + +// POST /api/v1/issues/:id/statuses - Add a status update log entry +router.post('/:id/statuses', statusController.createStatusUpdate); + +export default router; diff --git a/src/routes/outsidePartyRequests.js b/src/routes/outsidePartyRequests.js new file mode 100644 index 0000000..74f2a6b --- /dev/null +++ b/src/routes/outsidePartyRequests.js @@ -0,0 +1,24 @@ +import express from 'express'; +import * as ctrl from '../controllers/outsidePartyRequestController.js'; + +const router = express.Router(); + +// GET /api/v1/outside-party-requests +router.get('/', ctrl.getAll); + +// GET /api/v1/outside-party-requests/:id +router.get('/:id', ctrl.getOne); + +// POST /api/v1/outside-party-requests +router.post('/', ctrl.create); + +// PATCH /api/v1/outside-party-requests/:id/approve +router.patch('/:id/approve', ctrl.approve); + +// PATCH /api/v1/outside-party-requests/:id/reject +router.patch('/:id/reject', ctrl.reject); + +// DELETE /api/v1/outside-party-requests/:id +router.delete('/:id', ctrl.remove); + +export default router; diff --git a/src/services/issueService.js b/src/services/issueService.js index 58688a2..67b5bf8 100644 --- a/src/services/issueService.js +++ b/src/services/issueService.js @@ -1,14 +1,15 @@ import models from '../models/index.js'; -const { Issue, Branch, BranchManager, Technician, MaintenanceExecutive, ThirdParty, Message, PettyCashRequest, User } = models; +const { Issue, Branch, BranchManager, Technician, MaintenanceExecutive, ThirdParty, Message, PettyCashRequest, User, Status } = models; +import OutsidePartyRequest from '../models/outsidePartyRequest.js'; import { Op } from 'sequelize'; class IssueService { // Create a new issue async createIssue(issueData) { try { - const { manager_id, branch_id } = issueData; - + let { manager_id, branch_id } = issueData; + // Validate branch exists const branch = await Branch.findByPk(branch_id); if (!branch) { @@ -17,33 +18,52 @@ class IssueService { message: 'Invalid branch ID' }; } - - // Validate branch manager exists - const branchManager = await BranchManager.findByPk(manager_id); - if (!branchManager) { - return { - success: false, - message: 'Invalid branch manager ID' - }; - } - - // Validate that branch manager is assigned to the specified branch - if (branchManager.branchId && branchManager.branchId !== parseInt(branch_id)) { - return { - success: false, - message: `Branch manager is assigned to branch ${branchManager.branchId}, but issue is for branch ${branch_id}` - }; - } - - // If branch manager has no assigned branch, that might be okay or might be an error - // depending on your business logic. For now, we'll allow it. - if (!branchManager.branchId) { - console.warn(`Branch manager ${manager_id} has no assigned branch, but creating issue for branch ${branch_id}`); + + // If manager_id is not provided or is 0, auto-assign a branch manager + if (!manager_id) { + // Try to find a manager assigned to this specific branch first + let autoManager = await BranchManager.findOne({ where: { branchId: parseInt(branch_id) } }); + + // If no branch-specific manager found, pick any available branch manager + if (!autoManager) { + autoManager = await BranchManager.findOne(); + } + + if (!autoManager) { + return { + success: false, + message: 'No branch manager available to assign. Please contact support.' + }; + } + + manager_id = autoManager.id; + issueData = { ...issueData, manager_id }; + } else { + // Validate provided branch manager exists + const branchManager = await BranchManager.findByPk(manager_id); + if (!branchManager) { + return { + success: false, + message: 'Invalid branch manager ID' + }; + } + + // Validate that branch manager is assigned to the specified branch + if (branchManager.branchId && branchManager.branchId !== parseInt(branch_id)) { + return { + success: false, + message: `Branch manager is assigned to branch ${branchManager.branchId}, but issue is for branch ${branch_id}` + }; + } + + if (!branchManager.branchId) { + console.warn(`Branch manager ${manager_id} has no assigned branch, but creating issue for branch ${branch_id}`); + } } - + // Create the issue const issue = await Issue.create(issueData); - + return { success: true, message: 'Issue created successfully', @@ -63,32 +83,32 @@ class IssueService { async getAllIssues(filters = {}) { try { const where = {}; - + // Apply filters if provided if (filters.branch_id) { where.branch_id = filters.branch_id; } - + if (filters.manager_id) { where.manager_id = filters.manager_id; } - + if (filters.technician_id) { where.technician_id = filters.technician_id; } - + if (filters.maintenance_executive_id) { where.maintenance_executive_id = filters.maintenance_executive_id; } - + if (filters.third_party_id) { where.third_party_id = filters.third_party_id; } - + if (filters.status) { where.status = filters.status; } - + if (filters.search) { where[Op.or] = [ { title: { [Op.iLike]: `%${filters.search}%` } }, @@ -172,7 +192,7 @@ class IssueService { async getIssueById(id, includeRelations = false) { try { const include = []; - + if (includeRelations) { include.push( { @@ -236,11 +256,26 @@ class IssueService { model: PettyCashRequest, as: 'pettyCashRequests', attributes: ['id', 'technician_id', 'amount', 'description', 'status', 'createdAt'] + }, + { + model: OutsidePartyRequest, + as: 'outsidePartyRequests', + attributes: ['id', 'issue_id', 'suggested_by', 'vendor_name', 'description', 'status', 'approved_by', 'approval_comment', 'createdAt'] + }, + { + model: Status, + as: 'statuses', + attributes: ['id', 'user_id', 'description', 'image_url', 'status_type', 'createdAt'], + include: [{ + model: User, + as: 'user', + attributes: ['id', 'name', 'email', 'profilePicture'] + }] } ); } - const queryOptions = { + const queryOptions = { include, order: [] }; @@ -249,7 +284,9 @@ class IssueService { if (includeRelations) { queryOptions.order = [ [{ model: Message, as: 'messages' }, 'createdAt', 'ASC'], - [{ model: PettyCashRequest, as: 'pettyCashRequests' }, 'createdAt', 'DESC'] + [{ model: PettyCashRequest, as: 'pettyCashRequests' }, 'createdAt', 'DESC'], + [{ model: OutsidePartyRequest, as: 'outsidePartyRequests' }, 'createdAt', 'DESC'], + [{ model: Status, as: 'statuses' }, 'createdAt', 'ASC'] ]; } @@ -290,35 +327,12 @@ class IssueService { await issue.update(updateData); - // Fetch updated issue with relations - const updatedIssue = await Issue.findByPk(id, { - include: [ - { - model: Branch, - as: 'branch', - attributes: ['id', 'name', 'location'] - }, - { - model: BranchManager, - as: 'manager', - attributes: ['id'], - include: [{ - model: models.User, - as: 'user', - attributes: ['id', 'name', 'email'] - }] - }, - { - model: ThirdParty, - as: 'thirdParty', - attributes: ['id', 'organization', 'email'] - } - ] - }); + // Fetch full updated issue to return to the client + const updatedIssueResult = await this.getIssueById(id, true); return { success: true, - data: updatedIssue, + data: updatedIssueResult.data, message: 'Issue updated successfully' }; } catch (error) { @@ -378,29 +392,17 @@ class IssueService { }; } - await issue.update({ + await issue.update({ technician_id: technicianId, technician_assigned_at: new Date() }); - // Fetch updated issue with technician info and assignment timestamp - const updatedIssue = await Issue.findByPk(issueId, { - attributes: ['id', 'title', 'description', 'status', 'technician_id', 'technician_assigned_at', 'updatedAt'], - include: [{ - model: Technician, - as: 'technician', - attributes: ['id', 'specialization', 'createdAt', 'updatedAt'], - include: [{ - model: models.User, - as: 'user', - attributes: ['id', 'name', 'email', 'createdAt'] - }] - }] - }); + // Fetch full updated issue to return to the client + const updatedIssueResult = await this.getIssueById(issueId, true); return { success: true, - data: updatedIssue, + data: updatedIssueResult.data, message: 'Technician assigned successfully' }; } catch (error) { @@ -433,29 +435,17 @@ class IssueService { }; } - await issue.update({ + await issue.update({ maintenance_executive_id: executiveId, maintenance_executive_assigned_at: new Date() }); - // Fetch updated issue with executive info and assignment timestamp - const updatedIssue = await Issue.findByPk(issueId, { - attributes: ['id', 'title', 'description', 'status', 'maintenance_executive_id', 'maintenance_executive_assigned_at', 'updatedAt'], - include: [{ - model: MaintenanceExecutive, - as: 'maintenanceExecutive', - attributes: ['id', 'createdAt', 'updatedAt'], - include: [{ - model: models.User, - as: 'user', - attributes: ['id', 'name', 'email', 'createdAt'] - }] - }] - }); + // Fetch full updated issue to return to the client + const updatedIssueResult = await this.getIssueById(issueId, true); return { success: true, - data: updatedIssue, + data: updatedIssueResult.data, message: 'Maintenance Executive assigned successfully' }; } catch (error) { @@ -488,24 +478,17 @@ class IssueService { }; } - await issue.update({ + await issue.update({ third_party_id: thirdPartyId, third_party_assigned_at: new Date() }); - // Fetch updated issue with third party info and assignment timestamp - const updatedIssue = await Issue.findByPk(issueId, { - attributes: ['id', 'title', 'description', 'status', 'third_party_id', 'third_party_assigned_at', 'updatedAt'], - include: [{ - model: ThirdParty, - as: 'thirdParty', - attributes: ['id', 'organization', 'email', 'worktype', 'createdAt', 'updatedAt'] - }] - }); + // Fetch full updated issue to return to the client + const updatedIssueResult = await this.getIssueById(issueId, true); return { success: true, - data: updatedIssue, + data: updatedIssueResult.data, message: 'Third Party assigned successfully' }; } catch (error) { @@ -531,9 +514,12 @@ class IssueService { await issue.update({ status }); + // Fetch full updated issue to return to the client + const updatedIssueResult = await this.getIssueById(id, true); + return { success: true, - data: issue, + data: updatedIssueResult.data, message: 'Issue status updated successfully' }; } catch (error) { diff --git a/src/services/outsidePartyRequestService.js b/src/services/outsidePartyRequestService.js new file mode 100644 index 0000000..c2420bd --- /dev/null +++ b/src/services/outsidePartyRequestService.js @@ -0,0 +1,59 @@ +import OutsidePartyRequest from '../models/outsidePartyRequest.js'; + +/** + * Get all outside party requests (optionally filtered) + */ +export const getAll = async (filters = {}) => { + const records = await OutsidePartyRequest.getAllWithFilters(filters); + return records.map(r => r.toJSON()); +}; + +/** + * Get one by ID + */ +export const getById = async (id) => { + const record = await OutsidePartyRequest.findByPk(id); + return record ? record.toJSON() : null; +}; + +/** + * Create a new outside party request + */ +export const create = async (data) => { + const { issue_id, suggested_by, vendor_name, description } = data; + if (!issue_id || !suggested_by || !vendor_name || !description) { + throw new Error('Missing required fields: issue_id, suggested_by, vendor_name, description'); + } + const record = await OutsidePartyRequest.create({ issue_id, suggested_by, vendor_name, description }); + return record.toJSON(); +}; + +/** + * Approve a request + */ +export const approve = async (id, approvedBy, comment = null) => { + const record = await OutsidePartyRequest.findByPk(id); + if (!record) return null; + if (record.status === 'approved') throw new Error('Already approved'); + return (await OutsidePartyRequest.updateStatus(id, 'approved', approvedBy, comment)).toJSON(); +}; + +/** + * Reject a request + */ +export const reject = async (id, approvedBy, comment = null) => { + const record = await OutsidePartyRequest.findByPk(id); + if (!record) return null; + if (record.status === 'rejected') throw new Error('Already rejected'); + return (await OutsidePartyRequest.updateStatus(id, 'rejected', approvedBy, comment)).toJSON(); +}; + +/** + * Delete a request (cancel) + */ +export const remove = async (id) => { + const record = await OutsidePartyRequest.findByPk(id); + if (!record) return false; + await record.destroy(); + return true; +}; diff --git a/src/services/statusService.js b/src/services/statusService.js new file mode 100644 index 0000000..a111c90 --- /dev/null +++ b/src/services/statusService.js @@ -0,0 +1,103 @@ +import Status from '../models/status.js'; +import User from '../models/user.js'; +import Issue from '../models/issue.js'; + +class StatusService { + /** + * Create a new status update record for an issue. + * @param {object} data - { issue_id, user_id, description, image_url, image_urls, status_type } + */ + async createStatusUpdate(data) { + try { + const { issue_id, user_id, description, image_url, image_urls, status_type } = data; + + // Validate issue exists + const issue = await Issue.findByPk(issue_id); + if (!issue) { + return { success: false, message: 'Issue not found' }; + } + + // Validate user exists + const user = await User.findByPk(user_id); + if (!user) { + return { success: false, message: 'User not found' }; + } + + // Handle both single image_url and multiple image_urls + let imageValue = null; + if (image_urls && Array.isArray(image_urls) && image_urls.length > 0) { + imageValue = image_urls; + } else if (image_url) { + imageValue = image_url; + } + + const statusUpdate = await Status.create({ + issue_id, + user_id, + description, + image_url: imageValue, + status_type: status_type || 'Open' + }); + + // Fetch with user relation for the response + const result = await Status.findByPk(statusUpdate.id, { + include: [ + { + model: User, + as: 'user', + attributes: ['id', 'name', 'email', 'profilePicture'] + } + ] + }); + + return { + success: true, + message: 'Status update created successfully', + data: result + }; + } catch (error) { + console.error('Error creating status update:', error); + return { + success: false, + message: 'Failed to create status update', + error: error.message + }; + } + } + + /** + * Get all status updates for a given issue. + * @param {number} issue_id + */ + async getStatusUpdatesByIssue(issue_id) { + try { + const statusUpdates = await Status.findAll({ + where: { issue_id }, + include: [ + { + model: User, + as: 'user', + attributes: ['id', 'name', 'email', 'profilePicture'] + } + ], + order: [['createdAt', 'ASC']] + }); + + return { + success: true, + message: 'Status updates retrieved successfully', + data: statusUpdates, + count: statusUpdates.length + }; + } catch (error) { + console.error('Error fetching status updates:', error); + return { + success: false, + message: 'Failed to fetch status updates', + error: error.message + }; + } + } +} + +export default new StatusService(); diff --git a/src/socket/socket.js b/src/socket/socket.js index 064b972..3f70b12 100644 --- a/src/socket/socket.js +++ b/src/socket/socket.js @@ -4,6 +4,9 @@ import messageService from '../services/messageService.js'; import jwt from "jsonwebtoken"; import Issue from '../models/issue.js'; import { Op } from 'sequelize'; +import User from '../models/user.js'; +import * as CashRequestService from '../services/cashRequestService.js'; +import * as OutsidePartyRequestService from '../services/outsidePartyRequestService.js'; let ioInstance = null; let newIssue = null; @@ -110,7 +113,7 @@ export function notifyNewIssue(issue) { } //Emit an assigned_issue event to a specific technician in the /assign namespace. -export function notifyAssign(id,issue) { +export function notifyAssign(id, issue) { if (!assign) return; try { const room = `technician:${id}`; @@ -164,6 +167,105 @@ export function makeDynamicNamespace(issueId) { } }); + socket.on("petty_cash_request", async (data) => { + console.log("Petty cash request received:", data); + try { + const newRequest = await CashRequestService.createCashRequest({ + technician_id: data.technician_id, + issue_id: data.issue_id, + amount: data.amount, + description: data.description, + }); + // Emit once to the entire namespace (includes all users in this issue) + ioInstance.of(`/issue-${issueId}`).emit("issue_update", newRequest); + } catch (err) { + console.error('petty_cash_request error:', err); + } + }); + + socket.on("petty_cash_action", async (data) => { + console.log("Petty cash action received:", data); + try { + const uid = data.user_id || userId; + const user = await User.findByPk(uid); + + if (data.action === 'cancel') { + const existingRequest = await CashRequestService.getCashRequestById(data.request_id); + if (!existingRequest) return; + await CashRequestService.deleteCashRequest(data.request_id); + // Emit fake update to mark rejected/cancelled locally + const pseudoUpdate = { ...existingRequest, status: 'rejected' }; + ioInstance.of(`/issue-${issueId}`).emit("issue_update", pseudoUpdate); + return; + } + + if (!user || !['branch_manager', 'maintenance_executive'].includes(user.role)) { + console.error('PermissionDenied: Only managers can approve/reject petty cash.'); + return; + } + + let result; + if (data.action === 'undo') { + // Revert back to pending + result = await CashRequestService.updateCashRequest(data.request_id, { status: 'pending' }); + } else if (data.action === 'approve') { + result = await CashRequestService.approveCashRequest(data.request_id); + } else if (data.action === 'reject') { + result = await CashRequestService.rejectCashRequest(data.request_id); + } + + if (result) { + ioInstance.of(`/issue-${issueId}`).emit("issue_update", result); + } + } catch (err) { + console.error('petty_cash_action error:', err); + } + }); + + socket.on("outside_party_suggest", async (data) => { + console.log("Outside party suggestion received:", data); + try { + const record = await OutsidePartyRequestService.create({ + issue_id: data.issue_id, + suggested_by: data.suggested_by || userId, + vendor_name: data.vendor_name, + description: data.description, + }); + ioInstance.of(`/issue-${issueId}`).emit("outside_party_update", record); + } catch (err) { + console.error('outside_party_suggest error:', err); + socket.emit('socket_error', { message: err.message }); + } + }); + + socket.on("outside_party_action", async (data) => { + console.log("Outside party action received:", data); + try { + const uid = data.user_id || userId; + const user = await User.findByPk(uid); + + if (!user || !['branch_manager', 'maintenance_executive'].includes(user.role)) { + console.error('PermissionDenied: Only managers can approve/reject outside party requests.'); + socket.emit('socket_error', { message: 'Permission denied' }); + return; + } + + let result; + if (data.action === 'approve') { + result = await OutsidePartyRequestService.approve(data.request_id, uid, data.comment || null); + } else if (data.action === 'reject') { + result = await OutsidePartyRequestService.reject(data.request_id, uid, data.comment || null); + } + + if (result) { + ioInstance.of(`/issue-${issueId}`).emit("outside_party_update", result); + } + } catch (err) { + console.error('outside_party_action error:', err); + socket.emit('socket_error', { message: err.message }); + } + }); + socket.on("disconnect", () => { console.log(`User disconnected: ${socket.id}`); }); @@ -174,34 +276,34 @@ export function makeDynamicNamespace(issueId) { export function removeDynamicNamespace(issueId) { if (!ioInstance) return; - + try { const namespaceName = `/issue-${issueId}`; const namespace = ioInstance.of(namespaceName); - + console.log(`Removing dynamic namespace: ${namespaceName}`); // Emit issue_update event before disconnecting namespace.emit('issue_update', { status: 'closed', message: 'The issue has been closed.' }); - + // Get all sockets in the namespace and disconnect them namespace.fetchSockets().then((sockets) => { sockets.forEach((socket) => { console.log(`Disconnecting socket ${socket.id} from namespace ${namespaceName}`); socket.disconnect(true); }); - + // Remove all listeners from the namespace namespace.removeAllListeners(); - + // Delete the namespace from the server ioInstance._nsps.delete(namespaceName); - + console.log(`Dynamic namespace ${namespaceName} removed successfully`); }).catch((err) => { console.error(`Error removing namespace ${namespaceName}:`, err); }); - + } catch (err) { console.error('removeDynamicNamespace error:', err); } @@ -216,4 +318,15 @@ export function issueRealtimeUpdate(issueId, issueData) { } catch (err) { console.error('issueRealtimeUpdate error:', err); } +} + +// Emit a status_update_log event to all clients connected to the /issue- namespace. +export function statusUpdateLogCreated(issueId, statusData) { + if (!ioInstance) return; + try { + const namespace = ioInstance.of(`/issue-${issueId}`); + namespace.emit('status_update_log', statusData); + } catch (err) { + console.error('statusUpdateLogCreated error:', err); + } } \ No newline at end of file From 42a7a6436b1c26320528ba4e701119b65b94911d Mon Sep 17 00:00:00 2001 From: hello-sahasraka Date: Sat, 7 Mar 2026 16:41:55 +0530 Subject: [PATCH 3/4] feat: enhance cash request handling and validation --- server.js | 1 + src/controllers/cashRequestController.js | 23 ++++++++++++++++------- src/models/pettyCashRequest.js | 4 ++-- src/routes/cashRequestRoutes.js | 8 ++++---- src/services/cashRequestService.js | 10 +++++++--- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/server.js b/server.js index 6071cd3..b87eec5 100644 --- a/server.js +++ b/server.js @@ -29,6 +29,7 @@ app.use(cors({ origin: '*' })); app.use('/api/health', healthRoutes); app.use('/api/v1/auth', authRoutes); app.use('/api/v1/cash-requests', cashRequestRoutes); +app.use('/api/v1/petty-cash-requests', cashRequestRoutes); app.use('/api/v1/issues', issueRoutes); app.use('/api/v1/users', userRoutes); app.use('/api/v1/messages', messageRoutes); diff --git a/src/controllers/cashRequestController.js b/src/controllers/cashRequestController.js index c9d2dc0..be69d16 100644 --- a/src/controllers/cashRequestController.js +++ b/src/controllers/cashRequestController.js @@ -102,7 +102,7 @@ export const createCashRequest = async (req, res) => { }); } - const { technician_id, issue_id, amount, description } = req.body; + const { technician_id, issue_id, amount, description } = parseCreateBody(req.body); const newCashRequest = await CashRequestService.createCashRequest({ technician_id, @@ -111,12 +111,12 @@ export const createCashRequest = async (req, res) => { description }); - try { - // Notify via realtime update that a new cash request has been created for the issue - issueRealtimeUpdate(issue_id, newCashRequest); - } catch (err) { - console.error('issueRealtimeUpdate error after creating cash request:', err); - } + // try { + // // Notify via realtime update that a new cash request has been created for the issue + // issueRealtimeUpdate(issue_id, newCashRequest); + // } catch (err) { + // console.error('issueRealtimeUpdate error after creating cash request:', err); + // } res.status(201).json({ success: true, @@ -133,6 +133,15 @@ export const createCashRequest = async (req, res) => { } }; +// Ensure createCashRequest receives parsed numbers (express may pass strings from JSON) +function parseCreateBody(body) { + const technician_id = body.technician_id != null ? parseInt(body.technician_id, 10) : undefined; + const issue_id = body.issue_id != null ? parseInt(body.issue_id, 10) : undefined; + const amount = body.amount != null ? parseFloat(body.amount) : undefined; + const description = typeof body.description === 'string' ? body.description.trim() : body.description; + return { technician_id, issue_id, amount, description }; +} + /** * Update an existing cash request * @route PUT /api/v1/cash-requests/:id diff --git a/src/models/pettyCashRequest.js b/src/models/pettyCashRequest.js index 916b4bd..8758d70 100644 --- a/src/models/pettyCashRequest.js +++ b/src/models/pettyCashRequest.js @@ -78,8 +78,8 @@ const PettyCashRequest = sequelize.define( msg: 'Description cannot be empty' }, len: { - args: [10, 5000], - msg: 'Description must be between 10 and 5000 characters' + args: [1, 5000], + msg: 'Description must be between 1 and 5000 characters' } }, comment: 'Detailed description of what the cash will be used for' diff --git a/src/routes/cashRequestRoutes.js b/src/routes/cashRequestRoutes.js index 931b71a..4e6ad45 100644 --- a/src/routes/cashRequestRoutes.js +++ b/src/routes/cashRequestRoutes.js @@ -47,8 +47,8 @@ const createCashRequestValidation = [ .notEmpty() .withMessage('description is required') .trim() - .isLength({ min: 10, max: 5000 }) - .withMessage('description must be between 10 and 5000 characters') + .isLength({ min: 1, max: 5000 }) + .withMessage('description must be between 1 and 5000 characters') ]; const updateCashRequestValidation = [ @@ -59,8 +59,8 @@ const updateCashRequestValidation = [ body('description') .optional() .trim() - .isLength({ min: 10, max: 5000 }) - .withMessage('description must be between 10 and 5000 characters'), + .isLength({ min: 1, max: 5000 }) + .withMessage('description must be between 1 and 5000 characters'), body('status') .optional() .isIn(['pending', 'approved', 'rejected']) diff --git a/src/services/cashRequestService.js b/src/services/cashRequestService.js index a192815..7660eac 100644 --- a/src/services/cashRequestService.js +++ b/src/services/cashRequestService.js @@ -53,11 +53,15 @@ export const createCashRequest = async (cashRequestData) => { } // Validate description is not empty - if (!description.trim()) { - throw new Error('Description cannot be empty'); + const desc = typeof description === 'string' ? description.trim() : String(description ?? ''); + if (!desc || desc.length > 5000) { + throw new Error('Description cannot be empty and must be at most 5000 characters'); } - const newCashRequest = await PettyCashRequest.create(cashRequestData); + const newCashRequest = await PettyCashRequest.create({ + ...cashRequestData, + description: desc + }); return newCashRequest.toJSON(); } catch (error) { throw new Error(`Service error in createCashRequest: ${error.message}`); From 694ead61a6c4e31a9ed10ed7b93d5c77a00324c0 Mon Sep 17 00:00:00 2001 From: Naveen Sanjula <82176749+naveensanjula975@users.noreply.github.com> Date: Sat, 7 Mar 2026 23:31:16 +0530 Subject: [PATCH 4/4] chore: update minio to version 8.0.7 and fast-xml-parser to version 5.4.1 --- package-lock.json | 1287 ++++++++++++++++----------------------------- package.json | 4 +- 2 files changed, 463 insertions(+), 828 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f5bee6..33efbff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "express-validator": "^7.2.1", "jsonwebtoken": "^9.0.2", "mathjs": "^15.1.0", - "minio": "^8.0.6", + "minio": "^8.0.7", "multer": "^2.0.2", "nodemailer": "^7.0.11", "pg": "^8.16.3", @@ -33,13 +33,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -48,9 +48,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, "license": "MIT", "engines": { @@ -58,22 +58,22 @@ } }, "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -90,14 +90,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -107,13 +107,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -134,29 +134,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -166,9 +166,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -186,9 +186,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -206,27 +206,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -291,13 +291,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -333,13 +333,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -459,13 +459,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -475,42 +475,42 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -518,14 +518,14 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -539,9 +539,9 @@ "license": "MIT" }, "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", "dev": true, "license": "MIT", "optional": true, @@ -551,9 +551,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "dev": true, "license": "MIT", "optional": true, @@ -1043,9 +1043,9 @@ "license": "MIT" }, "node_modules/@paralleldrive/cuid2": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", - "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", "dev": true, "license": "MIT", "dependencies": { @@ -1077,9 +1077,9 @@ } }, "node_modules/@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "version": "0.34.48", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz", + "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==", "dev": true, "license": "MIT" }, @@ -1217,12 +1217,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.7.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.1.tgz", - "integrity": "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==", + "version": "25.3.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.5.tgz", + "integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==", "license": "MIT", "dependencies": { - "undici-types": "~7.14.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/stack-utils": { @@ -1233,15 +1233,15 @@ "license": "MIT" }, "node_modules/@types/validator": { - "version": "13.15.3", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz", - "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==", + "version": "13.15.10", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", "license": "MIT" }, "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, "license": "MIT", "dependencies": { @@ -1531,13 +1531,6 @@ "win32" ] }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "license": "(Unlicense OR Apache-2.0)", - "optional": true - }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", @@ -1666,21 +1659,6 @@ "node": ">= 4.0.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/babel-jest": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", @@ -1797,13 +1775,16 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.16", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", - "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/bcryptjs": { @@ -1842,9 +1823,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", @@ -1853,7 +1834,7 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", + "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, @@ -1895,9 +1876,9 @@ "license": "MIT" }, "node_modules/browserslist": { - "version": "4.26.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -1916,11 +1897,11 @@ "license": "MIT", "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -1980,24 +1961,6 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -2048,9 +2011,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001749", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz", - "integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==", + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", "dev": true, "funding": [ { @@ -2121,9 +2084,9 @@ } }, "node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true, "funding": [ { @@ -2137,9 +2100,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", - "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", "dev": true, "license": "MIT" }, @@ -2233,9 +2196,9 @@ } }, "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, "license": "MIT" }, @@ -2283,9 +2246,9 @@ } }, "node_modules/complex.js": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.2.tgz", - "integrity": "sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.3.tgz", + "integrity": "sha512-UrQVSUur14tNX6tiP4y8T4w4FeJAX3bi2cIv0pu/DTLFNxoq7z2Yh83Vfzztj6Px3X/lubqQ9IrPp7Bpn6p4MQ==", "license": "MIT", "engines": { "node": "*" @@ -2339,15 +2302,16 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -2392,9 +2356,9 @@ "license": "MIT" }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -2402,6 +2366,10 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cross-spawn": { @@ -2452,9 +2420,9 @@ } }, "node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2476,23 +2444,6 @@ "node": ">=0.10.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2534,9 +2485,9 @@ } }, "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -2546,9 +2497,9 @@ } }, "node_modules/dottie": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", - "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.7.tgz", + "integrity": "sha512-7lAK2A0b3zZr3UC5aE69CPdCFR4RHW1o2Dr74TqFykxkUCBXSRJum/yPc7g8zRHJqWKomPLHwFLLoUnn8PXXRg==", "license": "MIT" }, "node_modules/dunder-proto": { @@ -2582,15 +2533,15 @@ } }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -2600,26 +2551,10 @@ "node": ">=14" } }, - "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/editorconfig/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -2636,9 +2571,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.234", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.234.tgz", - "integrity": "sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==", + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", "dev": true, "license": "ISC" }, @@ -2672,9 +2607,9 @@ } }, "node_modules/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz", + "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", "license": "MIT", "dependencies": { "@types/cors": "^2.8.12", @@ -2683,46 +2618,28 @@ "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", - "debug": "~4.3.1", + "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" + "ws": "~8.18.3" }, "engines": { "node": ">=10.2.0" } }, "node_modules/engine.io-client": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", - "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", "dev": true, "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", + "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", + "ws": "~8.18.3", "xmlhttprequest-ssl": "~2.1.1" } }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/engine.io-parser": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", @@ -2745,23 +2662,6 @@ "node": ">= 0.6" } }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/engine.io/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2904,9 +2804,9 @@ } }, "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, "node_modules/execa": { @@ -2969,18 +2869,19 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -3037,10 +2938,22 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-xml-builder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.0.0.tgz", + "integrity": "sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/fast-xml-parser": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz", - "integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.2.tgz", + "integrity": "sha512-pw/6pIl4k0CSpElPEJhDppLzaixDEuWui2CUQQBH/ECDf7+y6YwA4Gf7Tyb0Rfe4DIMuZipYj4AEL0nACKglvQ==", "funding": [ { "type": "github", @@ -3049,7 +2962,8 @@ ], "license": "MIT", "dependencies": { - "strnum": "^2.1.0" + "fast-xml-builder": "^1.0.0", + "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" @@ -3088,9 +3002,9 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -3101,7 +3015,11 @@ "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/find-up": { @@ -3118,21 +3036,6 @@ "node": ">=8" } }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -3151,9 +3054,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { @@ -3279,15 +3182,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3372,6 +3266,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -3431,18 +3326,6 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -3459,6 +3342,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -3490,28 +3374,23 @@ "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/human-signals": { @@ -3525,9 +3404,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3600,30 +3479,14 @@ "license": "ISC" }, "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", "license": "MIT", "engines": { "node": ">= 10" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3644,18 +3507,6 @@ "node": ">=8" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -3702,25 +3553,6 @@ "node": ">=6" } }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3750,24 +3582,6 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3781,21 +3595,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3831,9 +3630,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -4388,9 +4187,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -4615,12 +4414,12 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -4637,9 +4436,9 @@ } }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4649,9 +4448,9 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -4660,12 +4459,12 @@ } }, "node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^1.4.2", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -4774,9 +4573,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -4806,9 +4605,9 @@ } }, "node_modules/mathjs": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.1.0.tgz", - "integrity": "sha512-HfnAcScQm9drGryodlDqeS3WAl4gUTYGDcOtcqL/8s23MZ28Ib1i8XnYK3ZdjNuaW/L4BAp9lIp8vxAMrcuu1w==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.1.1.tgz", + "integrity": "sha512-rM668DTtpSzMVoh/cKAllyQVEbBApM5g//IMGD8vD7YlrIz9ITRr3SrdhjaDxcBNTdyETWwPebj2unZyHD7ZdA==", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.26.10", @@ -4903,15 +4702,19 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-fn": { @@ -4925,13 +4728,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4940,19 +4743,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minio": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.6.tgz", - "integrity": "sha512-sOeh2/b/XprRmEtYsnNRFtOqNRTPDvYtMWh+spWlfsuCV/+IdxNeKVUMKLqI7b5Dr07ZqCPuaRGU/rB9pZYVdQ==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.7.tgz", + "integrity": "sha512-E737MgufW8CeQAsTAtnEMrxZ9scMSf29kkhZoXzDTKj/Jszzo2SfeZUH9wbDQH2Rsq6TCtl/yQL0+XdVKZansQ==", "license": "Apache-2.0", "dependencies": { "async": "^3.2.4", @@ -4960,14 +4754,13 @@ "browser-or-node": "^2.1.1", "buffer-crc32": "^1.0.0", "eventemitter3": "^5.0.1", - "fast-xml-parser": "^4.4.1", + "fast-xml-parser": "^5.3.4", "ipaddr.js": "^2.0.1", "lodash": "^4.17.21", "mime-types": "^2.1.35", "query-string": "^7.1.3", "stream-json": "^1.8.0", "through2": "^4.0.2", - "web-encoding": "^1.1.5", "xml2js": "^0.5.0 || ^0.6.2" }, "engines": { @@ -4996,27 +4789,15 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -5045,21 +4826,22 @@ "license": "MIT" }, "node_modules/multer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", - "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", + "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" + "type-is": "^1.6.18" }, "engines": { "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/multer/node_modules/media-typer": { @@ -5145,32 +4927,32 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "dev": true, "license": "MIT" }, "node_modules/nodemailer": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.11.tgz", - "integrity": "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.13.tgz", + "integrity": "sha512-PNDFSJdP+KFgdsG3ZzMXCgquO7I6McjY2vlqILjtJd0hy8wEvtugS9xKRF2NWlPNGxvLCXlTNIae4serI7dinw==", "license": "MIT-0", "engines": { "node": ">=6.0.0" } }, "node_modules/nodemon": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", - "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", + "minimatch": "^10.2.1", "pstree.remy": "^1.1.8", "semver": "^7.5.3", "simple-update-notifier": "^2.0.0", @@ -5189,15 +4971,27 @@ "url": "https://opencollective.com/nodemon" } }, + "node_modules/nodemon/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/nodemon/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/nodemon/node_modules/has-flag": { @@ -5211,22 +5005,25 @@ } }, "node_modules/nodemon/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/nodemon/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -5498,15 +5295,15 @@ } }, "node_modules/pg": { - "version": "8.16.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", - "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", "license": "MIT", "peer": true, "dependencies": { - "pg-connection-string": "^2.9.1", - "pg-pool": "^3.10.1", - "pg-protocol": "^1.10.3", + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, @@ -5514,7 +5311,7 @@ "node": ">= 16.0.0" }, "optionalDependencies": { - "pg-cloudflare": "^1.2.7" + "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" @@ -5526,16 +5323,16 @@ } }, "node_modules/pg-cloudflare": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", - "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", - "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", "license": "MIT" }, "node_modules/pg-hstore": { @@ -5560,18 +5357,18 @@ } }, "node_modules/pg-pool": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", - "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", "license": "MIT", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-protocol": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", - "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", "license": "MIT" }, "node_modules/pg-types": { @@ -5642,15 +5439,6 @@ "node": ">=8" } }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -5661,9 +5449,9 @@ } }, "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5772,9 +5560,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -5814,36 +5602,20 @@ } }, "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -5889,13 +5661,13 @@ } }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -5974,23 +5746,6 @@ ], "license": "MIT" }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5998,10 +5753,13 @@ "license": "MIT" }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } }, "node_modules/seedrandom": { "version": "3.0.5", @@ -6020,25 +5778,29 @@ } }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "license": "MIT", "dependencies": { - "debug": "^4.3.5", + "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "statuses": "^2.0.2" }, "engines": { "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/sequelize": { @@ -6104,9 +5866,9 @@ } }, "node_modules/sequelize-cli": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.3.tgz", - "integrity": "sha512-1YYPrcSRt/bpMDDSKM5ubY1mnJ2TEwIaGZcqITw4hLtGtE64nIqaBnLtMvH8VKHg6FbWpXTiFNc2mS/BtQCXZw==", + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.5.tgz", + "integrity": "sha512-DqyISCULOaEbTM+rRQH4YvcUWeOC1XDiSKcjsC6TfAnT7W837mNkChJhtB/Z4FdCFHRCojmiP7zsrA4pARmacA==", "dev": true, "license": "MIT", "dependencies": { @@ -6240,9 +6002,9 @@ } }, "node_modules/sequelize/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6252,9 +6014,9 @@ } }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "license": "MIT", "dependencies": { "encodeurl": "^2.0.0", @@ -6264,23 +6026,10 @@ }, "engines": { "node": ">= 18" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/setprototypeof": { @@ -6411,9 +6160,9 @@ } }, "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -6434,15 +6183,15 @@ } }, "node_modules/socket.io": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", - "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", - "debug": "~4.3.2", + "debug": "~4.4.1", "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" @@ -6452,41 +6201,24 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", + "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", "license": "MIT", "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "debug": "~4.4.1", + "ws": "~8.18.3" } }, "node_modules/socket.io-client": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", - "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", "dev": true, "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", + "debug": "~4.4.1", "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" }, @@ -6494,54 +6226,19 @@ "node": ">=10.0.0" } }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "debug": "~4.4.1" }, "engines": { "node": ">=10.0.0" } }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/socket.io/node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -6555,23 +6252,6 @@ "node": ">= 0.6" } }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/socket.io/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -6813,13 +6493,13 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -6886,9 +6566,9 @@ } }, "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz", + "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==", "funding": [ { "type": "github", @@ -6898,9 +6578,9 @@ "license": "MIT" }, "node_modules/superagent": { - "version": "10.2.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", - "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", + "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6908,25 +6588,26 @@ "cookiejar": "^2.1.4", "debug": "^4.3.7", "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.4", + "form-data": "^4.0.5", "formidable": "^3.5.4", "methods": "^1.1.2", "mime": "2.6.0", - "qs": "^6.11.2" + "qs": "^6.14.1" }, "engines": { "node": ">=14.18.0" } }, "node_modules/supertest": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", - "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", + "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", "dev": true, "license": "MIT", "dependencies": { + "cookie-signature": "^1.2.2", "methods": "^1.1.2", - "superagent": "^10.2.3" + "superagent": "^10.3.0" }, "engines": { "node": ">=14.18.0" @@ -6959,9 +6640,9 @@ } }, "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7001,9 +6682,9 @@ } }, "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -7119,9 +6800,9 @@ } }, "node_modules/typed-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", - "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.2.tgz", + "integrity": "sha512-VwaXim9Gp1bngi/q3do8hgttYn2uC3MoT/gfuMWylnj1IeZBUAyPddHZlo1K05BDoj8DYPpMdiHqH1dDYdJf2A==", "license": "MIT", "engines": { "node": ">= 18" @@ -7154,15 +6835,15 @@ "license": "MIT" }, "node_modules/underscore": { - "version": "1.13.7", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", - "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", "license": "MIT" }, "node_modules/undici-types": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", - "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT" }, "node_modules/universalify": { @@ -7220,9 +6901,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -7250,19 +6931,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7321,18 +6989,6 @@ "makeerror": "1.0.12" } }, - "node_modules/web-encoding": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", - "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", - "license": "MIT", - "dependencies": { - "util": "^0.12.3" - }, - "optionalDependencies": { - "@zxing/text-encoding": "0.9.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7349,27 +7005,6 @@ "node": ">= 8" } }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/wkx": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", @@ -7495,9 +7130,9 @@ } }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index cf14880..7ad68ba 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "express-validator": "^7.2.1", "jsonwebtoken": "^9.0.2", "mathjs": "^15.1.0", - "minio": "^8.0.6", + "minio": "^8.0.7", "multer": "^2.0.2", "nodemailer": "^7.0.11", "pg": "^8.16.3", @@ -43,6 +43,6 @@ "glob": "10.5.0", "validator": "^13.15.22", "js-yaml": "3.14.2", - "fast-xml-parser": "5.3.4" + "fast-xml-parser": "^5.4.1" } }