diff --git a/Jenkinsfile b/Jenkinsfile index 5860086..bd1379a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -31,6 +31,22 @@ pipeline { } } + stage('Run Tests') { + steps { + nodejs(nodeJSInstallationName: 'Node23') { + sh ''' + export NODE_ENV=test + yarn test + ''' + } + } + post { + always { + junit 'test-results.xml' + } + } + } + stage('Deploy via SSH') { steps { sshPublisher(publishers: [ diff --git a/babel.config.cjs b/babel.config.cjs new file mode 100644 index 0000000..4520044 --- /dev/null +++ b/babel.config.cjs @@ -0,0 +1,4 @@ +module.exports = { + presets: [['@babel/preset-env', { targets: { node: 'current' } }]], + plugins: ['transform-import-meta'], +}; diff --git a/config.json b/config.json index 1368e6d..78462b0 100644 --- a/config.json +++ b/config.json @@ -48,6 +48,54 @@ }, "otpExpiryMins": 0.5 }, + "test": { + "server": { + "port": 8788, + "logLevel": "error" + }, + "auth": { + "enabled": false, + "keycloak": { + "url": "http://localhost:8080", + "realm": "test", + "clientId": "test-client" + }, + "requiredRoles": [] + }, + "app": { + "urlClient": "http://localhost:3000", + "urlElectronClient": "http://localhost:5780", + "urlApi": "http://localhost:8788/api", + "devAuthClient": "http://localhost:3500" + }, + "database": { + "mongo": { + "url": "mongodb://127.0.0.1:27017/farmcontrol-test", + "link": "127.0.0.1:27017" + }, + "redis": { + "host": "localhost", + "port": 6379, + "password": "", + "cacheTtl": 30 + }, + "nats": { + "host": "localhost", + "port": 4222 + } + }, + "storage": { + "fileStorage": "./test-uploads", + "ceph": { + "accessKeyId": "minioadmin", + "secretAccessKey": "minioadmin123", + "endpoint": "http://127.0.0.1:9000", + "region": "us-east-1", + "filesBucket": "farmcontrol-test" + } + }, + "otpExpiryMins": 0.5 + }, "production": { "server": { "port": 8080, diff --git a/jest.config.cjs b/jest.config.cjs new file mode 100644 index 0000000..1651eda --- /dev/null +++ b/jest.config.cjs @@ -0,0 +1,22 @@ +module.exports = { + testEnvironment: 'node', + transform: {}, + moduleFileExtensions: ['js', 'json', 'jsx', 'node'], + testMatch: ['**/__tests__/**/*.js', '**/?(*.)+(spec|test).js'], + verbose: true, + reporters: [ + 'default', + [ + 'jest-junit', + { + outputDirectory: '.', + outputName: 'test-results.xml', + suiteName: 'farmcontrol-api-tests', + classNameTemplate: '{classname}', + titleTemplate: '{title}', + ancestorSeparator: ' › ', + usePathForSuiteName: 'true', + }, + ], + ], +}; diff --git a/package.json b/package.json index 7731727..0f59c62 100644 --- a/package.json +++ b/package.json @@ -41,20 +41,26 @@ "@babel/plugin-proposal-object-rest-spread": "^7.20.7", "@babel/preset-env": "^7.28.5", "@babel/register": "^7.28.3", + "@jest/globals": "^30.2.0", + "babel-jest": "^30.2.0", + "babel-plugin-transform-import-meta": "^2.3.3", "concurrently": "^9.2.1", "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.4", + "jest": "^30.2.0", + "jest-junit": "^16.0.0", "prettier": "^3.6.2", "sequelize-cli": "^6.6.3", - "standard": "^17.1.2" + "standard": "^17.1.2", + "supertest": "^7.1.4" }, "scripts": { "syncModelsWithWS": "node fcdev.js", "watch:schemas": "nodemon --config nodemon.schemas.json", "dev": "concurrently --names \"API,SCHEMAS\" --prefix-colors \"cyan,yellow\" \"nodemon --exec babel-node --experimental-specifier-resolution=node src/index.js\" \"nodemon --config nodemon.schemas.json\"", "dev:api": "nodemon --exec babel-node --experimental-specifier-resolution=node src/index.js", - "test": "echo \"Error: no test specified\" && exit 1", + "test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js", "seed": "node src/mongo/seedData.js", "clear": "node src/mongo/clearDbs.js" }, diff --git a/src/__tests__/users.api.test.js b/src/__tests__/users.api.test.js new file mode 100644 index 0000000..eb65fd9 --- /dev/null +++ b/src/__tests__/users.api.test.js @@ -0,0 +1,68 @@ +import { jest } from '@jest/globals'; +import request from 'supertest'; + +// Mock Keycloak and Auth +jest.unstable_mockModule('../keycloak.js', () => ({ + keycloak: { + middleware: () => (req, res, next) => next(), + protect: () => (req, res, next) => next(), + }, + isAuthenticated: (req, res, next) => next(), + expressSession: (req, res, next) => next(), +})); + +// Mock database connections and initializations in index.js +jest.unstable_mockModule('../database/mongo.js', () => ({ + dbConnect: jest.fn(), +})); +jest.unstable_mockModule('../database/nats.js', () => ({ + natsServer: { connect: jest.fn() }, +})); +jest.unstable_mockModule('../database/ceph.js', () => ({ + initializeBuckets: jest.fn(), + uploadFile: jest.fn(), + downloadFile: jest.fn(), + deleteFile: jest.fn(), + fileExists: jest.fn(), + listFiles: jest.fn(), + getFileMetadata: jest.fn(), + getPresignedUrl: jest.fn(), + BUCKETS: { FILES: 'test-bucket' }, +})); + +// Mock the service handlers to avoid database calls +jest.unstable_mockModule('../services/management/users.js', () => ({ + listUsersRouteHandler: jest.fn((req, res) => res.send([{ id: '1', name: 'Mock User' }])), + listUsersByPropertiesRouteHandler: jest.fn(), + getUserRouteHandler: jest.fn((req, res) => res.send({ id: req.params.id, name: 'Mock User' })), + editUserRouteHandler: jest.fn(), + getUserStatsRouteHandler: jest.fn(), + getUserHistoryRouteHandler: jest.fn(), +})); + +const { default: app } = await import('../index.js'); +const { listUsersRouteHandler, getUserRouteHandler } = await import( + '../services/management/users.js' +); + +describe('Users API Endpoints', () => { + describe('GET /users', () => { + it('should return a list of users', async () => { + const response = await request(app).get('/users'); + + expect(response.status).toBe(200); + expect(response.body).toEqual([{ id: '1', name: 'Mock User' }]); + expect(listUsersRouteHandler).toHaveBeenCalled(); + }); + }); + + describe('GET /users/:id', () => { + it('should return a single user', async () => { + const response = await request(app).get('/users/123'); + + expect(response.status).toBe(200); + expect(response.body).toEqual({ id: '123', name: 'Mock User' }); + expect(getUserRouteHandler).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/database/__tests__/database.test.js b/src/database/__tests__/database.test.js new file mode 100644 index 0000000..e357b20 --- /dev/null +++ b/src/database/__tests__/database.test.js @@ -0,0 +1,163 @@ +import { jest } from '@jest/globals'; + +// Mock src/database/utils.js (where generateId lives) +jest.unstable_mockModule('../utils.js', () => ({ + generateId: jest.fn(() => () => 'test-id'), +})); + +// Mock src/utils.js (where most database.js helpers live) +jest.unstable_mockModule('../../utils.js', () => ({ + deleteAuditLog: jest.fn(), + distributeDelete: jest.fn(), + expandObjectIds: jest.fn((obj) => obj), + modelHasRef: jest.fn(() => false), + getFieldsByRef: jest.fn(() => []), + getQueryToCacheKey: jest.fn(({ model, id }) => `${model}:${id}`), + editAuditLog: jest.fn(), + distributeUpdate: jest.fn(), + newAuditLog: jest.fn(), + distributeNew: jest.fn(), + distributeChildUpdate: jest.fn(), + distributeChildDelete: jest.fn(), + distributeChildNew: jest.fn(), + distributeStats: jest.fn(), +})); + +jest.unstable_mockModule('../redis.js', () => ({ + redisServer: { + getKey: jest.fn(), + setKey: jest.fn(), + deleteKey: jest.fn(), + getKeysByPattern: jest.fn(() => []), // Return empty array to avoid iterable error + }, +})); + +jest.unstable_mockModule('../../services/misc/model.js', () => ({ + getAllModels: jest.fn(() => []), +})); + +jest.unstable_mockModule('../schemas/management/auditlog.schema.js', () => ({ + auditLogModel: { + find: jest.fn(), + create: jest.fn(), + }, +})); + +// Mock fileModel specifically as it's imported by database.js +jest.unstable_mockModule('../schemas/management/file.schema.js', () => ({ + fileModel: { + findById: jest.fn(), + }, +})); + +// Now import the database utilities +const { listObjects, getObject, newObject, editObject, deleteObject } = await import( + '../database.js' +); + +describe('Database Utilities (CRUD)', () => { + let mockModel; + + beforeEach(() => { + mockModel = { + modelName: 'TestModel', + find: jest.fn().mockReturnThis(), + findById: jest.fn().mockReturnThis(), + findByIdAndUpdate: jest.fn().mockReturnThis(), + findByIdAndDelete: jest.fn().mockReturnThis(), + create: jest.fn(), + sort: jest.fn().mockReturnThis(), + skip: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + populate: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + lean: jest.fn().mockReturnThis(), + exec: jest.fn(), + }; + jest.clearAllMocks(); + }); + + describe('listObjects', () => { + it('should return a list of objects', async () => { + const mockData = [{ _id: '1', name: 'Test' }]; + mockModel.lean.mockResolvedValue(mockData); + + const result = await listObjects({ model: mockModel }); + + expect(mockModel.find).toHaveBeenCalled(); + expect(result).toEqual(mockData); + }); + + it('should handle pagination', async () => { + await listObjects({ model: mockModel, page: 2, limit: 10 }); + expect(mockModel.skip).toHaveBeenCalledWith(10); + expect(mockModel.limit).toHaveBeenCalledWith(10); + }); + }); + + describe('getObject', () => { + it('should return a single object by ID', async () => { + const mockData = { _id: '123', name: 'Test' }; + mockModel.lean.mockResolvedValue(mockData); + + const result = await getObject({ model: mockModel, id: '123' }); + + expect(mockModel.findById).toHaveBeenCalledWith('123'); + expect(result).toEqual(mockData); + }); + + it('should return 404 if object not found', async () => { + mockModel.lean.mockResolvedValue(null); + + const result = await getObject({ model: mockModel, id: '123' }); + + expect(result).toEqual({ error: 'Object not found.', code: 404 }); + }); + }); + + describe('newObject', () => { + it('should create a new object', async () => { + const newData = { name: 'New' }; + const createdData = { _id: '456', ...newData }; + mockModel.create.mockResolvedValue({ + toObject: () => createdData, + _id: '456', + }); + + const result = await newObject({ model: mockModel, newData }); + + expect(mockModel.create).toHaveBeenCalledWith(newData); + expect(result).toEqual(createdData); + }); + }); + + describe('editObject', () => { + it('should update an existing object', async () => { + const id = '123'; + const updateData = { name: 'Updated' }; + const previousData = { _id: id, name: 'Old' }; + + mockModel.lean.mockResolvedValue(previousData); + + const result = await editObject({ model: mockModel, id, updateData }); + + expect(mockModel.findByIdAndUpdate).toHaveBeenCalledWith(id, updateData); + expect(result).toEqual({ ...previousData, ...updateData }); + }); + }); + + describe('deleteObject', () => { + it('should delete an object', async () => { + const id = '123'; + const mockData = { _id: id, name: 'To be deleted' }; + mockModel.findByIdAndDelete.mockResolvedValue({ + toObject: () => mockData, + }); + + const result = await deleteObject({ model: mockModel, id }); + + expect(mockModel.findByIdAndDelete).toHaveBeenCalledWith(id); + expect(result).toEqual({ deleted: true, object: mockData }); + }); + }); +}); diff --git a/src/index.js b/src/index.js index f6edc79..ba1b7ff 100644 --- a/src/index.js +++ b/src/index.js @@ -150,4 +150,8 @@ app.use('/salesorders', salesOrderRoutes); app.use('/notes', noteRoutes); // Start the application -initializeApp(); +if (process.env.NODE_ENV !== 'test') { + initializeApp(); +} + +export default app; diff --git a/src/services/finance/__tests__/invoices.test.js b/src/services/finance/__tests__/invoices.test.js new file mode 100644 index 0000000..576b5ad --- /dev/null +++ b/src/services/finance/__tests__/invoices.test.js @@ -0,0 +1,154 @@ +import { jest } from '@jest/globals'; + +// Mock dependencies +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), + checkStates: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/finance/invoice.schema.js', () => ({ + invoiceModel: { modelName: 'Invoice' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/orderitem.schema.js', () => ({ + orderItemModel: { modelName: 'OrderItem' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/shipment.schema.js', () => ({ + shipmentModel: { modelName: 'Shipment' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +// Import handlers after mocking +const { + listInvoicesRouteHandler, + getInvoiceRouteHandler, + newInvoiceRouteHandler, + editInvoiceRouteHandler, + deleteInvoiceRouteHandler, + postInvoiceRouteHandler, +} = await import('../invoices.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject, checkStates } = await import( + '../../../database/database.js' +); +const { invoiceModel } = await import('../../../database/schemas/finance/invoice.schema.js'); + +describe('Invoice Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listInvoicesRouteHandler', () => { + it('should list invoices', async () => { + const mockResult = [{ _id: '1', invoiceNumber: 'INV-001' }]; + listObjects.mockResolvedValue(mockResult); + + await listInvoicesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('getInvoiceRouteHandler', () => { + it('should get an invoice by ID', async () => { + req.params.id = '123'; + const mockResult = { _id: '123', invoiceNumber: 'INV-001' }; + getObject.mockResolvedValue(mockResult); + + await getInvoiceRouteHandler(req, res); + + expect(getObject).toHaveBeenCalledWith(expect.objectContaining({ id: '123' })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newInvoiceRouteHandler', () => { + it('should create a new invoice with order items and shipments', async () => { + req.body = { order: 'order123', orderType: 'sales' }; + + // Mock listObjects for orderItems and shipments + listObjects.mockResolvedValueOnce([{ _id: 'oi1', totalAmount: 100, invoicedAmount: 0 }]); // orderItems + listObjects.mockResolvedValueOnce([{ _id: 's1', amount: 20, invoicedAmount: 0 }]); // shipments + + const mockInvoice = { _id: 'inv456' }; + newObject.mockResolvedValue(mockInvoice); + + await newInvoiceRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockInvoice); + }); + }); + + describe('postInvoiceRouteHandler', () => { + it('should post a draft invoice and update order items/shipments', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + + checkStates.mockResolvedValue(true); + + const mockInvoice = { + _id: '507f1f77bcf86cd799439011', + invoiceOrderItems: [{ orderItem: { _id: 'oi1' }, invoiceAmount: 50, invoiceQuantity: 1 }], + invoiceShipments: [{ shipment: { _id: 's1' }, invoiceAmount: 10 }], + }; + getObject.mockResolvedValueOnce(mockInvoice); + + // Mock getObject for individual orderItems and shipments + getObject.mockResolvedValueOnce({ _id: 'oi1', invoicedAmount: 0, invoicedQuantity: 0 }); + getObject.mockResolvedValueOnce({ _id: 's1', invoicedAmount: 0 }); + + editObject.mockResolvedValue({ _id: '507f1f77bcf86cd799439011', state: { type: 'sent' } }); + + await postInvoiceRouteHandler(req, res); + + expect(checkStates).toHaveBeenCalledWith(expect.objectContaining({ states: ['draft'] })); + expect(editObject).toHaveBeenCalled(); // Should be called for items, shipments, and the invoice itself + expect(res.send).toHaveBeenCalled(); + }); + + it('should fail if invoice is not in draft state', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + checkStates.mockResolvedValue(false); + + await postInvoiceRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.send).toHaveBeenCalledWith( + expect.objectContaining({ error: 'Invoice is not in draft state.' }) + ); + }); + }); +}); diff --git a/src/services/finance/__tests__/payments.test.js b/src/services/finance/__tests__/payments.test.js new file mode 100644 index 0000000..891bd24 --- /dev/null +++ b/src/services/finance/__tests__/payments.test.js @@ -0,0 +1,124 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), + checkStates: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/finance/payment.schema.js', () => ({ + paymentModel: { modelName: 'Payment' }, +})); + +jest.unstable_mockModule('../../../database/schemas/finance/invoice.schema.js', () => ({ + invoiceModel: { modelName: 'Invoice' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listPaymentsRouteHandler, + getPaymentRouteHandler, + newPaymentRouteHandler, + postPaymentRouteHandler, +} = await import('../payments.js'); + +const { listObjects, getObject, editObject, newObject, checkStates } = await import( + '../../../database/database.js' +); +const { paymentModel } = await import('../../../database/schemas/finance/payment.schema.js'); +const { invoiceModel } = await import('../../../database/schemas/finance/invoice.schema.js'); + +describe('Payment Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listPaymentsRouteHandler', () => { + it('should list payments', async () => { + const mockResult = [{ _id: '1', amount: 100 }]; + listObjects.mockResolvedValue(mockResult); + + await listPaymentsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newPaymentRouteHandler', () => { + it('should create a new payment with invoice data', async () => { + req.body = { invoice: 'inv123', amount: 100 }; + const mockInvoice = { _id: 'inv123', vendor: { _id: 'v1' }, client: { _id: 'c1' } }; + getObject.mockResolvedValueOnce(mockInvoice); + const mockPayment = { _id: 'pay456', ...req.body }; + newObject.mockResolvedValue(mockPayment); + + await newPaymentRouteHandler(req, res); + + expect(getObject).toHaveBeenCalledWith(expect.objectContaining({ id: 'inv123' })); + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockPayment); + }); + }); + + describe('postPaymentRouteHandler', () => { + it('should post a draft payment', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + checkStates.mockResolvedValue(true); + + const mockPayment = { _id: '507f1f77bcf86cd799439011', invoice: 'inv123' }; + getObject.mockResolvedValueOnce(mockPayment); + getObject.mockResolvedValueOnce({ _id: 'inv123' }); + editObject.mockResolvedValue({ _id: '507f1f77bcf86cd799439011', state: { type: 'posted' } }); + + await postPaymentRouteHandler(req, res); + + expect(checkStates).toHaveBeenCalledWith(expect.objectContaining({ states: ['draft'] })); + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalled(); + }); + + it('should fail if payment is not in draft state', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + checkStates.mockResolvedValue(false); + + await postPaymentRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.send).toHaveBeenCalledWith( + expect.objectContaining({ error: 'Payment is not in draft state.' }) + ); + }); + }); +}); + diff --git a/src/services/inventory/__tests__/filamentstocks.test.js b/src/services/inventory/__tests__/filamentstocks.test.js new file mode 100644 index 0000000..b3731a9 --- /dev/null +++ b/src/services/inventory/__tests__/filamentstocks.test.js @@ -0,0 +1,86 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/filamentstock.schema.js', () => ({ + filamentStockModel: { modelName: 'FilamentStock' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listFilamentStocksRouteHandler, + getFilamentStockRouteHandler, + newFilamentStockRouteHandler, +} = await import('../filamentstocks.js'); + +const { listObjects, getObject, newObject } = await import('../../../database/database.js'); +const { filamentStockModel } = await import( + '../../../database/schemas/inventory/filamentstock.schema.js' +); + +describe('Filament Stock Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listFilamentStocksRouteHandler', () => { + it('should list filament stocks', async () => { + const mockResult = [{ _id: '1', currentWeight: 500 }]; + listObjects.mockResolvedValue(mockResult); + + await listFilamentStocksRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: filamentStockModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newFilamentStockRouteHandler', () => { + it('should create a new filament stock', async () => { + req.body = { filament: 'filament123', currentWeight: 1000 }; + const mockStock = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockStock); + + await newFilamentStockRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockStock); + }); + }); +}); + diff --git a/src/services/inventory/__tests__/orderitems.test.js b/src/services/inventory/__tests__/orderitems.test.js new file mode 100644 index 0000000..d3bf1c6 --- /dev/null +++ b/src/services/inventory/__tests__/orderitems.test.js @@ -0,0 +1,100 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/orderitem.schema.js', () => ({ + orderItemModel: { modelName: 'OrderItem' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listOrderItemsRouteHandler, + getOrderItemRouteHandler, + newOrderItemRouteHandler, + editOrderItemRouteHandler, + deleteOrderItemRouteHandler, +} = await import('../orderitems.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { orderItemModel } = await import('../../../database/schemas/inventory/orderitem.schema.js'); + +describe('Order Item Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listOrderItemsRouteHandler', () => { + it('should list order items', async () => { + const mockResult = [{ _id: '1', name: 'Order Item 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listOrderItemsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: orderItemModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newOrderItemRouteHandler', () => { + it('should create a new order item', async () => { + req.body = { name: 'New Item', quantity: 10, order: 'order123' }; + const mockItem = { _id: '456', ...req.body, state: { type: 'draft' } }; + newObject.mockResolvedValue(mockItem); + + await newOrderItemRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockItem); + }); + }); + + describe('editOrderItemRouteHandler', () => { + it('should update an order item', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { quantity: 20 }; + const mockResult = { _id: '507f1f77bcf86cd799439011', quantity: 20 }; + editObject.mockResolvedValue(mockResult); + + await editOrderItemRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/inventory/__tests__/partstocks.test.js b/src/services/inventory/__tests__/partstocks.test.js new file mode 100644 index 0000000..7a98e7e --- /dev/null +++ b/src/services/inventory/__tests__/partstocks.test.js @@ -0,0 +1,88 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/partstock.schema.js', () => ({ + partStockModel: { modelName: 'PartStock' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listPartStocksRouteHandler, + getPartStockRouteHandler, + newPartStockRouteHandler, + editPartStockRouteHandler, + deletePartStockRouteHandler, +} = await import('../partstocks.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { partStockModel } = await import('../../../database/schemas/inventory/partstock.schema.js'); + +describe('Part Stock Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listPartStocksRouteHandler', () => { + it('should list part stocks', async () => { + const mockResult = [{ _id: '1', currentQuantity: 100 }]; + listObjects.mockResolvedValue(mockResult); + + await listPartStocksRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: partStockModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newPartStockRouteHandler', () => { + it('should create a new part stock', async () => { + req.body = { part: 'part123', currentQuantity: 50 }; + const mockStock = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockStock); + + await newPartStockRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockStock); + }); + }); +}); + diff --git a/src/services/inventory/__tests__/purchaseorders.test.js b/src/services/inventory/__tests__/purchaseorders.test.js new file mode 100644 index 0000000..14b6d97 --- /dev/null +++ b/src/services/inventory/__tests__/purchaseorders.test.js @@ -0,0 +1,122 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), + checkStates: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/purchaseorder.schema.js', () => ({ + purchaseOrderModel: { modelName: 'PurchaseOrder' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/orderitem.schema.js', () => ({ + orderItemModel: { modelName: 'OrderItem' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/shipment.schema.js', () => ({ + shipmentModel: { modelName: 'Shipment' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listPurchaseOrdersRouteHandler, + getPurchaseOrderRouteHandler, + newPurchaseOrderRouteHandler, + postPurchaseOrderRouteHandler, +} = await import('../purchaseorders.js'); + +const { listObjects, getObject, editObject, newObject, checkStates } = await import( + '../../../database/database.js' +); +const { purchaseOrderModel } = await import( + '../../../database/schemas/inventory/purchaseorder.schema.js' +); + +describe('Purchase Order Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listPurchaseOrdersRouteHandler', () => { + it('should list purchase orders', async () => { + const mockResult = [{ _id: '1', reference: 'PO-001' }]; + listObjects.mockResolvedValue(mockResult); + + await listPurchaseOrdersRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('postPurchaseOrderRouteHandler', () => { + it('should post a draft purchase order and update items/shipments', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + + checkStates.mockResolvedValue(true); + + listObjects.mockResolvedValueOnce([ + { _id: 'oi1', state: { type: 'draft' }, shipment: 's1', _reference: 'ITEM1' }, + ]); + listObjects.mockResolvedValueOnce([ + { _id: 's1', state: { type: 'draft' }, _reference: 'SHIP1' }, + ]); + + editObject.mockResolvedValue({ _id: '507f1f77bcf86cd799439011', state: { type: 'sent' } }); + + await postPurchaseOrderRouteHandler(req, res); + + expect(checkStates).toHaveBeenCalledWith(expect.objectContaining({ states: ['draft'] })); + expect(editObject).toHaveBeenCalledTimes(3); + expect(res.send).toHaveBeenCalled(); + }); + + it('should fail if an order item is not in draft state', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + checkStates.mockResolvedValue(true); + + listObjects.mockResolvedValueOnce([ + { _id: 'oi1', state: { type: 'ordered' }, _reference: 'ITEM1' }, + ]); + listObjects.mockResolvedValueOnce([]); + + await postPurchaseOrderRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.send).toHaveBeenCalledWith( + expect.objectContaining({ error: 'Order item ITEM1 not in draft state.' }) + ); + }); + }); +}); diff --git a/src/services/inventory/__tests__/shipments.test.js b/src/services/inventory/__tests__/shipments.test.js new file mode 100644 index 0000000..cad08c6 --- /dev/null +++ b/src/services/inventory/__tests__/shipments.test.js @@ -0,0 +1,111 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), + checkStates: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/shipment.schema.js', () => ({ + shipmentModel: { modelName: 'Shipment' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/orderitem.schema.js', () => ({ + orderItemModel: { modelName: 'OrderItem' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listShipmentsRouteHandler, + getShipmentRouteHandler, + newShipmentRouteHandler, + shipShipmentRouteHandler, +} = await import('../shipments.js'); + +const { listObjects, getObject, editObject, newObject, checkStates } = await import( + '../../../database/database.js' +); +const { shipmentModel } = await import('../../../database/schemas/inventory/shipment.schema.js'); +const { orderItemModel } = await import('../../../database/schemas/inventory/orderitem.schema.js'); + +describe('Shipment Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listShipmentsRouteHandler', () => { + it('should list shipments', async () => { + const mockResult = [{ _id: '1', trackingNumber: 'TRACK123' }]; + listObjects.mockResolvedValue(mockResult); + + await listShipmentsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: shipmentModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newShipmentRouteHandler', () => { + it('should create a new shipment', async () => { + req.body = { order: 'order123', trackingNumber: 'TRACK456' }; + const mockShipment = { _id: '456', ...req.body, state: { type: 'draft' } }; + newObject.mockResolvedValue(mockShipment); + + await newShipmentRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockShipment); + }); + }); + + describe('shipShipmentRouteHandler', () => { + it('should ship a planned shipment and update order items', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + checkStates.mockResolvedValue(true); + + listObjects.mockResolvedValue([ + { _id: 'oi1', state: { type: 'ordered' } }, + { _id: 'oi2', state: { type: 'ordered' } }, + ]); + + editObject.mockResolvedValue({ _id: '507f1f77bcf86cd799439011', state: { type: 'shipped' } }); + + await shipShipmentRouteHandler(req, res); + + expect(checkStates).toHaveBeenCalledWith(expect.objectContaining({ states: ['planned'] })); + expect(editObject).toHaveBeenCalledTimes(3); // 2 order items + 1 shipment + expect(res.send).toHaveBeenCalled(); + }); + }); +}); + diff --git a/src/services/inventory/__tests__/stockaudits.test.js b/src/services/inventory/__tests__/stockaudits.test.js new file mode 100644 index 0000000..80689f3 --- /dev/null +++ b/src/services/inventory/__tests__/stockaudits.test.js @@ -0,0 +1,91 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../utils.js', () => ({ + getAuditLogs: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/database.js', () => ({ + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/stockaudit.schema.js', () => ({ + stockAuditModel: { + modelName: 'StockAudit', + aggregate: jest.fn(), + findOne: jest.fn(), + create: jest.fn(), + }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listStockAuditsRouteHandler, + getStockAuditRouteHandler, + newStockAuditRouteHandler, +} = await import('../stockaudits.js'); + +const { getAuditLogs } = await import('../../../utils.js'); +const { stockAuditModel } = await import('../../../database/schemas/inventory/stockaudit.schema.js'); + +describe('Stock Audit Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listStockAuditsRouteHandler', () => { + it('should list stock audits', async () => { + const mockResult = [{ _id: '1', type: 'full' }]; + stockAuditModel.aggregate.mockResolvedValue(mockResult); + + await listStockAuditsRouteHandler(req, res); + + expect(stockAuditModel.aggregate).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('getStockAuditRouteHandler', () => { + it('should get a stock audit by ID with audit logs', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockAudit = { _id: '507f1f77bcf86cd799439011', type: 'full', _doc: {} }; + stockAuditModel.findOne.mockReturnValue({ + populate: jest.fn().mockReturnValue({ + populate: jest.fn().mockReturnValue({ + populate: jest.fn().mockResolvedValue(mockAudit), + }), + }), + }); + getAuditLogs.mockResolvedValue([]); + + await getStockAuditRouteHandler(req, res); + + expect(getAuditLogs).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalled(); + }); + }); +}); + diff --git a/src/services/inventory/__tests__/stockevents.test.js b/src/services/inventory/__tests__/stockevents.test.js new file mode 100644 index 0000000..e500895 --- /dev/null +++ b/src/services/inventory/__tests__/stockevents.test.js @@ -0,0 +1,84 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/stockevent.schema.js', () => ({ + stockEventModel: { modelName: 'StockEvent' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listStockEventsRouteHandler, + getStockEventRouteHandler, + newStockEventRouteHandler, +} = await import('../stockevents.js'); + +const { listObjects, getObject, newObject } = await import('../../../database/database.js'); +const { stockEventModel } = await import('../../../database/schemas/inventory/stockevent.schema.js'); + +describe('Stock Event Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listStockEventsRouteHandler', () => { + it('should list stock events', async () => { + const mockResult = [{ _id: '1', type: 'adjustment' }]; + listObjects.mockResolvedValue(mockResult); + + await listStockEventsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: stockEventModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newStockEventRouteHandler', () => { + it('should create a new stock event', async () => { + req.body = { type: 'adjustment', value: 10 }; + const mockEvent = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockEvent); + + await newStockEventRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockEvent); + }); + }); +}); + diff --git a/src/services/management/__tests__/auditlogs.test.js b/src/services/management/__tests__/auditlogs.test.js new file mode 100644 index 0000000..49d3fd6 --- /dev/null +++ b/src/services/management/__tests__/auditlogs.test.js @@ -0,0 +1,87 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/auditlog.schema.js', () => ({ + auditLogModel: { + modelName: 'AuditLog', + find: jest.fn(), + findOne: jest.fn(), + }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { listAuditLogsRouteHandler, getAuditLogRouteHandler } = await import('../auditlogs.js'); + +const { auditLogModel } = await import('../../../database/schemas/management/auditlog.schema.js'); + +describe('Audit Log Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listAuditLogsRouteHandler', () => { + it('should list audit logs', async () => { + const mockResult = [ + { _id: '1', operation: 'edit', parent: 'parent123', _doc: { parent: 'parent123' } }, + ]; + auditLogModel.find.mockReturnValue({ + sort: jest.fn().mockReturnThis(), + skip: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + populate: jest.fn().mockResolvedValue(mockResult), + }); + + await listAuditLogsRouteHandler(req, res); + + expect(auditLogModel.find).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalled(); + }); + }); + + describe('getAuditLogRouteHandler', () => { + it('should get an audit log by ID', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockLog = { _id: '507f1f77bcf86cd799439011', operation: 'edit' }; + auditLogModel.findOne.mockReturnValue({ + populate: jest.fn().mockReturnValue({ + populate: jest.fn().mockReturnValue({ + populate: jest.fn().mockResolvedValue(mockLog), + }), + }), + }); + + await getAuditLogRouteHandler(req, res); + + expect(auditLogModel.findOne).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockLog); + }); + }); +}); + diff --git a/src/services/management/__tests__/courier.test.js b/src/services/management/__tests__/courier.test.js new file mode 100644 index 0000000..6c39530 --- /dev/null +++ b/src/services/management/__tests__/courier.test.js @@ -0,0 +1,84 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/courier.schema.js', () => ({ + courierModel: { modelName: 'Courier' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listCouriersRouteHandler, + getCourierRouteHandler, + newCourierRouteHandler, + editCourierRouteHandler, +} = await import('../courier.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { courierModel } = await import('../../../database/schemas/management/courier.schema.js'); + +describe('Courier Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listCouriersRouteHandler', () => { + it('should list couriers', async () => { + const mockResult = [{ _id: '1', name: 'FedEx' }]; + listObjects.mockResolvedValue(mockResult); + + await listCouriersRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: courierModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newCourierRouteHandler', () => { + it('should create a new courier', async () => { + req.body = { name: 'DHL', email: 'contact@dhl.com' }; + const mockCourier = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockCourier); + + await newCourierRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockCourier); + }); + }); +}); + diff --git a/src/services/management/__tests__/courierservice.test.js b/src/services/management/__tests__/courierservice.test.js new file mode 100644 index 0000000..aadfb83 --- /dev/null +++ b/src/services/management/__tests__/courierservice.test.js @@ -0,0 +1,88 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/courierservice.schema.js', () => ({ + courierServiceModel: { modelName: 'CourierService' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listCourierServicesRouteHandler, + getCourierServiceRouteHandler, + newCourierServiceRouteHandler, + editCourierServiceRouteHandler, +} = await import('../courierservice.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { courierServiceModel } = await import( + '../../../database/schemas/management/courierservice.schema.js' +); + +describe('Courier Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listCourierServicesRouteHandler', () => { + it('should list courier services', async () => { + const mockResult = [{ _id: '1', name: 'Express' }]; + listObjects.mockResolvedValue(mockResult); + + await listCourierServicesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: courierServiceModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newCourierServiceRouteHandler', () => { + it('should create a new courier service', async () => { + req.body = { courier: 'courier123', name: 'Express Delivery' }; + const mockService = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockService); + + await newCourierServiceRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockService); + }); + }); +}); + diff --git a/src/services/management/__tests__/documentjobs.test.js b/src/services/management/__tests__/documentjobs.test.js new file mode 100644 index 0000000..9d8203f --- /dev/null +++ b/src/services/management/__tests__/documentjobs.test.js @@ -0,0 +1,85 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/documentjob.schema.js', () => ({ + documentJobModel: { modelName: 'DocumentJob' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listDocumentJobsRouteHandler, + getDocumentJobRouteHandler, + newDocumentJobRouteHandler, +} = await import('../documentjobs.js'); + +const { listObjects, getObject, newObject } = await import('../../../database/database.js'); +const { documentJobModel } = await import( + '../../../database/schemas/management/documentjob.schema.js' +); + +describe('Document Job Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listDocumentJobsRouteHandler', () => { + it('should list document jobs', async () => { + const mockResult = [{ _id: '1', state: { type: 'pending' } }]; + listObjects.mockResolvedValue(mockResult); + + await listDocumentJobsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: documentJobModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newDocumentJobRouteHandler', () => { + it('should create a new document job', async () => { + req.body = { documentTemplate: 'template123', documentPrinter: 'printer123' }; + const mockJob = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockJob); + + await newDocumentJobRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockJob); + }); + }); +}); + diff --git a/src/services/management/__tests__/documentprinters.test.js b/src/services/management/__tests__/documentprinters.test.js new file mode 100644 index 0000000..b9e8040 --- /dev/null +++ b/src/services/management/__tests__/documentprinters.test.js @@ -0,0 +1,85 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/documentprinter.schema.js', () => ({ + documentPrinterModel: { modelName: 'DocumentPrinter' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listDocumentPrintersRouteHandler, + getDocumentPrinterRouteHandler, + newDocumentPrinterRouteHandler, +} = await import('../documentprinters.js'); + +const { listObjects, getObject, newObject } = await import('../../../database/database.js'); +const { documentPrinterModel } = await import( + '../../../database/schemas/management/documentprinter.schema.js' +); + +describe('Document Printer Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listDocumentPrintersRouteHandler', () => { + it('should list document printers', async () => { + const mockResult = [{ _id: '1', name: 'HP LaserJet' }]; + listObjects.mockResolvedValue(mockResult); + + await listDocumentPrintersRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: documentPrinterModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newDocumentPrinterRouteHandler', () => { + it('should create a new document printer', async () => { + req.body = { name: 'Canon Printer', host: 'host123' }; + const mockPrinter = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockPrinter); + + await newDocumentPrinterRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockPrinter); + }); + }); +}); + diff --git a/src/services/management/__tests__/documentsizes.test.js b/src/services/management/__tests__/documentsizes.test.js new file mode 100644 index 0000000..d40eea8 --- /dev/null +++ b/src/services/management/__tests__/documentsizes.test.js @@ -0,0 +1,88 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/documentsize.schema.js', () => ({ + documentSizeModel: { modelName: 'DocumentSize' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listDocumentSizesRouteHandler, + getDocumentSizeRouteHandler, + newDocumentSizeRouteHandler, + editDocumentSizeRouteHandler, +} = await import('../documentsizes.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { documentSizeModel } = await import( + '../../../database/schemas/management/documentsize.schema.js' +); + +describe('Document Size Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listDocumentSizesRouteHandler', () => { + it('should list document sizes', async () => { + const mockResult = [{ _id: '1', name: 'A4', width: 210, height: 297 }]; + listObjects.mockResolvedValue(mockResult); + + await listDocumentSizesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: documentSizeModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newDocumentSizeRouteHandler', () => { + it('should create a new document size', async () => { + req.body = { name: 'Letter', width: 216, height: 279 }; + const mockSize = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockSize); + + await newDocumentSizeRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockSize); + }); + }); +}); + diff --git a/src/services/management/__tests__/documenttemplates.test.js b/src/services/management/__tests__/documenttemplates.test.js new file mode 100644 index 0000000..2f0cf0e --- /dev/null +++ b/src/services/management/__tests__/documenttemplates.test.js @@ -0,0 +1,88 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/documenttemplate.schema.js', () => ({ + documentTemplateModel: { modelName: 'DocumentTemplate' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listDocumentTemplatesRouteHandler, + getDocumentTemplateRouteHandler, + newDocumentTemplateRouteHandler, + editDocumentTemplateRouteHandler, +} = await import('../documenttemplates.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { documentTemplateModel } = await import( + '../../../database/schemas/management/documenttemplate.schema.js' +); + +describe('Document Template Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listDocumentTemplatesRouteHandler', () => { + it('should list document templates', async () => { + const mockResult = [{ _id: '1', name: 'Invoice Template' }]; + listObjects.mockResolvedValue(mockResult); + + await listDocumentTemplatesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: documentTemplateModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newDocumentTemplateRouteHandler', () => { + it('should create a new document template', async () => { + req.body = { name: 'New Template', documentSize: 'size123' }; + const mockTemplate = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockTemplate); + + await newDocumentTemplateRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockTemplate); + }); + }); +}); + diff --git a/src/services/management/__tests__/filaments.test.js b/src/services/management/__tests__/filaments.test.js new file mode 100644 index 0000000..ba7b8d9 --- /dev/null +++ b/src/services/management/__tests__/filaments.test.js @@ -0,0 +1,98 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/filament.schema.js', () => ({ + filamentModel: { modelName: 'Filament' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listFilamentsRouteHandler, + getFilamentRouteHandler, + newFilamentRouteHandler, + editFilamentRouteHandler, +} = await import('../filaments.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { filamentModel } = await import('../../../database/schemas/management/filament.schema.js'); + +describe('Filament Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listFilamentsRouteHandler', () => { + it('should list filaments', async () => { + const mockResult = [{ _id: '1', name: 'Filament 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listFilamentsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: filamentModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newFilamentRouteHandler', () => { + it('should create a new filament', async () => { + req.body = { name: 'PLA Red', diameter: 1.75, cost: 20 }; + const mockFilament = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockFilament); + + await newFilamentRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockFilament); + }); + }); + + describe('editFilamentRouteHandler', () => { + it('should update a filament', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Filament', cost: 25 }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editFilamentRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/management/__tests__/files.test.js b/src/services/management/__tests__/files.test.js new file mode 100644 index 0000000..d03ea51 --- /dev/null +++ b/src/services/management/__tests__/files.test.js @@ -0,0 +1,123 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + flushFile: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/file.schema.js', () => ({ + fileModel: { modelName: 'File' }, +})); + +jest.unstable_mockModule('../../../database/ceph.js', () => ({ + uploadFile: jest.fn(), + downloadFile: jest.fn(), + deleteFile: jest.fn(), + BUCKETS: { FILES: 'test-bucket' }, +})); + +jest.unstable_mockModule('../../../utils.js', () => ({ + getFileMeta: jest.fn(), +})); + +jest.unstable_mockModule('multer', () => { + const mockMemoryStorage = jest.fn(); + const mockMulter = jest.fn(() => ({ + single: jest.fn(), + })); + mockMulter.memoryStorage = mockMemoryStorage; + return { + default: mockMulter, + memoryStorage: mockMemoryStorage, + }; +}); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listFilesRouteHandler, + getFileRouteHandler, + editFileRouteHandler, + flushFileRouteHandler, +} = await import('../files.js'); + +const { listObjects, getObject, editObject, flushFile } = await import( + '../../../database/database.js' +); +const { fileModel } = await import('../../../database/schemas/management/file.schema.js'); + +describe('File Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listFilesRouteHandler', () => { + it('should list files', async () => { + const mockResult = [{ _id: '1', name: 'file.pdf' }]; + listObjects.mockResolvedValue(mockResult); + + await listFilesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: fileModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('getFileRouteHandler', () => { + it('should get a file by ID', async () => { + req.params.id = '123'; + const mockFile = { _id: '123', name: 'test.pdf' }; + getObject.mockResolvedValue(mockFile); + + await getFileRouteHandler(req, res); + + expect(getObject).toHaveBeenCalledWith(expect.objectContaining({ id: '123' })); + expect(res.send).toHaveBeenCalledWith(mockFile); + }); + }); + + describe('flushFileRouteHandler', () => { + it('should flush/delete a file', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockResult = { success: true }; + flushFile.mockResolvedValue(mockResult); + + await flushFileRouteHandler(req, res); + + expect(flushFile).toHaveBeenCalledWith( + expect.objectContaining({ id: '507f1f77bcf86cd799439011' }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/management/__tests__/hosts.test.js b/src/services/management/__tests__/hosts.test.js new file mode 100644 index 0000000..d9e4156 --- /dev/null +++ b/src/services/management/__tests__/hosts.test.js @@ -0,0 +1,99 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/host.schema.js', () => ({ + hostModel: { modelName: 'Host' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listHostsRouteHandler, + getHostRouteHandler, + newHostRouteHandler, + editHostRouteHandler, + deleteHostRouteHandler, +} = await import('../hosts.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { hostModel } = await import('../../../database/schemas/management/host.schema.js'); + +describe('Host Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listHostsRouteHandler', () => { + it('should list hosts', async () => { + const mockResult = [{ _id: '1', name: 'Host 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listHostsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: hostModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newHostRouteHandler', () => { + it('should create a new host', async () => { + req.body = { name: 'New Host', address: '192.168.1.100' }; + const mockHost = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockHost); + + await newHostRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockHost); + }); + }); + + describe('editHostRouteHandler', () => { + it('should update a host', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Host' }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editHostRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/management/__tests__/materials.test.js b/src/services/management/__tests__/materials.test.js new file mode 100644 index 0000000..452bfc2 --- /dev/null +++ b/src/services/management/__tests__/materials.test.js @@ -0,0 +1,75 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/schemas/management/material.schema.js', () => ({ + materialModel: { + modelName: 'Material', + aggregate: jest.fn(), + findOne: jest.fn(), + updateOne: jest.fn(), + create: jest.fn(), + }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listMaterialsRouteHandler, + getMaterialRouteHandler, + newMaterialRouteHandler, +} = await import('../materials.js'); + +const { materialModel } = await import('../../../database/schemas/management/material.schema.js'); + +describe('Material Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listMaterialsRouteHandler', () => { + it('should list materials', async () => { + const mockResult = [{ name: 'PLA' }]; + materialModel.aggregate.mockResolvedValue(mockResult); + + await listMaterialsRouteHandler(req, res); + + expect(materialModel.aggregate).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('getMaterialRouteHandler', () => { + it('should get a material by ID', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockMaterial = { _id: '507f1f77bcf86cd799439011', name: 'PLA' }; + materialModel.findOne.mockResolvedValue(mockMaterial); + + await getMaterialRouteHandler(req, res); + + expect(materialModel.findOne).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockMaterial); + }); + }); +}); + diff --git a/src/services/management/__tests__/notetypes.test.js b/src/services/management/__tests__/notetypes.test.js new file mode 100644 index 0000000..19f27c3 --- /dev/null +++ b/src/services/management/__tests__/notetypes.test.js @@ -0,0 +1,86 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/notetype.schema.js', () => ({ + noteTypeModel: { modelName: 'NoteType' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listNoteTypesRouteHandler, + getNoteTypeRouteHandler, + newNoteTypeRouteHandler, + editNoteTypeRouteHandler, +} = await import('../notetypes.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { noteTypeModel } = await import('../../../database/schemas/management/notetype.schema.js'); + +describe('Note Type Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listNoteTypesRouteHandler', () => { + it('should list note types', async () => { + const mockResult = [{ _id: '1', name: 'General' }]; + listObjects.mockResolvedValue(mockResult); + + await listNoteTypesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: noteTypeModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newNoteTypeRouteHandler', () => { + it('should create a new note type', async () => { + req.body = { name: 'Important', color: '#ff0000' }; + const mockNoteType = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockNoteType); + + await newNoteTypeRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockNoteType); + }); + }); +}); + diff --git a/src/services/management/__tests__/parts.test.js b/src/services/management/__tests__/parts.test.js new file mode 100644 index 0000000..7718822 --- /dev/null +++ b/src/services/management/__tests__/parts.test.js @@ -0,0 +1,124 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/part.schema.js', () => ({ + partModel: { modelName: 'Part' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listPartsRouteHandler, + getPartRouteHandler, + newPartRouteHandler, + editPartRouteHandler, + deletePartRouteHandler, +} = await import('../parts.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { partModel } = await import('../../../database/schemas/management/part.schema.js'); + +describe('Part Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listPartsRouteHandler', () => { + it('should list parts', async () => { + const mockResult = [{ _id: '1', name: 'Part 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listPartsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: partModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('getPartRouteHandler', () => { + it('should get a part by ID', async () => { + req.params.id = '123'; + const mockPart = { _id: '123', name: 'Test Part' }; + getObject.mockResolvedValue(mockPart); + + await getPartRouteHandler(req, res); + + expect(getObject).toHaveBeenCalledWith(expect.objectContaining({ id: '123' })); + expect(res.send).toHaveBeenCalledWith(mockPart); + }); + }); + + describe('newPartRouteHandler', () => { + it('should create a new part', async () => { + req.body = { name: 'New Part', price: 10.99 }; + const mockPart = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockPart); + + await newPartRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockPart); + }); + }); + + describe('editPartRouteHandler', () => { + it('should update a part', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Part', price: 15.99 }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editPartRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('deletePartRouteHandler', () => { + it('should delete a part', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockResult = { _id: '507f1f77bcf86cd799439011' }; + deleteObject.mockResolvedValue(mockResult); + + await deletePartRouteHandler(req, res); + + expect(deleteObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); diff --git a/src/services/management/__tests__/products.test.js b/src/services/management/__tests__/products.test.js new file mode 100644 index 0000000..db4cbec --- /dev/null +++ b/src/services/management/__tests__/products.test.js @@ -0,0 +1,98 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/product.schema.js', () => ({ + productModel: { modelName: 'Product' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listProductsRouteHandler, + getProductRouteHandler, + newProductRouteHandler, + editProductRouteHandler, + deleteProductRouteHandler, +} = await import('../products.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { productModel } = await import('../../../database/schemas/management/product.schema.js'); + +describe('Product Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listProductsRouteHandler', () => { + it('should list products', async () => { + const mockResult = [{ _id: '1', name: 'Product 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listProductsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: productModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newProductRouteHandler', () => { + it('should create a new product', async () => { + req.body = { name: 'New Product', parts: [] }; + const mockProduct = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockProduct); + + await newProductRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockProduct); + }); + }); + + describe('editProductRouteHandler', () => { + it('should update a product', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Product' }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editProductRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); diff --git a/src/services/management/__tests__/taxrates.test.js b/src/services/management/__tests__/taxrates.test.js new file mode 100644 index 0000000..20aeef7 --- /dev/null +++ b/src/services/management/__tests__/taxrates.test.js @@ -0,0 +1,98 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/taxrate.schema.js', () => ({ + taxRateModel: { modelName: 'TaxRate' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listTaxRatesRouteHandler, + getTaxRateRouteHandler, + newTaxRateRouteHandler, + editTaxRateRouteHandler, +} = await import('../taxrates.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { taxRateModel } = await import('../../../database/schemas/management/taxrate.schema.js'); + +describe('Tax Rate Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listTaxRatesRouteHandler', () => { + it('should list tax rates', async () => { + const mockResult = [{ _id: '1', name: 'GST', rate: 10 }]; + listObjects.mockResolvedValue(mockResult); + + await listTaxRatesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: taxRateModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newTaxRateRouteHandler', () => { + it('should create a new tax rate', async () => { + req.body = { name: 'VAT', rate: 20, rateType: 'percentage' }; + const mockTaxRate = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockTaxRate); + + await newTaxRateRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockTaxRate); + }); + }); + + describe('editTaxRateRouteHandler', () => { + it('should update a tax rate', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { rate: 15 }; + const mockResult = { _id: '507f1f77bcf86cd799439011', rate: 15 }; + editObject.mockResolvedValue(mockResult); + + await editTaxRateRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/management/__tests__/taxrecords.test.js b/src/services/management/__tests__/taxrecords.test.js new file mode 100644 index 0000000..01bb738 --- /dev/null +++ b/src/services/management/__tests__/taxrecords.test.js @@ -0,0 +1,86 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/taxrecord.schema.js', () => ({ + taxRecordModel: { modelName: 'TaxRecord' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listTaxRecordsRouteHandler, + getTaxRecordRouteHandler, + newTaxRecordRouteHandler, + editTaxRecordRouteHandler, +} = await import('../taxrecords.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { taxRecordModel } = await import('../../../database/schemas/management/taxrecord.schema.js'); + +describe('Tax Record Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listTaxRecordsRouteHandler', () => { + it('should list tax records', async () => { + const mockResult = [{ _id: '1', amount: 100, taxAmount: 10 }]; + listObjects.mockResolvedValue(mockResult); + + await listTaxRecordsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: taxRecordModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newTaxRecordRouteHandler', () => { + it('should create a new tax record', async () => { + req.body = { taxRate: 'rate123', amount: 100, taxAmount: 10 }; + const mockRecord = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockRecord); + + await newTaxRecordRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockRecord); + }); + }); +}); + diff --git a/src/services/management/__tests__/users.test.js b/src/services/management/__tests__/users.test.js new file mode 100644 index 0000000..eef3167 --- /dev/null +++ b/src/services/management/__tests__/users.test.js @@ -0,0 +1,126 @@ +import { jest } from '@jest/globals'; + +// Mock dependencies MUST be done before importing the module under test +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + listObjectsByProperties: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/user.schema.js', () => ({ + userModel: { findOne: jest.fn() }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +// Now import the modules +const { listUsersRouteHandler, getUserRouteHandler, editUserRouteHandler } = await import( + '../users.js' +); +const { listObjects, getObject, editObject } = await import('../../../database/database.js'); +const { userModel } = await import('../../../database/schemas/management/user.schema.js'); + +describe('User Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listUsersRouteHandler', () => { + it('should list users and send response', async () => { + const mockResult = [{ id: '1', name: 'User 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listUsersRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ + model: userModel, + }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + + it('should handle errors from listObjects', async () => { + const mockError = { error: 'Database error', code: 500 }; + listObjects.mockResolvedValue(mockError); + + await listUsersRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(500); + expect(res.send).toHaveBeenCalledWith(mockError); + }); + }); + + describe('getUserRouteHandler', () => { + it('should get a user by id and send response', async () => { + req.params.id = '123'; + const mockUser = { id: '123', name: 'Test User' }; + getObject.mockResolvedValue(mockUser); + + await getUserRouteHandler(req, res); + + expect(getObject).toHaveBeenCalledWith( + expect.objectContaining({ + model: userModel, + id: '123', + }) + ); + expect(res.send).toHaveBeenCalledWith(mockUser); + }); + + it('should handle user not found', async () => { + req.params.id = 'invalid'; + const mockError = { error: 'Not found', code: 404 }; + getObject.mockResolvedValue(mockError); + + await getUserRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(404); + expect(res.send).toHaveBeenCalledWith(mockError); + }); + }); + + describe('editUserRouteHandler', () => { + it('should edit a user and send response', async () => { + req.params.id = '507f1f77bcf86cd799439011'; // valid mongodb id format + req.body = { name: 'New Name' }; + const mockResult = { id: '507f1f77bcf86cd799439011', name: 'New Name' }; + editObject.mockResolvedValue(mockResult); + + await editUserRouteHandler(req, res); + + expect(editObject).toHaveBeenCalledWith( + expect.objectContaining({ + model: userModel, + updateData: expect.objectContaining({ name: 'New Name' }), + }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); diff --git a/src/services/management/__tests__/vendors.test.js b/src/services/management/__tests__/vendors.test.js new file mode 100644 index 0000000..12388c4 --- /dev/null +++ b/src/services/management/__tests__/vendors.test.js @@ -0,0 +1,99 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/management/vendor.schema.js', () => ({ + vendorModel: { modelName: 'Vendor' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listVendorsRouteHandler, + getVendorRouteHandler, + newVendorRouteHandler, + editVendorRouteHandler, + deleteVendorRouteHandler, +} = await import('../vendors.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { vendorModel } = await import('../../../database/schemas/management/vendor.schema.js'); + +describe('Vendor Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listVendorsRouteHandler', () => { + it('should list vendors', async () => { + const mockResult = [{ _id: '1', name: 'Vendor 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listVendorsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: vendorModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newVendorRouteHandler', () => { + it('should create a new vendor', async () => { + req.body = { name: 'New Vendor', email: 'vendor@example.com' }; + const mockVendor = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockVendor); + + await newVendorRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockVendor); + }); + }); + + describe('editVendorRouteHandler', () => { + it('should update a vendor', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Vendor' }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editVendorRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/misc/__tests__/notes.test.js b/src/services/misc/__tests__/notes.test.js new file mode 100644 index 0000000..44de4e8 --- /dev/null +++ b/src/services/misc/__tests__/notes.test.js @@ -0,0 +1,85 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + recursivelyDeleteChildObjects: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/misc/note.schema.js', () => ({ + noteModel: { modelName: 'Note' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listNotesRouteHandler, + getNoteRouteHandler, + newNoteRouteHandler, + editNoteRouteHandler, +} = await import('../../misc/notes.js'); + +const { listObjects, getObject, editObject, newObject } = await import( + '../../../database/database.js' +); +const { noteModel } = await import('../../../database/schemas/misc/note.schema.js'); + +describe('Note Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listNotesRouteHandler', () => { + it('should list notes', async () => { + const mockResult = [{ _id: '1', content: 'Test note' }]; + listObjects.mockResolvedValue(mockResult); + + await listNotesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: noteModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newNoteRouteHandler', () => { + it('should create a new note', async () => { + req.body = { content: 'New note', noteType: 'type123' }; + const mockNote = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockNote); + + await newNoteRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockNote); + }); + }); +}); + diff --git a/src/services/production/__tests__/gcodefiles.test.js b/src/services/production/__tests__/gcodefiles.test.js new file mode 100644 index 0000000..d6053dc --- /dev/null +++ b/src/services/production/__tests__/gcodefiles.test.js @@ -0,0 +1,106 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/production/gcodefile.schema.js', () => ({ + gcodeFileModel: { + modelName: 'GCodeFile', + aggregate: jest.fn(), + }, +})); + +jest.unstable_mockModule('../../management/files.js', () => ({ + getFileContentRouteHandler: jest.fn(), +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listGCodeFilesRouteHandler, + getGCodeFileRouteHandler, + newGCodeFileRouteHandler, + editGCodeFileRouteHandler, + deleteGCodeFileRouteHandler, +} = await import('../gcodefiles.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { gcodeFileModel } = await import('../../../database/schemas/production/gcodefile.schema.js'); + +describe('GCodeFile Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listGCodeFilesRouteHandler', () => { + it('should list gcode files', async () => { + const mockResult = [{ _id: '1', name: 'file.gcode' }]; + listObjects.mockResolvedValue(mockResult); + + await listGCodeFilesRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith( + expect.objectContaining({ model: gcodeFileModel }) + ); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newGCodeFileRouteHandler', () => { + it('should create a new gcode file', async () => { + req.body = { name: 'newfile.gcode', file: 'file123' }; + const mockFile = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockFile); + + await newGCodeFileRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockFile); + }); + }); + + describe('editGCodeFileRouteHandler', () => { + it('should update a gcode file', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'updated.gcode' }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editGCodeFileRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/production/__tests__/jobs.test.js b/src/services/production/__tests__/jobs.test.js new file mode 100644 index 0000000..76c9490 --- /dev/null +++ b/src/services/production/__tests__/jobs.test.js @@ -0,0 +1,114 @@ +import { jest } from '@jest/globals'; + +// Mock dependencies +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/production/job.schema.js', () => ({ + jobModel: { modelName: 'Job' }, +})); + +jest.unstable_mockModule('../../../database/schemas/production/subjob.schema.js', () => ({ + subJobModel: { modelName: 'SubJob' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +// Import handlers after mocking +const { listJobsRouteHandler, getJobRouteHandler, newJobRouteHandler, deleteJobRouteHandler } = + await import('../jobs.js'); + +const { listObjects, getObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { jobModel } = await import('../../../database/schemas/production/job.schema.js'); +const { subJobModel } = await import('../../../database/schemas/production/subjob.schema.js'); + +describe('Job Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listJobsRouteHandler', () => { + it('should list jobs', async () => { + const mockResult = [{ _id: '1', name: 'Job 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listJobsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newJobRouteHandler', () => { + it('should create a new job and corresponding subjobs', async () => { + req.body = { + quantity: 2, + printers: ['p1', 'p2'], + gcodeFile: 'file123', + }; + + const mockJob = { _id: 'job123' }; + newObject.mockResolvedValueOnce(mockJob); // For Job + newObject.mockResolvedValue({ _id: 'subjob' }); // For SubJobs + + await newJobRouteHandler(req, res); + + expect(newObject).toHaveBeenCalledTimes(3); // 1 Job + 2 SubJobs + expect(res.send).toHaveBeenCalledWith(mockJob); + }); + + it('should handle errors during job creation', async () => { + req.body = { quantity: 1, printers: ['p1'] }; + newObject.mockResolvedValueOnce({ error: 'Failed', code: 500 }); + + await newJobRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(500); + expect(res.send).toHaveBeenCalledWith(expect.objectContaining({ error: 'Failed' })); + }); + }); + + describe('deleteJobRouteHandler', () => { + it('should delete a job', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockResult = { _id: '507f1f77bcf86cd799439011' }; + deleteObject.mockResolvedValue(mockResult); + + await deleteJobRouteHandler(req, res); + + expect(deleteObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); diff --git a/src/services/production/__tests__/printers.test.js b/src/services/production/__tests__/printers.test.js new file mode 100644 index 0000000..e74f860 --- /dev/null +++ b/src/services/production/__tests__/printers.test.js @@ -0,0 +1,99 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/production/printer.schema.js', () => ({ + printerModel: { modelName: 'Printer' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listPrintersRouteHandler, + getPrinterRouteHandler, + newPrinterRouteHandler, + editPrinterRouteHandler, + deletePrinterRouteHandler, +} = await import('../printers.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { printerModel } = await import('../../../database/schemas/production/printer.schema.js'); + +describe('Printer Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listPrintersRouteHandler', () => { + it('should list printers', async () => { + const mockResult = [{ _id: '1', name: 'Printer 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listPrintersRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: printerModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newPrinterRouteHandler', () => { + it('should create a new printer', async () => { + req.body = { name: 'New Printer', host: 'host123' }; + const mockPrinter = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockPrinter); + + await newPrinterRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockPrinter); + }); + }); + + describe('editPrinterRouteHandler', () => { + it('should update a printer', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Printer' }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editPrinterRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/production/__tests__/subjobs.test.js b/src/services/production/__tests__/subjobs.test.js new file mode 100644 index 0000000..ee7f366 --- /dev/null +++ b/src/services/production/__tests__/subjobs.test.js @@ -0,0 +1,74 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/production/subjob.schema.js', () => ({ + subJobModel: { modelName: 'SubJob' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { listSubJobsRouteHandler, getSubJobRouteHandler } = await import('../subjobs.js'); + +const { listObjects, getObject } = await import('../../../database/database.js'); +const { subJobModel } = await import('../../../database/schemas/production/subjob.schema.js'); + +describe('SubJob Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listSubJobsRouteHandler', () => { + it('should list sub jobs', async () => { + const mockResult = [{ _id: '1', number: 1 }]; + listObjects.mockResolvedValue(mockResult); + + await listSubJobsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: subJobModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('getSubJobRouteHandler', () => { + it('should get a sub job by ID', async () => { + req.params.id = '123'; + const mockSubJob = { _id: '123', number: 1 }; + getObject.mockResolvedValue(mockSubJob); + + await getSubJobRouteHandler(req, res); + + expect(getObject).toHaveBeenCalledWith(expect.objectContaining({ id: '123' })); + expect(res.send).toHaveBeenCalledWith(mockSubJob); + }); + }); +}); + diff --git a/src/services/sales/__tests__/clients.test.js b/src/services/sales/__tests__/clients.test.js new file mode 100644 index 0000000..9a3986c --- /dev/null +++ b/src/services/sales/__tests__/clients.test.js @@ -0,0 +1,112 @@ +import { jest } from '@jest/globals'; + +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/sales/client.schema.js', () => ({ + clientModel: { modelName: 'Client' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +const { + listClientsRouteHandler, + getClientRouteHandler, + newClientRouteHandler, + editClientRouteHandler, + deleteClientRouteHandler, +} = await import('../clients.js'); + +const { listObjects, getObject, editObject, newObject, deleteObject } = await import( + '../../../database/database.js' +); +const { clientModel } = await import('../../../database/schemas/sales/client.schema.js'); + +describe('Client Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listClientsRouteHandler', () => { + it('should list clients', async () => { + const mockResult = [{ _id: '1', name: 'Client 1' }]; + listObjects.mockResolvedValue(mockResult); + + await listClientsRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalledWith(expect.objectContaining({ model: clientModel })); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('newClientRouteHandler', () => { + it('should create a new client', async () => { + req.body = { name: 'New Client', email: 'client@example.com' }; + const mockClient = { _id: '456', ...req.body }; + newObject.mockResolvedValue(mockClient); + + await newClientRouteHandler(req, res); + + expect(newObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockClient); + }); + }); + + describe('editClientRouteHandler', () => { + it('should update a client', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + req.body = { name: 'Updated Client' }; + const mockResult = { _id: '507f1f77bcf86cd799439011', ...req.body }; + editObject.mockResolvedValue(mockResult); + + await editClientRouteHandler(req, res); + + expect(editObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('deleteClientRouteHandler', () => { + it('should delete a client', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + const mockResult = { _id: '507f1f77bcf86cd799439011' }; + deleteObject.mockResolvedValue(mockResult); + + await deleteClientRouteHandler(req, res); + + expect(deleteObject).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); +}); + diff --git a/src/services/sales/__tests__/salesorders.test.js b/src/services/sales/__tests__/salesorders.test.js new file mode 100644 index 0000000..f6a0339 --- /dev/null +++ b/src/services/sales/__tests__/salesorders.test.js @@ -0,0 +1,123 @@ +import { jest } from '@jest/globals'; + +// Mock dependencies +jest.unstable_mockModule('../../../database/database.js', () => ({ + listObjects: jest.fn(), + getObject: jest.fn(), + editObject: jest.fn(), + editObjects: jest.fn(), + newObject: jest.fn(), + deleteObject: jest.fn(), + listObjectsByProperties: jest.fn(), + getModelStats: jest.fn(), + getModelHistory: jest.fn(), + checkStates: jest.fn(), +})); + +jest.unstable_mockModule('../../../database/schemas/sales/salesorder.schema.js', () => ({ + salesOrderModel: { modelName: 'SalesOrder' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/orderitem.schema.js', () => ({ + orderItemModel: { modelName: 'OrderItem' }, +})); + +jest.unstable_mockModule('../../../database/schemas/inventory/shipment.schema.js', () => ({ + shipmentModel: { modelName: 'Shipment' }, +})); + +jest.unstable_mockModule('log4js', () => ({ + default: { + getLogger: () => ({ + level: 'info', + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + trace: jest.fn(), + }), + }, +})); + +// Import handlers after mocking +const { + listSalesOrdersRouteHandler, + getSalesOrderRouteHandler, + newSalesOrderRouteHandler, + postSalesOrderRouteHandler, +} = await import('../salesorders.js'); + +const { listObjects, getObject, editObject, newObject, checkStates } = await import( + '../../../database/database.js' +); +const { salesOrderModel } = await import('../../../database/schemas/sales/salesorder.schema.js'); + +describe('Sales Order Service Route Handlers', () => { + let req, res; + + beforeEach(() => { + req = { + params: {}, + query: {}, + body: {}, + user: { id: 'test-user-id' }, + }; + res = { + send: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + jest.clearAllMocks(); + }); + + describe('listSalesOrdersRouteHandler', () => { + it('should list sales orders', async () => { + const mockResult = [{ _id: '1', reference: 'SO-001' }]; + listObjects.mockResolvedValue(mockResult); + + await listSalesOrdersRouteHandler(req, res); + + expect(listObjects).toHaveBeenCalled(); + expect(res.send).toHaveBeenCalledWith(mockResult); + }); + }); + + describe('postSalesOrderRouteHandler', () => { + it('should post a draft sales order and update items/shipments', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + + checkStates.mockResolvedValue(true); + + // Mock listObjects for orderItems and shipments + listObjects.mockResolvedValueOnce([ + { _id: 'oi1', state: { type: 'draft' }, shipment: 's1', _reference: 'ITEM1' }, + ]); // orderItems + listObjects.mockResolvedValueOnce([ + { _id: 's1', state: { type: 'draft' }, _reference: 'SHIP1' }, + ]); // shipments + + editObject.mockResolvedValue({ _id: '507f1f77bcf86cd799439011', state: { type: 'sent' } }); + + await postSalesOrderRouteHandler(req, res); + + expect(checkStates).toHaveBeenCalledWith(expect.objectContaining({ states: ['draft'] })); + expect(editObject).toHaveBeenCalledTimes(3); // 1 OrderItem + 1 Shipment + 1 SalesOrder + expect(res.send).toHaveBeenCalled(); + }); + + it('should fail if an order item is not in draft state', async () => { + req.params.id = '507f1f77bcf86cd799439011'; + checkStates.mockResolvedValue(true); + + listObjects.mockResolvedValueOnce([ + { _id: 'oi1', state: { type: 'ordered' }, _reference: 'ITEM1' }, + ]); + listObjects.mockResolvedValueOnce([]); + + await postSalesOrderRouteHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(400); + expect(res.send).toHaveBeenCalledWith( + expect.objectContaining({ error: 'Order item ITEM1 not in draft state.' }) + ); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 0ef03f0..ef7b11f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -608,7 +608,7 @@ "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" chokidar "^3.6.0" -"@babel/code-frame@^7.27.1": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1": version "7.27.1" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz" integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== @@ -622,7 +622,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz" integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== -"@babel/core@^7.28.5": +"@babel/core@^7.23.9", "@babel/core@^7.27.4", "@babel/core@^7.28.5": version "7.28.5" resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz" integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== @@ -643,7 +643,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.28.5": +"@babel/generator@^7.27.5", "@babel/generator@^7.28.5": version "7.28.5" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz" integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== @@ -742,7 +742,7 @@ dependencies: "@babel/types" "^7.27.1" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0": 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== @@ -817,7 +817,7 @@ regenerator-runtime "^0.14.0" v8flags "^3.1.1" -"@babel/parser@^7.27.2", "@babel/parser@^7.28.5": +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.27.2", "@babel/parser@^7.28.5": version "7.28.5" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz" integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== @@ -887,6 +887,34 @@ resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz" integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-import-assertions@^7.27.1": version "7.27.1" resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz" @@ -894,13 +922,55 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-syntax-import-attributes@^7.27.1": +"@babel/plugin-syntax-import-attributes@^7.24.7", "@babel/plugin-syntax-import-attributes@^7.27.1": 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== dependencies: "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" @@ -908,6 +978,41 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz" @@ -1409,7 +1514,7 @@ pirates "^4.0.6" source-map-support "^0.5.16" -"@babel/template@^7.27.1", "@babel/template@^7.27.2": +"@babel/template@^7.25.9", "@babel/template@^7.27.1", "@babel/template@^7.27.2": version "7.27.2" resolved "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz" integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== @@ -1431,7 +1536,7 @@ "@babel/types" "^7.28.5" debug "^4.3.1" -"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.4.4": version "7.28.5" resolved "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz" integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== @@ -1439,6 +1544,33 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@emnapi/core@^1.4.3": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.1.tgz#3a79a02dbc84f45884a1806ebb98e5746bdfaac4" + integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791" + integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.8.0": version "4.9.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz" @@ -1576,6 +1708,242 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-30.2.0.tgz#c52fcd5b58fdd2e8eb66b2fd8ae56f2f64d05b28" + integrity sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + jest-message-util "30.2.0" + jest-util "30.2.0" + slash "^3.0.0" + +"@jest/core@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-30.2.0.tgz#813d59faa5abd5510964a8b3a7b17cc77b775275" + integrity sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ== + dependencies: + "@jest/console" "30.2.0" + "@jest/pattern" "30.0.1" + "@jest/reporters" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + ci-info "^4.2.0" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-changed-files "30.2.0" + jest-config "30.2.0" + jest-haste-map "30.2.0" + jest-message-util "30.2.0" + jest-regex-util "30.0.1" + jest-resolve "30.2.0" + jest-resolve-dependencies "30.2.0" + jest-runner "30.2.0" + jest-runtime "30.2.0" + jest-snapshot "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + jest-watcher "30.2.0" + micromatch "^4.0.8" + pretty-format "30.2.0" + slash "^3.0.0" + +"@jest/diff-sequences@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz#0ededeae4d071f5c8ffe3678d15f3a1be09156be" + integrity sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw== + +"@jest/environment@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-30.2.0.tgz#1e673cdb8b93ded707cf6631b8353011460831fa" + integrity sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g== + dependencies: + "@jest/fake-timers" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + jest-mock "30.2.0" + +"@jest/expect-utils@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.2.0.tgz#4f95413d4748454fdb17404bf1141827d15e6011" + integrity sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA== + dependencies: + "@jest/get-type" "30.1.0" + +"@jest/expect@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-30.2.0.tgz#9a5968499bb8add2bbb09136f69f7df5ddbf3185" + integrity sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA== + dependencies: + expect "30.2.0" + jest-snapshot "30.2.0" + +"@jest/fake-timers@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-30.2.0.tgz#0941ddc28a339b9819542495b5408622dc9e94ec" + integrity sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw== + dependencies: + "@jest/types" "30.2.0" + "@sinonjs/fake-timers" "^13.0.0" + "@types/node" "*" + jest-message-util "30.2.0" + jest-mock "30.2.0" + jest-util "30.2.0" + +"@jest/get-type@30.1.0": + version "30.1.0" + resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.1.0.tgz#4fcb4dc2ebcf0811be1c04fd1cb79c2dba431cbc" + integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA== + +"@jest/globals@30.2.0", "@jest/globals@^30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-30.2.0.tgz#2f4b696d5862664b89c4ee2e49ae24d2bb7e0988" + integrity sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw== + dependencies: + "@jest/environment" "30.2.0" + "@jest/expect" "30.2.0" + "@jest/types" "30.2.0" + jest-mock "30.2.0" + +"@jest/pattern@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/pattern/-/pattern-30.0.1.tgz#d5304147f49a052900b4b853dedb111d080e199f" + integrity sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA== + dependencies: + "@types/node" "*" + jest-regex-util "30.0.1" + +"@jest/reporters@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-30.2.0.tgz#a36b28fcbaf0c4595250b108e6f20e363348fd91" + integrity sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@jridgewell/trace-mapping" "^0.3.25" + "@types/node" "*" + chalk "^4.1.2" + collect-v8-coverage "^1.0.2" + exit-x "^0.2.2" + glob "^10.3.10" + graceful-fs "^4.2.11" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^5.0.0" + istanbul-reports "^3.1.3" + jest-message-util "30.2.0" + jest-util "30.2.0" + jest-worker "30.2.0" + slash "^3.0.0" + string-length "^4.0.2" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-30.0.5.tgz#7bdf69fc5a368a5abdb49fd91036c55225846473" + integrity sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA== + dependencies: + "@sinclair/typebox" "^0.34.0" + +"@jest/snapshot-utils@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz#387858eb90c2f98f67bff327435a532ac5309fbe" + integrity sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug== + dependencies: + "@jest/types" "30.2.0" + chalk "^4.1.2" + graceful-fs "^4.2.11" + natural-compare "^1.4.0" + +"@jest/source-map@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-30.0.1.tgz#305ebec50468f13e658b3d5c26f85107a5620aaa" + integrity sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.25" + callsites "^3.1.0" + graceful-fs "^4.2.11" + +"@jest/test-result@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-30.2.0.tgz#9c0124377fb7996cdffb86eda3dbc56eacab363d" + integrity sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg== + dependencies: + "@jest/console" "30.2.0" + "@jest/types" "30.2.0" + "@types/istanbul-lib-coverage" "^2.0.6" + collect-v8-coverage "^1.0.2" + +"@jest/test-sequencer@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz#bf0066bc72e176d58f5dfa7f212b6e7eee44f221" + integrity sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q== + dependencies: + "@jest/test-result" "30.2.0" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + slash "^3.0.0" + +"@jest/transform@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.2.0.tgz#54bef1a4510dcbd58d5d4de4fe2980a63077ef2a" + integrity sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA== + dependencies: + "@babel/core" "^7.27.4" + "@jest/types" "30.2.0" + "@jridgewell/trace-mapping" "^0.3.25" + babel-plugin-istanbul "^7.0.1" + chalk "^4.1.2" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + jest-regex-util "30.0.1" + jest-util "30.2.0" + micromatch "^4.0.8" + pirates "^4.0.7" + slash "^3.0.0" + write-file-atomic "^5.0.1" + +"@jest/types@30.2.0": + version "30.2.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.2.0.tgz#1c678a7924b8f59eafd4c77d56b6d0ba976d62b8" + integrity sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg== + dependencies: + "@jest/pattern" "30.0.1" + "@jest/schemas" "30.0.5" + "@types/istanbul-lib-coverage" "^2.0.6" + "@types/istanbul-reports" "^3.0.4" + "@types/node" "*" + "@types/yargs" "^17.0.33" + chalk "^4.1.2" + "@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": version "0.3.13" resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz" @@ -1602,7 +1970,7 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28": version "0.3.31" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz" integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== @@ -1617,6 +1985,15 @@ dependencies: sparse-bitfield "^3.0.3" +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + "@nats-io/nats-core@3.2.0": version "3.2.0" resolved "https://registry.npmjs.org/@nats-io/nats-core/-/nats-core-3.2.0.tgz" @@ -1651,6 +2028,11 @@ resolved "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== +"@noble/hashes@^1.1.5": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -1677,6 +2059,13 @@ resolved "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz" integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw== +"@paralleldrive/cuid2@^2.2.2": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz#3d62ea9e7be867d3fa94b9897fab5b0ae187d784" + integrity sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw== + dependencies: + "@noble/hashes" "^1.1.5" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" @@ -1719,6 +2108,25 @@ resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== +"@sinclair/typebox@^0.34.0": + version "0.34.45" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.45.tgz#6c0426b584c74d57625ed6b180ac59a62f139f7c" + integrity sha512-qJcFVfCa5jxBFSuv7S5WYbA8XdeCPmhnaVVfX/2Y6L8WYg8sk3XY2+6W0zH+3mq1Cz+YC7Ki66HfqX6IHAwnkg== + +"@sinonjs/commons@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^13.0.0": + version "13.0.5" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5" + integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw== + dependencies: + "@sinonjs/commons" "^3.0.1" + "@smithy/abort-controller@^4.2.5": version "4.2.5" resolved "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.5.tgz" @@ -2229,6 +2637,46 @@ resolved "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz" integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== +"@tybys/wasm-util@^0.10.0": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + "@types/debug@^4.1.8": version "4.1.12" resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz" @@ -2241,6 +2689,25 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.1", "@types/istanbul-lib-coverage@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" @@ -2263,6 +2730,11 @@ dependencies: undici-types "~7.16.0" +"@types/stack-utils@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + "@types/validator@^13.7.17": version "13.15.9" resolved "https://registry.npmjs.org/@types/validator/-/validator-13.15.9.tgz" @@ -2280,6 +2752,18 @@ dependencies: "@types/webidl-conversions" "*" +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.33": + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== + dependencies: + "@types/yargs-parser" "*" + "@types/yauzl@^2.9.1": version "2.10.3" resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz" @@ -2287,11 +2771,108 @@ dependencies: "@types/node" "*" -"@ungap/structured-clone@^1.2.0": +"@ungap/structured-clone@^1.2.0", "@ungap/structured-clone@^1.3.0": version "1.3.0" resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz#36fb318eebdd690f6da32ac5e0499a76fa881935" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + +"@unrs/resolver-binding-win32-x64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== + abbrev@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz" @@ -2330,6 +2911,13 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -2347,12 +2935,17 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + ansi-styles@^6.1.0: version "6.2.3" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz" integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== -anymatch@~3.1.2: +anymatch@^3.1.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2365,6 +2958,13 @@ append-field@^1.0.0: resolved "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz" integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw== +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" @@ -2475,6 +3075,11 @@ arraybuffer.prototype.slice@^1.0.4: get-intrinsic "^1.2.6" is-array-buffer "^3.0.4" +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + asn1.js@^5.3.0: version "5.4.1" resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz" @@ -2523,6 +3128,37 @@ axios@^1.12.0, axios@^1.13.2: form-data "^4.0.4" proxy-from-env "^1.1.0" +babel-jest@30.2.0, babel-jest@^30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.2.0.tgz#fd44a1ec9552be35ead881f7381faa7d8f3b95ac" + integrity sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw== + dependencies: + "@jest/transform" "30.2.0" + "@types/babel__core" "^7.20.5" + babel-plugin-istanbul "^7.0.1" + babel-preset-jest "30.2.0" + chalk "^4.1.2" + graceful-fs "^4.2.11" + slash "^3.0.0" + +babel-plugin-istanbul@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz#d8b518c8ea199364cf84ccc82de89740236daf92" + integrity sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-instrument "^6.0.2" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz#94c250d36b43f95900f3a219241e0f4648191ce2" + integrity sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA== + dependencies: + "@types/babel__core" "^7.20.5" + babel-plugin-polyfill-corejs2@^0.4.14: version "0.4.14" resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz" @@ -2547,6 +3183,43 @@ babel-plugin-polyfill-regenerator@^0.6.5: dependencies: "@babel/helper-define-polyfill-provider" "^0.6.5" +babel-plugin-transform-import-meta@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.3.3.tgz#863de841f7df37e2bf39a057572a24e4f65f3c51" + integrity sha512-bbh30qz1m6ZU1ybJoNOhA2zaDvmeXMnGNBMVMDOJ1Fni4+wMBoy/j7MTRVmqAUCIcy54/rEnr9VEBsfcgbpm3Q== + dependencies: + "@babel/template" "^7.25.9" + tslib "^2.8.1" + +babel-preset-current-node-syntax@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz#04717843e561347781d6d7f69c81e6bcc3ed11ce" + integrity sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ== + dependencies: + babel-plugin-jest-hoist "30.2.0" + babel-preset-current-node-syntax "^1.2.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -2620,7 +3293,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@~3.0.2: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -2643,6 +3316,13 @@ browserslist@^4.24.0, browserslist@^4.26.3: node-releases "^2.0.27" update-browserslist-db "^1.1.4" +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + bson@^6.10.4: version "6.10.4" resolved "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz" @@ -2708,11 +3388,21 @@ call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: call-bind-apply-helpers "^1.0.2" get-intrinsic "^1.3.0" -callsites@^3.0.0: +callsites@^3.0.0, callsites@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-lite@^1.0.30001754: version "1.0.30001755" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz" @@ -2723,7 +3413,7 @@ canonical-json@^0.2.0: resolved "https://registry.npmjs.org/canonical-json/-/canonical-json-0.2.0.tgz" integrity sha512-xeH/NgtNA7kIuKSxopJVdXqCKWyDB79aqxQRQ9FV02fvmqW7DSnjoFyzAUrBpfbwjU6lwTYOLc+HM6KupbsfVQ== -chalk@4.1.2, chalk@^4.0.0: +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2731,6 +3421,11 @@ chalk@4.1.2, chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + chokidar@^3.5.2, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" @@ -2759,6 +3454,16 @@ chromedriver@latest: proxy-from-env "^1.1.0" tcp-port-used "^1.0.2" +ci-info@^4.2.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.1.tgz#355ad571920810b5623e11d40232f443f16f1daa" + integrity sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA== + +cjs-module-lexer@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz#bff23b0609cc9afa428bd35f1918f7d03b448562" + integrity sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ== + cliui@^7.0.2: version "7.0.4" resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" @@ -2796,6 +3501,16 @@ cluster-key-slot@1.1.2: resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" @@ -2835,6 +3550,11 @@ compare-versions@^6.1.0: resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz" integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== +component-emitter@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" + integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" @@ -2902,6 +3622,11 @@ cookie@0.7.2, cookie@^0.7.1: resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz" integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== +cookiejar@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" + integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== + core-js-compat@^3.43.0: version "3.46.0" resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz" @@ -2922,7 +3647,7 @@ cors@^2.8.5: object-assign "^4" vary "^1" -cross-spawn@^7.0.2, cross-spawn@^7.0.6: +cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -2975,7 +3700,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@4.x, debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.1: +debug@4, debug@4.x, debug@^4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.0, debug@^4.4.1: version "4.4.3" resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -2996,11 +3721,21 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +dedent@^1.6.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.1.tgz#364661eea3d73f3faba7089214420ec2f8f13e15" + integrity sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" @@ -3038,6 +3773,19 @@ depd@2.0.0, depd@^2.0.0, depd@~2.0.0: resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +detect-newline@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +dezalgo@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" + integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== + dependencies: + asap "^2.0.0" + wrappy "1" + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" @@ -3116,6 +3864,11 @@ elliptic@^6.6.1: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -3285,6 +4038,11 @@ escape-html@^1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" @@ -3568,7 +4326,7 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -esprima@^4.0.1: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -3602,11 +4360,43 @@ etag@^1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + exifr@^7.1.3: version "7.1.3" resolved "https://registry.npmjs.org/exifr/-/exifr-7.1.3.tgz" integrity sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw== +exit-x@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exit-x/-/exit-x-0.2.2.tgz#1f9052de3b8d99a696b10dad5bced9bdd5c3aa64" + integrity sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ== + +expect@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-30.2.0.tgz#d4013bed267013c14bc1199cec8aa57cee9b5869" + integrity sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw== + dependencies: + "@jest/expect-utils" "30.2.0" + "@jest/get-type" "30.1.0" + jest-matcher-utils "30.2.0" + jest-message-util "30.2.0" + jest-mock "30.2.0" + jest-util "30.2.0" + express-session@^1.18.2: version "1.18.2" resolved "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz" @@ -3675,7 +4465,7 @@ fast-diff@^1.1.2: resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -3685,6 +4475,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + fast-xml-parser@5.2.5: version "5.2.5" resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz" @@ -3699,6 +4494,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz" @@ -3755,6 +4557,14 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" @@ -3816,6 +4626,15 @@ form-data@^4.0.4: hasown "^2.0.2" mime-types "^2.1.12" +formidable@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-3.5.4.tgz#ac9a593b951e829b3298f21aa9a2243932f32ed9" + integrity sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug== + dependencies: + "@paralleldrive/cuid2" "^2.2.2" + dezalgo "^1.0.4" + once "^1.4.0" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" @@ -3855,7 +4674,7 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: +fsevents@^2.3.3, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -3913,6 +4732,11 @@ get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@ hasown "^2.0.2" math-intrinsics "^1.1.0" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-proto@^1.0.0, get-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" @@ -3933,6 +4757,11 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz" @@ -3965,6 +4794,18 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob@^10.3.10: + version "10.5.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" + integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^10.4.2: version "10.4.5" resolved "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz" @@ -3977,7 +4818,7 @@ glob@^10.4.2: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.2.0: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4014,7 +4855,7 @@ gopd@^1.0.1, gopd@^1.2.0: resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -4096,6 +4937,11 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + http-errors@2.0.0, http-errors@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" @@ -4123,6 +4969,11 @@ https-proxy-agent@^7.0.6: agent-base "^7.1.2" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + i@^0.3.7: version "0.3.7" resolved "https://registry.npmjs.org/i/-/i-0.3.7.tgz" @@ -4160,6 +5011,14 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-local@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" @@ -4305,6 +5164,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-generator-function@^1.0.10: version "1.1.2" resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz" @@ -4385,6 +5249,11 @@ is-shared-array-buffer@^1.0.4: dependencies: call-bound "^1.0.3" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz" @@ -4458,6 +5327,48 @@ isobject@^3.0.1: resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^5.0.0: + version "5.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz#acaef948df7747c8eb5fbf1265cb980f6353a441" + integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A== + dependencies: + "@jridgewell/trace-mapping" "^0.3.23" + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + iterator.prototype@^1.1.4: version "1.1.5" resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz" @@ -4479,6 +5390,372 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jest-changed-files@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-30.2.0.tgz#602266e478ed554e1e1469944faa7efd37cee61c" + integrity sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ== + dependencies: + execa "^5.1.1" + jest-util "30.2.0" + p-limit "^3.1.0" + +jest-circus@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-30.2.0.tgz#98b8198b958748a2f322354311023d1d02e7603f" + integrity sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg== + dependencies: + "@jest/environment" "30.2.0" + "@jest/expect" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + co "^4.6.0" + dedent "^1.6.0" + is-generator-fn "^2.1.0" + jest-each "30.2.0" + jest-matcher-utils "30.2.0" + jest-message-util "30.2.0" + jest-runtime "30.2.0" + jest-snapshot "30.2.0" + jest-util "30.2.0" + p-limit "^3.1.0" + pretty-format "30.2.0" + pure-rand "^7.0.0" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-cli@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-30.2.0.tgz#1780f8e9d66bf84a10b369aea60aeda7697dcc67" + integrity sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA== + dependencies: + "@jest/core" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/types" "30.2.0" + chalk "^4.1.2" + exit-x "^0.2.2" + import-local "^3.2.0" + jest-config "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + yargs "^17.7.2" + +jest-config@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-30.2.0.tgz#29df8c50e2ad801cc59c406b50176c18c362a90b" + integrity sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA== + dependencies: + "@babel/core" "^7.27.4" + "@jest/get-type" "30.1.0" + "@jest/pattern" "30.0.1" + "@jest/test-sequencer" "30.2.0" + "@jest/types" "30.2.0" + babel-jest "30.2.0" + chalk "^4.1.2" + ci-info "^4.2.0" + deepmerge "^4.3.1" + glob "^10.3.10" + graceful-fs "^4.2.11" + jest-circus "30.2.0" + jest-docblock "30.2.0" + jest-environment-node "30.2.0" + jest-regex-util "30.0.1" + jest-resolve "30.2.0" + jest-runner "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + micromatch "^4.0.8" + parse-json "^5.2.0" + pretty-format "30.2.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.2.0.tgz#e3ec3a6ea5c5747f605c9e874f83d756cba36825" + integrity sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A== + dependencies: + "@jest/diff-sequences" "30.0.1" + "@jest/get-type" "30.1.0" + chalk "^4.1.2" + pretty-format "30.2.0" + +jest-docblock@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-30.2.0.tgz#42cd98d69f887e531c7352309542b1ce4ee10256" + integrity sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA== + dependencies: + detect-newline "^3.1.0" + +jest-each@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-30.2.0.tgz#39e623ae71641c2ac3ee69b3ba3d258fce8e768d" + integrity sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ== + dependencies: + "@jest/get-type" "30.1.0" + "@jest/types" "30.2.0" + chalk "^4.1.2" + jest-util "30.2.0" + pretty-format "30.2.0" + +jest-environment-node@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-30.2.0.tgz#3def7980ebd2fd86e74efd4d2e681f55ab38da0f" + integrity sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA== + dependencies: + "@jest/environment" "30.2.0" + "@jest/fake-timers" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + jest-mock "30.2.0" + jest-util "30.2.0" + jest-validate "30.2.0" + +jest-haste-map@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-30.2.0.tgz#808e3889f288603ac70ff0ac047598345a66022e" + integrity sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + anymatch "^3.1.3" + fb-watchman "^2.0.2" + graceful-fs "^4.2.11" + jest-regex-util "30.0.1" + jest-util "30.2.0" + jest-worker "30.2.0" + micromatch "^4.0.8" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.3" + +jest-junit@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-16.0.0.tgz#d838e8c561cf9fdd7eb54f63020777eee4136785" + integrity sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ== + dependencies: + mkdirp "^1.0.4" + strip-ansi "^6.0.1" + uuid "^8.3.2" + xml "^1.0.1" + +jest-leak-detector@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz#292fdca7b7c9cf594e1e570ace140b01d8beb736" + integrity sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ== + dependencies: + "@jest/get-type" "30.1.0" + pretty-format "30.2.0" + +jest-matcher-utils@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz#69a0d4c271066559ec8b0d8174829adc3f23a783" + integrity sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg== + dependencies: + "@jest/get-type" "30.1.0" + chalk "^4.1.2" + jest-diff "30.2.0" + pretty-format "30.2.0" + +jest-message-util@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.2.0.tgz#fc97bf90d11f118b31e6131e2b67fc4f39f92152" + integrity sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@jest/types" "30.2.0" + "@types/stack-utils" "^2.0.3" + chalk "^4.1.2" + graceful-fs "^4.2.11" + micromatch "^4.0.8" + pretty-format "30.2.0" + slash "^3.0.0" + stack-utils "^2.0.6" + +jest-mock@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.2.0.tgz#69f991614eeb4060189459d3584f710845bff45e" + integrity sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + jest-util "30.2.0" + +jest-pnp-resolver@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-30.0.1.tgz#f17c1de3958b67dfe485354f5a10093298f2a49b" + integrity sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA== + +jest-resolve-dependencies@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz#3370e2c0b49cc560f6a7e8ec3a59dd99525e1a55" + integrity sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w== + dependencies: + jest-regex-util "30.0.1" + jest-snapshot "30.2.0" + +jest-resolve@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-30.2.0.tgz#2e2009cbd61e8f1f003355d5ec87225412cebcd7" + integrity sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A== + dependencies: + chalk "^4.1.2" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + jest-pnp-resolver "^1.2.3" + jest-util "30.2.0" + jest-validate "30.2.0" + slash "^3.0.0" + unrs-resolver "^1.7.11" + +jest-runner@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-30.2.0.tgz#c62b4c3130afa661789705e13a07bdbcec26a114" + integrity sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ== + dependencies: + "@jest/console" "30.2.0" + "@jest/environment" "30.2.0" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + emittery "^0.13.1" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-docblock "30.2.0" + jest-environment-node "30.2.0" + jest-haste-map "30.2.0" + jest-leak-detector "30.2.0" + jest-message-util "30.2.0" + jest-resolve "30.2.0" + jest-runtime "30.2.0" + jest-util "30.2.0" + jest-watcher "30.2.0" + jest-worker "30.2.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-30.2.0.tgz#395ea792cde048db1b0cd1a92dc9cb9f1921bf8a" + integrity sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg== + dependencies: + "@jest/environment" "30.2.0" + "@jest/fake-timers" "30.2.0" + "@jest/globals" "30.2.0" + "@jest/source-map" "30.0.1" + "@jest/test-result" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + cjs-module-lexer "^2.1.0" + collect-v8-coverage "^1.0.2" + glob "^10.3.10" + graceful-fs "^4.2.11" + jest-haste-map "30.2.0" + jest-message-util "30.2.0" + jest-mock "30.2.0" + jest-regex-util "30.0.1" + jest-resolve "30.2.0" + jest-snapshot "30.2.0" + jest-util "30.2.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-30.2.0.tgz#266fbbb4b95fc4665ce6f32f1f38eeb39f4e26d0" + integrity sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA== + dependencies: + "@babel/core" "^7.27.4" + "@babel/generator" "^7.27.5" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.27.1" + "@babel/types" "^7.27.3" + "@jest/expect-utils" "30.2.0" + "@jest/get-type" "30.1.0" + "@jest/snapshot-utils" "30.2.0" + "@jest/transform" "30.2.0" + "@jest/types" "30.2.0" + babel-preset-current-node-syntax "^1.2.0" + chalk "^4.1.2" + expect "30.2.0" + graceful-fs "^4.2.11" + jest-diff "30.2.0" + jest-matcher-utils "30.2.0" + jest-message-util "30.2.0" + jest-util "30.2.0" + pretty-format "30.2.0" + semver "^7.7.2" + synckit "^0.11.8" + +jest-util@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.2.0.tgz#5142adbcad6f4e53c2776c067a4db3c14f913705" + integrity sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA== + dependencies: + "@jest/types" "30.2.0" + "@types/node" "*" + chalk "^4.1.2" + ci-info "^4.2.0" + graceful-fs "^4.2.11" + picomatch "^4.0.2" + +jest-validate@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-30.2.0.tgz#273eaaed4c0963b934b5b31e96289edda6e0a2ef" + integrity sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw== + dependencies: + "@jest/get-type" "30.1.0" + "@jest/types" "30.2.0" + camelcase "^6.3.0" + chalk "^4.1.2" + leven "^3.1.0" + pretty-format "30.2.0" + +jest-watcher@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-30.2.0.tgz#f9c055de48e18c979e7756a3917e596e2d69b07b" + integrity sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg== + dependencies: + "@jest/test-result" "30.2.0" + "@jest/types" "30.2.0" + "@types/node" "*" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + emittery "^0.13.1" + jest-util "30.2.0" + string-length "^4.0.2" + +jest-worker@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-30.2.0.tgz#fd5c2a36ff6058ec8f74366ec89538cc99539d26" + integrity sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g== + dependencies: + "@types/node" "*" + "@ungap/structured-clone" "^1.3.0" + jest-util "30.2.0" + merge-stream "^2.0.0" + supports-color "^8.1.1" + +jest@^30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-30.2.0.tgz#9f0a71e734af968f26952b5ae4b724af82681630" + integrity sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A== + dependencies: + "@jest/core" "30.2.0" + "@jest/types" "30.2.0" + import-local "^3.2.0" + jest-cli "30.2.0" + js-beautify@1.15.4: version "1.15.4" resolved "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz" @@ -4500,6 +5777,14 @@ js-cookie@^3.0.5: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^3.13.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" @@ -4522,6 +5807,11 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" @@ -4638,6 +5928,11 @@ kind-of@^6.0.2: resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" @@ -4646,6 +5941,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + load-json-file@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz" @@ -4665,6 +5965,13 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" @@ -4765,6 +6072,20 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" @@ -4790,6 +6111,24 @@ merge-descriptors@^2.0.0: resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz" integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" @@ -4814,6 +6153,16 @@ mime-types@^3.0.0, mime-types@^3.0.1: dependencies: mime-db "^1.54.0" +mime@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" @@ -4831,7 +6180,7 @@ minimatch@9.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -4862,6 +6211,11 @@ mkdirp@^0.5.6: dependencies: minimist "^1.2.6" +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + moment-timezone@^0.5.43: version "0.5.48" resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz" @@ -4958,6 +6312,11 @@ nanoid@^5.1.6: resolved "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz" integrity sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg== +napi-postinstall@^0.3.0: + version "0.3.4" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9" + integrity sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" @@ -5003,6 +6362,11 @@ node-gyp-build@^4.8.4: resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz" integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + node-releases@^2.0.27: version "2.0.27" resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz" @@ -5041,6 +6405,13 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + object-assign@^4, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" @@ -5139,6 +6510,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" @@ -5160,14 +6538,14 @@ own-keys@^1.0.1: object-keys "^1.1.1" safe-push-apply "^1.0.0" -p-limit@^2.0.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -5181,6 +6559,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" @@ -5235,6 +6620,16 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz" @@ -5260,7 +6655,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -5349,17 +6744,22 @@ picocolors@^1.1.1: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + pify@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pirates@^4.0.6: +pirates@^4.0.6, pirates@^4.0.7: version "4.0.7" resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz" integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== @@ -5379,6 +6779,13 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + possible-typed-array-names@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz" @@ -5423,6 +6830,15 @@ prettier@^3.6.2: resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz" integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== +pretty-format@30.2.0: + version "30.2.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.2.0.tgz#2d44fe6134529aed18506f6d11509d8a62775ebe" + integrity sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA== + dependencies: + "@jest/schemas" "30.0.5" + ansi-styles "^5.2.0" + react-is "^18.3.1" + prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" @@ -5482,7 +6898,12 @@ punycode@^2.1.0, punycode@^2.3.1: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -qs@^6.14.0: +pure-rand@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-7.0.1.tgz#6f53a5a9e3e4a47445822af96821ca509ed37566" + integrity sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ== + +qs@^6.11.2, qs@^6.14.0: version "6.14.0" resolved "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz" integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== @@ -5519,6 +6940,11 @@ react-is@^16.13.1: resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + readable-stream@^3.0.2: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" @@ -5623,11 +7049,23 @@ require-directory@^2.1.1: resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve@^1.22.1, resolve@^1.22.10, resolve@^1.22.4: version "1.22.11" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz" @@ -5741,7 +7179,7 @@ semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^7.0.0, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.7.2: version "7.7.3" resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz" integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== @@ -5918,6 +7356,11 @@ sift@17.1.3: resolved "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz" integrity sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ== +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" @@ -5935,6 +7378,11 @@ slash@^2.0.0: resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" @@ -5957,6 +7405,14 @@ socks@^2.8.3: ip-address "^10.0.1" smart-buffer "^4.2.0" +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@^0.5.16: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" @@ -5982,6 +7438,18 @@ split2@^4.1.0: resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + standard-engine@^15.1.0: version "15.1.0" resolved "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz" @@ -6039,6 +7507,14 @@ streamsearch@^1.1.0: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== +string-length@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -6158,6 +7634,16 @@ strip-bom@^3.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" @@ -6168,7 +7654,30 @@ strnum@^2.1.0: resolved "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz" integrity sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw== -supports-color@8.1.1: +superagent@^10.2.3: + version "10.2.3" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-10.2.3.tgz#d1e4986f2caac423c37e38077f9073ccfe73a59b" + integrity sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig== + dependencies: + component-emitter "^1.3.1" + cookiejar "^2.1.4" + debug "^4.3.7" + fast-safe-stringify "^2.1.1" + form-data "^4.0.4" + formidable "^3.5.4" + methods "^1.1.2" + mime "2.6.0" + qs "^6.11.2" + +supertest@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-7.1.4.tgz#3175e2539f517ca72fdc7992ffff35b94aca7d34" + integrity sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg== + dependencies: + methods "^1.1.2" + superagent "^10.2.3" + +supports-color@8.1.1, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -6194,7 +7703,7 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: +synckit@^0.11.7, synckit@^0.11.8: version "0.11.11" resolved "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz" integrity sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw== @@ -6209,11 +7718,25 @@ tcp-port-used@^1.0.2: debug "4.3.1" is2 "^2.0.6" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" @@ -6258,7 +7781,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.1, tslib@^2.1.0, tslib@^2.6.2: +tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.1: version "2.8.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -6275,11 +7798,21 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz" @@ -6424,6 +7957,33 @@ unpipe@1.0.0: resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +unrs-resolver@^1.7.11: + version "1.11.1" + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9" + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== + dependencies: + napi-postinstall "^0.3.0" + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" + "@unrs/resolver-binding-android-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-x64" "1.11.1" + "@unrs/resolver-binding-freebsd-x64" "1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" + update-browserslist-db@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz" @@ -6449,6 +8009,15 @@ uuid@^8.3.2: resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + v8flags@^3.1.1: version "3.2.0" resolved "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz" @@ -6471,6 +8040,13 @@ version-guard@^1.1.1: resolved "https://registry.npmjs.org/version-guard/-/version-guard-1.1.3.tgz" integrity sha512-JwPr6erhX53EWH/HCSzfy1tTFrtPXUe927wdM1jqBBeYp1OM+qPHjWbsvv6pIBduqdgxxS+ScfG7S28pzyr2DQ== +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" @@ -6588,11 +8164,24 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" + integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^4.0.1" + xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + xtend@^4.0.0, xtend@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" @@ -6618,7 +8207,7 @@ yargs-parser@^21.1.1: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@17.7.2: +yargs@17.7.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==