From f33bbc19da72831c25194b8dd0997994c96e1d54 Mon Sep 17 00:00:00 2001 From: yajuusan <3141249582@qq.com> Date: Mon, 27 Apr 2026 19:32:39 +1000 Subject: [PATCH 1/2] incident report API - merge conflicts resolved --- app-backend/src/config/multer.js | 13 +- .../controllers/incidentreport.controller.js | 317 ++++++++++++++++++ app-backend/src/middleware/role.js | 2 + app-backend/src/models/IncidentReport.js | 51 +++ .../src/routes/incidentreport.routes.js | 286 ++++++++++++++++ app-backend/src/routes/index.js | 3 + 6 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 app-backend/src/controllers/incidentreport.controller.js create mode 100644 app-backend/src/models/IncidentReport.js create mode 100644 app-backend/src/routes/incidentreport.routes.js diff --git a/app-backend/src/config/multer.js b/app-backend/src/config/multer.js index dfc13656c..b09925099 100644 --- a/app-backend/src/config/multer.js +++ b/app-backend/src/config/multer.js @@ -31,4 +31,15 @@ export const upload = multer({ storage, fileFilter, limits: { fileSize: 5 * 1024 * 1024 }, -}); \ No newline at end of file +}); + +const incidentAttachmentFilter = (_req, file, cb) => { + const ok = ['image/jpeg', 'image/png', 'application/pdf'].includes(file.mimetype); + cb(ok ? null : new Error('Only JPG, PNG, and PDF files are allowed'), ok); +}; + +export const incidentAttachmentUpload = multer({ + storage: multer.memoryStorage(), // Use memory storage to keep files in buffer for MongoDB + fileFilter: incidentAttachmentFilter, + limits: {fileSize: 5 * 1024 * 1024}, +}); diff --git a/app-backend/src/controllers/incidentreport.controller.js b/app-backend/src/controllers/incidentreport.controller.js new file mode 100644 index 000000000..9c51c2354 --- /dev/null +++ b/app-backend/src/controllers/incidentreport.controller.js @@ -0,0 +1,317 @@ +import PDFDocument from 'pdfkit'; +import IncidentReport from "../models/IncidentReport.js"; +import Shift from "../models/Shift.js"; + +const mapAttachments = (req) => { + // Backend Validations - File upload restrictions and security checks. + let attachments = []; + if (req.files && req.files.length > 0) { + attachments = req.files.map(file => ({ + fileName: file.originalname, + fileData: file.buffer, // Store binary data directly in MongoDB + fileType: file.mimetype, + fileSize: file.size, + uploadedBy: req.user.id + })); + } + return attachments; +}; + +export const submitIncident = async (req, res) => { + try { + const { title, description, shiftId, location } = req.body; + const guardId = req.user.id; + + // Missing required field validation + if (!title || !description || !shiftId) { + return res.status(400).json({ + message: 'Title, description, and shiftId are required' + }); + } + + const attachments = mapAttachments(req); + + // Backend Validations - Only guards assigned to a shift can submit incident for that shift. + const shift = await Shift.findById(shiftId); + if (!shift || shift.guardId.toString() !== guardId) { + return res.status(403).json({ message: 'Not authorized to submit incident for this shift.' }); + } + + const newReport = new IncidentReport({ + title, + description, + guardId, + shiftId, + location, + attachments + }); + + const savedReport = await newReport.save(); + res.status(201).json(savedReport); + } catch (err) { + res.status(400).json({ message: err.message }); + } +}; + +export const updateIncident = async (req, res) => { + try { + const { id } = req.params; // Fixed: Added :id parameter + const { status, severity, employerComment, description } = req.body; + const userRole = req.user.role; + const userId = req.user.id; + + // Enum validation + const validSeverity = ['low', 'medium', 'high', 'critical']; + const validStatus = ['pending', 'resolved']; + + if (severity && !validSeverity.includes(severity)) { + return res.status(400).json({ message: 'Invalid severity value' }); + } + if (status && !validStatus.includes(status)) { + return res.status(400).json({ message: 'Invalid status value' }); + } + + const report = await IncidentReport.findById(id); + if (!report) return res.status(404).json({ message: 'Incident not found' }); + + // Ownership validation for guards + if (userRole === 'guard' && report.guardId.toString() !== userId) { + return res.status(403).json({ message: 'Not authorized to update this incident' }); + } + + // Guard can only update description and attachments + if (userRole === 'guard') { + if (description) report.description = description; + + // Fixed: Merge attachments instead of overwriting + const newAttachments = mapAttachments(req); + if (newAttachments.length > 0) { + report.attachments.push(...newAttachments); + + // Explicitly tell Mongoose this array was modified. + report.markModified('attachments'); + } + } + // Employer can add comments, assign severity, and update status (pending, resolved). + else if (userRole === 'employer' || userRole === 'admin') { + if (severity) report.severity = severity; + if (employerComment) report.employerComment = employerComment; + + // Fixed: Removed duplicate status assignment + if (status) { + // If previous status is already resolved, user can't resolve it again + if (status === 'resolved' && report.status !== 'resolved') { + report.resolvedAt = new Date(); + report.resolvedBy = req.user.id; + } + + // Fixed: Clear resolved info when changing from resolved to pending + else if (status === 'pending') { + report.resolvedAt = null; + report.resolvedBy = null; + } + + report.status = status; + } + + // They can also update description and attachments + if (description) report.description = description; + + // Fixed: Merge attachments instead of overwriting + const newAttachments = mapAttachments(req); + if (newAttachments.length > 0) { + report.attachments.push(...newAttachments); + + // Explicitly tell Mongoose this array was modified. + report.markModified('attachments'); + } + } + + const updatedReport = await report.save(); + res.status(200).json(updatedReport); + } catch (err) { + res.status(400).json({ message: err.message }); + } +}; + +export const getIncidentById = async (req, res) => { + try { + const { id } = req.params; + const userRole = req.user.role; + const userId = req.user.id; + + const report = await IncidentReport.findById(id) + .populate('guardId', 'name email phone') + .populate('shiftId', 'startTime endTime location') + .populate('resolvedBy', 'name'); + + if (!report) return res.status(404).json({ message: 'Incident not found' }); + + // Ownership validation + if (userRole === 'guard' && report.guardId._id.toString() !== userId) { + return res.status(403).json({ message: 'Not authorized to view this incident' }); + } + + res.status(200).json(report); + } catch (err) { + res.status(500).json({ message: err.message }); + } +}; + +export const getIncidents = async (req, res) => { + try { + const { guardId, shiftId, severity, status } = req.query; + const userRole = req.user.role; + const userId = req.user.id; + + const query = {}; + + // Guards can only see their own incidents + if (userRole === 'guard') { + query.guardId = userId; + } else { + if (guardId) query.guardId = guardId; + } + + if (shiftId) query.shiftId = shiftId; + if (severity) query.severity = severity; + if (status) query.status = status; + + const reports = await IncidentReport.find(query) + .sort({ createdAt: -1 }) + .populate('guardId', 'name') + .populate('shiftId', 'startTime endTime'); + + res.status(200).json(reports); + } catch (err) { + res.status(500).json({ message: err.message }); + } +}; + +export const markIncident = async (req, res) => { + try { + const { id } = req.params; + const { status } = req.body; + const userRole = req.user.role; + + // Enum validation + const validStatus = ['pending', 'resolved']; + if (!status || !validStatus.includes(status)) { + return res.status(400).json({ message: 'Valid status is required' }); + } + + // Only employers/admins can mark resolved + if (userRole !== 'employer' && userRole !== 'admin') { + return res.status(403).json({ message: 'Not authorized to update status.' }); + } + + const report = await IncidentReport.findById(id); + if (!report) return res.status(404).json({ message: 'Incident not found' }); + + report.status = status; + + // Fixed: Correct resolvedAt logic + if (status === 'resolved') { + report.resolvedAt = new Date(); + report.resolvedBy = req.user.id; + } else { + report.resolvedAt = null; + report.resolvedBy = null; + } + + const updatedReport = await report.save(); + res.status(200).json(updatedReport); + } catch (err) { + res.status(500).json({ message: err.message }); + } +}; + +export const exportIncident = async (req, res) => { + try { + const { id } = req.params; + const userRole = req.user.role; + const userId = req.user.id; + + const report = await IncidentReport.findById(id) + .populate('guardId', 'name email phone') + .populate('shiftId', 'startTime endTime location') + .populate('resolvedBy', 'name email'); + + if (!report) { + return res.status(404).json({ message: 'Incident not found' }); + } + + // Ownership validation + if (userRole === 'guard' && report.guardId._id.toString() !== userId) { + return res.status(403).json({ message: 'Not authorized to export this incident' }); + } + + // Set up the HTTP headers for a PDF download + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader( + 'Content-Disposition', + `attachment; filename="Incident_Report_${id}.pdf"` + ); + + const doc = new PDFDocument({ margin: 50, size: 'A4' }); + doc.pipe(res); + + // Header + doc.fontSize(20).font('Helvetica-Bold').text('Incident Report', { align: 'center' }); + doc.moveDown(2); + + // Meta Information Section + doc.fontSize(14).font('Helvetica-Bold').text('General Information'); + doc.fontSize(10).font('Helvetica').moveDown(0.5); + doc.text(`Report ID: ${report._id}`); + doc.text(`Title: ${report.title}`); + doc.text(`Status: ${report.status.toUpperCase()}`); + doc.text(`Severity: ${report.severity.toUpperCase()}`); + doc.text(`Created At: ${new Date(report.createdAt).toLocaleString()}`); + if (report.location) doc.text(`Location: ${report.location}`); + doc.moveDown(1.5); + + // Personnel Information + doc.fontSize(14).font('Helvetica-Bold').text('Personnel & Shift Details'); + doc.fontSize(10).font('Helvetica').moveDown(0.5); + doc.text(`Submitted By (Guard): ${report.guardId?.name || 'Unknown'} (${report.guardId?.email || 'N/A'})`); + doc.text(`Shift ID: ${report.shiftId?._id || 'N/A'}`); + if (report.resolvedAt) { + doc.moveDown(0.5); + doc.text(`Resolved At: ${new Date(report.resolvedAt).toLocaleString()}`); + doc.text(`Resolved By: ${report.resolvedBy?.name || 'Unknown'}`); + } + doc.moveDown(1.5); + + // Description Section + doc.fontSize(14).font('Helvetica-Bold').text('Incident Description'); + doc.fontSize(10).font('Helvetica').moveDown(0.5); + doc.text(report.description, { align: 'justify' }); + doc.moveDown(1.5); + + // Employer Comments (if any) + if (report.employerComment) { + doc.fontSize(14).font('Helvetica-Bold').text('Employer/Admin Comments'); + doc.fontSize(10).font('Helvetica').moveDown(0.5); + doc.text(report.employerComment, { align: 'justify' }); + doc.moveDown(1.5); + } + + // Attachments List (Metadata only, not embedding the actual files) + if (report.attachments && report.attachments.length > 0) { + doc.fontSize(14).font('Helvetica-Bold').text('Attached Files (References)'); + doc.fontSize(10).font('Helvetica').moveDown(0.5); + report.attachments.forEach((file, index) => { + doc.text(`${index + 1}. ${file.fileName} (${file.fileType})`); + }); + } + + doc.end(); + } catch (err) { + if (!res.headersSent) { + res.status(500).json({ message: err.message }); + } else { + console.error('Error during PDF generation stream:', err); + } + } +}; \ No newline at end of file diff --git a/app-backend/src/middleware/role.js b/app-backend/src/middleware/role.js index e47fee9e8..ef211e340 100644 --- a/app-backend/src/middleware/role.js +++ b/app-backend/src/middleware/role.js @@ -25,3 +25,5 @@ export const allowRoles = (...allowedRoles) => { export const guardOnly = allowRoles('guard'); export const employerOnly = allowRoles('employer'); export const adminOnly = allowRoles('admin'); +export const allRoles = allowRoles('guard', 'employer', 'admin') +export const employerOrAdmin = allowRoles('employer', 'admin') diff --git a/app-backend/src/models/IncidentReport.js b/app-backend/src/models/IncidentReport.js new file mode 100644 index 000000000..25621ce6e --- /dev/null +++ b/app-backend/src/models/IncidentReport.js @@ -0,0 +1,51 @@ +import mongoose from 'mongoose'; + +const incidentReportSchema = new mongoose.Schema( + { + title: { + type: String, + required: [true, 'Title is required'], + trim: true, + maxlength: [200, 'Title cannot exceed 200 characters'] + }, + description: { + type: String, + required: [true, 'Description is required'], + trim: true, + maxlength: [5000, 'Description cannot exceed 5000 characters'] + }, + guardId: {type: mongoose.Schema.Types.ObjectId, ref: "Guard", required: true}, + shiftId: {type: mongoose.Schema.Types.ObjectId, ref: "Shift", required: true}, + location: {type: String, trim: true}, + severity: { + type: String, + enum: ['low', 'medium', 'high', 'critical'], + default: 'medium' + }, + employerComment: { + type: String, + trim: true, + maxlength: [5000, 'Comment cannot exceed 5000 characters'] + }, + status: { + type: String, + enum: ['resolved', 'pending'], + default: 'pending' + }, + attachments: [ + { + fileName: {type: String, required: true}, + fileData: {type: Buffer, required: true}, // Store file as binary in MongoDB + fileType: {type: String}, + fileSize: {type: Number}, + uploadedAt: {type: Date, default: Date.now}, + uploadedBy: {type: mongoose.Schema.Types.ObjectId, ref: 'User'} + } + ], + resolvedAt: {type: Date}, + resolvedBy: {type: mongoose.Schema.Types.ObjectId, ref: 'User'} + }, {timestamps: true} // Auto create createdAt updatedAt fields in db +) + +const IncidentReport = mongoose.model('IncidentReport', incidentReportSchema); +export default IncidentReport; \ No newline at end of file diff --git a/app-backend/src/routes/incidentreport.routes.js b/app-backend/src/routes/incidentreport.routes.js new file mode 100644 index 000000000..e44ca6d96 --- /dev/null +++ b/app-backend/src/routes/incidentreport.routes.js @@ -0,0 +1,286 @@ +import express from 'express'; +import { + exportIncident, + getIncidentById, + getIncidents, + markIncident, + submitIncident, + updateIncident, +} from '../controllers/incidentreport.controller.js'; +import auth from '../middleware/auth.js'; +import { allRoles, employerOrAdmin, guardOnly } from '../middleware/role.js'; +import { incidentAttachmentUpload } from "../config/multer.js"; + +const router = express.Router(); + +/** + * @swagger + * tags: + * name: Incident Reports + * description: Incident Report operations + */ + +/** + * @swagger + * /api/v1/incidentreports: + * post: + * summary: Submit a new incident report (Guard only) + * description: Guard submits a new incident report. Supports uploading up to 5 attachments (images or PDFs). + * tags: [Incident Reports] + * security: + * - bearerAuth: [] + * requestBody: + * required: true + * content: + * multipart/form-data: + * schema: + * type: object + * required: + * - title + * - description + * - shiftId + * properties: + * title: + * type: string + * description: Brief title of the incident + * example: "Warehouse unauthorized access" + * description: + * type: string + * description: Detailed description of the incident + * shiftId: + * type: string + * description: Associated shift ID + * location: + * type: string + * description: Specific location where the incident occurred (optional) + * attachments: + * type: array + * items: + * type: string + * format: binary + * description: Attachment files, max 5 files, 5MB limit per file + * responses: + * 201: + * description: Incident report submitted successfully + * 400: + * description: Bad request or file validation failed + * 401: + * description: Unauthorized + * 403: + * description: Forbidden (Guard access only) + */ +router.post('/', auth, guardOnly, incidentAttachmentUpload.array('attachments', 5), submitIncident); + +/** + * @swagger + * /api/v1/incidentreports/{id}: + * put: + * summary: Update an incident report (All roles) + * description: | + * Update an existing incident report. + * Guards can only update the description and add attachments; + * Employers/Admins can update the status, severity, employer comments, description, and add attachments. + * tags: [Incident Reports] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: ID of the incident report to update + * requestBody: + * required: true + * content: + * multipart/form-data: + * schema: + * type: object + * properties: + * description: + * type: string + * description: Updated detailed description + * status: + * type: string + * enum: [pending, resolved] + * description: Incident status (employer/admin only) + * severity: + * type: string + * enum: [low, medium, high, critical] + * description: Incident severity (employer/admin only) + * employerComment: + * type: string + * description: Employer/Admin comment (employer/admin only) + * attachments: + * type: array + * items: + * type: string + * format: binary + * description: New attachment files to add + * responses: + * 200: + * description: Incident report updated successfully + * 400: + * description: Bad request or validation error + * 401: + * description: Unauthorized + * 403: + * description: Forbidden + * 404: + * description: Incident not found + */ +router.put('/:id', auth, allRoles, incidentAttachmentUpload.array('attachments', 5), updateIncident); + +/** + * @swagger + * /api/v1/incidentreports/{id}: + * get: + * summary: Get specific incident report details + * description: Employers/Admins can view any incident. Guards can only view their own incidents. + * tags: [Incident Reports] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: Incident Report ID + * responses: + * 200: + * description: Successfully retrieved incident details + * 401: + * description: Unauthorized + * 403: + * description: Forbidden + * 404: + * description: Incident not found + */ +router.get('/:id', auth, allRoles, getIncidentById); + +/** + * @swagger + * /api/v1/incidentreports: + * get: + * summary: Get incident report list + * description: | + * Supports filtering via Query parameters. + * Employers/Admins can filter by any parameter. + * Guards can only see their own incidents. + * tags: [Incident Reports] + * security: + * - bearerAuth: [] + * parameters: + * - in: query + * name: guardId + * schema: + * type: string + * description: Filter by specific Guard ID (employer/admin only) + * - in: query + * name: shiftId + * schema: + * type: string + * description: Filter by specific shift ID + * - in: query + * name: status + * schema: + * type: string + * enum: [pending, resolved] + * description: Filter by incident status + * - in: query + * name: severity + * schema: + * type: string + * enum: [low, medium, high, critical] + * description: Filter by incident severity + * responses: + * 200: + * description: Successfully retrieved incident list + * 401: + * description: Unauthorized + * 403: + * description: Forbidden + */ +router.get('/', auth, allRoles, getIncidents); + +/** + * @swagger + * /api/v1/incidentreports/{id}/status: + * patch: + * summary: Update incident status (Employer/Admin only) + * description: Mark the incident as resolved or pending + * tags: [Incident Reports] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: Incident Report ID + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - status + * properties: + * status: + * type: string + * enum: [pending, resolved] + * example: resolved + * responses: + * 200: + * description: Status updated successfully + * 400: + * description: Invalid status value + * 401: + * description: Unauthorized + * 403: + * description: Forbidden + * 404: + * description: Incident not found + */ +router.patch('/:id/status', auth, employerOrAdmin, markIncident); + +/** + * @swagger + * /api/v1/incidentreports/{id}/export: + * get: + * summary: Export incident report as PDF + * description: | + * Export incident report as PDF. + * Employers/Admins can export any incident. + * Guards can only export their own incidents. + * tags: [Incident Reports] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: string + * description: Incident Report ID + * responses: + * 200: + * description: Successfully exported PDF file stream + * content: + * application/pdf: + * schema: + * type: string + * format: binary + * 401: + * description: Unauthorized + * 403: + * description: Forbidden + * 404: + * description: Incident not found + */ +router.get('/:id/export', auth, allRoles, exportIncident); + +export default router; \ No newline at end of file diff --git a/app-backend/src/routes/index.js b/app-backend/src/routes/index.js index 7dae01a30..6f2f9e28a 100644 --- a/app-backend/src/routes/index.js +++ b/app-backend/src/routes/index.js @@ -15,6 +15,8 @@ import notificationRoutes from './notification.routes.js' import payrollRoutes from './payroll.routes.js'; import documentRoutes from './document.routes.js'; +import incidentReportRoutes from "./incidentreport.routes.js"; + const router = express.Router(); router.use('/documents', documentRoutes); router.use('/health', healthRoutes); @@ -30,5 +32,6 @@ router.use('/attendance', shiftAttendanceRoutes); router.use("/incidents", incidentRoutes); router.use('/notifications', notificationRoutes); router.use('/payroll', payrollRoutes); +router.use('/incidentreports', incidentReportRoutes); export default router; \ No newline at end of file From 93553626d8f4063c25e26cc8ef6d2fc3ef91c918 Mon Sep 17 00:00:00 2001 From: yajuusan <3141249582@qq.com> Date: Mon, 27 Apr 2026 19:42:06 +1000 Subject: [PATCH 2/2] update package-lock.json --- app-backend/package-lock.json | 304 +++++++++++++++++++++++++++++----- 1 file changed, 267 insertions(+), 37 deletions(-) diff --git a/app-backend/package-lock.json b/app-backend/package-lock.json index 30712b4b2..b18b5c74d 100644 --- a/app-backend/package-lock.json +++ b/app-backend/package-lock.json @@ -22,6 +22,7 @@ "morgan": "^1.10.1", "multer": "^2.0.2", "nodemailer": "^7.0.5", + "pdfkit": "^0.15.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1" }, @@ -2655,6 +2656,15 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@swc/helpers": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz", + "integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2951,7 +2961,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3097,7 +3106,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -3517,6 +3525,26 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -3613,6 +3641,24 @@ "node": ">=8" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, "node_modules/browserslist": { "version": "4.25.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", @@ -3701,7 +3747,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -3895,6 +3940,15 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -4103,6 +4157,12 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -4189,6 +4249,38 @@ } } }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4210,7 +4302,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -4228,7 +4319,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -4282,6 +4372,12 @@ "wrappy": "1" } }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -4478,6 +4574,26 @@ "node": ">= 0.4" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -5103,11 +5219,27 @@ "dev": true, "license": "ISC" }, + "node_modules/fontkit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.9.0.tgz", + "integrity": "sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.3.13", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "deep-equal": "^2.0.5", + "dfa": "^1.2.0", + "restructure": "^2.0.1", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.3.1", + "unicode-trie": "^2.0.0" + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -5248,7 +5380,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5440,7 +5571,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5463,7 +5593,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -5504,7 +5633,6 @@ "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" @@ -5685,7 +5813,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5705,11 +5832,26 @@ "node": ">= 0.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-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -5754,7 +5896,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -5783,7 +5924,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5800,7 +5940,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5847,7 +5986,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5942,7 +6080,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5978,7 +6115,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6001,7 +6137,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6020,7 +6155,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6033,7 +6167,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -6062,7 +6195,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6079,7 +6211,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6113,7 +6244,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6142,7 +6272,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6159,7 +6288,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -6878,6 +7006,13 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jpeg-exif": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", + "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7047,6 +7182,25 @@ "node": ">= 0.8.0" } }, + "node_modules/linebreak": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", + "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", + "license": "MIT", + "dependencies": { + "base64-js": "0.0.8", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/linebreak/node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -7695,11 +7849,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7709,7 +7878,6 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7910,6 +8078,12 @@ "node": ">=6" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7996,6 +8170,19 @@ "node": ">=16" } }, + "node_modules/pdfkit": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.15.2.tgz", + "integrity": "sha512-s3GjpdBFSCaeDSX/v73MI5UsPqH1kjKut2AXCgxQ5OH10lPVOu5q5vLAG0OCpz/EYqKsTSw1WHpENqMvp43RKg==", + "license": "MIT", + "dependencies": { + "crypto-js": "^4.2.0", + "fontkit": "^1.8.1", + "jpeg-exif": "^1.1.4", + "linebreak": "^1.0.2", + "png-js": "^1.0.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -8095,11 +8282,18 @@ "node": ">=8" } }, + "node_modules/png-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.1.0.tgz", + "integrity": "sha512-PM/uYGzGdNSzqeOgly68+6wKQDL1SY0a/N+OEa/+br6LnHWOAJB0Npiamnodfq3jd2LS/i2fMeOKSAILjA+m5Q==", + "dependencies": { + "browserify-zlib": "^0.2.0" + } + }, "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==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8339,7 +8533,6 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -8481,6 +8674,12 @@ "node": ">=10" } }, + "node_modules/restructure": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz", + "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg==", + "license": "MIT" + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -8558,7 +8757,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8631,7 +8829,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -8649,7 +8846,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -8893,7 +9089,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9210,6 +9405,12 @@ "node": ">=8" } }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -9297,6 +9498,12 @@ "node": ">=4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9485,6 +9692,16 @@ "node": ">=4" } }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", @@ -9495,6 +9712,22 @@ "node": ">=4" } }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -9636,7 +9869,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -9684,7 +9916,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -9703,7 +9934,6 @@ "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7",