From cdafb7f853921fe59400696566042d19fb155eb2 Mon Sep 17 00:00:00 2001 From: "Matheus (Handix)" Date: Thu, 3 Sep 2026 11:14:43 -0300 Subject: [PATCH] test(api): add Vitest+supertest integration test suite (eden-qa) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boots the real Nest app (Test.createTestingModule + AppModule) against a real Postgres — no mocked DB or guards anywhere in this suite. Uses SWC (unplugin-swc) instead of Vite's default esbuild transform because esbuild doesn't implement emitDecoratorMetadata, which silently breaks NestJS's constructor DI (every provider resolves to undefined). Covers: - auth.spec.ts: anti-enumeration login message, refresh-token rotation, replay-detection revoking the whole session chain, idempotent logout (ADR-0003). - role-weight.spec.ts: invalid role_key on invite returns 400 not 500 (regression guard), lower-weight actor forbidden from assigning a heavier role even when holding users:edit (ADR-0004). - companies.spec.ts: CNPJ digit-check validation (reject/accept). - mass-assignment.spec.ts: forbidNonWhitelisted actually rejects unexpected fields on companies/products. - reseller-assignment.spec.ts: assign-user always targets the URL's :id, never a body resellerId (regression guard for commit 8d108e0); unassign-user clears the assignment. All fixtures are qa-test-/qa_ tagged and cleaned up (deactivated where no DELETE endpoint exists, deleted where one does) — verified no pre-existing seed data (super_admin, Handix Telecom LTDA, Handix revenda própria) was touched. Co-Authored-By: Claude Sonnet 5 --- apps/api/.swcrc | 22 + apps/api/package.json | 13 +- apps/api/test/auth.spec.ts | 143 +++ apps/api/test/companies.spec.ts | 65 ++ apps/api/test/mass-assignment.spec.ts | 58 ++ apps/api/test/reseller-assignment.spec.ts | 120 +++ apps/api/test/role-weight.spec.ts | 124 +++ apps/api/test/setup.ts | 120 +++ apps/api/tsconfig.test.json | 15 + apps/api/vitest.config.ts | 60 ++ pnpm-lock.yaml | 1029 +++++++++++++++++++++ pnpm-workspace.yaml | 1 + 12 files changed, 1767 insertions(+), 3 deletions(-) create mode 100644 apps/api/.swcrc create mode 100644 apps/api/test/auth.spec.ts create mode 100644 apps/api/test/companies.spec.ts create mode 100644 apps/api/test/mass-assignment.spec.ts create mode 100644 apps/api/test/reseller-assignment.spec.ts create mode 100644 apps/api/test/role-weight.spec.ts create mode 100644 apps/api/test/setup.ts create mode 100644 apps/api/tsconfig.test.json create mode 100644 apps/api/vitest.config.ts diff --git a/apps/api/.swcrc b/apps/api/.swcrc new file mode 100644 index 0000000..e53ddcf --- /dev/null +++ b/apps/api/.swcrc @@ -0,0 +1,22 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "sourceMaps": true, + "jsc": { + "parser": { + "syntax": "typescript", + "decorators": true, + "dynamicImport": true + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + }, + "keepClassNames": true, + "target": "es2022", + "loose": false, + "externalHelpers": false + }, + "module": { + "type": "es6" + } +} diff --git a/apps/api/package.json b/apps/api/package.json index dd4ef3b..a2fd9bc 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -6,9 +6,10 @@ "build": "tsc -p tsconfig.json", "start": "node dist/main.js", "dev": "tsx watch src/main.ts", - "typecheck": "tsc -p tsconfig.json --noEmit", + "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json", "lint": "echo 'no linter configured yet'", - "test": "echo 'no tests yet'" + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@eden/config": "workspace:*", @@ -28,10 +29,16 @@ "rxjs": "^7.8.1" }, "devDependencies": { + "@nestjs/testing": "^10.4.15", + "@swc/core": "^1.10.1", "@types/express": "^5.0.0", "@types/jsonwebtoken": "^9.0.7", "@types/node": "^22.10.5", + "@types/supertest": "^6.0.2", + "supertest": "^7.0.0", "tsx": "^4.19.2", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "unplugin-swc": "^1.5.1", + "vitest": "^2.1.8" } } diff --git a/apps/api/test/auth.spec.ts b/apps/api/test/auth.spec.ts new file mode 100644 index 0000000..d900051 --- /dev/null +++ b/apps/api/test/auth.spec.ts @@ -0,0 +1,143 @@ +import { INestApplication } from "@nestjs/common"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { + agent, + bearer, + closeTestApp, + createTestApp, + loginSuperAdmin, + qaEmail, + type AuthedTokens, +} from "./setup.js"; + +/** + * Protects the session/refresh-token invariants of ADR-0003 + * (docs/adr/0003-auth-sessions.md) and apps/api/src/auth/auth.service.ts. + * + * Fixture: one throwaway user (role_key='user', a pre-existing system + * role — no new role is created here), invited via the real + * POST /v1/users/invite flow as super_admin. Every session created for it + * is a byproduct of real login/refresh/logout calls, never a hand-inserted + * row — replay detection specifically must be proven end-to-end through + * the actual rotation chain, not simulated. + * + * Cleanup: the fixture user is deactivated (PATCH isActive:false) in + * afterAll, which also revokes any sessions still active — there is no + * DELETE /v1/users endpoint. Session rows themselves are left in place + * (there's no session-deletion endpoint either, and they're an expected + * append-only-ish audit trail of real auth activity, not "dirty" state); + * they all point at a deactivated, obviously-tagged (qa-test-) fixture + * user. + */ +describe("auth — session lifecycle invariants", () => { + let app: INestApplication; + let admin: AuthedTokens; + let fixtureEmail: string; + let fixtureUserId: string; + let fixturePassword: string; + + beforeAll(async () => { + app = await createTestApp(); + admin = await loginSuperAdmin(app); + + fixtureEmail = qaEmail("auth"); + const invite = await agent(app) + .post("/api/v1/users/invite") + .set(...bearer(admin.accessToken)) + .send({ email: fixtureEmail, roleKey: "user", applications: ["core"] }) + .expect(201); + fixtureUserId = invite.body.user.id; + fixturePassword = invite.body.tempPassword; + }); + + afterAll(async () => { + await agent(app) + .patch(`/api/v1/users/${fixtureUserId}`) + .set(...bearer(admin.accessToken)) + .send({ isActive: false }) + .expect(200); + await closeTestApp(app); + }); + + describe("login — anti-enumeration (eden.md §4.1)", () => { + it("wrong password for an existing account returns a generic 401", async () => { + const res = await agent(app) + .post("/api/v1/auth/login") + .send({ email: fixtureEmail, password: "definitely-the-wrong-password", applicationKey: "core" }) + .expect(401); + expect(res.body.message).toBe("Credenciais inválidas"); + }); + + it("a non-existent account returns the exact same 401 message as a wrong password", async () => { + const res = await agent(app) + .post("/api/v1/auth/login") + .send({ email: qaEmail("nobody"), password: "whatever-12345", applicationKey: "core" }) + .expect(401); + // Invariant: the response must not let a caller distinguish + // "account doesn't exist" from "account exists, wrong password" — + // if this message ever diverges from the wrong-password case above, + // the API becomes an account-enumeration oracle. + expect(res.body.message).toBe("Credenciais inválidas"); + }); + }); + + describe("refresh — rotation (ADR-0003)", () => { + it("a successful refresh returns a different refresh token than the one submitted", async () => { + const session = await agent(app) + .post("/api/v1/auth/login") + .send({ email: fixtureEmail, password: fixturePassword, applicationKey: "core" }) + .expect(200); + const originalRefreshToken = session.body.refreshToken as string; + + const refreshed = await agent(app) + .post("/api/v1/auth/refresh") + .send({ refreshToken: originalRefreshToken }) + .expect(200); + + expect(refreshed.body.refreshToken).toBeTypeOf("string"); + expect(refreshed.body.refreshToken).not.toBe(originalRefreshToken); + }); + }); + + describe("refresh — replay detection revokes the whole session chain (ADR-0003)", () => { + it("reusing an already-rotated refresh token is rejected AND invalidates the token that replaced it", async () => { + const session = await agent(app) + .post("/api/v1/auth/login") + .send({ email: fixtureEmail, password: fixturePassword, applicationKey: "core" }) + .expect(200); + const firstToken = session.body.refreshToken as string; + + const rotated = await agent(app) + .post("/api/v1/auth/refresh") + .send({ refreshToken: firstToken }) + .expect(200); + const secondToken = rotated.body.refreshToken as string; + expect(secondToken).not.toBe(firstToken); + + // Replay: reuse the now-rotated-away first token. + await agent(app).post("/api/v1/auth/refresh").send({ refreshToken: firstToken }).expect(401); + + // The specific invariant under test: replay of a revoked token must + // revoke the ENTIRE session chain defensively (auth.service.ts + // refresh() -> revokeAllUserSessions), not just reject the replayed + // token. So the token that legitimately replaced it must now also + // be dead, even though it was never itself reused or leaked. + await agent(app).post("/api/v1/auth/refresh").send({ refreshToken: secondToken }).expect(401); + }); + }); + + describe("logout — idempotent", () => { + it("calling logout twice with the same refresh token succeeds both times", async () => { + const session = await agent(app) + .post("/api/v1/auth/login") + .send({ email: fixtureEmail, password: fixturePassword, applicationKey: "core" }) + .expect(200); + const refreshToken = session.body.refreshToken as string; + + await agent(app).post("/api/v1/auth/logout").send({ refreshToken }).expect(204); + // Second call: session is already revoked/gone — auth.service.ts's + // logout() treats "no active session found" as success, not 404/500. + await agent(app).post("/api/v1/auth/logout").send({ refreshToken }).expect(204); + }); + }); +}); diff --git a/apps/api/test/companies.spec.ts b/apps/api/test/companies.spec.ts new file mode 100644 index 0000000..c92a637 --- /dev/null +++ b/apps/api/test/companies.spec.ts @@ -0,0 +1,65 @@ +import { INestApplication } from "@nestjs/common"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { agent, bearer, closeTestApp, createTestApp, loginSuperAdmin, type AuthedTokens } from "./setup.js"; + +/** + * Protects the CNPJ digit-check invariant in + * apps/api/src/companies/companies.service.ts (assertValidCnpjIfPresent -> + * @eden/domain-shared's isValidCNPJ) — format validation only, per that + * function's own doc comment ("never confirms a document actually exists + * or belongs to whoever claims it"). + * + * The valid-CNPJ fixture uses 11.444.777/0001-61 — verified against the + * same digit-check algorithm (packages/domain-shared/src/validators/ + * br-documents.ts) before writing this test, and confirmed (by querying + * the shared dev Postgres directly) NOT already used by any company row, + * unlike 11.222.333/0001-81 which the seeded "Handix Telecom LTDA" company + * already holds. + * + * Cleanup: there is no DELETE /v1/companies endpoint, so the company + * created by the "valid CNPJ succeeds" test is deactivated + * (PATCH isActive:false) in afterAll rather than deleted. + */ +describe("companies — CNPJ validation invariant", () => { + let app: INestApplication; + let admin: AuthedTokens; + let createdCompanyId: string | undefined; + + beforeAll(async () => { + app = await createTestApp(); + admin = await loginSuperAdmin(app); + }); + + afterAll(async () => { + if (createdCompanyId) { + await agent(app) + .patch(`/api/v1/companies/${createdCompanyId}`) + .set(...bearer(admin.accessToken)) + .send({ isActive: false }) + .expect(200); + } + await closeTestApp(app); + }); + + it("rejects a CNPJ that fails the check-digit algorithm with 400", async () => { + const res = await agent(app) + .post("/api/v1/companies") + .set(...bearer(admin.accessToken)) + .send({ companyName: "qa-test- Empresa CNPJ Inválido", cnpj: "11.222.333/0001-00" }) + .expect(400); + expect(res.body.message).toContain("CNPJ inválido"); + }); + + it("accepts a company with a valid, not-already-used CNPJ", async () => { + const res = await agent(app) + .post("/api/v1/companies") + .set(...bearer(admin.accessToken)) + .send({ companyName: "qa-test- Empresa CNPJ Válido", cnpj: "11.444.777/0001-61" }) + .expect(201); + + expect(res.body.id).toBeTypeOf("string"); + // Persisted digits-only, per companies.service.ts's onlyDigits(dto.cnpj). + expect(res.body.cnpj).toBe("11444777000161"); + createdCompanyId = res.body.id; + }); +}); diff --git a/apps/api/test/mass-assignment.spec.ts b/apps/api/test/mass-assignment.spec.ts new file mode 100644 index 0000000..2f3f925 --- /dev/null +++ b/apps/api/test/mass-assignment.spec.ts @@ -0,0 +1,58 @@ +import { INestApplication } from "@nestjs/common"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { agent, bearer, closeTestApp, createTestApp, loginSuperAdmin, type AuthedTokens } from "./setup.js"; + +/** + * Protects the global ValidationPipe wiring itself + * (whitelist: true, forbidNonWhitelisted: true — apps/api/src/main.ts, + * mirrored in test/setup.ts's createTestApp). Master Prompt §12: the + * server never trusts a client-supplied field it didn't ask for. This + * doesn't test any one DTO's specific fields so much as prove the pipe + * is actually reaching these routes and actually configured to reject + * (not silently strip) unknown fields. + * + * No fixtures are created — every request here is expected to be + * rejected by the pipe *before* the controller/service runs, so nothing + * ever reaches the database. No cleanup needed. + */ +describe("mass-assignment — unexpected fields are rejected, not silently dropped", () => { + let app: INestApplication; + let admin: AuthedTokens; + + beforeAll(async () => { + app = await createTestApp(); + admin = await loginSuperAdmin(app); + }); + + afterAll(async () => { + await closeTestApp(app); + }); + + it("POST /v1/companies rejects an unexpected 'id' field", async () => { + await agent(app) + .post("/api/v1/companies") + .set(...bearer(admin.accessToken)) + .send({ companyName: "qa-test- mass assignment id", id: "11111111-1111-1111-1111-111111111111" }) + .expect(400); + }); + + it("POST /v1/companies rejects an unexpected 'isActive' field (not part of CreateCompanyDto)", async () => { + await agent(app) + .post("/api/v1/companies") + .set(...bearer(admin.accessToken)) + .send({ companyName: "qa-test- mass assignment isActive", isActive: false }) + .expect(400); + }); + + it("POST /v1/products rejects an unexpected 'createdBy' field", async () => { + await agent(app) + .post("/api/v1/products") + .set(...bearer(admin.accessToken)) + .send({ + name: "qa-test- mass assignment product", + productType: "service", + createdBy: "11111111-1111-1111-1111-111111111111", + }) + .expect(400); + }); +}); diff --git a/apps/api/test/reseller-assignment.spec.ts b/apps/api/test/reseller-assignment.spec.ts new file mode 100644 index 0000000..bda3cf9 --- /dev/null +++ b/apps/api/test/reseller-assignment.spec.ts @@ -0,0 +1,120 @@ +import { INestApplication } from "@nestjs/common"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { query } from "@eden/database"; +import { agent, bearer, closeTestApp, createTestApp, loginSuperAdmin, qaEmail, type AuthedTokens } from "./setup.js"; + +/** + * Protects the fix in commit 8d108e0 ("fix: assign-user de reseller usava + * resellerId do body, não o :id da URL"): the reseller a user is assigned + * to must always be the `:id` in the URL, never a value read from the + * request body. AssignUserToResellerDto (apps/api/src/resellers/dto/ + * assign-user-to-reseller.dto.ts) now only declares `userId` — it doesn't + * accept `resellerId` at all — so the strongest proof available at the + * HTTP layer is that a body containing `resellerId` is rejected outright + * by the mass-assignment whitelist (a body that could "win" over the URL + * literally cannot reach the service layer any more). This is backed up + * with a direct read of `users.reseller_id` after a legitimate call, + * confirming the URL's reseller is the one actually persisted. + * + * Fixtures: two throwaway resellers + one throwaway user (all + * `qa-test-`/`qa_` tagged). Cleanup: unassign the user (reseller_id back + * to null, exercised by test (b) itself), then deactivate the user and + * both resellers — no DELETE endpoint exists for either resource. + */ +describe("resellers — assign-user URL-wins-over-body invariant", () => { + let app: INestApplication; + let admin: AuthedTokens; + let resellerAId: string; + let resellerBId: string; + let userId: string; + + beforeAll(async () => { + app = await createTestApp(); + admin = await loginSuperAdmin(app); + + const resellerA = await agent(app) + .post("/api/v1/resellers") + .set(...bearer(admin.accessToken)) + .send({ name: "qa-test- Reseller A (target)" }) + .expect(201); + resellerAId = resellerA.body.id; + + const resellerB = await agent(app) + .post("/api/v1/resellers") + .set(...bearer(admin.accessToken)) + .send({ name: "qa-test- Reseller B (decoy in body)" }) + .expect(201); + resellerBId = resellerB.body.id; + + const invite = await agent(app) + .post("/api/v1/users/invite") + .set(...bearer(admin.accessToken)) + .send({ email: qaEmail("reseller-assignee"), roleKey: "user", applications: ["core"] }) + .expect(201); + userId = invite.body.user.id; + }); + + afterAll(async () => { + await agent(app) + .patch(`/api/v1/users/${userId}`) + .set(...bearer(admin.accessToken)) + .send({ isActive: false }) + .expect(200); + await agent(app) + .patch(`/api/v1/resellers/${resellerAId}`) + .set(...bearer(admin.accessToken)) + .send({ active: false }) + .expect(200); + await agent(app) + .patch(`/api/v1/resellers/${resellerBId}`) + .set(...bearer(admin.accessToken)) + .send({ active: false }) + .expect(200); + await closeTestApp(app); + }); + + it("a 'resellerId' in the body is rejected by the whitelist — there is no way to redirect the assignment via the body", async () => { + await agent(app) + .patch(`/api/v1/resellers/${resellerAId}/assign-user`) + .set(...bearer(admin.accessToken)) + .send({ userId, resellerId: resellerBId }) + .expect(400); + + // Confirm the rejected request didn't partially apply anything. + const { rows } = await query<{ reseller_id: string | null }>( + "SELECT reseller_id FROM users WHERE id = $1", + [userId], + ); + expect(rows[0]?.reseller_id).toBeNull(); + }); + + it("assigning via the URL's :id actually persists that reseller (not the decoy)", async () => { + const res = await agent(app) + .patch(`/api/v1/resellers/${resellerAId}/assign-user`) + .set(...bearer(admin.accessToken)) + .send({ userId }) + .expect(200); + expect(res.body.resellerId).toBe(resellerAId); + + const { rows } = await query<{ reseller_id: string | null }>( + "SELECT reseller_id FROM users WHERE id = $1", + [userId], + ); + expect(rows[0]?.reseller_id).toBe(resellerAId); + }); + + it("POST /v1/resellers/unassign-user clears the assignment", async () => { + const res = await agent(app) + .post("/api/v1/resellers/unassign-user") + .set(...bearer(admin.accessToken)) + .send({ userId }) + .expect(201); + expect(res.body.resellerId).toBeNull(); + + const { rows } = await query<{ reseller_id: string | null }>( + "SELECT reseller_id FROM users WHERE id = $1", + [userId], + ); + expect(rows[0]?.reseller_id).toBeNull(); + }); +}); diff --git a/apps/api/test/role-weight.spec.ts b/apps/api/test/role-weight.spec.ts new file mode 100644 index 0000000..6e90a27 --- /dev/null +++ b/apps/api/test/role-weight.spec.ts @@ -0,0 +1,124 @@ +import { INestApplication } from "@nestjs/common"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { + agent, + bearer, + closeTestApp, + createTestApp, + login, + loginSuperAdmin, + qaEmail, + qaKey, + type AuthedTokens, +} from "./setup.js"; + +/** + * Protects the role-weight invariant of apps/api/src/auth/role-weight.ts + * (docs/adr/0004-permission-model.md, eden.md §1.6): an actor can never + * assign/act on a role heavier than their own. Two distinct regressions + * are guarded here: + * + * (a) an unknown role_key must fail as a clean 400, not an unhandled + * DB FK-constraint 500 — see role-weight.ts's own comment on this + * exact bug ("this function must be the single place that turns + * 'role doesn't exist' into a clean 400, not the DB constraint"). + * (b) the weight comparison itself: a low-weight actor must be + * forbidden (403) from assigning a heavier role than their own, + * even when they otherwise hold the users:edit permission needed to + * reach the check at all. + */ +describe("role-weight — assignment invariant", () => { + let app: INestApplication; + let admin: AuthedTokens; + + beforeAll(async () => { + app = await createTestApp(); + admin = await loginSuperAdmin(app); + }); + + afterAll(async () => { + await closeTestApp(app); + }); + + it("inviting a user with a role_key that doesn't exist returns 400, not 500 (regression guard)", async () => { + const email = qaEmail("role-badkey"); + const res = await agent(app) + .post("/api/v1/users/invite") + .set(...bearer(admin.accessToken)) + .send({ email, roleKey: "does_not_exist_role_xyz" }) + .expect(400); + expect(res.body.message).toContain("does_not_exist_role_xyz"); + + // The invite must have been rejected before any row was written — + // confirm no user with this email exists. + const list = await agent(app) + .get("/api/v1/users") + .set(...bearer(admin.accessToken)) + .expect(200); + expect(list.body.some((u: { email: string }) => u.email === email.toLowerCase())).toBe(false); + }); + + describe("a lower-weight actor cannot assign a heavier role", () => { + let lowRoleKey: string; + let lowActorUserId: string; + let lowActorEmail: string; + let lowActorPassword: string; + let lowActorTokens: AuthedTokens; + + beforeAll(async () => { + // 1. A fresh, low-weight role (weight 5 — lighter than every + // system role except none; lighter than 'admin' at 80), granted + // users:edit/all so the actor reaches the role-weight check itself + // rather than being stopped earlier by PermissionGuard — isolating + // the specific invariant under test. + lowRoleKey = qaKey("lowrole"); + await agent(app) + .post("/api/v1/roles") + .set(...bearer(admin.accessToken)) + .send({ key: lowRoleKey, label: "QA test low-weight role", weight: 5 }) + .expect(201); + await agent(app) + .patch(`/api/v1/roles/${lowRoleKey}/permissions`) + .set(...bearer(admin.accessToken)) + .send({ permissions: [{ resource: "users", action: "edit", scope: "all" }] }) + .expect(200); + + // 2. A throwaway user in that role, logged in for real. + lowActorEmail = qaEmail("role-lowactor"); + const invite = await agent(app) + .post("/api/v1/users/invite") + .set(...bearer(admin.accessToken)) + .send({ email: lowActorEmail, roleKey: lowRoleKey, applications: ["core"] }) + .expect(201); + lowActorUserId = invite.body.user.id; + lowActorPassword = invite.body.tempPassword; + lowActorTokens = await login(app, lowActorEmail, lowActorPassword); + }); + + afterAll(async () => { + // Reassign the fixture user back to a system role and deactivate it + // so the throwaway role has zero referencing users left, then + // delete the throwaway role (RolesService.delete refuses to delete + // a role that still has users on it) — full cleanup, not just a + // tag, since both a DELETE-role and a PATCH-user endpoint exist. + await agent(app) + .patch(`/api/v1/users/${lowActorUserId}`) + .set(...bearer(admin.accessToken)) + .send({ roleKey: "user", isActive: false }) + .expect(200); + await agent(app) + .delete(`/api/v1/roles/${lowRoleKey}`) + .set(...bearer(admin.accessToken)) + .expect(204); + }); + + it("holding users:edit is not enough — assigning role 'admin' (weight 80 > actor's 5) is forbidden", async () => { + const res = await agent(app) + .post("/api/v1/users/invite") + .set(...bearer(lowActorTokens.accessToken)) + .send({ email: qaEmail("role-target"), roleKey: "admin" }) + .expect(403); + expect(res.body.message).toMatch(/peso maior/i); + }); + }); +}); diff --git a/apps/api/test/setup.ts b/apps/api/test/setup.ts new file mode 100644 index 0000000..7d0d426 --- /dev/null +++ b/apps/api/test/setup.ts @@ -0,0 +1,120 @@ +import "reflect-metadata"; +import { INestApplication, ValidationPipe } from "@nestjs/common"; +import { Test } from "@nestjs/testing"; +import request from "supertest"; +import { closePool } from "@eden/database"; +import { AppModule } from "../src/app.module.js"; + +/** + * Shared integration-test bootstrap (eden-qa). Boots the REAL Nest app — + * every module, guard, pipe and repository exactly as main.ts wires them — + * against the REAL Postgres pointed to by DATABASE_URL. The only thing + * skipped versus a full deployment is the separate OS process/container: + * HTTP goes through supertest -> app.getHttpServer() (real Express, real + * routing, real guards), and the DB goes through the real `pg` Pool (no + * mock/in-memory substitute anywhere in this stack). + * + * Mirrors main.ts's ValidationPipe + global prefix exactly (see + * apps/api/src/main.ts) without importing/touching main.ts itself, so + * this file can't conflict with other work landing there. + */ +export async function createTestApp(): Promise { + const moduleRef = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + const app = moduleRef.createNestApplication(); + + app.setGlobalPrefix("api", { exclude: ["health/live", "health/ready"] }); + + app.useGlobalPipes( + new ValidationPipe({ + whitelist: true, + forbidNonWhitelisted: true, + transform: true, + }), + ); + + await app.init(); + return app; +} + +export async function closeTestApp(app: INestApplication): Promise { + await app.close(); + // packages/database's pg Pool is a module-level singleton, not a Nest + // provider tied to app.close() — close it explicitly so vitest's process + // can exit instead of hanging on an idle DB connection. + await closePool(); +} + +/** Base path every controller in this API is mounted under (see main.ts's setGlobalPrefix). */ +export const API = "/api"; + +export function agent(app: INestApplication) { + return request(app.getHttpServer()); +} + +export interface AuthedTokens { + accessToken: string; + refreshToken: string; + userId: string; +} + +/** + * Logs in for real via POST /api/v1/auth/login (no guard/token mocking + * anywhere in this suite). Requires EDEN_SUPERADMIN_EMAIL/PASSWORD to be + * set in the environment (apps/api/src/bootstrap/seed.service.ts seeds + * this account once at boot, only if `users` was empty when the API first + * started) — the same account docker-compose's eden-api container seeds + * against the shared dev Postgres. + */ +export async function loginSuperAdmin(app: INestApplication): Promise { + const email = process.env.EDEN_SUPERADMIN_EMAIL; + const password = process.env.EDEN_SUPERADMIN_PASSWORD; + if (!email || !password) { + throw new Error( + "EDEN_SUPERADMIN_EMAIL/EDEN_SUPERADMIN_PASSWORD must be set (see .env) to run these integration tests — they authenticate for real, no mocked guard.", + ); + } + return login(app, email, password); +} + +export async function login( + app: INestApplication, + email: string, + password: string, + applicationKey: "core" | "reseller" | "subscriber" = "core", +): Promise { + const res = await agent(app) + .post(`${API}/v1/auth/login`) + .send({ email, password, applicationKey }) + .expect(200); + return { + accessToken: res.body.accessToken as string, + refreshToken: res.body.refreshToken as string, + userId: res.body.user.id as string, + }; +} + +export function bearer(token: string): [string, string] { + return ["Authorization", `Bearer ${token}`]; +} + +/** + * Every fixture this suite creates is tagged with this prefix so it's + * trivially identifiable (and greppable) as QA-test-owned data in the + * shared dev database, even if a cleanup step is ever missed. + */ +export const QA_PREFIX = "qa-test-"; + +export function qaEmail(label: string): string { + const rand = Math.random().toString(36).slice(2, 10); + return `${QA_PREFIX}${label}-${rand}@example.com`; +} + +export function qaKey(label: string): string { + const rand = Math.random().toString(36).slice(2, 8); + // Roles: lowercase, starts with a letter, a-z0-9_, 2-30 chars (see + // apps/api/src/roles/dto/create-role.dto.ts). + return `qa_${label}_${rand}`.slice(0, 30); +} diff --git a/apps/api/tsconfig.test.json b/apps/api/tsconfig.test.json new file mode 100644 index 0000000..e45184f --- /dev/null +++ b/apps/api/tsconfig.test.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "CommonJS", + "moduleResolution": "Node", + "target": "ES2022", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "strictPropertyInitialization": false, + "noEmit": true, + "types": ["node"] + }, + "include": ["src/**/*.ts", "test/**/*.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/apps/api/vitest.config.ts b/apps/api/vitest.config.ts new file mode 100644 index 0000000..230622d --- /dev/null +++ b/apps/api/vitest.config.ts @@ -0,0 +1,60 @@ +import { readFileSync, existsSync } from "node:fs"; +import { resolve } from "node:path"; +import { defineConfig } from "vitest/config"; +import swc from "unplugin-swc"; + +/** + * These are integration tests, not unit tests — they need DATABASE_URL, + * JWT_SIGNING_SECRET, EDEN_SUPERADMIN_EMAIL/PASSWORD, etc. from the repo + * root `.env` (gitignored, never read by vitest automatically the way + * Next/Vite's client env loading does). Parsed by hand here (no `dotenv` + * dependency needed) and passed through `test.env` so it reaches the + * worker process(es) vitest actually runs specs in. + */ +function loadRootEnv(): Record { + const envPath = resolve(__dirname, "../../.env"); + if (!existsSync(envPath)) return {}; + const out: Record = {}; + for (const line of readFileSync(envPath, "utf8").split("\n")) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq === -1) continue; + out[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim(); + } + return out; +} + +/** + * Integration test config (eden-qa). Every spec under test/ boots a real, + * fully-wired Nest app (Test.createTestingModule + AppModule) against a + * real Postgres — no mocked DB layer, per the eden-qa persona's rule. + * Timeout is generous (15s default) because some tests hit the DB several + * times in sequence and hash passwords with Argon2id (intentionally slow). + */ +export default defineConfig({ + // NestJS's DI resolves constructor parameter types from + // `design:paramtypes` metadata emitted by the TS decorator-metadata + // transform. Vite's default esbuild transform does NOT implement + // `emitDecoratorMetadata` (esbuild is a single-file transformer with no + // type checker to resolve types from) — every @Injectable()/@Controller + // class would silently receive `undefined` for its dependencies instead + // of a real instance. Using SWC (which does implement it, matching + // `tsc`'s behavior) here is the standard fix for testing Nest apps with + // Vitest — see https://docs.nestjs.com/recipes/swc#vitest. + plugins: [swc.vite()], + test: { + environment: "node", + include: ["test/**/*.spec.ts"], + testTimeout: 15000, + hookTimeout: 15000, + // Integration tests share one real Postgres connection pool + one + // seeded super_admin account; running spec files in parallel worker + // processes risks session/role-cleanup races between files (e.g. two + // files both minting/deleting similarly-named throwaway roles). Runs + // sequentially, file by file — still fully real, just not concurrent. + fileParallelism: false, + globals: false, + env: { ...loadRootEnv(), ...process.env }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16ff2ca..94fa0b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,12 @@ importers: specifier: ^7.8.1 version: 7.8.2 devDependencies: + '@nestjs/testing': + specifier: ^10.4.15 + 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)(@nestjs/platform-express@10.4.22) + '@swc/core': + specifier: ^1.10.1 + version: 1.16.1 '@types/express': specifier: ^5.0.0 version: 5.0.6 @@ -72,12 +78,24 @@ importers: '@types/node': specifier: ^22.10.5 version: 22.20.1 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + supertest: + specifier: ^7.0.0 + version: 7.2.2(supports-color@7.2.0) tsx: specifier: ^4.19.2 version: 4.23.13 typescript: specifier: ^5.7.3 version: 5.9.3 + unplugin-swc: + specifier: ^1.5.1 + version: 1.5.11(@swc/core@1.16.1)(esbuild@0.28.2)(rollup@4.63.1)(vite@5.4.21(@types/node@22.20.1)) + vitest: + specifier: ^2.1.8 + version: 2.1.9(@types/node@22.20.1)(supports-color@7.2.0) apps/core-web: dependencies: @@ -455,6 +473,12 @@ packages: '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -467,6 +491,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} @@ -479,6 +509,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} @@ -491,6 +527,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} @@ -503,6 +545,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} @@ -515,6 +563,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} @@ -527,6 +581,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} @@ -539,6 +599,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} @@ -551,6 +617,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} @@ -563,6 +635,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} @@ -575,6 +653,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} @@ -587,6 +671,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} @@ -599,6 +689,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} @@ -611,6 +707,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} @@ -623,6 +725,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} @@ -635,6 +743,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} @@ -647,6 +761,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} @@ -671,6 +791,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} @@ -695,6 +821,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} @@ -719,6 +851,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} @@ -731,6 +869,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} @@ -743,6 +887,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} @@ -755,6 +905,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} @@ -915,6 +1071,23 @@ packages: typeorm: optional: true + '@nestjs/testing@10.4.22': + resolution: {integrity: sha512-HO9aPus3bAedAC+jKVAA8jTdaj4fs5M9fing4giHrcYV2txe9CvC1l1WAjwQ9RDhEHdugjY4y+FZA/U/YqPZrA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + '@nestjs/microservices': ^10.0.0 + '@nestjs/platform-express': ^10.0.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -932,6 +1105,9 @@ packages: engines: {node: '>=8.0.0', npm: '>=5.0.0'} hasBin: true + '@paralleldrive/cuid2@2.3.1': + resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} + '@phc/format@1.0.0': resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} engines: {node: '>=10'} @@ -939,6 +1115,15 @@ packages: '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.63.1': resolution: {integrity: sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==} cpu: [arm] @@ -1104,6 +1289,99 @@ packages: resolution: {integrity: sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==} engines: {node: '>=18.0.0'} + '@swc/core-darwin-arm64@1.16.1': + resolution: {integrity: sha512-zlJblJ8ncErD43lKdxjbUaUskJQf+LxiPXYcWXD8/8ZMV+7uuAT+CwjciLXpyZBd5Pq/S726bMpeeAwSeL1hhg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.16.1': + resolution: {integrity: sha512-IN0BmPWb0YAh/17mmlWB/HDBtTw2MfuW4hulf/tQAgTQBRH17l+z499bNJLK6LizSjqs0P7V+jU38Zj+vJC1DA==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.16.1': + resolution: {integrity: sha512-EYgrx2YOCQ2Twz2S793kqNjPkpvYVUPzzR95bIb7by+VQcyaai4lZZ2iz/tZvcFVKSNcN3/JTKwx+aBn2ZL52A==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.16.1': + resolution: {integrity: sha512-moyKm0YZlHdHohzm1YwgAyesqnE853rO0REMfJLFAova51wF9BNi+3ZW2PeS7Vqvn6HeJuepLpAHbBdZctxpHA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.16.1': + resolution: {integrity: sha512-kKGBO9wdapiSzuf5ZzZ2fYtlu1BNSYtIIUxvH1ir/gcelTOREEHGDCLTDFx/2Knf878nU11A40z7LxwasEFxqA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-ppc64-gnu@1.16.1': + resolution: {integrity: sha512-nZ6qahtLxC3PM54cWOQZHxt4lTCF/3J4LIoWWzz6v7A+rLs8Dx54anYQf7mH3eIi8KlNpgKci/ie8ZSqFN8O7A==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-s390x-gnu@1.16.1': + resolution: {integrity: sha512-4ji5PNzhYq193Z4/4xUaSoNJza6iCkDJSzhetrbB6KOYxsr+kxtQr8ePWhMJUiMt6JUWtXaZ1PYT8FhtED+nGA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-gnu@1.16.1': + resolution: {integrity: sha512-VJQxqrisHV+B394IgrOu8YsIIXZgffnf5tO+yc9Z/hoUpuZEvuQTjWwlnpZdpyD+0nx6LTD1/3k646JYm43yJA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.16.1': + resolution: {integrity: sha512-r9oV1mwxxsIGcLV1IQ/tw76MW3doatKze1QFWuC+a7QqJUkhY/bKTSVk6NpKKUGm2LDsE33Va8VqSClfA7vSiQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.16.1': + resolution: {integrity: sha512-6huNRessoBLxWEqBm5zJXyCQ27TO7anvkdiuQ5MDO4CJni0nOXEqKtV9RllQ2TdyENKKsUMXVnIfW2hIXx/R5Q==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.16.1': + resolution: {integrity: sha512-OVKJFUzphrGmsh+BGtcZDesx0YryV7/Yvy5XGgTqnrZfjnyfcr5uaqYQugCckdIlupc5Vs3XtDjRAj12z4ZPlw==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.16.1': + resolution: {integrity: sha512-Bt+VIhWYCGk4urklnkkteLUOeLv1VxigwTCeB/xC6rBZxY6IIKdDwCJf6on3E3SUGsIqmQS6QqtuJQc1VxF4Aw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.16.1': + resolution: {integrity: sha512-nUaeu91O5QZKrQdaDCHd402ogUIoNOOjpkZNq0UomWK0G6gDaGmLhvddF1/3BXf5O8aLyo6ZPY/aMDWvaJQ/hg==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.28': + resolution: {integrity: sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==} + '@tokenizer/inflate@0.2.7': resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==} engines: {node: '>=18'} @@ -1159,6 +1437,9 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/cookiejar@2.1.5': + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -1174,6 +1455,9 @@ packages: '@types/jsonwebtoken@9.0.10': resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} + '@types/methods@1.1.4': + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -1209,6 +1493,12 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} + '@types/superagent@8.1.11': + resolution: {integrity: sha512-KA7srSW/HENDtOw9DOqaFLgWuMqN9WgjEw62lh9dpvRaZDkhdOkazASd7X7i2eMUYLHa1U37ZttnePsH5zTDHw==} + + '@types/supertest@6.0.3': + resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/validator@13.15.10': resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} @@ -1218,6 +1508,35 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.9': + resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} + + '@vitest/runner@2.1.9': + resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} + + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + + '@vitest/utils@2.1.9': + resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -1256,6 +1575,16 @@ packages: array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.5.4: resolution: {integrity: sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==} engines: {node: ^10 || ^12 || >=14} @@ -1318,6 +1647,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1337,6 +1670,10 @@ packages: caniuse-lite@1.0.30001810: resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -1345,6 +1682,10 @@ packages: resolution: {integrity: sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==} engines: {node: '>=16'} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -1370,10 +1711,17 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + concat-stream@2.0.0: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} @@ -1395,10 +1743,17 @@ packages: cookie-signature@1.0.7: resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -1432,6 +1787,14 @@ packages: supports-color: optional: true + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1440,6 +1803,9 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -1474,10 +1840,22 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} @@ -1495,10 +1873,20 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + express@4.22.1: resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} engines: {node: '>= 0.10.0'} @@ -1545,6 +1933,14 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + formidable@3.5.4: + resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} + engines: {node: '>=14.0.0'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -1606,6 +2002,10 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hasown@2.0.4: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} @@ -1704,6 +2104,10 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -1732,6 +2136,9 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lru-cache@11.5.2: resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} @@ -1739,6 +2146,9 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1775,6 +2185,11 @@ packages: engines: {node: '>=4'} hasBin: true + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + minimatch@10.2.6: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} @@ -1868,6 +2283,9 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1892,6 +2310,13 @@ packages: path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + pg-cloudflare@1.4.0: resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} @@ -2131,6 +2556,9 @@ packages: resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -2143,10 +2571,16 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -2171,6 +2605,14 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + superagent@10.3.0: + resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} + engines: {node: '>=14.18.0'} + + supertest@7.2.2: + resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} + engines: {node: '>=14.18.0'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2194,10 +2636,28 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2259,6 +2719,44 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin-swc@1.5.11: + resolution: {integrity: sha512-R7U4GbfrESPnYLn3nXREZrwhKQk3BAmTBoKJ5lmo7btTc/yJpNsDzavBWo+XpQTjDSIogiZEAxC5ig/vfMWxWg==} + peerDependencies: + '@swc/core': ^1.2.108 + + unplugin@3.3.0: + resolution: {integrity: sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@farmfe/core': '*' + '@rspack/core': '*' + bun-types-no-globals: '*' + esbuild: '*' + rolldown: '*' + rollup: '*' + unloader: '*' + vite: '*' + webpack: '*' + peerDependenciesMeta: + '@farmfe/core': + optional: true + '@rspack/core': + optional: true + bun-types-no-globals: + optional: true + esbuild: + optional: true + rolldown: + optional: true + rollup: + optional: true + unloader: + optional: true + vite: + optional: true + webpack: + optional: true + update-browserslist-db@1.3.2: resolution: {integrity: sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==} hasBin: true @@ -2280,6 +2778,42 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + vite@6.4.3: resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2320,9 +2854,37 @@ packages: yaml: optional: true + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -2331,6 +2893,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + widest-line@3.1.0: resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} engines: {node: '>=8'} @@ -2339,6 +2906,9 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -2644,102 +3214,153 @@ snapshots: '@borewit/text-codec@0.2.2': {} + '@esbuild/aix-ppc64@0.21.5': + optional: true + '@esbuild/aix-ppc64@0.25.12': optional: true '@esbuild/aix-ppc64@0.28.2': optional: true + '@esbuild/android-arm64@0.21.5': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true '@esbuild/android-arm64@0.28.2': optional: true + '@esbuild/android-arm@0.21.5': + optional: true + '@esbuild/android-arm@0.25.12': optional: true '@esbuild/android-arm@0.28.2': optional: true + '@esbuild/android-x64@0.21.5': + optional: true + '@esbuild/android-x64@0.25.12': optional: true '@esbuild/android-x64@0.28.2': optional: true + '@esbuild/darwin-arm64@0.21.5': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true '@esbuild/darwin-arm64@0.28.2': optional: true + '@esbuild/darwin-x64@0.21.5': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true '@esbuild/darwin-x64@0.28.2': optional: true + '@esbuild/freebsd-arm64@0.21.5': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true '@esbuild/freebsd-arm64@0.28.2': optional: true + '@esbuild/freebsd-x64@0.21.5': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true '@esbuild/freebsd-x64@0.28.2': optional: true + '@esbuild/linux-arm64@0.21.5': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true '@esbuild/linux-arm64@0.28.2': optional: true + '@esbuild/linux-arm@0.21.5': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true '@esbuild/linux-arm@0.28.2': optional: true + '@esbuild/linux-ia32@0.21.5': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true '@esbuild/linux-ia32@0.28.2': optional: true + '@esbuild/linux-loong64@0.21.5': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true '@esbuild/linux-loong64@0.28.2': optional: true + '@esbuild/linux-mips64el@0.21.5': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true '@esbuild/linux-mips64el@0.28.2': optional: true + '@esbuild/linux-ppc64@0.21.5': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true '@esbuild/linux-ppc64@0.28.2': optional: true + '@esbuild/linux-riscv64@0.21.5': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true '@esbuild/linux-riscv64@0.28.2': optional: true + '@esbuild/linux-s390x@0.21.5': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true '@esbuild/linux-s390x@0.28.2': optional: true + '@esbuild/linux-x64@0.21.5': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true @@ -2752,6 +3373,9 @@ snapshots: '@esbuild/netbsd-arm64@0.28.2': optional: true + '@esbuild/netbsd-x64@0.21.5': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true @@ -2764,6 +3388,9 @@ snapshots: '@esbuild/openbsd-arm64@0.28.2': optional: true + '@esbuild/openbsd-x64@0.21.5': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true @@ -2776,24 +3403,36 @@ snapshots: '@esbuild/openharmony-arm64@0.28.2': optional: true + '@esbuild/sunos-x64@0.21.5': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true '@esbuild/sunos-x64@0.28.2': optional: true + '@esbuild/win32-arm64@0.21.5': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true '@esbuild/win32-arm64@0.28.2': optional: true + '@esbuild/win32-ia32@0.21.5': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true '@esbuild/win32-ia32@0.28.2': optional: true + '@esbuild/win32-x64@0.21.5': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true @@ -2902,6 +3541,16 @@ snapshots: reflect-metadata: 0.2.2 rxjs: 7.8.2 + '@nestjs/testing@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)(@nestjs/platform-express@10.4.22)': + 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) + tslib: 2.8.1 + optionalDependencies: + '@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) + + '@noble/hashes@1.8.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2922,10 +3571,22 @@ snapshots: transitivePeerDependencies: - encoding + '@paralleldrive/cuid2@2.3.1': + dependencies: + '@noble/hashes': 1.8.0 + '@phc/format@1.0.0': {} '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rollup/pluginutils@5.4.0(rollup@4.63.1)': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.7 + optionalDependencies: + rollup: 4.63.1 + '@rollup/rollup-android-arm-eabi@4.63.1': optional: true @@ -3036,6 +3697,66 @@ snapshots: dependencies: tslib: 2.8.1 + '@swc/core-darwin-arm64@1.16.1': + optional: true + + '@swc/core-darwin-x64@1.16.1': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.16.1': + optional: true + + '@swc/core-linux-arm64-gnu@1.16.1': + optional: true + + '@swc/core-linux-arm64-musl@1.16.1': + optional: true + + '@swc/core-linux-ppc64-gnu@1.16.1': + optional: true + + '@swc/core-linux-s390x-gnu@1.16.1': + optional: true + + '@swc/core-linux-x64-gnu@1.16.1': + optional: true + + '@swc/core-linux-x64-musl@1.16.1': + optional: true + + '@swc/core-win32-arm64-msvc@1.16.1': + optional: true + + '@swc/core-win32-ia32-msvc@1.16.1': + optional: true + + '@swc/core-win32-x64-msvc@1.16.1': + optional: true + + '@swc/core@1.16.1': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.28 + optionalDependencies: + '@swc/core-darwin-arm64': 1.16.1 + '@swc/core-darwin-x64': 1.16.1 + '@swc/core-linux-arm-gnueabihf': 1.16.1 + '@swc/core-linux-arm64-gnu': 1.16.1 + '@swc/core-linux-arm64-musl': 1.16.1 + '@swc/core-linux-ppc64-gnu': 1.16.1 + '@swc/core-linux-s390x-gnu': 1.16.1 + '@swc/core-linux-x64-gnu': 1.16.1 + '@swc/core-linux-x64-musl': 1.16.1 + '@swc/core-win32-arm64-msvc': 1.16.1 + '@swc/core-win32-ia32-msvc': 1.16.1 + '@swc/core-win32-x64-msvc': 1.16.1 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.28': + dependencies: + '@swc/counter': 0.1.3 + '@tokenizer/inflate@0.2.7(supports-color@7.2.0)': dependencies: debug: 4.4.3(supports-color@7.2.0) @@ -3094,6 +3815,8 @@ snapshots: dependencies: '@types/node': 22.20.1 + '@types/cookiejar@2.1.5': {} + '@types/estree@1.0.9': {} '@types/express-serve-static-core@5.1.3': @@ -3116,6 +3839,8 @@ snapshots: '@types/ms': 2.1.0 '@types/node': 22.20.1 + '@types/methods@1.1.4': {} + '@types/ms@2.1.0': {} '@types/node@22.20.1': @@ -3156,6 +3881,18 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 22.20.1 + '@types/superagent@8.1.11': + dependencies: + '@types/cookiejar': 2.1.5 + '@types/methods': 1.1.4 + '@types/node': 22.20.1 + form-data: 4.0.6 + + '@types/supertest@6.0.3': + dependencies: + '@types/methods': 1.1.4 + '@types/superagent': 8.1.11 + '@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))': @@ -3170,6 +3907,46 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/expect@2.1.9': + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.20.1))': + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 5.4.21(@types/node@22.20.1) + + '@vitest/pretty-format@2.1.9': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.9': + dependencies: + '@vitest/utils': 2.1.9 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.21 + pathe: 1.1.2 + + '@vitest/spy@2.1.9': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + loupe: 3.2.1 + tinyrainbow: 1.2.0 + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -3206,6 +3983,12 @@ snapshots: array-flatten@1.1.1: {} + asap@2.0.6: {} + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + autoprefixer@10.5.4(postcss@8.5.26): dependencies: browserslist: 4.28.8 @@ -3294,6 +4077,8 @@ snapshots: bytes@3.1.2: {} + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -3310,6 +4095,14 @@ snapshots: caniuse-lite@1.0.30001810: {} + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -3317,6 +4110,8 @@ snapshots: check-disk-space@3.4.0: {} + check-error@2.1.3: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -3351,8 +4146,14 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@4.1.1: {} + component-emitter@1.3.1: {} + concat-stream@2.0.0: dependencies: buffer-from: 1.1.2 @@ -3372,8 +4173,12 @@ snapshots: cookie-signature@1.0.7: {} + cookie-signature@1.2.2: {} + cookie@0.7.2: {} + cookiejar@2.1.4: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -3401,10 +4206,19 @@ snapshots: optionalDependencies: supports-color: 7.2.0 + deep-eql@5.0.2: {} + + delayed-stream@1.0.0: {} + depd@2.0.0: {} destroy@1.2.0: {} + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + didyoumean@1.2.2: {} dlv@1.1.3: {} @@ -3431,10 +4245,45 @@ snapshots: es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -3497,8 +4346,16 @@ snapshots: escape-html@1.0.3: {} + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + etag@1.8.1: {} + expect-type@1.4.0: {} + express@4.22.1(supports-color@7.2.0): dependencies: accepts: 1.3.8 @@ -3621,6 +4478,20 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + formidable@3.5.4: + dependencies: + '@paralleldrive/cuid2': 2.3.1 + dezalgo: 1.0.4 + once: 1.4.0 + forwarded@0.2.0: {} fraction.js@5.3.4: {} @@ -3677,6 +4548,10 @@ snapshots: has-symbols@1.1.0: {} + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hasown@2.0.4: dependencies: function-bind: 1.1.2 @@ -3767,6 +4642,8 @@ snapshots: lines-and-columns@1.2.4: {} + load-tsconfig@0.2.5: {} + lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} @@ -3787,12 +4664,18 @@ snapshots: dependencies: js-tokens: 4.0.0 + loupe@3.2.1: {} + lru-cache@11.5.2: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + math-intrinsics@1.1.0: {} media-typer@0.3.0: {} @@ -3816,6 +4699,8 @@ snapshots: mime@1.6.0: {} + mime@2.6.0: {} + minimatch@10.2.6: dependencies: brace-expansion: 5.0.9 @@ -3884,6 +4769,10 @@ snapshots: dependencies: ee-first: 1.1.1 + once@1.4.0: + dependencies: + wrappy: 1.0.2 + package-json-from-dist@1.0.1: {} parseurl@1.3.3: {} @@ -3901,6 +4790,10 @@ snapshots: path-to-regexp@3.3.0: {} + pathe@1.1.2: {} + + pathval@2.0.1: {} + pg-cloudflare@1.4.0: optional: true @@ -4169,14 +5062,20 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@4.1.0: {} source-map-js@1.2.1: {} split2@4.2.0: {} + stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@3.10.0: {} + streamsearch@1.1.0: {} string-width@4.2.3: @@ -4207,6 +5106,28 @@ snapshots: tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 + superagent@10.3.0(supports-color@7.2.0): + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.4.3(supports-color@7.2.0) + fast-safe-stringify: 2.1.1 + form-data: 4.0.6 + formidable: 3.5.4 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.15.3 + transitivePeerDependencies: + - supports-color + + supertest@7.2.2(supports-color@7.2.0): + dependencies: + cookie-signature: 1.2.2 + methods: 1.1.2 + superagent: 10.3.0(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -4253,11 +5174,21 @@ snapshots: dependencies: any-promise: 1.3.0 + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 + tinypool@1.1.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -4312,6 +5243,33 @@ snapshots: unpipe@1.0.0: {} + unplugin-swc@1.5.11(@swc/core@1.16.1)(esbuild@0.28.2)(rollup@4.63.1)(vite@5.4.21(@types/node@22.20.1)): + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.1) + '@swc/core': 1.16.1 + load-tsconfig: 0.2.5 + unplugin: 3.3.0(esbuild@0.28.2)(rollup@4.63.1)(vite@5.4.21(@types/node@22.20.1)) + transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - rolldown + - rollup + - unloader + - vite + - webpack + + unplugin@3.3.0(esbuild@0.28.2)(rollup@4.63.1)(vite@5.4.21(@types/node@22.20.1)): + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.7 + webpack-virtual-modules: 0.6.2 + optionalDependencies: + esbuild: 0.28.2 + rollup: 4.63.1 + vite: 5.4.21(@types/node@22.20.1) + update-browserslist-db@1.3.2(browserslist@4.28.8): dependencies: browserslist: 4.28.8 @@ -4326,6 +5284,33 @@ snapshots: vary@1.1.2: {} + vite-node@2.1.9(@types/node@22.20.1)(supports-color@7.2.0): + dependencies: + cac: 6.7.14 + debug: 4.4.3(supports-color@7.2.0) + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@22.20.1) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@22.20.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.26 + rollup: 4.63.1 + optionalDependencies: + '@types/node': 22.20.1 + fsevents: 2.3.3 + vite@6.4.3(@types/node@22.20.1)(jiti@1.21.7)(tsx@4.23.13): dependencies: esbuild: 0.25.12 @@ -4340,8 +5325,45 @@ snapshots: jiti: 1.21.7 tsx: 4.23.13 + vitest@2.1.9(@types/node@22.20.1)(supports-color@7.2.0): + dependencies: + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.20.1)) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.3.3 + debug: 4.4.3(supports-color@7.2.0) + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.1.1 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@22.20.1) + vite-node: 2.1.9(@types/node@22.20.1)(supports-color@7.2.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.20.1 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + webidl-conversions@3.0.1: {} + webpack-virtual-modules@0.6.2: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -4351,6 +5373,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + widest-line@3.1.0: dependencies: string-width: 4.2.3 @@ -4361,6 +5388,8 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wrappy@1.0.2: {} + xtend@4.0.2: {} y18n@5.0.8: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 08faa3c..adcd231 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,5 +4,6 @@ packages: allowBuilds: '@nestjs/core': true '@scarf/scarf': false + '@swc/core': true argon2: true esbuild: true