diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..cfc635a --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(find:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index cf2d829..551c230 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -24,7 +24,7 @@ jobs: strategy: matrix: - node-version: [20.x] + node-version: [22.17.1] steps: - uses: actions/checkout@v4 diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..9fe0738 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.17.1 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3b76835 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "eslint.enable": true, + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], + "eslint.workingDirectories": [ + { + "mode": "auto" + } + ], + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "editor.formatOnSave": false, + "eslint.options": { + "overrideConfigFile": ".eslintrc.cjs" + }, + "eslint.nodePath": "./node_modules" +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5a605f5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,19 @@ +# Claude instructions + +## Vendomatic API + +Things to consider: + +* Everytime you generate code or suggest code explain the reasons of the changes + +* Use your best judgement and don't be afraid to ask questions. + +* Please use the latest documentation and best practices for anything. + +* Please use the latest version of the codebase and best practices for anything. + +* Always consider the project specification described in PROJECT_SPECIFICATION.md + +* Define properties and functions inside object always sorted alphabetically. + +* All source code should be written in TypeScript and use absolute imports. diff --git a/PROJECT_SPECIFICATION.md b/PROJECT_SPECIFICATION.md new file mode 100644 index 0000000..2f31181 --- /dev/null +++ b/PROJECT_SPECIFICATION.md @@ -0,0 +1,229 @@ +# 🏪 Vendomatic - Sistema de Gestão de Máquinas de Venda Automática + +## 📋 Visão Geral do Projeto + +O **Vendomatic** é um sistema de dashboard/backoffice para gestão e monitorização de máquinas de venda automática de uma empresa. O sistema permite o controle completo das operações, desde a gestão de máquinas e produtos até ao acompanhamento de reabastecimentos e manutenção. + +## 🎯 Objetivos Principais + +### Gestão de Máquinas + +- Adicionar, remover e alterar localização das máquinas +- Monitorizar o estado operacional de cada máquina +- Registar informações de localização e configuração + +### Gestão de Produtos + +- Gerir produtos em cada máquina individualmente +- Definir preços variáveis por localização +- Controlar stock e disponibilidade + +### Controlo de Reabastecimentos + +- Registar reabastecimentos com detalhes completos +- Rastrear quantidades adicionadas e dinheiro recolhido +- Documentar produtos descartados (desperdício) +- Associar funcionário responsável a cada operação + +### Manutenção e Monitorização + +- Registar atividades de manutenção +- Acompanhar histórico de intervenções +- Análise estatística (implementação futura) + +--- + +## 👥 User Stories + +### 🏢 Gestão de Máquinas + +**US001 - Adicionar Nova Máquina** + +> Como administrador, quero adicionar uma nova máquina ao sistema para poder começar a monitorizá-la. +> + +**Critérios de Aceitação:** + +- Posso inserir localização, código identificador e configurações iniciais +- O sistema valida se o código da máquina é único +- A máquina fica imediatamente disponível para gestão de produtos + +**US002 - Alterar Localização de Máquina** + +> Como administrador, quero alterar a localização de uma máquina existente para manter os dados atualizados. +> + +**Critérios de Aceitação:** + +- Posso selecionar uma máquina existente +- Posso alterar a localização mantendo o histórico +- Os preços dos produtos são atualizados conforme a nova localização + +**US003 - Remover Máquina** + +> Como administrador, quero remover uma máquina do sistema quando ela é desativada. +> + +**Critérios de Aceitação:** + +- Posso marcar uma máquina como inativa +- O histórico de operações é mantido +- A máquina não aparece nas operações ativas + +### 🛍️ Gestão de Produtos + +**US004 - Adicionar Produto à Máquina** + +> Como administrador, quero adicionar um produto a uma máquina específica para disponibilizá-lo aos clientes. +> + +**Critérios de Aceitação:** + +- Posso selecionar produto do catálogo ou criar novo +- Posso definir preço específico para a localização +- Posso definir quantidade inicial e capacidade máxima + +**US005 - Atualizar Preço de Produto** + +> Como administrador, quero atualizar o preço de um produto numa máquina específica. +> + +**Critérios de Aceitação:** + +- Posso alterar preço mantendo histórico de alterações +- A alteração é específica para a máquina/localização +- Sistema regista data e utilizador da alteração + +**US006 - Remover Produto da Máquina** + +> Como administrador, quero remover um produto de uma máquina quando não está mais disponível. +> + +**Critérios de Aceitação:** + +- Posso remover produto mantendo histórico +- Sistema alerta se há stock existente +- Remoção não afeta outras máquinas + +### 📦 Gestão de Reabastecimentos + +**US007 - Registar Reabastecimento** + +> Como funcionário, quero registar um reabastecimento para manter o controlo de stock e dinheiro. +> + +**Critérios de Aceitação:** + +- Posso selecionar máquina e produtos reabastecidos +- Posso inserir quantidades adicionadas por produto +- Posso registar valor monetário recolhido +- Sistema regista automaticamente minha identificação + +**US008 - Registar Desperdício** + +> Como funcionário, quero registar produtos descartados durante o reabastecimento. +> + +**Critérios de Aceitação:** + +- Posso selecionar produtos descartados e quantidades +- Sistema calcula valor monetário do desperdício +- Posso adicionar motivo do descarte +- Informação fica associada ao reabastecimento + +**US009 - Consultar Histórico de Reabastecimentos** + +> Como administrador, quero consultar o histórico de reabastecimentos para análise operacional. +> + +**Critérios de Aceitação:** + +- Posso filtrar por máquina, funcionário ou período +- Posso ver detalhes de cada reabastecimento +- Posso exportar relatórios + +### 🔧 Gestão de Manutenção + +**US010 - Registar Manutenção** + +> Como técnico, quero registar atividades de manutenção realizadas numa máquina. +> + +**Critérios de Aceitação:** + +- Posso selecionar máquina e tipo de manutenção +- Posso inserir descrição detalhada da intervenção +- Sistema regista data, hora e técnico responsável +- Posso anexar fotos ou documentos + +**US011 - Consultar Histórico de Manutenção** + +> Como administrador, quero consultar o histórico de manutenção para planeamento preventivo. +> + +**Critérios de Aceitação:** + +- Posso filtrar por máquina, tipo ou período +- Posso ver frequência de intervenções +- Posso identificar máquinas com mais problemas + +### 📊 Relatórios e Análise (Implementação Futura) + +**US012 - Visualizar Estatísticas de Vendas** + +> Como administrador, quero visualizar estatísticas gráficas de vendas por produto e máquina. +> + +**US013 - Análise de Rentabilidade** + +> Como gestor, quero analisar a rentabilidade de cada máquina e localização. +> + +**US014 - Relatório de Desperdício** + +> Como administrador, quero analisar padrões de desperdício para otimizar operações. +> + +--- + +## 🔐 Perfis de Utilizador + +### Administrador + +- Acesso completo a todas as funcionalidades +- Gestão de utilizadores e permissões +- Acesso a relatórios e análises + +### Funcionário/Técnico + +- Registar reabastecimentos e manutenção +- Consultar informações das máquinas +- Acesso limitado a relatórios + +### Gestor + +- Visualizar relatórios e análises +- Monitorizar performance operacional +- Não pode alterar configurações + +--- + +## 🛠️ Funcionalidades Técnicas + +### Autenticação e Autorização + +- Sistema de login seguro +- Gestão de perfis e permissões +- Auditoria de ações dos utilizadores + +### Interface Responsiva + +- Dashboard adaptável a diferentes dispositivos +- Navegação intuitiva e eficiente +- Feedback visual para ações do utilizador + +### Gestão de Dados + +- Base de dados robusta e escalável +- Backup automático de informações +- Exportação de dados em diferentes formatos diff --git a/env/custom.env.ts b/env/custom.env.ts index d134ecb..641d309 100644 --- a/env/custom.env.ts +++ b/env/custom.env.ts @@ -33,6 +33,10 @@ export default () => { server: { port: process.env.SERVER_PORT ?? 3000, }, + supabase: { + key: process.env.SUPABASE_KEY, + url: process.env.SUPABASE_URL, + }, }; return merge(customConfig, configuration()); diff --git a/env/test.env.ts b/env/test.env.ts index 245bf1e..5034973 100644 --- a/env/test.env.ts +++ b/env/test.env.ts @@ -11,4 +11,8 @@ export default () => ({ graphql: { debug: true, }, + supabase: { + key: 'test', + url: 'http://localhost:54321', + }, }); diff --git a/jest.config.cjs b/jest.config.cjs index 08edf8c..a8f1e66 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -18,4 +18,10 @@ module.exports = { transform: { '^.+\\.(t|j)s$': 'ts-jest', }, + collectCoverageFrom: [ + 'src/**/*.(t|j)s', + '!src/**/*.spec.ts', + '!src/**/*.e2e-spec.ts', + ], + coverageDirectory: './coverage', }; diff --git a/package.json b/package.json index 70e39ba..f75ec0f 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "author": "", "private": true, "license": "UNLICENSED", + "engines": { + "node": ">=22.17.1" + }, "scripts": { "build": "nest build", "docker": "docker-compose -f docker-compose.dev.yml up", @@ -12,7 +15,7 @@ "format:fix": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\"", - "migration:generate": "yarn typeorm migration:generate", + "migration:generate": "yarn typeorm migration:create", "migration:revert": "yarn typeorm migration:revert", "migration:run": "yarn build && yarn typeorm migration:run -d ./dist/src/database/datasource.config.js", "prepare": "husky", @@ -38,6 +41,9 @@ "@nestjs/graphql": "^12.2.0", "@nestjs/platform-express": "^10.0.0", "@nestjs/typeorm": "^10.0.2", + "@supabase/supabase-js": "^2.52.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", "graphql": "^16.9.0", "lodash": "^4.17.21", "pg": "^8.12.0", @@ -68,7 +74,8 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-sort-destructure-keys": "^2.0.0", "husky": "^9.0.11", - "jest": "^29.5.0", + "jest": "^30.0.5", + "jest-mock-extended": "^4.0.0", "prettier": "^3.3.3", "source-map-support": "^0.5.21", "supertest": "^7.0.0", @@ -78,22 +85,5 @@ "tsconfig-paths": "^4.2.0", "typescript": "^5.1.3", "webpack": "^5.93.0" - }, - "jest": { - "moduleFileExtensions": [ - "js", - "json", - "ts" - ], - "rootDir": "src", - "testRegex": ".*\\.spec\\.ts$", - "transform": { - "^.+\\.(t|j)s$": "ts-jest" - }, - "collectCoverageFrom": [ - "**/*.(t|j)s" - ], - "coverageDirectory": "../coverage", - "testEnvironment": "node" } } diff --git a/schema.gql b/schema.gql index 578ffd7..813b611 100644 --- a/schema.gql +++ b/schema.gql @@ -2,6 +2,24 @@ # THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) # ------------------------------------------------------ +type User { + email: String! + id: ID! + name: String + role: String! +} + +type Session { + accessToken: String! + expiresIn: Float! + refreshToken: String! +} + +type AuthOutput { + session: Session! + user: User! +} + type Spot { createdAt: DateTime! id: String! @@ -18,12 +36,24 @@ scalar DateTime type Query { spots: [Spot!]! spot(id: String!): Spot! + + """Get current authenticated user""" + me: User! } type Mutation { createSpot(input: CreateSpotInput!): Spot! updateSpot(id: String!, input: UpdateSpotInput!): Spot! removeSpot(id: String!): Spot! + + """Login with email and password""" + login(input: LoginInput!): AuthOutput! + + """Logout current user""" + logout: Boolean! + + """Refresh access token""" + refreshToken(input: RefreshTokenInput!): AuthOutput! } input CreateSpotInput { @@ -34,4 +64,13 @@ input CreateSpotInput { input UpdateSpotInput { location: String name: String +} + +input LoginInput { + email: String! + password: String! +} + +input RefreshTokenInput { + refreshToken: String! } \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index 47b2801..60e9b65 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,12 +1,16 @@ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; import { Module } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; +import { APP_INTERCEPTOR } from '@nestjs/core'; import { GraphQLModule } from '@nestjs/graphql'; import { AppService } from '@app/app.service'; +import { AuthModule } from '@auth/auth.module'; +import { LoggingInterceptor } from '@common/interceptors/logging.interceptor'; import { ConfigModule } from '@config/config.module'; import { DatabaseModule } from '@database/database.module'; import { SpotModule } from '@spot/spot.module'; +import { UserModule } from '@user/user.module'; process.env.NODE_ENV = process.env.NODE_ENV || 'test'; @@ -27,7 +31,15 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'test'; }), DatabaseModule, SpotModule, + AuthModule, + UserModule, + ], + providers: [ + AppService, + { + provide: APP_INTERCEPTOR, + useClass: LoggingInterceptor, + }, ], - providers: [AppService], }) export class AppModule {} diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 0000000..8b0b511 --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; + +import { AuthResolver } from '@auth/auth.resolver'; +import { AuthService } from '@auth/auth.service'; +import { GqlAuthGuard } from '@auth/guards/gql-auth.guard'; +import { ConfigModule } from '@config/config.module'; + +@Module({ + exports: [AuthService, GqlAuthGuard], + imports: [ConfigModule], + providers: [AuthResolver, AuthService, GqlAuthGuard], +}) +export class AuthModule {} diff --git a/src/auth/auth.resolver.ts b/src/auth/auth.resolver.ts new file mode 100644 index 0000000..125cb8a --- /dev/null +++ b/src/auth/auth.resolver.ts @@ -0,0 +1,36 @@ +import { UseGuards } from '@nestjs/common'; +import { Args, Mutation, Resolver } from '@nestjs/graphql'; + +import { AuthService } from '@auth/auth.service'; +import { AuthState as AuthStateType } from '@auth/auth.types'; +import { AuthState } from '@auth/decorators/auth-state.decorator'; +import { Roles } from '@auth/decorators/roles.decorator'; +import { LoginInput } from '@auth/dto/login.input'; +import { RefreshTokenInput } from '@auth/dto/refresh-token.input'; +import { AuthOutput } from '@auth/entities/auth.entity'; +import { Role } from '@auth/enums/role.enum'; +import { GqlAuthGuard } from '@auth/guards/gql-auth.guard'; + +@Resolver(() => AuthOutput) +export class AuthResolver { + constructor(private authService: AuthService) {} + + @Mutation(() => AuthOutput, { description: 'Login with email and password' }) + async login(@Args('input') loginInput: LoginInput): Promise { + return this.authService.login(loginInput); + } + + @Mutation(() => Boolean, { description: 'Logout current user' }) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN, Role.TECHNICIAN) + async logout(@AuthState() authState: AuthStateType): Promise { + return this.authService.logout(authState.token); + } + + @Mutation(() => AuthOutput, { description: 'Refresh access token' }) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN, Role.TECHNICIAN) + async refreshToken(@Args('input') refreshTokenInput: RefreshTokenInput): Promise { + return this.authService.refreshToken(refreshTokenInput); + } +} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts new file mode 100644 index 0000000..29c717e --- /dev/null +++ b/src/auth/auth.service.ts @@ -0,0 +1,104 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { createClient, SupabaseClient, User as SupabaseUser } from '@supabase/supabase-js'; + +import { LoginInput } from '@auth/dto/login.input'; +import { RefreshTokenInput } from '@auth/dto/refresh-token.input'; +import { AuthOutput, User } from '@auth/entities/auth.entity'; + +@Injectable() +export class AuthService { + private supabase: SupabaseClient; + + constructor(private configService: ConfigService) { + this.supabase = createClient( + this.configService.get('supabase.url'), + this.configService.get('supabase.key'), + ); + } + + private mapSupabaseUserToUser(supabaseUser: SupabaseUser): User { + if (!supabaseUser.email) { + throw new UnauthorizedException('User email not found'); + } + + if (!supabaseUser.user_metadata?.role) { + throw new UnauthorizedException('User role not defined'); + } + + return { + email: supabaseUser.email, + id: supabaseUser.id, + name: supabaseUser.user_metadata?.name || null, + role: supabaseUser.user_metadata.role, + }; + } + + async getLoggedUser(accessToken: string): Promise { + const { + data: { user }, + error, + } = await this.supabase.auth.getUser(accessToken); + + if (error || !user) { + return null; + } + + return this.mapSupabaseUserToUser(user); + } + + async login(loginInput: LoginInput): Promise { + const { email, password } = loginInput; + + const { data, error } = await this.supabase.auth.signInWithPassword({ + email, + password, + }); + + if (error || !data.session || !data.user) { + throw new UnauthorizedException('Invalid credentials'); + } + + const user = this.mapSupabaseUserToUser(data.user); + + return { + session: { + accessToken: data.session.access_token, + expiresIn: data.session.expires_in!, + refreshToken: data.session.refresh_token, + }, + user, + }; + } + + async logout(accessToken: string): Promise { + const { error } = await this.supabase.auth.admin.signOut(accessToken); + + if (error) { + throw new UnauthorizedException('Failed to logout'); + } + + return true; + } + + async refreshToken(refreshTokenInput: RefreshTokenInput): Promise { + const { data, error } = await this.supabase.auth.refreshSession({ + refresh_token: refreshTokenInput.refreshToken, + }); + + if (error || !data.session || !data.user) { + throw new UnauthorizedException('Invalid refresh token'); + } + + const user = this.mapSupabaseUserToUser(data.user); + + return { + session: { + accessToken: data.session.access_token, + expiresIn: data.session.expires_in!, + refreshToken: data.session.refresh_token, + }, + user, + }; + } +} diff --git a/src/auth/auth.types.ts b/src/auth/auth.types.ts new file mode 100644 index 0000000..a90914f --- /dev/null +++ b/src/auth/auth.types.ts @@ -0,0 +1,10 @@ +import { User } from '@auth/entities/auth.entity'; + +export interface AuthState { + token: string; + user: User; +} + +export interface AuthContext { + state: AuthState; +} diff --git a/src/auth/decorators/auth-state.decorator.ts b/src/auth/decorators/auth-state.decorator.ts new file mode 100644 index 0000000..8c4d2a8 --- /dev/null +++ b/src/auth/decorators/auth-state.decorator.ts @@ -0,0 +1,13 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; +import { GqlExecutionContext } from '@nestjs/graphql'; + +import { AuthContext, AuthState as AuthStateType } from '@auth/auth.types'; + +export const AuthState = createParamDecorator( + (_data: unknown, context: ExecutionContext): AuthStateType => { + const ctx = GqlExecutionContext.create(context); + const gqlContext = ctx.getContext(); + + return gqlContext.state; + }, +); diff --git a/src/auth/decorators/roles.decorator.ts b/src/auth/decorators/roles.decorator.ts new file mode 100644 index 0000000..5daee42 --- /dev/null +++ b/src/auth/decorators/roles.decorator.ts @@ -0,0 +1,6 @@ +import { SetMetadata } from '@nestjs/common'; + +import { Role } from '@auth/enums/role.enum'; +import { AUTH_ROLES_KEY } from '@common/constants/auth.constants'; + +export const Roles = (...roles: Role[]) => SetMetadata(AUTH_ROLES_KEY, roles); diff --git a/src/auth/dto/login.input.ts b/src/auth/dto/login.input.ts new file mode 100644 index 0000000..d09eab4 --- /dev/null +++ b/src/auth/dto/login.input.ts @@ -0,0 +1,14 @@ +import { Field, InputType } from '@nestjs/graphql'; +import { IsEmail, IsNotEmpty } from 'class-validator'; + +@InputType() +export class LoginInput { + @Field() + @IsEmail() + @IsNotEmpty() + email: string; + + @Field() + @IsNotEmpty() + password: string; +} diff --git a/src/auth/dto/refresh-token.input.ts b/src/auth/dto/refresh-token.input.ts new file mode 100644 index 0000000..2a5751b --- /dev/null +++ b/src/auth/dto/refresh-token.input.ts @@ -0,0 +1,9 @@ +import { Field, InputType } from '@nestjs/graphql'; +import { IsNotEmpty } from 'class-validator'; + +@InputType() +export class RefreshTokenInput { + @Field() + @IsNotEmpty() + refreshToken: string; +} diff --git a/src/auth/entities/auth.entity.ts b/src/auth/entities/auth.entity.ts new file mode 100644 index 0000000..49f4c71 --- /dev/null +++ b/src/auth/entities/auth.entity.ts @@ -0,0 +1,37 @@ +import { ObjectType, Field, ID } from '@nestjs/graphql'; + +@ObjectType() +export class User { + @Field() + email: string; + + @Field(() => ID) + id: string; + + @Field({ nullable: true }) + name?: string; + + @Field() + role: string; +} + +@ObjectType() +export class Session { + @Field() + accessToken: string; + + @Field() + expiresIn: number; + + @Field() + refreshToken: string; +} + +@ObjectType() +export class AuthOutput { + @Field(() => Session) + session: Session; + + @Field(() => User) + user: User; +} diff --git a/src/auth/enums/role.enum.ts b/src/auth/enums/role.enum.ts new file mode 100644 index 0000000..2d6b95b --- /dev/null +++ b/src/auth/enums/role.enum.ts @@ -0,0 +1,4 @@ +export enum Role { + ADMIN = 'admin', + TECHNICIAN = 'technician', +} diff --git a/src/auth/guards/gql-auth.guard.spec.ts b/src/auth/guards/gql-auth.guard.spec.ts new file mode 100644 index 0000000..2ead64a --- /dev/null +++ b/src/auth/guards/gql-auth.guard.spec.ts @@ -0,0 +1,217 @@ +import { ExecutionContext, UnauthorizedException } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { GqlExecutionContext } from '@nestjs/graphql'; +import { Test, TestingModule } from '@nestjs/testing'; + +import { AuthService } from '@auth/auth.service'; +import { Role } from '@auth/enums/role.enum'; +import { GqlAuthGuard } from '@auth/guards/gql-auth.guard'; + +describe('GqlAuthGuard', () => { + let guard: GqlAuthGuard; + + const mockAuthService = { + getLoggedUser: jest.fn(), + }; + + const mockReflector = { + getAllAndOverride: jest.fn(), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + GqlAuthGuard, + { + provide: AuthService, + useValue: mockAuthService, + }, + { + provide: Reflector, + useValue: mockReflector, + }, + ], + }).compile(); + + guard = module.get(GqlAuthGuard); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + const createMockExecutionContext = (headers: Record = {}): ExecutionContext => { + const contextState = { + value: null, + }; + + const mockContext = { + getContext: jest.fn().mockReturnValue({ + req: { + headers, + }, + state: contextState, + }), + } as unknown as GqlExecutionContext; + + // Make state property writable + Object.defineProperty(mockContext.getContext(), 'state', { + configurable: true, + get: () => contextState.value, + set: (value) => { + contextState.value = value; + }, + }); + + const executionContext = { + getArgByIndex: jest.fn(), + getArgs: jest.fn(), + getClass: jest.fn(), + getHandler: jest.fn(), + getType: jest.fn(), + switchToHttp: jest.fn(), + switchToRpc: jest.fn(), + switchToWs: jest.fn(), + } as unknown as ExecutionContext; + + jest.spyOn(GqlExecutionContext, 'create').mockReturnValue(mockContext); + + return executionContext; + }; + + describe('canActivate', () => { + it('should return true when valid Bearer token is provided and user exists', async () => { + const mockUser = { + email: 'test@example.com', + id: 'user-123', + name: 'Test User', + role: Role.ADMIN, + }; + + const context = createMockExecutionContext({ + authorization: 'Bearer valid-token', + }); + + mockAuthService.getLoggedUser.mockResolvedValue(mockUser); + mockReflector.getAllAndOverride.mockReturnValue(undefined); + + const result = await guard.canActivate(context); + + expect(result).toBe(true); + expect(mockAuthService.getLoggedUser).toHaveBeenCalledWith('valid-token'); + expect(mockReflector.getAllAndOverride).toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when no authorization header is provided', async () => { + const context = createMockExecutionContext({}); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when authorization header is empty', async () => { + const context = createMockExecutionContext({ + authorization: '', + }); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when authorization header has invalid format', async () => { + const context = createMockExecutionContext({ + authorization: 'InvalidFormat token', + }); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when authorization header is missing Bearer prefix', async () => { + const context = createMockExecutionContext({ + authorization: 'valid-token', + }); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when Bearer token is empty', async () => { + const context = createMockExecutionContext({ + authorization: 'Bearer ', + }); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when user is not found', async () => { + const context = createMockExecutionContext({ + authorization: 'Bearer invalid-token', + }); + + mockAuthService.getLoggedUser.mockResolvedValue(null); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).toHaveBeenCalledWith('invalid-token'); + }); + + it('should throw UnauthorizedException when Bearer has multiple spaces before token', async () => { + const context = createMockExecutionContext({ + authorization: 'Bearer valid-token', + }); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should throw UnauthorizedException when bearer is lowercase', async () => { + const context = createMockExecutionContext({ + authorization: 'bearer valid-token', + }); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + expect(mockAuthService.getLoggedUser).not.toHaveBeenCalled(); + }); + + it('should enforce role-based access when roles are required', async () => { + const mockUser = { + email: 'test@example.com', + id: 'user-123', + name: 'Test User', + role: Role.TECHNICIAN, + }; + + const context = createMockExecutionContext({ + authorization: 'Bearer valid-token', + }); + + mockAuthService.getLoggedUser.mockResolvedValue(mockUser); + mockReflector.getAllAndOverride.mockReturnValue([Role.ADMIN]); + + await expect(guard.canActivate(context)).rejects.toThrow('Access denied'); + expect(mockAuthService.getLoggedUser).toHaveBeenCalledWith('valid-token'); + }); + + it('should allow access when user has required role', async () => { + const mockUser = { + email: 'test@example.com', + id: 'user-123', + name: 'Test User', + role: Role.ADMIN, + }; + + const context = createMockExecutionContext({ + authorization: 'Bearer valid-token', + }); + + mockAuthService.getLoggedUser.mockResolvedValue(mockUser); + mockReflector.getAllAndOverride.mockReturnValue([Role.ADMIN, Role.TECHNICIAN]); + + const result = await guard.canActivate(context); + + expect(result).toBe(true); + expect(mockAuthService.getLoggedUser).toHaveBeenCalledWith('valid-token'); + }); + }); +}); diff --git a/src/auth/guards/gql-auth.guard.ts b/src/auth/guards/gql-auth.guard.ts new file mode 100644 index 0000000..df89d65 --- /dev/null +++ b/src/auth/guards/gql-auth.guard.ts @@ -0,0 +1,73 @@ +import { + CanActivate, + ExecutionContext, + ForbiddenException, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { GqlExecutionContext } from '@nestjs/graphql'; +import { Request } from 'express'; + +import { AuthService } from '@auth/auth.service'; +import { Role } from '@auth/enums/role.enum'; +import { AUTH_ROLES_KEY } from '@common/constants/auth.constants'; + +@Injectable() +export class GqlAuthGuard implements CanActivate { + constructor( + private authService: AuthService, + private reflector: Reflector, + ) {} + + async canActivate(context: ExecutionContext): Promise { + const ctx = GqlExecutionContext.create(context); + const gqlContext = ctx.getContext(); + const token = this.extractTokenFromHeader(gqlContext.req); + const user = await this.authService.getLoggedUser(token); + + if (!user) { + throw new UnauthorizedException('Invalid token'); + } + + const requiredRoles = this.reflector.getAllAndOverride(AUTH_ROLES_KEY, [ + context.getHandler(), + context.getClass(), + ]); + + if (!requiredRoles || requiredRoles.length === 0) { + return true; + } + + const hasRole = requiredRoles.some((role) => user.role === role); + + if (!hasRole) { + throw new ForbiddenException('Access denied'); + } + + // Attach authenticated state to GraphQL context + gqlContext.state = { token, user }; + + return true; + } + + private extractTokenFromHeader(request: Request): string | undefined { + const authHeader = request.headers.authorization; + + if (!authHeader) { + throw new UnauthorizedException('Authorization header missing'); + } + + const [type, token] = authHeader.split(' ') ?? []; + + if (type !== 'Bearer') { + throw new UnauthorizedException('Invalid authorization header'); + } + + if (!token) { + throw new UnauthorizedException('Token missing'); + } + + return token; + } +} diff --git a/src/common/constants/auth.constants.ts b/src/common/constants/auth.constants.ts new file mode 100644 index 0000000..46bc006 --- /dev/null +++ b/src/common/constants/auth.constants.ts @@ -0,0 +1 @@ +export const AUTH_ROLES_KEY = 'roles'; diff --git a/src/common/constants/log.constants.ts b/src/common/constants/log.constants.ts new file mode 100644 index 0000000..3e8afe9 --- /dev/null +++ b/src/common/constants/log.constants.ts @@ -0,0 +1 @@ +export const TIMEOUT_KEY = 'timeout'; diff --git a/src/common/decorators/timeout.decorator.ts b/src/common/decorators/timeout.decorator.ts new file mode 100644 index 0000000..bf049c5 --- /dev/null +++ b/src/common/decorators/timeout.decorator.ts @@ -0,0 +1,9 @@ +import { SetMetadata } from '@nestjs/common'; + +import { TIMEOUT_KEY } from '@common/constants/log.constants'; + +/** + * Set custom timeout for a specific operation + */ + +export const Timeout = (ms: number) => SetMetadata(TIMEOUT_KEY, ms); diff --git a/src/common/interceptors/logging.interceptor.ts b/src/common/interceptors/logging.interceptor.ts new file mode 100644 index 0000000..c5eb057 --- /dev/null +++ b/src/common/interceptors/logging.interceptor.ts @@ -0,0 +1,88 @@ +import { + CallHandler, + ExecutionContext, + Injectable, + Logger, + NestInterceptor, + RequestTimeoutException, +} from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { GqlExecutionContext } from '@nestjs/graphql'; +import { Observable, throwError } from 'rxjs'; +import { catchError, tap, timeout } from 'rxjs/operators'; + +import { TIMEOUT_KEY } from '@common/constants/log.constants'; + +@Injectable() +export class LoggingInterceptor implements NestInterceptor { + private readonly logger = new Logger(); + private readonly defaultTimeoutMillis = 30000; + + constructor(private readonly reflector?: Reflector) {} + + intercept(context: ExecutionContext, next: CallHandler): Observable { + const startTime = Date.now(); + const timeoutMs = this.getTimeout(context); + const { operationDetails, operationName } = this.getOperationDetails(context); + + this.logger.log(`${operationName} starting`); + + // TODO: add sanitization/mask for request, response and error data + this.logger.log(operationDetails); + + return next.handle().pipe( + timeout(timeoutMs), + tap({ + error: (error) => { + const duration = Date.now() - startTime; + + this.logger.error(`${operationName} failed after ${duration}ms: ${error}`); + }, + next: (response) => { + const duration = Date.now() - startTime; + + this.logger.log(`${operationName} completed in ${duration}ms`); + this.logger.debug(response); + }, + }), + // TODO: add better error handling to remove sensitive info thay may exist in 500+ errors + catchError((error) => { + if (error.name === 'TimeoutError') { + this.logger.error(`Timeout: ${operationName} exceeded ${timeoutMs}ms`); + + throw new RequestTimeoutException(`Operation timed out after ${timeoutMs}ms`); + } + + return throwError(() => error); + }), + ); + } + + private getTimeout(context: ExecutionContext): number { + if (!this.reflector) { + return this.defaultTimeoutMillis; + } + + return ( + this.reflector.get(TIMEOUT_KEY, context.getHandler()) ?? + this.reflector.get(TIMEOUT_KEY, context.getClass()) ?? + this.defaultTimeoutMillis + ); + } + + private getOperationDetails(context: ExecutionContext) { + const contextType = context.getType() as string; + + if (contextType !== 'graphql') { + return {}; + } + + const gqlContext = GqlExecutionContext.create(context); + const info = gqlContext.getInfo(); + + return { + operationDetails: gqlContext.getArgs(), + operationName: info.fieldName, + }; + } +} diff --git a/src/database/migrations/1736268149676-create-user.ts b/src/database/migrations/1736268149676-create-user.ts new file mode 100644 index 0000000..5985e74 --- /dev/null +++ b/src/database/migrations/1736268149676-create-user.ts @@ -0,0 +1,42 @@ +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; + +export class CreateUser1736268149676 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + columns: [ + { + default: 'now()', + name: 'created_at', + type: 'timestamp with time zone', + }, + { + default: 'uuid_generate_v4()', + isPrimary: true, + name: 'id', + type: 'uuid', + }, + { + name: 'name', + type: 'varchar', + }, + { + name: 'roles', + type: 'varchar', + }, + { + default: 'now()', + name: 'updated_at', + type: 'timestamp with time zone', + }, + ], + name: 'user', + }), + true, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + return queryRunner.dropTable('user'); + } +} diff --git a/src/spot/spot.module.ts b/src/spot/spot.module.ts index f1791a1..3ffd883 100644 --- a/src/spot/spot.module.ts +++ b/src/spot/spot.module.ts @@ -1,10 +1,12 @@ import { Module } from '@nestjs/common'; +import { AuthModule } from '@auth/auth.module'; import { SpotRepository } from '@spot/spot.repository'; import { SpotResolver } from '@spot/spot.resolver'; import { SpotService } from '@spot/spot.service'; @Module({ + imports: [AuthModule], providers: [SpotRepository, SpotResolver, SpotService], }) export class SpotModule {} diff --git a/src/spot/spot.resolver.ts b/src/spot/spot.resolver.ts index 250ec93..b1d30dd 100644 --- a/src/spot/spot.resolver.ts +++ b/src/spot/spot.resolver.ts @@ -1,5 +1,9 @@ +import { UseGuards } from '@nestjs/common'; import { Resolver, Query, Mutation, Args } from '@nestjs/graphql'; +import { Roles } from '@app/auth/decorators/roles.decorator'; +import { Role } from '@app/auth/enums/role.enum'; +import { GqlAuthGuard } from '@app/auth/guards/gql-auth.guard'; import { CreateSpotInput } from '@spot/dto/create-spot.input'; import { UpdateSpotInput } from '@spot/dto/update-spot.input'; import { Spot } from '@spot/entities/spot.entity'; @@ -10,26 +14,36 @@ export class SpotResolver { constructor(private readonly spotService: SpotService) {} @Mutation(() => Spot) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN) createSpot(@Args('input') createSpotInput: CreateSpotInput) { return this.spotService.create(createSpotInput); } @Query(() => [Spot], { name: 'spots' }) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN, Role.TECHNICIAN) spots() { return this.spotService.findAll(); } @Query(() => Spot, { name: 'spot' }) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN, Role.TECHNICIAN) spot(@Args('id') id: string) { return this.spotService.findById(id); } @Mutation(() => Spot) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN) updateSpot(@Args('id') id: string, @Args('input') updateSpotInput: UpdateSpotInput) { return this.spotService.update(id, updateSpotInput); } @Mutation(() => Spot) + @UseGuards(GqlAuthGuard) + @Roles(Role.ADMIN) removeSpot(@Args('id') id: string) { return this.spotService.remove(id); } diff --git a/src/user/user.module.ts b/src/user/user.module.ts new file mode 100644 index 0000000..37edf44 --- /dev/null +++ b/src/user/user.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { AuthModule } from '@auth/auth.module'; +import { UserResolver } from '@user/user.resolver'; + +@Module({ + imports: [AuthModule], + providers: [UserResolver], +}) +export class UserModule {} diff --git a/src/user/user.resolver.ts b/src/user/user.resolver.ts new file mode 100644 index 0000000..399c9c6 --- /dev/null +++ b/src/user/user.resolver.ts @@ -0,0 +1,19 @@ +import { UseGuards } from '@nestjs/common'; +import { Query, Resolver } from '@nestjs/graphql'; + +import { Roles } from '@app/auth/decorators/roles.decorator'; +import { Role } from '@app/auth/enums/role.enum'; +import { GqlAuthGuard } from '@app/auth/guards/gql-auth.guard'; +import { AuthState as AuthStateType } from '@auth/auth.types'; +import { AuthState } from '@auth/decorators/auth-state.decorator'; +import { User } from '@auth/entities/auth.entity'; + +@Resolver(() => User) +export class UserResolver { + @Query(() => User, { description: 'Get current authenticated user' }) + @Roles(Role.ADMIN, Role.TECHNICIAN) + @UseGuards(GqlAuthGuard) + me(@AuthState() authState: AuthStateType): User { + return authState.user; + } +} diff --git a/test/auth/resolver/login.e2e-spec.ts b/test/auth/resolver/login.e2e-spec.ts new file mode 100644 index 0000000..d36142e --- /dev/null +++ b/test/auth/resolver/login.e2e-spec.ts @@ -0,0 +1,174 @@ +import { INestApplication } from '@nestjs/common'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; +import request from 'supertest'; + +import { Role } from '@auth/enums/role.enum'; +import { createSignInErrorStub, createSignInSuccessStub } from '@test/stubs/supabase'; +import { clearDatabase } from '@test/utils/database-util'; +import { initializeApp } from '@test/utils/nest-testing-module'; + +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + +describe('login (e2e)', () => { + let app: INestApplication; + + beforeAll(async () => { + ({ app } = await initializeApp()); + }); + + beforeEach(async () => { + await clearDatabase(app); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('should successfully login with valid credentials', async () => { + const email = 'test@example.com'; + const password = 'password123'; + + mockSupabaseClient.auth.signInWithPassword.mockResolvedValue( + createSignInSuccessStub({ + user: { + email, + id: 'user-123', + user_metadata: { + name: 'Test User', + role: Role.TECHNICIAN, + }, + }, + }), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: `mutation { + login( + input: { + email: "${email}" + password: "${password}" + } + ) { + session { + accessToken + expiresIn + refreshToken + } + user { + email + id + name + role + } + } + } + `, + }) + .expect(200); + + expect(body.data.login).toEqual({ + session: { + accessToken: 'mock-access-token', + expiresIn: 3600, + refreshToken: 'mock-refresh-token', + }, + user: { + email, + id: 'user-123', + name: 'Test User', + role: Role.TECHNICIAN, + }, + }); + + expect(mockSupabaseClient.auth.signInWithPassword).toHaveBeenCalledWith({ + email, + password, + }); + }); + + it('should return error for invalid credentials', async () => { + const email = 'test@example.com'; + const password = 'wrong-password'; + + mockSupabaseClient.auth.signInWithPassword.mockResolvedValue( + createSignInErrorStub('Invalid login credentials'), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: `mutation { + login( + input: { + email: "${email}" + password: "${password}" + } + ) { + user { + email + } + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Invalid credentials'); + expect(body.data).toBeNull(); + }); + + it('should return error when user has no role', async () => { + const email = 'test@example.com'; + const password = 'password123'; + + mockSupabaseClient.auth.signInWithPassword.mockResolvedValue( + createSignInSuccessStub({ + user: { + email, + id: 'user-123', + user_metadata: { + name: 'Test User', + }, + }, + }), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: `mutation { + login( + input: { + email: "${email}" + password: "${password}" + } + ) { + user { + email + } + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('User role not defined'); + expect(body.data).toBeNull(); + }); +}); diff --git a/test/auth/resolver/logout.e2e-spec.ts b/test/auth/resolver/logout.e2e-spec.ts new file mode 100644 index 0000000..bc3e7af --- /dev/null +++ b/test/auth/resolver/logout.e2e-spec.ts @@ -0,0 +1,99 @@ +import { INestApplication } from '@nestjs/common'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; +import request from 'supertest'; + +import { + createSignOutSuccessStub, + createSignOutErrorStub, + createGetUserSuccessStub, +} from '@test/stubs/supabase'; +import { clearDatabase } from '@test/utils/database-util'; +import { initializeApp } from '@test/utils/nest-testing-module'; + +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + +describe('logout (e2e)', () => { + let app: INestApplication; + + beforeAll(async () => { + ({ app } = await initializeApp()); + }); + + beforeEach(async () => { + await clearDatabase(app); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('should successfully logout with valid access token', async () => { + const accessToken = 'valid-access-token'; + + mockSupabaseClient.auth.getUser.mockResolvedValue(createGetUserSuccessStub()); + mockSupabaseClient.auth.admin.signOut.mockResolvedValue(createSignOutSuccessStub()); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `mutation { + logout + }`, + }) + .expect(200); + + expect(body.data.logout).toBe(true); + expect(mockSupabaseClient.auth.admin.signOut).toHaveBeenCalledWith(accessToken); + }); + + it('should require authentication to access logout mutation', async () => { + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: `mutation { + logout + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); + }); + + it('should return error when logout fails on Supabase', async () => { + const accessToken = 'valid-access-token'; + + mockSupabaseClient.auth.admin.signOut.mockResolvedValue( + createSignOutErrorStub('Session not found'), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `mutation { + logout + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Failed to logout'); + expect(body.data).toBeNull(); + expect(mockSupabaseClient.auth.admin.signOut).toHaveBeenCalledWith(accessToken); + }); +}); diff --git a/test/auth/resolver/refresh-token.e2e-spec.ts b/test/auth/resolver/refresh-token.e2e-spec.ts new file mode 100644 index 0000000..908f34a --- /dev/null +++ b/test/auth/resolver/refresh-token.e2e-spec.ts @@ -0,0 +1,207 @@ +import { INestApplication } from '@nestjs/common'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; +import request from 'supertest'; + +import { Role } from '@auth/enums/role.enum'; +import { + createRefreshTokenSuccessStub, + createRefreshTokenErrorStub, + createGetUserSuccessStub, +} from '@test/stubs/supabase'; +import { clearDatabase } from '@test/utils/database-util'; +import { initializeApp } from '@test/utils/nest-testing-module'; + +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + +describe('refreshToken (e2e)', () => { + let app: INestApplication; + + beforeAll(async () => { + ({ app } = await initializeApp()); + }); + + beforeEach(async () => { + await clearDatabase(app); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('should successfully refresh token with valid refresh token', async () => { + const accessToken = 'valid-access-token'; + const refreshToken = 'valid-refresh-token'; + const email = 'test@example.com'; + const user = { + email, + id: 'user-123', + user_metadata: { + name: 'Test User', + role: Role.TECHNICIAN, + }, + }; + + const supabaseRefreshResponse = createRefreshTokenSuccessStub({ user }); + + mockSupabaseClient.auth.getUser.mockResolvedValue(createGetUserSuccessStub(user)); + mockSupabaseClient.auth.refreshSession.mockResolvedValue(supabaseRefreshResponse); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `mutation { + refreshToken( + input: { + refreshToken: "${refreshToken}" + } + ) { + session { + accessToken + expiresIn + refreshToken + } + user { + email + id + name + role + } + } + }`, + }) + .expect(200); + + expect(body.data.refreshToken).toEqual({ + session: { + accessToken: supabaseRefreshResponse.data.session.access_token, + expiresIn: supabaseRefreshResponse.data.session.expires_in, + refreshToken: supabaseRefreshResponse.data.session.refresh_token, + }, + user: { + email, + id: user.id, + name: user.user_metadata.name, + role: user.user_metadata.role, + }, + }); + + expect(mockSupabaseClient.auth.refreshSession).toHaveBeenCalledWith({ + refresh_token: refreshToken, + }); + }); + + it('should return error when refresh token is invalid', async () => { + const accessToken = 'valid-access-token'; + const refreshToken = 'invalid-refresh-token'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email: 'test@example.com', + id: 'user-123', + user_metadata: { + role: Role.TECHNICIAN, + }, + }), + ); + mockSupabaseClient.auth.refreshSession.mockResolvedValue( + createRefreshTokenErrorStub('Invalid refresh token'), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `mutation { + refreshToken( + input: { + refreshToken: "${refreshToken}" + } + ) { + session { + accessToken + } + } + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Invalid refresh token'); + expect(body.data).toBeNull(); + }); + + it('should return error when user has no role after refresh', async () => { + const accessToken = 'valid-access-token'; + const refreshToken = 'valid-refresh-token'; + const user = { + email: 'test@example.com', + id: 'user-123', + user_metadata: { + name: 'Test User', + // No role defined + }, + }; + + mockSupabaseClient.auth.getUser.mockResolvedValue(createGetUserSuccessStub(user)); + mockSupabaseClient.auth.refreshSession.mockResolvedValue( + createRefreshTokenSuccessStub({ user }), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `mutation { + refreshToken( + input: { + refreshToken: "${refreshToken}" + } + ) { + session { + accessToken + } + } + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('User role not defined'); + expect(body.data).toBeNull(); + }); + + it('should require authentication to access refreshToken mutation', async () => { + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: `mutation { + refreshToken( + input: { + refreshToken: "some-token" + } + ) { + session { + accessToken + } + } + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); + }); +}); diff --git a/test/fixtures/spot/index.ts b/test/fixtures/spot/index.ts new file mode 100644 index 0000000..8a00d8c --- /dev/null +++ b/test/fixtures/spot/index.ts @@ -0,0 +1 @@ +export * from './spot.fixture'; diff --git a/test/fixtures/spot-fixture.ts b/test/fixtures/spot/spot.fixture.ts similarity index 100% rename from test/fixtures/spot-fixture.ts rename to test/fixtures/spot/spot.fixture.ts diff --git a/test/spot/resolver/create-spot.e2e-spec.ts b/test/spot/resolver/create-spot.e2e-spec.ts index 144f223..a234abd 100644 --- a/test/spot/resolver/create-spot.e2e-spec.ts +++ b/test/spot/resolver/create-spot.e2e-spec.ts @@ -1,29 +1,69 @@ import { INestApplication } from '@nestjs/common'; import { TestingModule } from '@nestjs/testing'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; import { head } from 'lodash'; import request from 'supertest'; +import { Role } from '@auth/enums/role.enum'; import { SpotService } from '@spot/spot.service'; +import { createGetUserSuccessStub } from '@test/stubs/supabase'; import { clearDatabase } from '@test/utils/database-util'; import { initializeApp } from '@test/utils/nest-testing-module'; +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + describe('createSpot (e2e)', () => { let app: INestApplication; let service: SpotService; let module: TestingModule; - beforeEach(async () => { + beforeAll(async () => { ({ app, module } = await initializeApp()); service = module.get(SpotService); + }); + beforeEach(async () => { await clearDatabase(app); }); - it('should create a `spot`', async () => { + afterAll(async () => { + await app.close(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should create a `spot` with admin role', async () => { + const accessToken = 'valid-access-token'; + const email = 'admin@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'admin-123', + user_metadata: { + name: 'Admin User', + role: Role.ADMIN, + }, + }), + ); + const name = 'foo'; const location = 'waldo'; const { body } = await request(app.getHttpServer()) .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) .expect(200) .send({ query: ` @@ -48,5 +88,64 @@ describe('createSpot (e2e)', () => { createdAt: spot.createdAt.toISOString(), updatedAt: spot.updatedAt.toISOString(), }); + + expect(mockSupabaseClient.auth.getUser).toHaveBeenCalledWith(accessToken); + }); + + it('should require authentication to create spot', async () => { + const name = 'foo'; + const location = 'waldo'; + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + mutation { + createSpot(input: { location: "${location}" name: "${name}" }) { + id + name + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); + }); + + it('should reject creation with non-admin role', async () => { + const accessToken = 'valid-access-token'; + const email = 'technician@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'tech-123', + user_metadata: { + name: 'Tech User', + role: Role.TECHNICIAN, + }, + }), + ); + + const name = 'foo'; + const location = 'waldo'; + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: ` + mutation { + createSpot(input: { location: "${location}" name: "${name}" }) { + id + name + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Access denied'); + expect(body.data).toBeNull(); }); }); diff --git a/test/spot/resolver/spot.e2e-spec.ts b/test/spot/resolver/spot.e2e-spec.ts index ec663aa..bcae4a3 100644 --- a/test/spot/resolver/spot.e2e-spec.ts +++ b/test/spot/resolver/spot.e2e-spec.ts @@ -1,27 +1,67 @@ import { INestApplication } from '@nestjs/common'; import { TestingModule } from '@nestjs/testing'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; import request from 'supertest'; -import { spotFixture } from '@test/fixtures/spot-fixture'; +import { Role } from '@auth/enums/role.enum'; +import { spotFixture } from '@test/fixtures/spot'; +import { createGetUserSuccessStub } from '@test/stubs/supabase'; import { clearDatabase } from '@test/utils/database-util'; import { initializeApp } from '@test/utils/nest-testing-module'; +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + describe('spot (e2e)', () => { let app: INestApplication; let module: TestingModule; - beforeEach(async () => { + beforeAll(async () => { ({ app, module } = await initializeApp()); + }); + beforeEach(async () => { await clearDatabase(app); }); + afterAll(async () => { + await app.close(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + it('should get the `spot` with given `id`', async () => { + const accessToken = 'valid-access-token'; + const email = 'test@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'user-123', + user_metadata: { + name: 'Test User', + role: Role.TECHNICIAN, + }, + }), + ); + const name = 'foo'; const location = 'waldo'; const spot = await spotFixture(module, { location, name }); const { body } = await request(app.getHttpServer()) .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) .expect(200) .send({ query: ` @@ -42,5 +82,29 @@ describe('spot (e2e)', () => { createdAt: spot.createdAt.toISOString(), updatedAt: spot.updatedAt.toISOString(), }); + + expect(mockSupabaseClient.auth.getUser).toHaveBeenCalledWith(accessToken); + }); + + it('should require authentication to access spot query', async () => { + const name = 'foo'; + const location = 'waldo'; + const spot = await spotFixture(module, { location, name }); + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + query { + spot(id: "${spot.id}") { + id + name + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); }); }); diff --git a/test/spot/resolver/spots.e2e-spec.ts b/test/spot/resolver/spots.e2e-spec.ts index fb04ec3..4c04d4b 100644 --- a/test/spot/resolver/spots.e2e-spec.ts +++ b/test/spot/resolver/spots.e2e-spec.ts @@ -1,27 +1,67 @@ import { INestApplication } from '@nestjs/common'; import { TestingModule } from '@nestjs/testing'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; import request from 'supertest'; -import { spotFixture } from '@test/fixtures/spot-fixture'; +import { Role } from '@auth/enums/role.enum'; +import { spotFixture } from '@test/fixtures/spot'; +import { createGetUserSuccessStub } from '@test/stubs/supabase'; import { clearDatabase } from '@test/utils/database-util'; import { initializeApp } from '@test/utils/nest-testing-module'; +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + describe('spots (e2e)', () => { let app: INestApplication; let module: TestingModule; - beforeEach(async () => { + beforeAll(async () => { ({ app, module } = await initializeApp()); + }); + beforeEach(async () => { await clearDatabase(app); }); + afterAll(async () => { + await app.close(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + it('should get a list of `spot`', async () => { + const accessToken = 'valid-access-token'; + const email = 'test@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'user-123', + user_metadata: { + name: 'Test User', + role: Role.TECHNICIAN, + }, + }), + ); + const location = 'waldo'; const spotFoobar = await spotFixture(module, { location, name: 'foobar' }); const spotWaldo = await spotFixture(module, { location, name: 'waldo' }); const { body } = await request(app.getHttpServer()) .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) .expect(200) .send({ query: ` @@ -49,5 +89,26 @@ describe('spots (e2e)', () => { updatedAt: spotWaldo.updatedAt.toISOString(), }, ]); + + expect(mockSupabaseClient.auth.getUser).toHaveBeenCalledWith(accessToken); + }); + + it('should require authentication to access spots query', async () => { + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + query { + spots { + id + name + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); }); }); diff --git a/test/spot/resolver/update-spot.e2e-spec.ts b/test/spot/resolver/update-spot.e2e-spec.ts index 4723b57..a647202 100644 --- a/test/spot/resolver/update-spot.e2e-spec.ts +++ b/test/spot/resolver/update-spot.e2e-spec.ts @@ -1,30 +1,70 @@ import { INestApplication } from '@nestjs/common'; import { TestingModule } from '@nestjs/testing'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; import request from 'supertest'; +import { Role } from '@auth/enums/role.enum'; import { SpotService } from '@spot/spot.service'; -import { spotFixture } from '@test/fixtures/spot-fixture'; +import { spotFixture } from '@test/fixtures/spot'; +import { createGetUserSuccessStub } from '@test/stubs/supabase'; import { clearDatabase } from '@test/utils/database-util'; import { initializeApp } from '@test/utils/nest-testing-module'; +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + describe('updateSpot (e2e)', () => { let app: INestApplication; let service: SpotService; let module: TestingModule; - beforeEach(async () => { + beforeAll(async () => { ({ app, module } = await initializeApp()); service = module.get(SpotService); + }); + beforeEach(async () => { await clearDatabase(app); }); - it('should update a `spot`', async () => { + afterAll(async () => { + await app.close(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should update a `spot` with admin role', async () => { + const accessToken = 'valid-access-token'; + const email = 'admin@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'admin-123', + user_metadata: { + name: 'Admin User', + role: Role.ADMIN, + }, + }), + ); + const name = 'waldo'; const location = 'fred'; const spot = await spotFixture(module, { location, name }); const { body } = await request(app.getHttpServer()) .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) .expect(200) .send({ query: ` @@ -52,5 +92,72 @@ describe('updateSpot (e2e)', () => { name, updatedAt: updatedSpot.updatedAt.toISOString(), }); + + expect(mockSupabaseClient.auth.getUser).toHaveBeenCalledWith(accessToken); + }); + + it('should require authentication to update spot', async () => { + const name = 'waldo'; + const location = 'fred'; + const spot = await spotFixture(module, { location, name }); + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: ` + mutation { + updateSpot( + id: "${spot.id}" + input: { location: "${location}" name: "${name}" } + ) { + id + name + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); + }); + + it('should reject update with non-admin role', async () => { + const accessToken = 'valid-access-token'; + const email = 'technician@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'tech-123', + user_metadata: { + name: 'Tech User', + role: Role.TECHNICIAN, + }, + }), + ); + + const name = 'waldo'; + const location = 'fred'; + const spot = await spotFixture(module, { location, name }); + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: ` + mutation { + updateSpot( + id: "${spot.id}" + input: { location: "${location}" name: "${name}" } + ) { + id + name + } + } + `, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Access denied'); + expect(body.data).toBeNull(); }); }); diff --git a/test/stubs/supabase/get-user.stub.ts b/test/stubs/supabase/get-user.stub.ts new file mode 100644 index 0000000..6343fff --- /dev/null +++ b/test/stubs/supabase/get-user.stub.ts @@ -0,0 +1,13 @@ +import { AuthError } from '@supabase/supabase-js'; + +import { createUserStub, PartialSupabaseUser } from './user.stub'; + +export const createGetUserSuccessStub = (data: PartialSupabaseUser = {}) => ({ + data: { user: createUserStub(data) }, + error: null, +}); + +export const createGetUserErrorStub = (message = 'Invalid token') => ({ + data: { user: null }, + error: new AuthError(message, 401, 'unauthorized'), +}); diff --git a/test/stubs/supabase/index.ts b/test/stubs/supabase/index.ts new file mode 100644 index 0000000..63e0f1b --- /dev/null +++ b/test/stubs/supabase/index.ts @@ -0,0 +1,6 @@ +export * from './get-user.stub'; +export * from './refresh-token.stub'; +export * from './session.stub'; +export * from './sign-in.stub'; +export * from './sign-out.stub'; +export * from './user.stub'; diff --git a/test/stubs/supabase/refresh-token.stub.ts b/test/stubs/supabase/refresh-token.stub.ts new file mode 100644 index 0000000..c5240c9 --- /dev/null +++ b/test/stubs/supabase/refresh-token.stub.ts @@ -0,0 +1,22 @@ +import { AuthError } from '@supabase/supabase-js'; + +import { createSessionStub, SessionStubData } from './session.stub'; +import { createUserStub, PartialSupabaseUser } from './user.stub'; + +export const createRefreshTokenSuccessStub = (data: RefreshStubData = {}) => ({ + data: { + session: createSessionStub(data.session), + user: createUserStub(data.user), + }, + error: null, +}); + +export const createRefreshTokenErrorStub = (message = 'Invalid refresh token') => ({ + data: { session: null, user: null }, + error: new AuthError(message, 401, 'unauthorized'), +}); + +export type RefreshStubData = { + session?: SessionStubData; + user?: PartialSupabaseUser; +}; diff --git a/test/stubs/supabase/session.stub.ts b/test/stubs/supabase/session.stub.ts new file mode 100644 index 0000000..9b12a05 --- /dev/null +++ b/test/stubs/supabase/session.stub.ts @@ -0,0 +1,19 @@ +import { Session } from '@supabase/supabase-js'; + +import { createUserStub, PartialSupabaseUser } from './user.stub'; + +export const createSessionStub = (data: SessionStubData = {}): Session => ({ + access_token: data.access_token ?? 'mock-access-token', + expires_in: data.expires_in ?? 3600, + refresh_token: data.refresh_token ?? 'mock-refresh-token', + token_type: data.token_type ?? 'bearer', + user: createUserStub(data.user), +}); + +export type SessionStubData = { + access_token?: string; + expires_in?: number; + refresh_token?: string; + token_type?: string; + user?: PartialSupabaseUser; +}; diff --git a/test/stubs/supabase/sign-in.stub.ts b/test/stubs/supabase/sign-in.stub.ts new file mode 100644 index 0000000..842dda5 --- /dev/null +++ b/test/stubs/supabase/sign-in.stub.ts @@ -0,0 +1,23 @@ +import { AuthError, AuthTokenResponsePassword } from '@supabase/supabase-js'; + +import { createSessionStub, SessionStubData } from './session.stub'; +import { createUserStub, PartialSupabaseUser } from './user.stub'; + +export const createSignInSuccessStub = (data: SignInStubData = {}) => ({ + data: { + session: createSessionStub(data.session), + user: createUserStub(data.user), + }, + error: null, +}); + +export const createSignInErrorStub = (message = 'Invalid credentials') => + ({ + data: { session: null, user: null }, + error: new AuthError(message, 401, 'unauthorized'), + }) as AuthTokenResponsePassword; + +export type SignInStubData = { + session?: SessionStubData; + user?: PartialSupabaseUser; +}; diff --git a/test/stubs/supabase/sign-out.stub.ts b/test/stubs/supabase/sign-out.stub.ts new file mode 100644 index 0000000..166e2b4 --- /dev/null +++ b/test/stubs/supabase/sign-out.stub.ts @@ -0,0 +1,11 @@ +import { AuthError } from '@supabase/supabase-js'; + +export const createSignOutSuccessStub = () => ({ + data: null, + error: null, +}); + +export const createSignOutErrorStub = (message = 'Failed to logout') => ({ + data: null, + error: new AuthError(message, 400, 'bad_request'), +}); diff --git a/test/stubs/supabase/user.stub.ts b/test/stubs/supabase/user.stub.ts new file mode 100644 index 0000000..093454f --- /dev/null +++ b/test/stubs/supabase/user.stub.ts @@ -0,0 +1,30 @@ +import { User as SupabaseUser } from '@supabase/supabase-js'; + +import { Role } from '@auth/enums/role.enum'; + +export const createUserStub = (data: PartialSupabaseUser = {}): SupabaseUser => ({ + app_metadata: {}, + aud: 'authenticated', + confirmed_at: '2024-01-01T00:00:00.000Z', + created_at: '2024-01-01T00:00:00.000Z', + email: 'test@example.com', + email_confirmed_at: '2024-01-01T00:00:00.000Z', + id: 'user-123', + last_sign_in_at: '2024-01-01T00:00:00.000Z', + phone: '', + role: 'authenticated', + updated_at: '2024-01-01T00:00:00.000Z', + user_metadata: { + name: 'Test User', + role: Role.TECHNICIAN, + ...data.user_metadata, + }, + ...data, +}); + +export type PartialSupabaseUser = Partial & { + user_metadata?: { + name?: string; + role?: Role; + }; +}; diff --git a/test/user/resolver/me.e2e-spec.ts b/test/user/resolver/me.e2e-spec.ts new file mode 100644 index 0000000..3c3bb5c --- /dev/null +++ b/test/user/resolver/me.e2e-spec.ts @@ -0,0 +1,166 @@ +import { INestApplication } from '@nestjs/common'; +import { SupabaseClient } from '@supabase/supabase-js'; +import { mockDeep } from 'jest-mock-extended'; +import request from 'supertest'; + +import { Role } from '@auth/enums/role.enum'; +import { createGetUserSuccessStub } from '@test/stubs/supabase'; +import { clearDatabase } from '@test/utils/database-util'; +import { initializeApp } from '@test/utils/nest-testing-module'; + +/** + * Mocks. + */ + +const mockSupabaseClient = mockDeep(); + +jest.mock('@supabase/supabase-js', () => ({ + ...jest.requireActual('@supabase/supabase-js'), + createClient: jest.fn(() => mockSupabaseClient), +})); + +describe('me (e2e)', () => { + let app: INestApplication; + + beforeAll(async () => { + ({ app } = await initializeApp()); + }); + + beforeEach(async () => { + await clearDatabase(app); + }); + + afterAll(async () => { + await app.close(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should successfully return authenticated user data', async () => { + const accessToken = 'valid-access-token'; + const email = 'test@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'user-123', + user_metadata: { + name: 'Test User', + role: Role.ADMIN, + }, + }), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `query { + me { + email + id + name + role + } + }`, + }) + .expect(200); + + expect(body.data.me).toEqual({ + email, + id: 'user-123', + name: 'Test User', + role: Role.ADMIN, + }); + + expect(mockSupabaseClient.auth.getUser).toHaveBeenCalledWith(accessToken); + }); + + it('should require authentication to access me query', async () => { + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .send({ + query: `query { + me { + email + id + } + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('Authorization header missing'); + expect(body.data).toBeNull(); + }); + + it('should handle user with minimal data (no name)', async () => { + const accessToken = 'valid-access-token'; + const email = 'minimal@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'user-456', + user_metadata: { + role: Role.TECHNICIAN, + }, + }), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `query { + me { + email + id + name + role + } + }`, + }) + .expect(200); + + expect(body.data.me).toEqual({ + email, + id: 'user-456', + name: null, + role: Role.TECHNICIAN, + }); + }); + + it('should return error when user has no role', async () => { + const accessToken = 'valid-access-token'; + const email = 'norole@example.com'; + + mockSupabaseClient.auth.getUser.mockResolvedValue( + createGetUserSuccessStub({ + email, + id: 'user-789', + user_metadata: { + name: 'No Role User', + }, + }), + ); + + const { body } = await request(app.getHttpServer()) + .post('/graphql') + .set('Authorization', `Bearer ${accessToken}`) + .send({ + query: `query { + me { + email + id + role + } + }`, + }) + .expect(200); + + expect(body.errors[0].message).toBe('User role not defined'); + expect(body.data).toBeNull(); + }); +}); diff --git a/test/utils/nest-testing-module.ts b/test/utils/nest-testing-module.ts index 3a2d648..e6f4a20 100644 --- a/test/utils/nest-testing-module.ts +++ b/test/utils/nest-testing-module.ts @@ -6,7 +6,7 @@ import { AppModule } from 'src/app.module'; export const initializeApp = async (): Promise => { const module = await Test.createTestingModule({ imports: [AppModule] }).compile(); - const app = module.createNestApplication(); + const app = module.createNestApplication({ logger: false }); const dataSource = app.get(DataSource); await app.init(); diff --git a/tsconfig.json b/tsconfig.json index e3881cb..683cd79 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,11 +17,14 @@ "incremental": true, "paths": { "@app/*": ["src/*"], + "@auth/*": ["src/auth/*"], + "@common/*": ["src/common/*"], "@config/*": ["src/config/*"], "@database/*": ["src/database/*"], "@graphql/*": ["src/graphql/*"], "@spot/*": ["src/spot/*"], - "@test/*": ["test/*"] + "@test/*": ["test/*"], + "@user/*": ["src/user/*"] }, "skipLibCheck": true, "strictNullChecks": false, diff --git a/yarn.lock b/yarn.lock index 4b9bf89..4018275 100644 --- a/yarn.lock +++ b/yarn.lock @@ -213,12 +213,26 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" +"@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== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": +"@babel/compat-data@^7.27.2": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" + integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== + +"@babel/core@^7.23.9": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== @@ -239,7 +253,28 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.7", "@babel/generator@^7.7.2": +"@babel/core@^7.27.4": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" + integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.27.3" + "@babel/helpers" "^7.27.6" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.0" + "@babel/types" "^7.28.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== @@ -249,6 +284,17 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" +"@babel/generator@^7.27.5", "@babel/generator@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" + integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== + dependencies: + "@babel/parser" "^7.28.0" + "@babel/types" "^7.28.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + "@babel/helper-compilation-targets@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" @@ -260,6 +306,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-environment-visitor@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" @@ -275,6 +332,11 @@ "@babel/template" "^7.24.7" "@babel/types" "^7.24.7" +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + "@babel/helper-hoist-variables@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" @@ -290,6 +352,14 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + "@babel/helper-module-transforms@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" @@ -301,11 +371,25 @@ "@babel/helper-split-export-declaration" "^7.24.7" "@babel/helper-validator-identifier" "^7.24.7" -"@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.24.7", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-module-transforms@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02" + integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.3" + +"@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.8.0": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz#98c84fe6fe3d0d3ae7bfc3a5e166a46844feb2a0" integrity sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg== +"@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + "@babel/helper-simple-access@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" @@ -326,16 +410,31 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== +"@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.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@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-option@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + "@babel/helpers@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" @@ -344,6 +443,14 @@ "@babel/template" "^7.24.7" "@babel/types" "^7.24.7" +"@babel/helpers@^7.27.6": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.2.tgz#80f0918fecbfebea9af856c419763230040ee850" + integrity sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.2" + "@babel/highlight@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" @@ -354,11 +461,18 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.7": +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== +"@babel/parser@^7.27.2", "@babel/parser@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + "@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" @@ -373,14 +487,28 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@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-import-meta@^7.8.3": +"@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.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" + integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -394,14 +522,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" - integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@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== @@ -415,7 +543,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@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== @@ -443,21 +571,28 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c" - integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA== +"@babel/plugin-syntax-typescript@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.27.1" -"@babel/template@^7.24.7", "@babel/template@^7.3.3": +"@babel/template@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== @@ -466,6 +601,15 @@ "@babel/parser" "^7.24.7" "@babel/types" "^7.24.7" +"@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/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + "@babel/traverse@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" @@ -482,7 +626,20 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.3.3": +"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" + integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.0" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== @@ -491,6 +648,14 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.0", "@babel/types@^7.28.2": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b" + integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@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" @@ -508,6 +673,28 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@emnapi/core@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" + integrity sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q== + dependencies: + "@emnapi/wasi-threads" "1.0.4" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.5.tgz#c67710d0661070f38418b6474584f159de38aba9" + integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz#703fc094d969e273b1b71c292523b2f792862bf4" + integrity sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g== + dependencies: + tslib "^2.4.0" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -646,61 +833,73 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" - integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== +"@jest/console@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-30.0.5.tgz#d7d027c2db5c64c20a973b7f3e57b49956d6c335" + integrity sha512-xY6b0XiL0Nav3ReresUarwl2oIz1gTnxGbGpho9/rbUWsLH0f1OD/VT84xs8c7VmH7MChnLb0pag6PhZhAdDiA== dependencies: - "@jest/types" "^29.6.3" + "@jest/types" "30.0.5" "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" + chalk "^4.1.2" + jest-message-util "30.0.5" + jest-util "30.0.5" slash "^3.0.0" -"@jest/core@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" - integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== - dependencies: - "@jest/console" "^29.7.0" - "@jest/reporters" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" +"@jest/core@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-30.0.5.tgz#b5778922d2928f676636e3ec199829554e61e452" + integrity sha512-fKD0OulvRsXF1hmaFgHhVJzczWzA1RXMMo9LTPuFXo9q/alDbME3JIyWYqovWsUBWSoBcsHaGPSLF9rz4l9Qeg== + dependencies: + "@jest/console" "30.0.5" + "@jest/pattern" "30.0.1" + "@jest/reporters" "30.0.5" + "@jest/test-result" "30.0.5" + "@jest/transform" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^29.7.0" - jest-config "^29.7.0" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-resolve-dependencies "^29.7.0" - jest-runner "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - jest-watcher "^29.7.0" - micromatch "^4.0.4" - pretty-format "^29.7.0" + 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.0.5" + jest-config "30.0.5" + jest-haste-map "30.0.5" + jest-message-util "30.0.5" + jest-regex-util "30.0.1" + jest-resolve "30.0.5" + jest-resolve-dependencies "30.0.5" + jest-runner "30.0.5" + jest-runtime "30.0.5" + jest-snapshot "30.0.5" + jest-util "30.0.5" + jest-validate "30.0.5" + jest-watcher "30.0.5" + micromatch "^4.0.8" + pretty-format "30.0.5" slash "^3.0.0" - strip-ansi "^6.0.0" -"@jest/environment@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" - integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== +"@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.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-30.0.5.tgz#eaaae0403c7d3f8414053c2224acc3011e1c3a1b" + integrity sha512-aRX7WoaWx1oaOkDQvCWImVQ8XNtdv5sEWgk4gxR6NXb7WBUnL5sRak4WRzIQRZ1VTWPvV4VI4mgGjNL9TeKMYA== dependencies: - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" + "@jest/fake-timers" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - jest-mock "^29.7.0" + jest-mock "30.0.5" + +"@jest/expect-utils@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-30.0.5.tgz#9d42e4b8bc80367db30abc6c42b2cb14073f66fc" + integrity sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew== + dependencies: + "@jest/get-type" "30.0.1" "@jest/expect-utils@^29.7.0": version "29.7.0" @@ -709,66 +908,85 @@ dependencies: jest-get-type "^29.6.3" -"@jest/expect@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" - integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== +"@jest/expect@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-30.0.5.tgz#2bbd101df4869f5d171c3cfee881f810f1525005" + integrity sha512-6udac8KKrtTtC+AXZ2iUN/R7dp7Ydry+Fo6FPFnDG54wjVMnb6vW/XNlf7Xj8UDjAE3aAVAsR4KFyKk3TCXmTA== dependencies: - expect "^29.7.0" - jest-snapshot "^29.7.0" + expect "30.0.5" + jest-snapshot "30.0.5" -"@jest/fake-timers@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" - integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== +"@jest/fake-timers@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-30.0.5.tgz#c028a9465a44b7744cb2368196bed89ce13c7054" + integrity sha512-ZO5DHfNV+kgEAeP3gK3XlpJLL4U3Sz6ebl/n68Uwt64qFFs5bv4bfEEjyRGK5uM0C90ewooNgFuKMdkbEoMEXw== dependencies: - "@jest/types" "^29.6.3" - "@sinonjs/fake-timers" "^10.0.2" + "@jest/types" "30.0.5" + "@sinonjs/fake-timers" "^13.0.0" "@types/node" "*" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-util "^29.7.0" - -"@jest/globals@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" - integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + jest-message-util "30.0.5" + jest-mock "30.0.5" + jest-util "30.0.5" + +"@jest/get-type@30.0.1": + version "30.0.1" + resolved "https://registry.yarnpkg.com/@jest/get-type/-/get-type-30.0.1.tgz#0d32f1bbfba511948ad247ab01b9007724fc9f52" + integrity sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw== + +"@jest/globals@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-30.0.5.tgz#ca70e0ac08ab40417cf8cd92bcb76116c2ccca63" + integrity sha512-7oEJT19WW4oe6HR7oLRvHxwlJk2gev0U9px3ufs8sX9PoD1Eza68KF0/tlN7X0dq/WVsBScXQGgCldA1V9Y/jA== + dependencies: + "@jest/environment" "30.0.5" + "@jest/expect" "30.0.5" + "@jest/types" "30.0.5" + jest-mock "30.0.5" + +"@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: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/types" "^29.6.3" - jest-mock "^29.7.0" + "@types/node" "*" + jest-regex-util "30.0.1" -"@jest/reporters@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" - integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== +"@jest/reporters@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-30.0.5.tgz#b83585e6448d390a8d92a641c567f1655976d5c6" + integrity sha512-mafft7VBX4jzED1FwGC1o/9QUM2xebzavImZMeqnsklgcyxBto8mV4HzNSzUrryJ+8R9MFOM3HgYuDradWR+4g== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" + "@jest/console" "30.0.5" + "@jest/test-result" "30.0.5" + "@jest/transform" "30.0.5" + "@jest/types" "30.0.5" + "@jridgewell/trace-mapping" "^0.3.25" "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" + 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 "^4.0.0" + istanbul-lib-source-maps "^5.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - jest-worker "^29.7.0" + jest-message-util "30.0.5" + jest-util "30.0.5" + jest-worker "30.0.5" slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.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/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -776,55 +994,78 @@ dependencies: "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" - integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== +"@jest/snapshot-utils@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/snapshot-utils/-/snapshot-utils-30.0.5.tgz#e23a0e786f174e8cff7f150c1cfbdc9cb7cc81a4" + integrity sha512-XcCQ5qWHLvi29UUrowgDFvV4t7ETxX91CbDczMnoqXPOIcZOxyNdSjm6kV5XMc8+HkxfRegU/MUmnTbJRzGrUQ== dependencies: - "@jridgewell/trace-mapping" "^0.3.18" - callsites "^3.0.0" - graceful-fs "^4.2.9" + "@jest/types" "30.0.5" + chalk "^4.1.2" + graceful-fs "^4.2.11" + natural-compare "^1.4.0" -"@jest/test-result@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" - integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== +"@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: - "@jest/console" "^29.7.0" - "@jest/types" "^29.6.3" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" + "@jridgewell/trace-mapping" "^0.3.25" + callsites "^3.1.0" + graceful-fs "^4.2.11" -"@jest/test-sequencer@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" - integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== +"@jest/test-result@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-30.0.5.tgz#064c5210c24d5ea192fb02ceddad3be1cfa557c8" + integrity sha512-wPyztnK0gbDMQAJZ43tdMro+qblDHH1Ru/ylzUo21TBKqt88ZqnKKK2m30LKmLLoKtR2lxdpCC/P3g1vfKcawQ== dependencies: - "@jest/test-result" "^29.7.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" + "@jest/console" "30.0.5" + "@jest/types" "30.0.5" + "@types/istanbul-lib-coverage" "^2.0.6" + collect-v8-coverage "^1.0.2" + +"@jest/test-sequencer@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-30.0.5.tgz#c6dba8fc3c386dd793c087626e8508ff1ead19f4" + integrity sha512-Aea/G1egWoIIozmDD7PBXUOxkekXl7ueGzrsGGi1SbeKgQqCYCIf+wfbflEbf2LiPxL8j2JZGLyrzZagjvW4YQ== + dependencies: + "@jest/test-result" "30.0.5" + graceful-fs "^4.2.11" + jest-haste-map "30.0.5" slash "^3.0.0" -"@jest/transform@^29.7.0": - version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" - integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== +"@jest/transform@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-30.0.5.tgz#f8ca2e9f7466b77b406807d3bef1f6790dd384e4" + integrity sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg== dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.6.3" - "@jridgewell/trace-mapping" "^0.3.18" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" + "@babel/core" "^7.27.4" + "@jest/types" "30.0.5" + "@jridgewell/trace-mapping" "^0.3.25" + babel-plugin-istanbul "^7.0.0" + chalk "^4.1.2" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - micromatch "^4.0.4" - pirates "^4.0.4" + graceful-fs "^4.2.11" + jest-haste-map "30.0.5" + jest-regex-util "30.0.1" + jest-util "30.0.5" + micromatch "^4.0.8" + pirates "^4.0.7" slash "^3.0.0" - write-file-atomic "^4.0.2" + write-file-atomic "^5.0.1" + +"@jest/types@30.0.5": + version "30.0.5" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-30.0.5.tgz#29a33a4c036e3904f1cfd94f6fe77f89d2e1cc05" + integrity sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ== + 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" "@jest/types@^29.6.3": version "29.6.3" @@ -843,6 +1084,14 @@ resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== +"@jridgewell/gen-mapping@^0.3.12": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" + integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -875,6 +1124,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" + integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== + "@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" @@ -883,7 +1137,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -891,6 +1145,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" + integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@ljharb/through@^2.3.12": version "2.3.13" resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.13.tgz#b7e4766e0b65aa82e529be945ab078de79874edc" @@ -903,6 +1165,15 @@ resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA== +"@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" + "@nestjs/apollo@^12.2.0": version "12.2.0" resolved "https://registry.yarnpkg.com/@nestjs/apollo/-/apollo-12.2.0.tgz#938da4babbb81ac342b668585e17ee5e4b7b65a4" @@ -1069,6 +1340,11 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@pkgr/core@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b" + integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -1127,19 +1403,24 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@sinonjs/commons@^3.0.0": +"@sinclair/typebox@^0.34.0": + version "0.34.38" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.34.38.tgz#2365df7c23406a4d79413a766567bfbca708b49d" + integrity sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA== + +"@sinonjs/commons@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^10.0.2": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" - integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== +"@sinonjs/fake-timers@^13.0.0": + version "13.0.5" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5" + integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw== dependencies: - "@sinonjs/commons" "^3.0.0" + "@sinonjs/commons" "^3.0.1" "@sqltools/formatter@^1.2.5": version "1.2.5" @@ -1204,6 +1485,71 @@ "@stylistic/eslint-plugin-ts" "2.6.2" "@types/eslint" "^9.6.0" +"@supabase/auth-js@2.71.1": + version "2.71.1" + resolved "https://registry.yarnpkg.com/@supabase/auth-js/-/auth-js-2.71.1.tgz#349802c3b8275d62437e755ba73bd0cd8c26cd93" + integrity sha512-mMIQHBRc+SKpZFRB2qtupuzulaUhFYupNyxqDj5Jp/LyPvcWvjaJzZzObv6URtL/O6lPxkanASnotGtNpS3H2Q== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/functions-js@2.4.5": + version "2.4.5" + resolved "https://registry.yarnpkg.com/@supabase/functions-js/-/functions-js-2.4.5.tgz#0a87d1a296bb32a1474c9322c932d9bbd4993d74" + integrity sha512-v5GSqb9zbosquTo6gBwIiq7W9eQ7rE5QazsK/ezNiQXdCbY+bH8D9qEaBIkhVvX4ZRW5rP03gEfw5yw9tiq4EQ== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/node-fetch@2.6.15", "@supabase/node-fetch@^2.6.14": + version "2.6.15" + resolved "https://registry.yarnpkg.com/@supabase/node-fetch/-/node-fetch-2.6.15.tgz#731271430e276983191930816303c44159e7226c" + integrity sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ== + dependencies: + whatwg-url "^5.0.0" + +"@supabase/node-fetch@^2.6.13": + version "2.6.13" + resolved "https://registry.yarnpkg.com/@supabase/node-fetch/-/node-fetch-2.6.13.tgz#0d36219a9e2134049a7317591e1d4fbf73a42ec4" + integrity sha512-rEHQaDVzxLZMCK3p+JW2nzEsK4AJpOQhetppaqAzrFum0Ub8wcnoM/8f1dWRZSulY5fRDP6rJaWT/8X3VleCzg== + dependencies: + whatwg-url "^5.0.0" + +"@supabase/postgrest-js@1.19.4": + version "1.19.4" + resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.19.4.tgz#41de1e4310ce8ddba87becd7e0878f4ad7a659a2" + integrity sha512-O4soKqKtZIW3olqmbXXbKugUtByD2jPa8kL2m2c1oozAO11uCcGrRhkZL0kVxjBLrXHE0mdSkFsMj7jDSfyNpw== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/realtime-js@2.11.15": + version "2.11.15" + resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.11.15.tgz#74e520eee0dda51fdc83902abaaefacad6f3f0a9" + integrity sha512-HQKRnwAqdVqJW/P9TjKVK+/ETpW4yQ8tyDPPtRMKOH4Uh3vQD74vmj353CYs8+YwVBKubeUOOEpI9CT8mT4obw== + dependencies: + "@supabase/node-fetch" "^2.6.13" + "@types/phoenix" "^1.6.6" + "@types/ws" "^8.18.1" + isows "^1.0.7" + ws "^8.18.2" + +"@supabase/storage-js@2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@supabase/storage-js/-/storage-js-2.7.1.tgz#761482f237deec98a59e5af1ace18c7a5e0a69af" + integrity sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/supabase-js@^2.52.0": + version "2.52.0" + resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.52.0.tgz#f10f69b114c1c9773f7ee39088714140d6c8d86e" + integrity sha512-jbs3CV1f2+ge7sgBeEduboT9v/uGjF22v0yWi/5/XFn5tbM8MfWRccsMtsDwAwu24XK8H6wt2LJDiNnZLtx/bg== + dependencies: + "@supabase/auth-js" "2.71.1" + "@supabase/functions-js" "2.4.5" + "@supabase/node-fetch" "2.6.15" + "@supabase/postgrest-js" "1.19.4" + "@supabase/realtime-js" "2.11.15" + "@supabase/storage-js" "2.7.1" + "@tsconfig/node10@^1.0.7": version "1.0.11" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" @@ -1224,7 +1570,14 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/babel__core@^7.1.14": +"@tybys/wasm-util@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" + integrity sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ== + 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== @@ -1250,7 +1603,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*": version "7.20.6" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== @@ -1334,19 +1687,12 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/graceful-fs@^4.1.3": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" - integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== - dependencies: - "@types/node" "*" - "@types/http-errors@*": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@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== @@ -1358,7 +1704,7 @@ dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^3.0.0": +"@types/istanbul-reports@^3.0.0", "@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== @@ -1418,6 +1764,11 @@ dependencies: undici-types "~5.26.4" +"@types/phoenix@^1.6.6": + version "1.6.6" + resolved "https://registry.yarnpkg.com/@types/phoenix/-/phoenix-1.6.6.tgz#3c1ab53fd5a23634b8e37ea72ccacbf07fbc7816" + integrity sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A== + "@types/qs@*": version "6.9.15" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" @@ -1445,7 +1796,7 @@ "@types/node" "*" "@types/send" "*" -"@types/stack-utils@^2.0.0": +"@types/stack-utils@^2.0.0", "@types/stack-utils@^2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== @@ -1467,11 +1818,30 @@ "@types/methods" "^1.1.4" "@types/superagent" "^8.1.0" +"@types/validator@^13.11.8": + version "13.15.2" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.15.2.tgz#ee533a20ab977df36917a454754c7e0df4aa6f8f" + integrity sha512-y7pa/oEJJ4iGYBxOpfAKn5b9+xuihvzDVnC/OSvlVnGxVg0pOqmjiMafiJ1KVNQEaPZf9HsEp5icEwGg8uIe5Q== + +"@types/ws@^8.18.1": + version "8.18.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.1.tgz#48464e4bf2ddfd17db13d845467f6070ffea4aa9" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== + dependencies: + "@types/node" "*" + "@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.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + "@types/yargs@^17.0.8": version "17.0.32" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" @@ -1610,6 +1980,108 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== +"@ungap/structured-clone@^1.3.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== + 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== + "@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" @@ -1849,7 +2321,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -ansi-styles@^5.0.0: +ansi-styles@^5.0.0, 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== @@ -1864,7 +2336,7 @@ any-promise@^1.0.0: resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== -anymatch@^3.0.3, anymatch@~3.1.2: +anymatch@^3.1.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2004,65 +2476,67 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" -babel-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" - integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== +babel-jest@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.0.5.tgz#7cc7dd03d0d613125d458521f635b8c2361e89cc" + integrity sha512-mRijnKimhGDMsizTvBTWotwNpzrkHr+VvZUQBof2AufXKB8NXrL1W69TG20EvOz7aevx6FTJIaBuBkYxS8zolg== dependencies: - "@jest/transform" "^29.7.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.6.3" - chalk "^4.0.0" - graceful-fs "^4.2.9" + "@jest/transform" "30.0.5" + "@types/babel__core" "^7.20.5" + babel-plugin-istanbul "^7.0.0" + babel-preset-jest "30.0.1" + chalk "^4.1.2" + graceful-fs "^4.2.11" slash "^3.0.0" -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== +babel-plugin-istanbul@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz#629a178f63b83dc9ecee46fd20266283b1f11280" + integrity sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-instrument "^6.0.2" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" - integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== +babel-plugin-jest-hoist@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz#f271b2066d2c1fb26a863adb8e13f85b06247125" + integrity sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ== dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" + "@babel/template" "^7.27.2" + "@babel/types" "^7.27.3" + "@types/babel__core" "^7.20.5" -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== +babel-preset-current-node-syntax@^1.1.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.8.3" - "@babel/plugin-syntax-import-meta" "^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.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.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-top-level-await" "^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@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" - integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== +babel-preset-jest@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz#7d28db9531bce264e846c8483d54236244b8ae88" + integrity sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw== dependencies: - babel-plugin-jest-hoist "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" + babel-plugin-jest-hoist "30.0.1" + babel-preset-current-node-syntax "^1.1.0" backo2@^1.0.2: version "1.0.2" @@ -2143,6 +2617,16 @@ browserslist@^4.21.10, browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.16" +browserslist@^4.24.0: + version "4.25.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" + integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== + dependencies: + caniuse-lite "^1.0.30001726" + electron-to-chromium "^1.5.173" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -2201,7 +2685,7 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" -callsites@^3.0.0: +callsites@^3.0.0, callsites@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== @@ -2211,7 +2695,7 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0: +camelcase@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -2221,6 +2705,11 @@ caniuse-lite@^1.0.30001629: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz#32c467d4bf1f1a0faa63fc793c2ba81169e7652f" integrity sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA== +caniuse-lite@^1.0.30001726: + version "1.0.30001731" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz#277c07416ea4613ec564e5b0ffb47e7b60f32e2f" + integrity sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg== + chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -2278,10 +2767,29 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -cjs-module-lexer@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" - integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== +ci-info@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.3.0.tgz#c39b1013f8fdbd28cd78e62318357d02da160cd7" + integrity sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ== + +cjs-module-lexer@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz#586e87d4341cb2661850ece5190232ccdebcff8b" + integrity sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA== + +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +class-validator@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.2.tgz#a3de95edd26b703e89c151a2023d3c115030340d" + integrity sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw== + dependencies: + "@types/validator" "^13.11.8" + libphonenumber-js "^1.11.1" + validator "^13.9.0" cli-cursor@^3.1.0: version "3.1.0" @@ -2354,7 +2862,7 @@ co@^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.0: +collect-v8-coverage@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== @@ -2491,19 +2999,6 @@ cosmiconfig@^8.2.0: parse-json "^5.2.0" path-type "^4.0.0" -create-jest@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" - integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== - dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-config "^29.7.0" - jest-util "^29.7.0" - prompts "^2.0.1" - create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -2583,17 +3078,17 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: dependencies: ms "2.1.2" -dedent@^1.0.0: - version "1.5.3" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" - integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== +dedent@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.6.0.tgz#79d52d6389b1ffa67d2bcef59ba51847a9d503b2" + integrity sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA== 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.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== @@ -2638,7 +3133,7 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-newline@^3.0.0: +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== @@ -2712,6 +3207,11 @@ electron-to-chromium@^1.4.796: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.816.tgz#3624649d1e7fde5cdbadf59d31a524245d8ee85f" integrity sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw== +electron-to-chromium@^1.5.173: + version "1.5.195" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.195.tgz#2fe0d9b644726292189f227be73740868617b6d5" + integrity sha512-URclP0iIaDUzqcAyV1v2PgduJ9N0IdXmWsnPzPfelvBmjmZzEy6xJcjb1cXj+TbYqXgtLrjHEoaSIdTYhw4ezg== + emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -2853,6 +3353,11 @@ escalade@^3.1.1, escalade@^3.1.2: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -3089,7 +3594,7 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@^5.0.0: +execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -3104,12 +3609,24 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expect@^29.0.0, expect@^29.7.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.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/expect/-/expect-30.0.5.tgz#c23bf193c5e422a742bfd2990ad990811de41a5a" + integrity sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ== + dependencies: + "@jest/expect-utils" "30.0.5" + "@jest/get-type" "30.0.1" + jest-matcher-utils "30.0.5" + jest-message-util "30.0.5" + jest-mock "30.0.5" + jest-util "30.0.5" + +expect@^29.0.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== @@ -3209,7 +3726,7 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fb-watchman@^2.0.0: +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== @@ -3360,7 +3877,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.2, fsevents@~2.3.2: +fsevents@^2.3.3, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -3665,10 +4182,10 @@ import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== +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" @@ -3825,7 +4342,7 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-generator-fn@^2.0.0: +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== @@ -3932,23 +4449,17 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isows@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-instrument@^5.0.4: - version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" - integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-instrument@^6.0.0: +istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== @@ -3968,14 +4479,14 @@ istanbul-lib-report@^3.0.0: make-dir "^4.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== +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" - source-map "^0.6.1" istanbul-reports@^3.1.3: version "3.1.7" @@ -4004,86 +4515,97 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" -jest-changed-files@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" - integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== +jest-changed-files@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-30.0.5.tgz#ec448f83bd9caa894dd7da8707f207c356a19924" + integrity sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A== dependencies: - execa "^5.0.0" - jest-util "^29.7.0" + execa "^5.1.1" + jest-util "30.0.5" p-limit "^3.1.0" -jest-circus@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" - integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== +jest-circus@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-30.0.5.tgz#9b4d44feb56c7ffe14411ad7fc08af188c5d4da7" + integrity sha512-h/sjXEs4GS+NFFfqBDYT7y5Msfxh04EwWLhQi0F8kuWpe+J/7tICSlswU8qvBqumR3kFgHbfu7vU6qruWWBPug== dependencies: - "@jest/environment" "^29.7.0" - "@jest/expect" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" + "@jest/environment" "30.0.5" + "@jest/expect" "30.0.5" + "@jest/test-result" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - chalk "^4.0.0" + chalk "^4.1.2" co "^4.6.0" - dedent "^1.0.0" - is-generator-fn "^2.0.0" - jest-each "^29.7.0" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-runtime "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" + dedent "^1.6.0" + is-generator-fn "^2.1.0" + jest-each "30.0.5" + jest-matcher-utils "30.0.5" + jest-message-util "30.0.5" + jest-runtime "30.0.5" + jest-snapshot "30.0.5" + jest-util "30.0.5" p-limit "^3.1.0" - pretty-format "^29.7.0" - pure-rand "^6.0.0" + pretty-format "30.0.5" + pure-rand "^7.0.0" slash "^3.0.0" - stack-utils "^2.0.3" + stack-utils "^2.0.6" -jest-cli@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" - integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== +jest-cli@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-30.0.5.tgz#c3fbfdabd1a5c428429476f915a1ba6d0774cc50" + integrity sha512-Sa45PGMkBZzF94HMrlX4kUyPOwUpdZasaliKN3mifvDmkhLYqLLg8HQTzn6gq7vJGahFYMQjXgyJWfYImKZzOw== dependencies: - "@jest/core" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" - chalk "^4.0.0" - create-jest "^29.7.0" - exit "^0.1.2" - import-local "^3.0.2" - jest-config "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - yargs "^17.3.1" - -jest-config@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" - integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.7.0" - "@jest/types" "^29.6.3" - babel-jest "^29.7.0" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^29.7.0" - jest-environment-node "^29.7.0" - jest-get-type "^29.6.3" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-runner "^29.7.0" - jest-util "^29.7.0" - jest-validate "^29.7.0" - micromatch "^4.0.4" + "@jest/core" "30.0.5" + "@jest/test-result" "30.0.5" + "@jest/types" "30.0.5" + chalk "^4.1.2" + exit-x "^0.2.2" + import-local "^3.2.0" + jest-config "30.0.5" + jest-util "30.0.5" + jest-validate "30.0.5" + yargs "^17.7.2" + +jest-config@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-30.0.5.tgz#567cf39b595229b786506a496c22e222d5e8d480" + integrity sha512-aIVh+JNOOpzUgzUnPn5FLtyVnqc3TQHVMupYtyeURSb//iLColiMIR8TxCIDKyx9ZgjKnXGucuW68hCxgbrwmA== + dependencies: + "@babel/core" "^7.27.4" + "@jest/get-type" "30.0.1" + "@jest/pattern" "30.0.1" + "@jest/test-sequencer" "30.0.5" + "@jest/types" "30.0.5" + babel-jest "30.0.5" + 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.0.5" + jest-docblock "30.0.1" + jest-environment-node "30.0.5" + jest-regex-util "30.0.1" + jest-resolve "30.0.5" + jest-runner "30.0.5" + jest-util "30.0.5" + jest-validate "30.0.5" + micromatch "^4.0.8" parse-json "^5.2.0" - pretty-format "^29.7.0" + pretty-format "30.0.5" slash "^3.0.0" strip-json-comments "^3.1.1" +jest-diff@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-30.0.5.tgz#b40f81e0c0d13e5b81c4d62b0d0dfa6a524ee0fd" + integrity sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A== + dependencies: + "@jest/diff-sequences" "30.0.1" + "@jest/get-type" "30.0.1" + chalk "^4.1.2" + pretty-format "30.0.5" + jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -4094,67 +4616,77 @@ jest-diff@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-docblock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" - integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== +jest-docblock@30.0.1: + version "30.0.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-30.0.1.tgz#545ff59f2fa88996bd470dba7d3798a8421180b1" + integrity sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA== dependencies: - detect-newline "^3.0.0" + detect-newline "^3.1.0" -jest-each@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" - integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== +jest-each@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-30.0.5.tgz#5962264ff246cd757ba44db096c1bc5b4835173e" + integrity sha512-dKjRsx1uZ96TVyejD3/aAWcNKy6ajMaN531CwWIsrazIqIoXI9TnnpPlkrEYku/8rkS3dh2rbH+kMOyiEIv0xQ== dependencies: - "@jest/types" "^29.6.3" - chalk "^4.0.0" - jest-get-type "^29.6.3" - jest-util "^29.7.0" - pretty-format "^29.7.0" + "@jest/get-type" "30.0.1" + "@jest/types" "30.0.5" + chalk "^4.1.2" + jest-util "30.0.5" + pretty-format "30.0.5" -jest-environment-node@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" - integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== +jest-environment-node@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-30.0.5.tgz#6a98dd80e0384ead67ed05643381395f6cda93c9" + integrity sha512-ppYizXdLMSvciGsRsMEnv/5EFpvOdXBaXRBzFUDPWrsfmog4kYrOGWXarLllz6AXan6ZAA/kYokgDWuos1IKDA== dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/types" "^29.6.3" + "@jest/environment" "30.0.5" + "@jest/fake-timers" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - jest-mock "^29.7.0" - jest-util "^29.7.0" + jest-mock "30.0.5" + jest-util "30.0.5" + jest-validate "30.0.5" jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-haste-map@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" - integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== +jest-haste-map@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-30.0.5.tgz#fdd0daa322b02eb34267854cff2859fae21e92a6" + integrity sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg== dependencies: - "@jest/types" "^29.6.3" - "@types/graceful-fs" "^4.1.3" + "@jest/types" "30.0.5" "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.6.3" - jest-util "^29.7.0" - jest-worker "^29.7.0" - micromatch "^4.0.4" + anymatch "^3.1.3" + fb-watchman "^2.0.2" + graceful-fs "^4.2.11" + jest-regex-util "30.0.1" + jest-util "30.0.5" + jest-worker "30.0.5" + micromatch "^4.0.8" walker "^1.0.8" optionalDependencies: - fsevents "^2.3.2" + fsevents "^2.3.3" -jest-leak-detector@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" - integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== +jest-leak-detector@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-30.0.5.tgz#00cfd2b323f48d8f4416b0a3e05fcf4c51f18864" + integrity sha512-3Uxr5uP8jmHMcsOtYMRB/zf1gXN3yUIc+iPorhNETG54gErFIiUhLvyY/OggYpSMOEYqsmRxmuU4ZOoX5jpRFg== dependencies: - jest-get-type "^29.6.3" - pretty-format "^29.7.0" + "@jest/get-type" "30.0.1" + pretty-format "30.0.5" + +jest-matcher-utils@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz#dff3334be58faea4a5e1becc228656fbbfc2467d" + integrity sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ== + dependencies: + "@jest/get-type" "30.0.1" + chalk "^4.1.2" + jest-diff "30.0.5" + pretty-format "30.0.5" jest-matcher-utils@^29.7.0: version "29.7.0" @@ -4166,6 +4698,21 @@ jest-matcher-utils@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" +jest-message-util@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-30.0.5.tgz#dd12ffec91dd3fa6a59cbd538a513d8e239e070c" + integrity sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA== + dependencies: + "@babel/code-frame" "^7.27.1" + "@jest/types" "30.0.5" + "@types/stack-utils" "^2.0.3" + chalk "^4.1.2" + graceful-fs "^4.2.11" + micromatch "^4.0.8" + pretty-format "30.0.5" + slash "^3.0.0" + stack-utils "^2.0.6" + jest-message-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" @@ -4181,128 +4728,148 @@ jest-message-util@^29.7.0: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" - integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== +jest-mock-extended@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jest-mock-extended/-/jest-mock-extended-4.0.0.tgz#fe8cfa686c7ada4be2e7f7a3eced794b1338c18b" + integrity sha512-7BZpfuvLam+/HC+NxifIi9b+5VXj/utUDMPUqrDJehGWVuXPtLS9Jqlob2mJLrI/pg2k1S8DMfKDvEB88QNjaQ== dependencies: - "@jest/types" "^29.6.3" + ts-essentials "^10.0.2" + +jest-mock@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-30.0.5.tgz#ef437e89212560dd395198115550085038570bdd" + integrity sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ== + dependencies: + "@jest/types" "30.0.5" "@types/node" "*" - jest-util "^29.7.0" + jest-util "30.0.5" -jest-pnp-resolver@^1.2.2: +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@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" - integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== +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@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" - integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== +jest-resolve-dependencies@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-30.0.5.tgz#53be4c51d296c84a0e75608e7b77b6fe92dbac29" + integrity sha512-/xMvBR4MpwkrHW4ikZIWRttBBRZgWK4d6xt3xW1iRDSKt4tXzYkMkyPfBnSCgv96cpkrctfXs6gexeqMYqdEpw== dependencies: - jest-regex-util "^29.6.3" - jest-snapshot "^29.7.0" + jest-regex-util "30.0.1" + jest-snapshot "30.0.5" -jest-resolve@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" - integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== +jest-resolve@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-30.0.5.tgz#f52f91600070b7073db465dc553eee5471ea8e06" + integrity sha512-d+DjBQ1tIhdz91B79mywH5yYu76bZuE96sSbxj8MkjWVx5WNdt1deEFRONVL4UkKLSrAbMkdhb24XN691yDRHg== dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-pnp-resolver "^1.2.2" - jest-util "^29.7.0" - jest-validate "^29.7.0" - resolve "^1.20.0" - resolve.exports "^2.0.0" + chalk "^4.1.2" + graceful-fs "^4.2.11" + jest-haste-map "30.0.5" + jest-pnp-resolver "^1.2.3" + jest-util "30.0.5" + jest-validate "30.0.5" slash "^3.0.0" - -jest-runner@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" - integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== - dependencies: - "@jest/console" "^29.7.0" - "@jest/environment" "^29.7.0" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" + unrs-resolver "^1.7.11" + +jest-runner@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-30.0.5.tgz#5cbaaf85964246da4f65d697f186846f23cd9b5a" + integrity sha512-JcCOucZmgp+YuGgLAXHNy7ualBx4wYSgJVWrYMRBnb79j9PD0Jxh0EHvR5Cx/r0Ce+ZBC4hCdz2AzFFLl9hCiw== + dependencies: + "@jest/console" "30.0.5" + "@jest/environment" "30.0.5" + "@jest/test-result" "30.0.5" + "@jest/transform" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - chalk "^4.0.0" + chalk "^4.1.2" emittery "^0.13.1" - graceful-fs "^4.2.9" - jest-docblock "^29.7.0" - jest-environment-node "^29.7.0" - jest-haste-map "^29.7.0" - jest-leak-detector "^29.7.0" - jest-message-util "^29.7.0" - jest-resolve "^29.7.0" - jest-runtime "^29.7.0" - jest-util "^29.7.0" - jest-watcher "^29.7.0" - jest-worker "^29.7.0" + exit-x "^0.2.2" + graceful-fs "^4.2.11" + jest-docblock "30.0.1" + jest-environment-node "30.0.5" + jest-haste-map "30.0.5" + jest-leak-detector "30.0.5" + jest-message-util "30.0.5" + jest-resolve "30.0.5" + jest-runtime "30.0.5" + jest-util "30.0.5" + jest-watcher "30.0.5" + jest-worker "30.0.5" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" - integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== - dependencies: - "@jest/environment" "^29.7.0" - "@jest/fake-timers" "^29.7.0" - "@jest/globals" "^29.7.0" - "@jest/source-map" "^29.6.3" - "@jest/test-result" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" +jest-runtime@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-30.0.5.tgz#d6a7e22687264240d1786d6f7682ac6a2872e552" + integrity sha512-7oySNDkqpe4xpX5PPiJTe5vEa+Ak/NnNz2bGYZrA1ftG3RL3EFlHaUkA1Cjx+R8IhK0Vg43RML5mJedGTPNz3A== + dependencies: + "@jest/environment" "30.0.5" + "@jest/fake-timers" "30.0.5" + "@jest/globals" "30.0.5" + "@jest/source-map" "30.0.1" + "@jest/test-result" "30.0.5" + "@jest/transform" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^29.7.0" - jest-message-util "^29.7.0" - jest-mock "^29.7.0" - jest-regex-util "^29.6.3" - jest-resolve "^29.7.0" - jest-snapshot "^29.7.0" - jest-util "^29.7.0" + 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.0.5" + jest-message-util "30.0.5" + jest-mock "30.0.5" + jest-regex-util "30.0.1" + jest-resolve "30.0.5" + jest-snapshot "30.0.5" + jest-util "30.0.5" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" - integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-jsx" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.7.0" - "@jest/transform" "^29.7.0" - "@jest/types" "^29.6.3" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^29.7.0" - graceful-fs "^4.2.9" - jest-diff "^29.7.0" - jest-get-type "^29.6.3" - jest-matcher-utils "^29.7.0" - jest-message-util "^29.7.0" - jest-util "^29.7.0" - natural-compare "^1.4.0" - pretty-format "^29.7.0" - semver "^7.5.3" +jest-snapshot@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-30.0.5.tgz#6600716eef2e6d8ea1dd788ae4385f3a2791b11f" + integrity sha512-T00dWU/Ek3LqTp4+DcW6PraVxjk28WY5Ua/s+3zUKSERZSNyxTqhDXCWKG5p2HAJ+crVQ3WJ2P9YVHpj1tkW+g== + 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.0.5" + "@jest/get-type" "30.0.1" + "@jest/snapshot-utils" "30.0.5" + "@jest/transform" "30.0.5" + "@jest/types" "30.0.5" + babel-preset-current-node-syntax "^1.1.0" + chalk "^4.1.2" + expect "30.0.5" + graceful-fs "^4.2.11" + jest-diff "30.0.5" + jest-matcher-utils "30.0.5" + jest-message-util "30.0.5" + jest-util "30.0.5" + pretty-format "30.0.5" + semver "^7.7.2" + synckit "^0.11.8" + +jest-util@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-30.0.5.tgz#035d380c660ad5f1748dff71c4105338e05f8669" + integrity sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g== + dependencies: + "@jest/types" "30.0.5" + "@types/node" "*" + chalk "^4.1.2" + ci-info "^4.2.0" + graceful-fs "^4.2.11" + picomatch "^4.0.2" jest-util@^29.0.0, jest-util@^29.7.0: version "29.7.0" @@ -4316,60 +4883,61 @@ jest-util@^29.0.0, jest-util@^29.7.0: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" - integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== +jest-validate@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-30.0.5.tgz#d26fd218b8d566bff48fd98880b8ea94fd0d8456" + integrity sha512-ouTm6VFHaS2boyl+k4u+Qip4TSH7Uld5tyD8psQ8abGgt2uYYB8VwVfAHWHjHc0NWmGGbwO5h0sCPOGHHevefw== dependencies: - "@jest/types" "^29.6.3" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^29.6.3" + "@jest/get-type" "30.0.1" + "@jest/types" "30.0.5" + camelcase "^6.3.0" + chalk "^4.1.2" leven "^3.1.0" - pretty-format "^29.7.0" + pretty-format "30.0.5" -jest-watcher@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" - integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== +jest-watcher@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-30.0.5.tgz#90db6e3f582b88085bde58f7555cbdd3a1beb10d" + integrity sha512-z9slj/0vOwBDBjN3L4z4ZYaA+pG56d6p3kTUhFRYGvXbXMWhXmb/FIxREZCD06DYUwDKKnj2T80+Pb71CQ0KEg== dependencies: - "@jest/test-result" "^29.7.0" - "@jest/types" "^29.6.3" + "@jest/test-result" "30.0.5" + "@jest/types" "30.0.5" "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" + ansi-escapes "^4.3.2" + chalk "^4.1.2" emittery "^0.13.1" - jest-util "^29.7.0" - string-length "^4.0.1" + jest-util "30.0.5" + string-length "^4.0.2" -jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== +jest-worker@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-30.0.5.tgz#0b85cbab10610303e8d84e214f94d8f052c3cd04" + integrity sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ== dependencies: "@types/node" "*" + "@ungap/structured-clone" "^1.3.0" + jest-util "30.0.5" merge-stream "^2.0.0" - supports-color "^8.0.0" + supports-color "^8.1.1" -jest-worker@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" - integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== dependencies: "@types/node" "*" - jest-util "^29.7.0" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.5.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" - integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== +jest@^30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/jest/-/jest-30.0.5.tgz#ee62729fb77829790d67c660d852350fbde315ce" + integrity sha512-y2mfcJywuTUkvLm2Lp1/pFX8kTgMO5yyQGq/Sk/n2mN7XWYp4JsCZ/QXW34M8YScgk8bPZlREH04f6blPnoHnQ== dependencies: - "@jest/core" "^29.7.0" - "@jest/types" "^29.6.3" - import-local "^3.0.2" - jest-cli "^29.7.0" + "@jest/core" "30.0.5" + "@jest/types" "30.0.5" + import-local "^3.2.0" + jest-cli "30.0.5" js-tokens@^4.0.0: version "4.0.0" @@ -4396,6 +4964,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -4459,11 +5032,6 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -4477,6 +5045,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.11.1: + version "1.12.10" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.12.10.tgz#525f7c9ffaea40c21463d3906f52ec3209ea5945" + integrity sha512-E91vHJD61jekHHR/RF/E83T/CMoaLXT7cwYA75T4gim4FZjnM6hbJjVIGg7chqlSqRsSvQ3izGmOjHy1SQzcGQ== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -4627,6 +5200,14 @@ micromatch@^4.0.0, micromatch@^4.0.4: braces "^3.0.3" picomatch "^2.3.1" +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -4737,6 +5318,11 @@ mz@^2.4.0: object-assign "^4.0.1" thenify-all "^1.0.0" +napi-postinstall@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.2.tgz#03c62080e88b311c4d7423b0f15f0c920bbcc626" + integrity sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw== + 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" @@ -4786,6 +5372,11 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + normalize-path@3.0.0, normalize-path@^3.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" @@ -5085,6 +5676,11 @@ picocolors@^1.0.0, picocolors@^1.0.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.1.tgz#68c26c8837399e5819edce48590412ea07f17a07" @@ -5100,10 +5696,10 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pirates@^4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" - integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== +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" @@ -5161,6 +5757,15 @@ prettier@^3.3.3: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== +pretty-format@30.0.5: + version "30.0.5" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-30.0.5.tgz#e001649d472800396c1209684483e18a4d250360" + integrity sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw== + dependencies: + "@jest/schemas" "30.0.5" + ansi-styles "^5.2.0" + react-is "^18.3.1" + pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" @@ -5175,14 +5780,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -5196,10 +5793,10 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -pure-rand@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" - integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== +pure-rand@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-7.0.1.tgz#6f53a5a9e3e4a47445822af96821ca509ed37566" + integrity sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ== qs@6.11.0: version "6.11.0" @@ -5242,7 +5839,7 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -react-is@^18.0.0: +react-is@^18.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== @@ -5328,12 +5925,7 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve.exports@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" - integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== - -resolve@^1.20.0, resolve@^1.22.4: +resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -5434,7 +6026,7 @@ schema-utils@^3.1.1, schema-utils@^3.2.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -semver@^6.3.0, semver@^6.3.1: +semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -5444,6 +6036,11 @@ semver@^7.3.4, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== +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@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -5537,7 +6134,7 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -5547,11 +6144,6 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -5578,7 +6170,7 @@ source-map@0.7.4, 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== @@ -5593,7 +6185,7 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -stack-utils@^2.0.3: +stack-utils@^2.0.3, 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== @@ -5610,7 +6202,7 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string-length@^4.0.1: +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== @@ -5776,7 +6368,7 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: +supports-color@^8.0.0, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -5798,6 +6390,13 @@ symbol-observable@^1.0.4: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +synckit@^0.11.8: + version "0.11.11" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.11.tgz#c0b619cf258a97faa209155d9cd1699b5c998cb0" + integrity sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw== + dependencies: + "@pkgr/core" "^0.2.9" + synckit@^0.9.1: version "0.9.2" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" @@ -5909,6 +6508,11 @@ ts-api-utils@^1.3.0: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== +ts-essentials@^10.0.2: + 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-jest@^29.1.0: version "29.1.5" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.5.tgz#d6c0471cc78bffa2cb4664a0a6741ef36cfe8f69" @@ -6138,6 +6742,33 @@ unpipe@1.0.0, 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.0.16: version "1.1.0" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" @@ -6146,6 +6777,14 @@ update-browserslist-db@^1.0.16: escalade "^3.1.2" picocolors "^1.0.1" +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -6182,6 +6821,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" +validator@^13.9.0: + version "13.15.15" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.15.tgz#246594be5671dc09daa35caec5689fcd18c6e7e4" + integrity sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A== + value-or-promise@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" @@ -6377,13 +7021,13 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== +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 "^3.0.7" + signal-exit "^4.0.1" ws@8.17.1: version "8.17.1" @@ -6395,6 +7039,11 @@ ws@8.17.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== +ws@^8.18.2: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + xss@^1.0.8: version "1.0.15" resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.15.tgz#96a0e13886f0661063028b410ed1b18670f4e59a" @@ -6441,7 +7090,7 @@ yargs@^16.0.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.3.1, yargs@^17.6.2: +yargs@^17.6.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==