Add operational Resellers module (MVP CRUD, eden.md §1.7/§7)

Migration 1788439142825_resellers.cjs: `resellers` table plus nullable
`users.reseller_id` (scope=reseller per ADR-0004), indexes on
resellers.active and users.reseller_id.

packages/database/src/repositories/resellers.ts: list/get/create/update,
COALESCE-based partial update, mirroring the companies repository
pattern. Also adds repositories/audit.ts (hash-chained appendAuditEvent
over the existing audit_log table) and repositories/users.ts
(assignUserToReseller) - foundational pieces this module depends on that
hadn't landed in this worktree yet; audit.ts mirrors the sibling
worktree's already-built implementation verbatim to minimize merge
friction, and users.ts intentionally contains only the one function the
task asked to append (the fuller users repository belongs to the
auth/identity module being built in parallel).

apps/api/src/resellers/*: controller/service/module/dto mirroring the
Companies module's conventions - read open to any authenticated user,
write gated by @RequirePermission('resellers', 'edit'). Deliberate
deviation from legacy noted in code comments: the legacy hardcoded this
CRUD to requireAdmin and exposed reseller<->user assignment as
`PATCH /users/:id`; EDEN generalizes to the permission model (ADR-0004)
and adds `PATCH /v1/resellers/:id/assign-user` instead. Audits
reseller.created / reseller.updated / reseller.user_assigned.

packages/domain-shared/src/validators/br-documents.ts: CPF/CNPJ
digit-check validators (mirrors the sibling worktree's implementation
verbatim), used for the reseller `document` field the same way Companies
validates cnpj.

Known integration gap (by design, not a bug in this module): this
worktree doesn't yet have apps/api/src/auth/* or the companies-phase
exports in packages/database/src/index.ts - both are being built in
sibling worktrees and are explicitly out of scope here (per the task's
boundaries, app.module.ts and packages/database/src/index.ts are left
untouched for the user to wire up at merge time). @eden/database
typecheck/build pass cleanly; @eden/api typecheck/build currently fail
with exactly ten "cannot find module ../auth/..." /
"no exported member resellersRepo/usersRepo/auditRepo/Reseller" errors,
all attributable to those two integration points and nothing else.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 09:44:45 -03:00
parent 44510bd019
commit dca6eb2766
15 changed files with 653 additions and 14 deletions

View File

@@ -12,10 +12,14 @@
}, },
"dependencies": { "dependencies": {
"@eden/database": "workspace:*", "@eden/database": "workspace:*",
"@eden/domain-shared": "workspace:*",
"@nestjs/common": "^10.4.15", "@nestjs/common": "^10.4.15",
"@nestjs/core": "^10.4.15", "@nestjs/core": "^10.4.15",
"@nestjs/platform-express": "^10.4.15", "@nestjs/platform-express": "^10.4.15",
"@nestjs/swagger": "^8.1.0",
"@nestjs/terminus": "^10.2.3", "@nestjs/terminus": "^10.2.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"express": "^4.21.2", "express": "^4.21.2",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1" "rxjs": "^7.8.1"

View File

@@ -0,0 +1,15 @@
import { IsUUID, ValidateIf } from "class-validator";
/**
* `resellerId` is required-but-nullable (unassign is expressed as an
* explicit `null`, not by omitting the field) — @ValidateIf lets a null
* value through while still requiring a valid UUID whenever it's present.
*/
export class AssignUserToResellerDto {
@IsUUID()
userId!: string;
@ValidateIf((_object, value) => value !== null)
@IsUUID()
resellerId!: string | null;
}

View File

@@ -0,0 +1,11 @@
import { IsBoolean, IsEmail, IsOptional, IsString, MinLength } from "class-validator";
export class CreateResellerDto {
@IsString()
@MinLength(1)
name!: string;
@IsOptional() @IsString() document?: string;
@IsOptional() @IsEmail() contactEmail?: string;
@IsOptional() @IsBoolean() active?: boolean;
}

View File

@@ -0,0 +1,4 @@
import { PartialType } from "@nestjs/swagger";
import { CreateResellerDto } from "./create-reseller.dto.js";
export class UpdateResellerDto extends PartialType(CreateResellerDto) {}

View File

