diff --git a/.env.dev.example b/.env.dev.example deleted file mode 100644 index c626b1b..0000000 --- a/.env.dev.example +++ /dev/null @@ -1,2 +0,0 @@ -DATABASE_URL=postgresql://postgres:postgres@localhost:5432/reservation_db -SHADOW_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/reservation_db_shadow diff --git a/.env.prod.example b/.env.example similarity index 100% rename from .env.prod.example rename to .env.example diff --git a/.env.test.example b/.env.test.example deleted file mode 100644 index 0730e6d..0000000 --- a/.env.test.example +++ /dev/null @@ -1,2 +0,0 @@ -DATABASE_URL=postgresql://test:test@localhost:5433/barber_test -NODE_ENV=test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85cd7fd..a5596b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,20 +9,8 @@ jobs: quality: runs-on: ubuntu-latest - services: - postgres: - image: postgres:16 - env: - POSTGRES_DB: reservation_db - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - 5432:5432 - options: >- - --health-cmd="pg_isready -U postgres" - --health-interval=10s - --health-timeout=5s - --health-retries=5 + env: + DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }} steps: - uses: actions/checkout@v4 @@ -44,12 +32,5 @@ jobs: - name: Typecheck run: make typecheck - - name: Apply Drizzle migrations - env: - DATABASE_URL: postgresql://postgres:postgres@localhost:5432/reservation_db - run: make dev-migrate - - - name: Tests - env: - DATABASE_URL: postgresql://postgres:postgres@localhost:5432/reservation_db - run: make test + - name: Integration Tests + run: make ci-test diff --git a/.gitignore b/.gitignore index f83edf2..fe6d00e 100644 --- a/.gitignore +++ b/.gitignore @@ -35,10 +35,8 @@ lerna-debug.log* !.vscode/launch.json !.vscode/extensions.json -# dotenv environment variable files +# dotenv environment variable file .env -.env.* -!.env.*.example # temp directory .temp diff --git a/Makefile b/Makefile index 2e57823..6aea5e9 100644 --- a/Makefile +++ b/Makefile @@ -2,15 +2,10 @@ # Variáveis # ───────────────────────────────────────────────────────────── -DEV_ENV = .env.dev -PROD_ENV = .env.prod -TEST_ENV = .env.test - DEV_COMPOSE = docker/docker-compose.dev.yml PROD_COMPOSE = docker/docker-compose.prod.yml TEST_COMPOSE = docker/docker-compose.test.yml -MIGRATIONS_DIR = migrations TREE_IGNORE = node_modules|.git|dist|*.env* # ───────────────────────────────────────────────────────────── @@ -18,34 +13,26 @@ TREE_IGNORE = node_modules|.git|dist|*.env* # ───────────────────────────────────────────────────────────── .PHONY: \ - dev-up dev-down dev-reset dev-migrate \ - prod-up prod-migrate \ - test test-up test-down test-reset test-migrate test-run \ + check-env \ lint typecheck build \ - check-dev-env check-prod-env check-test-env \ + ci-test \ + dev-up dev-stop dev-start dev-down dev-reset dev-migrate \ + prod-up prod-migrate \ + test-up test-down test-reset test-migrate test \ tree # ───────────────────────────────────────────────────────────── -# Checks +# Environment Check # ───────────────────────────────────────────────────────────── -check-dev-env: - @test -f $(DEV_ENV) || (echo "❌ .env.dev não existe" && exit 1) - @grep -q "^DATABASE_URL=" $(DEV_ENV) || \ - (echo "❌ DATABASE_URL ausente (.env.dev)" && exit 1) - -check-prod-env: - @test -f $(PROD_ENV) || (echo "❌ .env.prod não existe" && exit 1) - @grep -q "^DATABASE_URL=" $(PROD_ENV) || \ - (echo "❌ DATABASE_URL ausente (.env.prod)" && exit 1) - -check-test-env: - @test -f $(TEST_ENV) || (echo "❌ .env.test não existe" && exit 1) - @grep -q "^DATABASE_URL=" $(TEST_ENV) || \ - (echo "❌ DATABASE_URL ausente (.env.test)" && exit 1) +check-env: + @if [ -z "$$DATABASE_URL" ]; then \ + echo "❌ DATABASE_URL não definida"; \ + exit 1; \ + fi # ───────────────────────────────────────────────────────────── -# CI +# Quality # ───────────────────────────────────────────────────────────── lint: @@ -54,6 +41,10 @@ lint: typecheck: pnpm tsc --noEmit +# ───────────────────────────────────────────────────────────── +# CI +# ───────────────────────────────────────────────────────────── + ci-test: make test-reset make test-up @@ -65,7 +56,7 @@ ci-test: # DEV # ───────────────────────────────────────────────────────────── -dev-up: check-dev-env +dev-up: @echo "🚧 Subindo Postgres DEV" docker compose -f $(DEV_COMPOSE) up -d @@ -85,27 +76,25 @@ dev-reset: @echo "💥 Resetando ambiente DEV (containers + volumes)" docker compose -f $(DEV_COMPOSE) down -v -dev-migrate: - npx dotenv-cli -e $(DEV_ENV) -- \ - npx ts-node src/infrastructure/scripts/migrate.ts +dev-migrate: check-env + npx ts-node src/infrastructure/scripts/migrate.ts # ───────────────────────────────────────────────────────────── # PROD # ───────────────────────────────────────────────────────────── -prod-up: check-prod-env +prod-up: @echo "🚀 Subindo Postgres PROD" docker compose -f $(PROD_COMPOSE) up -d -prod-migrate: check-prod-env - npx dotenv-cli -e $(PROD_ENV) -- \ - npx ts-node src/infrastructure/scripts/migrate.ts +prod-migrate: check-env + npx ts-node src/infrastructure/scripts/migrate.ts -# ──────────────────────────────────────────────────────────── +# ───────────────────────────────────────────────────────────── # TEST -# ──────────────────────────────────────────────────────────── +# ───────────────────────────────────────────────────────────── -test-up: check-test-env +test-up: @echo "🧪 Subindo Postgres TEST" docker compose -f $(TEST_COMPOSE) up -d @@ -117,13 +106,11 @@ test-reset: @echo "💥 Resetando ambiente TEST (containers + volumes)" docker compose -f $(TEST_COMPOSE) down -v -test-migrate: check-test-env - npx dotenv-cli -e $(TEST_ENV) -- \ - npx ts-node src/infrastructure/scripts/migrate.ts +test-migrate: check-env + npx ts-node src/infrastructure/scripts/migrate.ts test: - npx dotenv-cli -e $(TEST_ENV) -- \ - pnpm jest + pnpm jest # ───────────────────────────────────────────────────────────── # Utils diff --git a/docker/docker-compose.test.yml b/docker/docker-compose.test.yml index ef872fe..810c057 100644 --- a/docker/docker-compose.test.yml +++ b/docker/docker-compose.test.yml @@ -1,5 +1,3 @@ -version: "3.9" - services: postgres_test: image: postgres:16 diff --git a/docs/adr/0009-postgres-error-mapper.md b/docs/adr/0009-postgres-error-mapper.md index 0368f35..4538a50 100644 --- a/docs/adr/0009-postgres-error-mapper.md +++ b/docs/adr/0009-postgres-error-mapper.md @@ -21,7 +21,7 @@ Drizzle ORM wraps PostgreSQL errors, requiring custom logic to extract the under 2. **Repositories will depend only on semantic error checks** - * Example: `PostgresErrorMapper.isUniqueViolation(error)` + * Example: `PostgresErrorMapper.isExclusionViolation(error)` * Repositories will no longer parse error objects manually. 3. **The mapper remains an infrastructure concern** diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..f3eba4b --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,145 @@ +## Testing Strategy + +This project adopts a **multi-layered testing strategy** focused on enforcing domain invariants, validating persistence guarantees, and ensuring correct behavior under real database constraints. + +The goal is not only to test isolated logic, but to verify that **architectural boundaries and database-level invariants hold under realistic conditions**, including concurrent execution. + +--- + +## Test File Naming Conventions + +| Suffix | Meaning | Scope | +| -------------- | ----------------- | -------------------------------------- | +| `.spec.ts` | Unit tests | Domain / pure logic | +| `.int.spec.ts` | Integration tests | Database, repositories, infrastructure | +| `.e2e-spec.ts` | End-to-end tests | HTTP / NestJS application layer | + +Test folders mirror bounded contexts (e.g., `test/reservation`, `test/user`). + +--- + +## Test Types + +### Unit Tests (Domain Layer) + +Unit tests validate pure domain behavior without infrastructure dependencies. + +**Targets:** + +* Entities +* Value objects +* Domain services +* Logical invariants (e.g., reservation time validity) + +**Characteristics:** + +* No database +* No NestJS container +* No IO +* Deterministic and fast + +These tests validate business rules independently from persistence concerns. + +--- + +### Integration Tests (Persistence & Infrastructure) + +Integration tests validate interaction with a real PostgreSQL database. + +**Targets:** + +* Repository implementations +* Database constraints (UNIQUE, EXCLUDE, FK) +* Error mapping (PostgreSQL → domain errors) +* Schema behavior and migrations + +**Characteristics:** + +* Uses isolated PostgreSQL container via Docker +* Schema migrations executed before the test suite +* Database truncated before each test for deterministic isolation +* No mocks for persistence layer +* Enforced in CI + +Integration tests intentionally rely on real database behavior rather than mocks. +Database constraints are treated as part of the system’s correctness model. + +--- + +### Concurrency Tests + +Concurrency tests validate that race conditions are prevented under parallel execution. + +**Key invariants tested:** + +* A barber cannot have overlapping reservations +* Only one concurrent reservation for the same time slot can succeed + +**Strategy:** + +* Multiple concurrent transactions are started +* Execution is synchronized using a barrier to ensure simultaneous writes +* `Promise.allSettled` is used to observe outcomes +* PostgreSQL `EXCLUDE USING gist` constraint enforces correctness +* Constraint violations are mapped to `ReservationConflictError` + +These tests validate that concurrency protection is enforced at the database level and correctly surfaced at the domain layer. + +--- + +## Invariant Enforcement Model + +Invariant enforcement is intentionally split across layers: + +* **Domain layer** validates logical invariants (e.g., time range validity). +* **Database layer** enforces structural and concurrency invariants (e.g., overlapping reservations). +* **Repositories** translate database constraint violations into domain-specific errors. + +This ensures correctness even under concurrent execution and prevents reliance on application-level checks alone. + +--- + +## Database Test Lifecycle + +Integration tests rely on a deterministic PostgreSQL environment: + +1. Docker PostgreSQL container for tests +2. SQL migrations executed before the test suite +3. Tables truncated (with cascade) before each test +4. Isolated connection pool for test execution + +This guarantees test isolation and reproducibility. + +--- + +## Makefile Test Commands + +| Command | Description | +| ------------------- | ------------------------------- | +| `make test-up` | Start PostgreSQL test container | +| `make test-reset` | Drop and recreate schema | +| `make test-migrate` | Execute SQL migrations | +| `make test` | Run Jest test suite | + +--- + +## End-to-End Tests + +E2E tests validate HTTP behavior through the NestJS application layer. + +**Targets:** + +* Controllers +* Use cases +* Serialization +* HTTP error mapping + +These tests verify that domain and infrastructure layers integrate correctly at the application boundary. + +--- + +## Future Improvements + +* Property-based testing for reservation time-slot edge cases +* High-load concurrency stress testing +* CI-level performance thresholds for critical paths diff --git a/jest.config.ts b/jest.config.ts index af6633f..504be51 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,9 +1,7 @@ import type { Config } from 'jest'; const config: Config = { - preset: 'ts-jest', - testEnvironment: 'node', - globalSetup: '/test/setup/global-setup.ts', + maxWorkers: 1, moduleNameMapper: { '^@domain/(.*)$': '/src/domain/$1', '^@application/(.*)$': '/src/application/$1', @@ -11,6 +9,8 @@ const config: Config = { '^@http/(.*)$': '/src/http/$1', '^@test/(.*)$': '/test/$1', }, + preset: 'ts-jest', + testEnvironment: 'node', }; export default config; diff --git a/package.json b/package.json index f8fe27b..959591f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "@types/pg": "^8.16.0", "@types/supertest": "^6.0.2", "dotenv": "^17.2.3", - "dotenv-cli": "^11.0.0", "drizzle-kit": "^0.31.8", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c022050..380cfc9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,25 +10,25 @@ importers: dependencies: '@nestjs/common': specifier: ^11.0.1 - version: 11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: ^4.0.2 - version: 4.0.2(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.3(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.1 - version: 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.11)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.14)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': specifier: ^11.0.1 - version: 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.11) + version: 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14) argon2: specifier: ^0.44.0 version: 0.44.0 drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@types/pg@8.16.0)(pg@8.16.3) + version: 0.45.1(@types/pg@8.16.0)(pg@8.19.0) pg: specifier: ^8.16.3 - version: 8.16.3 + version: 8.19.0 reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -38,19 +38,19 @@ importers: devDependencies: '@eslint/eslintrc': specifier: ^3.2.0 - version: 3.3.3 + version: 3.3.4 '@eslint/js': specifier: ^9.18.0 - version: 9.39.2 + version: 9.39.3 '@nestjs/cli': specifier: ^11.0.0 - version: 11.0.14(@types/node@22.19.5)(esbuild@0.25.12) + version: 11.0.16(@types/node@22.19.13)(esbuild@0.25.12) '@nestjs/schematics': specifier: ^11.0.0 version: 11.0.9(chokidar@4.0.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.0.1 - version: 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.11)(@nestjs/platform-express@11.1.11) + version: 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14)(@nestjs/platform-express@11.1.14) '@types/express': specifier: ^5.0.0 version: 5.0.6 @@ -59,7 +59,7 @@ importers: version: 30.0.0 '@types/node': specifier: ^22.10.7 - version: 22.19.5 + version: 22.19.13 '@types/pg': specifier: ^8.16.0 version: 8.16.0 @@ -68,34 +68,31 @@ importers: version: 6.0.3 dotenv: specifier: ^17.2.3 - version: 17.2.3 - dotenv-cli: - specifier: ^11.0.0 - version: 11.0.0 + version: 17.3.1 drizzle-kit: specifier: ^0.31.8 - version: 0.31.8 + version: 0.31.9 eslint: specifier: ^9.18.0 - version: 9.39.2 + version: 9.39.3 eslint-config-prettier: specifier: ^10.0.1 - version: 10.1.8(eslint@9.39.2) + version: 10.1.8(eslint@9.39.3) eslint-plugin-prettier: specifier: ^5.2.2 - version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2))(eslint@9.39.2)(prettier@3.7.4) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.3))(eslint@9.39.3)(prettier@3.8.1) eslint-plugin-simple-import-sort: specifier: ^12.1.1 - version: 12.1.1(eslint@9.39.2) + version: 12.1.1(eslint@9.39.3) globals: specifier: ^16.0.0 version: 16.5.0 jest: specifier: ^30.0.0 - version: 30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + version: 30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) prettier: specifier: ^3.4.2 - version: 3.7.4 + version: 3.8.1 source-map-support: specifier: ^0.5.21 version: 0.5.21 @@ -104,13 +101,13 @@ importers: version: 7.2.2 ts-jest: specifier: ^29.2.5 - version: 29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(esbuild@0.25.12)(jest-util@30.2.0)(jest@30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(esbuild@0.25.12)(jest-util@30.2.0)(jest@30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)))(typescript@5.9.3) ts-loader: specifier: ^9.5.2 - version: 9.5.4(typescript@5.9.3)(webpack@5.103.0(esbuild@0.25.12)) + version: 9.5.4(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.19.5)(typescript@5.9.3) + version: 10.9.2(@types/node@22.19.13)(typescript@5.9.3) tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 @@ -119,7 +116,7 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.20.0 - version: 8.53.0(eslint@9.39.2)(typescript@5.9.3) + version: 8.56.1(eslint@9.39.3)(typescript@5.9.3) packages: @@ -154,20 +151,20 @@ packages: resolution: {integrity: sha512-J4Jarr0SohdrHcb40gTL4wGPCQ952IMWF1G/MSAQfBAPvA9ZKApYhpxcY7PmehVePve+ujpus1dGsJ7dPxz8Kg==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@babel/code-frame@7.28.6': - resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.6': - resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.6': - resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.6': - resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.28.6': @@ -208,8 +205,8 @@ packages: resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.6': - resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true @@ -308,12 +305,12 @@ packages: resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.6': - resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.6': - resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -663,12 +660,12 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + '@eslint/eslintrc@3.3.4': + resolution: {integrity: sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + '@eslint/js@9.39.3': + resolution: {integrity: sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -838,14 +835,6 @@ packages: '@types/node': optional: true - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -969,8 +958,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@nestjs/cli@11.0.14': - resolution: {integrity: sha512-YwP03zb5VETTwelXU+AIzMVbEZKk/uxJL+z9pw0mdG9ogAtqZ6/mpmIM4nEq/NU8D0a7CBRLcMYUmWW/55pfqw==} + '@nestjs/cli@11.0.16': + resolution: {integrity: sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==} engines: {node: '>= 20.11'} hasBin: true peerDependencies: @@ -982,8 +971,8 @@ packages: '@swc/core': optional: true - '@nestjs/common@11.1.11': - resolution: {integrity: sha512-R/+A8XFqLgN8zNs2twhrOaE7dJbRQhdPX3g46am4RT/x8xGLqDphrXkUIno4cGUZHxbczChBAaAPTdPv73wDZA==} + '@nestjs/common@11.1.14': + resolution: {integrity: sha512-IN/tlqd7Nl9gl6f0jsWEuOrQDaCI9vHzxv0fisHysfBQzfQIkqlv5A7w4Qge02BUQyczXT9HHPgHtWHCxhjRng==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -995,14 +984,14 @@ packages: class-validator: optional: true - '@nestjs/config@4.0.2': - resolution: {integrity: sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==} + '@nestjs/config@4.0.3': + resolution: {integrity: sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==} peerDependencies: '@nestjs/common': ^10.0.0 || ^11.0.0 rxjs: ^7.1.0 - '@nestjs/core@11.1.11': - resolution: {integrity: sha512-H9i+zT3RvHi7tDc+lCmWHJ3ustXveABCr+Vcpl96dNOxgmrx4elQSTC4W93Mlav2opfLV+p0UTHY6L+bpUA4zA==} + '@nestjs/core@11.1.14': + resolution: {integrity: sha512-7OXPPMoDr6z+5NkoQKu4hOhfjz/YYqM3bNilPqv1WVFWrzSmuNXxvhbX69YMmNmRYascPXiwESqf5jJdjKXEww==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -1019,8 +1008,8 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/platform-express@11.1.11': - resolution: {integrity: sha512-kyABSskdMRIAMWL0SlbwtDy4yn59RL4HDdwHDz/fxWuv7/53YP8Y2DtV3/sHqY5Er0msMVTZrM38MjqXhYL7gw==} + '@nestjs/platform-express@11.1.14': + resolution: {integrity: sha512-Fs+/j+mBSBSXErOQJ/YdUn/HqJGSJ4pGfiJyYOyz04l42uNVnqEakvu1kXLbxMabR6vd6/h9d6Bi4tso9p7o4Q==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -1030,8 +1019,8 @@ packages: peerDependencies: typescript: '>=4.8.2' - '@nestjs/testing@11.1.11': - resolution: {integrity: sha512-Po2aZKXlxuySDEh3Gi05LJ7/BtfTAPRZ3KPTrbpNrTmgGr3rFgEGYpQwN50wXYw0pywoICiFLZSZ/qXsplf6NA==} + '@nestjs/testing@11.1.14': + resolution: {integrity: sha512-cQxX0ronsTbpfHz8/LYOVWXxoTxv6VoxrnuZoQaVX7QV2PSMqxWE7/9jSQR0GcqAFUEmFP34c6EJqfkjfX/k4Q==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -1067,8 +1056,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@sinclair/typebox@0.34.47': - resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} @@ -1155,8 +1144,8 @@ packages: '@types/methods@1.1.4': resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} - '@types/node@22.19.5': - resolution: {integrity: sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==} + '@types/node@22.19.13': + resolution: {integrity: sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==} '@types/pg@8.16.0': resolution: {integrity: sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==} @@ -1188,63 +1177,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.53.0': - resolution: {integrity: sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==} + '@typescript-eslint/eslint-plugin@8.56.1': + resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.53.0 - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/parser': ^8.56.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.53.0': - resolution: {integrity: sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==} + '@typescript-eslint/parser@8.56.1': + resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.53.0': - resolution: {integrity: sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==} + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.53.0': - resolution: {integrity: sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==} + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.53.0': - resolution: {integrity: sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==} + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.53.0': - resolution: {integrity: sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==} + '@typescript-eslint/type-utils@8.56.1': + resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.53.0': - resolution: {integrity: sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==} + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.53.0': - resolution: {integrity: sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==} + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.53.0': - resolution: {integrity: sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==} + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.53.0': - resolution: {integrity: sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==} + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -1411,12 +1400,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -1446,12 +1435,15 @@ packages: peerDependencies: ajv: ^8.8.2 - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -1541,11 +1533,16 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.14: - resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} hasBin: true bl@4.1.0: @@ -1561,6 +1558,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1611,8 +1612,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001764: - resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + caniuse-lite@1.0.30001774: + resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1633,8 +1634,8 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} cjs-module-lexer@2.2.0: @@ -1732,8 +1733,8 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} cosmiconfig@8.3.6: @@ -1799,26 +1800,14 @@ packages: dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} - dotenv-cli@11.0.0: - resolution: {integrity: sha512-r5pA8idbk7GFWuHEU7trSTflWcdBpQEK+Aw17UrSHjS6CReuhrrPcyC3zcQBPQvhArRHnBo/h6eLH1fkCvNlww==} - hasBin: true - - dotenv-expand@12.0.1: - resolution: {integrity: sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==} - engines: {node: '>=12'} - dotenv-expand@12.0.3: resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==} engines: {node: '>=12'} - dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} - engines: {node: '>=12'} - dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -1827,8 +1816,12 @@ packages: resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} - drizzle-kit@0.31.8: - resolution: {integrity: sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg==} + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + engines: {node: '>=12'} + + drizzle-kit@0.31.9: + resolution: {integrity: sha512-GViD3IgsXn7trFyBUUHyTFBpH/FsHTxYJ66qdbVggxef4UBPHRYxQaRzYLTuekYnk9i5FIEL9pbBIwMqX/Uwrg==} hasBin: true drizzle-orm@0.45.1: @@ -1933,8 +1926,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-to-chromium@1.5.302: + resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -1950,8 +1943,8 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} error-ex@1.3.4: @@ -1965,8 +1958,8 @@ 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-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -2012,8 +2005,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-prettier@5.5.4: - resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + eslint-plugin-prettier@5.5.5: + resolution: {integrity: sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -2047,8 +2040,12 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.2: - resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.3: + resolution: {integrity: sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -2144,8 +2141,8 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - file-type@21.2.0: - resolution: {integrity: sha512-vCYBgFOrJQLoTzDyAXAL/RFfKnXXpUYt4+tipVy26nJJhT7ftgGETf2tAQF59EEL61i3MrorV/PG6tf7LJK7eg==} + file-type@21.3.0: + resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} engines: {node: '>=20'} fill-range@7.1.1: @@ -2240,8 +2237,8 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} @@ -2252,6 +2249,7 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@13.0.0: @@ -2260,7 +2258,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} @@ -2626,8 +2624,8 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} @@ -2636,8 +2634,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.4: - resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -2712,22 +2710,22 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} + minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} mkdirp@0.5.6: @@ -2866,9 +2864,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -2877,30 +2875,30 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pg-cloudflare@1.2.7: - resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} + pg-cloudflare@1.3.0: + resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - pg-connection-string@2.9.1: - resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} + pg-connection-string@2.11.0: + resolution: {integrity: sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-pool@3.10.1: - resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==} + pg-pool@3.12.0: + resolution: {integrity: sha512-eIJ0DES8BLaziFHW7VgJEBPi5hg3Nyng5iKpYtj3wbcAUV9A1wLgWiY7ajf/f/oO1wfxt83phXPY8Emztg7ITg==} peerDependencies: pg: '>=8.0' - pg-protocol@1.10.3: - resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} + pg-protocol@1.12.0: + resolution: {integrity: sha512-uOANXNRACNdElMXJ0tPz6RBM0XQ61nONGAwlt8da5zs/iUOOCLBQOHSXnrC6fMsvtjxbOJrZZl5IScGv+7mpbg==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.16.3: - resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} + pg@8.19.0: + resolution: {integrity: sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==} engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -2962,8 +2960,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true @@ -2982,8 +2980,8 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - qs@6.14.1: - resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} randombytes@2.1.0: @@ -3066,8 +3064,8 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true @@ -3176,8 +3174,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@3.0.0: @@ -3220,8 +3218,8 @@ packages: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} tapable@2.3.0: @@ -3244,8 +3242,8 @@ packages: uglify-js: optional: true - terser@5.44.1: - resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} engines: {node: '>=10'} hasBin: true @@ -3364,11 +3362,11 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.53.0: - resolution: {integrity: sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw==} + typescript-eslint@8.56.1: + resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' typescript@5.9.3: @@ -3429,8 +3427,8 @@ packages: walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - watchpack@2.5.0: - resolution: {integrity: sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} wcwidth@1.0.1: @@ -3440,12 +3438,12 @@ packages: resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} engines: {node: '>=6'} - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} engines: {node: '>=10.13.0'} - webpack@5.103.0: - resolution: {integrity: sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==} + webpack@5.104.1: + resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -3540,11 +3538,11 @@ snapshots: optionalDependencies: chokidar: 4.0.3 - '@angular-devkit/schematics-cli@19.2.19(@types/node@22.19.5)(chokidar@4.0.3)': + '@angular-devkit/schematics-cli@19.2.19(@types/node@22.19.13)(chokidar@4.0.3)': dependencies: '@angular-devkit/core': 19.2.19(chokidar@4.0.3) '@angular-devkit/schematics': 19.2.19(chokidar@4.0.3) - '@inquirer/prompts': 7.3.2(@types/node@22.19.5) + '@inquirer/prompts': 7.3.2(@types/node@22.19.13) ansi-colors: 4.1.3 symbol-observable: 4.0.0 yargs-parser: 21.1.1 @@ -3572,25 +3570,25 @@ snapshots: transitivePeerDependencies: - chokidar - '@babel/code-frame@7.28.6': + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.6': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.6': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) '@babel/helpers': 7.28.6 - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3600,17 +3598,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.6': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.6 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 @@ -3620,17 +3618,17 @@ snapshots: '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -3645,116 +3643,116 @@ snapshots: '@babel/helpers@7.28.6': dependencies: '@babel/template': 7.28.6 - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.6': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.6)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.6)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.6)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.6)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.6)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.6)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.6)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.6)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.6)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.6)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.6)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.6)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.6)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.6)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.6': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.6': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -3798,7 +3796,7 @@ snapshots: '@esbuild-kit/esm-loader@2.6.5': dependencies: '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.6 '@esbuild/aix-ppc64@0.25.12': optional: true @@ -3944,9 +3942,9 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2)': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.3)': dependencies: - eslint: 9.39.2 + eslint: 9.39.3 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -3955,7 +3953,7 @@ snapshots: dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -3967,21 +3965,21 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.4': dependencies: - ajv: 6.12.6 + ajv: 6.14.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.39.2': {} + '@eslint/js@9.39.3': {} '@eslint/object-schema@2.1.7': {} @@ -4003,155 +4001,149 @@ snapshots: '@inquirer/ansi@1.0.2': {} - '@inquirer/checkbox@4.3.2(@types/node@22.19.5)': + '@inquirer/checkbox@4.3.2(@types/node@22.19.13)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/type': 3.0.10(@types/node@22.19.13) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/confirm@5.1.21(@types/node@22.19.5)': + '@inquirer/confirm@5.1.21(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/core@10.3.2(@types/node@22.19.5)': + '@inquirer/core@10.3.2(@types/node@22.19.13)': dependencies: '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/type': 3.0.10(@types/node@22.19.13) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/editor@4.2.23(@types/node@22.19.5)': + '@inquirer/editor@4.2.23(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/external-editor': 1.0.3(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/external-editor': 1.0.3(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/expand@4.0.23(@types/node@22.19.5)': + '@inquirer/expand@4.0.23(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/external-editor@1.0.3(@types/node@22.19.5)': + '@inquirer/external-editor@1.0.3(@types/node@22.19.13)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@inquirer/figures@1.0.15': {} - '@inquirer/input@4.3.1(@types/node@22.19.5)': + '@inquirer/input@4.3.1(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/number@3.0.23(@types/node@22.19.5)': + '@inquirer/number@3.0.23(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/password@4.0.23(@types/node@22.19.5)': + '@inquirer/password@4.0.23(@types/node@22.19.13)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 - - '@inquirer/prompts@7.10.1(@types/node@22.19.5)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.5) - '@inquirer/confirm': 5.1.21(@types/node@22.19.5) - '@inquirer/editor': 4.2.23(@types/node@22.19.5) - '@inquirer/expand': 4.0.23(@types/node@22.19.5) - '@inquirer/input': 4.3.1(@types/node@22.19.5) - '@inquirer/number': 3.0.23(@types/node@22.19.5) - '@inquirer/password': 4.0.23(@types/node@22.19.5) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.5) - '@inquirer/search': 3.2.2(@types/node@22.19.5) - '@inquirer/select': 4.4.2(@types/node@22.19.5) + '@types/node': 22.19.13 + + '@inquirer/prompts@7.10.1(@types/node@22.19.13)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@22.19.13) + '@inquirer/confirm': 5.1.21(@types/node@22.19.13) + '@inquirer/editor': 4.2.23(@types/node@22.19.13) + '@inquirer/expand': 4.0.23(@types/node@22.19.13) + '@inquirer/input': 4.3.1(@types/node@22.19.13) + '@inquirer/number': 3.0.23(@types/node@22.19.13) + '@inquirer/password': 4.0.23(@types/node@22.19.13) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.13) + '@inquirer/search': 3.2.2(@types/node@22.19.13) + '@inquirer/select': 4.4.2(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 - - '@inquirer/prompts@7.3.2(@types/node@22.19.5)': - dependencies: - '@inquirer/checkbox': 4.3.2(@types/node@22.19.5) - '@inquirer/confirm': 5.1.21(@types/node@22.19.5) - '@inquirer/editor': 4.2.23(@types/node@22.19.5) - '@inquirer/expand': 4.0.23(@types/node@22.19.5) - '@inquirer/input': 4.3.1(@types/node@22.19.5) - '@inquirer/number': 3.0.23(@types/node@22.19.5) - '@inquirer/password': 4.0.23(@types/node@22.19.5) - '@inquirer/rawlist': 4.1.11(@types/node@22.19.5) - '@inquirer/search': 3.2.2(@types/node@22.19.5) - '@inquirer/select': 4.4.2(@types/node@22.19.5) + '@types/node': 22.19.13 + + '@inquirer/prompts@7.3.2(@types/node@22.19.13)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@22.19.13) + '@inquirer/confirm': 5.1.21(@types/node@22.19.13) + '@inquirer/editor': 4.2.23(@types/node@22.19.13) + '@inquirer/expand': 4.0.23(@types/node@22.19.13) + '@inquirer/input': 4.3.1(@types/node@22.19.13) + '@inquirer/number': 3.0.23(@types/node@22.19.13) + '@inquirer/password': 4.0.23(@types/node@22.19.13) + '@inquirer/rawlist': 4.1.11(@types/node@22.19.13) + '@inquirer/search': 3.2.2(@types/node@22.19.13) + '@inquirer/select': 4.4.2(@types/node@22.19.13) optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/rawlist@4.1.11(@types/node@22.19.5)': + '@inquirer/rawlist@4.1.11(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) + '@inquirer/type': 3.0.10(@types/node@22.19.13) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/search@3.2.2(@types/node@22.19.5)': + '@inquirer/search@3.2.2(@types/node@22.19.13)': dependencies: - '@inquirer/core': 10.3.2(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/type': 3.0.10(@types/node@22.19.13) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/select@4.4.2(@types/node@22.19.5)': + '@inquirer/select@4.4.2(@types/node@22.19.13)': dependencies: '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2(@types/node@22.19.5) + '@inquirer/core': 10.3.2(@types/node@22.19.13) '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@22.19.5) + '@inquirer/type': 3.0.10(@types/node@22.19.13) yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 - '@inquirer/type@3.0.10(@types/node@22.19.5)': + '@inquirer/type@3.0.10(@types/node@22.19.13)': optionalDependencies: - '@types/node': 22.19.5 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 + '@types/node': 22.19.13 '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 @@ -4169,13 +4161,13 @@ snapshots: '@jest/console@30.2.0': dependencies: '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 chalk: 4.1.2 jest-message-util: 30.2.0 jest-util: 30.2.0 slash: 3.0.0 - '@jest/core@30.2.0(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3))': + '@jest/core@30.2.0(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3))': dependencies: '@jest/console': 30.2.0 '@jest/pattern': 30.0.1 @@ -4183,14 +4175,14 @@ snapshots: '@jest/test-result': 30.2.0 '@jest/transform': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 4.3.1 + ci-info: 4.4.0 exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.2.0 - jest-config: 30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + jest-config: 30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) jest-haste-map: 30.2.0 jest-message-util: 30.2.0 jest-regex-util: 30.0.1 @@ -4217,7 +4209,7 @@ snapshots: dependencies: '@jest/fake-timers': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 jest-mock: 30.2.0 '@jest/expect-utils@30.2.0': @@ -4235,7 +4227,7 @@ snapshots: dependencies: '@jest/types': 30.2.0 '@sinonjs/fake-timers': 13.0.5 - '@types/node': 22.19.5 + '@types/node': 22.19.13 jest-message-util: 30.2.0 jest-mock: 30.2.0 jest-util: 30.2.0 @@ -4253,7 +4245,7 @@ snapshots: '@jest/pattern@30.0.1': dependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 jest-regex-util: 30.0.1 '@jest/reporters@30.2.0': @@ -4264,7 +4256,7 @@ snapshots: '@jest/transform': 30.2.0 '@jest/types': 30.2.0 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 22.19.5 + '@types/node': 22.19.13 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit-x: 0.2.2 @@ -4286,7 +4278,7 @@ snapshots: '@jest/schemas@30.0.5': dependencies: - '@sinclair/typebox': 0.34.47 + '@sinclair/typebox': 0.34.48 '@jest/snapshot-utils@30.2.0': dependencies: @@ -4317,7 +4309,7 @@ snapshots: '@jest/transform@30.2.0': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@jest/types': 30.2.0 '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 7.0.1 @@ -4341,7 +4333,7 @@ snapshots: '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -4383,25 +4375,25 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@nestjs/cli@11.0.14(@types/node@22.19.5)(esbuild@0.25.12)': + '@nestjs/cli@11.0.16(@types/node@22.19.13)(esbuild@0.25.12)': dependencies: '@angular-devkit/core': 19.2.19(chokidar@4.0.3) '@angular-devkit/schematics': 19.2.19(chokidar@4.0.3) - '@angular-devkit/schematics-cli': 19.2.19(@types/node@22.19.5)(chokidar@4.0.3) - '@inquirer/prompts': 7.10.1(@types/node@22.19.5) + '@angular-devkit/schematics-cli': 19.2.19(@types/node@22.19.13)(chokidar@4.0.3) + '@inquirer/prompts': 7.10.1(@types/node@22.19.13) '@nestjs/schematics': 11.0.9(chokidar@4.0.3)(typescript@5.9.3) ansis: 4.2.0 chokidar: 4.0.3 cli-table3: 0.6.5 commander: 4.1.1 - fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.103.0(esbuild@0.25.12)) + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)) glob: 13.0.0 node-emoji: 1.11.0 ora: 5.4.1 tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 typescript: 5.9.3 - webpack: 5.103.0(esbuild@0.25.12) + webpack: 5.104.1(esbuild@0.25.12) webpack-node-externals: 3.0.0 transitivePeerDependencies: - '@types/node' @@ -4409,9 +4401,9 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.2.0 + file-type: 21.3.0 iterare: 1.2.1 load-esm: 1.0.3 reflect-metadata: 0.2.2 @@ -4421,17 +4413,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/config@4.0.2(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@nestjs/config@4.0.3(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2) - dotenv: 16.4.7 - dotenv-expand: 12.0.1 - lodash: 4.17.21 + '@nestjs/common': 11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2) + dotenv: 17.2.3 + dotenv-expand: 12.0.3 + lodash: 4.17.23 rxjs: 7.8.2 - '@nestjs/core@11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.11)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.14)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -4441,13 +4433,13 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.11) + '@nestjs/platform-express': 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14) - '@nestjs/platform-express@11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.11)': + '@nestjs/platform-express@11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14)': dependencies: - '@nestjs/common': 11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.11)(reflect-metadata@0.2.2)(rxjs@7.8.2) - cors: 2.8.5 + '@nestjs/common': 11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.14)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cors: 2.8.6 express: 5.2.1 multer: 2.0.2 path-to-regexp: 8.3.0 @@ -4466,13 +4458,13 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/testing@11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.11)(@nestjs/platform-express@11.1.11)': + '@nestjs/testing@11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14)(@nestjs/platform-express@11.1.14)': dependencies: - '@nestjs/common': 11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.11)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.14)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.11(@nestjs/common@11.1.11(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.11) + '@nestjs/platform-express': 11.1.14(@nestjs/common@11.1.14(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.14) '@noble/hashes@1.8.0': {} @@ -4491,7 +4483,7 @@ snapshots: '@pkgr/core@0.2.9': {} - '@sinclair/typebox@0.34.47': {} + '@sinclair/typebox@0.34.48': {} '@sinonjs/commons@3.0.1': dependencies: @@ -4525,33 +4517,33 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@types/connect@3.4.38': dependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@types/cookiejar@2.1.5': {} @@ -4569,7 +4561,7 @@ snapshots: '@types/express-serve-static-core@5.1.1': dependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -4601,14 +4593,14 @@ snapshots: '@types/methods@1.1.4': {} - '@types/node@22.19.5': + '@types/node@22.19.13': dependencies: undici-types: 6.21.0 '@types/pg@8.16.0': dependencies: - '@types/node': 22.19.5 - pg-protocol: 1.10.3 + '@types/node': 22.19.13 + pg-protocol: 1.12.0 pg-types: 2.2.0 '@types/qs@6.14.0': {} @@ -4617,12 +4609,12 @@ snapshots: '@types/send@1.2.1': dependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@types/stack-utils@2.0.3': {} @@ -4630,7 +4622,7 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 22.19.5 + '@types/node': 22.19.13 form-data: 4.0.5 '@types/supertest@6.0.3': @@ -4644,15 +4636,15 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3)(typescript@5.9.3))(eslint@9.39.3)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.53.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.53.0 - eslint: 9.39.2 + '@typescript-eslint/parser': 8.56.1(eslint@9.39.3)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.3)(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.3)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.1 + eslint: 9.39.3 ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -4660,80 +4652,80 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/parser@8.56.1(eslint@9.39.3)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.1 debug: 4.4.3 - eslint: 9.39.2 + eslint: 9.39.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.53.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.53.0': + '@typescript-eslint/scope-manager@8.56.1': dependencies: - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 - '@typescript-eslint/tsconfig-utils@8.53.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.53.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.56.1(eslint@9.39.3)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.3)(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.2 + eslint: 9.39.3 ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.53.0': {} + '@typescript-eslint/types@8.56.1': {} - '@typescript-eslint/typescript-estree@8.53.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.53.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.3 + minimatch: 10.2.4 + semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.53.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/utils@8.56.1(eslint@9.39.3)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - eslint: 9.39.2 + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + eslint: 9.39.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.53.0': + '@typescript-eslint/visitor-keys@8.56.1': dependencies: - '@typescript-eslint/types': 8.53.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.56.1 + eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.0': {} @@ -4881,38 +4873,38 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-import-phases@1.0.4(acorn@8.15.0): + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-walk@8.3.4: + acorn-walk@8.3.5: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} - ajv-formats@2.1.1(ajv@8.17.1): + ajv-formats@2.1.1(ajv@8.18.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.18.0 ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 - ajv-keywords@3.5.2(ajv@6.12.6): + ajv-keywords@3.5.2(ajv@6.14.0): dependencies: - ajv: 6.12.6 + ajv: 6.14.0 - ajv-keywords@5.1.0(ajv@8.17.1): + ajv-keywords@5.1.0(ajv@8.18.0): dependencies: - ajv: 8.17.1 + ajv: 8.18.0 fast-deep-equal: 3.1.3 - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -4926,6 +4918,13 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -4974,13 +4973,13 @@ snapshots: asynckit@0.4.0: {} - babel-jest@30.2.0(@babel/core@7.28.6): + babel-jest@30.2.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@jest/transform': 30.2.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 7.0.1 - babel-preset-jest: 30.2.0(@babel/core@7.28.6) + babel-preset-jest: 30.2.0(@babel/core@7.29.0) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -5001,36 +5000,38 @@ snapshots: dependencies: '@types/babel__core': 7.20.5 - babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.6): - dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.6) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.6) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.6) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.6) - '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.28.6) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.6) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.6) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.6) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.6) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.6) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.6) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.6) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.6) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.6) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.6) - - babel-preset-jest@30.2.0(@babel/core@7.28.6): - dependencies: - '@babel/core': 7.28.6 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@30.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 babel-plugin-jest-hoist: 30.2.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.6) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + base64-js@1.5.1: {} - baseline-browser-mapping@2.9.14: {} + baseline-browser-mapping@2.10.0: {} bl@4.1.0: dependencies: @@ -5046,7 +5047,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.14.1 + qs: 6.15.0 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -5061,15 +5062,19 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.3: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.14 - caniuse-lite: 1.0.30001764 - electron-to-chromium: 1.5.267 + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001774 + electron-to-chromium: 1.5.302 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -5110,7 +5115,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001764: {} + caniuse-lite@1.0.30001774: {} chalk@4.1.2: dependencies: @@ -5127,7 +5132,7 @@ snapshots: chrome-trace-event@1.0.4: {} - ci-info@4.3.1: {} + ci-info@4.4.0: {} cjs-module-lexer@2.2.0: {} @@ -5204,7 +5209,7 @@ snapshots: core-util-is@1.0.3: {} - cors@2.8.5: + cors@2.8.6: dependencies: object-assign: 4.1.1 vary: 1.1.2 @@ -5256,30 +5261,19 @@ snapshots: asap: 2.0.6 wrappy: 1.0.2 - diff@4.0.2: {} - - dotenv-cli@11.0.0: - dependencies: - cross-spawn: 7.0.6 - dotenv: 17.2.3 - dotenv-expand: 12.0.3 - minimist: 1.2.8 - - dotenv-expand@12.0.1: - dependencies: - dotenv: 16.6.1 + diff@4.0.4: {} dotenv-expand@12.0.3: dependencies: dotenv: 16.6.1 - dotenv@16.4.7: {} - dotenv@16.6.1: {} dotenv@17.2.3: {} - drizzle-kit@0.31.8: + dotenv@17.3.1: {} + + drizzle-kit@0.31.9: dependencies: '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 @@ -5288,10 +5282,10 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.45.1(@types/pg@8.16.0)(pg@8.16.3): + drizzle-orm@0.45.1(@types/pg@8.16.0)(pg@8.19.0): optionalDependencies: '@types/pg': 8.16.0 - pg: 8.16.3 + pg: 8.19.0 dunder-proto@1.0.1: dependencies: @@ -5303,7 +5297,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.302: {} emittery@0.13.1: {} @@ -5313,7 +5307,7 @@ snapshots: encodeurl@2.0.0: {} - enhanced-resolve@5.18.4: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -5326,7 +5320,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: dependencies: @@ -5408,23 +5402,23 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@9.39.2): + eslint-config-prettier@10.1.8(eslint@9.39.3): dependencies: - eslint: 9.39.2 + eslint: 9.39.3 - eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2))(eslint@9.39.2)(prettier@3.7.4): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.3))(eslint@9.39.3)(prettier@3.8.1): dependencies: - eslint: 9.39.2 - prettier: 3.7.4 + eslint: 9.39.3 + prettier: 3.8.1 prettier-linter-helpers: 1.0.1 - synckit: 0.11.11 + synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@9.39.2) + eslint-config-prettier: 10.1.8(eslint@9.39.3) - eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.2): + eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.3): dependencies: - eslint: 9.39.2 + eslint: 9.39.3 eslint-scope@5.1.1: dependencies: @@ -5440,21 +5434,23 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2: + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.3: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.2 + '@eslint/eslintrc': 3.3.4 + '@eslint/js': 9.39.3 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -5473,7 +5469,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 transitivePeerDependencies: @@ -5481,8 +5477,8 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 esprima@4.0.1: {} @@ -5550,7 +5546,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.1 + qs: 6.15.0 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 @@ -5585,7 +5581,7 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-type@21.2.0: + file-type@21.3.0: dependencies: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.4 @@ -5631,22 +5627,22 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.103.0(esbuild@0.25.12)): + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)): dependencies: - '@babel/code-frame': 7.28.6 + '@babel/code-frame': 7.29.0 chalk: 4.1.2 chokidar: 4.0.3 cosmiconfig: 8.3.6(typescript@5.9.3) deepmerge: 4.3.1 fs-extra: 10.1.0 memfs: 3.5.3 - minimatch: 3.1.2 + minimatch: 3.1.5 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.7.3 + semver: 7.7.4 tapable: 2.3.0 typescript: 5.9.3 - webpack: 5.103.0(esbuild@0.25.12) + webpack: 5.104.1(esbuild@0.25.12) form-data@4.0.5: dependencies: @@ -5707,7 +5703,7 @@ snapshots: get-stream@6.0.1: {} - get-tsconfig@4.13.0: + get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -5721,23 +5717,23 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 + minimatch: 9.0.9 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 glob@13.0.0: dependencies: - minimatch: 10.1.1 - minipass: 7.1.2 - path-scurry: 2.0.1 + minimatch: 10.2.4 + minipass: 7.1.3 + path-scurry: 2.0.2 glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 @@ -5841,11 +5837,11 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.28.6 - '@babel/parser': 7.28.6 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -5888,7 +5884,7 @@ snapshots: '@jest/expect': 30.2.0 '@jest/test-result': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 chalk: 4.1.2 co: 4.6.0 dedent: 1.7.1 @@ -5908,15 +5904,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)): + jest-cli@30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)): dependencies: - '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) '@jest/test-result': 30.2.0 '@jest/types': 30.2.0 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + jest-config: 30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) jest-util: 30.2.0 jest-validate: 30.2.0 yargs: 17.7.2 @@ -5927,16 +5923,16 @@ snapshots: - supports-color - ts-node - jest-config@30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)): + jest-config@30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)): dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@jest/get-type': 30.1.0 '@jest/pattern': 30.0.1 '@jest/test-sequencer': 30.2.0 '@jest/types': 30.2.0 - babel-jest: 30.2.0(@babel/core@7.28.6) + babel-jest: 30.2.0(@babel/core@7.29.0) chalk: 4.1.2 - ci-info: 4.3.1 + ci-info: 4.4.0 deepmerge: 4.3.1 glob: 10.5.0 graceful-fs: 4.2.11 @@ -5954,9 +5950,9 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 esbuild-register: 3.6.0(esbuild@0.25.12) - ts-node: 10.9.2(@types/node@22.19.5)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@22.19.13)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -5985,7 +5981,7 @@ snapshots: '@jest/environment': 30.2.0 '@jest/fake-timers': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 jest-mock: 30.2.0 jest-util: 30.2.0 jest-validate: 30.2.0 @@ -5993,7 +5989,7 @@ snapshots: jest-haste-map@30.2.0: dependencies: '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -6019,7 +6015,7 @@ snapshots: jest-message-util@30.2.0: dependencies: - '@babel/code-frame': 7.28.6 + '@babel/code-frame': 7.29.0 '@jest/types': 30.2.0 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -6032,7 +6028,7 @@ snapshots: jest-mock@30.2.0: dependencies: '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 jest-util: 30.2.0 jest-pnp-resolver@1.2.3(jest-resolve@30.2.0): @@ -6066,7 +6062,7 @@ snapshots: '@jest/test-result': 30.2.0 '@jest/transform': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 chalk: 4.1.2 emittery: 0.13.1 exit-x: 0.2.2 @@ -6095,7 +6091,7 @@ snapshots: '@jest/test-result': 30.2.0 '@jest/transform': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 chalk: 4.1.2 cjs-module-lexer: 2.2.0 collect-v8-coverage: 1.0.3 @@ -6115,17 +6111,17 @@ snapshots: jest-snapshot@30.2.0: dependencies: - '@babel/core': 7.28.6 - '@babel/generator': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) - '@babel/types': 7.28.6 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 '@jest/expect-utils': 30.2.0 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.2.0 '@jest/transform': 30.2.0 '@jest/types': 30.2.0 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.6) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) chalk: 4.1.2 expect: 30.2.0 graceful-fs: 4.2.11 @@ -6134,17 +6130,17 @@ snapshots: jest-message-util: 30.2.0 jest-util: 30.2.0 pretty-format: 30.2.0 - semver: 7.7.3 - synckit: 0.11.11 + semver: 7.7.4 + synckit: 0.11.12 transitivePeerDependencies: - supports-color jest-util@30.2.0: dependencies: '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 chalk: 4.1.2 - ci-info: 4.3.1 + ci-info: 4.4.0 graceful-fs: 4.2.11 picomatch: 4.0.3 @@ -6161,7 +6157,7 @@ snapshots: dependencies: '@jest/test-result': 30.2.0 '@jest/types': 30.2.0 - '@types/node': 22.19.5 + '@types/node': 22.19.13 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -6170,24 +6166,24 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@30.2.0: dependencies: - '@types/node': 22.19.5 + '@types/node': 22.19.13 '@ungap/structured-clone': 1.3.0 jest-util: 30.2.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)): + jest@30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)): dependencies: - '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + '@jest/core': 30.2.0(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) '@jest/types': 30.2.0 import-local: 3.2.0 - jest-cli: 30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + jest-cli: 30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -6257,7 +6253,7 @@ snapshots: lodash.merge@4.6.2: {} - lodash@4.17.21: {} + lodash@4.17.23: {} log-symbols@4.1.0: dependencies: @@ -6266,7 +6262,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.4: {} + lru-cache@11.2.6: {} lru-cache@5.1.1: dependencies: @@ -6278,7 +6274,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 make-error@1.3.6: {} @@ -6323,21 +6319,21 @@ snapshots: mimic-fn@2.1.0: {} - minimatch@10.1.1: + minimatch@10.2.4: dependencies: - '@isaacs/brace-expansion': 5.0.0 + brace-expansion: 5.0.3 - minimatch@3.1.2: + minimatch@3.1.5: dependencies: brace-expansion: 1.1.12 - minimatch@9.0.5: + minimatch@9.0.9: dependencies: brace-expansion: 2.0.2 minimist@1.2.8: {} - minipass@7.1.2: {} + minipass@7.1.3: {} mkdirp@0.5.6: dependencies: @@ -6371,7 +6367,7 @@ snapshots: node-emoji@1.11.0: dependencies: - lodash: 4.17.21 + lodash: 4.17.23 node-gyp-build@4.8.4: {} @@ -6448,7 +6444,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.28.6 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -6464,29 +6460,29 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 - path-scurry@2.0.1: + path-scurry@2.0.2: dependencies: - lru-cache: 11.2.4 - minipass: 7.1.2 + lru-cache: 11.2.6 + minipass: 7.1.3 path-to-regexp@8.3.0: {} path-type@4.0.0: {} - pg-cloudflare@1.2.7: + pg-cloudflare@1.3.0: optional: true - pg-connection-string@2.9.1: {} + pg-connection-string@2.11.0: {} pg-int8@1.0.1: {} - pg-pool@3.10.1(pg@8.16.3): + pg-pool@3.12.0(pg@8.19.0): dependencies: - pg: 8.16.3 + pg: 8.19.0 - pg-protocol@1.10.3: {} + pg-protocol@1.12.0: {} pg-types@2.2.0: dependencies: @@ -6496,15 +6492,15 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.16.3: + pg@8.19.0: dependencies: - pg-connection-string: 2.9.1 - pg-pool: 3.10.1(pg@8.16.3) - pg-protocol: 1.10.3 + pg-connection-string: 2.11.0 + pg-pool: 3.12.0(pg@8.19.0) + pg-protocol: 1.12.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: - pg-cloudflare: 1.2.7 + pg-cloudflare: 1.3.0 pgpass@1.0.5: dependencies: @@ -6542,7 +6538,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.7.4: {} + prettier@3.8.1: {} pretty-format@30.2.0: dependencies: @@ -6559,7 +6555,7 @@ snapshots: pure-rand@7.0.1: {} - qs@6.14.1: + qs@6.15.0: dependencies: side-channel: 1.1.0 @@ -6632,19 +6628,19 @@ snapshots: schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv: 8.18.0 + ajv-formats: 2.1.1(ajv@8.18.0) + ajv-keywords: 5.1.0(ajv@8.18.0) semver@6.3.1: {} - semver@7.7.3: {} + semver@7.7.4: {} send@1.2.1: dependencies: @@ -6760,7 +6756,7 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 string_decoder@1.3.0: dependencies: @@ -6770,7 +6766,7 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 @@ -6796,7 +6792,7 @@ snapshots: formidable: 3.5.4 methods: 1.1.2 mime: 2.6.0 - qs: 6.14.1 + qs: 6.15.0 transitivePeerDependencies: - supports-color @@ -6818,27 +6814,27 @@ snapshots: symbol-observable@4.0.0: {} - synckit@0.11.11: + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 tapable@2.3.0: {} - terser-webpack-plugin@5.3.16(esbuild@0.25.12)(webpack@5.103.0(esbuild@0.25.12)): + terser-webpack-plugin@5.3.16(esbuild@0.25.12)(webpack@5.104.1(esbuild@0.25.12)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - terser: 5.44.1 - webpack: 5.103.0(esbuild@0.25.12) + terser: 5.46.0 + webpack: 5.104.1(esbuild@0.25.12) optionalDependencies: esbuild: 0.25.12 - terser@5.44.1: + terser@5.46.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -6846,7 +6842,7 @@ snapshots: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 - minimatch: 3.1.2 + minimatch: 3.1.5 tinyglobby@0.2.15: dependencies: @@ -6871,50 +6867,50 @@ snapshots: dependencies: typescript: 5.9.3 - ts-jest@29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(esbuild@0.25.12)(jest-util@30.2.0)(jest@30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(esbuild@0.25.12)(jest-util@30.2.0)(jest@30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 30.2.0(@types/node@22.19.5)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3)) + jest: 30.2.0(@types/node@22.19.13)(esbuild-register@3.6.0(esbuild@0.25.12))(ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.3 + semver: 7.7.4 type-fest: 4.41.0 typescript: 5.9.3 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@jest/transform': 30.2.0 '@jest/types': 30.2.0 - babel-jest: 30.2.0(@babel/core@7.28.6) + babel-jest: 30.2.0(@babel/core@7.29.0) esbuild: 0.25.12 jest-util: 30.2.0 - ts-loader@9.5.4(typescript@5.9.3)(webpack@5.103.0(esbuild@0.25.12)): + ts-loader@9.5.4(typescript@5.9.3)(webpack@5.104.1(esbuild@0.25.12)): dependencies: chalk: 4.1.2 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.19.0 micromatch: 4.0.8 - semver: 7.7.3 + semver: 7.7.4 source-map: 0.7.6 typescript: 5.9.3 - webpack: 5.103.0(esbuild@0.25.12) + webpack: 5.104.1(esbuild@0.25.12) - ts-node@10.9.2(@types/node@22.19.5)(typescript@5.9.3): + ts-node@10.9.2(@types/node@22.19.13)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.19.5 - acorn: 8.15.0 - acorn-walk: 8.3.4 + '@types/node': 22.19.13 + acorn: 8.16.0 + acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 - diff: 4.0.2 + diff: 4.0.4 make-error: 1.3.6 typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 @@ -6923,7 +6919,7 @@ snapshots: tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.19.0 tapable: 2.3.0 tsconfig-paths: 4.2.0 @@ -6958,13 +6954,13 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.53.0(eslint@9.39.2)(typescript@5.9.3): + typescript-eslint@8.56.1(eslint@9.39.3)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/parser': 8.53.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2)(typescript@5.9.3) - eslint: 9.39.2 + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3)(typescript@5.9.3))(eslint@9.39.3)(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.1(eslint@9.39.3)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.39.3)(typescript@5.9.3) + eslint: 9.39.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -7036,7 +7032,7 @@ snapshots: dependencies: makeerror: 1.0.12 - watchpack@2.5.0: + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 @@ -7047,9 +7043,9 @@ snapshots: webpack-node-externals@3.0.0: {} - webpack-sources@3.3.3: {} + webpack-sources@3.3.4: {} - webpack@5.103.0(esbuild@0.25.12): + webpack@5.104.1(esbuild@0.25.12): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -7057,12 +7053,12 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.4 - es-module-lexer: 1.7.0 + enhanced-resolve: 5.19.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -7073,9 +7069,9 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(esbuild@0.25.12)(webpack@5.103.0(esbuild@0.25.12)) - watchpack: 2.5.0 - webpack-sources: 3.3.3 + terser-webpack-plugin: 5.3.16(esbuild@0.25.12)(webpack@5.104.1(esbuild@0.25.12)) + watchpack: 2.5.1 + webpack-sources: 3.3.4 transitivePeerDependencies: - '@swc/core' - esbuild @@ -7105,7 +7101,7 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrappy@1.0.2: {} diff --git a/src/infrastructure/barber/barber.drizzle-repository.ts b/src/infrastructure/barber/barber.drizzle-repository.ts index e243b25..640224e 100644 --- a/src/infrastructure/barber/barber.drizzle-repository.ts +++ b/src/infrastructure/barber/barber.drizzle-repository.ts @@ -4,7 +4,7 @@ import { eq } from 'drizzle-orm'; import { Barber } from '@domain/barber/barber.entity'; import { BarberRepository } from '@domain/barber/barber.repository'; -import { Database } from '@infrastructure/database/database.provider'; +import { DrizzleClient } from '@infrastructure/database/database.provider'; import { DATABASE } from '@infrastructure/database/database.token'; import { barbers } from '@infrastructure/database/schema/barber'; @@ -13,7 +13,7 @@ import { BarberMapper } from './barber.mapper'; export class BarberDrizzleRepository implements BarberRepository { constructor( @Inject(DATABASE) - private readonly db: Database, + private readonly db: DrizzleClient, ) {} async save(barber: Barber): Promise { diff --git a/src/infrastructure/database/database.provider.ts b/src/infrastructure/database/database.provider.ts index 6b718f2..2f23ab9 100644 --- a/src/infrastructure/database/database.provider.ts +++ b/src/infrastructure/database/database.provider.ts @@ -1,16 +1,42 @@ -import { drizzle } from 'drizzle-orm/node-postgres'; +import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres'; import { Pool } from 'pg'; -import { DatabaseUrlNotDefinedError } from './errors/database-url-not-defined.error'; import * as schema from './schema'; -export function createDatabase() { +let pool: Pool | null = null; +let db: NodePgDatabase | null = null; + +export function createDatabase(): NodePgDatabase { + if (db) return db; + const url = process.env.DATABASE_URL; - if (!url) throw new DatabaseUrlNotDefinedError(); + if (!url) throw new Error('DATABASE_URL not defined'); - const pool = new Pool({ connectionString: url }); + pool = new Pool({ + connectionString: url, + max: Number(process.env.DB_POOL_MAX ?? 10), + }); - return drizzle(pool, { schema }); + db = drizzle(pool, { schema }); + + return db; +} + +export async function closeDatabase() { + if (pool) { + await pool.end(); + pool = null; + db = null; + } } export type Database = ReturnType; + +export type Transaction = Parameters[0] extends ( + tx: infer T, + ...args: any[] +) => any + ? T + : never; + +export type DrizzleClient = Database | Transaction; diff --git a/src/infrastructure/database/postgres-error.mapper.ts b/src/infrastructure/database/postgres-error.mapper.ts index 7851812..88ec048 100644 --- a/src/infrastructure/database/postgres-error.mapper.ts +++ b/src/infrastructure/database/postgres-error.mapper.ts @@ -29,7 +29,7 @@ export class PostgresErrorMapper { return null; } - static isUniqueViolation(error: unknown): boolean { + static isExclusionViolation(error: unknown): boolean { return this.extractCode(error) === '23P01'; } diff --git a/src/infrastructure/reservation/reservation.drizzle-repository.ts b/src/infrastructure/reservation/reservation.drizzle-repository.ts index 7528a33..42f69a5 100644 --- a/src/infrastructure/reservation/reservation.drizzle-repository.ts +++ b/src/infrastructure/reservation/reservation.drizzle-repository.ts @@ -5,7 +5,7 @@ import { ReservationConflictError } from '@domain/reservation/errors/reservation import { Reservation } from '@domain/reservation/reservation.entity'; import { ReservationRepository } from '@domain/reservation/reservation.repository'; -import { Database } from '@infrastructure/database/database.provider'; +import { DrizzleClient } from '@infrastructure/database/database.provider'; import { DATABASE } from '@infrastructure/database/database.token'; import { PostgresErrorMapper } from '@infrastructure/database/postgres-error.mapper'; import { reservations } from '@infrastructure/database/schema/reservation'; @@ -13,14 +13,14 @@ import { reservations } from '@infrastructure/database/schema/reservation'; import { ReservationMapper, ReservationRow } from './reservation.mapper'; export class ReservationDrizzleRepository implements ReservationRepository { - constructor(@Inject(DATABASE) private readonly db: Database) {} + constructor(@Inject(DATABASE) private readonly db: DrizzleClient) {} async save(reservation: Reservation): Promise { try { const data = ReservationMapper.toPersistence(reservation); await this.db.insert(reservations).values(data); } catch (error: unknown) { - if (PostgresErrorMapper.isUniqueViolation(error)) { + if (PostgresErrorMapper.isExclusionViolation(error)) { throw new ReservationConflictError(); } diff --git a/src/infrastructure/user/user.drizzle-repository.ts b/src/infrastructure/user/user.drizzle-repository.ts index be6f366..ba92605 100644 --- a/src/infrastructure/user/user.drizzle-repository.ts +++ b/src/infrastructure/user/user.drizzle-repository.ts @@ -4,7 +4,7 @@ import { eq } from 'drizzle-orm'; import { User } from '@domain/user/user.entity'; import { UserRepository } from '@domain/user/user.repository'; -import { Database } from '@infrastructure/database/database.provider'; +import { DrizzleClient } from '@infrastructure/database/database.provider'; import { DATABASE } from '@infrastructure/database/database.token'; import { UniqueConstraintViolationError } from '@infrastructure/database/errors/unique-constraint-violation.error'; import { users } from '@infrastructure/database/schema/user'; @@ -13,7 +13,7 @@ import { UserMapper } from './user.mapper'; @Injectable() export class UserDrizzleRepository implements UserRepository { - constructor(@Inject(DATABASE) private readonly db: Database) {} + constructor(@Inject(DATABASE) private readonly db: DrizzleClient) {} async findByEmail(email: string): Promise { const result = await this.db .select() diff --git a/test/factories/barber.factory.ts b/test/factories/barber.factory.ts index 84e5dfb..d96ae62 100644 --- a/test/factories/barber.factory.ts +++ b/test/factories/barber.factory.ts @@ -1,30 +1,26 @@ -import { testDb } from '@test/utils/infra/test-database'; +import { TEST_TIME } from '@test/utils/time'; import { randomUUID } from 'crypto'; -import { barbers } from '@infrastructure/database/schema/barber'; - -import { createUserFactory } from './user.factory'; +import { Barber } from '@domain/barber/barber.entity'; -type CreateBarberInput = { - id?: string; - name?: string; - bio?: string | null; - active?: boolean; -}; +import { Database } from '@infrastructure/database/database.provider'; +import { barbers } from '@infrastructure/database/schema/barber'; -export async function createBarberFactory(input: CreateBarberInput = {}) { +export function buildBarber(input: Partial = {}) { const id = input.id ?? randomUUID(); - // Ensure user exists first - await createUserFactory({ id }); - - await testDb.insert(barbers).values({ + return { id, name: input.name ?? 'John Barber', bio: input.bio ?? null, active: input.active ?? true, - createdAt: new Date(), - }); + createdAt: input.createdAt ?? TEST_TIME, + }; +} + +export async function persistBarber(db: Database, input?: Partial) { + const data = buildBarber(input); - return { id }; + await db.insert(barbers).values(data); + return data; } diff --git a/test/factories/reservation.factory.ts b/test/factories/reservation.factory.ts new file mode 100644 index 0000000..83ed615 --- /dev/null +++ b/test/factories/reservation.factory.ts @@ -0,0 +1,31 @@ +import { TEST_TIME } from '@test/utils/time'; +import { randomUUID } from 'crypto'; + +import { Reservation } from '@domain/reservation/reservation.entity'; + +import { Database } from '@infrastructure/database/database.provider'; +import { reservations } from '@infrastructure/database/schema/reservation'; + +export function buildReservation(input: Partial = {}) { + const id = input.id ?? randomUUID(); + const start = input.startTime ?? TEST_TIME; + const end = input.endTime ?? new Date(start.getTime() + 30 * 60 * 1000); + + return { + id, + barberId: input.barberId ?? 'fixed-barber-id', + userId: input.userId ?? 'fixed-user-id', + startTime: start, + endTime: end, + createdAt: input.createdAt ?? start, + }; +} + +export async function persistReservation( + db: Database, + input?: Partial, +) { + const data = buildReservation(input); + await db.insert(reservations).values(data); + return data; +} diff --git a/test/factories/user.factory.ts b/test/factories/user.factory.ts index 7cb1098..08c8ce5 100644 --- a/test/factories/user.factory.ts +++ b/test/factories/user.factory.ts @@ -1,24 +1,28 @@ -import { testDb } from '@test/utils/infra/test-database'; +import { TEST_TIME } from '@test/utils/time'; import { randomUUID } from 'crypto'; +import { Database } from '@infrastructure/database/database.provider'; import { users } from '@infrastructure/database/schema/user'; -type CreateUserInput = { +type persistUserInput = { id?: string; email?: string; passwordHash?: string; createdAt?: Date; }; -export async function createUserFactory(input: CreateUserInput = {}) { +export function buildUser(input: persistUserInput = {}) { const id = input.id ?? randomUUID(); - - await testDb.insert(users).values({ + return { id, - email: input.email ?? `${id}@test.com`, + email: input.email ?? `user-${id}@example.com`, passwordHash: input.passwordHash ?? 'hash', - createdAt: input.createdAt ?? new Date(), - }); + createdAt: input.createdAt ?? TEST_TIME, + }; +} - return { id }; +export async function persistUser(db: Database, input?: persistUserInput) { + const data = buildUser(input); + await db.insert(users).values(data); + return data; } diff --git a/test/reservation/reservation-concurrency.int.spec.ts b/test/reservation/reservation-concurrency.int.spec.ts new file mode 100644 index 0000000..b4ad9b1 --- /dev/null +++ b/test/reservation/reservation-concurrency.int.spec.ts @@ -0,0 +1,56 @@ +import { persistBarber } from '@test/factories/barber.factory'; +import { buildReservation } from '@test/factories/reservation.factory'; +import { persistUser } from '@test/factories/user.factory'; +import { Barrier } from '@test/utils/concurrency-barrier'; +import { testDb } from '@test/utils/infra/test-database'; + +import { ReservationConflictError } from '@domain/reservation/errors/reservation-conflict.error'; + +import { ReservationDrizzleRepository } from '@infrastructure/reservation/reservation.drizzle-repository'; + +it('should prevent double booking under real concurrency', async () => { + const barberUser = await persistUser(testDb); + const barber = await persistBarber(testDb, { id: barberUser.id }); + + const users = await Promise.all([ + persistUser(testDb), + persistUser(testDb), + persistUser(testDb), + persistUser(testDb), + persistUser(testDb), + ]); + + const start = new Date('2030-01-01T10:00:00Z'); + const end = new Date('2030-01-01T11:00:00Z'); + + const barrier = new Barrier(users.length); + const tasks = users.map(async (user): Promise => { + const reservation = buildReservation({ + barberId: barber.id, + userId: user.id, + startTime: start, + endTime: end, + }); + + return testDb.transaction(async (tx): Promise => { + const txRepo = new ReservationDrizzleRepository(tx); + + await barrier.wait(); + await txRepo.save(reservation); + }); + }); + + const results = await Promise.allSettled(tasks); + + console.log(results); + + const success = results.filter((r) => r.status === 'fulfilled'); + const failed = results.filter((r) => r.status === 'rejected'); + + expect(success).toHaveLength(1); + expect(failed.length).toBe(users.length - 1); + + for (const f of failed) { + expect(f.reason).toBeInstanceOf(ReservationConflictError); + } +}); diff --git a/test/reservation/reservation-invariants.int.spec.ts b/test/reservation/reservation-invariants.int.spec.ts index 410b7f0..f4cc9ad 100644 --- a/test/reservation/reservation-invariants.int.spec.ts +++ b/test/reservation/reservation-invariants.int.spec.ts @@ -1,5 +1,5 @@ -import { createBarberFactory } from '@test/factories/barber.factory'; -import { createUserFactory } from '@test/factories/user.factory'; +import { persistBarber } from '@test/factories/barber.factory'; +import { persistUser } from '@test/factories/user.factory'; import { testDb } from '@test/utils/infra/test-database'; import { truncateTestDatabase } from '@test/utils/infra/truncate-test-db'; import { randomUUID } from 'crypto'; @@ -21,8 +21,8 @@ describe('Reservation invariants (integration)', () => { }); it('should persist a valid reservation', async () => { - const user = await createUserFactory(); - const barber = await createBarberFactory(); + const user = await persistUser(testDb); + const barber = await persistBarber(testDb, { id: user.id }); const reservation = Reservation.create({ id: randomUUID(), @@ -30,7 +30,7 @@ describe('Reservation invariants (integration)', () => { userId: user.id, startTime: new Date('2030-01-01T10:00:00Z'), endTime: new Date('2030-01-01T11:00:00Z'), - createdAt: new Date(), + createdAt: new Date('2030-01-01T09:00:00Z'), }); await repository.save(reservation); @@ -41,9 +41,11 @@ describe('Reservation invariants (integration)', () => { }); it('should throw ReservationConflictError when slot is already taken', async () => { - const barber = await createBarberFactory(); - const userA = await createUserFactory(); - const userB = await createUserFactory(); + const barberUser = await persistUser(testDb); + const barber = await persistBarber(testDb, { id: barberUser.id }); + + const userA = await persistUser(testDb); + const userB = await persistUser(testDb); const start = new Date('2030-01-01T10:00:00Z'); const end = new Date('2030-01-01T11:00:00Z'); @@ -54,7 +56,7 @@ describe('Reservation invariants (integration)', () => { userId: userA.id, startTime: start, endTime: end, - createdAt: new Date(), + createdAt: new Date('2030-01-01T09:00:00Z'), }); await repository.save(first); @@ -65,7 +67,7 @@ describe('Reservation invariants (integration)', () => { userId: userB.id, startTime: start, endTime: end, - createdAt: new Date(), + createdAt: new Date('2030-01-01T09:00:00Z'), }); await expect(repository.save(conflicting)).rejects.toBeInstanceOf( diff --git a/test/setup-after-env.ts b/test/setup-after-env.ts new file mode 100644 index 0000000..c592e2a --- /dev/null +++ b/test/setup-after-env.ts @@ -0,0 +1,5 @@ +import { closeDatabase } from '@infrastructure/database/database.provider'; + +afterAll(async () => { + await closeDatabase(); +}); diff --git a/test/setup/global-setup.ts b/test/setup/global-setup.ts deleted file mode 100644 index b6ec8a0..0000000 --- a/test/setup/global-setup.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { config } from 'dotenv'; - -export default () => { - config({ path: '.env.test' }); -}; diff --git a/test/utils/concurrency-barrier.ts b/test/utils/concurrency-barrier.ts new file mode 100644 index 0000000..482337c --- /dev/null +++ b/test/utils/concurrency-barrier.ts @@ -0,0 +1,17 @@ +export class Barrier { + private count: number = 0; + private resolve!: () => void; + private promise: Promise; + + constructor(private readonly total: number) { + this.promise = new Promise((res) => (this.resolve = res)); + } + + async wait(): Promise { + this.count++; + if (this.count === this.total) { + this.resolve(); + } + return this.promise; + } +} diff --git a/test/utils/time.ts b/test/utils/time.ts new file mode 100644 index 0000000..9a8222f --- /dev/null +++ b/test/utils/time.ts @@ -0,0 +1 @@ +export const TEST_TIME = new Date('2026-01-01T10:00:00Z');