diff --git a/.env.example b/.env.example index 6158414..3fcb69a 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,4 @@ DATABASE_URL=postgresql://user:password@localhost:5432/b2bcall?schema=public POSTGRES_APP_USER= POSTGRES_APP_PASSWORD= APP_DATABASE_URL=postgresql://user:password@localhost:5432/b2bcall?schema=public +REDIS_URL=redis://:password@localhost:6379 diff --git a/TODO.md b/TODO.md index ebd6d4d..0a23384 100644 --- a/TODO.md +++ b/TODO.md @@ -37,8 +37,9 @@ - [x] Seed: catálogo de permissions + roles de sistema + Platform Super Admin inicial (senha em `FIRST_LOGIN.txt`, fora do Git, `mustChangePassword=true`) - [x] Teste automatizado (`pnpm --filter @b2bcall/auth run test:auth`) -- [ ] Camada HTTP (endpoints, rate limit por IP, guards) — depende de `apps/api` existir, - ver docs/AUTHENTICATION.md → "O que falta" +- [x] `apps/api` (NestJS + Fastify): endpoints de auth, JwtAuthGuard, DomainExceptionFilter, + rate limit de login via Redis (5/min por IP e por e-mail), helmet/cors, health checks + — testado ponta a ponta com curl (login, refresh rotation, logout, RBAC, 401/403/429) - [ ] Password reset por e-mail — depende de SMTP configurado ## PHASE 05+ — ver `agente.md` seções 15 em diante (FreeSWITCH, Telefonia, Call Center, diff --git a/apps/api/package.json b/apps/api/package.json new file mode 100644 index 0000000..9bb9bcc --- /dev/null +++ b/apps/api/package.json @@ -0,0 +1,33 @@ +{ + "name": "@b2bcall/api", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "tsx watch src/main.ts", + "build": "tsc -p tsconfig.json", + "start": "node dist/main.js", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@b2bcall/auth": "workspace:*", + "@b2bcall/database": "workspace:*", + "@b2bcall/shared": "workspace:*", + "@fastify/cors": "11.3.0", + "@fastify/helmet": "13.1.1", + "@fastify/rate-limit": "11.2.0", + "@nestjs/common": "^12.0.1", + "@nestjs/core": "^12.0.1", + "@nestjs/platform-fastify": "^12.0.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.15.1", + "fastify": "5.12.1", + "ioredis": "^6.0.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "tsx": "^4.23.12", + "typescript": "^5.7.0" + } +} diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts new file mode 100644 index 0000000..8fcb5db --- /dev/null +++ b/apps/api/src/app.module.ts @@ -0,0 +1,8 @@ +import { Module } from "@nestjs/common"; +import { HealthModule } from "./health/health.module"; +import { AuthModule } from "./auth/auth.module"; + +@Module({ + imports: [HealthModule, AuthModule], +}) +export class AppModule {} diff --git a/apps/api/src/auth/auth.controller.ts b/apps/api/src/auth/auth.controller.ts new file mode 100644 index 0000000..0bb05f1 --- /dev/null +++ b/apps/api/src/auth/auth.controller.ts @@ -0,0 +1,73 @@ +import { Body, Controller, Get, HttpCode, HttpStatus, Post, Req, UseGuards } from "@nestjs/common"; +import type { FastifyRequest } from "fastify"; +import { + changePassword, + listUserTenants, + login, + logout, + refreshSession, + setActiveTenant, + type AccessTokenClaims, +} from "@b2bcall/auth"; +import { JwtAuthGuard } from "../common/guards/jwt-auth.guard"; +import { CurrentUser } from "../common/decorators/current-user.decorator"; +import { LoginDto } from "./dto/login.dto"; +import { RefreshDto } from "./dto/refresh.dto"; +import { SelectTenantDto } from "./dto/select-tenant.dto"; +import { ChangePasswordDto } from "./dto/change-password.dto"; +import { LoginRateLimitGuard } from "./login-rate-limit.guard"; + +@Controller("auth") +export class AuthController { + @UseGuards(LoginRateLimitGuard) + @Post("login") + @HttpCode(HttpStatus.OK) + async login(@Body() dto: LoginDto, @Req() req: FastifyRequest) { + return login({ + email: dto.email, + password: dto.password, + ipAddress: req.ip, + userAgent: req.headers["user-agent"], + }); + } + + @Post("refresh") + @HttpCode(HttpStatus.OK) + async refresh(@Body() dto: RefreshDto) { + return refreshSession(dto.refreshToken); + } + + @UseGuards(JwtAuthGuard) + @Post("logout") + @HttpCode(HttpStatus.NO_CONTENT) + async logout(@CurrentUser() user: AccessTokenClaims) { + await logout(user.sessionId); + } + + @UseGuards(JwtAuthGuard) + @Get("tenants") + async tenants(@CurrentUser() user: AccessTokenClaims) { + const memberships = await listUserTenants(user.sub); + return memberships.map((m) => ({ + tenantId: m.tenant.id, + code: m.tenant.code, + name: m.tenant.tradeName ?? m.tenant.legalName, + status: m.tenant.status, + })); + } + + @UseGuards(JwtAuthGuard) + @Post("select-tenant") + @HttpCode(HttpStatus.OK) + async selectTenant(@CurrentUser() user: AccessTokenClaims, @Body() dto: SelectTenantDto) { + const accessToken = await setActiveTenant(user.sessionId, user.sub, dto.tenantId); + return { accessToken }; + } + + @UseGuards(JwtAuthGuard) + @Post("change-password") + @HttpCode(HttpStatus.NO_CONTENT) + async changePassword(@CurrentUser() user: AccessTokenClaims, @Body() dto: ChangePasswordDto) { + await changePassword(user.sub, user.sessionId, dto.currentPassword, dto.newPassword); + } +} diff --git a/apps/api/src/auth/auth.module.ts b/apps/api/src/auth/auth.module.ts new file mode 100644 index 0000000..817912c --- /dev/null +++ b/apps/api/src/auth/auth.module.ts @@ -0,0 +1,7 @@ +import { Module } from "@nestjs/common"; +import { AuthController } from "./auth.controller"; + +@Module({ + controllers: [AuthController], +}) +export class AuthModule {} diff --git a/apps/api/src/auth/dto/change-password.dto.ts b/apps/api/src/auth/dto/change-password.dto.ts new file mode 100644 index 0000000..fd096b4 --- /dev/null +++ b/apps/api/src/auth/dto/change-password.dto.ts @@ -0,0 +1,11 @@ +import { IsString, MinLength } from "class-validator"; + +export class ChangePasswordDto { + @IsString() + @MinLength(1) + currentPassword!: string; + + @IsString() + @MinLength(12) + newPassword!: string; +} diff --git a/apps/api/src/auth/dto/login.dto.ts b/apps/api/src/auth/dto/login.dto.ts new file mode 100644 index 0000000..943526c --- /dev/null +++ b/apps/api/src/auth/dto/login.dto.ts @@ -0,0 +1,10 @@ +import { IsEmail, IsString, MinLength } from "class-validator"; + +export class LoginDto { + @IsEmail() + email!: string; + + @IsString() + @MinLength(1) + password!: string; +} diff --git a/apps/api/src/auth/dto/refresh.dto.ts b/apps/api/src/auth/dto/refresh.dto.ts new file mode 100644 index 0000000..0de24ca --- /dev/null +++ b/apps/api/src/auth/dto/refresh.dto.ts @@ -0,0 +1,7 @@ +import { IsString, MinLength } from "class-validator"; + +export class RefreshDto { + @IsString() + @MinLength(1) + refreshToken!: string; +} diff --git a/apps/api/src/auth/dto/select-tenant.dto.ts b/apps/api/src/auth/dto/select-tenant.dto.ts new file mode 100644 index 0000000..253ecdd --- /dev/null +++ b/apps/api/src/auth/dto/select-tenant.dto.ts @@ -0,0 +1,6 @@ +import { IsUUID } from "class-validator"; + +export class SelectTenantDto { + @IsUUID() + tenantId!: string; +} diff --git a/apps/api/src/auth/login-rate-limit.guard.ts b/apps/api/src/auth/login-rate-limit.guard.ts new file mode 100644 index 0000000..79c8e52 --- /dev/null +++ b/apps/api/src/auth/login-rate-limit.guard.ts @@ -0,0 +1,51 @@ +import { CanActivate, ExecutionContext, HttpException, HttpStatus, Injectable } from "@nestjs/common"; +import type { FastifyRequest } from "fastify"; +import { getRedisClient } from "../common/redis"; + +const WINDOW_SECONDS = 60; +const MAX_ATTEMPTS = 5; // agente.md secao 149: "5 tentativas/minuto/IP" + +/** + * Rate limit de login por IP e por e-mail, contado via Redis (INCR + EXPIRE) + * — funciona corretamente com múltiplos workers/instâncias da API, ao + * contrário de um contador em memória local (mesmo princípio da secao 77 do + * agente.md para o CPS limiter do discador). + * + * Progressive blocking (backoff exponencial) NÃO está implementado ainda — + * ver docs/AUTHENTICATION.md. + */ +@Injectable() +export class LoginRateLimitGuard implements CanActivate { + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const redis = getRedisClient(); + + const ip = request.ip; + const email = + typeof (request.body as { email?: unknown } | undefined)?.email === "string" + ? (request.body as { email: string }).email.trim().toLowerCase() + : "unknown"; + + const [ipCount, emailCount] = await Promise.all([ + incrementAndGetCount(redis, `ratelimit:login:ip:${ip}`), + incrementAndGetCount(redis, `ratelimit:login:email:${email}`), + ]); + + if (ipCount > MAX_ATTEMPTS || emailCount > MAX_ATTEMPTS) { + throw new HttpException( + { message: "Muitas tentativas de login. Tente novamente em instantes." }, + HttpStatus.TOO_MANY_REQUESTS, + ); + } + + return true; + } +} + +async function incrementAndGetCount(redis: ReturnType, key: string) { + const count = await redis.incr(key); + if (count === 1) { + await redis.expire(key, WINDOW_SECONDS); + } + return count; +} diff --git a/apps/api/src/common/decorators/current-user.decorator.ts b/apps/api/src/common/decorators/current-user.decorator.ts new file mode 100644 index 0000000..0e9521c --- /dev/null +++ b/apps/api/src/common/decorators/current-user.decorator.ts @@ -0,0 +1,7 @@ +import { createParamDecorator, type ExecutionContext } from "@nestjs/common"; +import type { AuthenticatedRequest } from "../guards/jwt-auth.guard"; + +export const CurrentUser = createParamDecorator((_data: unknown, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + return request.user!; +}); diff --git a/apps/api/src/common/filters/domain-exception.filter.ts b/apps/api/src/common/filters/domain-exception.filter.ts new file mode 100644 index 0000000..961ee55 --- /dev/null +++ b/apps/api/src/common/filters/domain-exception.filter.ts @@ -0,0 +1,49 @@ +import { + ArgumentsHost, + Catch, + ExceptionFilter, + HttpException, + HttpStatus, +} from "@nestjs/common"; +import type { FastifyReply } from "fastify"; +import { + InvalidCredentialsError, + InvalidRefreshTokenError, + NotATenantMemberError, +} from "@b2bcall/auth"; + +/** + * Traduz erros de domínio de packages/auth para HTTP, sem nunca vazar stack + * trace ou detalhes internos na resposta (agente.md secao 147: IDOR/erros + * nunca devolvem dado sensível). + */ +@Catch() +export class DomainExceptionFilter implements ExceptionFilter { + catch(exception: unknown, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const reply = ctx.getResponse(); + + if (exception instanceof HttpException) { + reply.status(exception.getStatus()).send(exception.getResponse()); + return; + } + + if (exception instanceof InvalidCredentialsError) { + reply.status(HttpStatus.UNAUTHORIZED).send({ message: exception.message }); + return; + } + + if (exception instanceof InvalidRefreshTokenError) { + reply.status(HttpStatus.UNAUTHORIZED).send({ message: exception.message }); + return; + } + + if (exception instanceof NotATenantMemberError) { + reply.status(HttpStatus.FORBIDDEN).send({ message: exception.message }); + return; + } + + console.error(exception); + reply.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ message: "Erro interno" }); + } +} diff --git a/apps/api/src/common/guards/jwt-auth.guard.ts b/apps/api/src/common/guards/jwt-auth.guard.ts new file mode 100644 index 0000000..8367b3d --- /dev/null +++ b/apps/api/src/common/guards/jwt-auth.guard.ts @@ -0,0 +1,26 @@ +import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common"; +import type { FastifyRequest } from "fastify"; +import { verifyAccessToken, type AccessTokenClaims } from "@b2bcall/auth"; + +export interface AuthenticatedRequest extends FastifyRequest { + user?: AccessTokenClaims; +} + +@Injectable() +export class JwtAuthGuard implements CanActivate { + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const header = request.headers.authorization; + + if (!header?.startsWith("Bearer ")) { + throw new UnauthorizedException("Token de acesso ausente"); + } + + try { + request.user = await verifyAccessToken(header.slice("Bearer ".length)); + return true; + } catch { + throw new UnauthorizedException("Token de acesso invalido ou expirado"); + } + } +} diff --git a/apps/api/src/common/redis.ts b/apps/api/src/common/redis.ts new file mode 100644 index 0000000..4d0054c --- /dev/null +++ b/apps/api/src/common/redis.ts @@ -0,0 +1,17 @@ +import Redis from "ioredis"; + +let client: Redis | undefined; + +export function getRedisClient(): Redis { + if (!client) { + const url = process.env.REDIS_URL; + if (!url) { + throw new Error("REDIS_URL is not set"); + } + // REDIS_HOST/REDIS_PORT (docker-compose service name "redis") only + // resolve from inside the Docker network; REDIS_URL is the host-facing + // connection string (localhost) used while apps/api runs outside Docker. + client = new Redis(url); + } + return client; +} diff --git a/apps/api/src/health/health.controller.ts b/apps/api/src/health/health.controller.ts new file mode 100644 index 0000000..bc5f391 --- /dev/null +++ b/apps/api/src/health/health.controller.ts @@ -0,0 +1,40 @@ +import { Controller, Get, HttpException, HttpStatus } from "@nestjs/common"; +import { getPrismaClient } from "@b2bcall/database"; +import { getRedisClient } from "../common/redis"; + +@Controller("health") +export class HealthController { + @Get() + root() { + return { status: "ok" }; + } + + @Get("live") + live() { + return { status: "ok" }; + } + + @Get("ready") + async ready() { + const checks: Record = { postgres: "ok", redis: "ok" }; + + try { + await getPrismaClient().$queryRaw`SELECT 1`; + } catch { + checks.postgres = "fail"; + } + + try { + await getRedisClient().ping(); + } catch { + checks.redis = "fail"; + } + + const healthy = Object.values(checks).every((v) => v === "ok"); + if (!healthy) { + throw new HttpException({ status: "unhealthy", checks }, HttpStatus.SERVICE_UNAVAILABLE); + } + + return { status: "ok", checks }; + } +} diff --git a/apps/api/src/health/health.module.ts b/apps/api/src/health/health.module.ts new file mode 100644 index 0000000..40b7bdf --- /dev/null +++ b/apps/api/src/health/health.module.ts @@ -0,0 +1,7 @@ +import { Module } from "@nestjs/common"; +import { HealthController } from "./health.controller"; + +@Module({ + controllers: [HealthController], +}) +export class HealthModule {} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts new file mode 100644 index 0000000..a1542fd --- /dev/null +++ b/apps/api/src/main.ts @@ -0,0 +1,50 @@ +import "reflect-metadata"; +import { NestFactory } from "@nestjs/core"; +import { FastifyAdapter, type NestFastifyApplication } from "@nestjs/platform-fastify"; +import { ValidationPipe } from "@nestjs/common"; +import helmet from "@fastify/helmet"; +import cors from "@fastify/cors"; +import rateLimit from "@fastify/rate-limit"; +import { AppModule } from "./app.module"; +import { DomainExceptionFilter } from "./common/filters/domain-exception.filter"; + +async function bootstrap() { + const app = await NestFactory.create( + AppModule, + new FastifyAdapter({ trustProxy: true }), + ); + + // HTTP security headers (agente.md secao 182). + await app.register(helmet); + + // CORS restritivo: só a origem do frontend, configurável via env. Nunca + // "*" — dados de tenant nunca devem ser acessíveis por qualquer origem. + const corsOrigin = process.env.CORS_ORIGIN; + await app.register(cors, { + origin: corsOrigin ? corsOrigin.split(",") : false, + credentials: true, + }); + + // Rate limit global de defesa em profundidade; o login tem um limite mais + // estrito aplicado no próprio controller (agente.md secao 149). + await app.register(rateLimit, { + max: 300, + timeWindow: "1 minute", + }); + + app.useGlobalPipes( + new ValidationPipe({ + whitelist: true, + forbidNonWhitelisted: true, + transform: true, + }), + ); + + app.useGlobalFilters(new DomainExceptionFilter()); + + const port = Number(process.env.API_PORT ?? 3000); + await app.listen(port, "127.0.0.1"); + console.log(`b2bcall-api ouvindo em http://127.0.0.1:${port}`); +} + +bootstrap(); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json new file mode 100644 index 0000000..b942c1e --- /dev/null +++ b/apps/api/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "strictPropertyInitialization": false, + "types": ["node"] + }, + "include": ["src"] +} diff --git a/docs/AUTHENTICATION.md b/docs/AUTHENTICATION.md index 77be696..5c2b7de 100644 --- a/docs/AUTHENTICATION.md +++ b/docs/AUTHENTICATION.md @@ -71,18 +71,52 @@ O seed cria `admin@b2bcall.local` com senha aleatória de 24 bytes, salva uma `mustChangePassword = true`. Rodar de novo o seed não recria o admin se já existir um usuário com role `platform_super_admin`. -## O que falta (fica para quando existir `apps/api`) +## Camada HTTP (`apps/api`) -Tudo abaixo depende de uma camada HTTP (NestJS/Fastify) que ainda não existe: +NestJS sobre Fastify (agente.md secao 12). Rotas em `apps/api/src/auth`: + +``` +POST /auth/login { email, password } -> { accessToken, refreshToken, sessionId, mustChangePassword } +POST /auth/refresh { refreshToken } -> { accessToken, refreshToken } +POST /auth/logout (autenticado) -> 204 +GET /auth/tenants (autenticado) -> [{ tenantId, code, name, status }] +POST /auth/select-tenant (autenticado) { tenantId } -> { accessToken } +POST /auth/change-password (autenticado) { currentPassword, newPassword } -> 204 +``` + +- `JwtAuthGuard` (`apps/api/src/common/guards`) valida o access token e injeta + `request.user` (claims do JWT); `@CurrentUser()` expõe isso no controller. +- `DomainExceptionFilter` traduz os erros de `packages/auth` + (`InvalidCredentialsError` → 401, `InvalidRefreshTokenError` → 401, + `NotATenantMemberError` → 403) sem vazar stack trace. +- `LoginRateLimitGuard` conta tentativas de login por IP **e** por e-mail via + Redis (`INCR`+`EXPIRE`, 5/minuto — agente.md secao 149), funcionando + corretamente com múltiplas instâncias da API (ao contrário de um contador em + memória local). +- `helmet` + `cors` restritivo (`CORS_ORIGIN` via env, `false` por padrão — + nega tudo até ser configurado) + rate limit global de 300/min como defesa + extra (agente.md secao 182). +- `GET /health`, `/health/live`, `/health/ready` (agente.md secao 187) — + `ready` checa Postgres e Redis de verdade. +- API escuta só em `127.0.0.1:3000` (`API_PORT`) — nunca exposta direto, + fica atrás do nginx quando ele existir. + +**Pegadinha de rede corrigida durante os testes**: `REDIS_HOST=redis` / +`POSTGRES_HOST=postgres` no `.env` são os nomes de serviço do Docker Compose — +só resolvem de dentro da rede Docker. Como `apps/api` roda direto no host +(ainda não containerizada), ela usa `REDIS_URL`/`APP_DATABASE_URL` +(`@localhost`) em vez disso. Quando `b2bcall-api` virar um serviço Docker na +mesma rede, essas URLs precisam trocar para os hostnames internos. + +## O que falta -- Rate limiting de login por IP/usuário (agente.md secao 149) — plugin - `@fastify/rate-limit` ou equivalente, não implementável em `packages/auth` - isoladamente. -- Endpoints REST (`POST /auth/login`, `/auth/refresh`, `/auth/logout`, - `/auth/select-tenant`) e guards HTTP que traduzem `InvalidCredentialsError`/ - `NotATenantMemberError` em 401/403. - Password reset (link expirável por e-mail) — precisa de um provedor de e-mail/SMTP, fora do escopo desta fase. - Reuse detection de refresh token roubado (família de tokens) — não implementado; a rotação simples (secao 148) já está feita, a detecção de reuso é um hardening adicional a avaliar depois. +- Progressive blocking (backoff exponencial) no login — hoje é só janela fixa + de 5/minuto. +- Enforcement server-side de `mustChangePassword` bloqueando outras rotas + (hoje só o client precisa respeitar a flag) — revisitar quando existirem + rotas de negócio de verdade para proteger. diff --git a/packages/auth/src/session.ts b/packages/auth/src/session.ts index f271be9..3d60a41 100644 --- a/packages/auth/src/session.ts +++ b/packages/auth/src/session.ts @@ -1,6 +1,6 @@ import { getPrismaClient, withUserContext } from "@b2bcall/database"; import { recordAuditEvent } from "./audit"; -import { verifyPassword } from "./password"; +import { hashPassword, verifyPassword } from "./password"; import { REFRESH_TOKEN_TTL_MS, generateRefreshToken, @@ -185,3 +185,35 @@ export async function setActiveTenant( return signAccessToken({ sub: userId, sessionId: session.id, tenantId: session.activeTenantId! }); } + +/** + * Troca de senha (usada tanto voluntariamente quanto para satisfazer + * `mustChangePassword`, agente.md secao 199 — força troca no primeiro login). + * Revoga todas as outras sessões do usuário; a atual continua válida. + */ +export async function changePassword( + userId: string, + currentSessionId: string, + currentPassword: string, + newPassword: string, +): Promise { + const prisma = getPrismaClient(); + const user = await prisma.user.findUniqueOrThrow({ where: { id: userId } }); + + const currentOk = await verifyPassword(user.passwordHash, currentPassword); + if (!currentOk) { + throw new InvalidCredentialsError(); + } + + await prisma.user.update({ + where: { id: userId }, + data: { passwordHash: await hashPassword(newPassword), mustChangePassword: false }, + }); + + await prisma.session.updateMany({ + where: { userId, id: { not: currentSessionId }, revokedAt: null }, + data: { revokedAt: new Date() }, + }); + + await recordAuditEvent(prisma, { action: "PASSWORD_CHANGE", userId }); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7289a0f..33d61f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,64 @@ importers: specifier: ^5.9.3 version: 5.9.3 + apps/api: + dependencies: + '@b2bcall/auth': + specifier: workspace:* + version: link:../../packages/auth + '@b2bcall/database': + specifier: workspace:* + version: link:../../packages/database + '@b2bcall/shared': + specifier: workspace:* + version: link:../../packages/shared + '@fastify/cors': + specifier: 11.3.0 + version: 11.3.0 + '@fastify/helmet': + specifier: 13.1.1 + version: 13.1.1 + '@fastify/rate-limit': + specifier: 11.2.0 + version: 11.2.0 + '@nestjs/common': + specifier: ^12.0.1 + version: 12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^12.0.1 + version: 12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-fastify': + specifier: ^12.0.1 + version: 12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)) + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.15.1 + version: 0.15.1 + fastify: + specifier: 5.12.1 + version: 5.12.1 + ioredis: + specifier: ^6.0.0 + version: 6.0.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.2 + version: 7.8.2 + devDependencies: + '@types/node': + specifier: ^22.0.0 + version: 22.20.1 + tsx: + specifier: ^4.23.12 + version: 4.23.12 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + packages/auth: dependencies: '@b2bcall/database': @@ -88,6 +146,9 @@ packages: resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + '@electric-sql/pglite-socket@0.1.3': resolution: {integrity: sha512-LAciWM0M1dCL8hlsxu2venbVZcdxema0BtDfpWYVqr+Y468UADw0pFWidhKw1M8sfJ8rdLT71tjMmnirf/IZRQ==} hasBin: true @@ -258,6 +319,91 @@ packages: cpu: [x64] os: [win32] + '@fastify/ajv-compiler@4.0.6': + resolution: {integrity: sha512-NtuzM0SfaMJbGlnjr9LWQUN5LzgSrbB8tf/wRZNas+4E1O/Nmzl53e7ruT61HDZyRCJGC6FxIogmNZO1c5ETBA==} + + '@fastify/cors@11.3.0': + resolution: {integrity: sha512-ggQGua+xHv1MvePbPr0v//xLYEsCXbWspquXCJS9Ot5YoRXq8J8ZWzHnxDBVnbtXosvistXo6LtNzOJswf64Fw==} + + '@fastify/error@4.2.0': + resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} + + '@fastify/fast-json-stringify-compiler@5.1.0': + resolution: {integrity: sha512-PxcYtKLbQ8Z+yApiqjK8FwxIwvEj38k2OiLc17u8dkJSlmfi2wHHPaSnaoqBPQqtvF8YVsDgDpP2snDCfFrpfw==} + + '@fastify/formbody@9.0.0': + resolution: {integrity: sha512-T/af26CSrUARBCvsEmv+DJLPfZlrRKESzqironxP1j7qzuLyKcoZtj6MuTGShuKx1THXugoie2oFbUJxXfGFzA==} + + '@fastify/forwarded@3.0.2': + resolution: {integrity: sha512-NE8HgKLgYejV9lDpqkEFaDKMLYelJBVfHekhB0UKvX0ghagXRJqg68feg8er1NPXxG4N9i6vPxzt8E+3wHfcmA==} + + '@fastify/helmet@13.1.1': + resolution: {integrity: sha512-bSat5DTq8geASv8G6P0KW1UbltZ+xGD/zyd9S72pT7ogAHehcsWL85GdjMRCjDsExJvaEvgEZ52qU/2HXirVCw==} + + '@fastify/merge-json-schemas@0.2.1': + resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} + + '@fastify/proxy-addr@5.1.0': + resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} + + '@fastify/rate-limit@11.2.0': + resolution: {integrity: sha512-X7osJd4XSvMoejYrnJkSZYYjY1eNYoBqhjlzf1RakC2204qExFqZFTKj5+T7VuzA/iUI9Z3UoSqQRkB2HpG0oQ==} + + '@ioredis/commands@2.0.0': + resolution: {integrity: sha512-vrx0AE/T0h7cRZwfo1M39Cr+ZhZrkf0V8mQN75wucKCxCLD9l/VX6no3gFvrLqD1IlG/1LtzWovqEw3t0Vr9zg==} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@lukeed/ms@2.0.2': + resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} + engines: {node: '>=8'} + + '@nestjs/common@12.0.1': + resolution: {integrity: sha512-v0zTaRCTV2K2xSnb3GnJoQKtaR6VxouJtm+P2gpr5w61dlXeWpXl1WVknCSzUqx2QwTV10tBkHETxvQvkf2Exg==} + peerDependencies: + class-transformer: '>=0.4.1' + class-validator: '>=0.13.2' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@12.0.1': + resolution: {integrity: sha512-rU6tAi8vDdyzHgN0iW0J4UJvziroOqzHqzlqL7phOSPizaXVEePfv+OUOsdJEOh0Qd14mslc3udOheLrAEcZow==} + engines: {node: '>= 20'} + peerDependencies: + '@nestjs/common': ^12.0.0 + '@nestjs/microservices': ^12.0.0 + '@nestjs/platform-express': ^12.0.0 + '@nestjs/websockets': ^12.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + + '@nestjs/platform-fastify@12.0.1': + resolution: {integrity: sha512-LqR0kOahuZAei3wJK+SJfHc9o9H/OSdA7gMSMaW+Kfjy6GtpTNPdfpHeq3w2PuiPgUGk2QIX/dqUAYntJ5arSw==} + peerDependencies: + '@fastify/static': ^10.1.2 + '@fastify/view': ^10.0.0 || ^11.0.0 || ^12.0.0 + '@nestjs/common': ^12.0.0 + '@nestjs/core': ^12.0.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + '@fastify/view': + optional: true + '@node-rs/argon2-android-arm-eabi@2.1.0': resolution: {integrity: sha512-hdWo5kb4eFRbHjdu4O6dVlRPI/CR1vbkJpe3Z9kF2s0Kp42428wg8AxI+8Cv4mygdW309BpUBf3sZaqXBNpdpw==} engines: {node: '>= 10'} @@ -344,6 +490,9 @@ packages: resolution: {integrity: sha512-VBOWfM2u58/to3DFqTGJ2U5cJKQwmjN2zxzsQNZ5a2o8Z6aUrhvqQh8NdgotIF1Y0tMsBNtzOBDBdfvvkwJDSQ==} engines: {node: '>= 10'} + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@prisma/adapter-pg@7.10.0': resolution: {integrity: sha512-N7nwSor0HO1Kz6xBv0TPAjAPysKK0fac6p4fVN3ensLOuzc/83Fgmln5k92eK/cvzqdkSR/2kkAqlbcdwVrwpw==} @@ -484,6 +633,13 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@types/d3-array@3.0.3': resolution: {integrity: sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==} @@ -523,6 +679,9 @@ packages: '@types/lodash@4.17.25': resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==} + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + '@types/node@26.4.0': resolution: {integrity: sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==} @@ -532,6 +691,9 @@ packages: '@types/react@19.2.18': resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + '@types/validator@13.15.10': + resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} + '@visx/curve@4.0.1-alpha.0': resolution: {integrity: sha512-jRu61Uz274pV1zyioXmboyrLutYbnKsgjj4njSGCnhdXj5GkZvZbg+ThDb6oOzoAnJOBRLz4rzPlWvNJOzuVMg==} @@ -567,9 +729,27 @@ packages: '@visx/vendor@4.0.0-alpha.0': resolution: {integrity: sha512-6I+MuqXBcv9jnlcVowHoHKSdk9gXTWkHLKyqBwRWg7LY6A3Ei8SHfubpqGV5rBUSppxMq2RszPJUS6w+H0YgmQ==} + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + avvio@9.3.0: + resolution: {integrity: sha512-g2tQ7LE7oOSqDfwEm3M+ZCMTJc7KiZCdJ4UwyZJb5ckTKyYu50OYmvv0mCFXPuYXoM4zkSt8zM9XQ9KCvxA74A==} + aws-ssl-profiles@1.1.2: resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} engines: {node: '>= 6.0.0'} @@ -589,12 +769,26 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + + class-validator@0.15.1: + resolution: {integrity: sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + cluster-key-slot@1.1.1: + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} + engines: {node: '>=0.10.0'} + confbox@0.2.4: resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -650,6 +844,15 @@ packages: resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} engines: {node: '>=12'} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + deepmerge-ts@7.1.5: resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} engines: {node: '>=16.0.0'} @@ -664,6 +867,10 @@ packages: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -703,16 +910,42 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-json-stringify@7.0.1: + resolution: {integrity: sha512-eRSayARSbbwlBjpP4vnTTIRD5QPcIrmihPxDeN1DtKnHPg66UuJLx+8hlK1kaFdjvzyQ/dzALoi4vwAQ+T+iZA==} + fast-querystring@1.1.2: resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-uri@3.1.6: resolution: {integrity: sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==} + fast-uri@4.1.3: + resolution: {integrity: sha512-7+72G6vLt7jjNas8SmSATx2qeyRIjxeqO3i4IkmDTxlqYZRKANhOe1bnovcp4WZmvsYrp60WyqPyHqgRiX0yXw==} + + fastify-plugin@6.0.0: + resolution: {integrity: sha512-fZOty7z3O7vOliF6d8bHE3wiEh1KcNnKEQensSgTk9C1DvN6nRLS++XVd86v33Hw/8u9Un8A1zDrQ8ujcQDHEg==} + + fastify@5.12.1: + resolution: {integrity: sha512-FWi+tQvwxR/PeRX7Z2mhfEF5ozJ3jn9asiiclzKXNSzJRHAYcU924aIOKAdHFJ+YIKieh3cqr1IwCOvTr41B3Q==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + file-type@22.0.2: + resolution: {integrity: sha512-0H8TsCUGBLx+V5adH3EY52hTAcyLKbV1D4gq5cIOJ6DnQAHeV9Z2Hhuc5CoBX4YmvB2oL+JIC84z0qO7JsCoNw==} + engines: {node: '>=22'} + find-my-way@9.7.0: resolution: {integrity: sha512-f2JHn75x2JlwUwLenZypgczR7YWMb/uO9BvUXtus+JMgkbIkLADd38cI4EiV+OQqrGo1Zlq6V8wnqMJ8e62wUQ==} engines: {node: '>=20'} + find-my-way@9.9.0: + resolution: {integrity: sha512-sJsgZ1sQH2UDuowPuMKg8az7Qc8F0jnj+SKkFWU/+T0xcFlgV5skgXOGUqmQzOdmW6ALA7AhJINWx3qFBkbLHA==} + engines: {node: '>=20'} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -741,20 +974,43 @@ packages: graphmatch@1.1.1: resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} + helmet@8.3.0: + resolution: {integrity: sha512-Qgpiaws3Sm30Av8Eah6sjMCZZwjlBu+E68rhpCWBshY1lb09HtLwj5GviX0OyQIn+ulUS0iX0AxN5n3tLZzz1w==} + engines: {node: '>=18.0.0'} + iconv-lite@0.7.3: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + ioredis@6.0.0: + resolution: {integrity: sha512-f+Dtubxfpf6KYFq7WVXJoOLn0bk4TJrMrN9SzeE+jrWrCWj7XX3fA6vkryafhADX+GMymRxgDJDOI33COkJc0w==} + engines: {node: '>=20.0.0'} + + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} + engines: {node: '>= 12'} + + ipaddr.js@2.5.0: + resolution: {integrity: sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==} + engines: {node: '>= 10'} + is-property@1.0.2: resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true @@ -762,9 +1018,22 @@ packages: jose@6.2.10: resolution: {integrity: sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==} + json-schema-ref-resolver@3.0.0: + resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + libphonenumber-js@1.13.11: + resolution: {integrity: sha512-ETER2kMaIFTI/Nh1a8Gk03dUF/SL0VZqtI+CcVHZxp5WIHYwNS7S+uiYZDYCvLy3lOR4/DAD5jf0h5WkePPpqg==} + + light-my-request@6.6.0: + resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + + load-esm@1.0.3: + resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} + engines: {node: '>=13.2.0'} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -778,6 +1047,9 @@ packages: magicast@0.5.4: resolution: {integrity: sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mysql2@3.15.3: resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} engines: {node: '>= 8.0'} @@ -789,10 +1061,17 @@ packages: ohash@2.0.12: resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -833,6 +1112,16 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true + pkg-types@2.3.1: resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} @@ -873,12 +1162,21 @@ packages: typescript: optional: true + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + + process-warning@5.1.0: + resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} + proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + rc9@3.0.1: resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} @@ -895,6 +1193,20 @@ packages: resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} engines: {node: '>= 20.19.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + real-require@1.0.0: + resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + remeda@2.33.4: resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} @@ -910,22 +1222,47 @@ packages: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-regex2@5.1.1: resolution: {integrity: sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==} hasBin: true + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + seq-queue@0.0.5: resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -941,6 +1278,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -953,9 +1293,31 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + + thread-stream@4.2.0: + resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} + engines: {node: '>=20'} + + toad-cache@3.7.4: + resolution: {integrity: sha512-m1TdR/rvT7kgGJZhspNtXdsdYk0fddFpJJFlG5s+UkPFo6lkLoZ3YLOaovPYjq1R75NP5JfeTlSHaOsE09peCg==} + engines: {node: '>=20'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.23.12: resolution: {integrity: sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==} engines: {node: '>=18.0.0'} @@ -966,6 +1328,17 @@ packages: engines: {node: '>=14.17'} hasBin: true + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} @@ -977,6 +1350,10 @@ packages: typescript: optional: true + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} + engines: {node: '>= 0.10'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1008,6 +1385,8 @@ snapshots: '@babel/helper-validator-identifier': 7.29.7 optional: true + '@borewit/text-codec@0.2.2': {} + '@electric-sql/pglite-socket@0.1.3(@electric-sql/pglite@0.4.3)': dependencies: '@electric-sql/pglite': 0.4.3 @@ -1096,6 +1475,99 @@ snapshots: '@esbuild/win32-x64@0.28.2': optional: true + '@fastify/ajv-compiler@4.0.6': + dependencies: + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + fast-uri: 4.1.3 + + '@fastify/cors@11.3.0': + dependencies: + fastify-plugin: 6.0.0 + toad-cache: 3.7.4 + + '@fastify/error@4.2.0': {} + + '@fastify/fast-json-stringify-compiler@5.1.0': + dependencies: + fast-json-stringify: 7.0.1 + + '@fastify/formbody@9.0.0': + dependencies: + fast-querystring: 1.1.2 + fastify-plugin: 6.0.0 + + '@fastify/forwarded@3.0.2': {} + + '@fastify/helmet@13.1.1': + dependencies: + fastify-plugin: 6.0.0 + helmet: 8.3.0 + + '@fastify/merge-json-schemas@0.2.1': + dependencies: + dequal: 2.0.3 + + '@fastify/proxy-addr@5.1.0': + dependencies: + '@fastify/forwarded': 3.0.2 + ipaddr.js: 2.5.0 + + '@fastify/rate-limit@11.2.0': + dependencies: + '@lukeed/ms': 2.0.2 + fastify-plugin: 6.0.0 + ip-address: 10.5.0 + toad-cache: 3.7.4 + + '@ioredis/commands@2.0.0': {} + + '@lukeed/csprng@1.1.0': {} + + '@lukeed/ms@2.0.2': {} + + '@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@standard-schema/spec': 1.1.0 + file-type: 22.0.2 + iterare: 1.2.1 + load-esm: 1.0.3 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.15.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/core@12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 8.4.2 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + + '@nestjs/platform-fastify@12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2))': + dependencies: + '@fastify/cors': 11.3.0 + '@fastify/formbody': 9.0.0 + '@nestjs/common': 12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 12.0.1(@nestjs/common@12.0.1(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)(rxjs@7.8.2) + fast-querystring: 1.1.2 + fastify: 5.12.1 + fastify-plugin: 6.0.0 + find-my-way: 9.9.0 + light-my-request: 6.6.0 + path-to-regexp: 8.4.2 + reusify: 1.1.0 + tslib: 2.8.1 + '@node-rs/argon2-android-arm-eabi@2.1.0': optional: true @@ -1151,6 +1623,8 @@ snapshots: '@node-rs/argon2-win32-ia32-msvc': 2.1.0 '@node-rs/argon2-win32-x64-msvc': 2.1.0 + '@pinojs/redact@0.4.0': {} + '@prisma/adapter-pg@7.10.0': dependencies: '@prisma/driver-adapter-utils': 7.10.0 @@ -1313,6 +1787,15 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + '@types/d3-array@3.0.3': {} '@types/d3-color@3.1.0': {} @@ -1347,6 +1830,10 @@ snapshots: '@types/lodash@4.17.25': {} + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + '@types/node@26.4.0': dependencies: undici-types: 8.3.0 @@ -1361,6 +1848,8 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/validator@13.15.10': {} + '@visx/curve@4.0.1-alpha.0': dependencies: '@visx/vendor': 4.0.0-alpha.0 @@ -1438,6 +1927,12 @@ snapshots: d3-time-format: 4.1.0 internmap: 2.0.3 + abstract-logging@2.0.1: {} + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 @@ -1445,6 +1940,13 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + atomic-sleep@1.0.0: {} + + avvio@9.3.0: + dependencies: + '@fastify/error': 4.2.0 + fastq: 1.20.1 + aws-ssl-profiles@1.1.2: {} better-result@2.10.0: {} @@ -1470,10 +1972,22 @@ snapshots: dependencies: readdirp: 5.1.1 + class-transformer@0.5.1: {} + + class-validator@0.15.1: + dependencies: + '@types/validator': 13.15.10 + libphonenumber-js: 1.13.11 + validator: 13.15.35 + classnames@2.5.1: {} + cluster-key-slot@1.1.1: {} + confbox@0.2.4: {} + cookie@1.1.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -1528,6 +2042,10 @@ snapshots: dependencies: d3-array: 3.2.4 + debug@4.4.3: + dependencies: + ms: 2.1.3 + deepmerge-ts@7.1.5: {} defu@6.1.7: {} @@ -1538,6 +2056,8 @@ snapshots: denque@2.1.0: {} + dequal@2.0.3: {} + destr@2.0.5: {} dotenv@17.4.2: {} @@ -1592,18 +2112,70 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-json-stringify@7.0.1: + dependencies: + '@fastify/merge-json-schemas': 0.2.1 + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + fast-uri: 4.1.3 + json-schema-ref-resolver: 3.0.0 + rfdc: 1.4.1 + fast-querystring@1.1.2: dependencies: fast-decode-uri-component: 1.0.1 + fast-safe-stringify@2.1.1: {} + fast-uri@3.1.6: {} + fast-uri@4.1.3: {} + + fastify-plugin@6.0.0: {} + + fastify@5.12.1: + dependencies: + '@fastify/ajv-compiler': 4.0.6 + '@fastify/error': 4.2.0 + '@fastify/fast-json-stringify-compiler': 5.1.0 + '@fastify/proxy-addr': 5.1.0 + abstract-logging: 2.0.1 + avvio: 9.3.0 + fast-json-stringify: 7.0.1 + find-my-way: 9.7.0 + light-my-request: 6.6.0 + pino: 10.3.1 + process-warning: 5.1.0 + rfdc: 1.4.1 + secure-json-parse: 4.1.0 + semver: 7.8.5 + toad-cache: 3.7.4 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + file-type@22.0.2: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + find-my-way@9.7.0: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 safe-regex2: 5.1.1 + find-my-way@9.9.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 5.1.1 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -1626,22 +2198,57 @@ snapshots: graphmatch@1.1.1: {} + helmet@8.3.0: {} + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + internmap@2.0.3: {} + ioredis@6.0.0: + dependencies: + '@ioredis/commands': 2.0.0 + cluster-key-slot: 1.1.1 + debug: 4.4.3 + denque: 2.1.0 + redis-errors: 1.2.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + ip-address@10.5.0: {} + + ipaddr.js@2.5.0: {} + is-property@1.0.2: {} isexe@2.0.0: {} + iterare@1.2.1: {} + jiti@2.7.0: {} jose@6.2.10: {} + json-schema-ref-resolver@3.0.0: + dependencies: + dequal: 2.0.3 + json-schema-traverse@1.0.0: {} + libphonenumber-js@1.13.11: {} + + light-my-request@6.6.0: + dependencies: + cookie: 1.1.1 + process-warning: 4.0.1 + set-cookie-parser: 2.7.2 + + load-esm@1.0.3: {} + lodash@4.17.21: {} long@5.3.2: {} @@ -1655,6 +2262,8 @@ snapshots: source-map-js: 1.2.1 optional: true + ms@2.1.3: {} + mysql2@3.15.3: dependencies: aws-ssl-profiles: 1.1.2 @@ -1673,8 +2282,12 @@ snapshots: ohash@2.0.12: {} + on-exit-leak-free@2.1.2: {} + path-key@3.1.1: {} + path-to-regexp@8.4.2: {} + pathe@2.0.3: {} perfect-debounce@2.1.0: {} @@ -1714,6 +2327,26 @@ snapshots: dependencies: split2: 4.2.0 + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.1.0: {} + + pino@10.3.1: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.1.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.2.0 + pkg-types@2.3.1: dependencies: confbox: 0.2.4 @@ -1751,6 +2384,10 @@ snapshots: - react - react-dom + process-warning@4.0.1: {} + + process-warning@5.1.0: {} + proper-lockfile@4.1.2: dependencies: graceful-fs: 4.2.11 @@ -1759,6 +2396,8 @@ snapshots: pure-rand@6.1.0: {} + quick-format-unescaped@4.0.4: {} + rc9@3.0.1: dependencies: defu: 6.1.7 @@ -1773,6 +2412,14 @@ snapshots: readdirp@5.1.1: {} + real-require@0.2.0: {} + + real-require@1.0.0: {} + + redis-errors@1.2.0: {} + + reflect-metadata@0.2.2: {} + remeda@2.33.4: {} require-from-string@2.0.2: {} @@ -1781,18 +2428,34 @@ snapshots: retry@0.12.0: {} + reusify@1.1.0: {} + + rfdc@1.4.1: {} + robust-predicates@3.0.3: {} + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-regex2@5.1.1: dependencies: ret: 0.5.0 + safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: {} scheduler@0.27.0: {} + secure-json-parse@4.1.0: {} + + semver@7.8.5: {} + seq-queue@0.0.5: {} + set-cookie-parser@2.7.2: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -1803,6 +2466,10 @@ snapshots: signal-exit@4.1.0: {} + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: optional: true @@ -1810,8 +2477,28 @@ snapshots: sqlstring@2.3.3: {} + standard-as-callback@2.1.0: {} + std-env@3.10.0: {} + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + + thread-stream@4.2.0: + dependencies: + real-require: 1.0.0 + + toad-cache@3.7.4: {} + + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tslib@2.8.1: {} + tsx@4.23.12: dependencies: esbuild: 0.28.2 @@ -1820,12 +2507,22 @@ snapshots: typescript@5.9.3: {} + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + + uint8array-extras@1.5.0: {} + + undici-types@6.21.0: {} + undici-types@8.3.0: {} valibot@1.4.2(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 + validator@13.15.35: {} + which@2.0.2: dependencies: isexe: 2.0.0