diff --git a/jest.setup.js b/jest.setup.js deleted file mode 100644 index 69357ad19..000000000 --- a/jest.setup.js +++ /dev/null @@ -1,14 +0,0 @@ -// Jest setup file to handle BigInt serialization - -if (typeof globalThis.BigInt === 'function') { - if (!BigInt.prototype.toJSON) { - BigInt.prototype.toJSON = function () { - return this.toString(); - }; - } -} - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { TextEncoder, TextDecoder } = require('util'); -global.TextEncoder = global.TextEncoder || TextEncoder; -global.TextDecoder = global.TextDecoder || TextDecoder; diff --git a/package.json b/package.json index b922ff28f..f6525db30 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,11 @@ "cleanup:retroactive": "ts-node -r tsconfig-paths/register src/modules/jobs/commands/retroactive-deleted-items-cleanup.command.ts", "start:dev": "cross-env NODE_ENV=development nest start --watch", "start:debug": "cross-env NODE_ENV=development nest start --debug --watch", - "start:prod": "NODE_ENV=production node -r newrelic dist/main", + "start:prod": "cross-env NODE_ENV=production node -r newrelic dist/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "test": "cross-env NODE_OPTIONS=--experimental-vm-modules NODE_ENV=test jest", - "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch", - "test:cov": "NODE_OPTIONS=--experimental-vm-modules jest --coverage", - "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "NODE_OPTIONS=--experimental-vm-modules cross-env NODE_ENV=test jest --config ./test/jest-e2e.json --forceExit", - "test:e2e:watch": "cross-env NODE_ENV=test jest --config ./test/jest-e2e.json --watchAll", + "test": "cross-env NODE_ENV=test vitest run", + "test:watch": "cross-env NODE_ENV=test vitest --watch", + "test:cov": "cross-env NODE_ENV=test vitest run --coverage", "migrate": "cross-env NODE_ENV=development sequelize db:migrate", "migrate:undo": "cross-env NODE_ENV=development sequelize db:migrate:undo", "migrate:prod": "cross-env NODE_ENV=production sequelize db:migrate", @@ -97,14 +94,12 @@ "uuid": "^11.1.0" }, "devDependencies": { - "@golevelup/ts-jest": "^1.2.0", "@internxt/eslint-config-internxt": "^1.0.9", "@nestjs/schematics": "^11.0.7", "@nestjs/testing": "^11.1.6", "@types/chance": "^1.1.6", "@types/crypto-js": "^4.2.1", "@types/express": "^5.0.1", - "@types/jest": "^30.0.0", "@types/jsonwebtoken": "9.0.2", "@types/multer": "^1.4.13", "@types/multer-s3": "^3.0.3", @@ -114,6 +109,7 @@ "@types/supertest": "^6.0.3", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", + "@vitest/coverage-istanbul": "^4.0.18", "aws-sdk-client-mock": "^4.0.0", "chance": "^1.1.13", "cross-env": "^7.0.3", @@ -121,39 +117,17 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.1", "husky": "^8.0.3", - "jest": "^30.2.0", "lint-staged": "^15.1.0", "prettier": "^3.5.3", "sequelize-cli": "^6.6.3", "source-map-support": "^0.5.21", "supertest": "^7.1.4", - "ts-jest": "^29.4.6", "ts-loader": "^9.5.2", "ts-node": "^10.9.2", "tsconfig-paths": "4.2.0", - "typescript": "^5.8.3" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "roots": [ - "src", - "test" - ], - "testRegex": ".*\\.spec\\.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "collectCoverageFrom": [ - "**/*.(t|j)s" - ], - "testEnvironment": "node", - "setupFilesAfterEnv": [ - "/jest.setup.js" - ] + "typescript": "^5.8.3", + "vitest": "^4.0.18", + "vitest-mock-extended": "^3.1.0" }, "lint-staged": { "./src/**/*.{js,ts}": [ diff --git a/src/common/audit-logs/audit-log.service.spec.ts b/src/common/audit-logs/audit-log.service.spec.ts index 48430f263..416e34b6d 100644 --- a/src/common/audit-logs/audit-log.service.spec.ts +++ b/src/common/audit-logs/audit-log.service.spec.ts @@ -1,91 +1,112 @@ -import { Test, type TestingModule } from '@nestjs/testing'; -import { createMock, type DeepMocked } from '@golevelup/ts-jest'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { type Logger } from '@nestjs/common'; -import { AuditLogService } from './audit-log.service'; -import { AuditLogsRepository } from './audit-logs.repository'; +import { AuditLogService, type CreateAuditLogDto } from './audit-log.service'; +import { type AuditLogsRepository } from './audit-logs.repository'; import { - AuditAction, AuditEntityType, + AuditAction, AuditPerformerType, } from './audit-logs.attributes'; -import { v4 } from 'uuid'; + +const baseDto: CreateAuditLogDto = { + entityType: AuditEntityType.User, + entityId: 'user-123', + action: AuditAction.EmailChanged, + performerType: AuditPerformerType.User, + performerId: 'performer-456', + metadata: { ip: '127.0.0.1' }, +}; describe('AuditLogService', () => { let service: AuditLogService; - let repository: DeepMocked; - let logger: DeepMocked; + let mockRepository: { create: ReturnType }; + let loggerWarnSpy: ReturnType; beforeEach(async () => { - logger = createMock(); + mockRepository = { create: vi.fn() }; - const module: TestingModule = await Test.createTestingModule({ - providers: [AuditLogService], - }) - .setLogger(logger) - .useMocker(() => createMock()) - .compile(); - - service = module.get(AuditLogService); - repository = module.get(AuditLogsRepository); - }); + service = new AuditLogService(mockRepository as AuditLogsRepository); - it('When the service is instantiated, then it should be defined', () => { - expect(service).toBeDefined(); + loggerWarnSpy = vi + .spyOn(Logger.prototype, 'warn') + .mockImplementation(() => undefined); }); describe('log', () => { - it('When valid audit log data is provided, then it should create an audit log', async () => { - const auditLogDto = { - entityType: AuditEntityType.User, - entityId: v4(), - action: AuditAction.PasswordChanged, - performerType: AuditPerformerType.User, - performerId: v4(), - metadata: { folderUuid: v4() }, - }; + it('should call repository.create with the provided dto', async () => { + await service.log(baseDto); - repository.create.mockResolvedValueOnce({} as any); + expect(mockRepository.create).toHaveBeenCalledOnce(); + expect(mockRepository.create).toHaveBeenCalledWith(baseDto); + }); - await service.log(auditLogDto); + it('should not throw when repository.create fails', async () => { + mockRepository.create.mockRejectedValue(new Error('Database error')); - expect(repository.create).toHaveBeenCalledWith(auditLogDto); + await expect(service.log(baseDto)).resolves.toBeUndefined(); }); - it('When valid audit log data without metadata is provided, then it should create an audit log', async () => { - const auditLogDto = { - entityType: AuditEntityType.User, - entityId: v4(), - action: AuditAction.TfaEnabled, - performerType: AuditPerformerType.User, - performerId: v4(), - }; + it('should log a warning when repository.create fails', async () => { + const dbError = new Error('Connection timeout'); + mockRepository.create.mockRejectedValue(dbError); + + await service.log(baseDto); + + expect(loggerWarnSpy).toHaveBeenCalledOnce(); + expect(loggerWarnSpy).toHaveBeenCalledWith( + { + action: baseDto.action, + entityType: baseDto.entityType, + entityId: baseDto.entityId, + error: dbError.message, + }, + 'Failed to create audit log', + ); + }); - repository.create.mockResolvedValueOnce({} as any); + it('should include the correct error message in the warning', async () => { + const specificError = new Error('Unique constraint violation'); + mockRepository.create.mockRejectedValue(specificError); - await service.log(auditLogDto); + await service.log(baseDto); - expect(repository.create).toHaveBeenCalledWith(auditLogDto); + const [warnPayload] = loggerWarnSpy.mock.calls[0]; + expect(warnPayload.error).toBe('Unique constraint violation'); }); - it('When repository throws an error, then it should log a warning and not throw', async () => { - const auditLogDto = { + it('should not log a warning when repository.create succeeds', async () => { + mockRepository.create.mockResolvedValue(undefined); + + await service.log(baseDto); + + expect(loggerWarnSpy).not.toHaveBeenCalled(); + }); + + it('should work without optional fields (performerId, metadata)', async () => { + const minimalDto: CreateAuditLogDto = { entityType: AuditEntityType.User, - entityId: v4(), - action: AuditAction.EmailChanged, - performerType: AuditPerformerType.User, - performerId: v4(), - metadata: { newEmail: 'new@example.com' }, + entityId: 'user-999', + action: AuditAction.AccountDeactivated, + performerType: AuditPerformerType.System, }; + mockRepository.create.mockResolvedValue(undefined); - const error = new Error('Database connection failed'); - repository.create.mockRejectedValueOnce(error); - - const loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + await expect(service.log(minimalDto)).resolves.toBeUndefined(); + expect(mockRepository.create).toHaveBeenCalledWith(minimalDto); + }); - await service.log(auditLogDto); + it('should work with a Workspace entity and Gateway performer', async () => { + const workspaceDto: CreateAuditLogDto = { + entityType: AuditEntityType.Workspace, + entityId: 'workspace-123', + action: AuditAction.WorkspaceCreated, + performerType: AuditPerformerType.Gateway, + performerId: 'gateway-001', + }; + mockRepository.create.mockResolvedValue(undefined); - expect(repository.create).toHaveBeenCalledWith(auditLogDto); - expect(loggerWarnSpy).toHaveBeenCalled(); + await expect(service.log(workspaceDto)).resolves.toBeUndefined(); + expect(mockRepository.create).toHaveBeenCalledWith(workspaceDto); }); }); }); diff --git a/src/common/audit-logs/audit-logs.repository.spec.ts b/src/common/audit-logs/audit-logs.repository.spec.ts index c3236c6e7..018d3aea2 100644 --- a/src/common/audit-logs/audit-logs.repository.spec.ts +++ b/src/common/audit-logs/audit-logs.repository.spec.ts @@ -1,58 +1,206 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { Test, type TestingModule } from '@nestjs/testing'; -import { createMock } from '@golevelup/ts-jest'; import { getModelToken } from '@nestjs/sequelize'; import { SequelizeAuditLogRepository } from './audit-logs.repository'; import { AuditLogModel } from './audit-logs.model'; +import { AuditLog } from './audit-logs.domain'; import { - AuditAction, + type AuditLogAttributes, AuditEntityType, + AuditAction, AuditPerformerType, } from './audit-logs.attributes'; -import { newAuditLog, newUser } from '../../../test/fixtures'; + +const createMockAuditLogInstance = ( + overrides: Partial = {}, +) => { + const base: AuditLogAttributes = { + id: 'audit-id-123', + entityType: AuditEntityType.User, + entityId: 'entity-456', + action: AuditAction.EmailChanged, + performerType: AuditPerformerType.User, + performerId: 'performer-789', + metadata: { ip: '127.0.0.1' }, + createdAt: new Date('2024-01-01T00:00:00Z'), + ...overrides, + }; + + return { + ...base, + toJSON: vi.fn().mockReturnValue(base), + }; +}; + +const userAuditLogData: Omit = { + entityType: AuditEntityType.User, + entityId: 'user-456', + action: AuditAction.EmailChanged, + performerType: AuditPerformerType.User, + performerId: 'performer-789', + metadata: { ip: '127.0.0.1' }, +}; + +const workspaceAuditLogData: Omit = { + entityType: AuditEntityType.Workspace, + entityId: 'workspace-123', + action: AuditAction.WorkspaceCreated, + performerType: AuditPerformerType.Gateway, + performerId: 'gateway-001', +}; describe('SequelizeAuditLogRepository', () => { let repository: SequelizeAuditLogRepository; - let auditLogModel: typeof AuditLogModel; + let mockAuditLogModel: { create: ReturnType }; beforeEach(async () => { + mockAuditLogModel = { create: vi.fn() }; + const module: TestingModule = await Test.createTestingModule({ - providers: [SequelizeAuditLogRepository], - }) - .useMocker(() => createMock()) - .compile(); + providers: [ + SequelizeAuditLogRepository, + { + provide: getModelToken(AuditLogModel), + useValue: mockAuditLogModel, + }, + ], + }).compile(); repository = module.get( SequelizeAuditLogRepository, ); - auditLogModel = module.get( - getModelToken(AuditLogModel), - ); }); describe('create', () => { - it('When valid audit log data is provided, then it should create and return an audit log', async () => { - const user = newUser(); - const auditLogData = newAuditLog({ + it('should return an AuditLog domain instance', async () => { + mockAuditLogModel.create.mockResolvedValue(createMockAuditLogInstance()); + + const result = await repository.create(userAuditLogData); + + expect(result).toBeInstanceOf(AuditLog); + }); + + it('should call model.create with provided fields and an auto-generated createdAt', async () => { + mockAuditLogModel.create.mockResolvedValue(createMockAuditLogInstance()); + + await repository.create(userAuditLogData); + + expect(mockAuditLogModel.create).toHaveBeenCalledOnce(); + expect(mockAuditLogModel.create).toHaveBeenCalledWith( + expect.objectContaining({ + entityType: AuditEntityType.User, + entityId: 'user-456', + action: AuditAction.EmailChanged, + performerType: AuditPerformerType.User, + performerId: 'performer-789', + metadata: { ip: '127.0.0.1' }, + createdAt: expect.any(Date), + }), + ); + }); + + it('should handle a Workspace entity with a Gateway performer', async () => { + mockAuditLogModel.create.mockResolvedValue( + createMockAuditLogInstance({ + entityType: AuditEntityType.Workspace, + entityId: 'workspace-123', + action: AuditAction.WorkspaceCreated, + performerType: AuditPerformerType.Gateway, + performerId: 'gateway-001', + metadata: undefined, + }), + ); + + const result = await repository.create(workspaceAuditLogData); + + expect(result).toBeInstanceOf(AuditLog); + expect(mockAuditLogModel.create).toHaveBeenCalledWith( + expect.objectContaining({ + entityType: AuditEntityType.Workspace, + action: AuditAction.WorkspaceCreated, + performerType: AuditPerformerType.Gateway, + }), + ); + }); + + it('should handle a System performer without performerId or metadata', async () => { + const systemData: Omit = { + entityType: AuditEntityType.User, + entityId: 'user-999', + action: AuditAction.AccountDeactivated, + performerType: AuditPerformerType.System, + }; + + mockAuditLogModel.create.mockResolvedValue( + createMockAuditLogInstance({ + action: AuditAction.AccountDeactivated, + performerType: AuditPerformerType.System, + performerId: undefined, + metadata: undefined, + }), + ); + + const result = await repository.create(systemData); + + expect(result).toBeInstanceOf(AuditLog); + expect(mockAuditLogModel.create).toHaveBeenCalledWith( + expect.objectContaining({ + entityType: AuditEntityType.User, + action: AuditAction.AccountDeactivated, + performerType: AuditPerformerType.System, + createdAt: expect.any(Date), + }), + ); + }); + + it('should map all model fields to the domain object via toJSON', async () => { + const expected: AuditLogAttributes = { + id: 'audit-id-999', entityType: AuditEntityType.User, - entityId: user.uuid, + entityId: 'user-abc', action: AuditAction.PasswordChanged, performerType: AuditPerformerType.User, - performerId: user.uuid, + performerId: 'performer-xyz', + metadata: { reason: 'user request' }, + createdAt: new Date('2024-06-15T12:00:00Z'), + }; + + const mockInstance = createMockAuditLogInstance(expected); + mockAuditLogModel.create.mockResolvedValue(mockInstance); + + const result = await repository.create({ + entityType: expected.entityType, + entityId: expected.entityId, + action: expected.action, + performerType: expected.performerType, + performerId: expected.performerId, + metadata: expected.metadata, }); - jest.spyOn(auditLogModel, 'create').mockResolvedValueOnce({ - toJSON: jest.fn().mockReturnValue({ ...auditLogData }), - } as any); + expect(mockInstance.toJSON).toHaveBeenCalled(); + expect(result).toMatchObject(expected); + }); - const result = await repository.create(auditLogData); + it('should generate a createdAt timestamp within the call time window', async () => { + mockAuditLogModel.create.mockResolvedValue(createMockAuditLogInstance()); - expect(auditLogModel.create).toHaveBeenCalledWith({ - ...auditLogData, - createdAt: expect.any(Date), - }); - expect(result.entityId).toBe(user.uuid); - expect(result.action).toBe(AuditAction.PasswordChanged); - expect(result.performerId).toBe(user.uuid); + const before = new Date(); + await repository.create(userAuditLogData); + const after = new Date(); + + const [callArg] = mockAuditLogModel.create.mock.calls[0]; + expect(callArg.createdAt.getTime()).toBeGreaterThanOrEqual( + before.getTime(), + ); + expect(callArg.createdAt.getTime()).toBeLessThanOrEqual(after.getTime()); + }); + + it('should propagate errors thrown by model.create', async () => { + mockAuditLogModel.create.mockRejectedValue(new Error('Database error')); + + await expect(repository.create(userAuditLogData)).rejects.toThrow( + 'Database error', + ); }); }); }); diff --git a/src/common/audit-logs/interceptors/audit-log.interceptor.spec.ts b/src/common/audit-logs/interceptors/audit-log.interceptor.spec.ts index 5138452d8..0a29c8767 100644 --- a/src/common/audit-logs/interceptors/audit-log.interceptor.spec.ts +++ b/src/common/audit-logs/interceptors/audit-log.interceptor.spec.ts @@ -1,4 +1,5 @@ -import { createMock, type DeepMocked } from '@golevelup/ts-jest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mockDeep, type MockProxy } from 'vitest-mock-extended'; import { type CallHandler, type ExecutionContext } from '@nestjs/common'; import { type Reflector } from '@nestjs/core'; import { of, lastValueFrom } from 'rxjs'; @@ -11,34 +12,39 @@ import { AuditPerformerType, } from '../audit-logs.attributes'; import { newUser, newWorkspace } from '../../../../test/fixtures'; +import { type HttpArgumentsHost } from '@nestjs/common/interfaces'; describe('AuditLogInterceptor', () => { let interceptor: AuditLogInterceptor; - let reflector: DeepMocked; - let auditLogService: DeepMocked; + let reflector: MockProxy; + let auditLogService: MockProxy; - const mockHandler = jest.fn(); + const mockHandler = vi.fn(); - const createContext = (request: any) => - createMock({ - getHandler: () => mockHandler, - switchToHttp: () => ({ getRequest: () => request }), - }); + const createContext = (request: any) => { + const context = mockDeep(); + + context.getHandler.mockReturnValue(mockHandler); + + context.switchToHttp.mockReturnValue({ + getRequest: () => request, + getResponse: () => ({}) as any, + getNext: () => ({}) as any, + } satisfies HttpArgumentsHost); + + return context; + }; const createCallHandler = (response: any): CallHandler => ({ - handle: jest.fn().mockReturnValue(of(response)), + handle: vi.fn().mockReturnValue(of(response)), }); beforeEach(() => { - reflector = createMock(); - auditLogService = createMock(); + reflector = mockDeep(); + auditLogService = mockDeep(); interceptor = new AuditLogInterceptor(reflector, auditLogService); }); - afterEach(() => { - jest.clearAllMocks(); - }); - it('When the interceptor is instantiated, then it should be defined', () => { expect(interceptor).toBeDefined(); }); diff --git a/src/common/decorators/newrelic-trace-method.decorator.spec.ts b/src/common/decorators/newrelic-trace-method.decorator.spec.ts index 4308cfac1..25d6039b8 100644 --- a/src/common/decorators/newrelic-trace-method.decorator.spec.ts +++ b/src/common/decorators/newrelic-trace-method.decorator.spec.ts @@ -1,13 +1,12 @@ -jest.mock('newrelic'); - +import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest'; import newrelic from 'newrelic'; import { TraceMethod } from './newrelic-trace-method.decorator'; -const mockedNewrelic = newrelic as jest.Mocked; +vi.mock('newrelic', { spy: true }); +const mockedNewrelic = newrelic as Mocked; describe('TraceMethod Decorator', () => { beforeEach(() => { - jest.clearAllMocks(); mockedNewrelic.startSegment.mockImplementation((name, record, handler) => { return handler(); }); @@ -190,7 +189,7 @@ describe('TraceMethod Decorator', () => { }); it('When newrelic.startSegment callback executes, then original method is invoked', () => { - const originalMethodSpy = jest.fn().mockReturnValue('spy result'); + const originalMethodSpy = vi.fn().mockReturnValue('spy result'); class TestClass { @TraceMethod() diff --git a/src/common/dto/basic-pagination.dto.spec.ts b/src/common/dto/basic-pagination.dto.spec.ts index 2f0200f76..01f539522 100644 --- a/src/common/dto/basic-pagination.dto.spec.ts +++ b/src/common/dto/basic-pagination.dto.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { validate } from 'class-validator'; import { BasicPaginationDto } from './basic-pagination.dto'; diff --git a/src/common/dto/uuid.dto.spec.ts b/src/common/dto/uuid.dto.spec.ts index 6bc58ff57..102b50198 100644 --- a/src/common/dto/uuid.dto.spec.ts +++ b/src/common/dto/uuid.dto.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { validate } from 'class-validator'; import { UuidDto } from './uuid.dto'; import { newUser } from '../../../test/fixtures'; diff --git a/src/common/extract-data-from-request.spec.ts b/src/common/extract-data-from-request.spec.ts index 72f01cda7..6b5b3831d 100644 --- a/src/common/extract-data-from-request.spec.ts +++ b/src/common/extract-data-from-request.spec.ts @@ -1,3 +1,4 @@ +import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import { BadRequestException, type ExecutionContext, @@ -24,11 +25,11 @@ describe('extractDataFromRequest', () => { reflector = new Reflector(); context = { - getHandler: jest.fn(), + getHandler: vi.fn(), } as unknown as ExecutionContext; - jest.spyOn(Logger.prototype, 'error').mockImplementation(() => {}); - jest.spyOn(reflector, 'get').mockImplementation(); + vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {}); + vi.spyOn(reflector, 'get').mockImplementation(() => {}); }); it('When all fields are present, then it should extract data correctly', () => { @@ -43,8 +44,8 @@ describe('extractDataFromRequest', () => { { sourceKey: 'headers', fieldName: 'field4' }, ]; - (reflector.get as jest.Mock).mockReturnValue({ dataSources }); - (context.getHandler as jest.Mock).mockReturnValue('handler'); + (reflector.get as Mock).mockReturnValue({ dataSources }); + (context.getHandler as Mock).mockReturnValue('handler'); const result = extractDataFromRequest(request, reflector, context); @@ -61,8 +62,8 @@ describe('extractDataFromRequest', () => { { sourceKey: 'body', fieldName: 'missingField' }, ]; - (reflector.get as jest.Mock).mockReturnValue({ dataSources }); - (context.getHandler as jest.Mock).mockReturnValue('handler'); + (reflector.get as Mock).mockReturnValue({ dataSources }); + (context.getHandler as Mock).mockReturnValue('handler'); expect(() => extractDataFromRequest(request, reflector, context)).toThrow( BadRequestException, @@ -77,8 +78,8 @@ describe('extractDataFromRequest', () => { { sourceKey: 'body', fieldName: 'field1', value: 'providedValue' }, ]; - (reflector.get as jest.Mock).mockReturnValue({ dataSources }); - (context.getHandler as jest.Mock).mockReturnValue('handler'); + (reflector.get as Mock).mockReturnValue({ dataSources }); + (context.getHandler as Mock).mockReturnValue('handler'); const result = extractDataFromRequest(request, reflector, context); @@ -92,8 +93,8 @@ describe('extractDataFromRequest', () => { { sourceKey: 'body', fieldName: 'field1', value: null }, ]; - (reflector.get as jest.Mock).mockReturnValue({ dataSources }); - (context.getHandler as jest.Mock).mockReturnValue('handler'); + (reflector.get as Mock).mockReturnValue({ dataSources }); + (context.getHandler as Mock).mockReturnValue('handler'); expect(() => extractDataFromRequest(request, reflector, context)).toThrow( BadRequestException, @@ -108,8 +109,8 @@ describe('extractDataFromRequest', () => { { sourceKey: 'query', fieldName: 'field2', newFieldName: 'newField2' }, ]; - (reflector.get as jest.Mock).mockReturnValue({ dataSources }); - (context.getHandler as jest.Mock).mockReturnValue('handler'); + (reflector.get as Mock).mockReturnValue({ dataSources }); + (context.getHandler as Mock).mockReturnValue('handler'); const result = extractDataFromRequest(request, reflector, context); @@ -124,8 +125,8 @@ describe('extractDataFromRequest', () => { { sourceKey: 'query', fieldName: 'field2' }, ]; - (reflector.get as jest.Mock).mockReturnValue({ dataSources }); - (context.getHandler as jest.Mock).mockReturnValue('handler'); + (reflector.get as Mock).mockReturnValue({ dataSources }); + (context.getHandler as Mock).mockReturnValue('handler'); const result = extractDataFromRequest(request, reflector, context); diff --git a/src/common/http-global-exception-filter.exception.spec.ts b/src/common/http-global-exception-filter.exception.spec.ts index 4a3b0d945..927a2d322 100644 --- a/src/common/http-global-exception-filter.exception.spec.ts +++ b/src/common/http-global-exception-filter.exception.spec.ts @@ -1,3 +1,5 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mockDeep, type DeepMockProxy } from 'vitest-mock-extended'; import { type ArgumentsHost, HttpException, @@ -9,26 +11,25 @@ import { BaseExceptionFilter, HttpAdapterHost } from '@nestjs/core'; import { ValidationError } from 'sequelize'; import { AxiosError } from 'axios'; import { HttpGlobalExceptionFilter } from './http-global-exception-filter.exception'; -import { createMock, type DeepMocked } from '@golevelup/ts-jest'; import { newUser } from '../../test/fixtures'; import { v4 } from 'uuid'; -jest.mock('../common/decorators/client.decorator', () => ({ - getClientIdFromHeaders: jest.fn().mockReturnValue('drive-web'), +vi.mock('../common/decorators/client.decorator', () => ({ + getClientIdFromHeaders: vi.fn().mockReturnValue('drive-web'), })); describe('HttpGlobalExceptionFilter', () => { let filter: HttpGlobalExceptionFilter; - let mockHttpAdapter: DeepMocked; - let mockHttpAdapterHost: DeepMocked; - let loggerMock: DeepMocked; + let mockHttpAdapter: DeepMockProxy; + let mockHttpAdapterHost: DeepMockProxy; + let loggerMock: DeepMockProxy; beforeEach(async () => { - mockHttpAdapter = createMock(); - mockHttpAdapterHost = createMock({ + mockHttpAdapter = mockDeep(); + mockHttpAdapterHost = mockDeep({ httpAdapter: mockHttpAdapter, }); - loggerMock = createMock(); + loggerMock = mockDeep(); const module: TestingModule = await Test.createTestingModule({ providers: [ @@ -45,7 +46,7 @@ describe('HttpGlobalExceptionFilter', () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('When HttpException is sent, it should format response and not log errors', () => { @@ -237,7 +238,7 @@ describe('HttpGlobalExceptionFilter', () => { throw new Error('Error in filter'); }); - const superCatchSpy = jest + const superCatchSpy = vi .spyOn(BaseExceptionFilter.prototype, 'catch') .mockImplementation(() => undefined); @@ -274,16 +275,19 @@ const createMockArgumentsHost = ( user: any, body: any = {}, id: string = v4(), -) => - createMock({ - switchToHttp: () => ({ - getRequest: () => ({ - url, - method, - user, - body, - id, - }), - getResponse: () => ({ setHeader: jest.fn() }), +) => { + const mock = mockDeep(); + + mock.switchToHttp.mockReturnValue({ + getRequest: () => ({ + url, + method, + user, + body, + id, }), - }); + getResponse: () => ({ setHeader: vi.fn() }), + } as any); + + return mock; +}; diff --git a/src/common/pipes/validate-uuid.pipe.spec.ts b/src/common/pipes/validate-uuid.pipe.spec.ts index 601f40c48..b3d6d6fc3 100644 --- a/src/common/pipes/validate-uuid.pipe.spec.ts +++ b/src/common/pipes/validate-uuid.pipe.spec.ts @@ -1,3 +1,4 @@ +import { beforeEach, describe, expect, it } from 'vitest'; import { ValidateUUIDPipe } from './validate-uuid.pipe'; import { BadRequestException, type ArgumentMetadata } from '@nestjs/common'; diff --git a/src/externals/asymmetric-encryption/asymmetric-encryption.module.ts b/src/externals/asymmetric-encryption/asymmetric-encryption.module.ts index d02ccc798..766ddfef6 100644 --- a/src/externals/asymmetric-encryption/asymmetric-encryption.module.ts +++ b/src/externals/asymmetric-encryption/asymmetric-encryption.module.ts @@ -1,10 +1,9 @@ import { Module } from '@nestjs/common'; -import { KyberProvider } from './providers/kyber.provider'; import { AsymmetricEncryptionService } from './asymmetric-encryption.service'; @Module({ imports: [], - providers: [KyberProvider, AsymmetricEncryptionService], + providers: [AsymmetricEncryptionService], exports: [AsymmetricEncryptionService], }) export class AsymmetricEncryptionModule {} diff --git a/src/externals/asymmetric-encryption/asymmetric-encryption.service.spec.ts b/src/externals/asymmetric-encryption/asymmetric-encryption.service.spec.ts index 14b9f7545..b6e6f1cf0 100644 --- a/src/externals/asymmetric-encryption/asymmetric-encryption.service.spec.ts +++ b/src/externals/asymmetric-encryption/asymmetric-encryption.service.spec.ts @@ -1,17 +1,37 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Test, type TestingModule } from '@nestjs/testing'; import { AsymmetricEncryptionService } from './asymmetric-encryption.service'; -import { KyberProvider } from './providers/kyber.provider'; import { decryptMessageWithPrivateKey, encryptMessageWithPublicKey, } from './openpgp'; +vi.mock('@dashlane/pqc-kem-kyber512-node', () => ({ + default: vi.fn(() => ({ + keypair: vi.fn().mockResolvedValue({ + publicKey: new Uint8Array([1, 2, 3]), + privateKey: new Uint8Array([4, 5, 6]), + }), + encapsulate: vi.fn().mockResolvedValue({ + ciphertext: new Uint8Array([11, 12, 13, 14, 15]), + sharedSecret: new Uint8Array([ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ]), + }), + decapsulate: vi.fn().mockResolvedValue({ + sharedSecret: new Uint8Array([ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ]), + }), + })), +})); + describe('AsymmetricEncryptionService', () => { let service: AsymmetricEncryptionService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [AsymmetricEncryptionService, KyberProvider], + providers: [AsymmetricEncryptionService], }).compile(); await module.init(); diff --git a/src/externals/asymmetric-encryption/asymmetric-encryption.service.ts b/src/externals/asymmetric-encryption/asymmetric-encryption.service.ts index f9c30f8cb..b14913afe 100644 --- a/src/externals/asymmetric-encryption/asymmetric-encryption.service.ts +++ b/src/externals/asymmetric-encryption/asymmetric-encryption.service.ts @@ -1,5 +1,5 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { KyberBuilder, KyberProvider } from './providers/kyber.provider'; +import { Injectable } from '@nestjs/common'; +import kemBuilder from '@dashlane/pqc-kem-kyber512-node'; import { extendSecret, XORhex } from './utils'; import { decryptMessageWithPrivateKey, @@ -11,13 +11,11 @@ const WORDS_HYBRID_MODE_IN_BASE64 = 'SHlicmlkTW9kZQ=='; // 'HybridMode' in BASE6 @Injectable() export class AsymmetricEncryptionService { - constructor( - @Inject(KyberProvider.provide) - private readonly kyberKem: KyberBuilder, - ) {} + constructor() {} async generateKyberKeys() { - const keys = await this.kyberKem.keypair(); + const kyberKem = await kemBuilder(); + const keys = await kyberKem.keypair(); return { publicKey: Buffer.from(keys.publicKey).toString('base64'), privateKey: Buffer.from(keys.privateKey).toString('base64'), @@ -45,7 +43,8 @@ export class AsymmetricEncryptionService { async encapsulateKyberSharedSecret( publicKey: Uint8Array, ): Promise<{ ciphertext: Uint8Array; sharedSecret: Uint8Array }> { - return this.kyberKem.encapsulate(publicKey); + const kyberKem = await kemBuilder(); + return kyberKem.encapsulate(publicKey); } /** @@ -56,10 +55,8 @@ export class AsymmetricEncryptionService { ciphertext: Uint8Array, privateKey: Uint8Array, ): Promise { - const { sharedSecret } = await this.kyberKem.decapsulate( - ciphertext, - privateKey, - ); + const kyberKem = await kemBuilder(); + const { sharedSecret } = await kyberKem.decapsulate(ciphertext, privateKey); return sharedSecret; } diff --git a/src/externals/asymmetric-encryption/openpgp.spec.ts b/src/externals/asymmetric-encryption/openpgp.spec.ts index c40f83466..a46ebbff5 100644 --- a/src/externals/asymmetric-encryption/openpgp.spec.ts +++ b/src/externals/asymmetric-encryption/openpgp.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it, type Mock, vi } from 'vitest'; import { generateNewKeys, decryptMessageWithPrivateKey, @@ -5,14 +6,14 @@ import { } from './openpgp'; import * as openpgp from 'openpgp'; -jest.mock('openpgp', () => ({ - generateKey: jest.fn(), - readPrivateKey: jest.fn(), - readMessage: jest.fn(), - decrypt: jest.fn(), - readKey: jest.fn(), - encrypt: jest.fn(), - createMessage: jest.fn(), +vi.mock('openpgp', () => ({ + generateKey: vi.fn(), + readPrivateKey: vi.fn(), + readMessage: vi.fn(), + decrypt: vi.fn(), + readKey: vi.fn(), + encrypt: vi.fn(), + createMessage: vi.fn(), })); describe('PGP Utils', () => { @@ -22,7 +23,7 @@ describe('PGP Utils', () => { const mockPublicKey = 'mockPublicKey'; const mockRevocationCert = 'mockRevocationCert'; - (openpgp.generateKey as jest.Mock).mockResolvedValue({ + (openpgp.generateKey as Mock).mockResolvedValue({ privateKey: mockPrivateKey, publicKey: mockPublicKey, revocationCertificate: mockRevocationCert, @@ -51,11 +52,9 @@ describe('PGP Utils', () => { const mockPrivateKey = 'mockPrivateKeyBase64'; const mockDecryptedMessage = 'Decrypted message'; - (openpgp.readPrivateKey as jest.Mock).mockResolvedValue(mockPrivateKey); - (openpgp.readMessage as jest.Mock).mockResolvedValue( - mockEncryptedMessage, - ); - (openpgp.decrypt as jest.Mock).mockResolvedValue({ + (openpgp.readPrivateKey as Mock).mockResolvedValue(mockPrivateKey); + (openpgp.readMessage as Mock).mockResolvedValue(mockEncryptedMessage); + (openpgp.decrypt as Mock).mockResolvedValue({ data: mockDecryptedMessage, }); @@ -85,11 +84,11 @@ describe('PGP Utils', () => { const mockPublicKeyBase64 = Buffer.from(mockPublicKey).toString('base64'); const mockEncryptedMessage = 'mockEncryptedMessage'; - (openpgp.readKey as jest.Mock).mockResolvedValue(mockPublicKey); - (openpgp.createMessage as jest.Mock).mockResolvedValue({ + (openpgp.readKey as Mock).mockResolvedValue(mockPublicKey); + (openpgp.createMessage as Mock).mockResolvedValue({ text: mockMessage, }); - (openpgp.encrypt as jest.Mock).mockResolvedValue(mockEncryptedMessage); + (openpgp.encrypt as Mock).mockResolvedValue(mockEncryptedMessage); const result = await encryptMessageWithPublicKey({ message: mockMessage, diff --git a/src/externals/asymmetric-encryption/providers/kyber.provider.ts b/src/externals/asymmetric-encryption/providers/kyber.provider.ts deleted file mode 100644 index 5551f4717..000000000 --- a/src/externals/asymmetric-encryption/providers/kyber.provider.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { type FactoryProvider } from '@nestjs/common'; -import { importEsmPackage } from '../../../lib/import-esm-package'; -import type { KEM } from '@dashlane/pqc-kem-kyber512-node'; - -export type KyberBuilder = KEM; - -export const KyberProvider: FactoryProvider = { - provide: 'Kyber', - useFactory: async (): Promise => { - const kemBuilder = await importEsmPackage< - typeof import('@dashlane/pqc-kem-kyber512-node').default - >('@dashlane/pqc-kem-kyber512-node'); - - const kemInstance = await kemBuilder(); - - return kemInstance; - }, -}; diff --git a/src/externals/asymmetric-encryption/utils.spec.ts b/src/externals/asymmetric-encryption/utils.spec.ts index c90a4d5f8..e5b5146cc 100644 --- a/src/externals/asymmetric-encryption/utils.spec.ts +++ b/src/externals/asymmetric-encryption/utils.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { extendSecret, XORhex } from './utils'; describe('extendSecret', () => { diff --git a/src/externals/avatar/avatar.service.spec.ts b/src/externals/avatar/avatar.service.spec.ts index b8fc1b5a0..fc68f52eb 100644 --- a/src/externals/avatar/avatar.service.spec.ts +++ b/src/externals/avatar/avatar.service.spec.ts @@ -1,3 +1,4 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { Test, type TestingModule } from '@nestjs/testing'; import { AvatarService } from './avatar.service'; @@ -7,7 +8,7 @@ import configuration from '../../config/configuration'; import { v4 } from 'uuid'; import * as s3RequestPresigner from '@aws-sdk/s3-request-presigner'; -jest.mock('@aws-sdk/s3-request-presigner'); +vi.mock('@aws-sdk/s3-request-presigner'); describe('Avatar Service', () => { let service: AvatarService; @@ -40,17 +41,17 @@ describe('Avatar Service', () => { describe('Get avatar download url', () => { it('When avatar key is null then it should throw an error', async () => { const avatarKey = null; - jest - .spyOn(s3RequestPresigner, 'getSignedUrl') - .mockRejectedValueOnce(new Error()); + vi.spyOn(s3RequestPresigner, 'getSignedUrl').mockRejectedValueOnce( + new Error(), + ); await expect(service.getDownloadUrl(avatarKey)).rejects.toThrow(); }); it('When avatar key is not null then it should return an url', async () => { const avatarKey = v4(); const expectedUrl = `https://avatar.network.com/${avatarKey}`; - jest - .spyOn(s3RequestPresigner, 'getSignedUrl') - .mockResolvedValueOnce(expectedUrl); + vi.spyOn(s3RequestPresigner, 'getSignedUrl').mockResolvedValueOnce( + expectedUrl, + ); const response = await service.getDownloadUrl(avatarKey); expect(response).toBe(expectedUrl); }); diff --git a/src/externals/bridge/bridge.service.spec.ts b/src/externals/bridge/bridge.service.spec.ts index abfb93e4e..64d7d0b60 100644 --- a/src/externals/bridge/bridge.service.spec.ts +++ b/src/externals/bridge/bridge.service.spec.ts @@ -1,20 +1,18 @@ -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { Test, type TestingModule } from '@nestjs/testing'; -import { type Logger } from '@nestjs/common'; -import { createMock } from '@golevelup/ts-jest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mockDeep, type DeepMockProxy } from 'vitest-mock-extended'; +import { type ConfigService } from '@nestjs/config'; import { User } from '../../modules/user/user.domain'; -import { CryptoService } from '../crypto/crypto.service'; -import { HttpClientModule } from '../http/http.module'; -import { HttpClient } from '../http/http.service'; +import { type CryptoService } from '../crypto/crypto.service'; +import { type HttpClient } from '../http/http.service'; import { BridgeService } from './bridge.service'; import { type AxiosResponse, type InternalAxiosRequestConfig } from 'axios'; -import { CryptoModule } from '../crypto/crypto.module'; +import { mockLogger } from '../../../test/helpers/mocker.helper'; describe('Bridge Service', () => { let service: BridgeService; - let httpClient: HttpClient; - let cryptoService: CryptoService; - let configService: ConfigService; + let httpClient: DeepMockProxy; + let cryptoService: DeepMockProxy; + let configService: DeepMockProxy; const mockedUser = User.build({ id: 2, @@ -47,17 +45,12 @@ describe('Bridge Service', () => { }); beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [ConfigModule, HttpClientModule, CryptoModule], - providers: [BridgeService], - }) - .setLogger(createMock()) - .compile(); - - service = module.get(BridgeService); - httpClient = module.get(HttpClient); - configService = module.get(ConfigService); - cryptoService = module.get(CryptoService); + cryptoService = mockDeep(); + httpClient = mockDeep(); + configService = mockDeep(); + + service = new BridgeService(cryptoService, httpClient, configService); + mockLogger(); }); describe('delete file', () => { @@ -71,9 +64,9 @@ describe('Bridge Service', () => { config: {} as InternalAxiosRequestConfig, statusText: 'OK', }; - jest.spyOn(configService, 'get').mockReturnValue(testUrl); - jest.spyOn(cryptoService, 'hashSha256').mockReturnValue(hash); - jest.spyOn(httpClient, 'delete').mockResolvedValueOnce(response); + configService.get.mockReturnValue(testUrl); + cryptoService.hashSha256.mockReturnValue(hash); + httpClient.delete.mockResolvedValueOnce(response); await service.deleteFile( mockedUser, @@ -109,8 +102,8 @@ describe('Bridge Service', () => { statusText: 'OK', }; - jest.spyOn(configService, 'get').mockReturnValue(testBridgeApiUrl); - jest.spyOn(httpClient, 'delete').mockResolvedValueOnce(response); + configService.get.mockReturnValue(testBridgeApiUrl); + httpClient.delete.mockResolvedValueOnce(response); await service.sendDeactivationEmail( mockedUser, @@ -126,8 +119,8 @@ describe('Bridge Service', () => { }); it('When deactivation email fails, it should throw', async () => { - jest.spyOn(configService, 'get').mockReturnValue(testBridgeApiUrl); - jest.spyOn(httpClient, 'delete').mockRejectedValueOnce(new Error()); + configService.get.mockReturnValue(testBridgeApiUrl); + httpClient.delete.mockRejectedValueOnce(new Error()); await expect( service.sendDeactivationEmail( @@ -153,8 +146,8 @@ describe('Bridge Service', () => { statusText: 'OK', }; - jest.spyOn(configService, 'get').mockReturnValue(testBridgeApiUrl); - jest.spyOn(httpClient, 'get').mockResolvedValueOnce(response); + configService.get.mockReturnValue(testBridgeApiUrl); + httpClient.get.mockResolvedValueOnce(response); await service.confirmDeactivation(token); @@ -166,8 +159,8 @@ describe('Bridge Service', () => { }); it('When user deactivation confirmation fails, it should throw', async () => { - jest.spyOn(configService, 'get').mockReturnValue(testBridgeApiUrl); - jest.spyOn(httpClient, 'get').mockRejectedValueOnce(new Error()); + configService.get.mockReturnValue(testBridgeApiUrl); + httpClient.get.mockRejectedValueOnce(new Error()); await expect(service.confirmDeactivation(token)).rejects.toThrow(); }); diff --git a/src/externals/crypto/crypto.spec.ts b/src/externals/crypto/crypto.spec.ts index fbccac57f..0266ccca2 100644 --- a/src/externals/crypto/crypto.spec.ts +++ b/src/externals/crypto/crypto.spec.ts @@ -1,32 +1,16 @@ -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { Test, type TestingModule } from '@nestjs/testing'; -import configuration from '../../config/configuration'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { type ConfigService } from '@nestjs/config'; +import { mockDeep } from 'vitest-mock-extended'; import { CryptoService } from './crypto.service'; describe('Crypto', () => { let cryptoService: CryptoService; beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - envFilePath: [`.env.${process.env.NODE_ENV}`], - load: [configuration], - isGlobal: true, - }), - ], - providers: [ - { - provide: CryptoService, - useFactory: async (configService: ConfigService) => { - return new CryptoService(configService); - }, - inject: [ConfigService], - }, - ], - }).compile(); - - cryptoService = module.get(CryptoService); + const configService = mockDeep(); + configService.get.mockReturnValue('test'); + + cryptoService = new CryptoService(configService); }); describe('check crypto as singleton', () => { diff --git a/src/externals/klaviyo/klaviyo-tracking.service.spec.ts b/src/externals/klaviyo/klaviyo-tracking.service.spec.ts index 6d0882ea7..c03b45439 100644 --- a/src/externals/klaviyo/klaviyo-tracking.service.spec.ts +++ b/src/externals/klaviyo/klaviyo-tracking.service.spec.ts @@ -1,36 +1,29 @@ -import { Test, type TestingModule } from '@nestjs/testing'; -import { ConfigService } from '@nestjs/config'; +import { beforeEach, describe, expect, it, type Mocked, vi } from 'vitest'; +import { type ConfigService } from '@nestjs/config'; import { KlaviyoTrackingService } from './klaviyo-tracking.service'; import axios, { type AxiosResponse } from 'axios'; +import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended'; +import { mockLogger } from '../../../test/helpers/mocker.helper'; -jest.mock('axios'); -const mockedAxios = axios as jest.Mocked; +vi.mock('axios'); +const mockedAxios = axios as Mocked; describe('KlaviyoTrackingService', () => { let service: KlaviyoTrackingService; + let configService: DeepMockProxy; const mockApiKey = 'test-klaviyo-api-key'; const mockBaseUrl = 'https://a.klaviyo.com/api'; beforeEach(async () => { - jest.clearAllMocks(); - - const module: TestingModule = await Test.createTestingModule({ - providers: [ - KlaviyoTrackingService, - { - provide: ConfigService, - useValue: { - get: jest.fn((key: string) => { - if (key === 'klaviyo.apiKey') return mockApiKey; - if (key === 'klaviyo.baseUrl') return mockBaseUrl; - return null; - }), - }, - }, - ], - }).compile(); + configService = mockDeep(); + configService.get.mockImplementation((key: string) => { + if (key === 'klaviyo.apiKey') return mockApiKey; + if (key === 'klaviyo.baseUrl') return mockBaseUrl; + return null; + }); - service = module.get(KlaviyoTrackingService); + service = new KlaviyoTrackingService(configService); + mockLogger(); }); it('should be defined', () => { diff --git a/src/externals/notifications/storage.notifications.service.spec.ts b/src/externals/notifications/storage.notifications.service.spec.ts index c52d0563c..27998faef 100644 --- a/src/externals/notifications/storage.notifications.service.spec.ts +++ b/src/externals/notifications/storage.notifications.service.spec.ts @@ -1,10 +1,10 @@ -import { Test, type TestingModule } from '@nestjs/testing'; -import { createMock, type DeepMocked } from '@golevelup/ts-jest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mockDeep, type MockProxy } from 'vitest-mock-extended'; import { type Logger } from '@nestjs/common'; import { StorageNotificationService } from './storage.notifications.service'; -import { NotificationService } from './notification.service'; -import { ApnService } from '../apn/apn.service'; -import { SequelizeUserRepository } from '../../modules/user/user.repository'; +import { type NotificationService } from './notification.service'; +import { type ApnService } from '../apn/apn.service'; +import { type SequelizeUserRepository } from '../../modules/user/user.repository'; import { NotificationEvent } from './events/notification.event'; import { newUser } from '../../../test/fixtures'; import { UserNotificationTokens } from '../../modules/user/user-notification-tokens.domain'; @@ -15,46 +15,36 @@ import { type ItemToTrashDto, ItemToTrashType, } from '../../modules/trash/dto/controllers/move-items-to-trash.dto'; +import { mockLogger } from '../../../test/helpers/mocker.helper'; describe('StorageNotificationService', () => { const fixedSystemCurrentDate = new Date('2021-01-01T00:00:00Z'); let service: StorageNotificationService; - let notificationService: NotificationService; - let apnService: ApnService; - let userRepository: SequelizeUserRepository; - let loggerMock: DeepMocked; + let notificationService: MockProxy; + let apnService: MockProxy; + let userRepository: MockProxy; beforeEach(async () => { - loggerMock = createMock(); + notificationService = mockDeep(); + apnService = mockDeep(); + userRepository = mockDeep(); - const module: TestingModule = await Test.createTestingModule({ - providers: [StorageNotificationService], - }) - .setLogger(loggerMock) - .useMocker(createMock) - .compile(); + vi.useFakeTimers(); + vi.setSystemTime(fixedSystemCurrentDate); - jest.useFakeTimers(); - jest.setSystemTime(fixedSystemCurrentDate); - - service = module.get( - StorageNotificationService, - ); - notificationService = module.get(NotificationService); - apnService = module.get(ApnService); - userRepository = module.get( - SequelizeUserRepository, + service = new StorageNotificationService( + notificationService, + apnService, + userRepository, ); + + mockLogger(); }); it('should be defined', () => { expect(service).toBeDefined(); }); - afterEach(() => { - jest.clearAllMocks(); - }); - describe('fileCreated', () => { const user = newUser(); const payload = { @@ -64,7 +54,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.itemCreated', payload, @@ -94,7 +84,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.itemUpdated', payload, @@ -123,7 +113,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.itemCreated', payload, @@ -153,7 +143,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.itemUpdated', payload, @@ -182,7 +172,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.itemsToTrash', payload, @@ -217,7 +207,7 @@ describe('StorageNotificationService', () => { user.uuid, 'PLAN_UPDATED', ); - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); service.planUpdated({ payload, user, clientId }); @@ -240,7 +230,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.workspaceJoined', payload, @@ -271,7 +261,7 @@ describe('StorageNotificationService', () => { const clientId = 'test-client'; it('When called, then it should add a notification event and send APN notification', () => { - jest.spyOn(service, 'getTokensAndSendApnNotification'); + vi.spyOn(service, 'getTokensAndSendApnNotification'); const notification = new NotificationEvent( 'notification.workspaceLeft', payload, @@ -327,12 +317,11 @@ describe('StorageNotificationService', () => { ]; it('When called with valid tokens, then it should send notifications to all tokens', async () => { - jest - .spyOn(userRepository, 'getNotificationTokens') - .mockResolvedValue(tokens); - jest - .spyOn(apnService, 'sendNotification') - .mockResolvedValue({ statusCode: 200, body: '' }); + userRepository.getNotificationTokens.mockResolvedValue(tokens); + apnService.sendNotification.mockResolvedValue({ + statusCode: 200, + body: '', + }); await service.getTokensAndSendApnNotification(user.uuid); @@ -356,11 +345,8 @@ describe('StorageNotificationService', () => { }); it('When some tokens are expired, then it should delete them', async () => { - jest - .spyOn(userRepository, 'getNotificationTokens') - .mockResolvedValue(tokens); - jest - .spyOn(apnService, 'sendNotification') + userRepository.getNotificationTokens.mockResolvedValue(tokens); + apnService.sendNotification .mockResolvedValueOnce({ statusCode: 200, body: '' }) .mockResolvedValueOnce({ statusCode: 410, body: '' }) // expired token .mockResolvedValueOnce({ statusCode: 200, body: '' }); @@ -374,31 +360,29 @@ describe('StorageNotificationService', () => { }); it('When sending notification fails, then it should log error and continue', async () => { - jest - .spyOn(userRepository, 'getNotificationTokens') - .mockResolvedValue(tokens); + userRepository.getNotificationTokens.mockResolvedValue(tokens); const error = new Error('APN error'); - jest - .spyOn(apnService, 'sendNotification') + apnService.sendNotification .mockResolvedValueOnce({ statusCode: 200, body: '' }) .mockRejectedValueOnce(error) .mockResolvedValueOnce({ statusCode: 200, body: '' }); - const errorSpy = jest.spyOn(loggerMock, 'error'); + const errorSpy = vi.spyOn(Logger.prototype, 'error'); await service.getTokensAndSendApnNotification(user.uuid); - expect(errorSpy).toHaveBeenCalled(); expect(apnService.sendNotification).toHaveBeenCalledTimes(3); + expect(errorSpy).toHaveBeenCalled(); }); it('When called with custom options, then it should pass them properly', async () => { - jest - .spyOn(userRepository, 'getNotificationTokens') - .mockResolvedValue([{ token: 'token1' }] as any); - jest - .spyOn(apnService, 'sendNotification') - .mockResolvedValue({ statusCode: 200, body: '' }); + userRepository.getNotificationTokens.mockResolvedValue([ + { token: 'token1' }, + ] as any); + apnService.sendNotification.mockResolvedValue({ + statusCode: 200, + body: '', + }); const options = { isStorageNotification: false, diff --git a/src/externals/redis/redis.service.spec.ts b/src/externals/redis/redis.service.spec.ts index e8a17f94c..68bc4410f 100644 --- a/src/externals/redis/redis.service.spec.ts +++ b/src/externals/redis/redis.service.spec.ts @@ -1,46 +1,49 @@ -import { Test } from '@nestjs/testing'; -import { ConfigService } from '@nestjs/config'; -import { type Logger } from '@nestjs/common'; -import { createMock, type DeepMocked } from '@golevelup/ts-jest'; +import { + afterEach, + beforeEach, + describe, + expect, + it, + type Mock, + vi, +} from 'vitest'; +import { mockDeep, type MockProxy } from 'vitest-mock-extended'; +import { type ConfigService } from '@nestjs/config'; import { RedisService } from './redis.service'; import { createClient } from 'redis'; +import { mockLogger } from '../../../test/helpers/mocker.helper'; -jest.mock('redis', () => ({ - createClient: jest.fn(), +vi.mock('redis', () => ({ + createClient: vi.fn(), })); describe('RedisService', () => { let service: RedisService; - let configService: DeepMocked; + let configService: MockProxy; let mockRedisClient: any; beforeEach(async () => { + mockLogger(); + configService = mockDeep(); + mockRedisClient = { - connect: jest.fn(), - quit: jest.fn(), - disconnect: jest.fn(), - on: jest.fn(), - set: jest.fn(), - del: jest.fn(), + connect: vi.fn(), + quit: vi.fn(), + disconnect: vi.fn(), + on: vi.fn(), + set: vi.fn(), + del: vi.fn(), isReady: false, isOpen: false, }; - (createClient as jest.Mock).mockReturnValue(mockRedisClient); - - const moduleRef = await Test.createTestingModule({ - providers: [RedisService], - }) - .setLogger(createMock()) - .useMocker(() => createMock()) - .compile(); + (createClient as Mock).mockReturnValue(mockRedisClient); - service = moduleRef.get(RedisService); - configService = moduleRef.get(ConfigService); + service = new RedisService(configService); }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('should be defined', () => { @@ -71,7 +74,7 @@ describe('RedisService', () => { configService.get.mockReturnValue(redisUrl); mockRedisClient.connect.mockRejectedValue(connectionError); - const loggerErrorSpy = jest.spyOn(service['logger'], 'error'); + const loggerErrorSpy = vi.spyOn(service['logger'], 'error'); await expect(service.getClient()).rejects.toThrow(); @@ -94,17 +97,15 @@ describe('RedisService', () => { describe('onModuleDestroy', () => { beforeEach(async () => { - jest - .spyOn(configService, 'get') - .mockReturnValue('redis://localhost:6379'); - jest.spyOn(mockRedisClient, 'connect').mockResolvedValue(undefined); + configService.get.mockImplementation(() => 'redis://localhost:6379'); + vi.spyOn(mockRedisClient, 'connect').mockResolvedValue(undefined); mockRedisClient.isReady = true; await service.getClient(); }); it('When module is destroyed and client is open, then it should quit the redis connection', async () => { mockRedisClient.isOpen = true; - jest.spyOn(mockRedisClient, 'quit').mockResolvedValue(undefined); + vi.spyOn(mockRedisClient, 'quit').mockResolvedValue(undefined); await service.onModuleDestroy(); @@ -113,7 +114,7 @@ describe('RedisService', () => { it('When module is destroyed and client is not open, then it should not call quit', async () => { mockRedisClient.isOpen = false; - const quitSpy = jest.spyOn(mockRedisClient, 'quit'); + const quitSpy = vi.spyOn(mockRedisClient, 'quit'); await service.onModuleDestroy(); @@ -129,10 +130,8 @@ describe('RedisService', () => { describe('tryAcquireLock', () => { beforeEach(async () => { - jest - .spyOn(configService, 'get') - .mockReturnValue('redis://localhost:6379'); - jest.spyOn(mockRedisClient, 'connect').mockResolvedValue(undefined); + configService.get.mockImplementation(() => 'redis://localhost:6379'); + vi.spyOn(mockRedisClient, 'connect').mockResolvedValue(undefined); mockRedisClient.isReady = true; await service.getClient(); }); @@ -141,7 +140,7 @@ describe('RedisService', () => { const key = 'test-lock'; const ttlMs = 5000; - jest.spyOn(mockRedisClient, 'set').mockResolvedValue('OK'); + vi.spyOn(mockRedisClient, 'set').mockResolvedValue('OK'); const result = await service.tryAcquireLock(key, ttlMs); @@ -156,7 +155,7 @@ describe('RedisService', () => { const key = 'test-lock'; const ttlMs = 5000; - jest.spyOn(mockRedisClient, 'set').mockResolvedValue(null); + vi.spyOn(mockRedisClient, 'set').mockResolvedValue(null); const result = await service.tryAcquireLock(key, ttlMs); @@ -172,7 +171,7 @@ describe('RedisService', () => { const ttlMs = 5000; const customValue = 'custom-lock-value'; - jest.spyOn(mockRedisClient, 'set').mockResolvedValue('OK'); + vi.spyOn(mockRedisClient, 'set').mockResolvedValue('OK'); const result = await service.tryAcquireLock(key, ttlMs, customValue); diff --git a/src/lib/convert-size-to-bytes.spec.ts b/src/lib/convert-size-to-bytes.spec.ts index e352e3352..f2f14979f 100644 --- a/src/lib/convert-size-to-bytes.spec.ts +++ b/src/lib/convert-size-to-bytes.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { convertSizeToBytes } from './convert-size-to-bytes'; describe('convertSizeToBytes function', () => { diff --git a/src/lib/import-esm-package.ts b/src/lib/import-esm-package.ts deleted file mode 100644 index f9de1a381..000000000 --- a/src/lib/import-esm-package.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Dynamically imports an ESM package in a CommonJS NestJS project, - * avoiding TypeScript transpilation to `require()`, which ESM packages do not support. - */ - -export const importEsmPackage = async ( - packageName: string, -): Promise => { - try { - const modulePromise = eval(`import('${packageName}')`); - const module = await modulePromise; - - return (module.default ?? module) as ReturnType; - } catch (error) { - console.error(`Error importing ESM package ${packageName}:`, error); - throw error; - } -}; diff --git a/src/lib/path.spec.ts b/src/lib/path.spec.ts index 6b526bea8..695186cb5 100644 --- a/src/lib/path.spec.ts +++ b/src/lib/path.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import * as service from './path'; describe('Path class', () => { diff --git a/src/lib/time.spec.ts b/src/lib/time.spec.ts index adc1405c5..6032736b4 100644 --- a/src/lib/time.spec.ts +++ b/src/lib/time.spec.ts @@ -1,15 +1,16 @@ +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; import { Time } from './time'; describe('Time class', () => { const fixedSystemCurrentDate = new Date('2022-01-01'); beforeAll(() => { - jest.useFakeTimers(); - jest.setSystemTime(fixedSystemCurrentDate); + vi.useFakeTimers(); + vi.setSystemTime(fixedSystemCurrentDate); }); afterAll(() => { - jest.useRealTimers(); + vi.useRealTimers(); }); describe('now()', () => { diff --git a/src/middlewares/passport.spec.ts b/src/middlewares/passport.spec.ts index 9f40397d0..2cc9566b9 100644 --- a/src/middlewares/passport.spec.ts +++ b/src/middlewares/passport.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import jwt from 'jsonwebtoken'; import { SignEmail, diff --git a/src/modules/app-sumo/app-sumo.usecase.spec.ts b/src/modules/app-sumo/app-sumo.usecase.spec.ts index 238596780..e78361456 100644 --- a/src/modules/app-sumo/app-sumo.usecase.spec.ts +++ b/src/modules/app-sumo/app-sumo.usecase.spec.ts @@ -1,24 +1,25 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mockDeep, type MockProxy } from 'vitest-mock-extended'; import { AppSumoUseCase } from './app-sumo.usecase'; import { type SequelizeAppSumoRepository } from './app-sumo.repository'; import { type SequelizePlanRepository } from '../plan/plan.repository'; import { type AppSumoModel } from './app-sumo.model'; import { PlanNotFoundException } from '../plan/exception/plan-not-found.exception'; -import { type DeepMocked, createMock } from '@golevelup/ts-jest'; import { type PlanModel } from '../plan/plan.model'; describe('AppSumoUseCase', () => { let useCase: AppSumoUseCase; - let appSumoRepository: DeepMocked; - let planRepository: DeepMocked; - let appSumo: DeepMocked; - let plan: DeepMocked; + let appSumoRepository: MockProxy; + let planRepository: MockProxy; + let appSumo: MockProxy; + let plan: MockProxy; - beforeEach(async () => { - appSumo = createMock(); - plan = createMock(); + beforeEach(() => { + appSumo = mockDeep(); + plan = mockDeep(); - appSumoRepository = createMock(); - planRepository = createMock(); + appSumoRepository = mockDeep(); + planRepository = mockDeep(); useCase = new AppSumoUseCase(appSumoRepository, planRepository); @@ -64,7 +65,7 @@ describe('AppSumoUseCase', () => { new PlanNotFoundException('Plan not found'), ); - const errorLogSpy = jest.spyOn(useCase['logger'], 'log'); + const errorLogSpy = vi.spyOn(useCase['logger'], 'log'); try { await useCase.getByUserId(userId); diff --git a/src/modules/auth/auth.controller.spec.ts b/src/modules/auth/auth.controller.spec.ts index 63effb1dd..cf6a0a29e 100644 --- a/src/modules/auth/auth.controller.spec.ts +++ b/src/modules/auth/auth.controller.spec.ts @@ -1,51 +1,56 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended'; import { newKeyServer, newUser } from './../../../test/fixtures'; import { AuthController } from './auth.controller'; -import { UserUseCases } from '../user/user.usecase'; -import { KeyServerUseCases } from '../keyserver/key-server.usecase'; -import { CryptoService } from '../../externals/crypto/crypto.service'; +import { type UserUseCases } from '../user/user.usecase'; +import { type KeyServerUseCases } from '../keyserver/key-server.usecase'; +import { type CryptoService } from '../../externals/crypto/crypto.service'; import { LoginDto } from './dto/login-dto'; import { LoginAccessDto } from './dto/login-access.dto'; import { BadRequestException, ConflictException, - type Logger, NotFoundException, UnauthorizedException, } from '@nestjs/common'; -import { type DeepMocked, createMock } from '@golevelup/ts-jest'; import { v4 } from 'uuid'; -import { TwoFactorAuthService } from './two-factor-auth.service'; +import { type TwoFactorAuthService } from './two-factor-auth.service'; import { type GeneratedSecret } from 'speakeasy'; import { UpdateTfaDto } from './dto/update-tfa.dto'; import { DeleteTfaDto } from './dto/delete-tfa.dto'; import { UserKeysEncryptVersions } from '../keyserver/key-server.domain'; -import { Test } from '@nestjs/testing'; -import { FeatureLimitService } from '../feature-limit/feature-limit.service'; +import { type FeatureLimitService } from '../feature-limit/feature-limit.service'; import { PaymentRequiredException } from '../feature-limit/exceptions/payment-required.exception'; import { PlatformName } from '../../common/constants'; import { ClientEnum } from '../../common/enums/platform.enum'; +import { type AuthUsecases } from './auth.usecase'; +import { mockLogger } from '../../../test/helpers/mocker.helper'; describe('AuthController', () => { let authController: AuthController; - let userUseCases: DeepMocked; - let keyServerUseCases: DeepMocked; - let cryptoService: DeepMocked; - let twoFactorAuthService: DeepMocked; - let featureLimitService: DeepMocked; + let userUseCases: DeepMockProxy; + let keyServerUseCases: DeepMockProxy; + let cryptoService: DeepMockProxy; + let twoFactorAuthService: DeepMockProxy; + let featureLimitService: DeepMockProxy; beforeEach(async () => { - const moduleRef = await Test.createTestingModule({ - controllers: [AuthController], - }) - .setLogger(createMock()) - .useMocker(() => createMock()) - .compile(); - authController = moduleRef.get(AuthController); - userUseCases = moduleRef.get(UserUseCases); - keyServerUseCases = moduleRef.get(KeyServerUseCases); - cryptoService = moduleRef.get(CryptoService); - twoFactorAuthService = moduleRef.get(TwoFactorAuthService); - featureLimitService = moduleRef.get(FeatureLimitService); + userUseCases = mockDeep(); + keyServerUseCases = mockDeep(); + cryptoService = mockDeep(); + twoFactorAuthService = mockDeep(); + featureLimitService = mockDeep(); + const authUseCases = mockDeep(); + + authController = new AuthController( + userUseCases, + keyServerUseCases, + cryptoService, + twoFactorAuthService, + authUseCases, + featureLimitService, + ); + mockLogger(); }); it('should be defined', () => { @@ -67,11 +72,12 @@ describe('AuthController', () => { encryptVersion: UserKeysEncryptVersions.Kyber, }); - jest.spyOn(userUseCases, 'findByEmail').mockResolvedValueOnce(user); - jest - .spyOn(keyServerUseCases, 'findUserKeys') - .mockResolvedValueOnce({ ecc: eccKeys, kyber: kyberKeys }); - jest.spyOn(cryptoService, 'encryptText').mockReturnValue('encryptedText'); + userUseCases.findByEmail.mockResolvedValueOnce(user); + keyServerUseCases.findUserKeys.mockResolvedValueOnce({ + ecc: eccKeys, + kyber: kyberKeys, + }); + cryptoService.encryptText.mockReturnValue('encryptedText'); const result = await authController.login(loginDto); @@ -88,7 +94,7 @@ describe('AuthController', () => { const loginDto = new LoginDto(); loginDto.email = 'test@example.com'; - jest.spyOn(userUseCases, 'findByEmail').mockResolvedValueOnce(null); + userUseCases.findByEmail.mockResolvedValueOnce(null); await expect(authController.login(loginDto)).rejects.toThrow( new UnauthorizedException('Wrong login credentials'), @@ -99,8 +105,17 @@ describe('AuthController', () => { const body = { email: 'TEST@EXAMPLE.COM' }; const emailLowerCase = 'test@example.com'; const user = newUser({ attributes: { email: emailLowerCase } }); + const eccKeys = newKeyServer({ userId: user.id }); + const kyberKeys = newKeyServer({ + userId: user.id, + encryptVersion: UserKeysEncryptVersions.Kyber, + }); - jest.spyOn(userUseCases, 'findByEmail').mockResolvedValue(user); + userUseCases.findByEmail.mockResolvedValueOnce(user); + keyServerUseCases.findUserKeys.mockResolvedValueOnce({ + ecc: eccKeys, + kyber: kyberKeys, + }); await authController.login(body); @@ -119,14 +134,14 @@ describe('AuthController', () => { it('When valid login access details are provided, then it should return the result of loginAccess', async () => { const eccKey = newKeyServer({ ...loginAccessDto }); - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: null, }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce({ success: true } as any); + userUseCases.loginAccess.mockResolvedValueOnce({ + success: true, + } as any); const result = await authController.loginAccess(loginAccessDto); @@ -146,12 +161,17 @@ describe('AuthController', () => { }); it('When an error occurs during login access, then it should throw an error', async () => { - userUseCases.loginAccess = jest - .fn() - .mockRejectedValue(new Error('Login access error')); + const eccKey = newKeyServer({ ...loginAccessDto }); + const expectedError = new Error('Login access error'); + + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ + ecc: eccKey.toJSON(), + kyber: null, + }); + userUseCases.loginAccess.mockRejectedValue(expectedError); await expect(authController.loginAccess(loginAccessDto)).rejects.toThrow( - Error, + expectedError, ); }); @@ -171,13 +191,11 @@ describe('AuthController', () => { }, }; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: kyberKey.toJSON(), }); - jest.spyOn(userUseCases, 'loginAccess'); - await authController.loginAccess(inputWithKyberKeys); expect(userUseCases.loginAccess).toHaveBeenCalledWith({ @@ -217,12 +235,10 @@ describe('AuthController', () => { google_auth_qr: null, }; - jest - .spyOn(twoFactorAuthService, 'generateTwoFactorAuthSecret') - .mockResolvedValueOnce({ - secret: mockGeneratedSecret, - qrCode: qrCode, - }); + twoFactorAuthService.generateTwoFactorAuthSecret.mockResolvedValueOnce({ + secret: mockGeneratedSecret, + qrCode: qrCode, + }); const result = await authController.getTfa(user); @@ -246,10 +262,8 @@ describe('AuthController', () => { updateTfaDto.key = 'key'; updateTfaDto.code = 'code'; - jest - .spyOn(twoFactorAuthService, 'validateTwoFactorAuthCode') - .mockReturnValueOnce(true); - jest.spyOn(userUseCases, 'updateByUuid').mockResolvedValueOnce(); + twoFactorAuthService.validateTwoFactorAuthCode.mockReturnValueOnce(true); + userUseCases.updateByUuid.mockResolvedValueOnce(); const result = await authController.putTfa(user, updateTfaDto); @@ -276,13 +290,14 @@ describe('AuthController', () => { deleteTfaDto.code = 'code'; deleteTfaDto.pass = 'pass'; - const validateTfaSpy = jest - .spyOn(twoFactorAuthService, 'validateTwoFactorAuthCode') - .mockReturnValueOnce(true); - const decryptPasswordSpy = jest - .spyOn(cryptoService, 'decryptText') - .mockReturnValueOnce(user.password); - jest.spyOn(userUseCases, 'updateByUuid').mockResolvedValueOnce(); + const validateTfaSpy = + twoFactorAuthService.validateTwoFactorAuthCode.mockReturnValueOnce( + true, + ); + const decryptPasswordSpy = cryptoService.decryptText.mockReturnValueOnce( + user.password, + ); + userUseCases.updateByUuid.mockResolvedValueOnce(); const result = await authController.deleteTfa(user, deleteTfaDto); @@ -298,14 +313,9 @@ describe('AuthController', () => { const deleteTfaDto = new DeleteTfaDto(); deleteTfaDto.pass = 'pass'; - const validateTfaSpy = jest.spyOn( - twoFactorAuthService, - 'validateTwoFactorAuthCode', - ); - jest - .spyOn(cryptoService, 'decryptText') - .mockReturnValueOnce(user.password); - jest.spyOn(userUseCases, 'updateByUuid').mockResolvedValueOnce(); + const validateTfaSpy = twoFactorAuthService.validateTwoFactorAuthCode; + cryptoService.decryptText.mockReturnValueOnce(user.password); + userUseCases.updateByUuid.mockResolvedValueOnce(); const result = await authController.deleteTfa(user, deleteTfaDto); @@ -320,11 +330,9 @@ describe('AuthController', () => { const deleteTfaDto = new DeleteTfaDto(); deleteTfaDto.code = 'code'; - jest - .spyOn(twoFactorAuthService, 'validateTwoFactorAuthCode') - .mockReturnValueOnce(true); - const decryptPasswordSpy = jest.spyOn(cryptoService, 'decryptText'); - jest.spyOn(userUseCases, 'updateByUuid').mockResolvedValueOnce(); + twoFactorAuthService.validateTwoFactorAuthCode.mockReturnValueOnce(true); + const decryptPasswordSpy = cryptoService.decryptText; + userUseCases.updateByUuid.mockResolvedValueOnce(); const result = await authController.deleteTfa(user, deleteTfaDto); @@ -363,12 +371,8 @@ describe('AuthController', () => { deleteTfaDto.code = 'code'; deleteTfaDto.pass = 'invalid-pass'; - jest - .spyOn(twoFactorAuthService, 'validateTwoFactorAuthCode') - .mockReturnValueOnce(true); - jest - .spyOn(cryptoService, 'decryptText') - .mockReturnValueOnce('invalid-password'); + twoFactorAuthService.validateTwoFactorAuthCode.mockReturnValueOnce(true); + cryptoService.decryptText.mockReturnValueOnce('invalid-password'); await expect( authController.deleteTfa(user, deleteTfaDto), @@ -381,8 +385,6 @@ describe('AuthController', () => { const hashedPassword = '$2b$12$qEwggJIve0bWR4GRCb7KXuF0aKi5GI8vfvf'; const user = newUser(); - jest.spyOn(userUseCases, 'areCredentialsCorrect'); - await authController.areCredentialsCorrect(user, { hashedPassword, }); @@ -411,18 +413,14 @@ describe('AuthController', () => { newToken: 'new-jwt-token', } as any; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: null, }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce(mockLoginResult); + userUseCases.loginAccess.mockResolvedValueOnce(mockLoginResult); - jest - .spyOn(featureLimitService, 'canUserAccessPlatform') - .mockResolvedValueOnce(true); + featureLimitService.canUserAccessPlatform.mockResolvedValueOnce(true); const result = await authController.cliLoginAccess( loginAccessDto, @@ -457,18 +455,14 @@ describe('AuthController', () => { newToken: 'new-jwt-token', } as any; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: null, }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce(mockLoginResult); + userUseCases.loginAccess.mockResolvedValueOnce(mockLoginResult); - jest - .spyOn(featureLimitService, 'canUserAccessPlatform') - .mockResolvedValueOnce(true); + featureLimitService.canUserAccessPlatform.mockResolvedValueOnce(true); const result = await authController.cliLoginAccess( loginAccessDto, @@ -503,18 +497,14 @@ describe('AuthController', () => { newToken: 'new-jwt-token', } as any; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: null, }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce(mockLoginResult); + userUseCases.loginAccess.mockResolvedValueOnce(mockLoginResult); - jest - .spyOn(featureLimitService, 'canUserAccessPlatform') - .mockResolvedValueOnce(true); + featureLimitService.canUserAccessPlatform.mockResolvedValueOnce(true); const result = await authController.cliLoginAccess( loginAccessDto, @@ -549,18 +539,14 @@ describe('AuthController', () => { token: 'jwt-token', } as any; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: null, }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce(mockLoginResult); + userUseCases.loginAccess.mockResolvedValueOnce(mockLoginResult); - jest - .spyOn(featureLimitService, 'canUserAccessPlatform') - .mockResolvedValueOnce(false); + featureLimitService.canUserAccessPlatform.mockResolvedValueOnce(false); await expect( authController.cliLoginAccess(loginAccessDto, ClientEnum.Cli), @@ -581,18 +567,14 @@ describe('AuthController', () => { token: 'jwt-token', } as any; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: null, }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce(mockLoginResult); + userUseCases.loginAccess.mockResolvedValueOnce(mockLoginResult); - jest - .spyOn(featureLimitService, 'canUserAccessPlatform') - .mockResolvedValueOnce(false); + featureLimitService.canUserAccessPlatform.mockResolvedValueOnce(false); await expect( authController.cliLoginAccess(loginAccessDto, ClientEnum.Rclone), @@ -626,18 +608,14 @@ describe('AuthController', () => { }, }; - jest.spyOn(keyServerUseCases, 'parseKeysInput').mockReturnValueOnce({ + keyServerUseCases.parseKeysInput.mockReturnValueOnce({ ecc: eccKey.toJSON(), kyber: kyberKey.toJSON(), }); - jest - .spyOn(userUseCases, 'loginAccess') - .mockResolvedValueOnce(mockLoginResult); + userUseCases.loginAccess.mockResolvedValueOnce(mockLoginResult); - jest - .spyOn(featureLimitService, 'canUserAccessPlatform') - .mockResolvedValueOnce(true); + featureLimitService.canUserAccessPlatform.mockResolvedValueOnce(true); await authController.cliLoginAccess(inputWithKyberKeys, ClientEnum.Cli); diff --git a/src/modules/auth/auth.e2e-spec.ts b/src/modules/auth/auth.e2e-spec.ts index b33c89773..1d07e88d3 100644 --- a/src/modules/auth/auth.e2e-spec.ts +++ b/src/modules/auth/auth.e2e-spec.ts @@ -1,3 +1,4 @@ +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; import { HttpStatus } from '@nestjs/common'; import { type NestExpressApplication } from '@nestjs/platform-express'; import { getModelToken } from '@nestjs/sequelize'; diff --git a/src/modules/auth/auth.usecase.spec.ts b/src/modules/auth/auth.usecase.spec.ts index b92673dd5..d6b8a09bd 100644 --- a/src/modules/auth/auth.usecase.spec.ts +++ b/src/modules/auth/auth.usecase.spec.ts @@ -1,43 +1,38 @@ -import { Test, type TestingModule } from '@nestjs/testing'; -import { JwtService } from '@nestjs/jwt'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended'; +import { type JwtService } from '@nestjs/jwt'; import { AuthUsecases } from './auth.usecase'; -import { CacheManagerService } from '../cache-manager/cache-manager.service'; -import { createMock } from '@golevelup/ts-jest'; +import { type CacheManagerService } from '../cache-manager/cache-manager.service'; import { v4 } from 'uuid'; -describe('AuthUsecases', () => { - let usecases: AuthUsecases; - let jwtService: JwtService; - let cacheManagerService: CacheManagerService; +describe('AuthUsecase', () => { + let authUsecase: AuthUsecases; + let jwtService: DeepMockProxy; + let cacheManagerService: DeepMockProxy; const mockJwtToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.token'; beforeEach(async () => { - const moduleRef: TestingModule = await Test.createTestingModule({ - providers: [AuthUsecases], - }) - .useMocker(createMock) - .compile(); - - usecases = moduleRef.get(AuthUsecases); - jwtService = moduleRef.get(JwtService); - cacheManagerService = - moduleRef.get(CacheManagerService); + jwtService = mockDeep(); + cacheManagerService = mockDeep(); + + authUsecase = new AuthUsecases(cacheManagerService, jwtService); }); it('When tests are started, then it should be defined', () => { - expect(usecases).toBeDefined(); + expect(authUsecase).toBeDefined(); expect(jwtService).toBeDefined(); expect(cacheManagerService).toBeDefined(); }); describe('logout use case', () => { beforeEach(() => { - jest.spyOn(Date, 'now').mockReturnValue(1640995200000); // 2022-01-01 00:00:00 + vi.useFakeTimers(); + vi.setSystemTime(1640995200000); // 2022-01-01 00:00:00 }); afterEach(() => { - jest.restoreAllMocks(); + vi.useRealTimers(); }); it('When valid JWT with jti and exp is provided, then token should be blacklisted', async () => { @@ -47,10 +42,10 @@ describe('AuthUsecases', () => { }; const expectedTtl = 600; // 10 minutes - jest.spyOn(jwtService, 'decode').mockReturnValue(mockTokenClaims); - jest.spyOn(cacheManagerService, 'blacklistJwt').mockResolvedValue(true); + jwtService.decode.mockReturnValue(mockTokenClaims); + cacheManagerService.blacklistJwt.mockResolvedValue(true); - await usecases.logout(mockJwtToken); + await authUsecase.logout(mockJwtToken); expect(jwtService.decode).toHaveBeenCalledWith(mockJwtToken); expect(cacheManagerService.blacklistJwt).toHaveBeenCalledWith( @@ -61,13 +56,12 @@ describe('AuthUsecases', () => { it('When JWT has no jti claim, then token should not be blacklisted', async () => { const mockTokenClaims = { - exp: 1640995800, + exp: 1640995800, // 10 minutes from now }; - jest.spyOn(jwtService, 'decode').mockReturnValue(mockTokenClaims); - jest.spyOn(cacheManagerService, 'blacklistJwt'); + jwtService.decode.mockReturnValue(mockTokenClaims); - await usecases.logout(mockJwtToken); + await authUsecase.logout(mockJwtToken); expect(jwtService.decode).toHaveBeenCalledWith(mockJwtToken); expect(cacheManagerService.blacklistJwt).not.toHaveBeenCalled(); @@ -78,10 +72,9 @@ describe('AuthUsecases', () => { jti: v4(), }; - jest.spyOn(jwtService, 'decode').mockReturnValue(mockTokenClaims); - jest.spyOn(cacheManagerService, 'blacklistJwt'); + jwtService.decode.mockReturnValue(mockTokenClaims); - await usecases.logout(mockJwtToken); + await authUsecase.logout(mockJwtToken); expect(jwtService.decode).toHaveBeenCalledWith(mockJwtToken); expect(cacheManagerService.blacklistJwt).not.toHaveBeenCalled(); @@ -93,20 +86,18 @@ describe('AuthUsecases', () => { exp: 1640994600, // 10 minutes ago }; - jest.spyOn(jwtService, 'decode').mockReturnValue(mockTokenClaims); - jest.spyOn(cacheManagerService, 'blacklistJwt'); + jwtService.decode.mockReturnValue(mockTokenClaims); - await usecases.logout(mockJwtToken); + await authUsecase.logout(mockJwtToken); expect(jwtService.decode).toHaveBeenCalledWith(mockJwtToken); expect(cacheManagerService.blacklistJwt).not.toHaveBeenCalled(); }); it('When JWT decode returns nothing, then token should not be blacklisted', async () => { - jest.spyOn(jwtService, 'decode').mockReturnValue(null); - jest.spyOn(cacheManagerService, 'blacklistJwt'); + jwtService.decode.mockReturnValue(null); - await usecases.logout(mockJwtToken); + await authUsecase.logout(mockJwtToken); expect(jwtService.decode).toHaveBeenCalledWith(mockJwtToken); expect(cacheManagerService.blacklistJwt).not.toHaveBeenCalled(); @@ -118,10 +109,9 @@ describe('AuthUsecases', () => { exp: 1640995200, }; - jest.spyOn(jwtService, 'decode').mockReturnValue(mockTokenClaims); - jest.spyOn(cacheManagerService, 'blacklistJwt'); + jwtService.decode.mockReturnValue(mockTokenClaims); - await usecases.logout(mockJwtToken); + await authUsecase.logout(mockJwtToken); expect(jwtService.decode).toHaveBeenCalledWith(mockJwtToken); expect(cacheManagerService.blacklistJwt).not.toHaveBeenCalled(); diff --git a/src/modules/auth/conditional-captcha.guard.spec.ts b/src/modules/auth/conditional-captcha.guard.spec.ts index 8a06171ea..2c64a04e4 100644 --- a/src/modules/auth/conditional-captcha.guard.spec.ts +++ b/src/modules/auth/conditional-captcha.guard.spec.ts @@ -1,4 +1,5 @@ -import { createMock, type DeepMocked } from '@golevelup/ts-jest'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended'; import { ConditionalCaptchaGuard } from './conditional-captcha.guard'; import { type UserUseCases } from '../user/user.usecase'; import { type CaptchaService } from '../../externals/captcha/captcha.service'; @@ -14,12 +15,12 @@ import { ClientHeaders } from '../../common/decorators/client.decorator'; describe('ConditionalCaptchaGuard', () => { let guard: ConditionalCaptchaGuard; - let userUseCase: DeepMocked; - let captchaService: DeepMocked; + let userUseCase: DeepMockProxy; + let captchaService: DeepMockProxy; beforeEach(() => { - userUseCase = createMock(); - captchaService = createMock(); + userUseCase = mockDeep(); + captchaService = mockDeep(); guard = new ConditionalCaptchaGuard(userUseCase, captchaService); }); @@ -54,10 +55,10 @@ describe('ConditionalCaptchaGuard', () => { ip: '127.0.0.1', }); - const captchaServiceSpy = jest.spyOn(captchaService, 'verifyCaptcha'); - jest - .spyOn(userUseCase, 'findByEmail') - .mockResolvedValue(buildUserWithErrorLoginCount(0)); + const captchaServiceSpy = captchaService.verifyCaptcha; + userUseCase.findByEmail.mockResolvedValue( + buildUserWithErrorLoginCount(0), + ); const canUserLogin = await guard.canActivate(context); @@ -78,10 +79,10 @@ describe('ConditionalCaptchaGuard', () => { ip: '127.0.0.1', }); - jest - .spyOn(userUseCase, 'findByEmail') - .mockResolvedValue(buildUserWithErrorLoginCount(6)); - const captchaServiceSpy = jest.spyOn(captchaService, 'verifyCaptcha'); + userUseCase.findByEmail.mockResolvedValue( + buildUserWithErrorLoginCount(6), + ); + const captchaServiceSpy = captchaService.verifyCaptcha; await expect(guard.canActivate(context)).rejects.toThrow( ForbiddenException, @@ -103,10 +104,10 @@ describe('ConditionalCaptchaGuard', () => { ip: '127.0.0.1', }); - jest - .spyOn(userUseCase, 'findByEmail') - .mockResolvedValue(buildUserWithErrorLoginCount(6)); - jest.spyOn(captchaService, 'verifyCaptcha').mockResolvedValue(false); + userUseCase.findByEmail.mockResolvedValue( + buildUserWithErrorLoginCount(6), + ); + captchaService.verifyCaptcha.mockResolvedValue(false); await expect(guard.canActivate(context)).rejects.toThrow( UnauthorizedException, @@ -126,12 +127,11 @@ describe('ConditionalCaptchaGuard', () => { ip: '127.0.0.1', }); - jest - .spyOn(userUseCase, 'findByEmail') - .mockResolvedValue(buildUserWithErrorLoginCount(6)); - const captchaServiceSpy = jest - .spyOn(captchaService, 'verifyCaptcha') - .mockResolvedValue(true); + userUseCase.findByEmail.mockResolvedValue( + buildUserWithErrorLoginCount(6), + ); + const captchaServiceSpy = + captchaService.verifyCaptcha.mockResolvedValue(true); const canActivate = await guard.canActivate(context); @@ -154,9 +154,9 @@ describe('ConditionalCaptchaGuard', () => { ip: '127.0.0.1', }); - jest - .spyOn(userUseCase, 'findByEmail') - .mockResolvedValue(buildUserWithErrorLoginCount(6)); + userUseCase.findByEmail.mockResolvedValue( + buildUserWithErrorLoginCount(6), + ); await expect(guard.canActivate(context)).rejects.toThrow( ForbiddenException, @@ -176,12 +176,11 @@ describe('ConditionalCaptchaGuard', () => { ip: '127.0.0.1', }); - jest - .spyOn(userUseCase, 'findByEmail') - .mockResolvedValue(buildUserWithErrorLoginCount(6)); - const captchaServiceSpy = jest - .spyOn(captchaService, 'verifyCaptcha') - .mockResolvedValue(true); + userUseCase.findByEmail.mockResolvedValue( + buildUserWithErrorLoginCount(6), + ); + const captchaServiceSpy = + captchaService.verifyCaptcha.mockResolvedValue(true); await guard.canActivate(context); diff --git a/src/modules/auth/decorators/get-jwt.decorator.spec.ts b/src/modules/auth/decorators/get-jwt.decorator.spec.ts index 9b7d9ae67..f1ce053d5 100644 --- a/src/modules/auth/decorators/get-jwt.decorator.spec.ts +++ b/src/modules/auth/decorators/get-jwt.decorator.spec.ts @@ -1,24 +1,21 @@ +import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import { type ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { jwtDecoratorFactory } from './get-jwt.decorator'; describe('jwtDecoratorFactory', () => { - let mockGetRequest: jest.Mock; + let mockGetRequest: Mock; beforeEach(() => { - mockGetRequest = jest.fn(); + mockGetRequest = vi.fn(); }); const createMockExecutionContext = (req: any): ExecutionContext => ({ - switchToHttp: jest.fn().mockReturnValue({ + switchToHttp: vi.fn().mockReturnValue({ getRequest: mockGetRequest.mockReturnValue(req), }), }) as unknown as ExecutionContext; - afterEach(() => { - jest.clearAllMocks(); - }); - it('When authorization header contains valid Bearer token, it should return the token', () => { const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30'; diff --git a/src/modules/auth/decorators/requester.decorator.spec.ts b/src/modules/auth/decorators/requester.decorator.spec.ts index c0680e850..b34dd23ab 100644 --- a/src/modules/auth/decorators/requester.decorator.spec.ts +++ b/src/modules/auth/decorators/requester.decorator.spec.ts @@ -1,22 +1,31 @@ +import { + afterEach, + beforeEach, + describe, + expect, + it, + type Mock, + vi, +} from 'vitest'; import { type ExecutionContext } from '@nestjs/common'; import { requesterFactory } from './requester.decorator'; describe('requesterFactory', () => { - let mockGetRequest: jest.Mock; + let mockGetRequest: Mock; beforeEach(() => { - mockGetRequest = jest.fn(); + mockGetRequest = vi.fn(); }); const createMockExecutionContext = (req: any): ExecutionContext => ({ - switchToHttp: jest.fn().mockReturnValue({ + switchToHttp: vi.fn().mockReturnValue({ getRequest: mockGetRequest.mockReturnValue(req), }), }) as unknown as ExecutionContext; afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('When requester is present, it should return requester', () => { diff --git a/src/modules/auth/decorators/user-tier.decorator.spec.ts b/src/modules/auth/decorators/user-tier.decorator.spec.ts index df8f7bae2..997c54ed4 100644 --- a/src/modules/auth/decorators/user-tier.decorator.spec.ts +++ b/src/modules/auth/decorators/user-tier.decorator.spec.ts @@ -1,25 +1,22 @@ +import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import { type ExecutionContext } from '@nestjs/common'; import { userTierFactory } from './user-tier.decorator'; import { v4 } from 'uuid'; describe('userTierFactory', () => { - let mockGetRequest: jest.Mock; + let mockGetRequest: Mock; beforeEach(() => { - mockGetRequest = jest.fn(); + mockGetRequest = vi.fn(); }); const createMockExecutionContext = (req): ExecutionContext => ({ - switchToHttp: jest.fn().mockReturnValue({ + switchToHttp: vi.fn().mockReturnValue({ getRequest: mockGetRequest.mockReturnValue(req), }), }) as unknown as ExecutionContext; - afterEach(() => { - jest.clearAllMocks(); - }); - it('When authInfo has tier, then return tier object', () => { const mockTier = { id: v4(), diff --git a/src/modules/auth/dto/delete-tfa.dto.spec.ts b/src/modules/auth/dto/delete-tfa.dto.spec.ts index eceb762c0..e66f2aa62 100644 --- a/src/modules/auth/dto/delete-tfa.dto.spec.ts +++ b/src/modules/auth/dto/delete-tfa.dto.spec.ts @@ -1,3 +1,4 @@ +import { describe, expect, it } from 'vitest'; import { validate } from 'class-validator'; import { plainToInstance } from 'class-transformer'; import { DeleteTfaDto } from './delete-tfa.dto'; diff --git a/src/modules/auth/interceptors/timing-consistency.interceptor.spec.ts b/src/modules/auth/interceptors/timing-consistency.interceptor.spec.ts index 3d6ed6e58..e7b2bfc2a 100644 --- a/src/modules/auth/interceptors/timing-consistency.interceptor.spec.ts +++ b/src/modules/auth/interceptors/timing-consistency.interceptor.spec.ts @@ -1,7 +1,8 @@ -import { createMock } from '@golevelup/ts-jest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended'; import { type ExecutionContext, type CallHandler } from '@nestjs/common'; import { type Reflector } from '@nestjs/core'; -import { of } from 'rxjs'; +import { lastValueFrom, of } from 'rxjs'; import { delay } from 'rxjs/operators'; import { TimingConsistencyInterceptor } from './timing-consistency.interceptor'; import { @@ -11,10 +12,10 @@ import { describe('TimingConsistencyInterceptor', () => { let interceptor: TimingConsistencyInterceptor; - let reflector: Reflector; + let reflector: DeepMockProxy; beforeEach(() => { - reflector = createMock(); + reflector = mockDeep(); interceptor = new TimingConsistencyInterceptor(reflector); }); @@ -23,12 +24,12 @@ describe('TimingConsistencyInterceptor', () => { }); it('should pass through when no timing options are set', () => { - const context = createMock(); - const next = createMock(); + const context = mockDeep(); + const next = mockDeep(); const testData = { test: 'data' }; - jest.spyOn(reflector, 'get').mockReturnValue(undefined); - jest.spyOn(next, 'handle').mockReturnValue(of(testData)); + reflector.get.mockReturnValue(undefined); + next.handle.mockReturnValue(of(testData)); const result$ = interceptor.intercept(context, next); @@ -42,60 +43,47 @@ describe('TimingConsistencyInterceptor', () => { ); }); - it('should add delay when response is faster than minimum time', (done) => { - const context = createMock(); - const next = createMock(); + it('should add delay when response is faster than minimum time', async () => { + const context = mockDeep(); + const next = mockDeep(); const testData = { test: 'data' }; const minimumTime = 100; + const startTime = Date.now(); const timingOptions: TimingConsistencyOptions = { minimumResponseTimeMs: minimumTime, }; - jest.spyOn(reflector, 'get').mockReturnValue(timingOptions); - jest.spyOn(next, 'handle').mockReturnValue(of(testData)); + reflector.get.mockReturnValue(timingOptions); + next.handle.mockReturnValue(of(testData)); - const startTime = Date.now(); - const result$ = interceptor.intercept(context, next); + const result = await lastValueFrom(interceptor.intercept(context, next)); + const totalElapsed = Date.now() - startTime; - result$.subscribe(async (result) => { - if (result instanceof Promise) { - const resolvedResult = await result; - const totalElapsed = Date.now() - startTime; - expect(resolvedResult).toBe(testData); - expect(totalElapsed).toBeGreaterThanOrEqual(minimumTime - 10); - } else { - expect(result).toBe(testData); - } - - done(); - }); + expect(result).toBe(testData); + expect(totalElapsed).toBeGreaterThanOrEqual(minimumTime - 10); }); - it('should not add delay when response already takes longer than minimum time', (done) => { - const context = createMock(); - const next = createMock(); + it('should not add delay when response already takes longer than minimum time', async () => { + const context = mockDeep(); + const next = mockDeep(); const testData = { test: 'data' }; const minimumTime = 50; + const startTime = Date.now(); const timingOptions: TimingConsistencyOptions = { minimumResponseTimeMs: minimumTime, }; - jest.spyOn(reflector, 'get').mockReturnValue(timingOptions); - - jest - .spyOn(next, 'handle') - .mockReturnValue(of(testData).pipe(delay(minimumTime + 10))); + reflector.get.mockReturnValue(timingOptions); + next.handle.mockReturnValue( + of(testData).pipe(delay(minimumTime + 10)) as any, + ); - const startTime = Date.now(); - const result$ = interceptor.intercept(context, next); + const result = await lastValueFrom(interceptor.intercept(context, next)); + const totalElapsed = Date.now() - startTime; - result$.subscribe((result) => { - const elapsed = Date.now() - startTime; - expect(result).toBe(testData); - expect(elapsed).toBeGreaterThanOrEqual(minimumTime); - done(); - }); + expect(result).toBe(testData); + expect(totalElapsed).toBeGreaterThanOrEqual(minimumTime); }); }); diff --git a/src/modules/auth/jwt.strategy.spec.ts b/src/modules/auth/jwt.strategy.spec.ts index 33dd5bfdf..6b88ee53a 100644 --- a/src/modules/auth/jwt.strategy.spec.ts +++ b/src/modules/auth/jwt.strategy.spec.ts @@ -1,32 +1,34 @@ -import { Test, type TestingModule } from '@nestjs/testing'; -import { createMock } from '@golevelup/ts-jest'; -import { UserUseCases } from '../user/user.usecase'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { type DeepMockProxy, mockDeep } from 'vitest-mock-extended'; +import { type UserUseCases } from '../user/user.usecase'; import { JwtStrategy } from './jwt.strategy'; import { newUser } from '../../../test/fixtures'; import { UnauthorizedException } from '@nestjs/common'; import { getTokenDefaultIat } from '../../lib/jwt'; -import { CacheManagerService } from '../cache-manager/cache-manager.service'; -import { FeatureLimitService } from '../feature-limit/feature-limit.service'; +import { type CacheManagerService } from '../cache-manager/cache-manager.service'; +import { type FeatureLimitService } from '../feature-limit/feature-limit.service'; import { v4 } from 'uuid'; +import { type ConfigService } from '@nestjs/config'; describe('Jwt strategy', () => { - let userUseCases: UserUseCases; let strategy: JwtStrategy; - let cacheManagerService: CacheManagerService; - let featureLimitService: FeatureLimitService; - - beforeEach(async () => { - const moduleRef: TestingModule = await Test.createTestingModule({ - providers: [JwtStrategy], - }) - .useMocker(createMock) - .compile(); - userUseCases = moduleRef.get(UserUseCases); - strategy = moduleRef.get(JwtStrategy); - cacheManagerService = - moduleRef.get(CacheManagerService); - featureLimitService = - moduleRef.get(FeatureLimitService); + let userUseCases: DeepMockProxy; + let cacheManagerService: DeepMockProxy; + let featureLimitService: DeepMockProxy; + + beforeEach(() => { + userUseCases = mockDeep(); + cacheManagerService = mockDeep(); + featureLimitService = mockDeep(); + const configService = mockDeep(); + configService.get.mockReturnValue('test'); + + strategy = new JwtStrategy( + userUseCases, + cacheManagerService, + featureLimitService, + configService, + ); }); it('When token is old version, then fail', async () => { @@ -36,7 +38,7 @@ describe('Jwt strategy', () => { }); it('When user does not exist, then fail', async () => { - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(null); + userUseCases.getUser.mockResolvedValue(null); await expect( strategy.validate({ payload: { uuid: 'anyUuid' } }), @@ -50,7 +52,7 @@ describe('Jwt strategy', () => { greaterDate.setMinutes(greaterDate.getMinutes() + 1); user.lastPasswordChangedAt = greaterDate; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); + userUseCases.getUser.mockResolvedValue(user); await expect( strategy.validate({ payload: { uuid: 'anyUuid' }, iat: tokenIat }), @@ -64,7 +66,7 @@ describe('Jwt strategy', () => { olderDate.setMinutes(olderDate.getMinutes() - 1); user.lastPasswordChangedAt = olderDate; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); + userUseCases.getUser.mockResolvedValue(user); const result = await strategy.validate({ payload: { uuid: 'anyUuid' }, @@ -78,7 +80,7 @@ describe('Jwt strategy', () => { const user = newUser(); user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); + userUseCases.getUser.mockResolvedValue(user); const result = await strategy.validate({ payload: { uuid: 'anyUuid' }, @@ -98,13 +100,10 @@ describe('Jwt strategy', () => { olderDate.setMinutes(olderDate.getMinutes() - 1); guestUser.lastPasswordChangedAt = olderDate; - const getUserSpy = jest - .spyOn(userUseCases, 'getUser') - .mockResolvedValue(guestUser); + const getUserSpy = userUseCases.getUser.mockResolvedValue(guestUser); - const getUserByUsernameSpy = jest - .spyOn(userUseCases, 'getUserByUsername') - .mockResolvedValue(owner); + const getUserByUsernameSpy = + userUseCases.getUserByUsername.mockResolvedValue(owner); const result = await strategy.validate({ payload: { uuid: anyUuid }, @@ -121,8 +120,8 @@ describe('Jwt strategy', () => { const user = newUser(); user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); - jest.spyOn(cacheManagerService, 'isJwtBlacklisted').mockResolvedValue(true); + userUseCases.getUser.mockResolvedValue(user); + cacheManagerService.isJwtBlacklisted.mockResolvedValue(true); await expect( strategy.validate({ @@ -140,8 +139,8 @@ describe('Jwt strategy', () => { const user = newUser(); user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); - jest.spyOn(cacheManagerService, 'isJwtBlacklisted').mockResolvedValue(null); + userUseCases.getUser.mockResolvedValue(user); + cacheManagerService.isJwtBlacklisted.mockResolvedValue(null); const result = await strategy.validate({ payload: { uuid: user.uuid }, @@ -157,11 +156,8 @@ describe('Jwt strategy', () => { const user = newUser(); user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); - const isBlacklistedSpy = jest.spyOn( - cacheManagerService, - 'isJwtBlacklisted', - ); + userUseCases.getUser.mockResolvedValue(user); + const isBlacklistedSpy = cacheManagerService.isJwtBlacklisted; const result = await strategy.validate({ payload: { uuid: user.uuid }, @@ -183,10 +179,8 @@ describe('Jwt strategy', () => { user.tierId = tierId; user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); - jest - .spyOn(featureLimitService, 'getTier') - .mockResolvedValue(mockTier as any); + userUseCases.getUser.mockResolvedValue(user); + featureLimitService.getTier.mockResolvedValue(mockTier as any); const result = await strategy.validate({ payload: { uuid: user.uuid }, @@ -203,8 +197,8 @@ describe('Jwt strategy', () => { user.tierId = tierId; user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); - jest.spyOn(featureLimitService, 'getTier').mockResolvedValue(null); + userUseCases.getUser.mockResolvedValue(user); + featureLimitService.getTier.mockResolvedValue(null); const result = await strategy.validate({ payload: { uuid: user.uuid }, @@ -220,8 +214,8 @@ describe('Jwt strategy', () => { user.tierId = null; user.lastPasswordChangedAt = null; - jest.spyOn(userUseCases, 'getUser').mockResolvedValue(user); - const getTierSpy = jest.spyOn(featureLimitService, 'getTier'); + userUseCases.getUser.mockResolvedValue(user); + const getTierSpy = featureLimitService.getTier; const result = await strategy.validate({ payload: { uuid: user.uuid }, diff --git a/src/modules/auth/two-factor-auth.service.spec.ts b/src/modules/auth/two-factor-auth.service.spec.ts index a1f3074bf..ad6fb7cf7 100644 --- a/src/modules/auth/two-factor-auth.service.spec.ts +++ b/src/modules/auth/two-factor-auth.service.spec.ts @@ -1,3 +1,4 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { TwoFactorAuthService } from './two-factor-auth.service'; import { BadRequestException, @@ -6,8 +7,8 @@ import { import * as speakeasy from 'speakeasy'; import * as qrcode from 'qrcode'; -jest.mock('qrcode', () => ({ - toDataURL: jest.fn(), +vi.mock('qrcode', () => ({ + toDataURL: vi.fn(), })); describe('TwoFactorAuthService', () => { @@ -54,7 +55,7 @@ describe('TwoFactorAuthService', () => { it('When an invalid code is provided, then it should throw', async () => { const secret = speakeasy.generateSecret({ length: 10 }).ascii; - jest.spyOn(speakeasy.totp, 'verifyDelta').mockReturnValue(undefined); + vi.spyOn(speakeasy.totp, 'verifyDelta').mockReturnValue(undefined); expect(() => service.validateTwoFactorAuthCode(secret, 'invalidCode'), diff --git a/src/modules/sharing/sharing.controller.spec.ts b/src/modules/sharing/sharing.controller.spec.ts index 5aead00e5..b0c735fae 100644 --- a/src/modules/sharing/sharing.controller.spec.ts +++ b/src/modules/sharing/sharing.controller.spec.ts @@ -533,19 +533,31 @@ describe('SharingController', () => { describe('getSharingType', () => { it('When getting sharing type for file, then it calls service', async () => { const expectedSharing = newSharing(); - jest.spyOn(sharingService, 'getSharingType').mockResolvedValue(expectedSharing); + jest + .spyOn(sharingService, 'getSharingType') + .mockResolvedValue(expectedSharing); const result = await controller.getSharingType(user, 'file', file.uuid); expect(result).toBe(expectedSharing); - expect(sharingService.getSharingType).toHaveBeenCalledWith(user, file.uuid, 'file'); + expect(sharingService.getSharingType).toHaveBeenCalledWith( + user, + file.uuid, + 'file', + ); }); it('When getting sharing type for folder, then it calls service', async () => { const expectedSharing = newSharing(); - jest.spyOn(sharingService, 'getSharingType').mockResolvedValue(expectedSharing); + jest + .spyOn(sharingService, 'getSharingType') + .mockResolvedValue(expectedSharing); - const result = await controller.getSharingType(user, 'folder', folder.uuid); + const result = await controller.getSharingType( + user, + 'folder', + folder.uuid, + ); expect(result).toBe(expectedSharing); }); @@ -559,20 +571,44 @@ describe('SharingController', () => { describe('getItemSharingStatus', () => { it('When getting item sharing info for file, then it calls service', async () => { - const expectedInfo = { type: 'public', invitationsCount: 1, publicSharing: null }; - jest.spyOn(sharingService, 'getItemSharingInfo').mockResolvedValue(expectedInfo as any); + const expectedInfo = { + type: 'public', + invitationsCount: 1, + publicSharing: null, + }; + jest + .spyOn(sharingService, 'getItemSharingInfo') + .mockResolvedValue(expectedInfo as any); - const result = await controller.getItemSharingStatus(user, 'file', file.uuid); + const result = await controller.getItemSharingStatus( + user, + 'file', + file.uuid, + ); expect(result).toBe(expectedInfo); - expect(sharingService.getItemSharingInfo).toHaveBeenCalledWith(user, file.uuid, 'file'); + expect(sharingService.getItemSharingInfo).toHaveBeenCalledWith( + user, + file.uuid, + 'file', + ); }); it('When getting item sharing info for folder, then it calls service', async () => { - const expectedInfo = { type: 'private', invitationsCount: 0, publicSharing: null }; - jest.spyOn(sharingService, 'getItemSharingInfo').mockResolvedValue(expectedInfo as any); + const expectedInfo = { + type: 'private', + invitationsCount: 0, + publicSharing: null, + }; + jest + .spyOn(sharingService, 'getItemSharingInfo') + .mockResolvedValue(expectedInfo as any); - const result = await controller.getItemSharingStatus(user, 'folder', folder.uuid); + const result = await controller.getItemSharingStatus( + user, + 'folder', + folder.uuid, + ); expect(result).toBe(expectedInfo); }); @@ -587,7 +623,9 @@ describe('SharingController', () => { describe('getInvitesByUser', () => { it('When getting invites with valid params, then it returns invites', async () => { const expectedInvites = [{ id: 'invite-1' }]; - jest.spyOn(sharingService, 'getInvitesByUser').mockResolvedValue(expectedInvites as any); + jest + .spyOn(sharingService, 'getInvitesByUser') + .mockResolvedValue(expectedInvites as any); const result = await controller.getInvitesByUser(user, 10, 0); @@ -596,22 +634,20 @@ describe('SharingController', () => { }); it('When limit is out of range (too low), then it throws', async () => { - await expect( - controller.getInvitesByUser(user, -1, 0), - ).rejects.toThrow(); + await expect(controller.getInvitesByUser(user, -1, 0)).rejects.toThrow(); }); it('When offset is out of range (too low), then it throws', async () => { - await expect( - controller.getInvitesByUser(user, 10, -1), - ).rejects.toThrow(); + await expect(controller.getInvitesByUser(user, 10, -1)).rejects.toThrow(); }); }); describe('validateInvite', () => { it('When invite is valid, then it returns the uuid', async () => { const inviteId = 'invite-uuid'; - jest.spyOn(sharingService, 'validateInvite').mockResolvedValue({ uuid: inviteId }); + jest + .spyOn(sharingService, 'validateInvite') + .mockResolvedValue({ uuid: inviteId }); const result = await controller.validateInvite(inviteId); @@ -619,13 +655,19 @@ describe('SharingController', () => { }); it('When invite is invalid, then it fails', async () => { - jest.spyOn(sharingService, 'validateInvite').mockRejectedValue(new BadRequestException()); + jest + .spyOn(sharingService, 'validateInvite') + .mockRejectedValue(new BadRequestException()); - await expect(controller.validateInvite('id')).rejects.toThrow(BadRequestException); + await expect(controller.validateInvite('id')).rejects.toThrow( + BadRequestException, + ); }); it('When an unexpected error occurs while validating, then it fails', async () => { - jest.spyOn(sharingService, 'validateInvite').mockRejectedValue(new Error('unexpected')); + jest + .spyOn(sharingService, 'validateInvite') + .mockRejectedValue(new Error('unexpected')); await expect(controller.validateInvite('id')).rejects.toThrow(); }); @@ -633,8 +675,19 @@ describe('SharingController', () => { describe('getFoldersInPrivateSharedFolder', () => { it('When getting folders in private shared folder, then it calls service', async () => { - const expectedResult = { items: [], credentials: {}, token: '', bucket: '', encryptionKey: null, parent: { uuid: null, name: null }, name: 'test', role: 'OWNER' }; - jest.spyOn(sharingService, 'getFoldersInSharedFolder').mockResolvedValue(expectedResult as any); + const expectedResult = { + items: [], + credentials: {}, + token: '', + bucket: '', + encryptionKey: null, + parent: { uuid: null, name: null }, + name: 'test', + role: 'OWNER', + }; + jest + .spyOn(sharingService, 'getFoldersInSharedFolder') + .mockResolvedValue(expectedResult as any); const result = await controller.getFoldersInPrivateSharedFolder( user, @@ -644,25 +697,50 @@ describe('SharingController', () => { expect(result).toBe(expectedResult); expect(sharingService.getFoldersInSharedFolder).toHaveBeenCalledWith( - folder.uuid, 'some-token', user, 0, 50, + folder.uuid, + 'some-token', + user, + 0, + 50, ); }); it('When no page/perPage provided, then it uses defaults', async () => { - jest.spyOn(sharingService, 'getFoldersInSharedFolder').mockResolvedValue({} as any); + jest + .spyOn(sharingService, 'getFoldersInSharedFolder') + .mockResolvedValue({} as any); - await controller.getFoldersInPrivateSharedFolder(user, folder.uuid, {} as any); + await controller.getFoldersInPrivateSharedFolder( + user, + folder.uuid, + {} as any, + ); expect(sharingService.getFoldersInSharedFolder).toHaveBeenCalledWith( - folder.uuid, undefined, user, 0, 50, + folder.uuid, + undefined, + user, + 0, + 50, ); }); }); describe('getFilesInPrivateSharedFolder', () => { it('When getting files in private shared folder, then it calls service', async () => { - const expectedResult = { items: [], credentials: {}, token: '', bucket: '', encryptionKey: null, parent: { uuid: null, name: null }, name: 'test', role: 'OWNER' }; - jest.spyOn(sharingService, 'getFilesInSharedFolder').mockResolvedValue(expectedResult as any); + const expectedResult = { + items: [], + credentials: {}, + token: '', + bucket: '', + encryptionKey: null, + parent: { uuid: null, name: null }, + name: 'test', + role: 'OWNER', + }; + jest + .spyOn(sharingService, 'getFilesInSharedFolder') + .mockResolvedValue(expectedResult as any); const result = await controller.getFilesInPrivateSharedFolder( user, @@ -672,39 +750,80 @@ describe('SharingController', () => { expect(result).toBe(expectedResult); expect(sharingService.getFilesInSharedFolder).toHaveBeenCalledWith( - folder.uuid, 'some-token', user, 0, 50, + folder.uuid, + 'some-token', + user, + 0, + 50, ); }); }); describe('getPublicShareFiles', () => { it('When getting public share files, then it calls service', async () => { - const expectedResult = { items: [], credentials: {}, token: '', bucket: '', encryptionKey: null, parent: { uuid: null, name: null }, name: 'test', role: 'NONE' }; - jest.spyOn(sharingService, 'getFilesFromPublicFolder').mockResolvedValue(expectedResult as any); + const expectedResult = { + items: [], + credentials: {}, + token: '', + bucket: '', + encryptionKey: null, + parent: { uuid: null, name: null }, + name: 'test', + role: 'NONE', + }; + jest + .spyOn(sharingService, 'getFilesFromPublicFolder') + .mockResolvedValue(expectedResult as any); const result = await controller.getPublicShareFiles( - folder.uuid, 'token', 'code', 0, 50, + folder.uuid, + 'token', + 'code', + 0, + 50, ); expect(result).toBe(expectedResult); expect(sharingService.getFilesFromPublicFolder).toHaveBeenCalledWith( - folder.uuid, 'token', 'code', 0, 50, + folder.uuid, + 'token', + 'code', + 0, + 50, ); }); }); describe('getPublicSharedFolders', () => { it('When getting public shared folders, then it calls service', async () => { - const expectedResult = { items: [], credentials: {}, token: '', bucket: '', encryptionKey: null, parent: { uuid: null, name: null }, name: 'test', role: 'NONE' }; - jest.spyOn(sharingService, 'getFoldersFromPublicFolder').mockResolvedValue(expectedResult as any); + const expectedResult = { + items: [], + credentials: {}, + token: '', + bucket: '', + encryptionKey: null, + parent: { uuid: null, name: null }, + name: 'test', + role: 'NONE', + }; + jest + .spyOn(sharingService, 'getFoldersFromPublicFolder') + .mockResolvedValue(expectedResult as any); const result = await controller.getPublicSharedFolders( - folder.uuid, 'token', 'code', 0, 50, + folder.uuid, + 'token', + 'code', + 0, + 50, ); expect(result).toBe(expectedResult); expect(sharingService.getFoldersFromPublicFolder).toHaveBeenCalledWith( - folder.uuid, 'token', 0, 50, + folder.uuid, + 'token', + 0, + 50, ); }); }); @@ -712,25 +831,44 @@ describe('SharingController', () => { describe('getSharedFoldersWithAUser', () => { it('When getting shared folders with user, then it returns folders', async () => { const expectedFolders = [folder]; - jest.spyOn(sharingService, 'getSharedFoldersBySharedWith').mockResolvedValue(expectedFolders); + jest + .spyOn(sharingService, 'getSharedFoldersBySharedWith') + .mockResolvedValue(expectedFolders); - const result = await controller.getSharedFoldersWithAUser(user, undefined, 0, 50); + const result = await controller.getSharedFoldersWithAUser( + user, + undefined, + 0, + 50, + ); expect(result).toEqual({ folders: expectedFolders }); }); it('When orderBy is provided, then it passes order to service', async () => { - jest.spyOn(sharingService, 'getSharedFoldersBySharedWith').mockResolvedValue([]); + jest + .spyOn(sharingService, 'getSharedFoldersBySharedWith') + .mockResolvedValue([]); - await controller.getSharedFoldersWithAUser(user, 'createdAt:DESC' as any, 0, 50); + await controller.getSharedFoldersWithAUser( + user, + 'createdAt:DESC' as any, + 0, + 50, + ); expect(sharingService.getSharedFoldersBySharedWith).toHaveBeenCalledWith( - user, 0, 50, [['createdAt', 'DESC']], + user, + 0, + 50, + [['createdAt', 'DESC']], ); }); it('When service fails, then it fails', async () => { - jest.spyOn(sharingService, 'getSharedFoldersBySharedWith').mockRejectedValue(new Error('fail')); + jest + .spyOn(sharingService, 'getSharedFoldersBySharedWith') + .mockRejectedValue(new Error('fail')); await expect( controller.getSharedFoldersWithAUser(user, undefined, 0, 50), @@ -741,7 +879,9 @@ describe('SharingController', () => { describe('getSharedFolders (shared-by-me)', () => { it('When getting shared folders by owner, then it returns folders', async () => { const expectedFolders = [folder]; - jest.spyOn(sharingService, 'getSharedFoldersByOwner').mockResolvedValue(expectedFolders); + jest + .spyOn(sharingService, 'getSharedFoldersByOwner') + .mockResolvedValue(expectedFolders); const result = await controller.getSharedFolders(user, undefined, 0, 50); @@ -749,17 +889,24 @@ describe('SharingController', () => { }); it('When orderBy is provided, then it passes order to service', async () => { - jest.spyOn(sharingService, 'getSharedFoldersByOwner').mockResolvedValue([]); + jest + .spyOn(sharingService, 'getSharedFoldersByOwner') + .mockResolvedValue([]); await controller.getSharedFolders(user, 'name:ASC' as any, 0, 50); expect(sharingService.getSharedFoldersByOwner).toHaveBeenCalledWith( - user, 0, 50, [['name', 'ASC']], + user, + 0, + 50, + [['name', 'ASC']], ); }); it('When service fails, then it fails', async () => { - jest.spyOn(sharingService, 'getSharedFoldersByOwner').mockRejectedValue(new Error('fail')); + jest + .spyOn(sharingService, 'getSharedFoldersByOwner') + .mockRejectedValue(new Error('fail')); await expect( controller.getSharedFolders(user, undefined, 0, 50), @@ -769,29 +916,60 @@ describe('SharingController', () => { describe('getAllSharedFolders', () => { it('When getting all shared folders, then it calls service', async () => { - const expectedResult = { folders: [], files: [], credentials: {}, token: '', role: 'OWNER' }; - jest.spyOn(sharingService, 'getSharedFolders').mockResolvedValue(expectedResult as any); + const expectedResult = { + folders: [], + files: [], + credentials: {}, + token: '', + role: 'OWNER', + }; + jest + .spyOn(sharingService, 'getSharedFolders') + .mockResolvedValue(expectedResult as any); - const result = await controller.getAllSharedFolders(user, undefined, 0, 50); + const result = await controller.getAllSharedFolders( + user, + undefined, + 0, + 50, + ); expect(result).toBe(expectedResult); }); it('When orderBy is provided, then it passes order', async () => { - jest.spyOn(sharingService, 'getSharedFolders').mockResolvedValue({} as any); + jest + .spyOn(sharingService, 'getSharedFolders') + .mockResolvedValue({} as any); - await controller.getAllSharedFolders(user, 'createdAt:DESC' as any, 0, 50); + await controller.getAllSharedFolders( + user, + 'createdAt:DESC' as any, + 0, + 50, + ); expect(sharingService.getSharedFolders).toHaveBeenCalledWith( - user, 0, 50, [['createdAt', 'DESC']], + user, + 0, + 50, + [['createdAt', 'DESC']], ); }); }); describe('getAllSharedFiles', () => { it('When getting all shared files, then it calls service', async () => { - const expectedResult = { folders: [], files: [], credentials: {}, token: '', role: 'OWNER' }; - jest.spyOn(sharingService, 'getSharedFiles').mockResolvedValue(expectedResult as any); + const expectedResult = { + folders: [], + files: [], + credentials: {}, + token: '', + role: 'OWNER', + }; + jest + .spyOn(sharingService, 'getSharedFiles') + .mockResolvedValue(expectedResult as any); const result = await controller.getAllSharedFiles(user, undefined, 0, 50); @@ -803,24 +981,32 @@ describe('SharingController', () => { await controller.getAllSharedFiles(user, 'name:ASC' as any, 0, 50); - expect(sharingService.getSharedFiles).toHaveBeenCalledWith( - user, 0, 50, [['name', 'ASC']], - ); + expect(sharingService.getSharedFiles).toHaveBeenCalledWith(user, 0, 50, [ + ['name', 'ASC'], + ]); }); }); describe('getItemsSharedsWith', () => { it('When getting items shared with, then it returns users', async () => { const expectedUsers = [{ uuid: 'user-1' }]; - jest.spyOn(sharingService, 'getItemSharedWith').mockResolvedValue(expectedUsers as any); + jest + .spyOn(sharingService, 'getItemSharedWith') + .mockResolvedValue(expectedUsers as any); - const result = await controller.getItemsSharedsWith(user, file.uuid, 'file'); + const result = await controller.getItemsSharedsWith( + user, + file.uuid, + 'file', + ); expect(result).toEqual({ users: expectedUsers }); }); it('When service fails, then it fails', async () => { - jest.spyOn(sharingService, 'getItemSharedWith').mockRejectedValue(new Error('fail')); + jest + .spyOn(sharingService, 'getItemSharedWith') + .mockRejectedValue(new Error('fail')); await expect( controller.getItemsSharedsWith(user, file.uuid, 'file'), @@ -831,31 +1017,47 @@ describe('SharingController', () => { describe('getSharedWithByFolderId', () => { it('When getting shared with by folder id, then it returns users', async () => { const expectedUsers = [{ uuid: 'user-1' }]; - jest.spyOn(sharingService, 'getSharedWithByItemId').mockResolvedValue(expectedUsers as any); + jest + .spyOn(sharingService, 'getSharedWithByItemId') + .mockResolvedValue(expectedUsers as any); const result = await controller.getSharedWithByFolderId( - user, 0, 50, undefined, folder.uuid, + user, + 0, + 50, + undefined, + folder.uuid, ); expect(result).toEqual({ users: expectedUsers }); }); it('When orderBy is provided, then it passes order', async () => { - jest.spyOn(sharingService, 'getSharedWithByItemId').mockResolvedValue([] as any); + jest + .spyOn(sharingService, 'getSharedWithByItemId') + .mockResolvedValue([] as any); await controller.getSharedWithByFolderId( - user, 0, 50, 'createdAt:DESC' as any, folder.uuid, + user, + 0, + 50, + 'createdAt:DESC' as any, + folder.uuid, ); expect(sharingService.getSharedWithByItemId).toHaveBeenCalledWith( - user, folder.uuid, 0, 50, [['createdAt', 'DESC']], + user, + folder.uuid, + 0, + 50, + [['createdAt', 'DESC']], ); }); it('When service fails with a known error, then it fails', async () => { - jest.spyOn(sharingService, 'getSharedWithByItemId').mockRejectedValue( - new BadRequestException('test'), - ); + jest + .spyOn(sharingService, 'getSharedWithByItemId') + .mockRejectedValue(new BadRequestException('test')); await expect( controller.getSharedWithByFolderId(user, 0, 50, undefined, folder.uuid), @@ -863,7 +1065,9 @@ describe('SharingController', () => { }); it('When an unexpected error occurs, then it fails', async () => { - jest.spyOn(sharingService, 'getSharedWithByItemId').mockRejectedValue(new Error('unexpected')); + jest + .spyOn(sharingService, 'getSharedWithByItemId') + .mockRejectedValue(new Error('unexpected')); await expect( controller.getSharedWithByFolderId(user, 0, 50, undefined, folder.uuid), @@ -873,15 +1077,23 @@ describe('SharingController', () => { describe('removeUserFromSharedItem', () => { it('When removing user from shared item, then it returns success message', async () => { - jest.spyOn(sharingService, 'removeSharedWith').mockResolvedValue(undefined); + jest + .spyOn(sharingService, 'removeSharedWith') + .mockResolvedValue(undefined); const result = await controller.removeUserFromSharedItem( - user.uuid, file.uuid, 'file', user, + user.uuid, + file.uuid, + 'file', + user, ); expect(result).toEqual({ message: 'User removed from shared folder' }); expect(sharingService.removeSharedWith).toHaveBeenCalledWith( - file.uuid, 'file', user.uuid, user, + file.uuid, + 'file', + user.uuid, + user, ); }); }); diff --git a/src/modules/sharing/sharing.service.spec.ts b/src/modules/sharing/sharing.service.spec.ts index 19b411b1f..94a712c26 100644 --- a/src/modules/sharing/sharing.service.spec.ts +++ b/src/modules/sharing/sharing.service.spec.ts @@ -2470,26 +2470,29 @@ describe('Sharing Use Cases', () => { const limit = 10; const order: [string, string][] = [['createdAt', 'DESC']]; - const buildFolderWithSharedInfo = (overrides?: { avatar?: string; plainName?: string | null }) => { + const buildFolderWithSharedInfo = (overrides?: { + avatar?: string; + plainName?: string | null; + }) => { let plainName = folder.plainName; if (overrides && 'plainName' in overrides) { plainName = overrides.plainName; } return { - id: v4(), - encryptionKey: 'enc-key', - createdAt: new Date(), - folder: { - ...folder, - plainName, - user: { - uuid: user.uuid, - userId: user.userId, - bridgeUser: user.bridgeUser, - avatar: overrides?.avatar ?? null, + id: v4(), + encryptionKey: 'enc-key', + createdAt: new Date(), + folder: { + ...folder, + plainName, + user: { + uuid: user.uuid, + userId: user.userId, + bridgeUser: user.bridgeUser, + avatar: overrides?.avatar ?? null, + }, }, - }, - }; + }; }; it('When user requests shared folders, then it returns folders with shared info', async () => { @@ -2497,7 +2500,12 @@ describe('Sharing Use Cases', () => { buildFolderWithSharedInfo(), ] as any); - const result = await sharingService.getSharedFolders(user, offset, limit, order); + const result = await sharingService.getSharedFolders( + user, + offset, + limit, + order, + ); expect(result.folders).toHaveLength(1); expect(result.files).toEqual([]); @@ -2512,7 +2520,12 @@ describe('Sharing Use Cases', () => { 'https://example.com/avatar.jpg', ); - const result = await sharingService.getSharedFolders(user, offset, limit, order); + const result = await sharingService.getSharedFolders( + user, + offset, + limit, + order, + ); expect(usersUsecases.getAvatarUrl).toHaveBeenCalledWith('avatar-key'); expect(result.folders[0].user.avatar).toBe( @@ -2528,7 +2541,12 @@ describe('Sharing Use Cases', () => { plainName: 'Decrypted Name', } as any); - const result = await sharingService.getSharedFolders(user, offset, limit, order); + const result = await sharingService.getSharedFolders( + user, + offset, + limit, + order, + ); expect(result.folders[0].plainName).toBe('Decrypted Name'); }); @@ -2540,8 +2558,16 @@ describe('Sharing Use Cases', () => { const file = newFile({ owner }); const folder = newFolder({ owner }); const role = newRole(); - const fileSharing = newSharing({ owner, item: file, sharedWith: sharedUser }); - const folderSharing = newSharing({ owner, item: folder, sharedWith: sharedUser }); + const fileSharing = newSharing({ + owner, + item: file, + sharedWith: sharedUser, + }); + const folderSharing = newSharing({ + owner, + item: folder, + sharedWith: sharedUser, + }); it('When item is a file and user is owner, then it returns users with roles', async () => { fileUsecases.getByUuid.mockResolvedValue(file); @@ -2550,7 +2576,11 @@ describe('Sharing Use Cases', () => { ]); usersUsecases.findByUuids.mockResolvedValue([sharedUser]); - const result = await sharingService.getItemSharedWith(owner, file.uuid, 'file'); + const result = await sharingService.getItemSharedWith( + owner, + file.uuid, + 'file', + ); expect(result).toBeDefined(); expect(result.length).toBeGreaterThan(0); @@ -2563,7 +2593,11 @@ describe('Sharing Use Cases', () => { ]); usersUsecases.findByUuids.mockResolvedValue([sharedUser]); - const result = await sharingService.getItemSharedWith(owner, folder.uuid, 'folder'); + const result = await sharingService.getItemSharedWith( + owner, + folder.uuid, + 'folder', + ); expect(result).toBeDefined(); expect(result.length).toBeGreaterThan(0); @@ -2612,7 +2646,11 @@ describe('Sharing Use Cases', () => { ]); usersUsecases.findByUuids.mockResolvedValue([sharedUser]); - const result = await sharingService.getItemSharedWith(owner, file.uuid, 'file'); + const result = await sharingService.getItemSharedWith( + owner, + file.uuid, + 'file', + ); expect(usersUsecases.getUser).not.toHaveBeenCalled(); const ownerEntry = result.find((r) => r.role.name === 'OWNER'); @@ -2628,7 +2666,11 @@ describe('Sharing Use Cases', () => { usersUsecases.findByUuids.mockResolvedValue([sharedUser]); usersUsecases.getUser.mockResolvedValue(owner); - const result = await sharingService.getItemSharedWith(sharedUser, file.uuid, 'file'); + const result = await sharingService.getItemSharedWith( + sharedUser, + file.uuid, + 'file', + ); expect(usersUsecases.getUser).toHaveBeenCalledWith(owner.uuid); const ownerEntry = result.find((r) => r.role.name === 'OWNER'); @@ -2654,7 +2696,11 @@ describe('Sharing Use Cases', () => { usersUsecases.findByUuids.mockResolvedValue([sharedUser]); const result = await sharingService.getSharedWithByItemId( - owner, folder.uuid, offset, limit, order, + owner, + folder.uuid, + offset, + limit, + order, ); expect(result).toBeDefined(); @@ -2674,7 +2720,13 @@ describe('Sharing Use Cases', () => { sharingRepository.findSharingsWithRolesByItem.mockResolvedValue([]); await expect( - sharingService.getSharedWithByItemId(owner, folder.uuid, offset, limit, order), + sharingService.getSharedWithByItemId( + owner, + folder.uuid, + offset, + limit, + order, + ), ).rejects.toThrow(BadRequestException); }); @@ -2687,13 +2739,23 @@ describe('Sharing Use Cases', () => { ]); await expect( - sharingService.getSharedWithByItemId(outsider, folder.uuid, offset, limit, order), + sharingService.getSharedWithByItemId( + outsider, + folder.uuid, + offset, + limit, + order, + ), ).rejects.toThrow(ForbiddenException); }); it('When shared user has avatar, then it returns the avatar', async () => { const userWithAvatar = newUser({ attributes: { avatar: 'avatar-key' } }); - const avatarSharing = newSharing({ owner, item: folder, sharedWith: userWithAvatar }); + const avatarSharing = newSharing({ + owner, + item: folder, + sharedWith: userWithAvatar, + }); folderUseCases.getByUuid.mockResolvedValue(folder); sharingRepository.findSharingsWithRolesByItem.mockResolvedValue([ @@ -2705,7 +2767,11 @@ describe('Sharing Use Cases', () => { ); const result = await sharingService.getSharedWithByItemId( - owner, folder.uuid, offset, limit, order, + owner, + folder.uuid, + offset, + limit, + order, ); expect(usersUsecases.getAvatarUrl).toHaveBeenCalledWith('avatar-key'); @@ -2736,7 +2802,11 @@ describe('Sharing Use Cases', () => { usersUsecases.getAvatarUrl.mockResolvedValue(null); const result = await sharingService.getFoldersInSharedFolder( - folder.uuid, null, owner, page, perPage, + folder.uuid, + null, + owner, + page, + perPage, ); expect(result.role).toBe('OWNER'); @@ -2750,7 +2820,13 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(trashedFolder); await expect( - sharingService.getFoldersInSharedFolder(trashedFolder.uuid, null, owner, page, perPage), + sharingService.getFoldersInSharedFolder( + trashedFolder.uuid, + null, + owner, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2761,7 +2837,13 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(removedFolder); await expect( - sharingService.getFoldersInSharedFolder(removedFolder.uuid, null, owner, page, perPage), + sharingService.getFoldersInSharedFolder( + removedFolder.uuid, + null, + owner, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2780,7 +2862,11 @@ describe('Sharing Use Cases', () => { usersUsecases.getAvatarUrl.mockResolvedValue(null); const result = await sharingService.getFoldersInSharedFolder( - folder.uuid, null, sharedUser, page, perPage, + folder.uuid, + null, + sharedUser, + page, + perPage, ); expect(result.items).toBeDefined(); @@ -2795,7 +2881,13 @@ describe('Sharing Use Cases', () => { sharingRepository.findOneSharing.mockResolvedValue(null); await expect( - sharingService.getFoldersInSharedFolder(folder.uuid, null, outsider, page, perPage), + sharingService.getFoldersInSharedFolder( + folder.uuid, + null, + outsider, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2813,7 +2905,13 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFoldersInSharedFolder(folder.uuid, 'token', sharedUser, page, perPage), + sharingService.getFoldersInSharedFolder( + folder.uuid, + 'token', + sharedUser, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2832,19 +2930,32 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFoldersInSharedFolder(folder.uuid, 'token', sharedUser, page, perPage), + sharingService.getFoldersInSharedFolder( + folder.uuid, + 'token', + sharedUser, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); it('When folder has no parent, then parent is null', async () => { - const noParentFolder = newFolder({ owner, attributes: { parentId: null } }); + const noParentFolder = newFolder({ + owner, + attributes: { parentId: null }, + }); folderUseCases.getByUuid.mockResolvedValue(noParentFolder); folderUseCases.getFoldersWithParent.mockResolvedValue([]); usersUsecases.getAvatarUrl.mockResolvedValue(null); const result = await sharingService.getFoldersInSharedFolder( - noParentFolder.uuid, null, owner, page, perPage, + noParentFolder.uuid, + null, + owner, + page, + perPage, ); expect(result.parent.uuid).toBeNull(); @@ -2874,7 +2985,11 @@ describe('Sharing Use Cases', () => { usersUsecases.getAvatarUrl.mockResolvedValue(null); const result = await sharingService.getFilesInSharedFolder( - folder.uuid, null, owner, page, perPage, + folder.uuid, + null, + owner, + page, + perPage, ); expect(result.role).toBe('OWNER'); @@ -2888,7 +3003,13 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(trashedFolder); await expect( - sharingService.getFilesInSharedFolder(trashedFolder.uuid, null, owner, page, perPage), + sharingService.getFilesInSharedFolder( + trashedFolder.uuid, + null, + owner, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2899,7 +3020,13 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(removedFolder); await expect( - sharingService.getFilesInSharedFolder(removedFolder.uuid, null, owner, page, perPage), + sharingService.getFilesInSharedFolder( + removedFolder.uuid, + null, + owner, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2918,7 +3045,11 @@ describe('Sharing Use Cases', () => { usersUsecases.getAvatarUrl.mockResolvedValue(null); const result = await sharingService.getFilesInSharedFolder( - folder.uuid, null, sharedUser, page, perPage, + folder.uuid, + null, + sharedUser, + page, + perPage, ); expect(result.items).toBeDefined(); @@ -2933,7 +3064,13 @@ describe('Sharing Use Cases', () => { sharingRepository.findOneSharing.mockResolvedValue(null); await expect( - sharingService.getFilesInSharedFolder(folder.uuid, null, outsider, page, perPage), + sharingService.getFilesInSharedFolder( + folder.uuid, + null, + outsider, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2953,7 +3090,13 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFilesInSharedFolder(folder.uuid, 'token', sharedUser, page, perPage), + sharingService.getFilesInSharedFolder( + folder.uuid, + 'token', + sharedUser, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -2972,7 +3115,13 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFilesInSharedFolder(folder.uuid, 'token', sharedUser, page, perPage), + sharingService.getFilesInSharedFolder( + folder.uuid, + 'token', + sharedUser, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); }); @@ -2999,7 +3148,10 @@ describe('Sharing Use Cases', () => { ); const result = await sharingService.getFoldersFromPublicFolder( - folder.uuid, null, page, perPage, + folder.uuid, + null, + page, + perPage, ); expect(result.items).toHaveLength(1); @@ -3013,7 +3165,12 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(trashedFolder); await expect( - sharingService.getFoldersFromPublicFolder(trashedFolder.uuid, null, page, perPage), + sharingService.getFoldersFromPublicFolder( + trashedFolder.uuid, + null, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -3024,17 +3181,29 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(removedFolder); await expect( - sharingService.getFoldersFromPublicFolder(removedFolder.uuid, null, page, perPage), + sharingService.getFoldersFromPublicFolder( + removedFolder.uuid, + null, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); it('When navigation credentials are invalid, then it fails', async () => { folderUseCases.getByUuid.mockResolvedValue(folder); folderUseCases.getFolder.mockResolvedValue(parentFolder); - (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue('invalid-string'); + (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue( + 'invalid-string', + ); await expect( - sharingService.getFoldersFromPublicFolder(folder.uuid, 'some-token', page, perPage), + sharingService.getFoldersFromPublicFolder( + folder.uuid, + 'some-token', + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -3053,7 +3222,12 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFoldersFromPublicFolder(folder.uuid, 'some-token', page, perPage), + sharingService.getFoldersFromPublicFolder( + folder.uuid, + 'some-token', + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -3073,12 +3247,20 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFoldersFromPublicFolder(folder.uuid, 'some-token', page, perPage), + sharingService.getFoldersFromPublicFolder( + folder.uuid, + 'some-token', + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); it('When folder has no parent, then parent fields are null', async () => { - const noParentFolder = newFolder({ owner, attributes: { parentId: null } }); + const noParentFolder = newFolder({ + owner, + attributes: { parentId: null }, + }); const noParentSharing = newSharing({ owner, item: noParentFolder }); folderUseCases.getByUuid.mockResolvedValue(noParentFolder); @@ -3090,7 +3272,10 @@ describe('Sharing Use Cases', () => { ); const result = await sharingService.getFoldersFromPublicFolder( - noParentFolder.uuid, null, page, perPage, + noParentFolder.uuid, + null, + page, + perPage, ); expect(result.parent.uuid).toBeNull(); @@ -3122,7 +3307,11 @@ describe('Sharing Use Cases', () => { fileUsecases.getEncryptionKeyFromFile.mockResolvedValue('encrypted-key'); const result = await sharingService.getFilesFromPublicFolder( - folder.uuid, null, code, page, perPage, + folder.uuid, + null, + code, + page, + perPage, ); expect(result.items).toHaveLength(1); @@ -3136,7 +3325,13 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(trashedFolder); await expect( - sharingService.getFilesFromPublicFolder(trashedFolder.uuid, null, code, page, perPage), + sharingService.getFilesFromPublicFolder( + trashedFolder.uuid, + null, + code, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -3147,7 +3342,13 @@ describe('Sharing Use Cases', () => { folderUseCases.getByUuid.mockResolvedValue(removedFolder); await expect( - sharingService.getFilesFromPublicFolder(removedFolder.uuid, null, code, page, perPage), + sharingService.getFilesFromPublicFolder( + removedFolder.uuid, + null, + code, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -3157,17 +3358,31 @@ describe('Sharing Use Cases', () => { sharingRepository.findOneSharing.mockResolvedValue(null); await expect( - sharingService.getFilesFromPublicFolder(folder.uuid, null, code, page, perPage), + sharingService.getFilesFromPublicFolder( + folder.uuid, + null, + code, + page, + perPage, + ), ).rejects.toThrow(NotFoundException); }); it('When navigation credentials are invalid, then it fails', async () => { folderUseCases.getByUuid.mockResolvedValue(folder); folderUseCases.getFolder.mockResolvedValue(parentFolder); - (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue('invalid-string'); + (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue( + 'invalid-string', + ); await expect( - sharingService.getFilesFromPublicFolder(folder.uuid, 'some-token', code, page, perPage), + sharingService.getFilesFromPublicFolder( + folder.uuid, + 'some-token', + code, + page, + perPage, + ), ).rejects.toThrow(ForbiddenException); }); @@ -3187,7 +3402,13 @@ describe('Sharing Use Cases', () => { (jwtUtils.verifyWithDefaultSecret as jest.Mock).mockReturnValue(decoded); await expect( - sharingService.getFilesFromPublicFolder(folder.uuid, 'some-token', code, page, perPage), + sharingService.getFilesFromPublicFolder( + folder.uuid, + 'some-token', + code, + page, + perPage, + ), ).rejects.toThrow(NotFoundException); }); }); diff --git a/test/helpers/mocker.helper.ts b/test/helpers/mocker.helper.ts new file mode 100644 index 000000000..db1ba9434 --- /dev/null +++ b/test/helpers/mocker.helper.ts @@ -0,0 +1,14 @@ +import { Logger } from '@nestjs/common'; +import { vi } from 'vitest'; + +/** + * Mocks all the methods of a Logger instance. + * The methods are mocked to do nothing when called. + * This is useful for testing, to avoid logging output in test results. + */ +export function mockLogger() { + vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {}); + vi.spyOn(Logger.prototype, 'log').mockImplementation(() => {}); + vi.spyOn(Logger.prototype, 'warn').mockImplementation(() => {}); + vi.spyOn(Logger.prototype, 'debug').mockImplementation(() => {}); +} diff --git a/test/helpers/register.helper.ts b/test/helpers/register.helper.ts index 92328db45..f17c5fbd0 100644 --- a/test/helpers/register.helper.ts +++ b/test/helpers/register.helper.ts @@ -1,7 +1,7 @@ import { v4 } from 'uuid'; import { generateMnemonic } from 'bip39'; +import kemBuilder from '@dashlane/pqc-kem-kyber512-node'; import { generateNewKeys } from '../../src/externals/asymmetric-encryption/openpgp'; -import { importEsmPackage } from '../../src/lib/import-esm-package'; export interface RegisterUserDto { name: string; @@ -52,9 +52,6 @@ async function generateEccKeys(): Promise { } async function generateKyberKeys(): Promise { - const kemBuilder = await importEsmPackage< - typeof import('@dashlane/pqc-kem-kyber512-node').default - >('@dashlane/pqc-kem-kyber512-node'); const kem = await kemBuilder(); const keys = await kem.keypair(); return { diff --git a/test/jest-e2e.json b/test/jest-e2e.json deleted file mode 100644 index b5ec69a94..000000000 --- a/test/jest-e2e.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": "../", - "testEnvironment": "node", - "testRegex": ".e2e-spec.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - } -} \ No newline at end of file diff --git a/test/vitest.setup.ts b/test/vitest.setup.ts new file mode 100644 index 000000000..cec385db8 --- /dev/null +++ b/test/vitest.setup.ts @@ -0,0 +1,13 @@ +import 'reflect-metadata'; + +declare global { + interface BigInt { + toJSON(): string; + } +} + +if (typeof BigInt === 'function' && !BigInt.prototype.toJSON) { + BigInt.prototype.toJSON = function () { + return this.toString(); + }; +} diff --git a/tsconfig.json b/tsconfig.json index 0df713c15..a0f5f55a9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,15 @@ { "compilerOptions": { - "module": "commonjs", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "ESNext", + "lib": ["ESNext"], + "types": ["node"], "declaration": true, "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, - "target": "es2017", "sourceMap": true, "outDir": "./dist", "baseUrl": "./", diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 000000000..79a6c4bcd --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,28 @@ +import { coverageConfigDefaults, defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'node', + globals: true, + setupFiles: ['./test/vitest.setup.ts'], + exclude: ['node_modules', 'dist'], + include: [ + 'src/**/*.spec.{ts,tsx,js,jsx}', + 'test/**/*.spec.{ts,tsx,js,jsx}', + 'src/**/*.e2e-spec.{ts,tsx,js,jsx}', + 'test/**/*.e2e-spec.{ts,tsx,js,jsx}', + ], + coverage: { + provider: 'istanbul', + reporter: ['text', 'lcov'], + include: [ + 'src/**/*.{js,ts,jsx,tsx}', + 'test/**/*.{js,ts,jsx,tsx}' + ], + exclude: [ + ...coverageConfigDefaults.exclude + ] + }, + mockReset: true + }, +}); diff --git a/yarn.lock b/yarn.lock index ceaefb99f..9c8278f4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -688,20 +688,11 @@ tslib "^2.6.2" "@aws/lambda-invoke-store@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz#ceecff9ebe1f6199369e6911f38633fac3322811" - integrity sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww== - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1", "@babel/code-frame@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" - integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q== - dependencies: - "@babel/helper-validator-identifier" "^7.28.5" - js-tokens "^4.0.0" - picocolors "^1.1.1" + version "0.2.3" + resolved "https://registry.yarnpkg.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.3.tgz#f1137f56209ccc69c15f826242cbf37f828617dd" + integrity sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw== -"@babel/code-frame@^7.16.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== @@ -710,25 +701,34 @@ js-tokens "^4.0.0" picocolors "^1.1.1" +"@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" + integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" - integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" + integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== -"@babel/core@^7.23.9", "@babel/core@^7.27.4": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" - integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw== +"@babel/core@^7.23.9": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e" + integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== dependencies: - "@babel/code-frame" "^7.28.6" - "@babel/generator" "^7.28.6" - "@babel/helper-compilation-targets" "^7.28.6" - "@babel/helper-module-transforms" "^7.28.6" - "@babel/helpers" "^7.28.6" - "@babel/parser" "^7.28.6" - "@babel/template" "^7.28.6" - "@babel/traverse" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.4" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" "@jridgewell/remapping" "^2.3.5" convert-source-map "^2.0.0" debug "^4.1.0" @@ -736,18 +736,29 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.27.5", "@babel/generator@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" - integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== +"@babel/generator@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.5.tgz#712722d5e50f44d07bc7ac9fe84438742dd61298" + integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== dependencies: - "@babel/parser" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/parser" "^7.28.5" + "@babel/types" "^7.28.5" "@jridgewell/gen-mapping" "^0.3.12" "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" -"@babel/helper-compilation-targets@^7.28.6": +"@babel/generator@^7.29.0": + version "7.29.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.2": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== @@ -771,7 +782,7 @@ "@babel/traverse" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/helper-module-transforms@^7.28.6": +"@babel/helper-module-transforms@^7.28.3": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== @@ -780,17 +791,17 @@ "@babel/helper-validator-identifier" "^7.28.5" "@babel/traverse" "^7.28.6" -"@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.28.6", "@babel/helper-plugin-utils@^7.8.0": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" - integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== - "@babel/helper-string-parser@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== -"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5": +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-identifier@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== @@ -800,139 +811,36 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== -"@babel/helpers@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" - integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== - dependencies: - "@babel/template" "^7.28.6" - "@babel/types" "^7.28.6" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" - integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== - dependencies: - "@babel/types" "^7.28.6" - -"@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-attributes@^7.24.7": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" - integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== - dependencies: - "@babel/helper-plugin-utils" "^7.28.6" - -"@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.28.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" - integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== - dependencies: - "@babel/helper-plugin-utils" "^7.28.6" - -"@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.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - 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== +"@babel/helpers@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827" + integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== dependencies: - "@babel/helper-plugin-utils" "^7.8.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" -"@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== +"@babel/parser@^7.23.9", "@babel/parser@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08" + integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== dependencies: - "@babel/helper-plugin-utils" "^7.8.0" + "@babel/types" "^7.28.5" -"@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== +"@babel/parser@^7.27.2", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" + integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/types" "^7.29.0" -"@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== +"@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.27.1": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" - integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== - dependencies: - "@babel/helper-plugin-utils" "^7.28.6" + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" "@babel/template@^7.28.6": version "7.28.6" @@ -943,31 +851,47 @@ "@babel/parser" "^7.28.6" "@babel/types" "^7.28.6" +"@babel/traverse@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b" + integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.5" + debug "^4.3.1" + "@babel/traverse@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" - integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg== + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== dependencies: - "@babel/code-frame" "^7.28.6" - "@babel/generator" "^7.28.6" + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" "@babel/helper-globals" "^7.28.0" - "@babel/parser" "^7.28.6" + "@babel/parser" "^7.29.0" "@babel/template" "^7.28.6" - "@babel/types" "^7.28.6" + "@babel/types" "^7.29.0" debug "^4.3.1" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" - integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg== +"@babel/types@^7.27.1", "@babel/types@^7.28.6", "@babel/types@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== dependencies: "@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== +"@babel/types@^7.28.4", "@babel/types@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b" + integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" "@borewit/text-codec@^0.1.0": version "0.1.1" @@ -1005,27 +929,135 @@ resolved "https://registry.yarnpkg.com/@dashlane/pqc-kem-kyber512-node/-/pqc-kem-kyber512-node-1.0.0.tgz#0305f8a6c86595a1dc3b0d16184237c71e912d8c" integrity sha512-gVzQwP/1OqKLyYZ/oRI9uECSnYIcLUcZbnAA34Q2l8X1eXq5JWf304tDp1UTdYdJ+ZE58SmQ68VCa/WvpCviGw== -"@emnapi/core@^1.4.3": - version "1.8.1" - resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349" - integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg== - dependencies: - "@emnapi/wasi-threads" "1.1.0" - tslib "^2.4.0" - -"@emnapi/runtime@^1.4.3": - version "1.8.1" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5" - integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== - 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" +"@esbuild/aix-ppc64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz#2ae33300598132cc4cf580dbbb28d30fed3c5c49" + integrity sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg== + +"@esbuild/android-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz#927708b3db5d739d6cb7709136924cc81bec9b03" + integrity sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ== + +"@esbuild/android-arm@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.11.tgz#571f94e7f4068957ec4c2cfb907deae3d01b55ae" + integrity sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg== + +"@esbuild/android-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.11.tgz#8a3bf5cae6c560c7ececa3150b2bde76e0fb81e6" + integrity sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g== + +"@esbuild/darwin-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz#0a678c4ac4bf8717e67481e1a797e6c152f93c84" + integrity sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w== + +"@esbuild/darwin-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz#70f5e925a30c8309f1294d407a5e5e002e0315fe" + integrity sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ== + +"@esbuild/freebsd-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz#4ec1db687c5b2b78b44148025da9632397553e8a" + integrity sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA== + +"@esbuild/freebsd-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz#4c81abd1b142f1e9acfef8c5153d438ca53f44bb" + integrity sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw== + +"@esbuild/linux-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz#69517a111acfc2b93aa0fb5eaeb834c0202ccda5" + integrity sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA== + +"@esbuild/linux-arm@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz#58dac26eae2dba0fac5405052b9002dac088d38f" + integrity sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw== + +"@esbuild/linux-ia32@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz#b89d4efe9bdad46ba944f0f3b8ddd40834268c2b" + integrity sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw== + +"@esbuild/linux-loong64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz#11f603cb60ad14392c3f5c94d64b3cc8b630fbeb" + integrity sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw== + +"@esbuild/linux-mips64el@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz#b7d447ff0676b8ab247d69dac40a5cf08e5eeaf5" + integrity sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ== + +"@esbuild/linux-ppc64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz#b3a28ed7cc252a61b07ff7c8fd8a984ffd3a2f74" + integrity sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw== + +"@esbuild/linux-riscv64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz#ce75b08f7d871a75edcf4d2125f50b21dc9dc273" + integrity sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww== + +"@esbuild/linux-s390x@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz#cd08f6c73b6b6ff9ccdaabbd3ff6ad3dca99c263" + integrity sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw== + +"@esbuild/linux-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz#3c3718af31a95d8946ebd3c32bb1e699bdf74910" + integrity sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ== + +"@esbuild/netbsd-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz#b4c767082401e3a4e8595fe53c47cd7f097c8077" + integrity sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg== + +"@esbuild/netbsd-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz#f2a930458ed2941d1f11ebc34b9c7d61f7a4d034" + integrity sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A== + +"@esbuild/openbsd-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz#b4ae93c75aec48bc1e8a0154957a05f0641f2dad" + integrity sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg== + +"@esbuild/openbsd-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz#b42863959c8dcf9b01581522e40012d2c70045e2" + integrity sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw== + +"@esbuild/openharmony-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz#b2e717141c8fdf6bddd4010f0912e6b39e1640f1" + integrity sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ== + +"@esbuild/sunos-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz#9fbea1febe8778927804828883ec0f6dd80eb244" + integrity sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA== + +"@esbuild/win32-arm64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz#501539cedb24468336073383989a7323005a8935" + integrity sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q== + +"@esbuild/win32-ia32@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz#8ac7229aa82cef8f16ffb58f1176a973a7a15343" + integrity sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA== + +"@esbuild/win32-x64@0.25.11": + version "0.25.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz#5ecda6f3fe138b7e456f4e429edde33c823f392f" + integrity sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.9.0" @@ -1059,11 +1091,6 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== -"@golevelup/ts-jest@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@golevelup/ts-jest/-/ts-jest-1.2.0.tgz#986c514080bd9960e6a9ec19d2f0e46c48d1bdc4" - integrity sha512-plN26rWBmwOrtWBc46FKgTMWDlLK5F/vYP2i+0NXnoOLdcXrTNDftzW4dpa0fREqUdCRb3EJtuyr6g5AKNKTRA== - "@grpc/grpc-js@^1.13.2": version "1.14.2" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.14.2.tgz#d245069181a1a8057abd35522d6052482730cf19" @@ -1338,243 +1365,12 @@ 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": +"@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": - 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": +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.13", "@jridgewell/gen-mapping@^0.3.5": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== @@ -1603,11 +1399,19 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": version "1.5.5" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== +"@jridgewell/trace-mapping@0.3.31", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@0.3.9": version "0.3.9" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" @@ -1616,10 +1420,10 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@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.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" - integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.30" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz#4a76c4daeee5df09f5d3940e087442fb36ce2b99" + integrity sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -1653,15 +1457,6 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz#2249090633e04063176863a050c8f0808d2b6d2b" integrity sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA== -"@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" - "@nest-lab/throttler-storage-redis@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@nest-lab/throttler-storage-redis/-/throttler-storage-redis-1.1.0.tgz#78f3dad83dbf6f890f27ce3f323b4a1e5f33e227" @@ -2188,6 +1983,116 @@ resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-5.10.0.tgz#9c7de35fe023e36233fba5c8478ce25832ead64c" integrity sha512-cPkpddXH5kc/SdRhF0YG0qtjL+noqFT0AcHbQ6axhsPsO7iqPi1cjxgdkE9TNeKiBUUdCaU1DbqkR/LzbzPBhg== +"@rollup/rollup-android-arm-eabi@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz#0f44a2f8668ed87b040b6fe659358ac9239da4db" + integrity sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ== + +"@rollup/rollup-android-arm64@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz#25b9a01deef6518a948431564c987bcb205274f5" + integrity sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA== + +"@rollup/rollup-darwin-arm64@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz#8a102869c88f3780c7d5e6776afd3f19084ecd7f" + integrity sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA== + +"@rollup/rollup-darwin-x64@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz#8e526417cd6f54daf1d0c04cf361160216581956" + integrity sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA== + +"@rollup/rollup-freebsd-arm64@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz#0e7027054493f3409b1f219a3eac5efd128ef899" + integrity sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA== + +"@rollup/rollup-freebsd-x64@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz#72b204a920139e9ec3d331bd9cfd9a0c248ccb10" + integrity sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz#ab1b522ebe5b7e06c99504cc38f6cd8b808ba41c" + integrity sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ== + +"@rollup/rollup-linux-arm-musleabihf@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz#f8cc30b638f1ee7e3d18eac24af47ea29d9beb00" + integrity sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ== + +"@rollup/rollup-linux-arm64-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz#7af37a9e85f25db59dc8214172907b7e146c12cc" + integrity sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg== + +"@rollup/rollup-linux-arm64-musl@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz#a623eb0d3617c03b7a73716eb85c6e37b776f7e0" + integrity sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q== + +"@rollup/rollup-linux-loong64-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz#76ea038b549c5c6c5f0d062942627c4066642ee2" + integrity sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA== + +"@rollup/rollup-linux-ppc64-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz#d9a4c3f0a3492bc78f6fdfe8131ac61c7359ccd5" + integrity sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw== + +"@rollup/rollup-linux-riscv64-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz#87ab033eebd1a9a1dd7b60509f6333ec1f82d994" + integrity sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw== + +"@rollup/rollup-linux-riscv64-musl@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz#bda3eb67e1c993c1ba12bc9c2f694e7703958d9f" + integrity sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg== + +"@rollup/rollup-linux-s390x-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz#f7bc10fbe096ab44694233dc42a2291ed5453d4b" + integrity sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ== + +"@rollup/rollup-linux-x64-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz#a151cb1234cc9b2cf5e8cfc02aa91436b8f9e278" + integrity sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q== + +"@rollup/rollup-linux-x64-musl@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz#7859e196501cc3b3062d45d2776cfb4d2f3a9350" + integrity sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg== + +"@rollup/rollup-openharmony-arm64@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz#85d0df7233734df31e547c1e647d2a5300b3bf30" + integrity sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw== + +"@rollup/rollup-win32-arm64-msvc@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz#e62357d00458db17277b88adbf690bb855cac937" + integrity sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w== + +"@rollup/rollup-win32-ia32-msvc@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz#fc7cd40f44834a703c1f1c3fe8bcc27ce476cd50" + integrity sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg== + +"@rollup/rollup-win32-x64-gnu@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz#1a22acfc93c64a64a48c42672e857ee51774d0d3" + integrity sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ== + +"@rollup/rollup-win32-x64-msvc@4.52.5": + version "4.52.5" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz#1657f56326bbe0ac80eedc9f9c18fc1ddd24e107" + integrity sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg== + "@scarf/scarf@=1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@scarf/scarf/-/scarf-1.4.0.tgz#3bbb984085dbd6d982494538b523be1ce6562972" @@ -2229,11 +2134,6 @@ "@sendgrid/client" "^8.1.5" "@sendgrid/helpers" "^8.0.0" -"@sinclair/typebox@^0.34.0": - version "0.34.48" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.48.tgz#75b0ead87e59e1adbd6dccdc42bad4fddee73b59" - integrity sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA== - "@sinonjs/commons@^3.0.0", "@sinonjs/commons@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" @@ -2248,7 +2148,7 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@sinonjs/fake-timers@^13.0.0", "@sinonjs/fake-timers@^13.0.1": +"@sinonjs/fake-timers@^13.0.1": 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== @@ -2776,6 +2676,11 @@ color "^5.0.2" text-hex "1.0.x" +"@standard-schema/spec@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" + integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== + "@tokenizer/inflate@^0.3.1": version "0.3.1" resolved "https://registry.yarnpkg.com/@tokenizer/inflate/-/inflate-0.3.1.tgz#f0b9162741e8e4c5fa0c56764a049355ad29e1f4" @@ -2810,46 +2715,6 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@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/bluebird@*": version "3.5.42" resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.42.tgz#7ec05f1ce9986d920313c1377a5662b1b563d366" @@ -2863,6 +2728,14 @@ "@types/connect" "*" "@types/node" "*" +"@types/chai@^5.2.2": + version "5.2.3" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-5.2.3.tgz#8e9cd9e1c3581fa6b341a5aed5588eb285be0b4a" + integrity sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA== + dependencies: + "@types/deep-eql" "*" + assertion-error "^2.0.1" + "@types/chance@^1.1.6": version "1.1.7" resolved "https://registry.yarnpkg.com/@types/chance/-/chance-1.1.7.tgz#388c19748fe97bbe60552c83a056001a3c973082" @@ -2899,6 +2772,11 @@ dependencies: "@types/ms" "*" +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + "@types/eslint-scope@^3.7.7": version "3.7.7" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" @@ -2915,7 +2793,7 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.8": +"@types/estree@*", "@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== @@ -2944,33 +2822,6 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.5.tgz#5b749ab2b16ba113423feb1a64a95dcd30398472" integrity sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg== -"@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/jest@^30.0.0": - version "30.0.0" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-30.0.0.tgz#5e85ae568006712e4ad66f25433e9bdac8801f1d" - integrity sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA== - dependencies: - expect "^30.0.0" - pretty-format "^30.0.0" - "@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -3143,11 +2994,6 @@ dependencies: "@types/node" "*" -"@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/superagent@^8.1.0": version "8.1.9" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-8.1.9.tgz#28bfe4658e469838ed0bf66d898354bcab21f49f" @@ -3176,18 +3022,6 @@ resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.15.10.tgz#742b77ec34d58554b94a76a14cef30d59e3c16b9" integrity sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA== -"@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" "*" - "@typescript-eslint/eslint-plugin@^5.4.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" @@ -3363,107 +3197,84 @@ resolved "https://registry.yarnpkg.com/@tyriar/fibonacci-heap/-/fibonacci-heap-2.0.9.tgz#df3dcbdb1b9182168601f6318366157ee16666e9" integrity sha512-bYuSNomfn4hu2tPiDN+JZtnzCpSpbJ/PNeulmocDy3xN2X5OkJL65zo6rPZp65cPPhLF9vfT/dgE+RtFRCSxOA== -"@ungap/structured-clone@^1.2.0", "@ungap/structured-clone@^1.3.0": +"@ungap/structured-clone@^1.2.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" 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== +"@vitest/coverage-istanbul@^4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/coverage-istanbul/-/coverage-istanbul-4.0.18.tgz#9521482686849c76c2feee2335bb9b914ecc4f06" + integrity sha512-0OhjP30owEDihYTZGWuq20rNtV1RjjJs1Mv4MaZIKcFBmiLUXX7HJLX4fU7wE+Mrc3lQxI2HKq6WrSXi5FGuCQ== 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== + "@istanbuljs/schema" "^0.1.3" + "@jridgewell/gen-mapping" "^0.3.13" + "@jridgewell/trace-mapping" "0.3.31" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-instrument "^6.0.3" + istanbul-lib-report "^3.0.1" + istanbul-reports "^3.2.0" + magicast "^0.5.1" + obug "^2.1.1" + tinyrainbow "^3.0.3" + +"@vitest/expect@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.0.18.tgz#361510d99fbf20eb814222e4afcb8539d79dc94d" + integrity sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ== + dependencies: + "@standard-schema/spec" "^1.0.0" + "@types/chai" "^5.2.2" + "@vitest/spy" "4.0.18" + "@vitest/utils" "4.0.18" + chai "^6.2.1" + tinyrainbow "^3.0.3" + +"@vitest/mocker@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.0.18.tgz#b9735da114ef65ea95652c5bdf13159c6fab4865" + integrity sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ== + dependencies: + "@vitest/spy" "4.0.18" + estree-walker "^3.0.3" + magic-string "^0.30.21" + +"@vitest/pretty-format@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.0.18.tgz#fbccd4d910774072ec15463553edb8ca5ce53218" + integrity sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw== + dependencies: + tinyrainbow "^3.0.3" + +"@vitest/runner@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.0.18.tgz#c2c0a3ed226ec85e9312f9cc8c43c5b3a893a8b1" + integrity sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw== + dependencies: + "@vitest/utils" "4.0.18" + pathe "^2.0.3" + +"@vitest/snapshot@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.0.18.tgz#bcb40fd6d742679c2ac927ba295b66af1c6c34c5" + integrity sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA== + dependencies: + "@vitest/pretty-format" "4.0.18" + magic-string "^0.30.21" + pathe "^2.0.3" + +"@vitest/spy@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.0.18.tgz#ba0f20503fb6d08baf3309d690b3efabdfa88762" + integrity sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw== + +"@vitest/utils@4.0.18": + version "4.0.18" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.0.18.tgz#9636b16d86a4152ec68a8d6859cff702896433d4" + integrity sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA== + dependencies: + "@vitest/pretty-format" "4.0.18" + tinyrainbow "^3.0.3" "@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": version "1.14.1" @@ -3719,13 +3530,6 @@ ansi-colors@4.1.3: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -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-escapes@^7.0.0: version "7.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.2.0.tgz#31b25afa3edd3efc09d98c2fee831d460ff06b49" @@ -3750,11 +3554,6 @@ 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.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: version "6.2.3" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" @@ -3765,14 +3564,6 @@ ansis@4.2.0: resolved "https://registry.yarnpkg.com/ansis/-/ansis-4.2.0.tgz#2e6e61c46b11726ac67f78785385618b9e658780" integrity sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig== -anymatch@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - append-field@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" @@ -3783,13 +3574,6 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -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.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -3820,6 +3604,11 @@ asn1.js@^5.0.0: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + "async@2.1 - 2.6.4": version "2.6.4" resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" @@ -3874,66 +3663,6 @@ axios@^1.12.0: form-data "^4.0.4" proxy-from-env "^1.1.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-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.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -4043,20 +3772,6 @@ browserslist@^4.24.0, browserslist@^4.28.1: node-releases "^2.0.27" update-browserslist-db "^1.2.0" -bs-logger@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -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" - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -4123,26 +3838,26 @@ call-bound@^1.0.2: call-bind-apply-helpers "^1.0.2" get-intrinsic "^1.3.0" -callsites@^3.0.0, callsites@^3.1.0: +callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.0.0, camelcase@^5.3.1: +camelcase@^5.0.0: 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.30001759: version "1.0.30001766" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz#b6f6b55cb25a2d888d9393104d14751c6a7d6f7a" integrity sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA== +chai@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-6.2.2.tgz#ae41b52c9aca87734505362717f3255facda360e" + integrity sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg== + "chalk@4.1 - 4.1.2", chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -4161,11 +3876,6 @@ chance@^1.1.13: resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.13.tgz#d4ecfd20c5e6799aaf5c2270d7653b32385cd6e3" integrity sha512-V6lQCljcLznE7tUYUM9EOAnnKXbctE6j/rdQkYOHIWbfGQbrzTsAXNW9CdU5XCo4ArXQCj/rb6HgxPlmGJcaUg== -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== - chardet@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/chardet/-/chardet-2.1.1.tgz#5c75593704a642f71ee53717df234031e65373c8" @@ -4193,21 +3903,11 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== -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@^1.2.2: version "1.4.3" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== -cjs-module-lexer@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz#b3ca5101843389259ade7d88c77bd06ce55849ca" - integrity sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ== - class-transformer@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" @@ -4300,16 +4000,6 @@ cluster-key-slot@1.1.2, cluster-key-slot@^1.1.0, cluster-key-slot@^1.1.2: resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" 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.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -4538,7 +4228,14 @@ dayjs@^1.11.13: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938" integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw== -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, debug@^4.4.3: +debug@4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.0: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +debug@^4.1.0, debug@^4.4.1, debug@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -4550,17 +4247,12 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== -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.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deepmerge@^4.2.2, deepmerge@^4.3.1: +deepmerge@^4.2.2: 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== @@ -4587,11 +4279,6 @@ depd@^2.0.0, depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 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" @@ -4697,11 +4384,6 @@ electron-to-chromium@^1.5.263: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.277.tgz#7164191a07bf32a7e646e68334f402dd60629821" integrity sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw== -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@^10.3.0: version "10.6.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" @@ -4772,6 +4454,11 @@ es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-module-lexer@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + es-module-lexer@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.0.0.tgz#f657cd7a9448dcdda9c070a3cb75e5dc1e85f5b1" @@ -4794,6 +4481,38 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" +esbuild@^0.25.0: + version "0.25.11" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.11.tgz#0f31b82f335652580f75ef6897bba81962d9ae3d" + integrity sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.11" + "@esbuild/android-arm" "0.25.11" + "@esbuild/android-arm64" "0.25.11" + "@esbuild/android-x64" "0.25.11" + "@esbuild/darwin-arm64" "0.25.11" + "@esbuild/darwin-x64" "0.25.11" + "@esbuild/freebsd-arm64" "0.25.11" + "@esbuild/freebsd-x64" "0.25.11" + "@esbuild/linux-arm" "0.25.11" + "@esbuild/linux-arm64" "0.25.11" + "@esbuild/linux-ia32" "0.25.11" + "@esbuild/linux-loong64" "0.25.11" + "@esbuild/linux-mips64el" "0.25.11" + "@esbuild/linux-ppc64" "0.25.11" + "@esbuild/linux-riscv64" "0.25.11" + "@esbuild/linux-s390x" "0.25.11" + "@esbuild/linux-x64" "0.25.11" + "@esbuild/netbsd-arm64" "0.25.11" + "@esbuild/netbsd-x64" "0.25.11" + "@esbuild/openbsd-arm64" "0.25.11" + "@esbuild/openbsd-x64" "0.25.11" + "@esbuild/openharmony-arm64" "0.25.11" + "@esbuild/sunos-x64" "0.25.11" + "@esbuild/win32-arm64" "0.25.11" + "@esbuild/win32-ia32" "0.25.11" + "@esbuild/win32-x64" "0.25.11" + escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -4804,11 +4523,6 @@ escape-html@^1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 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.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -4906,7 +4620,7 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -4935,6 +4649,13 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -4960,21 +4681,6 @@ events@3.3.0, events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -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" - execa@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" @@ -4990,22 +4696,10 @@ execa@^8.0.1: signal-exit "^4.1.0" strip-final-newline "^3.0.0" -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, expect@^30.0.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" +expect-type@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.2.2.tgz#c030a329fb61184126c8447585bc75a7ec6fbff3" + integrity sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA== express@5.1.0: version "5.1.0" @@ -5073,7 +4767,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.8" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5107,13 +4801,6 @@ 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.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -5121,6 +4808,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + fecha@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" @@ -5177,7 +4869,7 @@ find-package-json@^1.2.0: resolved "https://registry.yarnpkg.com/find-package-json/-/find-package-json-1.2.0.tgz#4057d1b943f82d8445fe52dc9cf456f6b8b58083" integrity sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw== -find-up@^4.0.0, find-up@^4.1.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== @@ -5321,7 +5013,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.3: +fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -5380,11 +5072,6 @@ get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: 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.1: version "1.0.1" resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" @@ -5398,11 +5085,6 @@ get-stdin@=8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -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-stream@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" @@ -5448,7 +5130,7 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^10.3.10, glob@^10.3.7, glob@^10.4.2: +glob@^10.3.7, glob@^10.4.2: version "10.5.0" resolved "https://registry.yarnpkg.com/glob/-/glob-10.5.0.tgz#8ec0355919cd3338c28428a23d4f24ecc5fe738c" integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg== @@ -5460,7 +5142,7 @@ glob@^10.3.10, glob@^10.3.7, glob@^10.4.2: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.1.4: +glob@^7.1.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -5506,18 +5188,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -handlebars@^4.7.8: - version "4.7.8" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" - integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.2" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -5604,11 +5274,6 @@ https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.4: 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== - human-signals@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" @@ -5678,14 +5343,6 @@ import-in-the-middle@^1.13.0: cjs-module-lexer "^1.2.2" module-details-from-path "^1.0.3" -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.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -5762,7 +5419,7 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-core-module@^2.16.1: +is-core-module@^2.16.0, is-core-module@^2.16.1: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== @@ -5796,11 +5453,6 @@ is-fullwidth-code-point@^5.0.0: dependencies: get-east-asian-width "^1.3.1" -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-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -5853,12 +5505,12 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0, istanbul-lib-coverage@^3.2.2: 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: +istanbul-lib-instrument@^6.0.3: 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== @@ -5869,7 +5521,7 @@ istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2: istanbul-lib-coverage "^3.2.0" semver "^7.5.4" -istanbul-lib-report@^3.0.0: +istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: 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== @@ -5878,16 +5530,7 @@ istanbul-lib-report@^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: +istanbul-reports@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== @@ -5909,352 +5552,6 @@ 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-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-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" @@ -6264,16 +5561,6 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -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" - joycon@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" @@ -6307,14 +5594,6 @@ js-yaml@4.1.1, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -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" - jsbn@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" @@ -6488,11 +5767,6 @@ lazy@1.0.11: resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== -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.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -6613,11 +5887,6 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -6714,6 +5983,22 @@ magic-string@0.30.17: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" +magic-string@^0.30.21: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +magicast@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.2.tgz#70cea9df729c164485049ea5df85a390281dfb9d" + integrity sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + source-map-js "^1.2.1" + make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -6721,18 +6006,11 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@^1.1.1, make-error@^1.3.6: +make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -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.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -6945,20 +6223,15 @@ mute-stream@^2.0.0: integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== nan@^2.22.2: - version "2.23.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.23.1.tgz#6f86a31dd87e3d1eb77512bf4b9e14c8aded3975" - integrity sha512-r7bBUGKzlqk8oPBDYxt6Z0aEdF1G1rwlMcLk8LCOMbOzf0mG+JUfUzG4fIMWwHWP0iyaLWEQZJmtB7nOHEm/qw== + version "2.23.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.23.0.tgz#24aa4ddffcc37613a2d2935b97683c1ec96093c6" + integrity sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ== -nanoid@3: +nanoid@3, nanoid@^3.3.11: version "3.3.11" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== -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-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -7069,11 +6342,6 @@ node-gyp-build@^4.8.1: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" 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.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" @@ -7086,11 +6354,6 @@ nopt@^7.2.1: dependencies: abbrev "^2.0.0" -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - npm-run-path@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" @@ -7098,13 +6361,6 @@ npm-run-path@^3.1.0: dependencies: path-key "^3.0.0" -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" - npm-run-path@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" @@ -7122,6 +6378,11 @@ object-inspect@^1.13.3: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== +obug@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/obug/-/obug-2.1.1.tgz#2cba74ff241beb77d63055ddf4cd1e9f90b538be" + integrity sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ== + on-exit-leak-free@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" @@ -7148,7 +6409,7 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -7210,7 +6471,7 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2, p-limit@^3.1.0: +p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -7343,6 +6604,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -7419,12 +6685,12 @@ picomatch@4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -picomatch@^2.0.4, picomatch@^2.3.1: +picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -picomatch@^4.0.2: +picomatch@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== @@ -7499,18 +6765,6 @@ pino@^10.0.0: sonic-boom "^4.0.1" thread-stream "^3.0.0" -pirates@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" - integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== - -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" - pluralize@8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" @@ -7521,6 +6775,15 @@ pngjs@^5.0.0: resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== +postcss@^8.5.6: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -7577,15 +6840,6 @@ pretty-bytes@^5.6.0: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== -pretty-format@30.2.0, pretty-format@^30.0.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" - prettysize@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prettysize/-/prettysize-2.0.0.tgz#902c02480d865d9cc0813011c9feb4fa02ce6996" @@ -7645,11 +6899,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -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== - qrcode@^1.4.4: version "1.5.4" resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.4.tgz#5cb81d86eb57c675febb08cf007fff963405da88" @@ -7711,11 +6960,6 @@ raw-body@^3.0.1: iconv-lite "~0.7.0" unpipe "~1.0.0" -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, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.1, readable-stream@^3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" @@ -7792,24 +7036,21 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -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.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 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: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.22.1, resolve@^1.22.8: +resolve@^1.22.8: version "1.22.11" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== @@ -7880,6 +7121,37 @@ ringbufferjs@^2.0.0: resolved "https://registry.yarnpkg.com/ringbufferjs/-/ringbufferjs-2.0.0.tgz#09f40e2675a99cfef430b7ec5815ac1bc2e24120" integrity sha512-GCOqTzUsTHF7nrqcgtNGAFotXztLgiePpIDpyWZ7R5I02tmfJWV+/yuJc//Hlsd8G+WzI1t/dc2y/w2imDZdog== +rollup@^4.43.0: + version "4.52.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.52.5.tgz#96982cdcaedcdd51b12359981f240f94304ec235" + integrity sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.52.5" + "@rollup/rollup-android-arm64" "4.52.5" + "@rollup/rollup-darwin-arm64" "4.52.5" + "@rollup/rollup-darwin-x64" "4.52.5" + "@rollup/rollup-freebsd-arm64" "4.52.5" + "@rollup/rollup-freebsd-x64" "4.52.5" + "@rollup/rollup-linux-arm-gnueabihf" "4.52.5" + "@rollup/rollup-linux-arm-musleabihf" "4.52.5" + "@rollup/rollup-linux-arm64-gnu" "4.52.5" + "@rollup/rollup-linux-arm64-musl" "4.52.5" + "@rollup/rollup-linux-loong64-gnu" "4.52.5" + "@rollup/rollup-linux-ppc64-gnu" "4.52.5" + "@rollup/rollup-linux-riscv64-gnu" "4.52.5" + "@rollup/rollup-linux-riscv64-musl" "4.52.5" + "@rollup/rollup-linux-s390x-gnu" "4.52.5" + "@rollup/rollup-linux-x64-gnu" "4.52.5" + "@rollup/rollup-linux-x64-musl" "4.52.5" + "@rollup/rollup-openharmony-arm64" "4.52.5" + "@rollup/rollup-win32-arm64-msvc" "4.52.5" + "@rollup/rollup-win32-ia32-msvc" "4.52.5" + "@rollup/rollup-win32-x64-gnu" "4.52.5" + "@rollup/rollup-win32-x64-msvc" "4.52.5" + fsevents "~2.3.2" + router@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" @@ -7956,10 +7228,10 @@ semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.7.2, semver@^7.7.3: - version "7.7.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" - integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== +semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.7.2: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== send@^1.1.0, send@^1.2.0: version "1.2.0" @@ -8104,7 +7376,12 @@ side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" -signal-exit@^3.0.2, signal-exit@^3.0.3: +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +signal-exit@^3.0.2: 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== @@ -8154,13 +7431,10 @@ sonic-boom@^4.0.1: dependencies: atomic-sleep "^1.0.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-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== source-map-support@^0.5.21, source-map-support@~0.5.20: version "0.5.21" @@ -8175,7 +7449,7 @@ source-map@0.7.4: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -8202,11 +7476,6 @@ sprintf-js@1.1.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== -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== - sql-formatter@^13.1.0: version "13.1.0" resolved "https://registry.yarnpkg.com/sql-formatter/-/sql-formatter-13.1.0.tgz#272cccd9b249daee601e791cb12eb3c93edfd626" @@ -8221,12 +7490,10 @@ stack-trace@0.0.x: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== -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" +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== standard-as-callback@^2.1.0: version "2.1.0" @@ -8238,6 +7505,11 @@ statuses@^2.0.1, statuses@~2.0.2: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== +std-env@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + stream-browserify@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -8265,14 +7537,6 @@ string-argv@^0.3.2: resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -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.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -8347,16 +7611,6 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 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-final-newline@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" @@ -8422,7 +7676,7 @@ supports-color@^7, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0, supports-color@^8.1.1: +supports-color@^8.0.0: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -8467,13 +7721,6 @@ synckit@^0.11.7: dependencies: "@pkgr/core" "^0.2.9" -synckit@^0.11.8: - version "0.11.12" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.12.tgz#abe74124264fbc00a48011b0d98bdc1cffb64a7b" - integrity sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ== - dependencies: - "@pkgr/core" "^0.2.9" - tapable@^2.2.0, tapable@^2.2.1, tapable@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.0.tgz#7e3ea6d5ca31ba8e078b560f0d83ce9a14aa8be6" @@ -8521,15 +7768,6 @@ terser@^5.31.1: commander "^2.20.0" source-map-support "~0.5.20" -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-hex@1.0.x: version "1.0.0" resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" @@ -8547,10 +7785,28 @@ thread-stream@^3.0.0: dependencies: real-require "^0.2.0" -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== +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.2.tgz#bdd2737fe2ba40bd6f918ae26642f264b99ca251" + integrity sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg== + +tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tinyrainbow@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.0.3.tgz#984a5b1c1b25854a9b6bccbe77964d0593d1ea42" + integrity sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q== to-regex-range@^5.0.1: version "5.0.1" @@ -8588,20 +7844,10 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== -ts-jest@^29.4.6: - version "29.4.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.4.6.tgz#51cb7c133f227396818b71297ad7409bb77106e9" - integrity sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA== - dependencies: - bs-logger "^0.2.6" - fast-json-stable-stringify "^2.1.0" - handlebars "^4.7.8" - json5 "^2.2.3" - lodash.memoize "^4.1.2" - make-error "^1.3.6" - semver "^7.7.3" - type-fest "^4.41.0" - yargs-parser "^21.1.1" +ts-essentials@>=10.0.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-10.1.1.tgz#4e1d29b7c9b33c1a2744482376634c4fafba5210" + integrity sha512-4aTB7KLHKmUvkjNj8V+EdnmuVTiECzn3K+zIbRthumvHu+j44x3w63xpfs0JL3NGIzGXqoQ7AV591xHO+XrOTw== ts-loader@^9.5.2: version "9.5.4" @@ -8652,7 +7898,7 @@ tsconfig-paths@4.2.0, tsconfig-paths@^4.1.2: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2.8.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.6.2: +tslib@2.8.1, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.6.2: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -8691,16 +7937,6 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 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@^4.41.0: - version "4.41.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" - integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== - type-is@^1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -8728,11 +7964,6 @@ typescript@5.9.3, typescript@^5.8.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== -uglify-js@^3.1.4: - version "3.19.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" - integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== - uid@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/uid/-/uid-2.0.2.tgz#4b5782abf0f2feeefc00fa88006b2b3b7af3e3b9" @@ -8796,33 +8027,6 @@ unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 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.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" @@ -8873,31 +8077,67 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -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" +validator@^13.15.20: + version "13.15.26" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.26.tgz#36c3deeab30e97806a658728a155c66fcaa5b944" + integrity sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA== -validator@^13.15.20, validator@^13.9.0: - version "13.15.23" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.23.tgz#59a874f84e4594588e3409ab1edbe64e96d0c62d" - integrity sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw== +validator@^13.9.0: + version "13.15.20" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.20.tgz#054e9238109538a1bf46ae3e1290845a64fa2186" + integrity sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw== vary@^1, vary@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -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" +"vite@^6.0.0 || ^7.0.0": + version "7.1.12" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.12.tgz#8b29a3f61eba23bcb93fc9ec9af4a3a1e83eecdb" + integrity sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug== + dependencies: + esbuild "^0.25.0" + fdir "^6.5.0" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.43.0" + tinyglobby "^0.2.15" + optionalDependencies: + fsevents "~2.3.3" + +vitest-mock-extended@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/vitest-mock-extended/-/vitest-mock-extended-3.1.0.tgz#d4e23f4bbc18d07c4ab928b861e74414c942c974" + integrity sha512-vCM0VkuocOUBwwqwV7JB7YStw07pqeKvEIrZnR8l3PtwYi6rAAJAyJACeC1UYNfbQWi85nz7EdiXWBFI5hll2g== + dependencies: + ts-essentials ">=10.0.0" + +vitest@^4.0.18: + version "4.0.18" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.0.18.tgz#56f966353eca0b50f4df7540cd4350ca6d454a05" + integrity sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ== + dependencies: + "@vitest/expect" "4.0.18" + "@vitest/mocker" "4.0.18" + "@vitest/pretty-format" "4.0.18" + "@vitest/runner" "4.0.18" + "@vitest/snapshot" "4.0.18" + "@vitest/spy" "4.0.18" + "@vitest/utils" "4.0.18" + es-module-lexer "^1.7.0" + expect-type "^1.2.2" + magic-string "^0.30.21" + obug "^2.1.1" + pathe "^2.0.3" + picomatch "^4.0.3" + std-env "^3.10.0" + tinybench "^2.9.0" + tinyexec "^1.0.2" + tinyglobby "^0.2.15" + tinyrainbow "^3.0.3" + vite "^6.0.0 || ^7.0.0" + why-is-node-running "^2.3.0" watchpack@^2.5.1: version "2.5.1" @@ -8967,6 +8207,14 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + winston-transport@^4.5.0, winston-transport@^4.9.0: version "4.9.0" resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.9.0.tgz#3bba345de10297654ea6f33519424560003b3bf9" @@ -9005,11 +8253,6 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -9060,14 +8303,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 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" - ws@^8.17.1: version "8.18.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472"