@@ -0,0 +1,82 @@
import { Body, Controller, Get, Param, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
import { ResellersService } from "./resellers.service.js";
import { CreateResellerDto } from "./dto/create-reseller.dto.js";
import { UpdateResellerDto } from "./dto/update-reseller.dto.js";
import { AssignUserToResellerDto } from "./dto/assign-user-to-reseller.dto.js";
import { JwtAuthGuard } from "../auth/jwt-auth.guard.js";
import { PermissionGuard } from "../auth/permission.guard.js";
import { RequirePermission } from "../auth/decorators/require-permission.decorator.js";
import { CurrentUser } from "../auth/decorators/current-user.decorator.js";
import type { EdenAuthenticatedUser } from "../auth/jwt-auth.guard.js";
/**
* Operational reseller CRUD (eden.md §1.7, §7) — MVP scope only. The full
* "Programa de Canais" approval workflow with public tokens (eden.md §6)
* is a separate, later phase and isn't touched here.
*
* Read is open to any authenticated user (no @RequirePermission) —
* mirrors Companies: needed for reseller-selector dropdowns elsewhere
* (e.g. Orçamentos, cadastro de usuário) and isn't sensitive data.
* Write requires `resellers:edit`.
*
* Deliberate deviation from legacy, noted per eden-commercial rules:
* the legacy (`resellers.routes.js`, eden.md §7) hardcoded this whole
* CRUD to `requireAdmin` (a role check — admin/super_admin only,
* stricter than the revenda cadastro/aprovação feature). EDEN
* generalizes that role check to the resource+action+scope permission
* model (docs/adr/0004-permission-model.md) instead, so a role can be
* granted `resellers:edit` without needing the full `admin` role.
*/
@ApiTags("resellers")
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, PermissionGuard)
@Controller("v1/resellers")
export class ResellersController {
constructor(private readonly resellers: ResellersService) {}
@Get()
list(@Query("includeInactive") includeInactive?: string) {
return this.resellers.list(includeInactive === "true");
}
@Get(":id")
get(@Param("id") id: string) {
return this.resellers.get(id);
}
@Post()
@RequirePermission("resellers", "edit")
create(@Body() dto: CreateResellerDto, @CurrentUser() user: EdenAuthenticatedUser) {
return this.resellers.create(dto, user.id);
}
@Patch(":id")
@RequirePermission("resellers", "edit")
update(
@Param("id") id: string,
@Body() dto: UpdateResellerDto,
@CurrentUser() user: EdenAuthenticatedUser,
) {
return this.resellers.update(id, dto, user.id);
}
/**
* Legacy (eden.md §7) exposed reseller↔user assignment as a
* users-domain route: `PATCH /users/:id { reseller_id }`. EDEN
* deliberately places the same operation here instead — documented
* deviation — so it stays gated by `resellers:edit` (matching the
* legacy's `requireAdmin` scope for this screen) rather than needing a
* separate `users:edit` grant just to manage a reseller's roster from
* the Resellers screen.
*/
@Patch(":id/assign-user")
@RequirePermission("resellers", "edit")
assignUser(
@Param("id") id: string,
@Body() dto: AssignUserToResellerDto,
@CurrentUser() user: EdenAuthenticatedUser,
) {
return this.resellers.assignUser(id, dto, user.id);
}
}

View File

@@ -0,0 +1,11 @@
import { Module } from "@nestjs/common";
import { AuthModule } from "../auth/auth.module.js";
import { ResellersController } from "./resellers.controller.js";
import { ResellersService } from "./resellers.service.js";
@Module({
imports: [AuthModule],
controllers: [ResellersController],
providers: [ResellersService],
})
export class ResellersModule {}

View File

