From 7d250ec342506ea2213918959f607e5be5094f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Thu, 17 Sep 2026 19:14:41 +0800 Subject: [PATCH] feat(api): cn-app skeleton, toolchain, env loading convention Co-Authored-By: Claude Code --- .env.example | 3 + docs/plans/2026-09-17-P1a-后端核心链路.md | 16 +- eslint.config.js | 27 + package.json | 3 +- packages/contracts/package.json | 4 +- pnpm-lock.yaml | 1165 ++++++++++++++++- services/api/jest.config.ts | 39 + services/api/jest.e2e.config.ts | 11 + services/api/nest-cli.json | 6 + services/api/package.json | 37 + .../api/src/all-exceptions.filter.spec.ts | 77 ++ services/api/src/all-exceptions.filter.ts | 88 ++ services/api/src/app-cn.module.ts | 37 + services/api/src/health.controller.ts | 11 + services/api/src/main-cn.ts | 26 + services/api/src/request-id.middleware.ts | 37 + services/api/test/health.e2e-spec.ts | 47 + services/api/test/load-env.ts | 7 + services/api/test/reset.ts | 17 + services/api/tsconfig.build.json | 5 + services/api/tsconfig.json | 19 + 21 files changed, 1655 insertions(+), 27 deletions(-) create mode 100644 eslint.config.js create mode 100644 services/api/jest.config.ts create mode 100644 services/api/jest.e2e.config.ts create mode 100644 services/api/nest-cli.json create mode 100644 services/api/package.json create mode 100644 services/api/src/all-exceptions.filter.spec.ts create mode 100644 services/api/src/all-exceptions.filter.ts create mode 100644 services/api/src/app-cn.module.ts create mode 100644 services/api/src/health.controller.ts create mode 100644 services/api/src/main-cn.ts create mode 100644 services/api/src/request-id.middleware.ts create mode 100644 services/api/test/health.e2e-spec.ts create mode 100644 services/api/test/load-env.ts create mode 100644 services/api/test/reset.ts create mode 100644 services/api/tsconfig.build.json create mode 100644 services/api/tsconfig.json diff --git a/.env.example b/.env.example index c99120c..6d83168 100644 --- a/.env.example +++ b/.env.example @@ -8,3 +8,6 @@ S3_BUCKET=photo-dev SIGNED_URL_TTL_SECONDS=900 AUTH_SESSION_TTL_SECONDS=2592000 UPLOAD_MAX_BYTES=52428800 +PORT=8080 +CORS_ORIGINS=http://localhost:5173 +LOG_LEVEL=info diff --git a/docs/plans/2026-09-17-P1a-后端核心链路.md b/docs/plans/2026-09-17-P1a-后端核心链路.md index 0a26681..a34688e 100644 --- a/docs/plans/2026-09-17-P1a-后端核心链路.md +++ b/docs/plans/2026-09-17-P1a-后端核心链路.md @@ -286,7 +286,7 @@ export interface OutboxEvent { } ``` -- [ ] **Step 2: 单测**:类型测试——合法 `OutboxEvent{type:'photo.published'}` 编译通过,非法 type 用 `@ts-expect-error` 验证编译期拒绝;**枚举同步测试**(Task 4 审查遗留):断言 `ErrorCode` 与 `components['schemas']['Error']['code']` 的 enum 双向可赋值。 +- [x] **Step 2: 单测**:类型测试——合法 `OutboxEvent{type:'photo.published'}` 编译通过,非法 type 用 `@ts-expect-error` 验证编译期拒绝;**枚举同步测试**(Task 4 审查遗留):断言 `ErrorCode` 与 `components['schemas']['Error']['code']` 的 enum 双向可赋值。(完成:8/8 通过,两护栏经变异验证真实生效) ```bash pnpm --filter @photo/contracts test @@ -294,8 +294,8 @@ pnpm --filter @photo/contracts test Expected: PASS。 -- [ ] **Step 3: ⏸ 用户确认点:请用户过目 openapi.yaml(接口形态、字段命名、分页方式)后再进入 M2。** -- [ ] **Step 4: Commit** `feat(contracts): outbox event contract types` +- [x] **Step 3: ⏸ 用户确认点:请用户过目 openapi.yaml(接口形态、字段命名、分页方式)后再进入 M2。**(完成:用户于 2026-09-17 确认"确认,继续 M2") +- [x] **Step 4: Commit** `feat(contracts): outbox event contract types`(完成:f77ab5a) --- @@ -306,10 +306,10 @@ Expected: PASS。 **Files:** - Create: `services/api/package.json`(name `@photo/api-cn`)、`tsconfig.json`、`nest-cli.json`、`src/main-cn.ts`、`src/app-cn.module.ts`、`src/health.controller.ts`、`src/request-id.middleware.ts`、`src/all-exceptions.filter.ts`、`services/api/jest.config.ts`、`services/api/test/load-env.ts`、`services/api/test/reset.ts`、根 `eslint.config.js` -- [ ] **Step 1: env 加载约定(全仓库唯一机制,解决 pnpm --filter cwd 在包目录的问题)**:根 `.env` 为唯一 env 文件。开发/迁移脚本经根 `dotenv-cli` 注入(Task 2 scripts 已配置);Jest 经 `services/api/test/load-env.ts`(`dotenv.config({ path: join(__dirname, '../../../.env') })`)作为 `setupFiles` 载入;运行时代码只读 `process.env`。 -- [ ] **Step 2: 依赖与入口**:deps `@nestjs/common @nestjs/core @nestjs/platform-express nest-pino pino-http`;devDeps `jest ts-jest @types/jest supertest @types/supertest @nestjs/testing`;scripts:`test`(`*.spec.ts` 单测)、`test:e2e`(`test/*.e2e-spec.ts`,前置 compose 依赖)、`typecheck`、`lint`、`start`。`test/reset.ts` 为 e2e 共用隔离工具:每个 e2e spec `beforeAll` 调用——truncate 全部 cn 表 + 删除 MinIO `photo-live/dev` 前缀对象(防止 spec 间唯一约束冲突与脏数据)。入口监听 `PORT`(默认 8080),`app.setGlobalPrefix('v1')`,注册 request-id 中间件(无则生成 cuid,挂 `res.setHeader('x-request-id')`)、全局异常过滤器(映射 `ErrorCodes`,响应 `{code,message,requestId}`,不泄露堆栈)、`/v1/health` 返回 `{status:'ok'}`。 -- [ ] **Step 3: 根 ESLint flat config**(eslint + typescript-eslint,覆盖 packages/services/apps),各包(contracts、storage、db-cn、api、worker)`lint` 脚本接 `eslint .`,确保 turbo 不静默跳过。ts-jest 保持类型检查模式(非 isolatedModules),使 `@ts-expect-error` 负向断言生效。 -- [ ] **Step 4: 启动验证** +- [x] **Step 1: env 加载约定(全仓库唯一机制,解决 pnpm --filter cwd 在包目录的问题)**:根 `.env` 为唯一 env 文件。开发/迁移脚本经根 `dotenv-cli` 注入(Task 2 scripts 已配置);Jest 经 `services/api/test/load-env.ts`(`dotenv.config({ path: join(__dirname, '../../../.env') })`)作为 `setupFiles` 载入;运行时代码只读 `process.env`。(完成:2026-09-17) +- [x] **Step 2: 依赖与入口**:deps `@nestjs/common @nestjs/core @nestjs/platform-express nest-pino pino-http`(实际:`nest-pino` 上游已更名 `nestjs-pino`,取 ^4.6.1 兼容 Nest 10);devDeps `jest ts-jest @types/jest supertest @types/supertest @nestjs/testing`;scripts:`test`(`*.spec.ts` 单测)、`test:e2e`(`test/*.e2e-spec.ts`,前置 compose 依赖)、`typecheck`、`lint`、`start`。`test/reset.ts` 为 e2e 共用隔离工具:每个 e2e spec `beforeAll` 调用——truncate 全部 cn 表 + 删除 MinIO `photo-live/dev` 前缀对象(防止 spec 间唯一约束冲突与脏数据)。入口监听 `PORT`(默认 8080),`app.setGlobalPrefix('v1')`,注册 request-id 中间件(无则生成 cuid,挂 `res.setHeader('x-request-id')`)、全局异常过滤器(映射 `ErrorCodes`,响应 `{code,message,requestId}`,不泄露堆栈)、`/v1/health` 返回 `{status:'ok'}`。 +- [x] **Step 3: 根 ESLint flat config**(eslint + typescript-eslint,覆盖 packages/services/apps),各包(contracts、storage、db-cn、api、worker)`lint` 脚本接 `eslint .`,确保 turbo 不静默跳过。ts-jest 保持类型检查模式(非 isolatedModules),使 `@ts-expect-error` 负向断言生效。(完成:contracts 与 api 已接入,storage/db-cn/worker 待各自任务建包时接入) +- [x] **Step 4: 启动验证**(完成:curl -i 见 x-request-id 响应头;单测 6/6、e2e 3/3、根 lint/typecheck/test/build/e2e 全绿) ```bash cp .env.example .env @@ -318,7 +318,7 @@ pnpm dev:api & until curl -s localhost:8080/v1/health; do sleep 1; done # 等待启动 → {"status":"ok"} ``` -- [ ] **Step 5: Commit** `feat(api): cn-app skeleton, toolchain, env loading convention` +- [x] **Step 5: Commit** `feat(api): cn-app skeleton, toolchain, env loading convention` ### Task 8: Prisma cn schema —— 身份与审计域 diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..56b96e1 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,27 @@ +// eslint.config.js —— 根 flat config(覆盖 packages/services/apps 全部 TS)。 +// 各包 lint 脚本为 `eslint .`,在包目录执行时向上发现本文件,turbo 不会静默跳过。 +// 仅 typescript-eslint recommended(无类型感知规则,无需 project service), +// 避免跨包 tsconfig 差异(contracts NodeNext / api node16)带来的配置负担。 +// @ts-check +const globals = require('globals'); +const tseslint = require('typescript-eslint'); + +module.exports = tseslint.config( + { + ignores: [ + '**/node_modules/', + '**/dist/', + '**/coverage/', + '**/.turbo/', + // 生成产物不参与 lint(契约生成类型已提交入库,改动随 `pnpm gen` 审查) + '**/generated/', + ], + }, + ...tseslint.configs.recommended, + { + files: ['apps/**/*.{ts,tsx}', 'packages/**/*.ts', 'services/**/*.ts'], + languageOptions: { + globals: { ...globals.node }, + }, + }, +); diff --git a/package.json b/package.json index c0c6099..655ddd9 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "prettier": "^3.3.0", "dotenv-cli": "^7.4.0", "eslint": "^9.0.0", - "typescript-eslint": "^8.0.0" + "typescript-eslint": "^8.0.0", + "globals": "^16.0.0" } } diff --git a/packages/contracts/package.json b/packages/contracts/package.json index fe672e4..2f25c4a 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "description": "API contract single source of truth (OpenAPI 3.1 + error codes); types generated via openapi-typescript and committed under src/generated/", - "//": "lint script is a placeholder (exit 0): eslint flat config arrives in Task 7. test is a minimal ts-jest scaffold: real type tests arrive in Task 6.", + "//": "lint runs `eslint .` against the root flat config (Task 7). test is ts-jest with full type-checking (Task 6 type tests).", "main": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { @@ -21,7 +21,7 @@ "build": "tsc -p tsconfig.json && node -e \"require('fs').cpSync('src/generated', 'dist/generated', { recursive: true })\"", "typecheck": "tsc --noEmit", "test": "jest", - "lint": "exit 0" + "lint": "eslint ." }, "devDependencies": { "@redocly/cli": "^1.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0b9d1cc..624d46a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: eslint: specifier: ^9.0.0 version: 9.39.5 + globals: + specifier: ^16.0.0 + version: 16.5.0 prettier: specifier: ^3.3.0 version: 3.9.7 @@ -37,13 +40,74 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.20.3) + version: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) openapi-typescript: specifier: ^7.0.0 version: 7.13.0(typescript@5.9.3) ts-jest: specifier: ^29.2.0 - version: 29.4.12(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.3))(typescript@5.9.3) + version: 29.4.12(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)))(typescript@5.9.3) + typescript: + specifier: ^5.6.0 + version: 5.9.3 + + services/api: + dependencies: + '@nestjs/common': + specifier: ^10.4.6 + version: 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^10.4.6 + version: 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^10.4.6 + version: 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22) + '@photo/contracts': + specifier: workspace:* + version: link:../../packages/contracts + nestjs-pino: + specifier: ^4.6.1 + version: 4.6.1(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(pino-http@11.0.0)(pino@10.3.1)(rxjs@7.8.2) + pino: + specifier: ^10.0.0 + version: 10.3.1 + pino-http: + specifier: ^11.0.0 + version: 11.0.0 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.1 + version: 7.8.2 + devDependencies: + '@nestjs/testing': + specifier: ^10.4.6 + version: 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@nestjs/platform-express@10.4.22) + '@types/jest': + specifier: ^29.5.13 + version: 29.5.14 + '@types/node': + specifier: ^22.10.0 + version: 22.20.3 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) + supertest: + specifier: ^7.0.0 + version: 7.2.2 + ts-jest: + specifier: ^29.2.5 + version: 29.4.12(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)))(typescript@5.9.3) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.20.3)(typescript@5.9.3) typescript: specifier: ^5.6.0 version: 5.9.3 @@ -219,6 +283,13 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@emotion/is-prop-valid@1.4.0': resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} @@ -384,6 +455,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} engines: {node: '>= 10.16.0'} @@ -396,9 +470,71 @@ packages: peerDependencies: jsep: ^0.4.0||^1.0.0 + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@nestjs/common@10.4.22': + resolution: {integrity: sha512-fxJ4v85nDHaqT1PmfNCQ37b/jcv2OojtXTaK1P2uAXhzLf9qq6WNUOFvxBrV4fhQek1EQoT1o9oj5xAZmv3NRw==} + peerDependencies: + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@10.4.22': + resolution: {integrity: sha512-6IX9+VwjiKtCjx+mXVPncpkQ5ZjKfmssOZPFexmT+6T9H9wZ3svpYACAo7+9e7Nr9DZSoRZw3pffkJP7Z0UjaA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/microservices': ^10.0.0 + '@nestjs/platform-express': ^10.0.0 + '@nestjs/websockets': ^10.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + + '@nestjs/platform-express@10.4.22': + resolution: {integrity: sha512-ySSq7Py/DFozzZdNDH67m/vHoeVdphDniWBnl6q5QVoXldDdrZIHLXLRMPayTDh5A95nt7jjJzmD4qpTbNQ6tA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + + '@nestjs/testing@10.4.22': + resolution: {integrity: sha512-HO9aPus3bAedAC+jKVAA8jTdaj4fs5M9fing4giHrcYV2txe9CvC1l1WAjwQ9RDhEHdugjY4y+FZA/U/YqPZrA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + '@nestjs/microservices': ^10.0.0 + '@nestjs/platform-express': ^10.0.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + '@nodable/entities@3.0.0': resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} + '@nuxtjs/opencollective@0.3.2': + resolution: {integrity: sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + '@opentelemetry/api-logs@0.222.0': resolution: {integrity: sha512-9mb1If+IF6u0ZVXkHQ6ogEae5HwA6ajIVUgpSDQyRASxft6BSXHvBvPooRle3yFN/fKnCdSOnuu0OC3PLcF6+g==} engines: {node: '>=8.0.0'} @@ -481,6 +617,12 @@ packages: resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} + '@paralleldrive/cuid2@2.3.1': + resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} + + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@redocly/ajv@8.11.2': resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} @@ -509,6 +651,25 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@tokenizer/inflate@0.2.7': + resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tsconfig/node10@1.0.13': + resolution: {integrity: sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@turbo/darwin-64@2.10.13': resolution: {integrity: sha512-m5DBcpkxmcKpEJHHFUfqf9GLUjSmw3cDnBJM9nghPW3kjCNb5OyNKmzG7/yT5x5AwzOO+HMwKN+UI4iVKL87YA==} cpu: [x64] @@ -551,6 +712,9 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/cookiejar@2.1.5': + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} @@ -572,12 +736,21 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/methods@1.1.4': + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} + '@types/node@22.20.3': resolution: {integrity: sha512-DZmzkmwHzXrLPAXPyKNDzlIwMMUZCVacoD25ywdy5YTKGbOx/2ld+Q38Im2zJ0vBuZP5Prd3VZutKZyXwkOS8A==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/superagent@8.1.11': + resolution: {integrity: sha512-KA7srSW/HENDtOw9DOqaFLgWuMqN9WgjEw62lh9dpvRaZDkhdOkazASd7X7i2eMUYLHa1U37ZttnePsH5zTDHw==} + + '@types/supertest@6.0.3': + resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -650,11 +823,19 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + acorn@8.18.0: resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} engines: {node: '>=0.4.0'} @@ -694,15 +875,31 @@ packages: anynum@1.0.1: resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -750,6 +947,10 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + brace-expansion@1.1.21: resolution: {integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==} @@ -783,10 +984,22 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + call-me-maybe@1.0.2: resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} @@ -865,6 +1078,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -872,21 +1088,49 @@ packages: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} + consola@2.15.3: + resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + core-js@3.32.1: resolution: {integrity: sha512-lqufgNn9NLnESg5mQeYsxQP5w7wrViSj0jr/kv6ECQiByzQkrn1MKvV0L3acttpDqfQrHLwr2KCMgX5b8X+lyQ==} + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -894,6 +1138,14 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -937,14 +1189,29 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + dompurify@3.4.15: resolution: {integrity: sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==} @@ -968,6 +1235,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.430: resolution: {integrity: sha512-e1QEj72Y4zd8RlNZVmoTg+iCOSVwpk05IOiiQwdrkwCSVlZfPthevErhE+nckGd2YbsXfp1SkisznhGVIXP2NQ==} @@ -978,6 +1248,10 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -1004,6 +1278,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} @@ -1064,6 +1341,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -1083,6 +1364,10 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + engines: {node: '>= 0.10.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1114,14 +1399,25 @@ packages: picomatch: optional: true + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@20.4.1: + resolution: {integrity: sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==} + engines: {node: '>=18'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -1144,6 +1440,18 @@ packages: resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} + formidable@3.5.4: + resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} + engines: {node: '>=14.0.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1198,6 +1506,10 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1229,6 +1541,10 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http2-client@1.3.5: resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} @@ -1240,6 +1556,13 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1272,6 +1595,10 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -1351,6 +1678,10 @@ packages: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} + iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1600,9 +1931,20 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -1615,6 +1957,16 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -1633,6 +1985,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + mobx-react-lite@4.1.1: resolution: {integrity: sha512-iUxiMpsvNraCKXU+yPotsOncNNmyeS2B5DKL+TL6Tar/xm+wwNJAubJmtRSeAoYawdZqwv8Z/+5nPRHeQxTiXg==} peerDependencies: @@ -1662,15 +2018,35 @@ packages: mobx@6.12.3: resolution: {integrity: sha512-c8NKkO4R2lShkSXZ2Ongj1ycjugjzFFo/UswHBnS62y07DMcTc9Rvo03/3nRyszIvwPNljlkd4S828zIBv/piw==} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multer@2.0.2: + resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} + engines: {node: '>= 10.16.0'} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + nestjs-pino@4.6.1: + resolution: {integrity: sha512-nuARXa0xpdJ1lY2+fgycIQr6H3g0VgqAWNK3xMYjOFcj2DoPETNXj0lV3Y86nRuI7BUfQp5PGiVoZvT4dTWbpQ==} + engines: {node: '>= 14'} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + pino: ^7.5.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + pino-http: ^6.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + rxjs: ^7.1.0 + node-fetch-h2@2.3.0: resolution: {integrity: sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==} engines: {node: 4.x || >=6.0.0} @@ -1722,6 +2098,18 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -1784,6 +2172,10 @@ packages: resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} engines: {node: '>=18'} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -1806,6 +2198,12 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} + + path-to-regexp@3.3.0: + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + perfect-scrollbar@1.5.6: resolution: {integrity: sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==} @@ -1820,6 +2218,19 @@ packages: resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-http@11.0.0: + resolution: {integrity: sha512-wqg5XIAGRRIWtTk8qPGxkbrfiwEWz1lgedVLvhLALudKXvg1/L2lTFgTGPJ4Z2e3qcRmxoFxDuSdMdMGNM6I1g==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true + pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -1853,6 +2264,9 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + process-warning@5.1.0: + resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -1860,6 +2274,10 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-addr@2.0.8: + resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==} + engines: {node: '>= 0.10'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1867,12 +2285,31 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + engines: {node: '>=0.6'} + + qs@6.16.0: + resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + react-dom@19.3.0: resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==} peerDependencies: @@ -1901,6 +2338,13 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + real-require@1.0.0: + resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + redoc@2.5.3: resolution: {integrity: sha512-bBbat+Sx6xKWdyoCGTtA0BWeTEW9Vs4VnEja7q7ZLOk4IM7cHQLrf+kDxWF6dKeKxT8kOBnoy/OsNXCeLttpyQ==} engines: {node: '>=6.9', npm: '>=3.0.0'} @@ -1911,6 +2355,9 @@ packages: react-dom: ^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0 styled-components: ^4.1.1 || ^5.1.1 || ^6.0.5 + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reftools@1.1.9: resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==} @@ -1947,9 +2394,19 @@ packages: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.28.0: resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} @@ -1967,9 +2424,20 @@ packages: engines: {node: '>=10'} hasBin: true + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + set-cookie-parser@2.7.1: resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1996,6 +2464,22 @@ packages: should@13.2.3: resolution: {integrity: sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -2013,6 +2497,9 @@ packages: resolution: {integrity: sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==} engines: {node: '>=8.0.0'} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} @@ -2020,6 +2507,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -2027,9 +2518,17 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + stickyfill@1.1.1: resolution: {integrity: sha512-GCp7vHAfpao+Qh/3Flh9DXEJ/qSi0KJwJw6zYlZOtRYXWUIpMM6mC2rIep/dK8RQqwW0KxGJIllmjPIBOGN8AA==} + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -2060,6 +2559,10 @@ packages: strnum@2.4.2: resolution: {integrity: sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==} + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + styled-components@6.5.3: resolution: {integrity: sha512-vAX79sfpmUerP9fsTTxoTrBDE0RuO4ahjInyWYoohNgqrdg63Ms4q6FJ/o2Fyity82NU3cujOT8Ewl9TThBdwg==} engines: {node: '>= 16'} @@ -2079,6 +2582,14 @@ packages: stylis@4.3.6: resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + superagent@10.3.0: + resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} + engines: {node: '>=14.18.0'} + + supertest@7.2.2: + resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} + engines: {node: '>=14.18.0'} + supports-color@10.2.2: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} @@ -2103,6 +2614,10 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + thread-stream@4.2.0: + resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} + engines: {node: '>=20'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -2114,6 +2629,14 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -2150,6 +2673,23 @@ packages: jest-util: optional: true + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + turbo@2.10.13: resolution: {integrity: sha512-69MkPbjk+G8oyC7pC2DeBk0rPdbLz51wuH5eAT0Q4BVJkzq/b1XM4kUUidsARbmDjwIELSJwd1ezITULY9kWNw==} hasBin: true @@ -2170,6 +2710,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} @@ -2190,6 +2734,14 @@ packages: engines: {node: '>=0.8.0'} hasBin: true + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -2197,6 +2749,10 @@ packages: resolution: {integrity: sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==} engines: {node: '>=18.17'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + update-browserslist-db@1.3.3: resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} hasBin: true @@ -2220,10 +2776,21 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -2272,6 +2839,10 @@ packages: resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==} engines: {node: '>=16.0.0'} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2302,6 +2873,10 @@ packages: resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2499,6 +3074,12 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@borewit/text-codec@0.2.2': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + '@emotion/is-prop-valid@1.4.0': dependencies: '@emotion/memoize': 0.9.0 @@ -2592,7 +3173,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -2606,7 +3187,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.20.3) + jest-config: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -2764,6 +3345,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': dependencies: jsep: 1.4.0 @@ -2772,8 +3358,67 @@ snapshots: dependencies: jsep: 1.4.0 + '@lukeed/csprng@1.1.0': {} + + '@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + file-type: 20.4.1 + iterare: 1.2.1 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + transitivePeerDependencies: + - supports-color + + '@nestjs/core@10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nuxtjs/opencollective': 0.3.2 + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/platform-express': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22) + transitivePeerDependencies: + - encoding + + '@nestjs/platform-express@10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)': + dependencies: + '@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + body-parser: 1.20.4 + cors: 2.8.5 + express: 4.22.1 + multer: 2.0.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/testing@10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@nestjs/platform-express@10.4.22)': + dependencies: + '@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + tslib: 2.8.1 + optionalDependencies: + '@nestjs/platform-express': 10.4.22(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22) + + '@noble/hashes@1.8.0': {} + '@nodable/entities@3.0.0': {} + '@nuxtjs/opencollective@0.3.2': + dependencies: + chalk: 4.1.2 + consola: 2.15.3 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + '@opentelemetry/api-logs@0.222.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -2858,6 +3503,12 @@ snapshots: '@opentelemetry/semantic-conventions@1.43.0': {} + '@paralleldrive/cuid2@2.3.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@pinojs/redact@0.4.0': {} + '@redocly/ajv@8.11.2': dependencies: fast-deep-equal: 3.1.3 @@ -2954,6 +3605,24 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@tokenizer/inflate@0.2.7': + dependencies: + debug: 4.4.3(supports-color@10.2.2) + fflate: 0.8.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@tsconfig/node10@1.0.13': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + '@turbo/darwin-64@2.10.13': optional: true @@ -2993,6 +3662,8 @@ snapshots: dependencies: '@babel/types': 7.29.8 + '@types/cookiejar@2.1.5': {} + '@types/estree@1.0.9': {} '@types/graceful-fs@4.1.9': @@ -3016,12 +3687,26 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/methods@1.1.4': {} + '@types/node@22.20.3': dependencies: undici-types: 6.21.0 '@types/stack-utils@2.0.3': {} + '@types/superagent@8.1.11': + dependencies: + '@types/cookiejar': 2.1.5 + '@types/methods': 1.1.4 + '@types/node': 22.20.3 + form-data: 4.0.6 + + '@types/supertest@6.0.3': + dependencies: + '@types/methods': 1.1.4 + '@types/superagent': 8.1.11 + '@types/trusted-types@2.0.7': optional: true @@ -3126,10 +3811,19 @@ snapshots: dependencies: event-target-shim: 5.0.1 + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: acorn: 8.18.0 + acorn-walk@8.3.5: + dependencies: + acorn: 8.18.0 + acorn@8.18.0: {} agent-base@7.1.4: {} @@ -3162,14 +3856,24 @@ snapshots: anynum@1.0.1: {} + append-field@1.0.0: {} + + arg@4.1.3: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 argparse@2.0.1: {} + array-flatten@1.1.1: {} + + asap@2.0.6: {} + asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} + babel-jest@29.7.0(@babel/core@7.29.7): dependencies: '@babel/core': 7.29.7 @@ -3242,6 +3946,23 @@ snapshots: binary-extensions@2.3.0: {} + body-parser@1.20.4: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.14.2 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + brace-expansion@1.1.21: dependencies: balanced-match: 1.0.2 @@ -3281,11 +4002,22 @@ snapshots: dependencies: run-applescript: 7.1.0 + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + bytes@3.1.2: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + call-me-maybe@1.0.2: {} callsites@3.1.0: {} @@ -3355,6 +4087,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + component-emitter@1.3.1: {} + concat-map@0.0.1: {} concat-stream@2.0.0: @@ -3364,19 +4098,38 @@ snapshots: readable-stream: 3.6.2 typedarray: 0.0.6 + consola@2.15.3: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} + cookie-signature@1.0.7: {} + + cookie-signature@1.2.2: {} + cookie@0.7.2: {} + cookiejar@2.1.4: {} + core-js@3.32.1: {} - create-jest@29.7.0(@types/node@22.20.3): + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + create-jest@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.20.3) + jest-config: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -3385,6 +4138,8 @@ snapshots: - supports-color - ts-node + create-require@1.1.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -3393,6 +4148,10 @@ snapshots: csstype@3.2.3: {} + debug@2.6.9: + dependencies: + ms: 2.0.0 + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 @@ -3418,10 +4177,21 @@ snapshots: delayed-stream@1.0.0: {} + depd@2.0.0: {} + + destroy@1.2.0: {} + detect-newline@3.1.0: {} + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + diff-sequences@29.6.3: {} + diff@4.0.4: {} + dompurify@3.4.15: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -3445,12 +4215,16 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + ee-first@1.1.1: {} + electron-to-chromium@1.5.430: {} emittery@0.13.1: {} emoji-regex@8.0.0: {} + encodeurl@2.0.0: {} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -3474,6 +4248,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} @@ -3548,6 +4324,8 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + event-target-shim@5.0.1: {} eventemitter3@5.0.4: {} @@ -3574,6 +4352,42 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + express@4.22.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.4 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.13 + proxy-addr: 2.0.8 + qs: 6.14.2 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2 + serve-static: 1.16.3 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} @@ -3604,14 +4418,37 @@ snapshots: optionalDependencies: picomatch: 4.0.7 + fflate@0.8.3: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 + file-type@20.4.1: + dependencies: + '@tokenizer/inflate': 0.2.7 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 + finalhandler@1.3.2: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -3639,6 +4476,16 @@ snapshots: hasown: 2.0.4 mime-types: 2.1.35 + formidable@3.5.4: + dependencies: + '@paralleldrive/cuid2': 2.3.1 + dezalgo: 1.0.4 + once: 1.4.0 + + forwarded@0.2.0: {} + + fresh@0.5.2: {} + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -3693,6 +4540,8 @@ snapshots: globals@14.0.0: {} + globals@16.5.0: {} + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -3720,6 +4569,14 @@ snapshots: html-escaper@2.0.2: {} + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http2-client@1.3.5: {} https-proxy-agent@7.0.6(supports-color@10.2.2): @@ -3731,6 +4588,12 @@ snapshots: human-signals@2.1.0: {} + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.9: {} @@ -3756,6 +4619,8 @@ snapshots: inherits@2.0.4: {} + ipaddr.js@1.9.1: {} + is-arrayish@0.2.1: {} is-binary-path@2.1.0: @@ -3835,6 +4700,8 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + iterare@1.2.1: {} + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -3867,16 +4734,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.20.3): + jest-cli@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.20.3) + create-jest: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.20.3) + jest-config: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.3 @@ -3886,7 +4753,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@22.20.3): + jest-config@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)): dependencies: '@babel/core': 7.29.7 '@jest/test-sequencer': 29.7.0 @@ -3912,6 +4779,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.20.3 + ts-node: 10.9.2(@types/node@22.20.3)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -4131,12 +4999,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.20.3): + jest@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.20.3) + jest-cli: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -4237,8 +5105,14 @@ snapshots: math-intrinsics@1.1.0: {} + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + merge-stream@2.0.0: {} + methods@1.1.2: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -4250,6 +5124,10 @@ snapshots: dependencies: mime-db: 1.52.0 + mime@1.6.0: {} + + mime@2.6.0: {} + mimic-fn@2.1.0: {} minimatch@10.2.6: @@ -4266,6 +5144,10 @@ snapshots: minimist@1.2.8: {} + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + mobx-react-lite@4.1.1(mobx@6.12.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: mobx: 6.12.3 @@ -4284,12 +5166,33 @@ snapshots: mobx@6.12.3: {} + ms@2.0.0: {} + ms@2.1.3: {} + multer@2.0.2: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 2.0.0 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + natural-compare@1.4.0: {} + negotiator@0.6.3: {} + neo-async@2.6.2: {} + nestjs-pino@4.6.1(@nestjs/common@10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2))(pino-http@11.0.0)(pino@10.3.1)(rxjs@7.8.2): + dependencies: + '@nestjs/common': 10.4.22(reflect-metadata@0.2.2)(rxjs@7.8.2) + pino: 10.3.1 + pino-http: 11.0.0 + rxjs: 7.8.2 + node-fetch-h2@2.3.0: dependencies: http2-client: 1.3.5 @@ -4345,6 +5248,14 @@ snapshots: object-assign@4.1.1: {} + object-inspect@1.13.4: {} + + on-exit-leak-free@2.1.2: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -4428,6 +5339,8 @@ snapshots: index-to-position: 1.2.0 type-fest: 4.41.0 + parseurl@1.3.3: {} + path-browserify@1.0.1: {} path-exists@4.0.0: {} @@ -4440,6 +5353,10 @@ snapshots: path-parse@1.0.7: {} + path-to-regexp@0.1.13: {} + + path-to-regexp@3.3.0: {} + perfect-scrollbar@1.5.6: {} picocolors@1.1.1: {} @@ -4448,6 +5365,33 @@ snapshots: picomatch@4.0.7: {} + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-http@11.0.0: + dependencies: + get-caller-file: 2.0.5 + pino: 10.3.1 + pino-std-serializers: 7.1.0 + process-warning: 5.1.0 + + pino-std-serializers@7.1.0: {} + + pino@10.3.1: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.1.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.2.0 + pirates@4.0.7: {} pkg-dir@4.2.0: @@ -4472,6 +5416,8 @@ snapshots: prismjs@1.30.0: {} + process-warning@5.1.0: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -4483,16 +5429,41 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proxy-addr@2.0.8: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + punycode@2.3.1: {} pure-rand@6.1.0: {} + qs@6.14.2: + dependencies: + side-channel: 1.1.1 + + qs@6.16.0: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 + range-parser@1.2.1: {} + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + react-dom@19.3.0(react@19.3.0): dependencies: react: 19.3.0 @@ -4520,6 +5491,10 @@ snapshots: dependencies: picomatch: 2.3.2 + real-require@0.2.0: {} + + real-require@1.0.0: {} + redoc@2.5.3(core-js@3.32.1)(mobx@6.12.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(styled-components@6.5.3(react-dom@19.3.0(react@19.3.0))(react@19.3.0)): dependencies: '@redocly/openapi-core': 1.34.20(supports-color@10.2.2) @@ -4553,6 +5528,8 @@ snapshots: - react-native - supports-color + reflect-metadata@0.2.2: {} + reftools@1.1.9: {} require-directory@2.1.1: {} @@ -4578,8 +5555,16 @@ snapshots: run-applescript@7.1.0: {} + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-buffer@5.2.1: {} + safe-stable-stringify@2.5.0: {} + + safer-buffer@2.1.2: {} + scheduler@0.28.0: {} semver@6.3.1: {} @@ -4588,8 +5573,37 @@ snapshots: semver@7.8.5: {} + send@0.19.2: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + set-cookie-parser@2.7.1: {} + setprototypeof@1.2.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -4622,6 +5636,34 @@ snapshots: should-type-adaptors: 1.1.0 should-util: 1.0.1 + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} simple-websocket@9.1.0: @@ -4642,6 +5684,10 @@ snapshots: slugify@1.4.7: {} + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 @@ -4649,14 +5695,20 @@ snapshots: source-map@0.6.1: {} + split2@4.2.0: {} + sprintf-js@1.0.3: {} stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 + statuses@2.0.2: {} + stickyfill@1.1.1: {} + streamsearch@1.1.0: {} + string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -4686,6 +5738,10 @@ snapshots: dependencies: anynum: 1.0.1 + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + styled-components@6.5.3(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: '@emotion/is-prop-valid': 1.4.0 @@ -4697,6 +5753,28 @@ snapshots: stylis@4.3.6: {} + superagent@10.3.0: + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.4.3(supports-color@10.2.2) + fast-safe-stringify: 2.1.1 + form-data: 4.0.6 + formidable: 3.5.4 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.16.0 + transitivePeerDependencies: + - supports-color + + supertest@7.2.2: + dependencies: + cookie-signature: 1.2.2 + methods: 1.1.2 + superagent: 10.3.0 + transitivePeerDependencies: + - supports-color + supports-color@10.2.2: {} supports-color@7.2.0: @@ -4731,6 +5809,10 @@ snapshots: glob: 7.2.3 minimatch: 3.1.5 + thread-stream@4.2.0: + dependencies: + real-require: 1.0.0 + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.7) @@ -4742,18 +5824,26 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + tr46@0.0.3: {} ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - ts-jest@29.4.12(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.3))(typescript@5.9.3): + ts-jest@29.4.12(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 29.7.0(@types/node@22.20.3) + jest: 29.7.0(@types/node@22.20.3)(ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -4768,6 +5858,26 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.29.7) jest-util: 29.7.0 + ts-node@10.9.2(@types/node@22.20.3)(typescript@5.9.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.13 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.20.3 + acorn: 8.18.0 + acorn-walk: 8.3.5 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.4 + make-error: 1.3.6 + typescript: 5.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tslib@2.8.1: {} + turbo@2.10.13: optionalDependencies: '@turbo/darwin-64': 2.10.13 @@ -4787,6 +5897,11 @@ snapshots: type-fest@4.41.0: {} + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + typedarray@0.0.6: {} typescript-eslint@8.70.0(eslint@9.39.5)(typescript@5.9.3): @@ -4805,10 +5920,18 @@ snapshots: uglify-js@3.19.3: optional: true + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + + uint8array-extras@1.5.0: {} + undici-types@6.21.0: {} undici@6.28.0: {} + unpipe@1.0.0: {} + update-browserslist-db@1.3.3(browserslist@4.29.0): dependencies: browserslist: 4.29.0 @@ -4829,12 +5952,18 @@ snapshots: util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} + + v8-compile-cache-lib@3.0.1: {} + v8-to-istanbul@9.3.0: dependencies: '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + vary@1.1.2: {} + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -4871,6 +6000,8 @@ snapshots: xml-naming@0.3.0: {} + xtend@4.0.2: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -4903,4 +6034,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yn@3.1.1: {} + yocto-queue@0.1.0: {} diff --git a/services/api/jest.config.ts b/services/api/jest.config.ts new file mode 100644 index 0000000..2fd8115 --- /dev/null +++ b/services/api/jest.config.ts @@ -0,0 +1,39 @@ +// services/api/jest.config.ts —— 单测(*.spec.ts,排除 e2e)。 +// ts-jest 保持类型检查模式(非 isolatedModules),@ts-expect-error 负向断言可生效。 +// env 约定:setupFiles 经 test/load-env.ts 载入仓库根 .env(全仓库唯一 env 文件)。 +// ESM 互操作:@photo/contracts 为 ESM 包(NodeNext + .js 后缀导入),测试经 +// moduleNameMapper 直接指向其 TS 源码,由 ts-jest 以 CJS 编译(同 +// packages/contracts/jest.config.cjs 的 .js -> $1 映射模式);运行时(node dist) +// 则经 require(esm) 消费其 dist(Node >= 22.12 支持)。 +import type { Config } from 'jest'; + +const config: Config = { + testEnvironment: 'node', + rootDir: '.', + setupFiles: ['./test/load-env.ts'], + transform: { + '^.+\\.tsx?$': [ + 'ts-jest', + { + tsconfig: { + module: 'commonjs', + moduleResolution: 'node10', + target: 'es2022', + lib: ['es2022'], + strict: true, + esModuleInterop: true, + skipLibCheck: true, + types: ['node', 'jest'], + }, + }, + ], + }, + moduleNameMapper: { + '^@photo/contracts$': '/../../packages/contracts/src/index.ts', + '^(\\.{1,2}/.*)\\.js$': '$1', + }, + testMatch: ['/src/**/*.spec.ts'], + testPathIgnorePatterns: ['/node_modules/', '/dist/'], +}; + +export default config; diff --git a/services/api/jest.e2e.config.ts b/services/api/jest.e2e.config.ts new file mode 100644 index 0000000..3602de0 --- /dev/null +++ b/services/api/jest.e2e.config.ts @@ -0,0 +1,11 @@ +// services/api/jest.e2e.config.ts —— e2e(test/*.e2e-spec.ts),复用单测配置, +// 仅切换 testMatch;隔离工具见 test/reset.ts(每个 spec 的 beforeAll 调用)。 +import type { Config } from 'jest'; +import baseConfig from './jest.config'; + +const config: Config = { + ...baseConfig, + testMatch: ['/test/**/*.e2e-spec.ts'], +}; + +export default config; diff --git a/services/api/nest-cli.json b/services/api/nest-cli.json new file mode 100644 index 0000000..2a328c0 --- /dev/null +++ b/services/api/nest-cli.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "entryFile": "main-cn" +} diff --git a/services/api/package.json b/services/api/package.json new file mode 100644 index 0000000..d520cac --- /dev/null +++ b/services/api/package.json @@ -0,0 +1,37 @@ +{ + "name": "@photo/api-cn", + "version": "0.1.0", + "private": true, + "description": "CN NestJS API service (P1a skeleton: bootstrap, /v1/health, request-id, error envelope)", + "scripts": { + "build": "tsc -p tsconfig.build.json", + "start": "tsc -p tsconfig.build.json && node dist/main-cn.js", + "typecheck": "tsc --noEmit", + "lint": "eslint .", + "test": "jest", + "test:e2e": "jest --config jest.e2e.config.ts" + }, + "dependencies": { + "@nestjs/common": "^10.4.6", + "@nestjs/core": "^10.4.6", + "@nestjs/platform-express": "^10.4.6", + "@photo/contracts": "workspace:*", + "nestjs-pino": "^4.6.1", + "pino": "^10.0.0", + "pino-http": "^11.0.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@nestjs/testing": "^10.4.6", + "@types/jest": "^29.5.13", + "@types/node": "^22.10.0", + "@types/supertest": "^6.0.2", + "dotenv": "^16.4.5", + "jest": "^29.7.0", + "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "ts-node": "^10.9.2", + "typescript": "^5.6.0" + } +} diff --git a/services/api/src/all-exceptions.filter.spec.ts b/services/api/src/all-exceptions.filter.spec.ts new file mode 100644 index 0000000..f7ce8a1 --- /dev/null +++ b/services/api/src/all-exceptions.filter.spec.ts @@ -0,0 +1,77 @@ +// services/api/src/all-exceptions.filter.spec.ts +// 过滤器信封映射单测:HttpException -> ErrorCodes 映射、未知异常不泄露内部信息。 +import { + type ArgumentsHost, + BadRequestException, + ForbiddenException, + HttpStatus, + Logger, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { ErrorCodes } from '@photo/contracts'; +import { AllExceptionsFilter } from './all-exceptions.filter'; + +// 测试不断言日志内容,静音 Nest 控制台日志以保持输出干净。 +Logger.overrideLogger(false); + +interface Captured { + status?: number; + body?: { code?: string; message?: string; requestId?: string }; +} + +function runFilter(exception: unknown, requestId: string): Captured { + const captured: Captured = {}; + const res = { + status: (code: number) => { + captured.status = code; + return { + json: (body: Captured['body']) => { + captured.body = body; + }, + }; + }, + }; + const host = { + switchToHttp: () => ({ + getResponse: () => res, + getRequest: () => ({ id: requestId }), + }), + } as unknown as ArgumentsHost; + new AllExceptionsFilter().catch(exception, host); + return captured; +} + +describe('AllExceptionsFilter', () => { + it.each([ + [new BadRequestException('title is required'), HttpStatus.BAD_REQUEST, ErrorCodes.VALIDATION_FAILED], + [new UnauthorizedException(), HttpStatus.UNAUTHORIZED, ErrorCodes.AUTH_TOKEN_EXPIRED], + [new ForbiddenException(), HttpStatus.FORBIDDEN, ErrorCodes.AUTH_FORBIDDEN], + [new NotFoundException('album'), HttpStatus.NOT_FOUND, ErrorCodes.ALBUM_NOT_FOUND], + ])('maps HttpException %p to status %i / code %s', (exception, status, code) => { + const captured = runFilter(exception, 'req-1'); + expect(captured.status).toBe(status); + expect(captured.body?.code).toBe(code); + expect(captured.body?.requestId).toBe('req-1'); + }); + + it('keeps class-validator style array messages readable', () => { + const exception = new BadRequestException(['fieldA must be a string', 'fieldB must be positive']); + const captured = runFilter(exception, 'req-2'); + expect(captured.status).toBe(HttpStatus.BAD_REQUEST); + expect(captured.body?.code).toBe(ErrorCodes.VALIDATION_FAILED); + expect(captured.body?.message).toBe( + 'fieldA must be a string, fieldB must be positive', + ); + }); + + it('returns INTERNAL_ERROR with generic message for unknown errors (no stack leak)', () => { + const captured = runFilter(new Error('secret db failure'), 'req-3'); + expect(captured.status).toBe(HttpStatus.INTERNAL_SERVER_ERROR); + expect(captured.body).toEqual({ + code: ErrorCodes.INTERNAL_ERROR, + message: 'Internal server error', + requestId: 'req-3', + }); + }); +}); diff --git a/services/api/src/all-exceptions.filter.ts b/services/api/src/all-exceptions.filter.ts new file mode 100644 index 0000000..739c25c --- /dev/null +++ b/services/api/src/all-exceptions.filter.ts @@ -0,0 +1,88 @@ +// services/api/src/all-exceptions.filter.ts +// 全局兜底异常过滤器:所有错误响应统一 {code, message, requestId} 信封。 +// code 取自 @photo/contracts ErrorCodes;HttpException 按状态码映射默认错误码 +// (后续任务可按异常类型精化),未知异常一律 INTERNAL_ERROR + 通用文案, +// 完整错误仅写服务端日志,绝不向客户端泄露堆栈或内部细节。 +import { + type ArgumentsHost, + Catch, + type ExceptionFilter, + HttpException, + HttpStatus, + Logger, +} from '@nestjs/common'; +import { type ErrorCode, ErrorCodes } from '@photo/contracts'; + +interface JsonRespondable { + status(code: number): { json(body: unknown): void }; +} + +interface RequestWithId { + id?: string; +} + +const STATUS_TO_ERROR_CODE: Readonly> = { + [HttpStatus.BAD_REQUEST]: ErrorCodes.VALIDATION_FAILED, + [HttpStatus.UNAUTHORIZED]: ErrorCodes.AUTH_TOKEN_EXPIRED, + [HttpStatus.FORBIDDEN]: ErrorCodes.AUTH_FORBIDDEN, + [HttpStatus.NOT_FOUND]: ErrorCodes.ALBUM_NOT_FOUND, +}; + +@Catch() +export class AllExceptionsFilter implements ExceptionFilter { + private readonly logger = new Logger(AllExceptionsFilter.name); + + catch(exception: unknown, host: ArgumentsHost): void { + const res = host.switchToHttp().getResponse(); + const req = host.switchToHttp().getRequest(); + const requestId = req.id ?? 'unknown'; + + if (exception instanceof HttpException) { + const status = exception.getStatus(); + const code = STATUS_TO_ERROR_CODE[status] ?? ErrorCodes.INTERNAL_ERROR; + const message = extractMessage(exception); + this.logger.warn( + `HttpException ${status} -> ${code} (requestId=${requestId}): ${message}`, + ); + res.status(status).json({ code, message, requestId }); + return; + } + + const stack = exception instanceof Error ? exception.stack : undefined; + this.logger.error( + `Unhandled exception (requestId=${requestId}): ${stringifyException(exception)}`, + stack, + ); + res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ + code: ErrorCodes.INTERNAL_ERROR, + message: 'Internal server error', + requestId, + }); + } +} + +function extractMessage(exception: HttpException): string { + const body: unknown = exception.getResponse(); + if (typeof body === 'string') { + return body; + } + if (body !== null && typeof body === 'object' && 'message' in body) { + const message = (body as { message: unknown }).message; + if (typeof message === 'string' && message !== '') { + return message; + } + if (Array.isArray(message)) { + const parts = message.filter((part): part is string => typeof part === 'string'); + if (parts.length > 0) { + return parts.join(', '); + } + } + } + return exception.message; +} + +function stringifyException(exception: unknown): string { + return exception instanceof Error + ? `${exception.name}: ${exception.message}` + : String(exception); +} diff --git a/services/api/src/app-cn.module.ts b/services/api/src/app-cn.module.ts new file mode 100644 index 0000000..a773865 --- /dev/null +++ b/services/api/src/app-cn.module.ts @@ -0,0 +1,37 @@ +// services/api/src/app-cn.module.ts +// 根模块:日志(nestjs-pino / pino-http)、request-id 中间件、全局异常过滤器、 +// /v1/health。功能模块(auth/albums/uploads/photos/public)自 Task 12+ 起逐个加入。 +// 过滤器经 APP_FILTER、中间件经 NestModule 在模块层注册——e2e 直接 import 本模块 +// 即可获得与生产一致的管线(全局前缀除外,由入口设置)。 +import { type MiddlewareConsumer, Module, type NestModule } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; +import { LoggerModule } from 'nestjs-pino'; +import type { IncomingMessage, ServerResponse } from 'node:http'; +import { AllExceptionsFilter } from './all-exceptions.filter'; +import { HealthController } from './health.controller'; +import { RequestIdMiddleware, resolveRequestId } from './request-id.middleware'; + +@Module({ + imports: [ + LoggerModule.forRoot({ + pinoHttp: { + // 与 RequestIdMiddleware 共用同一解析函数:优先透传 x-request-id, + // 其次复用已生成的 req.id,否则生成 UUID;并回写响应头。 + genReqId: (req: IncomingMessage, res: ServerResponse) => + resolveRequestId(req, res), + redact: { + paths: ['req.headers.authorization', 'res.headers.authorization'], + censor: '[REDACTED]', + }, + level: process.env.LOG_LEVEL ?? 'info', + }, + }), + ], + controllers: [HealthController], + providers: [{ provide: APP_FILTER, useClass: AllExceptionsFilter }], +}) +export class AppCnModule implements NestModule { + configure(consumer: MiddlewareConsumer): void { + consumer.apply(RequestIdMiddleware).forRoutes('*'); + } +} diff --git a/services/api/src/health.controller.ts b/services/api/src/health.controller.ts new file mode 100644 index 0000000..064c46a --- /dev/null +++ b/services/api/src/health.controller.ts @@ -0,0 +1,11 @@ +// services/api/src/health.controller.ts +// GET /v1/health —— 存活探针(P1a 仅此一个端点,后续任务逐步扩展)。 +import { Controller, Get } from '@nestjs/common'; + +@Controller('health') +export class HealthController { + @Get() + check(): { status: 'ok' } { + return { status: 'ok' }; + } +} diff --git a/services/api/src/main-cn.ts b/services/api/src/main-cn.ts new file mode 100644 index 0000000..f1a703d --- /dev/null +++ b/services/api/src/main-cn.ts @@ -0,0 +1,26 @@ +// services/api/src/main-cn.ts +// cn-app 部署入口(P1a 仅此一个 API 入口)。构建产物 dist/main-cn.js 由根 dev:api / +// 生产启动命令运行;env 一律来自进程环境(根 dotenv-cli 注入),此处不读文件。 +import 'reflect-metadata'; +import { type INestApplication } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; +import { Logger } from 'nestjs-pino'; +import { AppCnModule } from './app-cn.module'; + +async function bootstrap(): Promise { + const app = await NestFactory.create(AppCnModule, { + bufferLogs: true, + }); + app.useLogger(app.get(Logger)); + app.setGlobalPrefix('v1'); + const corsOrigins = (process.env.CORS_ORIGINS ?? 'http://localhost:5173') + .split(',') + .map((origin) => origin.trim()) + .filter((origin) => origin !== ''); + app.enableCors({ origin: corsOrigins }); + const port = Number.parseInt(process.env.PORT ?? '', 10) || 8080; + await app.listen(port); + app.get(Logger).log(`api-cn listening on port ${port}`); +} + +void bootstrap(); diff --git a/services/api/src/request-id.middleware.ts b/services/api/src/request-id.middleware.ts new file mode 100644 index 0000000..ac07eb9 --- /dev/null +++ b/services/api/src/request-id.middleware.ts @@ -0,0 +1,37 @@ +// services/api/src/request-id.middleware.ts +// 请求 ID 约定:优先透传上游 x-request-id(网关/前端可携带),否则生成 UUID v4; +// 挂到 req.id(pino-http 日志字段)并写回响应头 x-request-id,便于全链路排障。 +// genReqId 与本中间件共用 resolveRequestId,先后顺序不影响结果。 +import { randomUUID } from 'node:crypto'; +import type { IncomingMessage, ServerResponse } from 'node:http'; +import type { NestMiddleware } from '@nestjs/common'; + +interface RequestWithId { + id?: string; +} + +export function resolveRequestId( + req: IncomingMessage, + res: ServerResponse, +): string { + const existing = (req as IncomingMessage & RequestWithId).id; + if (existing) { + return existing; + } + const header = req.headers['x-request-id']; + const fromHeader = Array.isArray(header) ? header[0] : header; + const id = + typeof fromHeader === 'string' && fromHeader.trim() !== '' + ? fromHeader + : randomUUID(); + (req as IncomingMessage & RequestWithId).id = id; + res.setHeader('x-request-id', id); + return id; +} + +export class RequestIdMiddleware implements NestMiddleware { + use(req: IncomingMessage, res: ServerResponse, next: () => void): void { + resolveRequestId(req, res); + next(); + } +} diff --git a/services/api/test/health.e2e-spec.ts b/services/api/test/health.e2e-spec.ts new file mode 100644 index 0000000..5a0dfac --- /dev/null +++ b/services/api/test/health.e2e-spec.ts @@ -0,0 +1,47 @@ +// services/api/test/health.e2e-spec.ts +// e2e 冒烟:验证 e2e 工装(Nest testing module + supertest + 根 .env 加载)可用。 +// 不监听端口:app.init() 后直接对 app.getHttpServer() 发请求。 +// 全局前缀与 main-cn.ts 保持一致('v1'),由 spec 显式设置。 +import { type INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import request from 'supertest'; +import { AppCnModule } from '../src/app-cn.module'; +import { resetDb } from './reset'; + +describe('GET /v1/health (e2e)', () => { + let app: INestApplication; + + beforeAll(async () => { + await resetDb(); + const moduleRef = await Test.createTestingModule({ + imports: [AppCnModule], + }).compile(); + app = moduleRef.createNestApplication(); + app.setGlobalPrefix('v1'); + await app.init(); + }); + + afterAll(async () => { + await app.close(); + }); + + it('responds 200 {"status":"ok"}', async () => { + const res = await request(app.getHttpServer()).get('/v1/health'); + expect(res.status).toBe(200); + expect(res.body).toEqual({ status: 'ok' }); + }); + + it('sets x-request-id response header (generated when absent)', async () => { + const res = await request(app.getHttpServer()).get('/v1/health'); + const requestId = res.headers['x-request-id']; + expect(typeof requestId).toBe('string'); + expect(requestId.length ?? 0).toBeGreaterThan(0); + }); + + it('echoes incoming x-request-id header', async () => { + const res = await request(app.getHttpServer()) + .get('/v1/health') + .set('x-request-id', 'e2e-fixed-request-id'); + expect(res.headers['x-request-id']).toBe('e2e-fixed-request-id'); + }); +}); diff --git a/services/api/test/load-env.ts b/services/api/test/load-env.ts new file mode 100644 index 0000000..d8c464b --- /dev/null +++ b/services/api/test/load-env.ts @@ -0,0 +1,7 @@ +// services/api/test/load-env.ts +// 全仓库唯一 env 加载机制(Jest 侧):仓库根 .env。开发/迁移脚本经根 dotenv-cli +// 注入;运行时代码只读 process.env。worker/storage 包的 test/load-env.ts 复制同约定。 +import { join } from 'node:path'; +import { config } from 'dotenv'; + +config({ path: join(__dirname, '../../../.env') }); diff --git a/services/api/test/reset.ts b/services/api/test/reset.ts new file mode 100644 index 0000000..e21de62 --- /dev/null +++ b/services/api/test/reset.ts @@ -0,0 +1,17 @@ +// services/api/test/reset.ts +// e2e 共用隔离工具:每个 e2e spec 的 beforeAll 调用 resetDb(),防止 spec 间 +// 唯一约束冲突与脏数据。 +// TODO(Task 8): 用 Prisma 实现 RESET_TABLES 中全部表的 truncate-if-exists +// (Task 8-10 逐步登记表名,届时空列表不再成立)。 +// TODO(Task 11): 增加 MinIO `photo-live/dev` 前缀对象清理(同一函数内追加)。 +export const RESET_TABLES: readonly string[] = []; + +export async function resetDb(): Promise { + if (RESET_TABLES.length === 0) { + // 尚未登记任何表(Task 8 前数据库无表):干净地跳过。 + return; + } + throw new Error( + 'resetDb: RESET_TABLES is non-empty but truncation is not implemented until Task 8', + ); +} diff --git a/services/api/tsconfig.build.json b/services/api/tsconfig.build.json new file mode 100644 index 0000000..fc2329d --- /dev/null +++ b/services/api/tsconfig.build.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"], + "exclude": ["node_modules", "dist", "test", "**/*.spec.ts", "**/*.e2e-spec.ts"] +} diff --git a/services/api/tsconfig.json b/services/api/tsconfig.json new file mode 100644 index 0000000..a7ba04e --- /dev/null +++ b/services/api/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node10", + "target": "ES2022", + "lib": ["ES2022"], + "strict": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "declaration": false, + "sourceMap": true, + "outDir": "./dist", + "types": ["node", "jest"] + }, + "include": ["src", "test"] +}