@@ -0,0 +1,101 @@
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
import { resellersRepo, usersRepo, auditRepo, type Reseller } from "@eden/database";
import { onlyDigits, isValidCPF, isValidCNPJ } from "@eden/domain-shared";
import type { CreateResellerDto } from "./dto/create-reseller.dto.js";
import type { UpdateResellerDto } from "./dto/update-reseller.dto.js";
import type { AssignUserToResellerDto } from "./dto/assign-user-to-reseller.dto.js";
@Injectable()
export class ResellersService {
list(includeInactive: boolean): Promise<Reseller[]> {
return resellersRepo.listResellers(includeInactive);
}
async get(id: string): Promise<Reseller> {
const reseller = await resellersRepo.getResellerById(id);
if (!reseller) throw new NotFoundException("Revenda não encontrada");
return reseller;
}
async create(dto: CreateResellerDto, actorId: string): Promise<Reseller> {
this.assertValidDocumentIfPresent(dto.document);
const reseller = await resellersRepo.createReseller({
name: dto.name,
document: dto.document ? onlyDigits(dto.document) : undefined,
contactEmail: dto.contactEmail,
active: dto.active,
createdBy: actorId,
});
await auditRepo.appendAuditEvent({
actorType: "user",
actorId,
action: "reseller.created",
resourceType: "reseller",
resourceId: reseller.id,
});
return reseller;
}
async update(id: string, dto: UpdateResellerDto, actorId: string): Promise<Reseller> {
await this.get(id); // 404 if missing
this.assertValidDocumentIfPresent(dto.document);
const reseller = await resellersRepo.updateReseller(id, {
name: dto.name,
document: dto.document ? onlyDigits(dto.document) : undefined,
contactEmail: dto.contactEmail,
active: dto.active,
});
if (!reseller) throw new NotFoundException("Revenda não encontrada");
await auditRepo.appendAuditEvent({
actorType: "user",
actorId,
action: "reseller.updated",
resourceType: "reseller",
resourceId: id,
metadata: { fields: Object.keys(dto) },
});
return reseller;
}
async assignUser(
id: string,
dto: AssignUserToResellerDto,
actorId: string,
): Promise<{ userId: string; resellerId: string | null }> {
await this.get(id); // 404 if the reseller in the URL doesn't exist
if (dto.resellerId !== null && dto.resellerId !== id) {
await this.get(dto.resellerId); // 404 if a different target reseller doesn't exist
}
const found = await usersRepo.assignUserToReseller(dto.userId, dto.resellerId);
if (!found) throw new NotFoundException("Usuário não encontrado");
await auditRepo.appendAuditEvent({
actorType: "user",
actorId,
action: "reseller.user_assigned",
resourceType: "user",
resourceId: dto.userId,
metadata: { resellerId: dto.resellerId },
});
return { userId: dto.userId, resellerId: dto.resellerId };
}
/** Mirrors Companies' assertValidCnpjIfPresent — document is CPF or CNPJ here. */
private assertValidDocumentIfPresent(document: string | undefined): void {
if (!document) return;
const digits = onlyDigits(document);
const valid =
digits.length === 11 ? isValidCPF(digits) : digits.length === 14 ? isValidCNPJ(digits) : false;
if (!valid) {
throw new BadRequestException("CPF/CNPJ inválido");
}
}
}

View File

@@ -0,0 +1,59 @@
/**
* Commercial bounded context, first slice: `resellers` — the operational
* reseller/partner registry (eden.md §1.7). Pre-dates the "Programa de
* Canais" approval workflow with public tokens described in eden.md §6 —
* that workflow (client_registrations/reseller_registrations, public
* approval tokens) is explicitly out of scope for this migration and
* lands in its own later phase. This is just the simple operational CRUD
* table eden.md §1.7 describes, already referenced by `quotes.reseller_id`
* conceptually (quotes themselves aren't modeled yet either — Commercial
* phase lands module by module).
*
* Also adds `users.reseller_id` (nullable) — how a user gets scoped to a
* reseller, per eden.md §7 and the `scope=reseller` permission model
* (docs/adr/0004-permission-model.md). Lives in this migration rather
* than a separate one so the FK to `resellers(id)` can be added in the
* same statement the table is created in, without a two-step migration.
*/
exports.shorthands = undefined;
exports.up = (pgm) => {
pgm.sql(`
CREATE TABLE resellers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by UUID REFERENCES users(id),
name TEXT NOT NULL,
document TEXT,
contact_email TEXT,
active BOOLEAN NOT NULL DEFAULT true
);
COMMENT ON TABLE resellers IS
'Cadastro operacional de revenda — eden.md §1.7. document é CPF/CNPJ livre (sem CHECK de dígito no banco, validado na camada de aplicação, igual companies.cnpj). Leitura aberta a qualquer autenticado (usado em seletores, ex. Orçamentos); escrita restrita à permissão resellers:edit.';
CREATE TRIGGER trg_resellers_updated_at BEFORE UPDATE ON resellers
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE INDEX idx_resellers_active ON resellers(active);
-- =====================================================================
-- users.reseller_id — scopes a user to a reseller (eden.md §7,
-- docs/adr/0004-permission-model.md scope=reseller)
-- =====================================================================
ALTER TABLE users ADD COLUMN reseller_id UUID REFERENCES resellers(id);
COMMENT ON COLUMN users.reseller_id IS
'Nullable — vincula o usuário a uma revenda (vendedor de revenda), escopando o que ele vê (eden.md §7). Atribuído via PATCH /v1/resellers/:id/assign-user, nunca aceito de campo vindo do cliente para decisão de autorização (docs/architecture.md, ADR-0004).';
CREATE INDEX idx_users_reseller ON users(reseller_id);
`);
};
exports.down = (pgm) => {
pgm.sql(`
DROP INDEX IF EXISTS idx_users_reseller;
ALTER TABLE users DROP COLUMN IF EXISTS reseller_id;
DROP TABLE IF EXISTS resellers;
`);
};

View File

@@ -0,0 +1,66 @@
import { createHash } from "node:crypto";
import { query } from "../pool.js";
export interface AuditEventInput {
actorType: "user" | "system" | "service";
actorId?: string | null;
action: string;
resourceType: string;
resourceId?: string | null;
metadata?: Record<string, unknown>;
ipAddress?: string | null;
}
function canonicalJson(value: unknown): string {
if (value === null || typeof value !== "object") return JSON.stringify(value);
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
const obj = value as Record<string, unknown>;
const keys = Object.keys(obj).sort();
return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`).join(",")}}`;
}
/**
* Appends one event to the audit_log hash chain (see baseline-schema
* migration and .claude/skills/eden-security/references/audit.md). Never
* call this inside a larger transaction that might roll back for
* unrelated reasons without considering that the chain must stay
* contiguous — a rolled-back event never happened (fine, nothing was
* recorded), but a *committed* event must never be skipped when
* computing previous_event_hash for the next one.
*/
export async function appendAuditEvent(input: AuditEventInput): Promise<void> {
const { rows } = await query<{ event_hash: string }>(
"SELECT event_hash FROM audit_log ORDER BY seq DESC LIMIT 1",
);
const previousEventHash = rows[0]?.event_hash ?? "";
const fields = {
actorType: input.actorType,
actorId: input.actorId ?? null,
action: input.action,
resourceType: input.resourceType,
resourceId: input.resourceId ?? null,
metadata: input.metadata ?? {},
ipAddress: input.ipAddress ?? null,
};
const eventHash = createHash("sha256")
.update(previousEventHash + canonicalJson(fields))
.digest("hex");
await query(
`INSERT INTO audit_log
(actor_type, actor_id, action, resource_type, resource_id, metadata, ip_address, previous_event_hash, event_hash)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
[
input.actorType,
input.actorId ?? null,
input.action,
input.resourceType,
input.resourceId ?? null,
JSON.stringify(input.metadata ?? {}),
input.ipAddress ?? null,
previousEventHash || null,
eventHash,
],
);
}

View File

@@ -0,0 +1,71 @@
import { query } from "../pool.js";
export interface Reseller {
id: string;
created_at: Date;
updated_at: Date;
created_by: string | null;
name: string;
document: string | null;
contact_email: string | null;
active: boolean;
}
export async function listResellers(includeInactive = false): Promise<Reseller[]> {
const { rows } = await query<Reseller>(
includeInactive
? "SELECT * FROM resellers ORDER BY created_at ASC"
: "SELECT * FROM resellers WHERE active = true ORDER BY created_at ASC",
);
return rows;
}
export async function getResellerById(id: string): Promise<Reseller | null> {
const { rows } = await query<Reseller>("SELECT * FROM resellers WHERE id = $1", [id]);
return rows[0] ?? null;
}
export interface CreateResellerInput {
name: string;
document?: string | null;
contactEmail?: string | null;
active?: boolean;
createdBy?: string | null;
}
export async function createReseller(input: CreateResellerInput): Promise<Reseller> {
const { rows } = await query<Reseller>(
`INSERT INTO resellers (name, document, contact_email, active, created_by)
VALUES ($1, $2, $3, COALESCE($4, true), $5)
RETURNING *`,
[
input.name,
input.document ?? null,
input.contactEmail ?? null,
input.active ?? null,
input.createdBy ?? null,
],
);
const reseller = rows[0];
if (!reseller) throw new Error("failed to create reseller");
return reseller;
}
export type UpdateResellerInput = Partial<Omit<CreateResellerInput, "createdBy">>;
export async function updateReseller(
id: string,
input: UpdateResellerInput,
): Promise<Reseller | null> {
const { rows } = await query<Reseller>(
`UPDATE resellers SET
name = COALESCE($2, name),
document = COALESCE($3, document),
contact_email = COALESCE($4, contact_email),
active = COALESCE($5, active)
WHERE id = $1
RETURNING *`,
[id, input.name ?? null, input.document ?? null, input.contactEmail ?? null, input.active ?? null],
);
return rows[0] ?? null;
}

View File

@@ -0,0 +1,30 @@
import { query } from "../pool.js";
/**
* NOTE: at the time this file was created, the fuller `users` repository
* (createUser, findUserByEmail, findUserById, etc. — identity/auth
* bounded context) hadn't landed in this worktree yet, since it's being
* built in parallel by another agent. Per the resellers-module task
* spec this function was meant to be appended to the end of that
* existing file rather than living in a file of its own — do that at
* merge time; this file's only reason to exist standalone right now is
* that the one it was supposed to be appended to didn't exist here.
*/
/**
* Reseller-scoping: sets or clears which reseller a user belongs to
* (`users.reseller_id`, nullable — eden.md §1.7, §7). Resolved and
* enforced server-side only; callers must never accept `reseller_id`
* from client input for authorization decisions (docs/adr/0004,
* docs/architecture.md).
*/
export async function assignUserToReseller(
userId: string,
resellerId: string | null,
): Promise<boolean> {
const { rowCount } = await query("UPDATE users SET reseller_id = $2 WHERE id = $1", [
userId,
resellerId,
]);
return (rowCount ?? 0) > 0;
}

View File

@@ -5,3 +5,4 @@
* bounded context needs to share a type with the first. * bounded context needs to share a type with the first.
*/ */
export const DOMAIN_SHARED_PACKAGE_VERSION = "0.1.0"; export const DOMAIN_SHARED_PACKAGE_VERSION = "0.1.0";
export { onlyDigits, isValidCPF, isValidCNPJ } from "./validators/br-documents.js";

View File

@@ -0,0 +1,50 @@
/**
* CPF/CNPJ format validation (digit-check only — never confirms a document
* actually exists or belongs to whoever claims it). Ported from the
* standard Brazilian algorithm, matching the legacy's isValidCPF/
* isValidCNPJ (eden.md §1 companies, §3 client registration, §1.7
* resellers).
*/
export function onlyDigits(value: string): string {
return value.replace(/\D/g, "");
}
export function isValidCPF(value: string): boolean {
const cpf = onlyDigits(value);
if (cpf.length !== 11 || /^(\d)\1{10}$/.test(cpf)) return false;
const digits = cpf.split("").map(Number);
const checkDigit = (length: number): number => {
let sum = 0;
for (let i = 0; i < length; i++) {
sum += digits[i]! * (length + 1 - i);
}
const remainder = (sum * 10) % 11;
return remainder === 10 ? 0 : remainder;
};
return checkDigit(9) === digits[9] && checkDigit(10) === digits[10];
}
export function isValidCNPJ(value: string): boolean {
const cnpj = onlyDigits(value);
if (cnpj.length !== 14 || /^(\d)\1{13}$/.test(cnpj)) return false;
const digits = cnpj.split("").map(Number);
// Standard CNPJ weight sequences — the second is the first with a
// leading 6, not a generic slice (easy to get subtly wrong otherwise).
const WEIGHTS_12 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const WEIGHTS_13 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const checkDigit = (length: number, weights: number[]): number => {
let sum = 0;
for (let i = 0; i < length; i++) {
sum += digits[i]! * weights[i]!;
}
const remainder = sum % 11;
return remainder < 2 ? 0 : 11 - remainder;
};
return (
checkDigit(12, WEIGHTS_12) === digits[12] && checkDigit(13, WEIGHTS_13) === digits[13]
);
}

161
pnpm-lock.yaml generated
View File

@@ -20,18 +20,30 @@ importers:
'@eden/database': '@eden/database':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/database version: link:../../packages/database
'@eden/domain-shared':
specifier: workspace:*
version: link:../../packages/domain-shared
'@nestjs/common': '@nestjs/common':
specifier: ^10.4.15 specifier: ^10.4.15
version: 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0) version: 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)
'@nestjs/core': '@nestjs/core':
specifier: ^10.4.15 specifier: ^10.4.15
version: 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/platform-express': '@nestjs/platform-express':
specifier: ^10.4.15 specifier: ^10.4.15
version: 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(supports-color@7.2.0) version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(supports-color@7.2.0)
'@nestjs/swagger':
specifier: ^8.1.0
version: 8.1.1(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)
'@nestjs/terminus': '@nestjs/terminus':
specifier: ^10.2.3 specifier: ^10.2.3
version: 10.3.0(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) version: 10.3.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)
class-transformer:
specifier: ^0.5.1
version: 0.5.1
class-validator:
specifier: ^0.14.1
version: 0.14.4
express: express:
specifier: ^4.21.2 specifier: ^4.21.2
version: 4.22.2(supports-color@7.2.0) version: 4.22.2(supports-color@7.2.0)
@@ -672,6 +684,9 @@ packages:
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
engines: {node: '>=8'} engines: {node: '>=8'}
'@microsoft/tsdoc@0.15.1':
resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
'@napi-rs/lzma-linux-x64-gnu@1.5.1': '@napi-rs/lzma-linux-x64-gnu@1.5.1':
resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==}
engines: {node: ^22.20 || ^24.12 || >=25} engines: {node: ^22.20 || ^24.12 || >=25}
@@ -709,12 +724,42 @@ packages:
'@nestjs/websockets': '@nestjs/websockets':
optional: true optional: true
'@nestjs/mapped-types@2.0.6':
resolution: {integrity: sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==}
peerDependencies:
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
class-transformer: ^0.4.0 || ^0.5.0
class-validator: ^0.13.0 || ^0.14.0
reflect-metadata: ^0.1.12 || ^0.2.0
peerDependenciesMeta:
class-transformer:
optional: true
class-validator:
optional: true
'@nestjs/platform-express@10.4.22': '@nestjs/platform-express@10.4.22':
resolution: {integrity: sha512-ySSq7Py/DFozzZdNDH67m/vHoeVdphDniWBnl6q5QVoXldDdrZIHLXLRMPayTDh5A95nt7jjJzmD4qpTbNQ6tA==} resolution: {integrity: sha512-ySSq7Py/DFozzZdNDH67m/vHoeVdphDniWBnl6q5QVoXldDdrZIHLXLRMPayTDh5A95nt7jjJzmD4qpTbNQ6tA==}
peerDependencies: peerDependencies:
'@nestjs/common': ^10.0.0 '@nestjs/common': ^10.0.0
'@nestjs/core': ^10.0.0 '@nestjs/core': ^10.0.0
'@nestjs/swagger@8.1.1':
resolution: {integrity: sha512-5Mda7H1DKnhKtlsb0C7PYshcvILv8UFyUotHzxmWh0G65Z21R3LZH/J8wmpnlzL4bmXIfr42YwbEwRxgzpJ5sQ==}
peerDependencies:
'@fastify/static': ^6.0.0 || ^7.0.0
'@nestjs/common': ^9.0.0 || ^10.0.0
'@nestjs/core': ^9.0.0 || ^10.0.0
class-transformer: '*'
class-validator: '*'
reflect-metadata: ^0.1.12 || ^0.2.0
peerDependenciesMeta:
'@fastify/static':
optional: true
class-transformer:
optional: true
class-validator:
optional: true
'@nestjs/terminus@10.3.0': '@nestjs/terminus@10.3.0':
resolution: {integrity: sha512-vOJGCwt1OgrFuuxWQwPoaHqy9m9CfIk2qMUX2mosZLK5dFVJSEjHXrklkh3/Fw9PiUnfzvYFfiAdJRzUaxx+5Q==} resolution: {integrity: sha512-vOJGCwt1OgrFuuxWQwPoaHqy9m9CfIk2qMUX2mosZLK5dFVJSEjHXrklkh3/Fw9PiUnfzvYFfiAdJRzUaxx+5Q==}
peerDependencies: peerDependencies:
@@ -921,6 +966,9 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@scarf/scarf@1.4.0':
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
'@tokenizer/inflate@0.2.7': '@tokenizer/inflate@0.2.7':
resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==} resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -1017,6 +1065,9 @@ packages:
'@types/serve-static@2.2.0': '@types/serve-static@2.2.0':
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
'@types/validator@13.15.10':
resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==}
'@vitejs/plugin-react@4.7.0': '@vitejs/plugin-react@4.7.0':
resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
@@ -1051,6 +1102,9 @@ packages:
arg@5.0.2: arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
array-flatten@1.1.1: array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@@ -1141,6 +1195,12 @@ packages:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'} engines: {node: '>= 8.10.0'}
class-transformer@0.5.1:
resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==}
class-validator@0.14.4:
resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==}
cli-boxes@2.2.1: cli-boxes@2.2.1:
resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -1453,6 +1513,10 @@ packages:
js-tokens@4.0.0: js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
jsesc@3.1.0: jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -1463,6 +1527,9 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
hasBin: true hasBin: true
libphonenumber-js@1.13.12:
resolution: {integrity: sha512-uLVeV1c9OTk6qkdqnj+mpMD+ZdnZ0szVyWu58HwMmpwkHA1gCEkyjd3veZQXDnuw9KEwSRjcc9B1pS9XKIN1fA==}
lilconfig@3.1.3: lilconfig@3.1.3:
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'} engines: {node: '>=14'}
@@ -1470,6 +1537,9 @@ packages:
lines-and-columns@1.2.4: lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
loose-envify@1.4.0: loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true hasBin: true
@@ -1904,6 +1974,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
swagger-ui-dist@5.18.2:
resolution: {integrity: sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==}
tailwindcss@3.4.19: tailwindcss@3.4.19:
resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@@ -1994,6 +2067,10 @@ packages:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'} engines: {node: '>= 0.4.0'}
validator@13.15.35:
resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==}
engines: {node: '>= 0.10'}
vary@1.1.2: vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -2373,10 +2450,12 @@ snapshots:
'@lukeed/csprng@1.1.0': {} '@lukeed/csprng@1.1.0': {}
'@microsoft/tsdoc@0.15.1': {}
'@napi-rs/lzma-linux-x64-gnu@1.5.1': '@napi-rs/lzma-linux-x64-gnu@1.5.1':
optional: true optional: true
'@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)': '@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)':
dependencies: dependencies:
file-type: 20.4.1(supports-color@7.2.0) file-type: 20.4.1(supports-color@7.2.0)
iterare: 1.2.1 iterare: 1.2.1
@@ -2384,12 +2463,15 @@ snapshots:
rxjs: 7.8.2 rxjs: 7.8.2
tslib: 2.8.1 tslib: 2.8.1
uid: 2.0.2 uid: 2.0.2
optionalDependencies:
class-transformer: 0.5.1
class-validator: 0.14.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@nestjs/core@10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)': '@nestjs/core@10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)':
dependencies: dependencies:
'@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0) '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)
'@nuxtjs/opencollective': 0.3.2 '@nuxtjs/opencollective': 0.3.2
fast-safe-stringify: 2.1.1 fast-safe-stringify: 2.1.1
iterare: 1.2.1 iterare: 1.2.1
@@ -2399,14 +2481,22 @@ snapshots:
tslib: 2.8.1 tslib: 2.8.1
uid: 2.0.2 uid: 2.0.2
optionalDependencies: optionalDependencies:
'@nestjs/platform-express': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(supports-color@7.2.0) '@nestjs/platform-express': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(supports-color@7.2.0)
transitivePeerDependencies: transitivePeerDependencies:
- encoding - encoding
'@nestjs/platform-express@10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(supports-color@7.2.0)': '@nestjs/mapped-types@2.0.6(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)':
dependencies: dependencies:
'@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0) '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)
'@nestjs/core': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2
optionalDependencies:
class-transformer: 0.5.1
class-validator: 0.14.4
'@nestjs/platform-express@10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(supports-color@7.2.0)':
dependencies:
'@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)
'@nestjs/core': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)
body-parser: 1.20.4(supports-color@7.2.0) body-parser: 1.20.4(supports-color@7.2.0)
cors: 2.8.5 cors: 2.8.5
express: 4.22.1(supports-color@7.2.0) express: 4.22.1(supports-color@7.2.0)
@@ -2415,10 +2505,25 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@nestjs/terminus@10.3.0(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)': '@nestjs/swagger@8.1.1(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)':
dependencies: dependencies:
'@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0) '@microsoft/tsdoc': 0.15.1
'@nestjs/core': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)
'@nestjs/core': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/mapped-types': 2.0.6(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)
js-yaml: 4.1.0
lodash: 4.17.21
path-to-regexp: 3.3.0
reflect-metadata: 0.2.2
swagger-ui-dist: 5.18.2
optionalDependencies:
class-transformer: 0.5.1
class-validator: 0.14.4
'@nestjs/terminus@10.3.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/core@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)':
dependencies:
'@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0)
'@nestjs/core': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)(supports-color@7.2.0))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)
boxen: 5.1.2 boxen: 5.1.2
check-disk-space: 3.4.0 check-disk-space: 3.4.0
reflect-metadata: 0.2.2 reflect-metadata: 0.2.2
@@ -2521,6 +2626,8 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.63.1': '@rollup/rollup-win32-x64-msvc@4.63.1':
optional: true optional: true
'@scarf/scarf@1.4.0': {}
'@tokenizer/inflate@0.2.7(supports-color@7.2.0)': '@tokenizer/inflate@0.2.7(supports-color@7.2.0)':
dependencies: dependencies:
debug: 4.4.3(supports-color@7.2.0) debug: 4.4.3(supports-color@7.2.0)
@@ -2630,6 +2737,8 @@ snapshots:
'@types/http-errors': 2.0.5 '@types/http-errors': 2.0.5
'@types/node': 22.20.1 '@types/node': 22.20.1
'@types/validator@13.15.10': {}
'@vitejs/plugin-react@4.7.0(supports-color@7.2.0)(vite@6.4.3(@types/node@22.20.1)(jiti@1.21.7)(tsx@4.23.13))': '@vitejs/plugin-react@4.7.0(supports-color@7.2.0)(vite@6.4.3(@types/node@22.20.1)(jiti@1.21.7)(tsx@4.23.13))':
dependencies: dependencies:
'@babel/core': 7.29.7(supports-color@7.2.0) '@babel/core': 7.29.7(supports-color@7.2.0)
@@ -2668,6 +2777,8 @@ snapshots:
arg@5.0.2: {} arg@5.0.2: {}
argparse@2.0.1: {}
array-flatten@1.1.1: {} array-flatten@1.1.1: {}
autoprefixer@10.5.4(postcss@8.5.26): autoprefixer@10.5.4(postcss@8.5.26):
@@ -2789,6 +2900,14 @@ snapshots:
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
class-transformer@0.5.1: {}
class-validator@0.14.4:
dependencies:
'@types/validator': 13.15.10
libphonenumber-js: 1.13.12
validator: 13.15.35
cli-boxes@2.2.1: {} cli-boxes@2.2.1: {}
cliui@8.0.1: cliui@8.0.1:
@@ -3177,14 +3296,22 @@ snapshots:
js-tokens@4.0.0: {} js-tokens@4.0.0: {}
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
jsesc@3.1.0: {} jsesc@3.1.0: {}
json5@2.2.3: {} json5@2.2.3: {}
libphonenumber-js@1.13.12: {}
lilconfig@3.1.3: {} lilconfig@3.1.3: {}
lines-and-columns@1.2.4: {} lines-and-columns@1.2.4: {}
lodash@4.17.21: {}
loose-envify@1.4.0: loose-envify@1.4.0:
dependencies: dependencies:
js-tokens: 4.0.0 js-tokens: 4.0.0
@@ -3607,6 +3734,10 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
swagger-ui-dist@5.18.2:
dependencies:
'@scarf/scarf': 1.4.0
tailwindcss@3.4.19(tsx@4.23.13): tailwindcss@3.4.19(tsx@4.23.13):
dependencies: dependencies:
'@alloc/quick-lru': 5.3.0 '@alloc/quick-lru': 5.3.0
@@ -3712,6 +3843,8 @@ snapshots:
utils-merge@1.0.1: {} utils-merge@1.0.1: {}
validator@13.15.35: {}
vary@1.1.2: {} vary@1.1.2: {}
vite@6.4.3(@types/node@22.20.1)(jiti@1.21.7)(tsx@4.23.13): vite@6.4.3(@types/node@22.20.1)(jiti@1.21.7)(tsx@4.23.13):

View File

@@ -3,4 +3,5 @@ packages:
- "packages/*" - "packages/*"
allowBuilds: allowBuilds:
'@nestjs/core': true '@nestjs/core': true
'@scarf/scarf': false
esbuild: true esbuild: true